commit 0de103c1cdf1e4c40cfad4e233a42a6d1165953d Author: Martin Poirier Date: Tue Nov 6 22:29:20 2007 +0000 Filling in branch from trunk diff --git a/CMake/macros.cmake b/CMake/macros.cmake new file mode 100644 index 00000000000..6b6837d25f0 --- /dev/null +++ b/CMake/macros.cmake @@ -0,0 +1,81 @@ +MACRO(BLENDERLIB_NOLIST + name + sources + includes) + + # Gather all headers + FILE(GLOB_RECURSE INC_ALL *.h) + + INCLUDE_DIRECTORIES(${includes}) + ADD_LIBRARY(${name} ${INC_ALL} ${sources}) + + # Group by location on disk + SOURCE_GROUP(Files FILES CMakeLists.txt) + SET(ALL_FILES ${sources} ${INC_ALL}) + FOREACH(SRC ${ALL_FILES}) + STRING(REGEX REPLACE ${CMAKE_CURRENT_SOURCE_DIR} "Files" REL_DIR "${SRC}") + STRING(REGEX REPLACE "[\\\\/][^\\\\/]*$" "" REL_DIR "${REL_DIR}") + STRING(REGEX REPLACE "^[\\\\/]" "" REL_DIR "${REL_DIR}") + IF(REL_DIR) + SOURCE_GROUP(${REL_DIR} FILES ${SRC}) + ELSE(REL_DIR) + SOURCE_GROUP(Files FILES ${SRC}) + ENDIF(REL_DIR) + ENDFOREACH(SRC) + + MESSAGE(STATUS "Configuring library ${name}") +ENDMACRO(BLENDERLIB_NOLIST) + +MACRO(BLENDERLIB + name + sources + includes) + + BLENDERLIB_NOLIST(${name} "${sources}" "${includes}") + + # Add to blender's list of libraries + FILE(APPEND ${CMAKE_BINARY_DIR}/cmake_blender_libs.txt "${name};") +ENDMACRO(BLENDERLIB) + +MACRO(SETUP_LIBDIRS) + LINK_DIRECTORIES(${PYTHON_LIBPATH} ${SDL_LIBPATH} ${JPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH} ${ICONV_LIBPATH} ${OPENEXR_LIBPATH} ${QUICKTIME_LIBPATH} ${FFMPEG_LIBPATH}) + IF(WITH_INTERNATIONAL) + LINK_DIRECTORIES(${GETTEXT_LIBPATH}) + LINK_DIRECTORIES(${FREETYPE_LIBPATH}) + ENDIF(WITH_INTERNATIONAL) + IF(WITH_OPENAL) + LINK_DIRECTORIES(${OPENAL_LIBPATH}) + ENDIF(WITH_OPENAL) + + IF(WIN32) + LINK_DIRECTORIES(${PTHREADS_LIBPATH}) + ENDIF(WIN32) +ENDMACRO(SETUP_LIBDIRS) + +MACRO(SETUP_LIBLINKS + target) + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS} ") + TARGET_LINK_LIBRARIES(${target} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ${PYTHON_LIB} ${PYTHON_LINKFLAGS} ${JPEG_LIB} ${PNG_LIB} ${ZLIB_LIB} ${SDL_LIB} ${LLIBS}) + IF(WITH_INTERNATIONAL) + TARGET_LINK_LIBRARIES(${target} ${FREETYPE_LIB}) + TARGET_LINK_LIBRARIES(${target} ${GETTEXT_LIB}) + ENDIF(WITH_INTERNATIONAL) + IF(WITH_OPENAL) + TARGET_LINK_LIBRARIES(${target} ${OPENAL_LIB}) + ENDIF(WITH_OPENAL) + IF(WIN32) + TARGET_LINK_LIBRARIES(${target} ${ICONV_LIB}) + ENDIF(WIN32) + IF(WITH_QUICKTIME) + TARGET_LINK_LIBRARIES(${target} ${QUICKTIME_LIB}) + ENDIF(WITH_QUICKTIME) + IF(WITH_OPENEXR) + TARGET_LINK_LIBRARIES(${target} ${OPENEXR_LIB}) + ENDIF(WITH_OPENEXR) + IF(WITH_FFMPEG) + TARGET_LINK_LIBRARIES(${target} ${FFMPEG_LIB}) + ENDIF(WITH_FFMPEG) + IF(WIN32) + TARGET_LINK_LIBRARIES(${target} ${PTHREADS_LIB}) + ENDIF(WIN32) +ENDMACRO(SETUP_LIBLINKS) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000000..0227c51f39d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,408 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +#----------------------------------------------------------------------------- +# We don't allow in-source builds. This causes no end of troubles because +# all out-of-source builds will use the CMakeCache.txt file there and even +# build the libs and objects in it. It will also conflict with the current +# Makefile system for Blender + +IF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) +MESSAGE(FATAL_ERROR "CMake generation for blender is not allowed within the source directory! +Remove the CMakeCache.txt file and try again from another folder, e.g.: + + rm CMakeCache.txt + cd .. + mkdir cmake-make + cd cmake-make + cmake -G \"Unix Makefiles\" ../blender +") +ENDIF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + +CMAKE_MINIMUM_REQUIRED(VERSION 2.4) +PROJECT(Blender) + +#----------------------------------------------------------------------------- +# Redirect output files + +SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) + +#----------------------------------------------------------------------------- +# Set default config options +OPTION(WITH_PLAYER "Build Player" OFF) +OPTION(WITH_GAMEENGINE "Enable Game Engine" ON) +OPTION(WITH_BULLET "Enable Bullet (Physics Engine)" ON) +OPTION(WITH_INTERNATIONAL "Enable I18N (International fonts and text)" ON) +OPTION(WITH_VERSE "Enable Verse (http://verse.blender.org)" OFF) +OPTION(WITH_ELBEEM "Enable Elbeem (Fluid Simulation)" ON) +OPTION(WITH_QUICKTIME "Enable Quicktime Support" OFF) +OPTION(WITH_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" OFF) +OPTION(WITH_FFMPEG "Enable FFMPeg Support (http://ffmpeg.mplayerhq.hu/)" OFF) +OPTION(WITH_OPENAL "Enable OpenAL Support (http://www.openal.org)" ON) +OPTION(YESIAMSTUPID "Enable execution on 64-bit platforms" OFF) + +IF(NOT WITH_GAMEENGINE AND WITH_PLAYER) + MESSAGE("WARNING: WITH_PLAYER needs WITH_GAMEENGINE") +ENDIF(NOT WITH_GAMEENGINE AND WITH_PLAYER) + +# For alternate Python locations the commandline can be used to override detected/default cache settings, e.g: +# On Unix: +# cmake -D PYTHON_LIB=/usr/local/lib/python2.3/config/libpython2.3.so -D PYTHON_INC=/usr/local/include/python2.3 -D PYTHON_BINARY=/usr/local/bin/python2.3 -G "Unix Makefiles" ../blender +# On Macs: +# cmake -D PYTHON_INC=/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -D PYTHON_LIBPATH=/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/config -D PYTHON_BINARY=/System/Library/Frameworks/Python.framework/Versions/2.5/bin/python2.5 -G Xcode ../blender +# +# When changing any of this remember to update the notes in doc/blender-cmake.txt + +#----------------------------------------------------------------------------- +# Load some macros. +INCLUDE(CMake/macros.cmake) + +#----------------------------------------------------------------------------- +#Platform specifics + +IF(UNIX) + INCLUDE(${CMAKE_ROOT}/Modules/FindOpenAL.cmake) + IF(OPENAL_FOUND) + SET(WITH_OPENAL ON) + SET(OPENAL_LIB ${OPENAL_LIBRARY}) + SET(OPENAL_INC ${OPENAL_INCLUDE_DIR}) + ELSE(OPENAL_FOUND) + SET(WITH_OPENAL OFF) + ENDIF(OPENAL_FOUND) + + FIND_LIBRARY(ALUT_LIBRARY + NAMES alut + PATHS + /usr/local/lib + /usr/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + ) + IF(ALUT_LIBRARY) + SET(OPENAL_LIB ${OPENAL_LIB} ${ALUT_LIBRARY}) + ENDIF(ALUT_LIBRARY) + + FIND_LIBRARY(INTL_LIBRARY + NAMES intl + PATHS + /usr/local/lib + /usr/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + ) + FIND_LIBRARY(ICONV_LIBRARY + NAMES iconv + PATHS + /usr/local/lib + /usr/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + ) + IF(INTL_LIBRARY AND ICONV_LIBRARY) + SET(GETTEXT_LIB ${INTL_LIBRARY} ${ICONV_LIBRARY}) + ENDIF(INTL_LIBRARY AND ICONV_LIBRARY) + + FIND_PATH(FREETYPE_INC + freetype + PATHS + /usr/local/include/freetype2 + /usr/include/freetype2 + /sw/include/freetype2 + /opt/local/include/freetype2 + /opt/csw/include/freetype2 + /opt/include/freetype2 + NO_DEFAULT_PATH + ) + SET(FREETYPE_LIB freetype) + + INCLUDE(${CMAKE_ROOT}/Modules/FindPythonLibs.cmake) + SET(PYTHON_INC "${PYTHON_INCLUDE_PATH}" CACHE STRING "") + SET(PYTHON_LIB "${PYTHON_LIBRARIES}" CACHE STRING "") + INCLUDE(${CMAKE_ROOT}/Modules/FindPythonInterp.cmake) + SET(PYTHON_BINARY ${PYTHON_EXECUTABLE} CACHE STRING "") + SET(PYTHON_LINKFLAGS "-Xlinker -export-dynamic") + + INCLUDE(${CMAKE_ROOT}/Modules/FindSDL.cmake) + SET(SDL_INC ${SDL_INCLUDE_DIR}) + SET(SDL_LIB ${SDL_LIBRARY}) + + FIND_PATH(OPENEXR_INC + ImfXdr.h + PATHS + /usr/local/include/OpenEXR + /usr/include/OpenEXR + /sw/include/OpenEXR + /opt/local/include/OpenEXR + /opt/csw/include/OpenEXR + /opt/include/OpenEXR + ) + SET(OPENEXR_LIB Half IlmImf Iex Imath) + + SET(FFMPEG /usr) + SET(FFMPEG_INC ${FFMPEG}/include) + SET(FFMPEG_LIB avformat avcodec avutil) + SET(FFMPEG_LIBPATH ${FFMPEG}/lib) + + SET(JPEG_LIB jpeg) + + SET(PNG_LIB png) + + SET(ZLIB_LIB z) + + SET(LLIBS "-lXi -lutil -lc -lm -lpthread -lstdc++") + + SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -DXP_UNIX -Wno-char-subscripts") + + SET(PLATFORM_LINKFLAGS "-pthread") + + INCLUDE_DIRECTORIES(/usr/include /usr/local/include) +ENDIF(UNIX) + +IF(WIN32) + INCLUDE(${CMAKE_ROOT}/Modules/Platform/Windows-cl.cmake) + + SET(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/windows) + + SET(PYTHON ${LIBDIR}/python) + SET(PYTHON_VERSION 2.5) + SET(PYTHON_INC "${PYTHON}/include/python${PYTHON_VERSION}") + SET(PYTHON_BINARY python) + SET(PYTHON_LIB python25) + SET(PYTHON_LIBPATH ${PYTHON}/lib) + + #SET(WITH_OPENAL ON) + SET(OPENAL ${LIBDIR}/openal) + SET(OPENAL_INC ${OPENAL}/include ${OPENAL}/include/AL) + SET(OPENAL_LIB openal_static) + SET(OPENAL_LIBPATH ${OPENAL}/lib) + + SET(PNG_LIB libpng_st) + SET(JPEG_LIB libjpeg) + + SET(ZLIB ${LIBDIR}/zlib) + SET(ZLIB_INC ${ZLIB}/include) + SET(ZLIB_LIB libz) + SET(ZLIB_LIBPATH ${ZLIB}/lib) + + SET(PTHREADS ${LIBDIR}/pthreads) + SET(PTHREADS_INC ${PTHREADS}/include) + SET(PTHREADS_LIB pthreadVC2) + SET(PTHREADS_LIBPATH ${PTHREADS}/lib) + + SET(ICONV ${LIBDIR}/iconv) + SET(ICONV_INC ${ICONV}/include) + SET(ICONV_LIB iconv) + SET(ICONV_LIBPATH ${ICONV}/lib) + + SET(GETTEXT ${LIBDIR}/gettext) + SET(GETTEXT_INC ${GETTEXT}/include) + SET(GETTEXT_LIB gnu_gettext) + SET(GETTEXT_LIBPATH ${GETTEXT}/lib) + + SET(FREETYPE ${LIBDIR}/freetype) + SET(FREETYPE_INC ${FREETYPE}/include ${FREETYPE}/include/freetype2) + SET(FREETYPE_LIBPATH ${FREETYPE}/lib) + SET(FREETYPE_LIB freetype2ST) + + SET(OPENEXR ${LIBDIR}/openexr) + SET(OPENEXR_INC ${OPENEXR}/include ${OPENEXR}/include/IlmImf ${OPENEXR}/include/Iex ${OPENEXR}/include/Imath) + SET(OPENEXR_LIB Iex Half IlmImf Imath IlmThread) + IF (MSVC80) + SET(OPENEXR_LIBPATH ${OPENEXR}/lib_vs2005) + ELSE (MSVC80) + SET(OPENEXR_LIBPATH ${OPENEXR}/lib_msvc) + ENDIF(MSVC80) + + SET(QUICKTIME ${LIBDIR}/QTDevWin) + SET(QUICKTIME_INC ${QUICKTIME}/CIncludes) + SET(QUICKTIME_LIB qtmlClient) + SET(QUICKTIME_LIBPATH ${QUICKTIME}/Libraries) + + SET(FFMPEG ${LIBDIR}/ffmpeg) + SET(FFMPEG_INC ${FFMPEG}/include) + SET(FFMPEG_LIB avcodec-51 avformat-51 avutil-49) + SET(FFMPEG_LIBPATH ${FFMPEG}/lib) + + SET(LLIBS kernel32 user32 gdi32 comdlg32 advapi32 shell32 ole32 oleaut32 uuid ws2_32 vfw32 winmm) + IF(WITH_OPENAL) + SET(LLIBS ${LLIBS} dxguid) + ENDIF(WITH_OPENAL) + + SET(CMAKE_CXX_FLAGS_DEBUG "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /D_DEBUG /Od /Gm /EHsc /RTC1 /MTd /W3 /nologo /ZI /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_CXX_FLAGS_RELEASE "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob2 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_CXX_FLAGS_MINSIZEREL "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O1 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /Zi /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_C_FLAGS_DEBUG "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /D_DEBUG /Od /Gm /EHsc /RTC1 /MTd /W3 /nologo /ZI /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_C_FLAGS_RELEASE "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob2 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_C_FLAGS_MINSIZEREL "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O1 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /J" CACHE STRING "MSVC MT flags " FORCE) + SET(CMAKE_C_FLAGS_RELWITHDEBINFO "/D_CRT_NONSTDC_NO_DEPRECATE /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /wd4800 /wd4244 /wd4305 /O2 /Ob1 /DNDEBUG /EHsc /MT /W3 /nologo /Zi /J" CACHE STRING "MSVC MT flags " FORCE) + + SET(SDL ${LIBDIR}/sdl) + SET(SDL_INC ${SDL}/include) + SET(SDL_LIB SDL) + SET(SDL_LIBPATH ${SDL}/lib) + + SET(PNG "${LIBDIR}/png") + SET(PNG_INC "${PNG}/include") + SET(PNG_LIBPATH ${PNG}/lib) + + SET(JPEG "${LIBDIR}/jpeg") + SET(JPEG_INC "${JPEG}/include") + SET(JPEG_LIBPATH ${JPEG}/lib) + + SET(TIFF ${LIBDIR}/tiff) + SET(TIFF_INC ${TIFF}/include) + + SET(WINTAB_INC ${LIBDIR}/wintab/include) + + SET(PLATFORM_LINKFLAGS "/NODEFAULTLIB:libc.lib") + SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt.lib ") +ENDIF(WIN32) + +IF(APPLE) + IF(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-8.x.i386) + ELSE(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-6.1-powerpc) + ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES i386) + + INCLUDE(${CMAKE_ROOT}/Modules/FindOpenAL.cmake) + IF(OPENAL_FOUND) + SET(WITH_OPENAL ON) + SET(OPENAL_LIB ${OPENAL_LIBRARY}) + SET(OPENAL_INC ${OPENAL_INCLUDE_DIR}) + ELSE(OPENAL_FOUND) + SET(WITH_OPENAL OFF) + ENDIF(OPENAL_FOUND) + + SET(PYTHON /System/Library/Frameworks/Python.framework/Versions/) + SET(PYTHON_VERSION 2.3) + SET(PYTHON_INC "${PYTHON}${PYTHON_VERSION}/include/python${PYTHON_VERSION}" CACHE STRING "") + SET(PYTHON_BINARY ${PYTHON}${PYTHON_VERSION}/bin/python${PYTHON_VERSION} CACHE STRING "") + SET(PYTHON_LIB "") + SET(PYTHON_LIBPATH ${PYTHON}${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config CACHE STRING "") + SET(PYTHON_LINKFLAGS "-u __dummy -u _PyMac_Error -framework System -framework Python") + + SET(GETTEXT ${LIBDIR}/gettext) + SET(GETTEXT_INC "${GETTEXT}/include") + SET(GETTEXT_LIB intl iconv) + SET(GETTEXT_LIBPATH ${GETTEXT}/lib) + + SET(PNG_LIB png) + SET(JPEG_LIB jpeg) + + SET(ZLIB /usr) + SET(ZLIB_INC "${ZLIB}/include") + SET(ZLIB_LIB z) + + SET(FREETYPE ${LIBDIR}/freetype) + SET(FREETYPE_INC ${FREETYPE}/include ${FREETYPE}/include/freetype2) + SET(FREETYPE_LIBPATH ${FREETYPE}/lib) + SET(FREETYPE_LIB freetype) + + SET(OPENEXR ${LIBDIR}/openexr) + SET(OPENEXR_INC ${OPENEXR}/include/OpenEXR ${OPENEXR}/include) + IF(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(OPENEXR_LIB Iex Half IlmImf Imath IlmThread) + ELSE(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(OPENEXR_LIB Iex Half IlmImf Imath) + ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES i386) + SET(OPENEXR_LIBPATH ${OPENEXR}/lib) + + SET(LLIBS stdc++ SystemStubs) + + SET(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing") + SET(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime") + + SET(SDL ${LIBDIR}/sdl) + SET(SDL_INC ${SDL}/include) + SET(SDL_LIB SDL) + SET(SDL_LIBPATH ${SDL}/lib) + + SET(PNG "${LIBDIR}/png") + SET(PNG_INC "${PNG}/include") + SET(PNG_LIBPATH ${PNG}/lib) + + SET(JPEG "${LIBDIR}/jpeg") + SET(JPEG_INC "${JPEG}/include") + SET(JPEG_LIBPATH ${JPEG}/lib) + + SET(TIFF ${LIBDIR}/tiff) + SET(TIFF_INC ${TIFF}/include) + + SET(EXETYPE MACOSX_BUNDLE) +ENDIF(APPLE) + +#----------------------------------------------------------------------------- +# Common. +SET(VERSE_INC ${CMAKE_SOURCE_DIR}/extern/verse/dist) + +SET(FTGL ${CMAKE_SOURCE_DIR}/extern/bFTGL) +SET(FTGL_INC ${FTGL}/include) +SET(FTGL_LIB extern_ftgl) + + +#----------------------------------------------------------------------------- +# Configure OpenGL. +INCLUDE(${CMAKE_ROOT}/Modules/FindOpenGL.cmake) +INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) +#----------------------------------------------------------------------------- +# Extra compile flags +IF(WITH_GAMEENGINE) + SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -DGAMEBLENDER ") +ENDIF(WITH_GAMEENGINE) +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS} ") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PLATFORM_CFLAGS} ") + +#----------------------------------------------------------------------------- +# Libraries +FILE(WRITE ${CMAKE_BINARY_DIR}/cmake_blender_libs.txt "") +SUBDIRS( + intern + extern + source +) + + +#----------------------------------------------------------------------------- +# Blender Application +SUBDIRS(source/creator) + +#----------------------------------------------------------------------------- +# Blender Player +IF(WITH_PLAYER) + SUBDIRS(blenderplayer) +ENDIF(WITH_PLAYER) diff --git a/COPYING b/COPYING new file mode 100644 index 00000000000..232ee776d87 --- /dev/null +++ b/COPYING @@ -0,0 +1,3 @@ +Please read over both of the following files: +doc/GPL-license.txt +doc/BL-license.txt diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..b77adf82cfb --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2002 by Wouter van Heyst +# All rights reserved. +# +# The Original Code is: revision 1.1 +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Toplevel Makefile for blender. Bounces make to subdirectories. +# Available targets: 'all' 'debug' 'release' + +# If the user wants to override some of the build +# vars they can put it in the file user-def.mk which +# will get included if it exists (please do not commit +# user-def.mk to cvs). + +sinclude user-def.mk + +# To build without openAL, uncomment the following line, or set it as +# an environment variable, or put it uncommented in user-def.mk: +# export NAN_NO_OPENAL=true + +export NANBLENDERHOME=$(shell pwd) +MAKEFLAGS=-I$(NANBLENDERHOME)/source --no-print-directory + +SOURCEDIR = +ifeq ($(FREE_WINDOWS),true) + DIRS ?= dlltool extern intern source po +endif + +DIRS ?= extern intern source po +include source/nan_subdirs.mk + +.PHONY: release +release: + @echo "====> $(MAKE) $@ in $(SOURCEDIR)/$@" ;\ + $(MAKE) -C $@ $@ || exit 1; + + diff --git a/README b/README new file mode 100644 index 00000000000..d123a90ba48 --- /dev/null +++ b/README @@ -0,0 +1,45 @@ +Welcome to the fun world of open source. + +For instructions on building and installing Blender, please see the file named +INSTALL. + + +---------------------.Blanguages and the .blender directory--------------------- + +The .blender directory holds various data files for Blender. +In the 2.28a release those are the .Blanguages file containing a list of +translations, the translations themselves and a default ttf font. + +Blender checks for the presence of this directory in several locations: + - the current directory + - your home directory + - On OSX, the blender bundle is also checked + - On Windows, the installation dir is checked. + +If you get a 'File ".Blanguages" not found' warning, try to copy the .blender +dir to one of these locations (your home directory being recommended). + + + +-------------------------------------Links-------------------------------------- + +Getting Involved: +http://www.blender.org/docs/get_involved.html + +Community: +http://www.blender3d.org/Community/ + +Main blender development site: +http://www.blender.org/ + +The Blender project homepage: +http://projects.blender.org/projects/bf-blender/ + +Documentation: +http://www.blender.org/modules.php?op=modload&name=documentation&file=index + +Bug tracker: +http://projects.blender.org/tracker/?atid=125&group_id=9&func=browse + +Feature request tracker: +http://projects.blender.org/tracker/?atid=128&group_id=9&func=browse diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000000..2cacb91d103 --- /dev/null +++ b/SConstruct @@ -0,0 +1,447 @@ +#!/usr/bin/env python +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Nathan Letwory. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# Main entry-point for the SCons building system +# Set up some custom actions and target/argument handling +# Then read all SConscripts and build + +import sys +import os +import os.path +import string +import shutil +import glob +import re + +import tools.Blender +import tools.btools +import tools.bcolors + +BlenderEnvironment = tools.Blender.BlenderEnvironment +btools = tools.btools +B = tools.Blender + +### globals ### +platform = sys.platform +quickie = None +quickdebug = None +nsis_build = None + +##### BEGIN SETUP ##### + +B.possible_types = ['core', 'common', 'blender', 'intern', + 'international', 'game', 'game2', + 'player', 'player2', 'system'] + +B.binarykind = ['blender' , 'blenderplayer'] +################################## +# target and argument validation # +################################## +# XX cheating for BF_FANCY, we check for BF_FANCY before args are validated +use_color = ARGUMENTS.get('BF_FANCY', '1') +if platform=='win32': + use_color = None + +if not use_color=='1': + B.bc.disable() + + #on defaut white Os X terminal, some colors are totally unlegible +if platform=='darwin': + B.bc.OKGREEN = '\033[34m' + B.bc.WARNING = '\033[36m' + +# arguments +print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC +B.arguments = btools.validate_arguments(ARGUMENTS, B.bc) +btools.print_arguments(B.arguments, B.bc) + +# targets +print B.bc.HEADER+'Command-line targets'+B.bc.ENDC +B.targets = btools.validate_targets(COMMAND_LINE_TARGETS, B.bc) +btools.print_targets(B.targets, B.bc) + +########################## +# setting up environment # +########################## + +# handling cmd line arguments & config file + +# first check cmdline for toolset and we create env to work on +quickie = B.arguments.get('BF_QUICK', None) +quickdebug = B.arguments.get('BF_QUICKDEBUG', None) + +if quickdebug: + B.quickdebug=string.split(quickdebug, ',') +else: + B.quickdebug=[] + +if quickie: + B.quickie=string.split(quickie,',') +else: + B.quickie=[] + +toolset = B.arguments.get('BF_TOOLSET', None) +if toolset: + print "Using " + toolset + if toolset=='mstoolkit': + env = BlenderEnvironment(ENV = os.environ) + env.Tool('mstoolkit', ['tools']) + else: + env = BlenderEnvironment(tools=[toolset], ENV = os.environ) + if env: + btools.SetupSpawn(env) +else: + env = BlenderEnvironment(ENV = os.environ) + +if not env: + print "Could not create a build environment" + Exit() + + +cc = B.arguments.get('CC', None) +cxx = B.arguments.get('CXX', None) +if cc: + env['CC'] = cc +if cxx: + env['CXX'] = cxx + +if env['CC'] in ['cl', 'cl.exe'] and sys.platform=='win32': + platform = 'win32-vc' +elif env['CC'] in ['gcc'] and sys.platform=='win32': + platform = 'win32-mingw' + +env.SConscriptChdir(0) + +crossbuild = B.arguments.get('BF_CROSS', None) +if crossbuild and platform!='win32': + platform = 'linuxcross' + +env['OURPLATFORM'] = platform + +configfile = B.arguments.get('BF_CONFIG', 'config'+os.sep+platform+'-config.py') + +if os.path.exists(configfile): + print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile +else: + print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC + +if crossbuild and env['PLATFORM'] != 'win32': + print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC + env.Tool('crossmingw', ['tools']) + # todo: determine proper libs/includes etc. + # Needed for gui programs, console programs should do without it + env.Append(LINKFLAGS=['-mwindows']) + +# first read platform config. B.arguments will override +optfiles = [configfile] +if os.path.exists('user-config.py'): + print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + 'user-config.py' + optfiles += ['user-config.py'] +else: + print B.bc.WARNING + 'user-config.py' + " not found, no user overrides" + B.bc.ENDC + +opts = btools.read_opts(optfiles, B.arguments) +opts.Update(env) + +# disable elbeem (fluidsim) compilation? +if env['BF_NO_ELBEEM'] == 1: + env['CPPFLAGS'].append('-DDISABLE_ELBEEM') + env['CXXFLAGS'].append('-DDISABLE_ELBEEM') + env['CCFLAGS'].append('-DDISABLE_ELBEEM') + +#check for additional debug libnames + +if env.has_key('BF_DEBUG_LIBS'): + B.quickdebug += env['BF_DEBUG_LIBS'] + +printdebug = B.arguments.get('BF_LISTDEBUG', 0) + +# see if this linux distro has libalut + +if env['OURPLATFORM'] == 'linux2' : + if env['WITH_BF_OPENAL']: + mylib_test_source_file = """ + #include "AL/alut.h" + int main(int argc, char **argv) + { + alutGetMajorVersion(); + return 0; + } + """ + + def CheckFreeAlut(context,env): + context.Message( B.bc.OKGREEN + "Linux platform detected:\n checking for FreeAlut... " + B.bc.ENDC ) + env['LIBS'] = 'alut' + result = context.TryLink(mylib_test_source_file, '.c') + context.Result(result) + return result + + env2 = env.Copy( LIBPATH = env['BF_OPENAL'] ) + conf = Configure( env2, {'CheckFreeAlut' : CheckFreeAlut}, '.sconf_temp', '/dev/null' ) + if conf.CheckFreeAlut( env2 ): + env['BF_OPENAL_LIB'] += ' alut' + del env2 + for root, dirs, files in os.walk('.sconf_temp', topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + os.rmdir(os.path.join(root, name)) + os.rmdir(root) + +if len(B.quickdebug) > 0 and printdebug != 0: + print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC + for l in B.quickdebug: + print "\t" + l + +# check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline +if 'blenderplayer' in B.targets: + env['WITH_BF_PLAYER'] = True + +if 'blendernogame' in B.targets: + env['WITH_BF_GAMEENGINE'] = False + +# lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir +#B.root_build_dir = B.arguments.get('BF_BUILDDIR', '..'+os.sep+'build'+os.sep+platform+os.sep) +B.root_build_dir = env['BF_BUILDDIR'] +env['BUILDDIR'] = B.root_build_dir +if not B.root_build_dir[-1]==os.sep: + B.root_build_dir += os.sep + +# We do a shortcut for clean when no quicklist is given: just delete +# builddir without reading in SConscripts +do_clean = None +if 'clean' in B.targets: + do_clean = True + +if not quickie and do_clean: + if os.path.exists(B.root_build_dir): + print B.bc.HEADER+'Cleaning...'+B.bc.ENDC + dirs = os.listdir(B.root_build_dir) + for dir in dirs: + if os.path.isdir(B.root_build_dir + dir) == 1: + print "clean dir %s"%(B.root_build_dir+dir) + shutil.rmtree(B.root_build_dir+dir) + print B.bc.OKGREEN+'...done'+B.bc.ENDC + else: + print B.bc.HEADER+'Already Clean, nothing to do.'+B.bc.ENDC + Exit() + +if not os.path.isdir ( B.root_build_dir): + os.makedirs ( B.root_build_dir ) + os.makedirs ( B.root_build_dir + 'source' ) + os.makedirs ( B.root_build_dir + 'intern' ) + os.makedirs ( B.root_build_dir + 'extern' ) + os.makedirs ( B.root_build_dir + 'lib' ) + os.makedirs ( B.root_build_dir + 'bin' ) + +Help(opts.GenerateHelpText(env)) + +# default is new quieter output, but if you need to see the +# commands, do 'scons BF_QUIET=0' +bf_quietoutput = B.arguments.get('BF_QUIET', '1') +if bf_quietoutput=='1': + B.set_quiet_output(env) +else: + if toolset=='msvc': + B.msvc_hack(env) + +print B.bc.HEADER+'Building in '+B.bc.ENDC+B.root_build_dir +env.SConsignFile(B.root_build_dir+'scons-signatures') +B.init_lib_dict() + +##### END SETUP ########## + +Export('env') + +BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0) +SConscript(B.root_build_dir+'/intern/SConscript') +BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0) +SConscript(B.root_build_dir+'/extern/SConscript') +BuildDir(B.root_build_dir+'/source', 'source', duplicate=0) +SConscript(B.root_build_dir+'/source/SConscript') + +# now that we have read all SConscripts, we know what +# libraries will be built. Create list of +# libraries to give as objects to linking phase +mainlist = [] +for tp in B.possible_types: + if not tp == 'player' and not tp == 'player2': + mainlist += B.create_blender_liblist(env, tp) + +if B.arguments.get('BF_PRIORITYLIST', '0')=='1': + B.propose_priorities() + +dobj = B.buildinfo(env, "dynamic") + B.resources +thestatlibs, thelibincs = B.setup_staticlibs(env) +thesyslibs = B.setup_syslibs(env) + +env.BlenderProg(B.root_build_dir, "blender", dobj + mainlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender') +if env['WITH_BF_PLAYER']: + playerlist = B.create_blender_liblist(env, 'player') + env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, [], thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer') + +##### Now define some targets + + +#------------ INSTALL + +#-- binaries +blenderinstall = [] +if env['OURPLATFORM']=='darwin': + for prg in B.program_list: + bundle = '%s.app' % prg[0] + bundledir = os.path.dirname(bundle) + for dp, dn, df in os.walk(bundle): + if 'CVS' in dn: + dn.remove('CVS') + if '.svn' in dn: + dn.remove('.svn') + dir=env['BF_INSTALLDIR']+dp[len(bundledir):] + source=[dp+os.sep+f for f in df] + blenderinstall.append(env.Install(dir=dir,source=source)) +else: + blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list) + +#-- .blender +dotblendlist = [] +dottargetlist = [] +for dp, dn, df in os.walk('bin/.blender'): + if 'CVS' in dn: + dn.remove('CVS') + if '.svn' in dn: + dn.remove('.svn') + for f in df: + dotblendlist.append(dp+os.sep+f) + dottargetlist.append(env['BF_INSTALLDIR']+dp[3:]+os.sep+f) + +dotblenderinstall = [] +for targetdir,srcfile in zip(dottargetlist, dotblendlist): + td, tf = os.path.split(targetdir) + dotblenderinstall.append(env.Install(dir=td, source=srcfile)) + +#-- .blender/scripts +scriptinstall = [] +scriptpath='release/scripts' +for dp, dn, df in os.walk(scriptpath): + if 'CVS' in dn: + dn.remove('CVS') + if '.svn' in dn: + dn.remove('.svn') + dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):] + source=[dp+os.sep+f for f in df] + scriptinstall.append(env.Install(dir=dir,source=source)) + +#-- plugins +pluglist = [] +plugtargetlist = [] +for tp, tn, tf in os.walk('release/plugins'): + if 'CVS' in tn: + tn.remove('CVS') + if '.svn' in tn: + tn.remove('.svn') + for f in tf: + pluglist.append(tp+os.sep+f) + plugtargetlist.append(env['BF_INSTALLDIR']+tp[7:]+os.sep+f) + +plugininstall = [] +for targetdir,srcfile in zip(plugtargetlist, pluglist): + td, tf = os.path.split(targetdir) + plugininstall.append(env.Install(dir=td, source=srcfile)) + +textlist = [] +texttargetlist = [] +for tp, tn, tf in os.walk('release/text'): + if 'CVS' in tn: + tn.remove('CVS') + if '.svn' in tn: + tn.remove('.svn') + for f in tf: + textlist.append(tp+os.sep+f) + +textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist) + +allinstall = [blenderinstall, dotblenderinstall, scriptinstall, plugininstall, textinstall] + +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'): + dllsources = ['${LCGDIR}/gettext/lib/gnu_gettext.dll', + '${LCGDIR}/png/lib/libpng.dll', + '#release/windows/extra/python25.zip', + '#release/windows/extra/zlib.pyd', + '${LCGDIR}/sdl/lib/SDL.dll', + '${LCGDIR}/zlib/lib/zlib.dll', + '${LCGDIR}/tiff/lib/libtiff.dll'] + if env['BF_DEBUG']: + dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}.dll') + else: + dllsources.append('${LCGDIR}/python/lib/${BF_PYTHON_LIB}.dll') + if env['OURPLATFORM'] == 'win32-mingw': + dllsources += ['${LCGDIR}/pthreads/lib/pthreadGC2.dll'] + else: + dllsources += ['${LCGDIR}/pthreads/lib/pthreadVC2.dll'] + if env['WITH_BF_ICONV']: + dllsources += ['${LCGDIR}/iconv/lib/iconv.dll'] + if env['WITH_BF_FFMPEG']: + dllsources += ['${LCGDIR}/ffmpeg/lib/avcodec-51.dll', + '${LCGDIR}/ffmpeg/lib/avformat-51.dll', + '${LCGDIR}/ffmpeg/lib/avutil-49.dll'] + windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources) + allinstall += windlls + +installtarget = env.Alias('install', allinstall) +bininstalltarget = env.Alias('install-bin', blenderinstall) + +nsisaction = env.Action(btools.NSIS_Installer, btools.NSIS_print) +nsiscmd = env.Command('nsisinstaller', None, nsisaction) +nsisalias = env.Alias('nsis', nsiscmd) + +if env['WITH_BF_PLAYER']: + blenderplayer = env.Alias('blenderplayer', B.program_list) + Depends(blenderplayer,installtarget) + +if not env['WITH_BF_GAMEENGINE']: + blendernogame = env.Alias('blendernogame', B.program_list) + Depends(blendernogame,installtarget) + +Depends(nsiscmd, allinstall) + +Default(B.program_list) + +if not env['WITHOUT_BF_INSTALL']: + Default(installtarget) + +#------------ RELEASE +# TODO: zipup the installation + +#------------ BLENDERPLAYER +# TODO: build stubs and link into blenderplayer + +#------------ EPYDOC +# TODO: run epydoc + diff --git a/bin/.blender/.Blanguages b/bin/.blender/.Blanguages new file mode 100644 index 00000000000..b50b3097eca --- /dev/null +++ b/bin/.blender/.Blanguages @@ -0,0 +1,21 @@ +English:en_US +Japanese:ja_JP +Dutch:nl_NL +Italian:it_IT +German:de_DE +Finnish:fi_FI +Swedish:sv_SE +French:fr_FR +Spanish:es_ES +Catalan:ca_ES +Czech:cs_CZ +Brazilian Portuguese:pt_BR +Simplified Chinese:zh_CN +Russian:ru_RU +Croatian:hr_HR +Serbian:sr +Ukrainian:uk +Polish:pl_PL +Romanian:ro +Arabic:ar +Bulgarian:bg diff --git a/bin/.blender/.bfont.ttf b/bin/.blender/.bfont.ttf new file mode 100644 index 00000000000..58cd6b5e61e Binary files /dev/null and b/bin/.blender/.bfont.ttf differ diff --git a/blenderplayer/CMakeLists.txt b/blenderplayer/CMakeLists.txt new file mode 100644 index 00000000000..4a2fc330077 --- /dev/null +++ b/blenderplayer/CMakeLists.txt @@ -0,0 +1,124 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +MESSAGE(STATUS "Configuring blenderplayer") + +SETUP_LIBDIRS() + +IF(WITH_QUICKTIME) + ADD_DEFINITIONS(-DWITH_QUICKTIME) +ENDIF(WITH_QUICKTIME) + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dna.c + COMMAND ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/makesdna ${CMAKE_CURRENT_BINARY_DIR}/dna.c ${CMAKE_SOURCE_DIR}/source/blender/makesdna/ + DEPENDS ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/makesdna +) + +IF(WIN32) + ADD_EXECUTABLE(blenderplayer ${EXETYPE} ${CMAKE_CURRENT_BINARY_DIR}/dna.c ../source/icons/winblender.rc) +ELSE(WIN32) + ADD_EXECUTABLE(blenderplayer ${CMAKE_CURRENT_BINARY_DIR}/dna.c) +ENDIF(WIN32) + +ADD_DEPENDENCIES(blenderplayer makesdna) + +FILE(READ ${CMAKE_BINARY_DIR}/cmake_blender_libs.txt BLENDER_LINK_LIBS) + +SET(BLENDER_LINK_LIBS ${BLENDER_LINK_LIBS} gp_common gp_ghost blenkernel_blc) + +IF(UNIX) + # Sort libraries + SET(BLENDER_SORTED_LIBS + gp_ghost + gp_common + bf_string + bf_ghost + bf_blenkernel + verse + bf_blenkernel + bf_decimation + bf_blenloader + bf_blenpluginapi + bf_blroutines + bf_converter + bf_sumo + bf_ketsji + extern_solid + extern_qhull + bf_bullet + bf_common + bf_dummy + bf_logic + bf_rasterizer + bf_oglrasterizer + bf_expressions + bf_scenegraph + bf_moto + bf_soundsystem + bf_kernel + bf_nodes + bf_imbuf + bf_avi + kx_network + bf_ngnetwork + bf_loopbacknetwork + extern_bullet + bf_guardedalloc + bf_memutil + bf_bmfont + bf_blenlib + bf_cineon + bf_openexr + bf_ftfont + extern_ftgl + bf_readblenfile + blenkernel_blc + bf_quicktime + ) + + FOREACH(SORTLIB ${BLENDER_SORTED_LIBS}) + SET(REMLIB ${SORTLIB}) + FOREACH(SEARCHLIB ${BLENDER_LINK_LIBS}) + IF(${SEARCHLIB} STREQUAL ${SORTLIB}) + SET(REMLIB "") + ENDIF(${SEARCHLIB} STREQUAL ${SORTLIB}) + ENDFOREACH(SEARCHLIB) + IF(REMLIB) + MESSAGE(STATUS "Removing library ${REMLIB} from blenderplayer linking because: not configured") + LIST(REMOVE_ITEM BLENDER_SORTED_LIBS ${REMLIB}) + ENDIF(REMLIB) + ENDFOREACH(SORTLIB) + + TARGET_LINK_LIBRARIES(blenderplayer ${BLENDER_SORTED_LIBS}) +ELSE(UNIX) + TARGET_LINK_LIBRARIES(blenderplayer ${BLENDER_LINK_LIBS}) +ENDIF(UNIX) + +SETUP_LIBLINKS(blenderplayer) diff --git a/config/darwin-config.py b/config/darwin-config.py new file mode 100644 index 00000000000..5a2fc93c52d --- /dev/null +++ b/config/darwin-config.py @@ -0,0 +1,185 @@ +LCGDIR = '#../lib/darwin-6.1-powerpc' +LIBDIR = '${LCGDIR}' + +# enable ffmpeg support +WITH_BF_FFMPEG = 'true' # -DWITH_FFMPEG +BF_FFMPEG = LIBDIR +'/ffmpeg' +BF_FFMPEG_INC = '${BF_FFMPEG}/include' +BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib' +BF_FFMPEG_LIB = 'avformat.a avcodec.a avutil.a' + +WITH_BF_VERSE = 'false' +BF_VERSE = "#extern/verse/dist" +BF_VERSE_LIBPATH = "${BF_BUILDDIR}/extern/verse/dist" +BF_VERSE_INCLUDE = BF_VERSE +BF_VERSE_LIBS = "libverse" + +# python.org libs install in /library +BF_PYTHON_VERSION = '2.3' +if BF_PYTHON_VERSION=='2.3': + BF_PYTHON = '/System/Library/Frameworks/Python.framework/Versions/' +else: + BF_PYTHON = '/Library/Frameworks/Python.framework/Versions/' + +BF_PYTHON_INC = '${BF_PYTHON}${BF_PYTHON_VERSION}/include/python${BF_PYTHON_VERSION}' +BF_PYTHON_BINARY = '${BF_PYTHON}${BF_PYTHON_VERSION}/bin/python${BF_PYTHON_VERSION}' +BF_PYTHON_LIB = '' +BF_PYTHON_LIBPATH = '${BF_PYTHON}${BF_PYTHON_VERSION}/lib/python${BF_PYTHON_VERSION}/config' +BF_PYTHON_LINKFLAGS = '-u __dummy -u _PyMac_Error -framework System -framework Python' + +WITH_BF_OPENAL = 'true' +#different lib must be used following version of gcc +# for gcc 3.3 +#BF_OPENAL = LIBDIR + '/openal' +# for gcc 3.4 +BF_OPENAL = '#../lib/darwin-8.0.0-powerpc/openal' + +BF_OPENAL_INC = '${BF_OPENAL}/include' +BF_OPENAL_LIB = 'openal' +BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib' + +WITH_BF_SDL = 'true' +BF_SDL = LIBDIR + '/sdl' #$(shell sdl-config --prefix) +BF_SDL_INC = '${BF_SDL}/include' #$(shell $(BF_SDL)/bin/sdl-config --cflags) +BF_SDL_LIB = 'SDL' #BF_SDL #$(shell $(BF_SDL)/bin/sdl-config --libs) -lSDL_mixer +BF_SDL_LIBPATH = '${BF_SDL}/lib' + +WITH_BF_FMOD = 'false' +BF_FMOD = LIBDIR + '/fmod' + +WITH_BF_OPENEXR = 'true' +BF_OPENEXR = '${LCGDIR}/openexr' +BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR' +BF_OPENEXR_LIB = ' Iex Half IlmImf Imath IlmThread' +BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib' + +WITH_BF_DDS = 'true' + +WITH_BF_JPEG = 'true' +BF_JPEG = LIBDIR + '/jpeg' +BF_JPEG_INC = '${BF_JPEG}/include' +BF_JPEG_LIB = 'jpeg' +BF_JPEG_LIBPATH = '${BF_JPEG}/lib' + +WITH_BF_PNG = 'true' +BF_PNG = LIBDIR + '/png' +BF_PNG_INC = '${BF_PNG}/include' +BF_PNG_LIB = 'png' +BF_PNG_LIBPATH = '${BF_PNG}/lib' + +BF_TIFF = LIBDIR + '/tiff' +BF_TIFF_INC = '${BF_TIFF}/include' + +WITH_BF_ZLIB = 'true' +BF_ZLIB = '/usr' +BF_ZLIB_INC = '${BF_ZLIB}/include' +BF_ZLIB_LIB = 'z' + +WITH_BF_INTERNATIONAL = 'true' + +BF_GETTEXT = LIBDIR + '/gettext' +BF_GETTEXT_INC = '${BF_GETTEXT}/include' +BF_GETTEXT_LIB = 'intl' +BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' + +WITH_BF_FTGL = 'true' +BF_FTGL = '#extern/bFTGL' +BF_FTGL_INC = '${BF_FTGL}/include' +BF_FTGL_LIB = 'extern_ftgl' + +WITH_BF_GAMEENGINE='true' +WITH_BF_PLAYER='true' + +WITH_BF_ODE = 'false' +BF_ODE = LIBDIR + '/ode' +BF_ODE_INC = '${BF_ODE}/include' +BF_ODE_LIB = '${BF_ODE}/lib/libode.a' + +WITH_BF_BULLET = 'true' +BF_BULLET = '#extern/bullet2/src' +BF_BULLET_INC = '${BF_BULLET}' +BF_BULLET_LIB = 'extern_bullet' + +BF_SOLID = '#extern/solid' +BF_SOLID_INC = '${BF_SOLID}' +BF_SOLID_LIB = 'extern_solid' + +WITH_BF_YAFRAY = 'true' + +#WITH_BF_NSPR = 'true' +#BF_NSPR = $(LIBDIR)/nspr +#BF_NSPR_INC = -I$(BF_NSPR)/include -I$(BF_NSPR)/include/nspr +#BF_NSPR_LIB = + +# Uncomment the following line to use Mozilla inplace of netscape +#CPPFLAGS += -DMOZ_NOT_NET +# Location of MOZILLA/Netscape header files... +#BF_MOZILLA = $(LIBDIR)/mozilla +#BF_MOZILLA_INC = -I$(BF_MOZILLA)/include/mozilla/nspr -I$(BF_MOZILLA)/include/mozilla -I$(BF_MOZILLA)/include/mozilla/xpcom -I$(BF_MOZILLA)/include/mozilla/idl +#BF_MOZILLA_LIB = +# Will fall back to look in BF_MOZILLA_INC/nspr and BF_MOZILLA_LIB +# if this is not set. +# +# Be paranoid regarding library creation (do not update archives) +#BF_PARANOID = 'true' + +# enable freetype2 support for text objects +BF_FREETYPE = LIBDIR + '/freetype' +BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2' +BF_FREETYPE_LIB = 'freetype' +BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib' + +WITH_BF_QUICKTIME = 'true' # -DWITH_QUICKTIME + +WITH_BF_ICONV = 'false' +BF_ICONV = LIBDIR + "/iconv" +BF_ICONV_INC = '${BF_ICONV}/include' +BF_ICONV_LIB = 'iconv' +BF_ICONV_LIBPATH = '${BF_ICONV}/lib' + +# Mesa Libs should go here if your using them as well.... +WITH_BF_STATICOPENGL = 'true' +BF_OPENGL_LIB = 'GL GLU' +BF_OPENGL_LIBPATH = '/System/Library/Frameworks/OpenGL.framework/Libraries' +BF_OPENGL_LINKFLAGS = '-framework OpenGL' + +## +##CC = gcc +##CCC = g++ +##ifeq ($CPU),alpha) +## CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing -mieee + +CFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing'] + +CPPFLAGS = ['-fpascal-strings'] +CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing', '-fpascal-strings'] +CXXFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing', '-fpascal-strings'] +PLATFORM_LINKFLAGS = '-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime' +REL_CFLAGS = ['-O2'] +REL_CCFLAGS = ['-O2'] +##BF_DEPEND = 'true' +## +##AR = ar +##ARFLAGS = ruv +##ARFLAGSQUIET = ru +## +CC = 'gcc' +CXX = 'g++' +C_WARN = ' -Wall -Wno-long-double -Wdeclaration-after-statement ' + +CC_WARN = ' -Wall -Wno-long-double' + +##FIX_STUBS_WARNINGS = -Wno-unused + +LLIBS = 'stdc++ SystemStubs' +##LOPTS = --dynamic +##DYNLDFLAGS = -shared $(LDFLAGS) + +BF_PROFILE_FLAGS = ' -pg -g ' +BF_PROFILE = 'false' + +BF_DEBUG = 'false' +BF_DEBUG_FLAGS = '-g' + +BF_BUILDDIR='../build/darwin' +BF_INSTALLDIR='../install/darwin' diff --git a/config/linux2-config.py b/config/linux2-config.py new file mode 100644 index 00000000000..4bf7e755c49 --- /dev/null +++ b/config/linux2-config.py @@ -0,0 +1,175 @@ +LCGDIR = '../lib/linux2' +LIBDIR = "${LCGDIR}" + +WITH_BF_VERSE = 'false' +BF_VERSE_INCLUDE = "#extern/verse/dist" + +BF_PYTHON = '/usr' +BF_PYTHON_VERSION = '2.5' +BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' +BF_PYTHON_BINARY = '${BF_PYTHON}/bin/python${BF_PYTHON_VERSION}' +BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION}' #BF_PYTHON+'/lib/python'+BF_PYTHON_VERSION+'/config/libpython'+BF_PYTHON_VERSION+'.a' +BF_PYTHON_LINKFLAGS = ['-Xlinker', '-export-dynamic'] + +WITH_BF_OPENAL = 'true' +BF_OPENAL = '/usr' +BF_OPENAL_INC = '${BF_OPENAL}/include' +BF_OPENAL_LIB = 'openal' +# some distros have a separate libalut +# if you get linker complaints, you need to uncomment the line below +# BF_OPENAL_LIB = 'openal alut' + +WITH_BF_SDL = 'true' +BF_SDL = '/usr' #$(shell sdl-config --prefix) +BF_SDL_INC = '${BF_SDL}/include/SDL' #$(shell $(BF_SDL)/bin/sdl-config --cflags) +BF_SDL_LIB = 'SDL' #BF_SDL #$(shell $(BF_SDL)/bin/sdl-config --libs) -lSDL_mixer + +WITH_BF_FMOD = 'false' +BF_FMOD = LIBDIR + '/fmod' + +WITH_BF_OPENEXR = 'true' +BF_OPENEXR = '/usr' +BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR' +BF_OPENEXR_LIB = 'Half IlmImf Iex Imath ' + +WITH_BF_DDS = 'true' + +WITH_BF_JPEG = 'true' +BF_JPEG = '/usr' +BF_JPEG_INC = '${BF_JPEG}/include' +BF_JPEG_LIB = 'jpeg' + +WITH_BF_PNG = 'true' +BF_PNG = '/usr' +BF_PNG_INC = '${BF_PNG}/include' +BF_PNG_LIB = 'png' + +BF_TIFF = '/usr' +BF_TIFF_INC = '${BF_TIFF}/include' + +WITH_BF_ZLIB = 'true' +BF_ZLIB = '/usr' +BF_ZLIB_INC = '${BF_ZLIB}/include' +BF_ZLIB_LIB = 'z' + +WITH_BF_INTERNATIONAL = 'true' + +BF_GETTEXT = '/usr' +BF_GETTEXT_INC = '${BF_GETTEXT}/include' +BF_GETTEXT_LIB = 'gettextlib' +BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' + +WITH_BF_FTGL = 'true' +BF_FTGL = '#extern/bFTGL' +BF_FTGL_INC = '${BF_FTGL}/include' +BF_FTGL_LIB = 'extern_ftgl' + +WITH_BF_GAMEENGINE='false' + +WITH_BF_ODE = 'false' +BF_ODE = LIBDIR + '/ode' +BF_ODE_INC = BF_ODE + '/include' +BF_ODE_LIB = BF_ODE + '/lib/libode.a' + +WITH_BF_BULLET = 'true' +BF_BULLET = '#extern/bullet2/src' +BF_BULLET_INC = '${BF_BULLET}' +BF_BULLET_LIB = 'extern_bullet' + +BF_SOLID = '#extern/solid' +BF_SOLID_INC = '${BF_SOLID}' +BF_SOLID_LIB = 'extern_solid' + +WITH_BF_YAFRAY = 'true' + +#WITH_BF_NSPR = 'true' +#BF_NSPR = $(LIBDIR)/nspr +#BF_NSPR_INC = -I$(BF_NSPR)/include -I$(BF_NSPR)/include/nspr +#BF_NSPR_LIB = + +# Uncomment the following line to use Mozilla inplace of netscape +#CPPFLAGS += -DMOZ_NOT_NET +# Location of MOZILLA/Netscape header files... +#BF_MOZILLA = $(LIBDIR)/mozilla +#BF_MOZILLA_INC = -I$(BF_MOZILLA)/include/mozilla/nspr -I$(BF_MOZILLA)/include/mozilla -I$(BF_MOZILLA)/include/mozilla/xpcom -I$(BF_MOZILLA)/include/mozilla/idl +#BF_MOZILLA_LIB = +# Will fall back to look in BF_MOZILLA_INC/nspr and BF_MOZILLA_LIB +# if this is not set. +# +# Be paranoid regarding library creation (do not update archives) +#BF_PARANOID = 'true' + +# enable freetype2 support for text objects +BF_FREETYPE = '/usr' +BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2' +BF_FREETYPE_LIB = 'freetype' + +WITH_BF_QUICKTIME = 'false' # -DWITH_QUICKTIME +BF_QUICKTIME = '/usr/local' +BF_QUICKTIME_INC = '${BF_QUICKTIME}/include' + +WITH_BF_ICONV = 'false' +BF_ICONV = LIBDIR + "/iconv" +BF_ICONV_INC = '${BF_ICONV}/include' +BF_ICONV_LIB = 'iconv' +BF_ICONV_LIBPATH = '${BF_ICONV}/lib' + +# enable ffmpeg support +WITH_BF_FFMPEG = 'true' # -DWITH_FFMPEG +BF_FFMPEG = '#extern/ffmpeg' +BF_FFMPEG_LIB = '' +# Uncomment the following two lines to use system's ffmpeg +# BF_FFMPEG = '/usr' +# BF_FFMPEG_LIB = 'avformat avcodec swscale avutil' +BF_FFMPEG_INC = '${BF_FFMPEG}/include' +BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib' + +# Mesa Libs should go here if your using them as well.... +WITH_BF_STATICOPENGL = 'false' +BF_OPENGL = '/usr' +BF_OPENGL_INC = '${BF_OPENGL}/include' +BF_OPENGL_LIB = 'GL GLU X11 Xi' +BF_OPENGL_LIBPATH = '/usr/X11R6/lib' +BF_OPENGL_LIB_STATIC = '${BF_OPENGL}/libGL.a ${BF_OPENGL}/libGLU.a ${BF_OPENGL}/libXxf86vm.a ${BF_OPENGL}/libX11.a ${BF_OPENGL}/libXi.a ${BF_OPENGL}/libXext.a ${BF_OPENGL}/libXxf86vm.a' + +## +CC = 'gcc' +CXX = 'g++' +##ifeq ($CPU),alpha) +## CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing -mieee + +CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing'] + +CPPFLAGS = ['-DXP_UNIX'] +CXXFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing'] +REL_CFLAGS = ['-O2'] +REL_CCFLAGS = ['-O2'] +##BF_DEPEND = 'true' +## +##AR = ar +##ARFLAGS = ruv +##ARFLAGSQUIET = ru +## +C_WARN = '-Wall -Wno-char-subscripts -Wdeclaration-after-statement' + +CC_WARN = '-Wall' + +##FIX_STUBS_WARNINGS = -Wno-unused + +LLIBS = 'util c m dl pthread stdc++' +##LOPTS = --dynamic +##DYNLDFLAGS = -shared $(LDFLAGS) + +BF_PROFILE_FLAGS = ['-pg','-g'] +BF_PROFILE = 'false' + +BF_DEBUG = 'false' +BF_DEBUG_FLAGS = '-g' + +BF_BUILDDIR = '../build/linux2' +BF_INSTALLDIR='../install/linux2' + + +#Link against pthread +PLATFORM_LINKFLAGS = ['-pthread'] + diff --git a/config/linuxcross-config.py b/config/linuxcross-config.py new file mode 100644 index 00000000000..e6c4e8769b4 --- /dev/null +++ b/config/linuxcross-config.py @@ -0,0 +1,139 @@ +LCGDIR = '../lib/windows' +LIBDIR = '${LCGDIR}' + +WITH_BF_VERSE = 'false' +BF_VERSE_INCLUDE = "#extern/verse/dist" + +WITH_BF_YAFRAY = 'true' + +BF_PYTHON = LIBDIR + '/python' +BF_PYTHON_VERSION = '2.5' +BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' +BF_PYTHON_BINARY = 'python' +BF_PYTHON_LIB = 'python25' +BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib' + +WITH_BF_OPENAL = 'true' +BF_OPENAL = LIBDIR + '/openal' +BF_OPENAL_INC = '${BF_OPENAL}/include' +BF_OPENAL_LIB = 'openal_static' +BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib' + +WITH_BF_SDL = 'true' +BF_SDL = LIBDIR + '/sdl' +BF_SDL_INC = '${BF_SDL}/include' +BF_SDL_LIB = 'SDL' +BF_SDL_LIBPATH = '${BF_SDL}/lib' + +BF_PTHREADS = LIBDIR + '/pthreads' +BF_PTHREADS_INC = '${BF_PTHREADS}/include' +BF_PTHREADS_LIB = 'pthreadGC2' +BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib' + +WITH_BF_FMOD = 'false' +BF_FMOD = LIBDIR + '/fmod' + +WITH_BF_OPENEXR = 'true' +BF_OPENEXR = LIBDIR + '/gcc/openexr' +BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR' +BF_OPENEXR_LIB = ' Half IlmImf Iex ' +BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib' + +WITH_BF_DDS = 'true' + +WITH_BF_JPEG = 'true' +BF_JPEG = LIBDIR + '/jpeg' +BF_JPEG_INC = '${BF_JPEG}/include' +BF_JPEG_LIB = 'jpeg' +BF_JPEG_LIBPATH = '${BF_JPEG}/lib' + +WITH_BF_PNG = 'true' +BF_PNG = LIBDIR + '/png' +BF_PNG_INC = '${BF_PNG}/include' +BF_PNG_LIB = 'png' +BF_PNG_LIBPATH = '${BF_PNG}/lib' + +BF_TIFF = LIBDIR + '/tiff' +BF_TIFF_INC = '${BF_TIFF}/include' + +WITH_BF_ZLIB = 'true' +BF_ZLIB = LIBDIR + '/zlib' +BF_ZLIB_INC = '${BF_ZLIB}/include' +#BF_ZLIB_LIB = 'z' +BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' + +WITH_BF_INTERNATIONAL = 'true' + +BF_GETTEXT = LIBDIR + '/gettext' +BF_GETTEXT_INC = '${BF_GETTEXT}/include' +BF_GETTEXT_LIB = 'gnu_gettext' +BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' + +WITH_BF_FTGL = 'true' +BF_FTGL = LIBDIR + '/ftgl' +BF_FTGL_INC = '${BF_FTGL}/include' +BF_FTGL_LIB = 'extern_ftgl' + +WITH_BF_GAMEENGINE = 'false' + +WITH_BF_ODE = 'true' +BF_ODE = LIBDIR + '/ode' +BF_ODE_INC = BF_ODE + '/include' +BF_ODE_LIB = BF_ODE + '/lib/libode.a' + +WITH_BF_BULLET = 'true' +BF_BULLET = '#extern/bullet2/src' +BF_BULLET_INC = '${BF_BULLET}' +BF_BULLET_LIB = 'extern_bullet' + +BF_SOLID = '#extern/solid' +BF_SOLID_INC = '${BF_SOLID}' +BF_SOLID_LIB = 'extern_solid' + +# enable freetype2 support for text objects +BF_FREETYPE = LIBDIR + '/gcc/freetype' +BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2' +BF_FREETYPE_LIB = 'freetype' +BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib' + +WITH_BF_QUICKTIME = 'false' # -DWITH_QUICKTIME +BF_QUICKTIME = '/usr/local' +BF_QUICKTIME_INC = '${BF_QUICKTIME}/include' + +WITH_BF_ICONV = 'false' +BF_ICONV = LIBDIR + "/iconv" +BF_ICONV_INC = '${BF_ICONV}/include' +BF_ICONV_LIB = 'iconv' +BF_ICONV_LIBPATH = '${BF_ICONV}/lib' + +# Mesa Libs should go here if your using them as well.... +WITH_BF_STATICOPENGL = 'false' +BF_OPENGL = 'C:\\MingW' +BF_OPENGL_INC = '${BF_OPENGL}/include' +BF_OPENGL_LIBINC = '${BF_OPENGL}/lib' +BF_OPENGL_LIB = 'opengl32 glu32' +BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a', + '${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a', + '${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ] + +CC = 'i586-mingw32msvc-gcc' +CXX = 'i586-mingw32msvc-g++' + +CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ] + +CPPFLAGS = [ '-DXP_UNIX', '-DWIN32', '-DFREE_WINDOWS' ] +CXXFLAGS = ['-pipe', '-mwindows', '-funsigned-char', '-fno-strict-aliasing' ] +REL_CFLAGS = [ '-O2' ] +REL_CCFLAGS = [ '-O2' ] +C_WARN = [ '-Wall' , '-Wno-char-subscripts', '-Wdeclaration-after-statement' ] + +CC_WARN = [ '-Wall' ] + + +LLIBS = [ '-ldxguid', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz'] #'-lutil', '-lc', '-lm', '-ldl', '-lpthread' ] + +BF_DEBUG = 'false' +BF_DEBUG_FLAGS= '' + +BF_BUILDDIR = '../build/linuxcross' +BF_INSTALLDIR='../install/linuxcross' diff --git a/config/openbsd3-config.py b/config/openbsd3-config.py new file mode 100644 index 00000000000..f7f254973af --- /dev/null +++ b/config/openbsd3-config.py @@ -0,0 +1,160 @@ +LCGDIR = '../lib/openbsd3' +LIBDIR = '${LCGDIR}' + +BF_PYTHON = '/usr/local' +BF_PYTHON_VERSION = '2.5' +BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' +BF_PYTHON_BINARY = '${BF_PYTHON}/bin/python${BF_PYTHON_VERSION}' +BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION}' +BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib/python${BF_PYTHON_VERSION}/config' + +WITH_BF_OPENAL = 'false' +#BF_OPENAL = LIBDIR + '/openal' +#BF_OPENAL_INC = '${BF_OPENAL}/include' +#BF_OPENAL_LIB = 'openal' +#BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib' + +WITH_BF_SDL = 'true' +BF_SDL = '/usr/local' #$(shell sdl-config --prefix) +BF_SDL_INC = '${BF_SDL}/include/SDL' #$(shell $(BF_SDL)/bin/sdl-config --cflags) +BF_SDL_LIB = 'SDL' #BF_SDL #$(shell $(BF_SDL)/bin/sdl-config --libs) -lSDL_mixer +BF_SDL_LIBPATH = '${BF_SDL}/lib' + +WITH_BF_FMOD = 'false' +BF_FMOD = LIBDIR + '/fmod' + +WITH_BF_OPENEXR = 'false' +BF_OPENEXR = '/usr/local' +BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR' +BF_OPENEXR_LIB = 'Half IlmImf Iex Imath ' + +WITH_BF_DDS = 'true' + +WITH_BF_JPEG = 'true' +BF_JPEG = '/usr/local' +BF_JPEG_INC = '${BF_JPEG}/include' +BF_JPEG_LIB = 'jpeg' +BF_JPEG_LIBPATH = '${BF_JPEG}/lib' + +WITH_BF_PNG = 'true' +BF_PNG = '/usr/local' +BF_PNG_INC = '${BF_PNG}/include/libpng' +BF_PNG_LIB = 'png' +BF_PNG_LIBPATH = '${BF_PNG}/lib' + +BF_TIFF = '/usr/local' +BF_TIFF_INC = '${BF_TIFF}/include' + +WITH_BF_ZLIB = 'true' +BF_ZLIB = '/usr/local' +BF_ZLIB_INC = '${BF_ZLIB}/include' +BF_ZLIB_LIB = 'z' + +WITH_BF_INTERNATIONAL = 'true' + +BF_GETTEXT = '/usr/local' +BF_GETTEXT_INC = '${BF_GETTEXT}/include' +BF_GETTEXT_LIB = 'intl iconv' +BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' + +WITH_BF_FTGL = 'true' +BF_FTGL = '#extern/bFTGL' +BF_FTGL_INC = '${BF_FTGL}/include' +BF_FTGL_LIB = 'extern_ftgl' + +WITH_BF_GAMEENGINE='false' + +WITH_BF_ODE = 'false' +BF_ODE = LIBDIR + '/ode' +BF_ODE_INC = '${BF_ODE}/include' +BF_ODE_LIB = '${BF_ODE}/lib/libode.a' + +WITH_BF_BULLET = 'true' +BF_BULLET = '#extern/bullet2/src' +BF_BULLET_INC = '${BF_BULLET}' +BF_BULLET_LIB = 'extern_bullet' + +BF_SOLID = '#extern/solid' +BF_SOLID_INC = '${BF_SOLID}' +BF_SOLID_LIB = 'extern_solid' + +WITH_BF_YAFRAY = 'true' + +#WITH_BF_NSPR = 'true' +#BF_NSPR = $(LIBDIR)/nspr +#BF_NSPR_INC = -I$(BF_NSPR)/include -I$(BF_NSPR)/include/nspr +#BF_NSPR_LIB = + +# Uncomment the following line to use Mozilla inplace of netscape +#CPPFLAGS += -DMOZ_NOT_NET +# Location of MOZILLA/Netscape header files... +#BF_MOZILLA = $(LIBDIR)/mozilla +#BF_MOZILLA_INC = -I$(BF_MOZILLA)/include/mozilla/nspr -I$(BF_MOZILLA)/include/mozilla -I$(BF_MOZILLA)/include/mozilla/xpcom -I$(BF_MOZILLA)/include/mozilla/idl +#BF_MOZILLA_LIB = +# Will fall back to look in BF_MOZILLA_INC/nspr and BF_MOZILLA_LIB +# if this is not set. +# +# Be paranoid regarding library creation (do not update archives) +#BF_PARANOID = 'true' + +# enable freetype2 support for text objects +BF_FREETYPE = '/usr/X11R6' +BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2' +BF_FREETYPE_LIB = 'freetype' +BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib' + +WITH_BF_QUICKTIME = 'false' # -DWITH_QUICKTIME + +WITH_BF_ICONV = 'false' +BF_ICONV = LIBDIR + "/iconv" +BF_ICONV_INC = '${BF_ICONV}/include' +BF_ICONV_LIB = 'iconv' +BF_ICONV_LIBPATH = '${BF_ICONV}/lib' + +# Mesa Libs should go here if your using them as well.... +WITH_BF_STATICOPENGL = 'true' +BF_OPENGL = '/usr/X11R6' +BF_OPENGL_INC = '${BF_OPENGL}/include' +BF_OPENGL_LIB = 'GL GLU X11 Xi' +BF_OPENGL_LIBPATH = '${BF_OPENGL}/lib' +BF_OPENGL_LIB_STATIC = '${BF_OPENGL_LIBPATH}/libGL.a ${BF_OPENGL_LIBPATH}/libGLU.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a ${BF_OPENGL_LIBPATH}/libX11.a ${BF_OPENGL_LIBPATH}/libXi.a ${BF_OPENGL_LIBPATH}/libXext.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a' + +## +##CC = gcc +##CCC = g++ +##ifeq ($CPU),alpha) +## CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing -mieee + +CFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing'] + +CPPFLAGS = [] +CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing'] +CXXFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing'] +REL_CFLAGS = ['-O2'] +REL_CCFLAGS = ['-O2'] +##BF_DEPEND = 'true' +## +##AR = ar +##ARFLAGS = ruv +##ARFLAGSQUIET = ru +## +CC = 'gcc' +CXX = 'g++' +C_WARN = '-Wall -Wdeclaration-after-statement' + +CC_WARN = '-Wall' + +##FIX_STUBS_WARNINGS = -Wno-unused + +LLIBS = 'm stdc++ pthread util' +##LOPTS = --dynamic +##DYNLDFLAGS = -shared $(LDFLAGS) + +BF_PROFILE_FLAGS = ' -pg -g ' +BF_PROFILE = 'false' + +BF_DEBUG = 'false' +BF_DEBUG_FLAGS = '-g' + +BF_BUILDDIR='../build/openbsd3' +BF_INSTALLDIR='../install/openbsd3' diff --git a/config/sunos5-config.py b/config/sunos5-config.py new file mode 100644 index 00000000000..b3ca0e267ff --- /dev/null +++ b/config/sunos5-config.py @@ -0,0 +1,171 @@ +LCGDIR = '../lib/sunos5' +LIBDIR = '${LCGDIR}' + +BF_PYTHON = '/usr/local' +BF_PYTHON_VERSION = '2.5' +BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' +BF_PYTHON_BINARY = '${BF_PYTHON}/bin/python${BF_PYTHON_VERSION}' +BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION}' #BF_PYTHON+'/lib/python'+BF_PYTHON_VERSION+'/config/libpython'+BF_PYTHON_VERSION+'.a' +BF_PYTHON_LINKFLAGS = ['-Xlinker', '-export-dynamic'] + +WITH_BF_OPENAL = 'true' +BF_OPENAL = '/usr/local' +BF_OPENAL_INC = '${BF_OPENAL}/include' +BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib' +BF_OPENAL_LIB = 'openal' + +WITH_BF_SDL = 'true' +BF_SDL = '/usr/local' #$(shell sdl-config --prefix) +BF_SDL_INC = '${BF_SDL}/include/SDL' #$(shell $(BF_SDL)/bin/sdl-config --cflags) +BF_SDL_LIBPATH = '${BF_SDL}/lib' +BF_SDL_LIB = 'SDL' #BF_SDL #$(shell $(BF_SDL)/bin/sdl-config --libs) -lSDL_mixer + +WITH_BF_FMOD = 'false' +BF_FMOD = LIBDIR + '/fmod' + +WITH_BF_OPENEXR = 'true' +BF_OPENEXR = '/usr/local' +BF_OPENEXR_INC = ['${BF_OPENEXR}/include', '${BF_OPENEXR}/include/OpenEXR' ] +BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib' +BF_OPENEXR_LIB = 'Half IlmImf Iex Imath ' + +WITH_BF_DDS = 'true' + +WITH_BF_JPEG = 'true' +BF_JPEG = '/usr/local' +BF_JPEG_INC = '${BF_JPEG}/include' +BF_JPEG_LIBPATH = '${BF_JPEG}/lib' +BF_JPEG_LIB = 'jpeg' + +WITH_BF_PNG = 'true' +BF_PNG = '/usr/local' +BF_PNG_INC = '${BF_PNG}/include' +BF_PNG_LIBPATH = '${BF_PNG}/lib' +BF_PNG_LIB = 'png' + +BF_TIFF = '/usr/local' +BF_TIFF_INC = '${BF_TIFF}/include' + +WITH_BF_ZLIB = 'true' +BF_ZLIB = '/usr' +BF_ZLIB_INC = '${BF_ZLIB}/include' +BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' +BF_ZLIB_LIB = 'z' + +WITH_BF_INTERNATIONAL = 'true' + +BF_GETTEXT = '/usr/local' +BF_GETTEXT_INC = '${BF_GETTEXT}/include' +BF_GETTEXT_LIB = 'gettextlib' +BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' + +WITH_BF_FTGL = 'true' +BF_FTGL = '#extern/bFTGL' +BF_FTGL_INC = '${BF_FTGL}/include' +BF_FTGL_LIB = 'extern_ftgl' + +WITH_BF_GAMEENGINE='false' + +WITH_BF_ODE = 'false' +BF_ODE = LIBDIR + '/ode' +BF_ODE_INC = BF_ODE + '/include' +BF_ODE_LIB = BF_ODE + '/lib/libode.a' + +WITH_BF_BULLET = 'true' +BF_BULLET = '#extern/bullet2/src' +BF_BULLET_INC = '${BF_BULLET}' +BF_BULLET_LIB = 'extern_bullet' + +BF_SOLID = '#extern/solid' +BF_SOLID_INC = '${BF_SOLID}' +BF_SOLID_LIB = 'extern_solid' + +WITH_BF_YAFRAY = 'true' + +#WITH_BF_NSPR = 'true' +#BF_NSPR = $(LIBDIR)/nspr +#BF_NSPR_INC = -I$(BF_NSPR)/include -I$(BF_NSPR)/include/nspr +#BF_NSPR_LIB = + +# Uncomment the following line to use Mozilla inplace of netscape +#CPPFLAGS += -DMOZ_NOT_NET +# Location of MOZILLA/Netscape header files... +#BF_MOZILLA = $(LIBDIR)/mozilla +#BF_MOZILLA_INC = -I$(BF_MOZILLA)/include/mozilla/nspr -I$(BF_MOZILLA)/include/mozilla -I$(BF_MOZILLA)/include/mozilla/xpcom -I$(BF_MOZILLA)/include/mozilla/idl +#BF_MOZILLA_LIB = +# Will fall back to look in BF_MOZILLA_INC/nspr and BF_MOZILLA_LIB +# if this is not set. +# +# Be paranoid regarding library creation (do not update archives) +#BF_PARANOID = 'true' + +# enable freetype2 support for text objects +BF_FREETYPE = '/usr/local' +BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2' +BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib' +BF_FREETYPE_LIB = 'freetype' + +WITH_BF_QUICKTIME = 'false' # -DWITH_QUICKTIME +BF_QUICKTIME = '/usr/local' +BF_QUICKTIME_INC = '${BF_QUICKTIME}/include' + +WITH_BF_ICONV = 'true' +BF_ICONV = "/usr" +BF_ICONV_INC = '${BF_ICONV}/include' +BF_ICONV_LIB = 'iconv' +BF_ICONV_LIBPATH = '${BF_ICONV}/lib' + +# enable ffmpeg support +WITH_BF_FFMPEG = 'false' # -DWITH_FFMPEG +BF_FFMPEG = '/usr/local' +BF_FFMPEG_INC = '${BF_FFMPEG}/include' +BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib' +BF_FFMPEG_LIB = 'avformat avcodec avutil' + +# Mesa Libs should go here if your using them as well.... +WITH_BF_STATICOPENGL = 'false' +BF_OPENGL = '/usr/openwin' +BF_OPENGL_INC = '${BF_OPENGL}/include' +BF_OPENGL_LIB = 'GL GLU X11 Xi' +BF_OPENGL_LIBPATH = '${BF_OPENGL}/lib' +BF_OPENGL_LIB_STATIC = '${BF_OPENGL_LIBPATH}/libGL.a ${BF_OPENGL_LIBPATH}/libGLU.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a ${BF_OPENGL_LIBPATH}/libX11.a ${BF_OPENGL_LIBPATH}/libXi.a ${BF_OPENGL_LIBPATH}/libXext.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a' + +## +CC = 'gcc' +CXX = 'g++' +##ifeq ($CPU),alpha) +## CFLAGS += -pipe -fPIC -funsigned-char -fno-strict-aliasing -mieee + +CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing'] + +CPPFLAGS = ['-DXP_UNIX', '-DSUN_OGL_NO_VERTEX_MACROS'] +CXXFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing'] +REL_CFLAGS = ['-O2'] +REL_CCFLAGS = ['-O2'] +##BF_DEPEND = 'true' +## +##AR = ar +##ARFLAGS = ruv +##ARFLAGSQUIET = ru +## +C_WARN = '-Wall -Wno-char-subscripts -Wdeclaration-after-statement' + +CC_WARN = '-Wall' + +##FIX_STUBS_WARNINGS = -Wno-unused + +LLIBS = 'c m dl pthread stdc++' +##LOPTS = --dynamic +##DYNLDFLAGS = -shared $(LDFLAGS) + +BF_PROFILE_FLAGS = ['-pg','-g'] +BF_PROFILE = 'false' + +BF_DEBUG = 'false' +BF_DEBUG_FLAGS = '' + +BF_BUILDDIR = '../build/sunos5' +BF_INSTALLDIR='../install/sunos5' + + +PLATFORM_LINKFLAGS = [''] diff --git a/config/win32-mingw-config.py b/config/win32-mingw-config.py new file mode 100644 index 00000000000..54d8e0c6ffd --- /dev/null +++ b/config/win32-mingw-config.py @@ -0,0 +1,160 @@ +LCGDIR = '#../lib/windows' +LIBDIR = "${LCGDIR}" + +WITH_BF_VERSE = 'false' +BF_VERSE_INCLUDE = "#extern/verse/dist" + +BF_PYTHON = LIBDIR + '/python' +BF_PYTHON_VERSION = '2.5' +BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' +BF_PYTHON_BINARY = 'python' +BF_PYTHON_LIB = 'python25' +BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib' + +WITH_BF_OPENAL = 'true' +BF_OPENAL = LIBDIR + '/openal' +BF_OPENAL_INC = '${BF_OPENAL}/include' +BF_OPENAL_LIB = 'openal_static' +BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib' + +WITH_BF_FFMPEG = 'false' +BF_FFMPEG_LIB = 'avformat avutil avcodec' +BF_FFMPEG_LIBPATH = LIBDIR + '/gcc/ffmpeg/lib' +BF_FFMPEG_INC = LIBDIR + '/gcc/ffmpeg/include' + +WITH_BF_SDL = 'true' +BF_SDL = LIBDIR + '/sdl' +BF_SDL_INC = '${BF_SDL}/include' +BF_SDL_LIB = 'SDL' +BF_SDL_LIBPATH = '${BF_SDL}/lib' + +BF_PTHREADS = LIBDIR + '/pthreads' +BF_PTHREADS_INC = '${BF_PTHREADS}/include' +BF_PTHREADS_LIB = 'pthreadGC2' +BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib' + +WITH_BF_FMOD = 'false' +BF_FMOD = LIBDIR + '/fmod' + +WITH_BF_OPENEXR = 'true' +BF_OPENEXR = LIBDIR + '/gcc/openexr' +BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR' +BF_OPENEXR_LIB = ' Half IlmImf Iex ' +BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib' + +WITH_BF_DDS = 'true' + +WITH_BF_JPEG = 'true' +BF_JPEG = LIBDIR + '/jpeg' +BF_JPEG_INC = '${BF_JPEG}/include' +BF_JPEG_LIB = 'jpeg' +BF_JPEG_LIBPATH = '${BF_JPEG}/lib' + +WITH_BF_PNG = 'true' +BF_PNG = LIBDIR + '/png' +BF_PNG_INC = '${BF_PNG}/include' +BF_PNG_LIB = 'png' +BF_PNG_LIBPATH = '${BF_PNG}/lib' + +BF_TIFF = LIBDIR + '/tiff' +BF_TIFF_INC = '${BF_TIFF}/include' + +WITH_BF_ZLIB = 'true' +BF_ZLIB = LIBDIR + '/zlib' +BF_ZLIB_INC = '${BF_ZLIB}/include' +BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' + +WITH_BF_INTERNATIONAL = 'true' + +BF_GETTEXT = LIBDIR + '/gettext' +BF_GETTEXT_INC = '${BF_GETTEXT}/include' +BF_GETTEXT_LIB = 'gnu_gettext' +BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' + +WITH_BF_FTGL = 'true' +BF_FTGL = LIBDIR + '/ftgl' +BF_FTGL_INC = '${BF_FTGL}/include' +BF_FTGL_LIB = 'extern_ftgl' + +WITH_BF_GAMEENGINE = 'false' + +WITH_BF_ODE = 'true' +BF_ODE = LIBDIR + '/ode' +BF_ODE_INC = BF_ODE + '/include' +BF_ODE_LIB = BF_ODE + '/lib/libode.a' + +WITH_BF_BULLET = 'true' +BF_BULLET = '#extern/bullet2/src' +BF_BULLET_INC = '${BF_BULLET}' +BF_BULLET_LIB = 'extern_bullet' + +BF_SOLID = '#extern/solid' +BF_SOLID_INC = '${BF_SOLID}' +BF_SOLID_LIB = 'extern_solid' + +BF_WINTAB = LIBDIR + '/wintab' +BF_WINTAB_INC = '${BF_WINTAB}/INCLUDE' + +WITH_BF_YAFRAY = 'true' + +#WITH_BF_NSPR = 'true' +#BF_NSPR = $(LIBDIR)/nspr +#BF_NSPR_INC = -I$(BF_NSPR)/include -I$(BF_NSPR)/include/nspr +#BF_NSPR_LIB = + +# Uncomment the following line to use Mozilla inplace of netscape +#CPPFLAGS += -DMOZ_NOT_NET +# Location of MOZILLA/Netscape header files... +#BF_MOZILLA = $(LIBDIR)/mozilla +#BF_MOZILLA_INC = -I$(BF_MOZILLA)/include/mozilla/nspr -I$(BF_MOZILLA)/include/mozilla -I$(BF_MOZILLA)/include/mozilla/xpcom -I$(BF_MOZILLA)/include/mozilla/idl +#BF_MOZILLA_LIB = +# Will fall back to look in BF_MOZILLA_INC/nspr and BF_MOZILLA_LIB +# if this is not set. + +# enable freetype2 support for text objects +BF_FREETYPE = LIBDIR + '/gcc/freetype' +BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2' +BF_FREETYPE_LIB = 'freetype' +BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib' + +WITH_BF_QUICKTIME = 'false' # -DWITH_QUICKTIME +BF_QUICKTIME = '/usr/local' +BF_QUICKTIME_INC = '${BF_QUICKTIME}/include' + +WITH_BF_ICONV = 'false' +BF_ICONV = LIBDIR + "/iconv" +BF_ICONV_INC = '${BF_ICONV}/include' +BF_ICONV_LIB = 'iconv' +BF_ICONV_LIBPATH = '${BF_ICONV}/lib' + +# Mesa Libs should go here if your using them as well.... +WITH_BF_STATICOPENGL = 'false' +BF_OPENGL = 'C:\\MingW' +BF_OPENGL_INC = '${BF_OPENGL}/include' +BF_OPENGL_LIBINC = '${BF_OPENGL}/lib' +BF_OPENGL_LIB = 'opengl32 glu32' +BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a', + '${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a', + '${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ] +## +CC = 'gcc' +CXX = 'g++' + +CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ] + +CPPFLAGS = [ '-DXP_UNIX', '-DWIN32', '-DFREE_WINDOWS' ] +CXXFLAGS = ['-pipe', '-mwindows', '-funsigned-char', '-fno-strict-aliasing' ] +REL_CFLAGS = [ '-O2' ] +REL_CCFLAGS = [ '-O2' ] + +C_WARN = [ '-Wall' , '-Wno-char-subscripts', '-Wdeclaration-after-statement' ] + +CC_WARN = [ '-Wall' ] + +LLIBS = ['-lshell32', '-lshfolder', '-ldxguid', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++'] + +BF_DEBUG = 'false' +BF_DEBUG_FLAGS= '-g' + +BF_BUILDDIR = '..\\build\\win32-mingw' +BF_INSTALLDIR='..\\install\\win32-mingw' diff --git a/config/win32-vc-config.py b/config/win32-vc-config.py new file mode 100644 index 00000000000..d1a63022ac8 --- /dev/null +++ b/config/win32-vc-config.py @@ -0,0 +1,175 @@ +LCGDIR = '#../lib/windows' +LIBDIR = '${LCGDIR}' + +WITH_BF_VERSE = 'false' +BF_VERSE_INCLUDE = "#extern/verse/dist" + +# enable ffmpeg support +WITH_BF_FFMPEG = 'false' # -DWITH_FFMPEG +BF_FFMPEG = LIBDIR +'/ffmpeg' +BF_FFMPEG_INC = '${BF_FFMPEG}/include' +BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib' +BF_FFMPEG_LIB = 'avformat-51.lib avcodec-51.lib avutil-49.lib' + +BF_PYTHON = LIBDIR + '/python' +BF_PYTHON_VERSION = '2.5' +BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' +BF_PYTHON_BINARY = 'python' +BF_PYTHON_LIB = 'python25' +BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib' + +WITH_BF_OPENAL = 'true' +BF_OPENAL = LIBDIR + '/openal' +BF_OPENAL_INC = '${BF_OPENAL}/include ${BF_OPENAL}/include/AL ' +BF_OPENAL_LIB = 'openal_static' +BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib' + +WITH_BF_ICONV = 'true' +BF_ICONV = LIBDIR + '/iconv' +BF_ICONV_INC = '${BF_ICONV}/include' +BF_ICONV_LIB = 'iconv' +BF_ICONV_LIBPATH = '${BF_ICONV}/lib' + +WITH_BF_SDL = 'true' +BF_SDL = LIBDIR + '/sdl' +BF_SDL_INC = '${BF_SDL}/include' +BF_SDL_LIB = 'SDL.lib' +BF_SDL_LIBPATH = '${BF_SDL}/lib' + +BF_PTHREADS = LIBDIR + '/pthreads' +BF_PTHREADS_INC = '${BF_PTHREADS}/include' +BF_PTHREADS_LIB = 'pthreadVC2' +BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib' + +WITH_BF_FMOD = 'false' +BF_FMOD = LIBDIR + '/fmod' + +WITH_BF_OPENEXR = 'true' +BF_OPENEXR = LIBDIR + '/openexr' +BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/IlmImf ${BF_OPENEXR}/include/Iex ${BF_OPENEXR}/include/Imath ' +BF_OPENEXR_LIB = ' Iex Half IlmImf Imath IlmThread ' +BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib_msvc' + +WITH_BF_DDS = 'true' + +WITH_BF_JPEG = 'true' +BF_JPEG = LIBDIR + '/jpeg' +BF_JPEG_INC = '${BF_JPEG}/include' +BF_JPEG_LIB = 'libjpeg' +BF_JPEG_LIBPATH = '${BF_JPEG}/lib' + +WITH_BF_PNG = 'true' +BF_PNG = LIBDIR + '/png' +BF_PNG_INC = '${BF_PNG}/include' +BF_PNG_LIB = 'libpng_st' +BF_PNG_LIBPATH = '${BF_PNG}/lib' + +BF_TIFF = LIBDIR + '/tiff' +BF_TIFF_INC = '${BF_TIFF}/include' + +WITH_BF_ZLIB = 'true' +BF_ZLIB = LIBDIR + '/zlib' +BF_ZLIB_INC = '${BF_ZLIB}/include' +BF_ZLIB_LIB = 'libz' +BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' + +WITH_BF_INTERNATIONAL = 'true' + +BF_GETTEXT = LIBDIR + '/gettext' +BF_GETTEXT_INC = '${BF_GETTEXT}/include' +BF_GETTEXT_LIB = 'gnu_gettext' +BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' + +WITH_BF_FTGL = 'true' +BF_FTGL = LIBDIR + '/ftgl' +BF_FTGL_INC = '${BF_FTGL}/include' +BF_FTGL_LIB = 'extern_ftgl' + +WITH_BF_GAMEENGINE = 'false' + +WITH_BF_ODE = 'true' +BF_ODE = LIBDIR + '/ode' +BF_ODE_INC = BF_ODE + '/include' +BF_ODE_LIB = BF_ODE + '/lib/libode.a' + +WITH_BF_BULLET = 'true' +BF_BULLET = '#extern/bullet2/src' +BF_BULLET_INC = '${BF_BULLET}' +BF_BULLET_LIB = 'extern_bullet' + +BF_SOLID = '#extern/solid' +BF_SOLID_INC = '${BF_SOLID}' +BF_SOLID_LIB = 'extern_solid' + +BF_WINTAB = LIBDIR + '/wintab' +BF_WINTAB_INC = '${BF_WINTAB}/INCLUDE' + +WITH_BF_YAFRAY = 'true' + +#WITH_BF_NSPR = 'true' +#BF_NSPR = $(LIBDIR)/nspr +#BF_NSPR_INC = -I$(BF_NSPR)/include -I$(BF_NSPR)/include/nspr +#BF_NSPR_LIB = + +# Uncomment the following line to use Mozilla inplace of netscape +#CPPFLAGS += -DMOZ_NOT_NET +# Location of MOZILLA/Netscape header files... +#BF_MOZILLA = $(LIBDIR)/mozilla +#BF_MOZILLA_INC = -I$(BF_MOZILLA)/include/mozilla/nspr -I$(BF_MOZILLA)/include/mozilla -I$(BF_MOZILLA)/include/mozilla/xpcom -I$(BF_MOZILLA)/include/mozilla/idl +#BF_MOZILLA_LIB = +# Will fall back to look in BF_MOZILLA_INC/nspr and BF_MOZILLA_LIB +# if this is not set. +# +# Be paranoid regarding library creation (do not update archives) +#BF_PARANOID = 'true' + +# enable freetype2 support for text objects +BF_FREETYPE = LIBDIR + '/freetype' +BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2' +BF_FREETYPE_LIB = 'freetype2ST' +BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib' + +WITH_BF_QUICKTIME = 'true' # -DWITH_QUICKTIME +BF_QUICKTIME = LIBDIR + '/QTDevWin' +BF_QUICKTIME_INC = '${BF_QUICKTIME}/CIncludes' +BF_QUICKTIME_LIB = 'qtmlClient' +BF_QUICKTIME_LIBPATH = '${BF_QUICKTIME}/Libraries' + +WITH_BF_STATICOPENGL = 'false' +BF_OPENGL_INC = '${BF_OPENGL}/include' +BF_OPENGL_LIBINC = '${BF_OPENGL}/lib' +BF_OPENGL_LIB = 'opengl32 glu32' +BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a', + '${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a', + '${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ] +CC = 'cl.exe' +CXX = 'cl.exe' + +CCFLAGS = ['/nologo', '/Og', '/Ot', '/Ob1', '/Op', '/G6','/EHsc', '/J', '/W3', '/Gd', '/MT'] + +BF_DEBUG_FLAGS = ['/Zi', '/FR${TARGET}.sbr'] + +CPPFLAGS = ['-DWIN32','-D_CONSOLE', '-D_LIB', '-DUSE_OPENAL', '-DFTGL_LIBRARY_STATIC', '-D_CRT_SECURE_NO_DEPRECATE'] +REL_CFLAGS = ['-O2', '-DNDEBUG'] +REL_CCFLAGS = ['-O2', '-DNDEBUG'] +C_WARN = [] +CC_WARN = [] + +LLIBS = 'ws2_32 dxguid vfw32 winmm kernel32 user32 gdi32 comdlg32 advapi32 shell32 ole32 oleaut32 uuid' + +PLATFORM_LINKFLAGS = ''' + /SUBSYSTEM:CONSOLE + /MACHINE:IX86 + /ENTRY:mainCRTStartup + /INCREMENTAL:NO + /NODEFAULTLIB:"msvcprt.lib" + /NODEFAULTLIB:"glut32.lib" + /NODEFAULTLIB:"libc.lib" + /NODEFAULTLIB:"libcd.lib" + /NODEFAULTLIB:"libcpd.lib" + /NODEFAULTLIB:"libcp.lib" + /NODEFAULTLIB:"libcmtd.lib" + ''' + +BF_BUILDDIR = '..\\build\\win32-vc' +BF_INSTALLDIR='..\\install\\win32-vc' diff --git a/doc/BL-license.txt b/doc/BL-license.txt new file mode 100644 index 00000000000..2ba19e96ec3 --- /dev/null +++ b/doc/BL-license.txt @@ -0,0 +1,35 @@ +Blender License (the "BL", see http://www.blender.org/BL/ ). + +Copyright (C) 2002-2005 Blender Foundation. All Rights Reserved. + +This text supersedes the previous BL description, called Blender License 1.0. + +When the Blender source code was released in 2002, the Blender Foundation reserved +the right to offer licenses outside of the GNU GPL. This so-called "dual license" +model was chosen to provide potential revenues for the Blender Foundation. + +The BL has not been activated yet. Partially because; + +- there has to be a clear benefit for Blender itself and its community of + developers and users. +- the developers who have copyrighted additions to the source code need to approve + the decision. +- the (c) holder NaN Holding has to approve on a standard License Contract + +But most important; + +- the Blender Foundation is financially healthy, based on community support + (e-shop sales), sponsoring and subsidy grants +- current focus for the Blender Foundation is to not set up any commercial + activity related to Blender development. +- the GNU GPL provides sufficient freedom for third parties to conduct business + with Blender + +For these reasons we've decided to cancel the BL offering for an indefinite period. + +Third parties interested to discuss usage or exploitation of Blender can email +license@blender.org for further information. + +Ton Roosendaal +Chairman Blender Foundation. +June 2005 \ No newline at end of file diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 00000000000..cad2ea51a0f --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,943 @@ +# Doxyfile 1.2.15 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Blender + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = V2.27 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, +# German, Greek, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, +# Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consist of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = doxygen.main ../source/creator/ ../source/blender/src/B.blend.c ../source/blender/src/blenderbuttons.c ../source/blender/readblenfile/intern/BLO_readblenfile.c ../intern/ghost/GHOST_C-api.h ../source/blender/imbuf/ ../source/blender/src/mainqueue.c + +# cmccad - The following lines are directories which will eventually be included: +# +# ../source/blender/blenkernel/ ../source/blender/imbuf/ ../source/blender/render/ +# ../source/blender/blenlib/ ../source/blender/include + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse. + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the Html help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+, +# or Internet explorer 4.0+). Note that for large projects the tree generation +# can take a very long time. In such cases it is better to disable this feature. +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = BUILD_DATE + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line and do not end with a semicolon. Such function macros are typically +# used for boiler-plate code, and will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yield more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermedate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/doc/GPL-license.txt b/doc/GPL-license.txt new file mode 100644 index 00000000000..14db8fc79db --- /dev/null +++ b/doc/GPL-license.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/doc/README.windows-gcc b/doc/README.windows-gcc new file mode 100644 index 00000000000..78018eabbc0 --- /dev/null +++ b/doc/README.windows-gcc @@ -0,0 +1,123 @@ +An updated version of this guide can be found at: + +http://www.blender3d.org/cms/Building_with_Cygwin.524.0.html + +Introduction +------------ + +Here are some basic instructions for building +blender for windows using gcc under cygwin. +Please note that the resulting executable does not +depend on cygwin and can be distrubuted to machines +that don't have cygwin installed. + +The instructions are: + +1. Download cygwin (www.cygwin.com) and use the setup program + to install packages for gcc, gcc-mingw, gcc-g++, w32api, make, cvs, + python, perl, gettext, and gettext-devel (and maybe others... the + dependency list is bound to change over time and hopefully these + instructions will keep up with the changes). All of the following + commands will be entered at the cygwin prompt so launch + cygwin now. + +2. Create a directory to put your sources and then enter that + directory, e.g.: + mkdir bf-blender + cd bf-blender + + *********WARNING: if the directory path you are in contains a space in + it you will get errors in trying to compile the code. Change directorys + to a one that does not contain a space in the path before creating the + above directory ********* + + +Please note that a backslash at the end of a line in the following +means that the command spans two lines. If you wish to type the command as +one line, exclude the '\'. + +3. Checkout the blender module from the bf-blender tree using cvs + (use password anonymous): + cvs -d:pserver:anonymous@cvs.blender.org:/cvsroot/bf-blender login + cvs -z3 -d:pserver:anonymous@cvs.blender.org:/cvsroot/bf-blender \ + co blender + +4. Checkout the lib/windows module from bf-blender using cvs: + cvs -z3 -d:pserver:anonymous@cvs.blender.org:/cvsroot/bf-blender \ + co lib/windows + +5. Enter the newly created blender directory: + cd blender + +6. To prepare the build system to use only the free tools we must + set some environment variables. This is done by creating a + file called "user-def.mk" in the blender directory and + inserting the following line with notepad or your favorite + text editor: + export FREE_WINDOWS=true + + The quickest way to do this though is to issue the following + command: + echo 'export FREE_WINDOWS=true' > user-def.mk + +7. Time to build... issue the command: + make + +8. Wait for it to finish (there is this mysterious place called + 'outside' that I am told is nice to go to while waiting for a + compile to finish). + +9. After it finishes compiling, if you would like to run your freshly compiled + blender, type make release. Then change directorys to obj/233.a/ and move + the zip file to where you want to use it, unzip the file, enter the directory + and run your brand new blender. + + +Getting Help +------------ +If you have problems, come by #blendercompilers on irc.freenode.net +or post questions to the "Compiling, Libraries, Modules" forum +at www.blender.org. There is also the very useful bf-committers +mailing list, what you can subscribe to here: + +http://www.blender.org/mailman/listinfo/bf-committers +(as a bonus you can get info about the most recent features that +are coming down the pipe ...) + +This said, the most common fix to a problem will +probably involve installing an additional cygwin package, +so keep that cygwin setup program close by ... + +Some final notes +---------------- + +- The build will take a long time, even on a fast machine + (a clean build takes almost an hour on my Athlon 1800+ + based laptop). +- If the build is successful you will find it has created + the program obj/windows/bin/blender.exe +- The executable generated by gcc will generally be slower + that an msvc++ generated executable at rendering, but the + OpenGL speed should be about the same. +- Sound is disabled +- If you want to clean your sources issue a 'make clean' + in the top blender directory. +- If you want to update your sources when somebody has + added a new awesome feature, you will want to go to the + topmost blender directory and issue the following command: + cvs -z3 update -P -d + It would probably be best to clean your sources before + re-building (see previous note). +- This is a work in progress, so some things may not be working + right or it may not support all of the cutting edge features. +- Want to make a fancy zipped up blender package to give + to your buddies? Try "make release" ... read the output + to find out where the zip file was placed (note: you will + probably need the zip/unzip packages from cygwin to do + this). +- You can make a debug executable using 'make debug'. The + debug executable will be larger and slower that the + regular executable, but when used with the gnu debugger + (gdb) it can help debug a blender problem (for example, + it can locate the line of code that caused blender to + crash). diff --git a/doc/bf-members.txt b/doc/bf-members.txt new file mode 100644 index 00000000000..181ed152081 --- /dev/null +++ b/doc/bf-members.txt @@ -0,0 +1,1393 @@ +Blender Foundation Members + +Special thanks to the following people, who have supported the Blender Foundation +by donating at least USD 50 to pay for opening the Blender sources: +(in chronological order): + +Bradley Keyes +Robert Knop +Thomas Brown +Adam Goodenough +Steven Tally +Jason Tally +Alan Taylor +Pascal COMPAGNON +Christopher Koppler +Matthew P. Carter +Gideon Vaala +F.O. Bossert +Frank Mayhar +Peter Volgyesi +Mark E. Nelmes +Peter Lammers +Craig Maloney +daniel e vertseegh +Freek Zijlmans +Anthony Ogden +Anders Dys +Gerald Saunders +Fernando Cordas +Joshua Smith +Max R. Huskins +imarend +Olaf Arnold +Eric Van Hensbergen +Christian Reichlin +brian moore +Anthony Walker +Carsten Hšfer +Raymond Fordham +David Megginson +Jason Schmidt +Christopher Walden +Robert van Straten +Daniel Schwartz +ekzakt +Jellybean +Streit Eric +Bob Ippolito +Keith Frederick +Ryan Heimbuch +Martin Hess +Shigeo Yoshida +Rens Houben +Jun IIO +Derek Gladding +Adam Wendt +Habib Loew +Jani Turkia +Warren Landon +Chip Lynch +Hans Ruedisueli +Keith Jones +Eugenio Mario Longo +Philippe Tanguay +nekurai +Ricardo Kustner +Peter Van Loock +Jun-ichi OKAMURA +alain dejoux +dario trombino +Kenneth Johansson +Felix Schwarz +Eugenio Diaz +Aoki Katsutoshi +Norman J. Harman Jr. +Ralf Habel +Ken Payne +DEBEUX Sylvain +Douglas Philips +Lai Che Hung +Johan Bolmsjš +Aaron Mitchell +Teinye Horsfall +Martin Marbach +Jason Poole +Cesar Delgado +Gareth Clay +Paul Wasserman +Joeri Sebrechts +Johannes Lehtinen +Marcio L. Teixeira +James A. Peltier +George E. Nimmer III +Matthew Fite +Ken Sedgwick +Gary Baltzell +lukas schroeder +Dan Lyke +Mark Thorpe +A.D. Arul Nirai Selvan +Herbert Pštzl +Andy Payne +LAFFITTE Benoit (KenjForce) +James Ertle +Tom Turelinckx +Rigo Ketelings +Bryan Green +Suzuki Akihiro +Mason Staugler +Guillaume Randon +francois Gombault +Harald Thelen +Graziano Roccon +Jonathan DuBois +Jason Luros +Drew M. Snyder +Jesse DeFer +Michael Keith +Gaetano Tinat +Ferris McCormick +Sherman Boyd +Thomas C Anth Jr +Joseph Catto +Damian Soto +John Walsh +Stephen Rosman +Ross Hopkins +Robert Wenzlaff +Joe Galat +LinuxFrench.NET +Thomas Erichsen +Gary E. Deschaines +Denis McCarthy +Michael Dowman +John (J5) Palmieri +alphawolf +Peter Paul Fink +Charles F. McKnight +Avi Schwartz +Jim Witte +Jens Ansorg +William Bate +Ron Romano +Marc Schraffenberger +Steve Thompson +Martin Whitaker +Kendall Dugger +Brice Due +Simon Vogl +Bernd Koestler +clŽment CORDIER +CreationAnimation.com +Pete Carss +HERSEN Antoine +Charles R. Tersteeg +James T Burnett +Shawn Legrand +David Choice +patrick amaru +David Eck +Gabriel Welsche +Henning von Zitzewitz +Chris Impink +Den Giles +Jon Cisewski +Ricki Myers +Luis Collado +Robert G. Watkins +Rainer Perl +YAGI, Toshiki +Bruno Nitrosso +Athalyba / Blender Brasil +Dave Whittington +Darryl Luscombe +Benjamin A Moore +Andreas Kollegger +Stamatis Logos +Ray Kelm +Albrecht Jacobs +Mirko Horstmann +Ranjit Mathew +Jaron Blackburn +Antonio Hui +Scott Moore +CSN media +Scott Carle +Ted Milker +Lars Brinkhoff +Louise Edwards +Alex Ruano +Art Rozenbaum +Manuel Hossfeld +Brandon Ehle +Lou Bruce +ROMASZEWSKI +cadic jean-yves +Ralf Pietersz +KAZY +serge Jadot +HervŽ LOUINET +Tom Houtman +Magnus Kššhler +Martin Sinnaeve +Kevin Yank +Tomoichi Iriyama +THIBAULT +Dr Steven J. Baines +Hans-Peter Berger +Jeffrey D. Holland +Philip XP Talbot +Peter Haight +Krister Bruhwel +the Smoos +Hohenegger Michael +Alejandro Gabriel y Galan +Boyer +Alwin Eilers +Tyberghein Jorrit +Jaroslav Benkovsky +Gianluigi Belli +Naoki Abe +NOTTE Jean-Pierre +Jack Way +Bjšrn Westlin +Mitch Magee +wizoptic +Jake Edge +David Hoover +Xabier Go–i +Daniel Fort +Erik Noteboom +Pavel Vostatek +Javier Belanche Alonso +Jeffrey Blank +Nathan Ryan +Peter Wrangell +Josef Sie§ +Timm Krumnack +Steve Martin +Shigeru Matsumoto +Marko Kohtala +Aleix Conchillo +Curtis Smith +Tatjana Svizensky +Matt Graham +Karo Launonen +Nikolaj Brandt Jensen +Jean-Michel Smith +Nathan Clegg +Joaquim Carvalho +Bomholt +Martin Imobersteg +Jordan +Justin Warwick +barussaud +Eric Molbert +Ben Berck +Jacco van Beek +Dominic Agoro-Ombaka +Colin Foster +Sascha Adler +Stuart Duncan +Brendon Smith +SŽbastien COLLETTE +Clemens Auer +Kay Fricke +Fabian Fagerholm +Norman Lin +Aaron Digulla +Camilo Moreno +Detlev Reppin +Denis NICOLAS +Armin Antons +Darren Heighington +Mario Latronico +Frank Meier +Joerg Frochte +Matthew Ingle +Anters +Bjoern C. Schaefer +STEMax +Jeff Cox +Trevor Ratliff +Matt Henley +Franois VALETTE +Rob Saunders +Mike Luethi +Rami Aubourg-Kaires +Matthew Thomas +Allan Jacobsen +Adam Lowe +David Hostetler +Lo•c Vigneras +Dan Reiland +Pedro D’az del Arco +Pierre Beyssac +Chris Davey +YOSHIAKI Nishino +Cyber Perk +Fabrizio Cali +Harunobu Yoda +Gerrit Jan Baarda +LarstiQ +Ico Doornekamp +Emiel den Biesen +Willem Zwarthoed +Carl Giesberts +Buzz +lieve vanderschaeve +Margreet de Brie +hans verwaal +Saskia van Dijk +Martin Gosch +Alexander Konopka +Thomas Gebert +Gerard de Vries +Hans Lambermont +Kim Beumer +Kay Thust +Alexander Jung +Tony Corlett +Olivier Thouverey +Hideo Nomoto +Giel Peters +Ray Poynter +Edoardo Galvagno +Pim Feijen +Hua-lun Li +William Reynish +Bryan Carpenter +Jim Scott +NGUYEN Fabien +Dave Stone +Andy Kugyelka +Andrew Ross +MerieJean-Christophe +Marko Mestrovic +Jack +Lars Gunnar West +Wile E. Coyote +Rick Clark +Carlos A. Duque +Franck Barnier +Matt Shirley +Viktor Zacek +Peter Williamson +Chema Celorio +Paul Cleveland +Guo-Rong Koh +Andrew Potter +Daniel Smeltzer +Cativo +Dmitri Bichko +Jeremy Brinkley +Stephen Saville +Michael Proto +Kurt Korbatits +Ruan Muller +Mike Beggs +Beat Schiess +Sven Marcel Buchholz +Enrique Monfort +Simon Posnjak +Steven Ahkim +theGyre +William Marble +Allen Smith +Joshua SS Miller +Mike Edwards (PinkFreud) +Mark D. Butala +Auriea Harvey&Michael Samyn +Randy Newman +Leslie Spring +Marc Schefer +Dean Edmonds +David Whitehouse +Tim Humphrey +Phillip Richdale +Jason McHugh +Claudio de Sario +Artur Kedzierski +Richard Garcia +Isaac Rivas Alvarez +Kiernan Holland +Holger Malessa +Masanori Okuda +Andrea Maracci +Kai-Peter BŠckman +Gregg Patton +Luis M Ibarra +Julian Green +Christian Bender +Mark Winkelman +Ebbe L. Nielsen +Carlos Orozco +magnetHead +KrŸckel Oliver +Thomas Ingham +Wes Devauld +Uwe Steinmann +Jesus Gonzalez +DenMeridiS +Marc Hofer +Marko Mestrovic +Leslie Owen Everett +Knut Bueltemann +Eric Garaventa +Wolfram Schwenzer +Edwin Brouwer +mauro ujetto +Franck Vibert +Daniel Pacheco +Justin Shumaker +Steve Wallace +Forensic Engineering Inc. +Steve Mackay +NDNWarrior +Christopher Gray +Darius Clarke (Socinian) +Jean-SŽbastien SEVESTRE +Douglas Fellows +Craig Symons +Quincin Gonjon +Brian B. Kelley +Kie Brooks +Scott Whitney +kwbrads +Keijiro Takahashi +Geno Ruffalo +Zzeb +Peter Dohnt +Jeff E Schram +ernst bunders +Nobutoshi Shigemori +Mariano Aured +Rab Gordon +Kurt Maurer +Ron Cavagnaro (doogs) +Johan Bjorklund +Cyril M. Hansen +JOSEPH GRACI +Rafael Rubio +fabrice meynard +Emilio Aguirre +Mark Lewis +Markus Q. Roberts +Christoher Bartak +Peter Truog +Eric Dynowski +Philipp GŸhring +Pierre-Yves RANNO +Jason Nollan (Cluh) +Launay Jean-Claude +Wayne Buckhanan +Jan Magne Landsvik +Douglas Dragan Njegovan +Brian David Hale +Randal Walser +Matthew A. Nicholson +Thomas +Phillip Kinsley +Jerome Zago +David Rosky +TROJANI Cedric +David Polston +Patrick Mullen +Tetsuya Okuno +Bodo JŠger +Leon Brooks +Cedric Adjih +Michael L. Fisher +Dan Tomalesky +Sky Schulz +Scott Brickert +James Purdon +Miles Langham +N Yiannakoulias +Stephen Swaney +www.artwave.nl +Take Vos +sspickle +Denis Oliver Kropp +Gustavo +rodgers whittington jr +George Dvorak +Norman J Davis, Jr. +Javier Velazquez +John Tougas +John Howland +Steve Organek +Jano Lukac +David Cardon +Mick Balaban +Michael Kaufman +Viper Expo +Chassoulier +Sjoerd Zaalberg van Zelst +B. Douglas Hilton +Benoit CANTAGREL +Kai Fischer +Mark Osborne +Michael Hollenbeck +iconjunky +luca de giorgi +Jonathan Mullen +Javier Fernandez-Ivern +Reuben Burgess +Olivier Scalbert +claudio luis Rogers +Jeremy Peterson +Mark Streutker +Lourens Veen +Neil Davis +John McGurk +Stephen Teegarden +Dave LeCompte +Michael Lang +Mortal_Enemy +Arigo Stanescu +Vincent Stoessel +Adrian Virnig +Chris Dixon +Travis Cole +MŒrten MŒrtensson +Evan Scott +Mark Coletti +Ken Burke +Karl Holland +ScRaze +Wilco Wilbrink +chris montijn +Michael Wagenmann +Viktor Pracht +henrik wilming +Jim Evins +Christophe Massaloux +Marc Sommer +Luc Stepniewski +Eric M. Clark +Iain Russell +Thomas Bleicher +Anthony Zishka +Jefferson Dubrule +Esa PiirilŠ +Bill Thiede +William Anderson +Alexander Kittel +Joe Tennies +Sam Cable +Christian Peper +Joshua Frederick +Steve Sutton +Pete Toscano +Michael Zucchi +Peter Degenhardt +Horizont Entertainment +Olivier Bornet +Richard D. Laudenslager +sha +John DiLauro +John Miller +Frederic Crozat +Matt Welland +Paul CalcŽ +Joe Prochilo +Justin Shafer +Joe Croft +Detlef Mueller +Raschbacher Thomas +Alain Gallo +Phuoc Ngo +Krabat +Derek Harmison +SŽbastien Devine +Kenneth P. Stox +Wade Felde +Kai Groshert +Michael Soibelman +janine dalisda-davis +Philippe Raxhon +Daniel Sheridan +Michael Pressler +Daniel Lundqvist +Tim Oertel +James Ahlschwede +William Henstrom +PETIT-PHAR Patrice +Marc-Aurele DARCHE +Wei-ju Wu +Robert Wilson +Gerald Severs +Alejandro Conty Estevez +Tetsuya Yatagai +David Dolder +Luigi Cristiano +Posse Press / Romain Canonge +Vania Smrkovski +Bartosch Pixa +Dr. Jens Rosenboom +Gunnar Stahl +Robert Kroeger +Martin Forisch +Guillermina Manon +Randal D. Adams +Kevin Reagh (kevin3D) +Wolfgang KŸhn +BEAUSOLEIL Arnaud +Stan Jakubek +Klaus Brand +Holger Mueller +Fankhauser +Jon McCallum +Rob Olsen +Joel Davis +Kenneth Bledsoe +James F. Campanella +Jens Kilian +wim hendrix +Karri Kaksonen +Luis Roldan +Jason L. Shiffer +Jacco Marks +Dale Schoeck +Agustin Catalan +A. T. Meinen +Kamiel Wanrooij +Samuel Seay +Mike Schaudies +Robert Sherwood +Fernando Villalon Panzano +Jšrg Roschke +Carl Symons +Peter Pichler +Alan Heckart +seth nagy +pelletier +Jeff Kowalczyk +LIONEL ALLORGE +Bhishma Patel +Richard Rowell +Barbara Seaton +Aschwin van der Woude +William J Black +Kars Meyboom +Glen Nakamura +Jim Belcher +Tim Scott +mea van amstel +Robert-Reinder Nederhoed +Neil Hunt +WizardNx +Brad Choate +scott schoen +Dan Merillat +Martin Krueger +Samuel Greenfeld +Damon Tkoch +Colin Millar +Mike Roseman +Patrick Trussell +Hans-Peter Bock +Daniel Haertle +Wiremu Te Kani +Joep Mathijssen +LATRY +Witold Hazuka +geoff marshall +dave howard +Jan Zielinski +Fernando Buelna Sanchez +Timo Mihaljov +Allard Willem van den Brul +T.J.T van Kooten +Thijs van der Vossen +Antonio de Santis +Jama Poulsen +Robert Emanuele +Timothy Lord +Tom Parker +Jarrod Willard +Leon Merts +Tom Dow +Eric Anholt +mercier +Marc van Kempen +wim van hoydonck +Joe Hacobian +Jose Luis Fresquet Febrer +toni calmardo +Sam Littlewood +Charles Wardlaw +Javier Rodriguez +Michael C. Schwab +Corey Bell +Emmanuel Preveraud de La Boutresse +Davide Desogus +Larry Phillips +Marko Teiste +John Roesink +Legrand Johan +Jeff Boody +James Turner +Peter Petrakis +Ravi Ravindran +dickie +Rene Geerlings +Richard Braakman +Arthur Frenslich +Carsten Schmidt +Ronny Martin +Erwin Kuiper +Lopez-Garcia, Juan-Carlos +Rau, Bernhard +Stephen Uithoven +Ken Beyer +Matjaz Jakopec +Eckhard M. JŠger +Mike Siebach +John Harger +Justin W. Carper +Markus Weber +Elena Grandi +Arndt Heuvel +Miguel Cancela Da Fonseca +Kirk Lancaster +Phillip Elliott +Chris Halsall +Andre Voitel +benjamin scheers +Robinder S. Bains +David Brunton +David Brown +Craig Duncan +du Song +Ben Wart +Eryk Kedzierski +Ronald Hayden +Raymond de Vries +David Johnson +Kenichi Fujihiro +WANG +Chris Weber +Christian Lehmann +DENDIEVEL Stephane +Bryan Jaycox +Karl Bartel +Ralph Howes +Matthew J. Stott +Omar Priego +ke Westerstršm +Imago Viva +James E Hill +Rune Myrland +James Hill +Nick +Ramiro Santos +Giuseppe Chiesa +Philippe Ney +Tom Woodyard +Jim Gray +Jim Newman +Robert I Black III +Peter Marouelli +Ian Roberts +Guy Van Rentergem +Jose Luis Perez Rubio +Gabriel Mainberger +Klein Poelhuis +Luke Sargeant +Edomaur +robert stok +Karl J. Smith +Harry Splinter +Paul Boese +Dave Mata +piet visser +Nicolas Christin +Erik Zidowecki +Markus Michael Egger +Edward R. Helwig +Alyx Flannery +raphael betemps +Masahiro Takahata +Claude Bilat +Mario Palomo +Neipi +Grethus Bode +Jan MŸller +Mark Pearson +Stanislav Osicka +DataCare Solutions AG +Russell Elliott +Antonio Campos +bordeaux samuel +Herman Vereycken +Sergio Avila +George Dobrozemsky +Ocie Mitchell +Ryuuji Kusajima +Nick Austin +Edward Wei +Gregg Tavares +Aaron Bredon +Hideki Suzuki +josef radinger +Robert Friemer +Jšrg Zastrau +Burton Bicksler +Kimmo Mšsš +Robert F Johnson +Mark Johnson +Avi Bercovich +Mike Armitage +Roy Jones +Kathleen Sinnott +Per-Erik Westerberg +Reid Ellis +Phillip J. Birmingham +Ken Jordan +Duffaud +Marco Ardito +Simon Suter +Tobias Huelsdau +Winfried EnglŠnder +Stephen Groundwater +Joel Ray Holveck +Mag. Tibor Rudas +Hartmut Wolf +Douglas Jones +brett hartshorn +Beat MŠgert +Javon Prince +bri +James Klicman +Harvey Fong +jeroen v.d. Meulen +Wim Vandersmissen +Carlos Moreno Rodr’guez +Trausti Kristjansson +Larry Snyder +olivier +jip +Thomas Hintz +Daan van der Munnik +gideon +jared +Erick I. Jimenez Alvarado +John Martinez +Daniel Stephens +Alaric Haag +Michael Edwards +Sam Tregillus +Joe Pribele +Jeffry Archambeault +robert schiffers +shane smith +elout de kok +Felix Esser +Dietrich Lange +Richard Clark +errol garner +Jose M Cerqueira Esteves +Jeroen Janssen +Sven Meyer +Mike Bayer +Arash Vahdat +Bernd Hoppe +Tobias Geiger +Ronnie Stevens +W. van Ophoven +Artem Baguinski +Peter Morse +Nicholas Phillips +Leo Mannhart +philippe eygonnet +Hans Klerk +wes uchida +Guido Winkelmann +Doug Ferguson +Robert Lindsay +John Lovgren +Rogers Cadenhead +Philippe Crassous +Dirk Krause +lexpattison +Fred Roberts +Njin-Zu Chen +GUILLON Marc +Felix Klock +Ernesto Salas Rodr’guez +Pavel Roskin +Jaap +Stefan Maass +Adam Bower +Gary Thomas +Chris Gottbrath +seyssel claude +Chris Winberry +Chip Collier +Balint Reczey +Nuno Sucena Almeida +Landon Bradshaw +Chua Mei Ling +JC Hythloday +Dustin Knie +artshow +Ralf Gauglitz +Ted Schundler +Bernard Hurley +delerue +Dirk Behrens +Doc Holiday +Wouter Kerkhoven +Andreas BŸttner +James Black +Nicholas Ward +David Oberbeck +The Shizit +Erich Moog +James Amendolagine +Alex Penner +Dieter Finkenzeller +giol franco +Tobias Regenbrecht +Ryan Dewalt +Spencer Cathey +Benoit SERRA +System Impuls +Jason Tranter +macherb +LCC Consulting AG +Ivan So +Cori Verschoor +Henauer Pascal +Chris Bilderback +Eddie Sheffield +DEHEN Pierre +henk van den toorn +Ian Whitworth +Ruud H.G. van Tol +Pierre Lo Cicero +Srinivas Digumarty +digitalvelocity¨ +Alan J Booth +Tony OBrien +Douglas Toltzman +Christophe BOUCHET +Paul Robertson +SCHNEIDER Philippe +Jason Cunliffe +Dick Damian +Charles Hakari +jeff knowlton +Kevyn Shortell +robin +Craig Spitzer +Jeffrey Van Ness +Lucas Vergnettes +Wolfgang Michaelis +Luis JimŽnez Linares +Julian Eden +Ms Lilo von Hanffstengel +Kurt B. Kaiser +Mark Ping +CombŽe +Diego Matho +MELIN Philippe +Damian Sobieralski +Luigino Masarati +Leonard Wikberg III +Tom Howsman +Christopher R Marquard +Claus Munk +Chris D'Iorio +Graphics Solutions Pty Ltd +Bernd Stein +Jose Angel Vallejo Pinto +Matthew William Turner +Kelly A. Flinn +Hai T. Nguyen +Tim Formica +Kevin Purrington +Andreas Lindenblatt +Brian Musker +Diego Silvio Novo +Close Pierre-Yves +Wayne Pierce +Hattan Lee +Didier PEYRET +Jacquelin GAZEAU +Kenneth Balmer +Robert Hwang +Gaertner, Klaus +Peter Gumieniak +Simon Pigot +Ian Thompson +Jason Southwell +Stephan +Robert Kuehn +IUT Mesures Physiques:gilbert Garnier CAEN France +Nigel I Phillip +powermacg4 +Joan Touzet +Mike Mormando +katsuhiko ebisawa +Baheux Tony +Randi Joseph +Rick Comeau +michiel van der kley +Thijs Seelen +Robert Roos +ton +david seccombe +Joshua Eckert +Joshua Newman +Paolo Sammicheli +Gentilini Bruno +Martin Herren +STRAPPAZON Mathias +Steven Gibbs +Florian Kruesch +Wesley Blijlevens +Fabianne Balvedi +Colin Henry +Mark Deepak Puttnam +LE GOULVEN +evolutie +Stephane Portha +Robert Gentner +David B. Camhy +RenŽ Foucart +Coyok Drio +Mark Ng +klein michael +Antonin Kral +Edward Jomisko +Wouter de Mik +Matteo De Simone +Gal Barak +Thomas Dyar +Nathan Allworth +Dean Giberson +Larry Cummings +Eric Augustine +IngieBee +Michael Velikanje +Andre M. Czausov +H@dj +Thorsten Burghaus +Renzo Lauper +Martin White +Ferdinand Strixner +Neil Mannall +Maxime Wacker +Gal Buki +Rene Christen +Andreas Neukoetter +DAVID JOHNSON +John Walton +Volker Mische +Michel Vilain +Luigi/Blender Brasil +Clifton A. Cross +Kent B. Mein (SirDude) +Anne Postma +Matt Runion +Bob Tackett +stanislas nanchen +Jorge Monteiro +S68 +Ville Kaajakari +Adrien Rebollo +Al Curatolo +Frank Rutten +Dierk Dohmann +Roel Spruit +Rob Coldwell +Yann Vernier +Haunt_House (PH) +Ravinder Singh Bhara +Erik Augustijns +Ryan Earle Freckleton +Andreas Sturm +matt mullin +MOREAUX Denis +Brendan Stromberger +Hideki Saito +Christian Ullrich +Courty Didier +Steve Newton +Brecht Van Lommel +Jasper Op de Coul +Stuart MacKinnon +Dietrich Dietz - the IMaGiNation project (IMGN) +Tina Hirsch +John R Thorp +FrŽdŽric Bouvier +LINETTE +Felix Rabe +Chay Adamou +nick harron +stephen john ford +Kino +Daniel Sjšlie +Matthias Derer +Alain VALLETON +Kervin Pierre +Mike Laughton +Frank van Puffelen +Andreas Dluzewski +Christofer Edvardsen +Maciek Szczyglowski +Rakesh Ravuri +Robert Schouwenburg +Bob Bayens +Devas73 +Mika Saari +Robert Ives +Adam McBride +IAN ROSS +Uriah Liggett +stefan fischer +Didac Miro +Tim Barlow +G. T. Blackwell +Tim Weaver +Dalet +Erwin Vervacke +Benjamin Eduardo Rodriguez Berumen +Ozono Multimedia s.l.l. +James Kersey +Michael DeLuca +Mark Swann +Andreas Altenburger +John Smith +Simon de Haan +David Gregory +Harald Krummeck +E Warren McNee +Marc-Andre Levesque +Satoshi Yamasaki +Rolf-Dieter Klein +J. Deetman +Helge Walter +Roland StrŒlberg +Nicolas Morenas (Caronte) +Simon Clarke +Maigrot Michel +Rod Robinson +Kevin Cozens +Germ‡n Alonso (taz) +Martin Stegeman +Henrik Jordfald Olsen +Mitchell Skinner +Michael Lei +Spiridon G. Kontarakis +Bas Denissen +Loic Dachary +Michael Rutter +Thorsten SchlŸter +hijothema +Andreas Hauser +Holger Haase +Danilo Duina +Matthias Thurau +Flavio Curti +Ian Beardslee +Cristina Lozano Ballester +Jason Roberson +Victor Lim +andreas palsson +Richard Charvat +James Ezell +Florian Eggenberger +John J. Marshall +Paul Lunneberg +Peter Wolkerstorfer +Gerhard Siegesmund +Nat Budin +NDNChief +Dave Leeak +Michael Siebecker +Jan Walter +John Aughey +Corey Rice +Darren F. Coolen +tony principali +Joe Kimmes +Pekka Karvonen +Rick Kimball +Christopher Capoccia +Bertram Zeller +Vanpoucke Alexandre +Bassam Kurdali +Michael Baker +Michael Schwemmle +Ford "fullback" Roberts +Lama Angelo +Kevin Roeder +oliv +pinhead_66 +Zach Millis +Ryan C. Stallings +Adam LaJeunesse +Satish Goda +Erik Haagsman +Lorenzo Moro +Nathan Letwory +stephan f. haupt +Alex Papadopoulos +Gianluigi Berrone +andrea casentini +David Randall Simpson +Jason Oppel +Mark Bloomfield +Alexander Ehrath +Owen Swerkstrom +Aurelio Caliaro +Karsten Dambekalns +Eddy MOUSSA +Bernd Roetter +Roland Hess +Luis Eduardo P. Gervasio +Pierre-Luc Robert (bedsitter) +Andreu Cuartiella +Nathan Vegdahl +Scott Ross +Jacob Kafka +Mario Bolte +Wolfgang Draxinger +Starr Kline +John Lullie +Chiffi Cosimo +Morgan McMillian +Stefan HŸbner +Loic de MONTAIGNAC +AndrŽs Castillo +Francesco Anselmo +Ingo Guenther +James C. Davis, Jr. +Claudio Andaur +Caleb Williams +Orest Dubay +Adam Casto +David +Joost Burger +Ken Hahn +Mark Herring +Stig Oeveraas +Robert Rainthorpe +Martin Middleton +Simon Sedgwick +Joseph Firestine +Miguel Melo +Wooster Dennis +Gary Lucas +Johannes Schwarz +Mark Dalton +Mike Norton +Michael Schardt +jean-michel soler +Chris Bracewell +Ross Dawson +Tim De Graeve +Adam Wiseman +Luiz Olsson Barbosa +Donna Carey +Auke van Balen +Mike Birdsong +Martin Curran +Shawn M. Murray +Roy Simmons +Malik +Teguh Pangestu +Mats Holmberg +Julien Jehannet +Michael A. Nelson +Axel Cushing +erik vogan +Datenflug GmbH +KC Roeyer +Ryan J. Parker +Robert E. Meuse +Alex Heizer +Netsail Ltd / Mats Holmberg +Jonathan Lawman +Seikoh Hokama +Perry Faulkner +Will Hanson +Lyubomir Pavlov Kovachev +Ennio Quattrini +Marcelo "xfer" Alves +Joseph Winston IV +Jorge Otero Rueda +Timothy Murakami +Matthew Johnson +Erik Rombouts +Petr Vlk +Thomas Dammann +Henrik Turkerud +Erlend Hamberg +Arnaud Lebegue +Kevin O'Brien +Michael Buettner +Engel A. Sanchez +Alexander Hilgert +FAUGE Thierry +Wulf Huesken +John M. Adams +Dell'Aiera Pol +Waylena McCully +Russell Smith +Luke Titley +marinus meijers +Henry Kaminski +Alistair Riddoch +Daniel NŸmm +Matthew Meadows +Bjoern Paschen +Paul Fredrickson +Gavin Baker +Jan Illetschko +Aaron C. McLeod +Thomas Muldowney +Cheyenne Cloud, LLC +Helmut A. Goettl +Martin A. Boegelund +Beno”t Cousson +Scott Brooks +Ferlet Patrice +Aaron Porterfield +Ivan Florentin +Scott Isaacson +Rui Paulo Sanguinheira Diogo +Jason Saville +Active-Websight GbR +Bryon Roche +Gustavo Mu–oz +Christopher Gillanders +Phil Frost Tate +Gilles Gonon +Kay +James C. Franklin +Luis Enrique Caama–o Navas +Alexander "estartu" Felder +Marc Ledermann +vrijschrift.org +Holger Weihe +Peter Cammaert +Andres Meyer +Tony Arnett +Adam Hughes +Tony Farley +Dmitriy Teresh +Maickel Swart +Peter den Bak +Steve Bennett +Romain Rubi +John Bolt +Michael Gaston +Philip Brown +Wasi +Mike Hirst +Lloyd J Robinson, Jr +Charles Rinker +Nick Vogtmann +Frank van Beek +Bruce Mitchener +ROBERTO A. RUIZ VIAL +Maurizio Sibaud +Ron Bolger +Nathan Parton +Andrew Fry +VINCENT StŽphane +Yan Yan +Justin L Graham +Wade Beasley +Salvador Mata Rodriguez +Jan Tiemersma +Luis A. R. Fernandez +Jacob Moy +Stefano Francesi +Jochen Hanne +David Stephenson +Brent O'Dell +Mike Kasprzak +Tom Thompson +David Fung +Radoslav Dejanovic +James H. Cloos, Jr. +Karl Erlandsen (LethalSideParting) +Kari Pulli +Dave Shemano \ No newline at end of file diff --git a/doc/blender-cmake.txt b/doc/blender-cmake.txt new file mode 100644 index 00000000000..05037a3ab2a --- /dev/null +++ b/doc/blender-cmake.txt @@ -0,0 +1,156 @@ +$Id$ + + Blender CMake build system + ============================ + + Contents + --------------- + + 1. Introduction + 2. Obtaining CMake + 3. Obtaining Dependencies + 4. Deciding on a Build Environment + 5. Configuring the build for the first time + 6. Configuring the build after CVS updates + 7. Specify alternate Python library versions and locations + + + 1. Introduction + --------------- + + This document describes general usage of the new CMake scripts. The + inner workings will be described in blender-cmake-dev.txt (TODO). + + 2. Obtaining CMake + ------------------ + + CMake for can either be downloaded using your favorite package manager + or is also available from the CMake website at http://www.cmake.org + The website also contains some documentation on CMake usage but I found + the man page alone pretty helpful. + + 3. Obtaining Dependencies + ------------------------- + + Check from the page + http://www.blender.org/cms/Getting_Dependencies.135.0.html that you + have all dependencies needed for building Blender. Note that for + windows many of these dependencies already come in the lib/windows + module from CVS. + + 4. Deciding on a Build Environment + ---------------------------------- + + To build Blender with the CMake scripts you first need to decide which + build environment you feel comfortable with. This decision will also be + influenced by the platform you are developing on. The current implementation + have been successfully used to generate build files for the following + environments: + + 1. Microsoft Visual Studio 2005. There is a free version available + at http://msdn.microsoft.com/vstudio/express/visualc/. + + 2. Xcode on Mac OSX + + 3. Unix Makefiles (On Linux and Mac OSX): CMake actually creates make + files which generates nicely color coded output and a percentage + progress indicator. + + + 5. Configuring the build for the first time + ------------------------------------------- + + CMake allows one to generate the build project files and binary objects + outside the source tree which can be pretty handy in working and experimenting + with different Blender configurations (Audio/NoAudio, GameEngine/NoGameEngine etc.) + while maintaining a clean source tree. It also makes it possible to generate files + for different build systems on the same source tree. This also has benefits for + general CVS management for the developer as patches and submit logs are much cleaner. + + Create a directory outside the blender source tree where you would like to build + Blender (from now on called $BLENDERBUILD). On the commandline you can then run + the cmake command to generate your initial build files. First just run 'cmake' which + will inform you what the available generators are. Thn you can run + 'cmake -G generator $BLENDERSOURCE' to generate the build files. Here is an example + of all this for Xcode: + + % mkdir $BLENDERBUILD + % cd $BLENDERBUILD + % cmake + + ... + ... + --version [file] = Show program name/version banner and exit. + + Generators + + The following generators are available on this platform: + KDevelop3 = Generates KDevelop 3 project files. + Unix Makefiles = Generates standard UNIX makefiles. + Xcode = Generate XCode project files. + + + + % cmake -G Xcode $BLENDERSOURCE + ... + ... + -- Configuring blender + -- Configuring blenderplayer + -- Configuring done + -- Generating done + -- Build files have been written to: $BLENDERBUILD + + This will generate the build files with default values. Specific features can + be enabled or disabled by running the ccmake "GUI" from $BLENDERBUILD as follows: + + % ccmake $BLENDERSOURCE + + A number of options appear which can be changed depending on your needs and + available dependencies (e.g. setting WITH_OPENEXR to OFF will disable support + for OpenEXR). It will also allow you to override default and detected paths + (e.g. Python directories) and compile and link flags. When you are satisfied + used ccmake to re-configure the build files and exit. + + It is also possible to use the commandline of 'cmake' to override certain + of these settings. + + 6. Configuring the build after CVS updates + ------------------------------------------ + + The $BLENDERBUILD directory maintains a file called CMakeCache.txt which + remembers the initial run's settings for subsequent generation runs. After + every CVS update it may be a good idea to rerun the generation before building + Blender again. Just rerun the original 'cmake' run to do this, the settings + will be remembered. For the example above the following will do after every + 'cvs up': + + % cmake -G Xcode $BLENDERSOURCE + + 7. Specify alternate Python library versions and locations + ---------------------------------------------------------- + + The commandline can be used to override detected/default settings, e.g: + + On Unix: + cmake -D PYTHON_LIB=/usr/local/lib/python2.3/config/libpython2.3.so -D PYTHON_INC=/usr/local/include/python2.3 -D PYTHON_BINARY=/usr/local/bin/python2.3 -G "Unix Makefiles" ../blender + On Macs: + cmake -D PYTHON_INC=/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -D PYTHON_LIBPATH=/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/config -D PYTHON_BINARY=/System/Library/Frameworks/Python.framework/Versions/2.5/bin/python2.5 -G Xcode ../blender + + Mote that this should only be needed once per build directory generation because it will keep the overrides in CMakeCache.txt for subsequent runs. + + + + To be continued... + + TODO's + ------ + + 1. Get CMake to create proper distribution directories for the various platforms + like scons does. + 2. Investigate the viability of using CPack to package installs automatically. + 3. Refine this document and write detailed developer's document. + 4. Make sure all options (ffmpeg, openexr, quicktime) has proper CMake support + on the various platforms. + + /Jacques Beaurain (jbinto) + diff --git a/doc/blender-guardedalloc.txt b/doc/blender-guardedalloc.txt new file mode 100644 index 00000000000..44a9722a4e4 --- /dev/null +++ b/doc/blender-guardedalloc.txt @@ -0,0 +1,57 @@ +MEMORY MANAGEMENT IN BLENDER (guardedalloc) +------------------------------------------- + +NOTE: This file does not cover memutil and smart pointers and rerefence counted + garbage collection, which are contained in the memutil module. + +Blender takes care of dynamic memory allocation using a set of own functions +which are recognizeable through their MEM_ prefix. All memory allocation and +deallocation in blender is done through these functions. + +The following functions are available through MEM_guardedalloc.h: + +For normal operation: +--------------------- + +void *MEM_[mc]allocN(unsigned int len, char * str); + +- nearest ANSI counterpart: malloc() +- str must be a static string describing the memory block (used for debugging +memory management problems) +- returns a memory block of length len +- MEM_callocN clears the memory block to 0 + +void *MEM_dupallocN(void *vmemh); + +- nearest ANSI counterpart: combination malloc() and memcpy() +- returns a pointer to a copy of the given memory area + +short MEM_freeN(void *vmemh); + +- nearest ANSI counterpart: free() +- frees the memory area given by the pointer +- returns 0 on success and !=0 on error + +int MEM_allocN_len(void *vmemh); + +- nearest ANSI counterpart: none known +- returns the length of the given memory area + +For debugging: +-------------- + +void MEM_set_error_stream(FILE*); + +- this sets the file the memory manager should use to output debugging messages +- if the parameter is NULL the messages are suppressed +- default is that messages are suppressed + +void MEM_printmemlist(void); + +- if err_stream is set by MEM_set_error_stream() this function dumps a list of all +currently allocated memory blocks with length and name to the stream + +int MEM_check_memory_integrity(void); + +- this function tests if the internal structures of the memory manager are intact +- returns 0 on success and !=0 on error diff --git a/doc/blender-scons-dev.txt b/doc/blender-scons-dev.txt new file mode 100644 index 00000000000..d13ea7c036f --- /dev/null +++ b/doc/blender-scons-dev.txt @@ -0,0 +1,194 @@ +$Id$ + + + Internals of Blenders SCons scripts + =================================== + + Scope + ------ + This document describes the architecture of the SCons scripts for + Blender. An overview of available functionality and how to modify, + extend and maintain the system. + + Audience + -------- + This document is for developers who need to modify the system, + ie. add or remove new libraries, add new arguments for SCons, etc. + + Files and their meaning + ----------------------- + + The main entry point for the build system is the SConstruct-file in + $BLENDERHOME. This file creates the first BlenderEnvironment to work + with, reads in options, and sets up some directory structures. Further + it defines some targets. + + Platform-specific configurations are in $BLENDERHOME/config. The + filenames have the form (platform)-config.py, where platform one of: + + * darwin + * linux2 + * win32-mingw + * win32-vc + + The user can override options by creating a file + $BLENDERHOME/user-config.py. It can have any option from + (platform)-config.py. Options in this file will override the platform + defaults. + + Much of the actual functionality can be found in the python scripts + in the directory $BLENDERHOME/tools, with Blender.py defining the + bulk of the functionality. btools.py has some helper functions, and + bcolors.py is for the terminal colours. mstoolkit.py and crossmingw.py + are modules which set up SCons for the MS VC++ 2003 toolkit and + the cross-compile toolset for compiling Windows binaries on Linux + respectively. Note: the cross-compile doesn't work yet for Blender, + but is added in preparation for having it work in the distant future. + + BlenderEnvironment + ------------------ + + The module Blender.py implements a BlenderEnvironment class, derived + from the SConsEnvironment of SCons. This is done to wrap some often + used functionality. The BlenderEnvironment offers two important + wrappers: BlenderProg() and BlenderLib(). The first one is used to + specify a binary to be built, the second one is used to specify what + static library is built from given sources. + + Build a static library called "somelib". The system handles library + pre- and suffixes automatically, you don't need to bother yourself + with these details: + + env = BlenderEnvironment(ENV = os.environ) # create an environment + env.BlenderLib(libname="somelib", sources=['list.c','with.c','sources.c'], + includes=['/list/with/include/paths', '.', '..'], + defines=['LIST_WITH', 'CPP_DEFINES', 'TO_USE'], + libtype=['blender', 'common'] # this is a list with libtypes. Normally you don't + # need to specify this, but if you encounter linking + # problems you may need this + priority=[10, 20] # Priorities, list as long as libtype, priority per type + compileflags=['/O2'] # List of compile flags needed for this particular library. + # used only in rare cases, like SOLID, qhull and Bullet + ) + + There should be no need to ever add an extra BlenderProg to the + existing ones in SConstruct, see that file for its use, and Blender.py + for its implementation. + + The new system works so that using these wrappers, has all libraries + (and programs) register with a central repository. This means that + adding a new library is as easy as just creating the new SConscript + and making sure that it gets called properly. Linking and such will + then be handled automatically. + + If you want that adding new source files for a certain library + is handled automatically, you can use the Glob() function from + the BlenderEnvironment to create lists of needed files. See + $BLENDERHOME/source/blender/src/SConscript for an example. Keep in + mind that this will add any new file that complies to the rule given + to the Glob() function. There are a few (external) libraries with + which this can't be used, because it'd take files that shouldn't be + compiled, and create subsequentially problems during the linking stage + (like SOLID, qhull, Bullet). + + Linking order and priorities + ---------------------------- + + As shown above, you can give a library a priority in a certain + group. If you need to make sure that a Blender library is linked + before or after another one, you can give it a priority. To debug + the priorities us BF_PRIORITYLIST=1 on the command-line while running + a build. + + % scons BF_PRIORITYLIST=1 + + This will give a list with values suggested by the system. Make + changes to all SConscripts in question to reflect or change the + values given by this command. ALWAYS check this after adding a new + internal, external library or core library, and make sure there are + sane values. You can use large and negative numbers to test with, + but after you've got a working linking order, do change the system + to reflect BF_PRIORITYLIST values. + + Also, if you find that a library needs to be given multiple times to + the linker, you can do that by giving a python list with the names + of the available library types. They are currently: + + B.possible_types = ['core', 'common', 'blender', 'intern', + 'international', 'game', 'game2', + 'player', 'player2', 'system'] + + More groups can be added, but that should be carefully considered, + as it may lead to large-scale changes. The current amount of libraries + should suffice. + + The central repository is utilised in the SConstruct in two + ways. Firstly, it is used to determine the order of all static + libraries to link into the main Blender executable. Secondly, it + is used to keep track of all built binaries and their location, + so that they can be properly copied to BF_INSTALLDIR. + + The libraries can be fetched in their priority order with + create_blender_liblist from Blender.py, see the SConstruct on how + it is used. + + The program repository is the global list program_list from + Blender.py. See SConstruct for its usage. + + + Adding a new option and libraries + --------------------------------- + + Lets say we want to add WITH_BF_NEWLIB, which will + enable or disable a new feature library with sources in + $BLENDERHOME/source/blender/newlib. This 'newlib' needs external + headers from a 3rd party library '3rdparty'. For this we want to + add a set of options BF_3RDPARTY, BF_3RDPARTY_INC, BF_3RDPARTY_LIB, + BF_3RDPARTY_LIBPATH: + + 1) Add all mentiond options to all (platform)-config.py + files. WITH_BF_NEWLIB is a boolean option ('true', 'false'), + the rest are strings with paths and library names. See the + OpenEXR options for example. + + 2) Add all options to the argument checking function + validate_arguments() in btools.py. See again OpenEXR options + for example. + + 3) Add all options to the option reading function read_opts() + in btools.py. See again OpenEXR options for example. All default + values can be empty, as the actual default values are in the + (platform)-config.py files. + + 4) Add BF_3RDPARTY_LIB to the function setup_syslibs() + and BF_3RDPARTY_LIBPATH to the function setup_staticlibs() + in Blender.py + + At this stage we have prepared all option setting and linking needs, + but we still need to add in the compiling of the 'newlib'. + + 5) Create a SConscript in $BLENDERHOME/source/blender/newlib. Look + at ie. $BLENDERHOME/source/blender/src/SConscript for + template. The new SConscript will register the new library + like so: + + env.BlenderLib(libname='newlib', sources=sourcefiles, includes=incs) # the rest of the arguments get defaults = empty lists and values + + 6) Edit $BLENDERHOME/source/blender/SConscript with the following + addition: + + if env['WITH_BF_NEWLIB'] == 1: + SConscript(['newlib/SConscript']) + + After this you can see if this works by trying to build: + + % scons WITH_BF_NEWLIB=1 # build with newlib + % scons WITH_BF_NEWLIB=0 # disable newlib + + This is all what should be needed. Changing the library name doesn't + need changes elsewhere in the system, as it is handled automatically + with the central library repository. + + Enjoy the new system! + + /Nathan Letwory (jesterKing) diff --git a/doc/blender-scons.txt b/doc/blender-scons.txt new file mode 100644 index 00000000000..8c71c31db0c --- /dev/null +++ b/doc/blender-scons.txt @@ -0,0 +1,236 @@ +$Id$ + + Note: The current official release of SCons is 0.97 + + Blenders SCons build scripts + ============================ + + Introduction + ------------ + + Since the beginning of 2004 Blender has had the SCons system as a + build option. SCons is a Python-based, accurate build system. The + scripts that were implemented in the first iteration worked, but + the system grew quickly into such a state that maintaining it became + a nightmare, and adding new features was just horrible, leading to + many hacks without much sense in the overall structure. + + The rewrite has been waiting for a long time. Jonathan Jacobs provided + a first overhaul of the scripts, which I used in the first phase of + the rewrite. To make the system as maintainable as possible I made + some radical changes, but thanks go to Jonathan for providing me + with the patch to get started. + + This document describes the usage of the new SCons scripts. The + inner workings are described in blender-scons-dev.txt. + + Building Blender + ---------------- + + To build Blender with the SCons scripts you need a full Python + install, version 2.4 or later (http://www.python.org) and a SCons + installation, version v0.97 (http://www.scons.org). + + Check from the page + http://www.blender.org/development/building-blender/getting-dependencies/ + that you have all dependencies needed for building Blender. Note that for + windows many of these dependencies already come in the lib/windows module + from CVS. + + In the base directory of the sources (from now on called $BLENDERHOME) + you'll see a file named SConstruct. This is the entry point for the + SCons build system. In a terminal, change to this directory. To just + build, issue the command 'scons': + + % scons + + This will start the build process with default values. Depending + on your platform you may see colour in your output (non-Windows + machines). In the the beginning an overview of targets and arguments + from the command-line is given, then all libraries and binaries to + build are configured. + + The build uses BF_BUILDDIR to build into and BF_INSTALLDIR to + finally copy all needed files to get a proper setup. These + variabbles have default values for every platform in + $BLENDERHOME/config/(platform)-config.py. After the build successfully + completes, you can find everything you need in BF_INSTALLDIR. + + + Configuring the build + --------------------- + + The default values for your platform can be found in the directory + $BLENDERHOME/config. Your platform specific defaults are in + (platform)-config.py, where platform is one of: + + - linux2, for machines running Linux + - win32-vc, for Windows machines, compiling with a Microsoft compiler + - win32-mingw, for Windows machines, compiling with the MingW compiler + - darwin, for OS X machines + (TBD: add cygwin, solaris and freebsd support) + + These files you will normally not change. If you need to override + a default value, make a copy of the proper configuration to + $BLENDERHOME/user-config.py. This file you can modify to your + likings. Any value set here will override the ones from the + (platform)-config.py. + + If you want to quickly test a new setting, you can give the option + also on the command-line: + + % scons BF_BUILDDIR=../mybuilddir WITH_BF_OPENEXR=0 + + This command sets the build directory to BF_BUILDDIR and disables + OpenEXR support. + + If you need to know what can be set through the command-line, run + scons with -h: + + % scons -h + + This command will print a long list with settable options and what + every option means. Many of the default values will be empty, and + from a fresh checkout without a user-config.py the actual values + are the defaults as per $BLENDERHOME/config/(platform)-config.py + (unless you have overridden any of them in your + $BLENDERHOME/user-config.py). + + NOTE: The best way to avoid confusion is the + copy $BLENDERHOME/config/(platform)-config.py to + $BLENDERHOME/user-config.py. You should NEVER have to modify + $BLENDERHOME/config/(platform)-config.py + + Configuring the output + ---------------------- + + This rewrite features a cleaner output during the build process. If + you need to see the full command-line for compiles, then you can + change that behaviour. Also the use of colours can be changed: + + % scons BF_FANCY=0 + + This will disable the use of colours. + + % scons BF_QUIET=0 + + This will give the old, noisy output. Every command-line per + compile is printed out in its full glory. This is very useful when + debugging problems with compiling, because you can see what the + included paths are, what defines are given on the command-line, + what compiler switches are used, etc. + + Compiling Only Some Libraries + ----------------------------- + + Scons now has support for specifying a list of libraries that are + exclusively compiled, ignoring all other libraries. This is invoked + with the BF_QUICK arguments; for example: + + % scons BF_QUICK=src,bf_blenkernel + + Note that this not the same as passing a list of folders as in the + makefile's "quicky" command. In Scons, all of Blender's code modules + are in their own static library; this corresponds to one-lib-per-folder + in some cases (especially in blender/source/blender). + + To obtain a list of the libraries, simple fire up scons and CTRL-C out once + it finishes configuring (and printing to the console) the library list. + + Compiling Libraries With Debug Profiling + ---------------------------------------- + + Scons has support for specifying a list of libraries that are compiled + with debug profiling enabled. This is implemented in two commands: + BF_QUICKDEBUG which is a command-line argument and BF_DEBUG_LIBS, which goes + in your user-config.py + + BF_QUICKDEBUG is similar to BF_QUICK: + + % scons BF_QUICKDEBUG=src,bf_blenkernel,some-other-lib + + To use BF_DEBUG_LIBS, put something like the following in you user-config.py: + + BF_DEBUG_LIBS = ['bf_blenlib', 'src', 'some_lib'] + + For instructions on how to find the names of the libraries (folders) you + wish to use, see the above section. Note that the command BF_DEBUG + (see below) will override these settings and compile ALL of Blender with + debug symbols. Also note that BF_QUICKDEBUG and BF_DEBUG_LIBS are combined; + for example, setting BF_QUICKDEBUG won't overwrite the contents of BF_DEBUG_LIBS. + + + Not installing + -------------- + + If you dont want to install the build result, you can use the following option either + on the commandline or in your user-config.py : + + WITHOUT_BF_INSTALL='true' + + by default, this is set to 'false', and so the build is installed + + + Supported toolset + ----------------- + + WINDOWS + + * msvc, this is a full install of Microsoft Visual C++. You'll + likely have the .NET Framework SDK, Platform SDK and DX9 SDK + installed * mstoolkit, this is the free MS VC++ 2003 Toolkit. You + need to verify you have also the SDKs installed as mentioned + for msvc. * mingw, this is a minimal MingW install. TBD: write + proper instructions on getting needed packages. + + On Windows with all of the three toolset installed you need to + specify what toolset to use + + % scons BF_TOOLSET=msvc + % scons BF_TOOLSET=mstoolkit + % scons BF_TOOLSET=mingw + + If you have only the toolkit installed, you will also need to give + BF_TOOLSET=mstoolkit on the command-line, to make sure everything is + setup properly. Currently there is no good mechanism to automatically + determine wether the found 'cl.exe' is from the toolkit or from a + complete install. + + LINUX and OS X + + Currently only the default toolsets are supported for these platforms, + so nothing special needs to be told to SCons when building. The + defaults should work fine in most cases. + + Examples + -------- + + Build Blender with the defaults: + + % scons + + Build Blender, but disable OpenEXR support: + + % scons WITH_BF_OPENEXR=0 + + Build Blender, enable debug symbols: + + % scons BF_DEBUG=1 + + Build Blender, install to different directory: + + % scons BF_INSTALLDIR=/tmp/testbuild + + Build Blender in /tmp/obj and install to /usr/local: + + % scons BF_BUILDDIR=/tmp/obj BF_INSTALLDIR=/usr/local + + Clean BF_BUILDDIR: + + % scons clean + + Clean out the installed files: + + % scons -c + + /Nathan Letwory (jesterKing) diff --git a/doc/doxygen.main b/doc/doxygen.main new file mode 100644 index 00000000000..1965de3c2dc --- /dev/null +++ b/doc/doxygen.main @@ -0,0 +1,63 @@ +/** \mainpage Blender + * + * \section intro Introduction + * + * Blender is an integrated 3d package, which features: + * - modeling + * - animation + * - texturing + * - compositing + * - rendering + * - scripting + * - game creation + * + * These pages document the source code of blender. + * + * \section sects Main sections of the blender code + * + * The following sections are the broad categories into which the various modules + * belong. + * + * - \ref mainmodule + * - \ref render + * - \ref meshedit + * - \ref texture + * - \ref compositor + * - \ref scripts + * - \ref gameengine + * + * \section GUI + * - \ref gui + * - \ref hotkeys + * - \ref toolbox + * + * \section Libraries and Wrappers + * - GHOST API: \ref GHOST_C-api.h + * - \ref imbuf + * + * \section Miscellaneous + * - \ref undoc + */ + +/** \defgroup mainmodule Main Module */ +/** \defgroup defaultconfig Default and Configuration + * \ingroup mainmodule + */ + +/** \defgroup render Rendering Module */ +/** \defgroup meshedit Mesh Editing Module */ +/** \defgroup texture Textureing */ +/** \defgroup compositor Compositing */ +/** \defgroup scripts Scripting */ +/** \defgroup gameengine Game Engine */ + +/** \defgroup gui GUI */ +/** \defgroup hotkeys Hotkeys + * \ingroup gui + */ +/** \defgroup toolbox Toolbox + * \ingroup gui + */ + +/** \defgroup imbuf IMage Buffer */ +/** \defgroup undoc Undocumented */ diff --git a/doc/interface_API.txt b/doc/interface_API.txt new file mode 100644 index 00000000000..c98794444e6 --- /dev/null +++ b/doc/interface_API.txt @@ -0,0 +1,515 @@ +--------------------------------------------------- +Blender interface.c API toolkit notes +(july 2003, Ton Roosendaal) +--------------------------------------------------- + +Contents + +1 General notes +1.1 C and H files + +2. Windows & Blocks +2.1 Memory allocation +2.2 And how it works internally + +3. API for uiBlock +3.1 uiBlock Controlling functions +3.2 Internal function to know + +4. API for uiButton +4.1 UiDefBut + 1. BUT + 2. TOG or TOGN or TOGR + TOG|BIT| + 3. TOG3|BIT| + 4. ROW + 5. SLI or NUMSLI or HSVSLI + 6. NUM + 7. TEX + 8. LABEL + 9 SEPR + 10. MENU + 11. COL +4.2 Icon buttons + 12. ICONROW + 13. ICONTEXTROW +4.3 pulldown menus / block buttons + 14. BLOCK +4.4 specials + 15. KEYEVT + 16. LINK and INLINK + 17. IDPOIN +4.5 uiButton control fuctions + + +----------------1. General notes + +- The API is built with Blender in mind, with some buttons acting on lists of Blender data. + It was not meant to be available as a separate SDK, nor to be used for other applications. + +- It works with only OpenGL calls, for the full 100%. This means that it has some quirks + built-in to work with all OS's and OpenGL versions. Especially frontbuffer drawing is + a continuous point of attention. Buttons can be drawn with any window matrix. However, + errors can still occor when buttons are created in windows with non-standard glViewports. + +- The code was written to replace the old 1.8 button system, but under high pressure. Quite + some button methods from the old system were copied for that reason. + +- I tried to design a unified GUI system, which equally works for pulldown menus, pop up menus, + and normal button layouts. Although it gives nice features and freedom in design, the code + looks quite hard to understand for that reason. Not all 'normal' pulldown menu features + could be hacked in easily, they just differ too much from other UI elements. Could be + looked at once... + +- During the past period of NaN (beginning of 2002) someone tried to make a more 'high' level + API for it, with less low level defines and structure info needed in calling code. I am not + really sure if this was done well... or even finished. In the bottom of interface.c you can + see the 'new' API which is now used in Blender code. It used to be so much more simple! + Nevertheless, I will use that convention in this doc. + +- Unfinished stuff: the code was scheduled to be expanded with 'floating blocks' which can + serve as permanent little button-fields in Blender windows. Think for example of having + an (optional) extra field in the 3d window displaying object loc/rot/size. + After that, the existing button windows can be reorganized in such blocks as well, allowing + a user to configure the genereal buttons layout (make vertical for example). + + +--------------1.1 C and H files + +blender/source/blender/src/interface.c /* almost all code */ +blender/source/blender/include/interface.h /* internals for previous code */ +blender/source/blender/include/BIF_interface.h /* externals for previous code */ + +(the previous 2 include files have not been separated fully yet) + +Color and icons stuff has been put in: (unfinished code, under development) +blender/source/blender/src/resources.c +blender/source/blender/include/BIF_resources.h + +Related code: +blender/source/blender/src/toolbox.c (extra GUI elements built on top of this API) + + +--------------2. Windows & Blocks + +All GUI elements are collected in uiBlocks, which in turn are linked together in a list that's +part of a Blender Area-window. + + uiBlock *block= uiNewBlock(&curarea->uiblocks, "stuff", UI_EMBOSSX, UI_HELV, curarea->win); + +The next code example makes a new block, and puts it in the list of blocks of the current active +Area: + + uiDoBlocks(&curarea->uiblocks, event); + +This code is usually available in each area-window event queue handler. You give uiDoBlocks +an event code, and the uiDoBlocks handles whatever is to be handled. Blocks can be +standard buttons or pull down menus. Can return immediately, or jump to an internal handling +loop. + +2.1 Memory allocation + +Important to know is that for this toolkit there's no difference in "creating blocks" or +"drawing blocks". In fact, for each window redraw all blocks are created again. Constructing +button interfaces in Blender always happens in the main drawing function itself. + +Memory allocation is handled as follows: +- if in this window a uiBlock with the same name existed, it is freed +- when you close a window (or blender) the uiBlocks get freed. +- when you duplicate (split) a window, the uiBlocks get copied + +2.2 And how it works internally + +With a call to uiDoblocks, all blocks in the current active window are evaluated. +It walks through the lists in a rather complex manner: + +- while(looping) + + /* the normal buttons handling */ + - for each block + - call uiDoBlock (handles buttons for single block) + - (end for) + + /* at this moment, a new block can be created, for a menu */ + /* so we create a 2nd loop for it */ + - while first block is a menu + - if block is a menu and not initialized: + - initalize 'saveunder' + - draw it + - get event from queue + - call uiDoBlock (handles buttons for single block) + /* here, a new block again can be created, for a sub menu */ + - if return "end" from uiDoBlock + restore 'saveunder's + free all menu blocks + exit from loop + - do tooltip if nothing has happened + - (end while) + + - if there was menu, it does this loop once more + (when you click outside a menu, at another button) + +- (end while) + +- do tooltip if nothing has happened + + + +-------------3. API for uiBlock + +Create a new buttons block, and link it to the window: + +uiBlock *uiNewBlock(ListBase *lb, char *name, short dt, short font, short win) + ListBase *lb pointer to list basis, where the block will be appended to (blenlib) + char *name unique name to identify the block. When the name exists in the list, + the old uiBlock gets freed. + short dt drawtype. See below + short font font id number + short win blender area-window id + +drawtype: + UI_EMBOSSX 0 /* Rounded embossed button (standard in Blender) */ + UI_EMBOSSW 1 /* Simpler embossed button */ + UI_EMBOSSN 2 /* Button with no border */ + UI_EMBOSSF 3 /* Square embossed button (file select) */ + UI_EMBOSSM 4 /* Colored, for pulldown menus */ + UI_EMBOSSP 5 /* Simple borderless coloured button (like blender sensors) */ + +font: + UI_HELV 0 /* normal font */ + UI_HELVB 1 /* bold font */ +With the new truetype option in Blender, this is used for all font families + +When a uiBlock is created, each uiButton that is defined gets the uiBlock properties. +Changing Block properties inbetween will affact uiButtons defined thereafter. + + + +----------3.1 uiBlock Controlling functions: + +void uiDrawBlock(block) + draws the block + +void uiBlockSetCol(uiBlock *block, int col) + +col: + BUTGREY, + BUTGREEN, + BUTBLUE, + BUTSALMON, + MIDGREY, + BUTPURPLE, + +void uiBlockSetEmboss(uiBlock *block, int emboss) + changes drawtype + +void uiBlockSetDirection(uiBlock *block, int direction) + for pop-up and pulldown menus: + +direction: + UI_TOP + UI_DOWN + UI_LEFT + UI_RIGHT + +void uiBlockSetXOfs(uiBlock *block, int xofs) + for menus, offset from parent + +void uiBlockSetButmFunc(uiBlock *block, void (*menufunc)(void *arg, int event), void *arg) + sets function to be handled when a menu-block is marked "OK" + +void uiAutoBlock(uiBlock *block, float minx, float miny, float sizex, float sizey, UI_BLOCK_ROWS) + + Sets the buttons in this block to automatically align, and fit within boundaries. + Internally it allows multiple collums or rows as well. Only 'row order' has been implemented. + The uiDefBut definitions don't need coordinates as input here, but instead: + - first value (x1) to indicate row number + - width and height values (if filled in) will be used to define a relative width/height. + A call to uiDrawBlock will invoke the calculus to fit in all buttons. + + + +---------- 3.2 Internal function to know: + +These flags used to be accessible from outside of interface.c. Currently it is only +used elsewhere by toolbox.c, so it can be considered 'internal' somewhat. + +void uiBlockSetFlag(uiBlock *block, int flag) /* block types, can be 'OR'ed */ + UI_BLOCK_LOOP 1 a sublooping block, drawn in frontbuffer, i.e. menus + UI_BLOCK_REDRAW 2 block needs a redraw + UI_BLOCK_RET_1 4 block is closed when an event happens with value '1' (press key, not for mouse) + UI_BLOCK_BUSY 8 internal + UI_BLOCK_NUMSELECT 16 keys 1-2-...-9-0 can be used to select items + UI_BLOCK_ENTER_OK 32 enter key closes block with "OK" + +(these values are being set within the interface.c and toolbox.c code.) + + +-------------4. API for uiButton + +In Blender a button can do four things: + +- directly visualize data, and write to it. +- put event codes (shorts) back in the queue, to be handled +- call a user-defined function pointer (while being pressed, etc) +- create and call another block (i.e. menu) + +Internally, each button or menu item is a 'uiButton', with a generic API and handling: +ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); + +Beacause a lot of obscure generic (re-use) happens here, translation calls have been made +for each most button types individually. + + +-----------4.1 UiDefBut + +uiBut *UiDefBut[CSIF]( uiBlock *block, int type, int retval, char *str, + short x1, short y1, short x2, short y2, xxxx *poin, + float min, float max, float a1, float a2, char *tip) + +UiDefButC operatates on char +UiDefButS operatates on short +UiDefButI operatates on int +UiDefButF operatates on float + +*block: current uiBlock pointer +type: see below +retval: return value, which is put back in queue +*str: button name +x1, y1: coordinates of left-lower corner +x2, y2: width, height +*poin: pointer to char, short, int, float +min, max used for slider buttons +a1, a2 extra info for some buttons +*tip: tooltip string + +type: + +1. BUT + Activation button. (like "Render") + Passing on a pointer is not needed + +2. TOG or TOGN or TOGR + Toggle button (like "Lock") + The pointer value is set either at 0 or 1 + If pressed, it calls the optional function with arguments provided. + Type TOGN: works negative, when pressed it sets at 0 + Type TOGR: is part of a row, redraws automatically all buttons with same *poin + + "|BIT|" + When added to type, it works on a single bit (lowest order bit: nr = '0') + +3. TOG3|BIT| + A toggle with 3 values! + Can be only used for short *poin. + In the third toggle setting, the bit of *( poin+1) is set. + +4. ROW + Button that's part of a row. + in "min" you set a row-id number, in "max" the value you want *poin to be + assigned when you press the button. Always pass on these values as floats. + When this button is pressed, it sets the "max" value to *poin, and redraws + all buttons with the same row-id number. + +5. SLI or NUMSLI or HSVSLI + Slider, number-slider or hsv-slider button. + "min" and "max" are to clamp the value to. + If you want a button type "Col" to be updated, make 'a1' equal to 'retval' + from the COL button. + +6. NUM + Number button + Set the clamping values 'min' and 'max' always as float. + For UiDefButF, set a 'step' in 'a1', in 1/100's. The step value is the increment or + decrement when you click once on the right or left side of a button. + The optional button function is additionally called for each change of the *poin value. + +7. TEX + Text string button. + Pointertype is standard a char. Value 'max' is length of string (pass as float). + When button is left with ESC, it doesn't put the 'retval' at the queue. + +8. LABEL + Label button. + Only displays text. + If 'min' is set at 1.0, the text is printed in white. + +9 SEPR + A separator line, typically used within pulldown menus. + +10. MENU + Menu button. + The syntax of the string in *name defines the menu items: + - %t means the previous text becomes the title + - item separator is '|' + - return values are indicated with %x[nr] (i.e: %x12). + without returnvalues, the first item gets value 0 (incl. title!) + Example: "Do something %t| turn left %2| turn right %1| nothing %0" + +11. COL + A special button that only visualizes a RGB value + In 'retval' you can put a code, which is used to identify for sliders if it needs + redraws while using the sliders. Check button '5'. + As *poin you input the pointer to the 'r' value, 'g' and 'b' are supposed to be + next to that. + + +------------4.2 Icon buttons + +Instead of a 'name', all buttons as described for uiDefBut also can have an icon: + +uiBut *uiDefIconBut(uiBlock *block, int type, int retval, int icon, + short x1, short y1, short x2, short y2, void *poin, + float min, float max, float a1, float a2, char *tip) + + Same syntax and types available as previous uiDefBut, but now with an icon code + instead of a name. THe icons are numbered in resources.c + +uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, int icon, char *str, + short x1, short y1, short x2, short y2, float *poin, + float min, float max, float a1, float a2, char *tip) + + Same again, but now with an icon and string as button name. + +Two special icon buttons are available in Blender: + +12. ICONROW + (uiDefIconBut) + This button pops up a vertical menu with a row of icons to choose from. + 'max' = amount of icons. The icons are supposed to be ordered in a sequence + It writes in *poin which item in the menu was choosen (starting with 0). + +13. ICONTEXTROW + (uiDefIconTextBut) + Same as previous, but with the texts next to it. + + + +-----------4.3 pulldown menus / block buttons + +14. BLOCK +void uiDefBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, char *str, + short x1, short y1, short x2, short y2, char *tip) + + This button creates a new block when pressed. The function argument 'func' is called + to take care of this. An example func: + + static uiBlock *info_file_importmenu(void *arg_unused) + { + uiBlock *block; + short yco= 0, xco = 20; + + block= uiNewBlock(&curarea->uiblocks, "importmenu", UI_EMBOSSW, UI_HELV, G.curscreen->mainwin); + uiBlockSetXOfs(block, -40); // offset to parent button + + /* flags are defines */ + uiDefBut(block, LABEL, 0, "VRML 2.0 options", xco, yco, 125, 19, NULL, 0.0, 0.0, 0, 0, ""); + uiDefButS(block, TOG|BIT|0, 0, "SepLayers", xco, yco-=20, 75, 19, &U.vrmlflag, 0.0, 0.0, 0, 0, ""); + uiDefButS(block, TOG|BIT|1, 0, "Scale 1/100", xco, yco-=20, 75, 19, &U.vrmlflag, 0.0, 0.0, 0, 0, ""); + uiDefButS(block, TOG|BIT|2, 0, "Two Sided", xco, yco-=20, 75, 19, &U.vrmlflag, 0.0, 0.0, 0, 0, ""); + + uiBlockSetDirection(block, UI_RIGHT); + uiTextBoundsBlock(block, 50); // checks for fontsize + + return block; + } + + The uiDef coordinates here are only relative. When this function is called, the interface + code automatically makes sure the buttons fit in the menu nicely. + + Inside a menu uiBlock, other uiBlocks can be invoked to make a hierarchical menu. + + + +-----------4.4 specials + +15. KEYEVT + +void uiDefKeyevtButS(uiBlock *block, int retval, char *str, + short x1, short y1, short x2, short y2, short *spoin, char *tip) + + A special button, which stores a keyvalue in *spoin. When the button is pressed, + it displays the text 'Press any Key'. A keypress then stores the value. + +16. LINK and INLINK + + These button present a method of linking data in Blender, by drawing a line from one + icon to another. It consists of two button types: + + LINK, the 'linking from' part, can be: + - a single pointer to data (only one line allowed) + - an array of pointers to data. The LINK buttons system keeps track of allocating + space for the array, and set the correct pointers in it. + + INLINK, the 'linking to' part activates creating a link, when a user releases the mouse + cursor over it, while dragging a line from the LINK button. + + These buttons are defined as follows: + + +uiBut but= uiDefIconBut(block, LINK, 0, ICON_LINK, x1, y1, w, h, NULL, 0, 0, 0, 0, ""); + /* create the LINK icon */ + +uiSetButLink(but, void **pt, void ***ppt, short *totlink, short fromcode, short tocode); + **pt: pointer to pointer (only one link allowed) + ***ppt: pointer to pointerpointer (an array of pointers) + (Either one of these values should be NULL) + + fromcode: (currently unused) + tocode: a short indicating which blocks it can link to. + + +uiDefIconBut(block, INLINK, 0, ICON_INLINK, x1, y1, w, h, void *poin, short fromcode, 0, 0, 0, ""); + poin: the pointer of the datablock you want to create links to + fromcode: a short identifying which LINK buttons can connect to it + + + +17. IDPOIN +void uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, int retval, char *str, + short x1, short y1, short x2, short y2, void *idpp, char *tip) + + The ID struct is a generic part in structs like Object, Material, Mesh, etc. + Most linking options in Blender happens using ID's. (Mesh -> Material). + + This special button in Blender visualizes an ID pointer with its name. Typing in + a new name, changes the pointer. For most ID types in Blender functions have been + written already, needed by this button, to check validity of names, and assign the pointer. + + (BTW: the 'void *idpp' has to be a pointer to the ID pointer!) + + Example function that can be put in 'func': + + void test_scriptpoin_but(char *name, ID **idpp) + { + ID *id; + + id= G.main->text.first; + while(id) { + if( strcmp(name, id->name+2)==0 ) { + *idpp= id; + return; + } + id= id->next; + } + *idpp= 0; + } + + +------------- 4.5 uiButton control fuctions + + +void uiButSetFunc(uiBut *but, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2) + When the button is pressed and released, it calls this function, with the 2 arguments. + +void uiButSetFlag(uiBut *but, int flag) + set a flag for further control of button behaviour: + flag: + UI_TEXT_LEFT + +int uiButGetRetVal(uiBut *but) + gives return value + + + +


diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt new file mode 100644 index 00000000000..0f07bde72d5 --- /dev/null +++ b/extern/CMakeLists.txt @@ -0,0 +1,45 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +IF(WITH_GAMEENGINE) + SUBDIRS(qhull solid) + + IF(WITH_BULLET) + SUBDIRS(bullet2) + ENDIF(WITH_BULLET) +ENDIF(WITH_GAMEENGINE) + +IF(WITH_INTERNATIONAL) + SUBDIRS(bFTGL) +ENDIF(WITH_INTERNATIONAL) + +IF(WITH_VERSE) + SUBDIRS(verse) +ENDIF(WITH_VERSE) + diff --git a/extern/Makefile b/extern/Makefile new file mode 100644 index 00000000000..04b282a8926 --- /dev/null +++ b/extern/Makefile @@ -0,0 +1,76 @@ +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2002 by Hans Lambermont +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Bounces make to subdirectories. Also installs after succesful all target. + +include nan_definitions.mk + +SOURCEDIR = extern +DIR = $(OCGDIR)/extern +DIRS = qhull/src solid + +ifeq ($(WITH_FREETYPE2), true) + DIRS += bFTGL/src +endif + +ifeq ($(WITH_FFMPEG), true) +ifeq ($(NAN_FFMPEG), $(LCGDIR)/ffmpeg) + DIRS += ffmpeg +endif +ifeq ($(NAN_FFMPEG), $(LCGDIR)/gcc/ffmpeg) + DIRS += ffmpeg +endif +endif + +ifeq ($(WITH_VERSE), true) + DIRS += verse +endif + +ifneq ($(NAN_NO_KETSJI), true) + DIRS += bullet2 +endif + +TARGET = +ifneq ($(OS),irix) + TARGET=solid +endif + +all:: + @[ -d $(OCGDIR)/extern ] || mkdir -p $(OCGDIR)/extern + @for i in $(DIRS); do \ + echo "====> $(MAKE) $@ in $(SOURCEDIR)/$$i" ;\ + $(MAKE) -C $$i install || exit 1; \ + done + +clean test debug:: + @[ -d $(OCGDIR)/extern ] || mkdir -p $(OCGDIR)/extern + @for i in $(DIRS); do \ + echo "====> $(MAKE) $@ in $(SOURCEDIR)/$$i" ;\ + $(MAKE) -C $$i $@ || exit 1; \ + done diff --git a/extern/SConscript b/extern/SConscript new file mode 100644 index 00000000000..924b7f54507 --- /dev/null +++ b/extern/SConscript @@ -0,0 +1,18 @@ +#!/usr/bin/python + +Import('env') + +if env['WITH_BF_GAMEENGINE']: + SConscript(['qhull/SConscript', + 'solid/SConscript']) + if env['WITH_BF_BULLET']: + SConscript(['bullet2/src/SConscript']) + +if env['WITH_BF_INTERNATIONAL']: + SConscript(['bFTGL/SConscript']) + +if env['WITH_BF_VERSE']: + SConscript(['verse/dist/SConstruct']) + +if env['WITH_BF_FFMPEG'] and env['BF_FFMPEG_LIB'] == '': + SConscript(['ffmpeg/SConscript']); diff --git a/extern/bFTGL/CMakeLists.txt b/extern/bFTGL/CMakeLists.txt new file mode 100644 index 00000000000..fc9aea8ea4e --- /dev/null +++ b/extern/bFTGL/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC include src ${FREETYPE_INC}) + +FILE(GLOB SRC src/*.cpp) +ADD_DEFINITIONS(-DFTGL_LIBRARY_STATIC) +BLENDERLIB(extern_ftgl "${SRC}" "${INC}") +#, libtype=['international','player'], priority=[5, 210]) diff --git a/extern/bFTGL/COPYING.txt b/extern/bFTGL/COPYING.txt new file mode 100644 index 00000000000..92b8903ff3f --- /dev/null +++ b/extern/bFTGL/COPYING.txt @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/extern/bFTGL/README.txt b/extern/bFTGL/README.txt new file mode 100644 index 00000000000..a679d86c22e --- /dev/null +++ b/extern/bFTGL/README.txt @@ -0,0 +1,51 @@ +FTGL 2.0.11 +16 August 2004 + +DESCRIPTION: + +FTGL is a free open source library to enable developers to use arbitrary +fonts in their OpenGL (www.opengl.org) applications. +Unlike other OpenGL font libraries FTGL uses standard font file formats +so doesn't need a preprocessing step to convert the high quality font data +into a lesser quality, proprietary format. +FTGL uses the Freetype (www.freetype.org) font library to open and 'decode' +the fonts. It then takes that output and stores it in a format most efficient +for OpenGL rendering. + +Rendering modes supported are +- Bit maps +- Antialiased Pix maps +- Texture maps +- Outlines +- Polygon meshes +- Extruded polygon meshes + +FTGL is designed to be used in commercial quality software. It has been +written with performance, robustness and simplicity in mind. + +USAGE: + + FTGLPixmapFont font( "Fonts:Arial"); + + font.FaceSize( 72); + + font.render( "Hello World!"); + +This library was inspired by gltt, Copyright (C) 1998-1999 Stephane Rehel +(http://gltt.sourceforge.net) +Bezier curve code contributed by Jed Soane. +Demo, Linux port, extrusion code and gltt maintainance by Gerard Lanois +Linux port by Matthias Kretz +Windows port by Andrew Ellerton & Max Rheiner +Bug fixes by Robert Osfield, Marcelo E. Magallon, Markku Rontu, Mark A. Fox, +Patrick Rogers +Containers and optimisations by Sebastien Barre +Autoconf Marcelo E. Magallon. + + +Please contact me if you have any suggestions, feature requests, or problems. + +Henry Maddocks +ftgl@opengl.geek.nz +http://homepages.paradise.net.nz/henryj/ + diff --git a/extern/bFTGL/SConscript b/extern/bFTGL/SConscript new file mode 100644 index 00000000000..bd20db5a459 --- /dev/null +++ b/extern/bFTGL/SConscript @@ -0,0 +1,30 @@ +#!/usr/bin/python +import sys +import os + +Import('env') + +# Import the C flags set in the SConstruct file +#Import ('cflags') +#Import ('defines') +#Import ('user_options_dict') + +#if sys.platform=='linux2' or sys.platform=='linux-i386': +# ftgl_env.Append (CCFLAGS = ['-O2', '-ansi']) +#elif sys.platform=='win32': + #ftgl_env.Append (CCFLAGS = ['/O2']) +#elif sys.platform=='sunos': +# ftgl_env.Append (CCFLAGS = ['Xc', '-v', '-fast']) +#elif sys.platform=='darwin': +# ftgl_env.Append (CCFLAGS = ['-O2', '-pipe', '-fPIC', '-funsigned-char', '-ffast-math']) +#else: +# ftgl_env.Append (CCFLAGS = cflags) + +#ftgl_env.Append (CPPDEFINES = defines) + +incs = 'include src ' + env['BF_FREETYPE_INC'] +defs = '' + +sources = env.Glob('src/*.cpp') + +env.BlenderLib ( 'extern_ftgl', sources, Split(incs), Split(defs), libtype=['international','player'], priority=[5, 210]) diff --git a/extern/bFTGL/cleanup b/extern/bFTGL/cleanup new file mode 100755 index 00000000000..c6d24edb287 --- /dev/null +++ b/extern/bFTGL/cleanup @@ -0,0 +1,4 @@ +#!/bin/sh -fx +# script to get rid of the grabage that MAC OSX drops in all the directories + +find . -name .DS_Store -print -exec rm {} \; diff --git a/extern/bFTGL/include/FTBBox.h b/extern/bFTGL/include/FTBBox.h new file mode 100644 index 00000000000..7ff530166ca --- /dev/null +++ b/extern/bFTGL/include/FTBBox.h @@ -0,0 +1,124 @@ +#ifndef __FTBBox__ +#define __FTBBox__ + +#include +#include FT_FREETYPE_H +//#include FT_GLYPH_H +#include FT_OUTLINE_H + +#include "FTGL.h" +#include "FTPoint.h" + + +/** + * FTBBox is a convenience class for handling bounding boxes. + */ +class FTGL_EXPORT FTBBox +{ + public: + /** + * Default constructor. Bounding box is set to zero. + */ + FTBBox() + : lowerX(0.0f), + lowerY(0.0f), + lowerZ(0.0f), + upperX(0.0f), + upperY(0.0f), + upperZ(0.0f) + {} + + /** + * Constructor. + */ + FTBBox( float lx, float ly, float lz, float ux, float uy, float uz) + : lowerX(lx), + lowerY(ly), + lowerZ(lz), + upperX(ux), + upperY(uy), + upperZ(uz) + {} + + /** + * Constructor. Extracts a bounding box from a freetype glyph. Uses + * the control box for the glyph. FT_Glyph_Get_CBox() + * + * @param glyph A freetype glyph + */ + FTBBox( FT_GlyphSlot glyph) + : lowerX(0.0f), + lowerY(0.0f), + lowerZ(0.0f), + upperX(0.0f), + upperY(0.0f), + upperZ(0.0f) + { + FT_BBox bbox; + FT_Outline_Get_CBox( &(glyph->outline), &bbox); + + lowerX = static_cast( bbox.xMin) / 64.0f; + lowerY = static_cast( bbox.yMin) / 64.0f; + lowerZ = 0.0f; + upperX = static_cast( bbox.xMax) / 64.0f; + upperY = static_cast( bbox.yMax) / 64.0f; + upperZ = 0.0f; + + } + + /** + * Destructor + */ + ~FTBBox() + {} + + + /** + * Move the Bounding Box by a vector. + * + * @param distance The distance to move the bbox in 3D space. + */ + FTBBox& Move( FTPoint distance) + { + lowerX += distance.x; + lowerY += distance.y; + lowerZ += distance.z; + upperX += distance.x; + upperY += distance.y; + upperZ += distance.z; + return *this; + } + + FTBBox& operator += ( const FTBBox& bbox) + { + lowerX = bbox.lowerX < lowerX? bbox.lowerX: lowerX; + lowerY = bbox.lowerY < lowerY? bbox.lowerY: lowerY; + lowerZ = bbox.lowerZ < lowerZ? bbox.lowerZ: lowerZ; + upperX = bbox.upperX > upperX? bbox.upperX: upperX; + upperY = bbox.upperY > upperY? bbox.upperY: upperY; + upperZ = bbox.upperZ > upperZ? bbox.upperZ: upperZ; + + return *this; + } + + void SetDepth( float depth) + { + upperZ = lowerZ + depth; + } + + + /** + * The bounds of the box + */ + // Make these ftPoints & private + float lowerX, lowerY, lowerZ, upperX, upperY, upperZ; + protected: + + + private: + +}; + + +#endif // __FTBBox__ + diff --git a/extern/bFTGL/include/FTBitmapGlyph.h b/extern/bFTGL/include/FTBitmapGlyph.h new file mode 100644 index 00000000000..89154a97fac --- /dev/null +++ b/extern/bFTGL/include/FTBitmapGlyph.h @@ -0,0 +1,76 @@ +#ifndef __FTBitmapGlyph__ +#define __FTBitmapGlyph__ + + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTGlyph.h" + + +/** + * FTBitmapGlyph is a specialisation of FTGlyph for creating bitmaps. + * + * It provides the interface between Freetype glyphs and their openGL + * Renderable counterparts. This is an abstract class and derived classes + * must implement the Render function. + * + * @see FTGlyphContainer + * + */ +class FTGL_EXPORT FTBitmapGlyph : public FTGlyph +{ + public: + /** + * Constructor + * + * @param glyph The Freetype glyph to be processed + */ + FTBitmapGlyph( FT_GlyphSlot glyph); + + /** + * Destructor + */ + virtual ~FTBitmapGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FTPoint& pen); + + private: + /** + * The width of the glyph 'image' + */ + unsigned int destWidth; + + /** + * The height of the glyph 'image' + */ + unsigned int destHeight; + + /** + * The pitch of the glyph 'image' + */ + unsigned int destPitch; + + /** + * Vector from the pen position to the topleft corner of the bitmap + */ + FTPoint pos; + + /** + * Pointer to the 'image' data + */ + unsigned char* data; + +}; + + +#endif // __FTBitmapGlyph__ + diff --git a/extern/bFTGL/include/FTBufferGlyph.h b/extern/bFTGL/include/FTBufferGlyph.h new file mode 100644 index 00000000000..9795f4de5d4 --- /dev/null +++ b/extern/bFTGL/include/FTBufferGlyph.h @@ -0,0 +1,76 @@ +#ifndef __FTBufferGlyph__ +#define __FTBufferGlyph__ + + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTGlyph.h" + + +/** + * FTBufferGlyph is a specialisation of FTGlyph for creating pixmaps. + * + * @see FTGlyphContainer + * + */ +class FTGL_EXPORT FTBufferGlyph : public FTGlyph +{ + public: + /** + * Constructor + * + * @param glyph The Freetype glyph to be processed + */ + FTBufferGlyph( FT_GlyphSlot glyph, unsigned char* clientBuffer); + + /** + * Destructor + */ + virtual ~FTBufferGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FTPoint& pen); + + // attributes + + private: + /** + * The width of the glyph 'image' + */ + int destWidth; + + /** + * The height of the glyph 'image' + */ + int destHeight; + + /** + * The pitch of the glyph 'image' + */ + unsigned int destPitch; + + /** + * Vector from the pen position to the topleft corner of the pixmap + */ + FTPoint pos; + + /** + * Pointer to the 'image' data + */ + unsigned char* data; + + + unsigned char* buffer; + +}; + + +#endif // __FTBufferGlyph__ diff --git a/extern/bFTGL/include/FTCharToGlyphIndexMap.h b/extern/bFTGL/include/FTCharToGlyphIndexMap.h new file mode 100644 index 00000000000..6e40d3c9574 --- /dev/null +++ b/extern/bFTGL/include/FTCharToGlyphIndexMap.h @@ -0,0 +1,130 @@ +#ifndef __FTCharToGlyphIndexMap__ +#define __FTCharToGlyphIndexMap__ + +#include + +#include "FTGL.h" + +/** + * Provides a non-STL alternative to the STL map + * which maps character codes to glyph indices inside FTCharmap. + * + * Implementation: + * - NumberOfBuckets buckets are considered. + * - Each bucket has BucketSize entries. + * - When the glyph index for the character code C has to be stored, the + * bucket this character belongs to is found using 'C div BucketSize'. + * If this bucket has not been allocated yet, do it now. + * The entry in the bucked is found using 'C mod BucketSize'. + * If it is set to IndexNotFound, then the glyph entry has not been set. + * - Try to mimic the calls made to the STL map API. + * + * Caveats: + * - The glyph index is now a signed long instead of unsigned long, so + * the special value IndexNotFound (= -1) can be used to specify that the + * glyph index has not been stored yet. + */ +class FTGL_EXPORT FTCharToGlyphIndexMap +{ + public: + + typedef unsigned long CharacterCode; + typedef signed long GlyphIndex; + + enum + { + NumberOfBuckets = 256, + BucketSize = 256, + IndexNotFound = -1 + }; + + FTCharToGlyphIndexMap() + { + this->Indices = 0; + } + + virtual ~FTCharToGlyphIndexMap() + { + if( this->Indices) + { + // Free all buckets + this->clear(); + + // Free main structure + delete [] this->Indices; + this->Indices = 0; + } + } + + void clear() + { + if(this->Indices) + { + for( int i = 0; i < FTCharToGlyphIndexMap::NumberOfBuckets; i++) + { + if( this->Indices[i]) + { + delete [] this->Indices[i]; + this->Indices[i] = 0; + } + } + } + } + + const GlyphIndex find( CharacterCode c) + { + if( !this->Indices) + { + return 0; + } + + // Find position of char code in buckets + div_t pos = div( c, FTCharToGlyphIndexMap::BucketSize); + + if( !this->Indices[pos.quot]) + { + return 0; + } + + const FTCharToGlyphIndexMap::GlyphIndex *ptr = &this->Indices[pos.quot][pos.rem]; + if( *ptr == FTCharToGlyphIndexMap::IndexNotFound) + { + return 0; + } + + return *ptr; + } + + void insert( CharacterCode c, GlyphIndex g) + { + if( !this->Indices) + { + this->Indices = new GlyphIndex* [FTCharToGlyphIndexMap::NumberOfBuckets]; + for( int i = 0; i < FTCharToGlyphIndexMap::NumberOfBuckets; i++) + { + this->Indices[i] = 0; + } + } + + // Find position of char code in buckets + div_t pos = div(c, FTCharToGlyphIndexMap::BucketSize); + + // Allocate bucket if does not exist yet + if( !this->Indices[pos.quot]) + { + this->Indices[pos.quot] = new GlyphIndex [FTCharToGlyphIndexMap::BucketSize]; + for( int i = 0; i < FTCharToGlyphIndexMap::BucketSize; i++) + { + this->Indices[pos.quot][i] = FTCharToGlyphIndexMap::IndexNotFound; + } + } + + this->Indices[pos.quot][pos.rem] = g; + } + + private: + GlyphIndex** Indices; +}; + + +#endif // __FTCharToGlyphIndexMap__ diff --git a/extern/bFTGL/include/FTCharmap.h b/extern/bFTGL/include/FTCharmap.h new file mode 100644 index 00000000000..74ca6f2cacb --- /dev/null +++ b/extern/bFTGL/include/FTCharmap.h @@ -0,0 +1,136 @@ +#ifndef __FTCharmap__ +#define __FTCharmap__ + + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTCharToGlyphIndexMap.h" + +#include "FTGL.h" + + +/** + * FTCharmap takes care of specifying the encoding for a font and mapping + * character codes to glyph indices. + * + * It doesn't preprocess all indices, only on an as needed basis. This may + * seem like a performance penalty but it is quicker than using the 'raw' + * freetype calls and will save significant amounts of memory when dealing + * with unicode encoding + * + * @see "Freetype 2 Documentation" + * + */ + +class FTFace; + +class FTGL_EXPORT FTCharmap +{ + public: + /** + * Constructor + */ + FTCharmap( FTFace* face); + + /** + * Destructor + */ + virtual ~FTCharmap(); + + /** + * Queries for the current character map code. + * + * @return The current character map code. + */ + FT_Encoding Encoding() const { return ftEncoding;} + + /** + * Sets the character map for the face. + * Valid encodings as at Freetype 2.0.4 + * ft_encoding_none + * ft_encoding_symbol + * ft_encoding_unicode + * ft_encoding_latin_2 + * ft_encoding_sjis + * ft_encoding_gb2312 + * ft_encoding_big5 + * ft_encoding_wansung + * ft_encoding_johab + * ft_encoding_adobe_standard + * ft_encoding_adobe_expert + * ft_encoding_adobe_custom + * ft_encoding_apple_roman + * + * @param encoding the Freetype encoding symbol. See above. + * @return true if charmap was valid and set + * correctly. If the requested encoding is + * unavailable it will be set to ft_encoding_none. + */ + bool CharMap( FT_Encoding encoding); + + /** + * Get the FTGlyphContainer index of the input character. + * + * @param characterCode The character code of the requested glyph in + * the current encoding eg apple roman. + * @return The FTGlyphContainer index for the character or zero + * if it wasn't found + */ + unsigned int GlyphListIndex( const unsigned int characterCode); + + /** + * Get the font glyph index of the input character. + * + * @param characterCode The character code of the requested glyph in + * the current encoding eg apple roman. + * @return The glyph index for the character. + */ + unsigned int FontIndex( const unsigned int characterCode); + + /** + * Set the FTGlyphContainer index of the character code. + * + * @param characterCode The character code of the requested glyph in + * the current encoding eg apple roman. + * @param containerIndex The index into the FTGlyphContainer of the + * character code. + */ + void InsertIndex( const unsigned int characterCode, const unsigned int containerIndex); + + /** + * Queries for errors. + * + * @return The current error code. Zero means no error. + */ + FT_Error Error() const { return err;} + + private: + /** + * Current character map code. + */ + FT_Encoding ftEncoding; + + /** + * The current Freetype face. + */ + const FT_Face ftFace; + + /** + * A structure that maps glyph indices to character codes + * + * < character code, face glyph index> + */ + typedef FTCharToGlyphIndexMap CharacterMap; + CharacterMap charMap; + + /** + * Current error code. + */ + FT_Error err; + +}; + + +#endif // __FTCharmap__ diff --git a/extern/bFTGL/include/FTContour.h b/extern/bFTGL/include/FTContour.h new file mode 100644 index 00000000000..895d9edeff8 --- /dev/null +++ b/extern/bFTGL/include/FTContour.h @@ -0,0 +1,88 @@ +#ifndef __FTContour__ +#define __FTContour__ + +#include "FTPoint.h" +#include "FTVector.h" +#include "FTGL.h" + + +/** + * FTContour class is a container of points that describe a vector font + * outline. It is used as a container for the output of the bezier curve + * evaluator in FTVectoriser. + * + * @see FTOutlineGlyph + * @see FTPolyGlyph + * @see FTPoint + */ +class FTGL_EXPORT FTContour +{ + public: + /** + * Constructor + * + * @param contour + * @param pointTags + * @param numberOfPoints + */ + FTContour( FT_Vector* contour, char* pointTags, unsigned int numberOfPoints); + + /** + * Destructor + */ + ~FTContour() + { + pointList.clear(); + } + + /** + * Return a point at index. + * + * @param index of the point in the curve. + * @return const point reference + */ + const FTPoint& Point( unsigned int index) const { return pointList[index];} + + /** + * How many points define this contour + * + * @return the number of points in this contour + */ + size_t PointCount() const { return pointList.size();} + + private: + /** + * Add a point to this contour. This function tests for duplicate + * points. + * + * @param point The point to be added to the contour. + */ + inline void AddPoint( FTPoint point); + + inline void AddPoint( float x, float y); + + /** + * De Casteljau (bezier) algorithm contributed by Jed Soane + * Evaluates a quadratic or conic (second degree) curve + */ + inline void evaluateQuadraticCurve(); + + /** + * De Casteljau (bezier) algorithm contributed by Jed Soane + * Evaluates a cubic (third degree) curve + */ + inline void evaluateCubicCurve(); + + /** + * The list of points in this contour + */ + typedef FTVector PointVector; + PointVector pointList; + + /** + * 2D array storing values of de Casteljau algorithm. + */ + float controlPoints[4][2]; +}; + +#endif // __FTContour__ diff --git a/extern/bFTGL/include/FTExtrdGlyph.h b/extern/bFTGL/include/FTExtrdGlyph.h new file mode 100644 index 00000000000..01e7c9e1d76 --- /dev/null +++ b/extern/bFTGL/include/FTExtrdGlyph.h @@ -0,0 +1,71 @@ +#ifndef __FTExtrdGlyph__ +#define __FTExtrdGlyph__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTGlyph.h" + +class FTVectoriser; + +/** + * FTExtrdGlyph is a specialisation of FTGlyph for creating tessellated + * extruded polygon glyphs. + * + * @see FTGlyphContainer + * @see FTVectoriser + * + */ +class FTGL_EXPORT FTExtrdGlyph : public FTGlyph +{ + public: + /** + * Constructor. Sets the Error to Invalid_Outline if the glyphs isn't an outline. + * + * @param glyph The Freetype glyph to be processed + * @param depth The distance along the z axis to extrude the glyph + */ + FTExtrdGlyph( FT_GlyphSlot glyph, float depth); + + /** + * Destructor + */ + virtual ~FTExtrdGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FTPoint& pen); + + private: + /** + * Calculate the normal vector to 2 points. This is 2D and ignores + * the z component. The normal will be normalised + * + * @param a + * @param b + * @return + */ + FTPoint GetNormal( const FTPoint &a, const FTPoint &b); + + + /** + * OpenGL display list + */ + GLuint glList; + + /** + * Distance to extrude the glyph + */ + float depth; + +}; + + +#endif // __FTExtrdGlyph__ + diff --git a/extern/bFTGL/include/FTFace.h b/extern/bFTGL/include/FTFace.h new file mode 100644 index 00000000000..26bb3966462 --- /dev/null +++ b/extern/bFTGL/include/FTFace.h @@ -0,0 +1,149 @@ +#ifndef __FTFace__ +#define __FTFace__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTPoint.h" +#include "FTSize.h" + +/** + * FTFace class provides an abstraction layer for the Freetype Face. + * + * @see "Freetype 2 Documentation" + * + */ +class FTGL_EXPORT FTFace +{ + public: + /** + * Opens and reads a face file. Error is set. + * + * @param filename font file name. + */ + FTFace( const char* filename); + + /** + * Read face data from an in-memory buffer. Error is set. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTFace( const unsigned char *pBufferBytes, size_t bufferSizeInBytes ); + + /** + * Destructor + * + * Disposes of the current Freetype Face. + */ + virtual ~FTFace(); + + /** + * Attach auxilliary file to font (e.g., font metrics). + * + * @param filename auxilliary font file name. + * @return true if file has opened + * successfully. + */ + bool Attach( const char* filename); + + /** + * Attach auxilliary data to font (e.g., font metrics) from memory + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + * @return true if file has opened + * successfully. + */ + bool Attach( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Disposes of the face + */ + void Close(); + + /** + * Get the freetype face object.. + * + * @return pointer to an FT_Face. + */ + FT_Face* Face() const { return ftFace;} + + /** + * Sets the char size for the current face. + * + * This doesn't guarantee that the size was set correctly. Clients + * should check errors. + * + * @param size the face size in points (1/72 inch) + * @param res the resolution of the target device. + * @return FTSize object + */ + const FTSize& Size( const unsigned int size, const unsigned int res); + + unsigned int UnitsPerEM() const; + + /** + * Get the number of character maps in this face. + * + * @return character map count. + */ + unsigned int CharMapCount(); + + /** + * Get a list of character maps in this face. + * + * @return pointer to the first encoding. + */ + FT_Encoding* CharMapList(); + + /** + * Gets the kerning vector between two glyphs + */ + FTPoint KernAdvance( unsigned int index1, unsigned int index2); + + /** + * Loads and creates a Freetype glyph. + */ + FT_GlyphSlot Glyph( unsigned int index, FT_Int load_flags); + + /** + * Gets the number of glyphs in the current face. + */ + unsigned int GlyphCount() const { return numGlyphs;} + + /** + * Queries for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err; } + + private: + /** + * The Freetype face + */ + FT_Face* ftFace; + + /** + * The size object associated with this face + */ + FTSize charSize; + + /** + * The number of glyphs in this face + */ + int numGlyphs; + + FT_Encoding* fontEncodingList; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; +}; + + +#endif // __FTFace__ diff --git a/extern/bFTGL/include/FTFont.h b/extern/bFTGL/include/FTFont.h new file mode 100644 index 00000000000..5b3d9e46f68 --- /dev/null +++ b/extern/bFTGL/include/FTFont.h @@ -0,0 +1,260 @@ +#ifndef __FTFont__ +#define __FTFont__ + +#include +#include FT_FREETYPE_H + +#include "FTFace.h" +#include "FTGL.h" + +class FTGlyphContainer; +class FTGlyph; + + +/** + * FTFont is the public interface for the FTGL library. + * + * Specific font classes are derived from this class. It uses the helper + * classes FTFace and FTSize to access the Freetype library. This class + * is abstract and deriving classes must implement the protected + * MakeGlyph function to create glyphs of the + * appropriate type. + * + * It is good practice after using these functions to test the error + * code returned. FT_Error Error() + * + * @see FTFace + * @see FTSize + * @see FTGlyphContainer + * @see FTGlyph + */ +class FTGL_EXPORT FTFont +{ + public: + /** + * Open and read a font file. Sets Error flag. + * + * @param fontname font file name. + */ + FTFont( const char* fontname); + + /** + * Open and read a font from a buffer in memory. Sets Error flag. + * The buffer is owned by the client and is NOT copied by FTGL. The + * pointer must be valid while using FTGL. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Destructor + */ + virtual ~FTFont(); + + /** + * Attach auxilliary file to font e.g font metrics. + * + * Note: not all font formats implement this function. + * + * @param filename auxilliary font file name. + * @return true if file has been attached + * successfully. + */ + bool Attach( const char* filename); + + /** + * Attach auxilliary data to font e.g font metrics, from memory + * + * Note: not all font formats implement this function. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + * @return true if file has been attached + * successfully. + */ + bool Attach( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Set the character map for the face. + * + * @param encoding Freetype enumerate for char map code. + * @return true if charmap was valid and + * set correctly + */ + bool CharMap( FT_Encoding encoding ); + + /** + * Get the number of character maps in this face. + * + * @return character map count. + */ + unsigned int CharMapCount(); + + /** + * Get a list of character maps in this face. + * + * @return pointer to the first encoding. + */ + FT_Encoding* CharMapList(); + + /** + * Set the char size for the current face. + * + * @param size the face size in points (1/72 inch) + * @param res the resolution of the target device. + * @return true if size was set correctly + */ + virtual bool FaceSize( const unsigned int size, const unsigned int res = 72); + + /** + * Get the current face size in points. + * + * @return face size + */ + unsigned int FaceSize() const; + + /** + * Set the extrusion distance for the font. Only implemented by + * FTGLExtrdFont + * + * @param d The extrusion distance. + */ + virtual void Depth( float d){} + + /** + * Get the global ascender height for the face. + * + * @return Ascender height + */ + float Ascender() const; + + /** + * Gets the global descender height for the face. + * + * @return Descender height + */ + float Descender() const; + + /** + * Get the bounding box for a string. + * + * @param string a char string + * @param llx lower left near x coord + * @param lly lower left near y coord + * @param llz lower left near z coord + * @param urx upper right far x coord + * @param ury upper right far y coord + * @param urz upper right far z coord + */ + void BBox( const char* string, float& llx, float& lly, float& llz, float& urx, float& ury, float& urz); + + /** + * Get the bounding box for a string. + * + * @param string a wchar_t string + * @param llx lower left near x coord + * @param lly lower left near y coord + * @param llz lower left near z coord + * @param urx upper right far x coord + * @param ury upper right far y coord + * @param urz upper right far z coord + */ + void BBox( const wchar_t* string, float& llx, float& lly, float& llz, float& urx, float& ury, float& urz); + + /** + * Get the advance width for a string. + * + * @param string a wchar_t string + * @return advance width + */ + float Advance( const wchar_t* string); + + /** + * Get the advance width for a string. + * + * @param string a char string + * @return advance width + */ + float Advance( const char* string); + + /** + * Render a string of characters + * + * @param string 'C' style string to be output. + */ + virtual void Render( const char* string ); + + /** + * Render a string of characters + * + * @param string wchar_t string to be output. + */ + virtual void Render( const wchar_t* string ); + + /** + * Queries the Font for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err;} + + protected: + /** + * Construct a glyph of the correct type. + * + * Clients must overide the function and return their specialised + * FTGlyph. + * + * @param g The glyph index NOT the char code. + * @return An FT****Glyph or null on failure. + */ + virtual FTGlyph* MakeGlyph( unsigned int g) = 0; + + /** + * Current face object + */ + FTFace face; + + /** + * Current size object + */ + FTSize charSize; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + + private: + /** + * Render a character + * This function does an implicit conversion on it's arguments. + * + * @param chr current character + * @param nextChr next character + */ + inline void DoRender( const unsigned int chr, const unsigned int nextChr); + + /** + * Check that the glyph at chr exist. If not load it. + * + * @param chr character index + */ + inline void CheckGlyph( const unsigned int chr); + + /** + * An object that holds a list of glyphs + */ + FTGlyphContainer* glyphList; + + /** + * Current pen or cursor position; + */ + FTPoint pen; +}; + + +#endif // __FTFont__ + diff --git a/extern/bFTGL/include/FTGL.h b/extern/bFTGL/include/FTGL.h new file mode 100644 index 00000000000..e92bd526012 --- /dev/null +++ b/extern/bFTGL/include/FTGL.h @@ -0,0 +1,96 @@ +#ifndef __FTGL__ +#define __FTGL__ + + +typedef double FTGL_DOUBLE; +typedef float FTGL_FLOAT; + +// Fixes for deprecated identifiers in 2.1.5 +#ifndef FT_OPEN_MEMORY + #define FT_OPEN_MEMORY (FT_Open_Flags)1 +#endif + +#ifndef FT_RENDER_MODE_MONO + #define FT_RENDER_MODE_MONO ft_render_mode_mono +#endif + +#ifndef FT_RENDER_MODE_NORMAL + #define FT_RENDER_MODE_NORMAL ft_render_mode_normal +#endif + + +#ifdef WIN32 + + // Under windows avoid including is overrated. + // Sure, it can be avoided and "name space pollution" can be + // avoided, but why? It really doesn't make that much difference + // these days. + #define WIN32_LEAN_AND_MEAN + #include + + #ifndef __gl_h_ + #include + #include + #endif + +#else + + // Non windows platforms - don't require nonsense as seen above :-) + #ifndef __gl_h_ + #ifdef __APPLE_CC__ + #include + #include + #else + #include + #include + #endif + + #endif + + // Required for compatibility with glext.h style function definitions of + // OpenGL extensions, such as in src/osg/Point.cpp. + #ifndef APIENTRY + #define APIENTRY + #endif +#endif + +// Compiler-specific conditional compilation +#ifdef _MSC_VER // MS Visual C++ + + // Disable various warning. + // 4786: template name too long + #pragma warning( disable : 4251 ) + #pragma warning( disable : 4275 ) + #pragma warning( disable : 4786 ) + + // The following definitions control how symbols are exported. + // If the target is a static library ensure that FTGL_LIBRARY_STATIC + // is defined. If building a dynamic library (ie DLL) ensure the + // FTGL_LIBRARY macro is defined, as it will mark symbols for + // export. If compiling a project to _use_ the _dynamic_ library + // version of the library, no definition is required. + #ifdef FTGL_LIBRARY_STATIC // static lib - no special export required + # define FTGL_EXPORT + #elif FTGL_LIBRARY // dynamic lib - must export/import symbols appropriately. + # define FTGL_EXPORT __declspec(dllexport) + #else + # define FTGL_EXPORT __declspec(dllimport) + #endif + +#else + // Compiler that is not MS Visual C++. + // Ensure that the export symbol is defined (and blank) + #define FTGL_EXPORT +#endif + + +// lifted from glext.h, to remove dependancy on glext.h +#ifndef GL_EXT_texture_object + #define GL_TEXTURE_PRIORITY_EXT 0x8066 + #define GL_TEXTURE_RESIDENT_EXT 0x8067 + #define GL_TEXTURE_1D_BINDING_EXT 0x8068 + #define GL_TEXTURE_2D_BINDING_EXT 0x8069 + #define GL_TEXTURE_3D_BINDING_EXT 0x806A +#endif + +#endif // __FTGL__ diff --git a/extern/bFTGL/include/FTGLBitmapFont.h b/extern/bFTGL/include/FTGLBitmapFont.h new file mode 100644 index 00000000000..12feae00cb6 --- /dev/null +++ b/extern/bFTGL/include/FTGLBitmapFont.h @@ -0,0 +1,65 @@ +#ifndef __FTGLBitmapFont__ +#define __FTGLBitmapFont__ + +#include "FTFont.h" +#include "FTGL.h" + + +class FTGlyph; + +/** + * FTGLBitmapFont is a specialisation of the FTFont class for handling + * Bitmap fonts + * + * @see FTFont + */ +class FTGL_EXPORT FTGLBitmapFont : public FTFont +{ + public: + /** + * Open and read a font file. Sets Error flag. + * + * @param fontname font file name. + */ + FTGLBitmapFont( const char* fontname); + + /** + * Open and read a font from a buffer in memory. Sets Error flag. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTGLBitmapFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Destructor + */ + ~FTGLBitmapFont(); + + /** + * Renders a string of characters + * + * @param string 'C' style string to be output. + */ + void Render( const char* string); + + /** + * Renders a string of characters + * + * @param string 'C' style wide string to be output. + */ + void Render( const wchar_t* string); + + // attributes + + private: + /** + * Construct a FTBitmapGlyph. + * + * @param g The glyph index NOT the char code. + * @return An FTBitmapGlyph or null on failure. + */ + inline virtual FTGlyph* MakeGlyph( unsigned int g); + +}; +#endif // __FTGLBitmapFont__ diff --git a/extern/bFTGL/include/FTGLBufferFont.h b/extern/bFTGL/include/FTGLBufferFont.h new file mode 100644 index 00000000000..2f74b5cdef9 --- /dev/null +++ b/extern/bFTGL/include/FTGLBufferFont.h @@ -0,0 +1,76 @@ +#ifndef __FTGLBufferFont__ +#define __FTGLBufferFont__ + + +#include "FTFont.h" +#include "FTGL.h" + + +class FTGlyph; + + +/** + * FTGLBufferFont is a specialisation of the FTFont class for handling + * Pixmap (Grey Scale) fonts + * + * @see FTFont + */ +class FTGL_EXPORT FTGLBufferFont : public FTFont +{ + public: + /** + * Open and read a font file. Sets Error flag. + * + * @param fontname font file name. + */ + FTGLBufferFont( const char* fontname); + + /** + * Open and read a font from a buffer in memory. Sets Error flag. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTGLBufferFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + + void SetClientBuffer( unsigned char* b) + { + buffer = b; + } + + + /** + * Destructor + */ + ~FTGLBufferFont(); + + /** + * Renders a string of characters + * + * @param string 'C' style string to be output. + */ + void Render( const char* string); + + /** + * Renders a string of characters + * + * @param string wchar_t string to be output. + */ + void Render( const wchar_t* string); + + private: + /** + * Construct a FTBufferGlyph. + * + * @param g The glyph index NOT the char code. + * @return An FTBufferGlyph or null on failure. + */ + inline virtual FTGlyph* MakeGlyph( unsigned int g); + + unsigned char* buffer; +}; + + +#endif // __FTGLBufferFont__ + diff --git a/extern/bFTGL/include/FTGLExtrdFont.h b/extern/bFTGL/include/FTGLExtrdFont.h new file mode 100644 index 00000000000..dc784bbb5b0 --- /dev/null +++ b/extern/bFTGL/include/FTGLExtrdFont.h @@ -0,0 +1,55 @@ +#ifndef __FTGLExtrdFont__ +#define __FTGLExtrdFont__ + +#include "FTFont.h" +#include "FTGL.h" + +class FTGlyph; + +/** + * FTGLExtrdFont is a specialisation of the FTFont class for handling + * extruded Polygon fonts + * + * @see FTFont + * @see FTGLPolygonFont + */ +class FTGL_EXPORT FTGLExtrdFont : public FTFont +{ + public: + /** + * Open and read a font file. Sets Error flag. + * + * @param fontname font file name. + */ + FTGLExtrdFont( const char* fontname); + + /** + * Open and read a font from a buffer in memory. Sets Error flag. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTGLExtrdFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Destructor + */ + ~FTGLExtrdFont(); + + void Depth( float d) { depth = d;} + + private: + /** + * Construct a FTPolyGlyph. + * + * @param glyphIndex The glyph index NOT the char code. + * @return An FTExtrdGlyph or null on failure. + */ + inline virtual FTGlyph* MakeGlyph( unsigned int glyphIndex); + + float depth; +}; + + +#endif // __FTGLExtrdFont__ + diff --git a/extern/bFTGL/include/FTGLOutlineFont.h b/extern/bFTGL/include/FTGLOutlineFont.h new file mode 100644 index 00000000000..a7f4b23092d --- /dev/null +++ b/extern/bFTGL/include/FTGLOutlineFont.h @@ -0,0 +1,64 @@ +#ifndef __FTGLOutlineFont__ +#define __FTGLOutlineFont__ + + +#include "FTFont.h" +#include "FTGL.h" + +class FTGlyph; + + +/** + * FTGLOutlineFont is a specialisation of the FTFont class for handling + * Vector Outline fonts + * + * @see FTFont + */ +class FTGL_EXPORT FTGLOutlineFont : public FTFont +{ + public: + /** + * Open and read a font file. Sets Error flag. + * + * @param fontname font file name. + */ + FTGLOutlineFont( const char* fontname); + + /** + * Open and read a font from a buffer in memory. Sets Error flag. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTGLOutlineFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Destructor + */ + ~FTGLOutlineFont(); + + /** + * Renders a string of characters + * + * @param string 'C' style string to be output. + */ + void Render( const char* string); + + /** + * Renders a string of characters + * + * @param string wchar_t string to be output. + */ + void Render( const wchar_t* string); + + private: + /** + * Construct a FTOutlineGlyph. + * + * @param g The glyph index NOT the char code. + * @return An FTOutlineGlyph or null on failure. + */ + inline virtual FTGlyph* MakeGlyph( unsigned int g); + +}; +#endif // __FTGLOutlineFont__ diff --git a/extern/bFTGL/include/FTGLPixmapFont.h b/extern/bFTGL/include/FTGLPixmapFont.h new file mode 100644 index 00000000000..f781ddf68dd --- /dev/null +++ b/extern/bFTGL/include/FTGLPixmapFont.h @@ -0,0 +1,68 @@ +#ifndef __FTGLPixmapFont__ +#define __FTGLPixmapFont__ + + +#include "FTFont.h" +#include "FTGL.h" + + +class FTGlyph; + + +/** + * FTGLPixmapFont is a specialisation of the FTFont class for handling + * Pixmap (Grey Scale) fonts + * + * @see FTFont + */ +class FTGL_EXPORT FTGLPixmapFont : public FTFont +{ + public: + /** + * Open and read a font file. Sets Error flag. + * + * @param fontname font file name. + */ + FTGLPixmapFont( const char* fontname); + + /** + * Open and read a font from a buffer in memory. Sets Error flag. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTGLPixmapFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Destructor + */ + ~FTGLPixmapFont(); + + /** + * Renders a string of characters + * + * @param string 'C' style string to be output. + */ + void Render( const char* string); + + /** + * Renders a string of characters + * + * @param string wchar_t string to be output. + */ + void Render( const wchar_t* string); + + private: + /** + * Construct a FTPixmapGlyph. + * + * @param g The glyph index NOT the char code. + * @return An FTPixmapGlyph or null on failure. + */ + inline virtual FTGlyph* MakeGlyph( unsigned int g); + +}; + + +#endif // __FTGLPixmapFont__ + diff --git a/extern/bFTGL/include/FTGLPolygonFont.h b/extern/bFTGL/include/FTGLPolygonFont.h new file mode 100644 index 00000000000..54e624a1893 --- /dev/null +++ b/extern/bFTGL/include/FTGLPolygonFont.h @@ -0,0 +1,53 @@ +#ifndef __FTGLPolygonFont__ +#define __FTGLPolygonFont__ + + +#include "FTFont.h" +#include "FTGL.h" + +class FTGlyph; + + +/** + * FTGLPolygonFont is a specialisation of the FTFont class for handling + * tesselated Polygon Mesh fonts + * + * @see FTFont + */ +class FTGL_EXPORT FTGLPolygonFont : public FTFont +{ + public: + /** + * Open and read a font file. Sets Error flag. + * + * @param fontname font file name. + */ + FTGLPolygonFont( const char* fontname); + + /** + * Open and read a font from a buffer in memory. Sets Error flag. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTGLPolygonFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Destructor + */ + ~FTGLPolygonFont(); + + private: + /** + * Construct a FTPolyGlyph. + * + * @param g The glyph index NOT the char code. + * @return An FTPolyGlyph or null on failure. + */ + inline virtual FTGlyph* MakeGlyph( unsigned int g); + +}; + + +#endif // __FTGLPolygonFont__ + diff --git a/extern/bFTGL/include/FTGLTextureFont.h b/extern/bFTGL/include/FTGLTextureFont.h new file mode 100644 index 00000000000..f0575143f4b --- /dev/null +++ b/extern/bFTGL/include/FTGLTextureFont.h @@ -0,0 +1,151 @@ +#ifndef __FTGLTextureFont__ +#define __FTGLTextureFont__ + +#include "FTFont.h" +#include "FTVector.h" +#include "FTGL.h" + +class FTTextureGlyph; + + +/** + * FTGLTextureFont is a specialisation of the FTFont class for handling + * Texture mapped fonts + * + * @see FTFont + */ +class FTGL_EXPORT FTGLTextureFont : public FTFont +{ + public: + /** + * Open and read a font file. Sets Error flag. + * + * @param fontname font file name. + */ + FTGLTextureFont( const char* fontname); + + /** + * Open and read a font from a buffer in memory. Sets Error flag. + * + * @param pBufferBytes the in-memory buffer + * @param bufferSizeInBytes the length of the buffer in bytes + */ + FTGLTextureFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes); + + /** + * Destructor + */ + virtual ~FTGLTextureFont(); + + /** + * Set the char size for the current face. + * + * @param size the face size in points (1/72 inch) + * @param res the resolution of the target device. + * @return true if size was set correctly + */ + virtual bool FaceSize( const unsigned int size, const unsigned int res = 72); + + /** + * Renders a string of characters + * + * @param string 'C' style string to be output. + */ + virtual void Render( const char* string); + + /** + * Renders a string of characters + * + * @param string wchar_t string to be output. + */ + virtual void Render( const wchar_t* string); + + + private: + /** + * Construct a FTTextureGlyph. + * + * @param glyphIndex The glyph index NOT the char code. + * @return An FTTextureGlyph or null on failure. + */ + inline virtual FTGlyph* MakeGlyph( unsigned int glyphIndex); + + /** + * Get the size of a block of memory required to layout the glyphs + * + * Calculates a width and height based on the glyph sizes and the + * number of glyphs. It over estimates. + */ + inline void CalculateTextureSize(); + + /** + * Creates a 'blank' OpenGL texture object. + * + * The format is GL_ALPHA and the params are + * GL_TEXTURE_WRAP_S = GL_CLAMP + * GL_TEXTURE_WRAP_T = GL_CLAMP + * GL_TEXTURE_MAG_FILTER = GL_LINEAR + * GL_TEXTURE_MIN_FILTER = GL_LINEAR + * Note that mipmapping is NOT used + */ + inline GLuint CreateTexture(); + + /** + * The maximum texture dimension on this OpenGL implemetation + */ + GLsizei maxTextSize; + + /** + * The minimum texture width required to hold the glyphs + */ + GLsizei textureWidth; + + /** + * The minimum texture height required to hold the glyphs + */ + GLsizei textureHeight; + + /** + *An array of texture ids + */ + FTVector textureIDList; + + /** + * The max height for glyphs in the current font + */ + int glyphHeight; + + /** + * The max width for glyphs in the current font + */ + int glyphWidth; + + /** + * A value to be added to the height and width to ensure that + * glyphs don't overlap in the texture + */ + unsigned int padding; + + /** + * + */ + unsigned int numGlyphs; + + /** + */ + unsigned int remGlyphs; + + /** + */ + int xOffset; + + /** + */ + int yOffset; + +}; + + +#endif // __FTGLTextureFont__ + + diff --git a/extern/bFTGL/include/FTGlyph.h b/extern/bFTGL/include/FTGlyph.h new file mode 100644 index 00000000000..c38d51e728e --- /dev/null +++ b/extern/bFTGL/include/FTGlyph.h @@ -0,0 +1,89 @@ +#ifndef __FTGlyph__ +#define __FTGlyph__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTBBox.h" +#include "FTPoint.h" +#include "FTGL.h" + + +/** + * FTGlyph is the base class for FTGL glyphs. + * + * It provides the interface between Freetype glyphs and their openGL + * renderable counterparts. This is an abstract class and derived classes + * must implement the render function. + * + * @see FTGlyphContainer + * @see FTBBox + * @see FTPoint + * + */ +class FTGL_EXPORT FTGlyph +{ + public: + /** + * Constructor + */ + FTGlyph( FT_GlyphSlot glyph); + + /** + * Destructor + */ + virtual ~FTGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FTPoint& pen) = 0; + + /** + * Return the advance width for this glyph. + * + * @return advance width. + */ + float Advance() const { return advance;} + + /** + * Return the bounding box for this glyph. + * + * @return bounding box. + */ + const FTBBox& BBox() const { return bBox;} + + /** + * Queries for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err;} + + protected: + /** + * The advance distance for this glyph + */ + float advance; + + /** + * The bounding box of this glyph. + */ + FTBBox bBox; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + + private: + +}; + + +#endif // __FTGlyph__ + diff --git a/extern/bFTGL/include/FTGlyphContainer.h b/extern/bFTGL/include/FTGlyphContainer.h new file mode 100644 index 00000000000..de668b61dbd --- /dev/null +++ b/extern/bFTGL/include/FTGlyphContainer.h @@ -0,0 +1,127 @@ +#ifndef __FTGlyphContainer__ +#define __FTGlyphContainer__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTBBox.h" +#include "FTPoint.h" +#include "FTVector.h" + +class FTFace; +class FTGlyph; +class FTCharmap; + +/** + * FTGlyphContainer holds the post processed FTGlyph objects. + * + * @see FTGlyph + */ +class FTGL_EXPORT FTGlyphContainer +{ + typedef FTVector GlyphVector; + public: + /** + * Constructor + * + * @param face The Freetype face + */ + FTGlyphContainer( FTFace* face); + + /** + * Destructor + */ + ~FTGlyphContainer(); + + /** + * Sets the character map for the face. + * + * @param encoding the Freetype encoding symbol. See above. + * @return true if charmap was valid + * and set correctly + */ + bool CharMap( FT_Encoding encoding); + + /** + * Get the font index of the input character. + * + * @param characterCode The character code of the requested glyph in the + * current encoding eg apple roman. + * @return The font index for the character. + */ + unsigned int FontIndex( const unsigned int characterCode ) const; + + /** + * Adds a glyph to this glyph list. + * + * @param glyph The FTGlyph to be inserted into the container + * @param characterCode The char code of the glyph NOT the glyph index. + */ + void Add( FTGlyph* glyph, const unsigned int characterCode); + + /** + * Get a glyph from the glyph list + * + * @param characterCode The char code of the glyph NOT the glyph index + * @return An FTGlyph or null is it hasn't been + * loaded. + */ + const FTGlyph* const Glyph( const unsigned int characterCode) const; + + /** + * Get the bounding box for a character. + * @param characterCode The char code of the glyph NOT the glyph index + */ + FTBBox BBox( const unsigned int characterCode) const; + + /** + * Returns the kerned advance width for a glyph. + * + * @param characterCode glyph index of the character + * @param nextCharacterCode the next glyph in a string + * @return advance width + */ + float Advance( const unsigned int characterCode, const unsigned int nextCharacterCode); + + /** + * Renders a character + * @param characterCode the glyph to be Rendered + * @param nextCharacterCode the next glyph in the string. Used for kerning. + * @param penPosition the position to Render the glyph + * @return The distance to advance the pen position after Rendering + */ + FTPoint Render( const unsigned int characterCode, const unsigned int nextCharacterCode, FTPoint penPosition); + + /** + * Queries the Font for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err;} + + private: + /** + * The FTGL face + */ + FTFace* face; + + /** + * The Character Map object associated with the current face + */ + FTCharmap* charMap; + + /** + * A structure to hold the glyphs + */ + GlyphVector glyphs; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; +}; + + +#endif // __FTGlyphContainer__ diff --git a/extern/bFTGL/include/FTLibrary.h b/extern/bFTGL/include/FTLibrary.h new file mode 100644 index 00000000000..1e5ed6b1a08 --- /dev/null +++ b/extern/bFTGL/include/FTLibrary.h @@ -0,0 +1,97 @@ +#ifndef __FTLibrary__ +#define __FTLibrary__ + +#include +#include FT_FREETYPE_H +//#include FT_CACHE_H + +#include "FTGL.h" + + +/** + * FTLibrary class is the global accessor for the Freetype library. + * + * This class encapsulates the Freetype Library. This is a singleton class + * and ensures that only one FT_Library is in existence at any one time. + * All constructors are private therefore clients cannot create or + * instantiate this class themselves and must access it's methods via the + * static FTLibrary::Instance() function. + * + * Just because this class returns a valid FTLibrary object + * doesn't mean that the Freetype Library has been successfully initialised. + * Clients should check for errors. You can initialse the library AND check + * for errors using the following code... + * err = FTLibrary::Instance().Error(); + * + * @see "Freetype 2 Documentation" + * + */ +class FTGL_EXPORT FTLibrary +{ + public: + /** + * Global acces point to the single FTLibrary object. + * + * @return The global FTLibrary object. + */ + static FTLibrary& Instance(); + + /** + * Gets a pointer to the native Freetype library. + * + * @return A handle to a FreeType library instance. + */ + const FT_Library* const GetLibrary() const { return library;} + + /** + * Queries the library for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err;} + + /** + * Destructor + * + * Disposes of the Freetype library + */ + ~FTLibrary(); + + private: + /** + * Default constructors. + * + * Made private to stop clients creating there own FTLibrary + * objects. + */ + FTLibrary(); + FTLibrary( const FT_Library&){} + FTLibrary& operator=( const FT_Library&) { return *this; } + + /** + * Initialises the Freetype library + * + * Even though this function indicates success via the return value, + * clients can't see this so must check the error codes. This function + * is only ever called by the default c_stor + * + * @return true if the Freetype library was + * successfully initialised, false + * otherwise. + */ + bool Initialise(); + + /** + * Freetype library handle. + */ + FT_Library* library; +// FTC_Manager* manager; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + +}; + +#endif // __FTLibrary__ diff --git a/extern/bFTGL/include/FTList.h b/extern/bFTGL/include/FTList.h new file mode 100644 index 00000000000..34992168103 --- /dev/null +++ b/extern/bFTGL/include/FTList.h @@ -0,0 +1,112 @@ +#ifndef __FTList__ +#define __FTList__ + +#include "FTGL.h" + +/** +* Provides a non-STL alternative to the STL list + */ +template +class FTGL_EXPORT FTList +{ + public: + typedef FT_LIST_ITEM_TYPE value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + /** + * Constructor + */ + FTList() + : listSize(0), + tail(0) + { + tail = NULL; + head = new Node; + } + + /** + * Destructor + */ + ~FTList() + { + Node* next; + + for( Node *walk = head; walk; walk = next) + { + next = walk->next; + delete walk; + } + } + + /** + * Get the number of items in the list + */ + size_type size() const + { + return listSize; + } + + /** + * Add an item to the end of the list + */ + void push_back( const value_type& item) + { + Node* node = new Node( item); + + if( head->next == NULL) + { + head->next = node; + } + + if( tail) + { + tail->next = node; + } + tail = node; + ++listSize; + } + + /** + * Get the item at the front of the list + */ + reference front() const + { + return head->next->payload; + } + + /** + * Get the item at the end of the list + */ + reference back() const + { + return tail->payload; + } + + private: + struct Node + { + Node() + : next(NULL) + {} + + Node( const value_type& item) + : next(NULL) + { + payload = item; + } + + Node* next; + + value_type payload; + }; + + size_type listSize; + + Node* head; + Node* tail; +}; + +#endif // __FTList__ + diff --git a/extern/bFTGL/include/FTOutlineGlyph.h b/extern/bFTGL/include/FTOutlineGlyph.h new file mode 100644 index 00000000000..7dd0ba042b9 --- /dev/null +++ b/extern/bFTGL/include/FTOutlineGlyph.h @@ -0,0 +1,54 @@ +#ifndef __FTOutlineGlyph__ +#define __FTOutlineGlyph__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTGlyph.h" + +class FTVectoriser; + + +/** + * FTOutlineGlyph is a specialisation of FTGlyph for creating outlines. + * + * @see FTGlyphContainer + * @see FTVectoriser + * + */ +class FTGL_EXPORT FTOutlineGlyph : public FTGlyph +{ + public: + /** + * Constructor. Sets the Error to Invalid_Outline if the glyphs isn't an outline. + * + * @param glyph The Freetype glyph to be processed + */ + FTOutlineGlyph( FT_GlyphSlot glyph); + + /** + * Destructor + */ + virtual ~FTOutlineGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FTPoint& pen); + + private: + /** + * OpenGL display list + */ + GLuint glList; + +}; + + +#endif // __FTOutlineGlyph__ + diff --git a/extern/bFTGL/include/FTPixmapGlyph.h b/extern/bFTGL/include/FTPixmapGlyph.h new file mode 100644 index 00000000000..9d43d6c58b3 --- /dev/null +++ b/extern/bFTGL/include/FTPixmapGlyph.h @@ -0,0 +1,68 @@ +#ifndef __FTPixmapGlyph__ +#define __FTPixmapGlyph__ + + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTGlyph.h" + + +/** + * FTPixmapGlyph is a specialisation of FTGlyph for creating pixmaps. + * + * @see FTGlyphContainer + * + */ +class FTGL_EXPORT FTPixmapGlyph : public FTGlyph +{ + public: + /** + * Constructor + * + * @param glyph The Freetype glyph to be processed + */ + FTPixmapGlyph( FT_GlyphSlot glyph); + + /** + * Destructor + */ + virtual ~FTPixmapGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FTPoint& pen); + + // attributes + + private: + /** + * The width of the glyph 'image' + */ + int destWidth; + + /** + * The height of the glyph 'image' + */ + int destHeight; + + /** + * Vector from the pen position to the topleft corner of the pixmap + */ + FTPoint pos; + + /** + * Pointer to the 'image' data + */ + unsigned char* data; + +}; + + +#endif // __FTPixmapGlyph__ diff --git a/extern/bFTGL/include/FTPoint.h b/extern/bFTGL/include/FTPoint.h new file mode 100644 index 00000000000..bb1772c4c18 --- /dev/null +++ b/extern/bFTGL/include/FTPoint.h @@ -0,0 +1,85 @@ +#ifndef __FTPoint__ +#define __FTPoint__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" + +/** + * FTPoint class is a basic 3 dimensional point or vector. + */ +class FTGL_EXPORT FTPoint +{ + public: + /** + * Default constructor. Point is set to zero. + */ + FTPoint() + : x(0), y(0), z(0) + {} + + /** + * Constructor. + * + * @param X + * @param Y + * @param Z + */ + FTPoint( const FTGL_DOUBLE X, const FTGL_DOUBLE Y, const FTGL_DOUBLE Z) + : x(X), y(Y), z(Z) + {} + + /** + * Constructor. This converts an FT_Vector to an FT_Point + * + * @param ft_vector A freetype vector + */ + FTPoint( const FT_Vector& ft_vector) + : x(ft_vector.x), y(ft_vector.y), z(0) + {} + + /** + * Operator += + * + * @param point + * @return this plus point. + */ + FTPoint& operator += ( const FTPoint& point) + { + x += point.x; + y += point.y; + z += point.z; + + return *this; + } + + /** + * Operator == Tests for eqaulity + * + * @param a + * @param b + * @return + */ + friend bool operator == ( const FTPoint &a, const FTPoint &b); + + /** + * Operator != Tests for non equality + * + * @param a + * @param b + * @return + */ + friend bool operator != ( const FTPoint &a, const FTPoint &b); + + /** + * The point data + */ + FTGL_DOUBLE x, y, z; // FIXME make private + + private: +}; + +#endif // __FTPoint__ + diff --git a/extern/bFTGL/include/FTPolyGlyph.h b/extern/bFTGL/include/FTPolyGlyph.h new file mode 100644 index 00000000000..c8faeffceb6 --- /dev/null +++ b/extern/bFTGL/include/FTPolyGlyph.h @@ -0,0 +1,55 @@ +#ifndef __FTPolyGlyph__ +#define __FTPolyGlyph__ + + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTGlyph.h" + +class FTVectoriser; + +/** + * FTPolyGlyph is a specialisation of FTGlyph for creating tessellated + * polygon glyphs. + * + * @see FTGlyphContainer + * @see FTVectoriser + * + */ +class FTGL_EXPORT FTPolyGlyph : public FTGlyph +{ + public: + /** + * Constructor. Sets the Error to Invalid_Outline if the glyphs isn't an outline. + * + * @param glyph The Freetype glyph to be processed + */ + FTPolyGlyph( FT_GlyphSlot glyph); + + /** + * Destructor + */ + virtual ~FTPolyGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FTPoint& pen); + + private: + /** + * OpenGL display list + */ + GLuint glList; + +}; + + +#endif // __FTPolyGlyph__ + diff --git a/extern/bFTGL/include/FTSize.h b/extern/bFTGL/include/FTSize.h new file mode 100644 index 00000000000..31f6bb66db1 --- /dev/null +++ b/extern/bFTGL/include/FTSize.h @@ -0,0 +1,132 @@ +#ifndef __FTSize__ +#define __FTSize__ + + +#include +#include FT_FREETYPE_H + +#include "FTGL.h" + + + +/** + * FTSize class provides an abstraction layer for the Freetype Size. + * + * @see "Freetype 2 Documentation" + * + */ +class FTGL_EXPORT FTSize +{ + public: + /** + * Default Constructor + */ + FTSize(); + + /** + * Destructor + */ + virtual ~FTSize(); + + /** + * Sets the char size for the current face. + * + * This doesn't guarantee that the size was set correctly. Clients + * should check errors. + * + * @param face Parent face for this size object + * @param point_size the face size in points (1/72 inch) + * @param x_resolution the horizontal resolution of the target device. + * @param y_resolution the vertical resolution of the target device. + * @return true if the size has been set. Clients should check Error() for more information if this function returns false() + */ + bool CharSize( FT_Face* face, unsigned int point_size, unsigned int x_resolution, unsigned int y_resolution); + + /** + * get the char size for the current face. + * + * @return The char size in points + */ + unsigned int CharSize() const; + + /** + * Gets the global ascender height for the face in pixels. + * + * @return Ascender height + */ + float Ascender() const; + + /** + * Gets the global descender height for the face in pixels. + * + * @return Ascender height + */ + float Descender() const; + + /** + * Gets the global face height for the face. + * + * If the face is scalable this returns the height of the global + * bounding box which ensures that any glyph will be less than or + * equal to this height. If the font isn't scalable there is no + * guarantee that glyphs will not be taller than this value. + * + * @return height in pixels. + */ + float Height() const; + + /** + * Gets the global face width for the face. + * + * If the face is scalable this returns the width of the global + * bounding box which ensures that any glyph will be less than or + * equal to this width. If the font isn't scalable this value is + * the max_advance for the face. + * + * @return width in pixels. + */ + float Width() const; + + /** + * Gets the underline position for the face. + * + * @return underline position in pixels + */ + float Underline() const; + + unsigned int XPixelsPerEm() const; + + unsigned int YPixelsPerEm() const; + + /** + * Queries for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err; } + + private: + /** + * The current Freetype face that this FTSize object relates to. + */ + FT_Face* ftFace; + + /** + * The Freetype size. + */ + FT_Size ftSize; + + /** + * The size in points. + */ + unsigned int size; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + +}; + +#endif // __FTSize__ + diff --git a/extern/bFTGL/include/FTTextureGlyph.h b/extern/bFTGL/include/FTTextureGlyph.h new file mode 100644 index 00000000000..389e6f778da --- /dev/null +++ b/extern/bFTGL/include/FTTextureGlyph.h @@ -0,0 +1,89 @@ +#ifndef __FTTextureGlyph__ +#define __FTTextureGlyph__ + + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGL.h" +#include "FTGlyph.h" + + +/** + * FTTextureGlyph is a specialisation of FTGlyph for creating texture + * glyphs. + * + * @see FTGlyphContainer + * + */ +class FTGL_EXPORT FTTextureGlyph : public FTGlyph +{ + public: + /** + * Constructor + * + * @param glyph The Freetype glyph to be processed + * @param id The id of the texture that this glyph will be + * drawn in + * @param xOffset The x offset into the parent texture to draw + * this glyph + * @param yOffset The y offset into the parent texture to draw + * this glyph + * @param width The width of the parent texture + * @param height The height (number of rows) of the parent texture + */ + FTTextureGlyph( FT_GlyphSlot glyph, int id, int xOffset, int yOffset, GLsizei width, GLsizei height); + + /** + * Destructor + */ + virtual ~FTTextureGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FTPoint& pen); + + private: + /** + * The width of the glyph 'image' + */ + int destWidth; + + /** + * The height of the glyph 'image' + */ + int destHeight; + + /** + * Vector from the pen position to the topleft corner of the pixmap + */ + FTPoint pos; + + /** + * The texture co-ords of this glyph within the texture. + */ + FTPoint uv[2]; + + /** + * The texture index that this glyph is contained in. + */ + int glTextureID; + + /** + * The texture index of the currently active texture + * + * We call glGetIntegerv( GL_TEXTURE_2D_BINDING, activeTextureID); + * to get the currently active texture to try to reduce the number + * of texture bind operations + */ + GLint activeTextureID; + +}; + + +#endif // __FTTextureGlyph__ diff --git a/extern/bFTGL/include/FTVector.h b/extern/bFTGL/include/FTVector.h new file mode 100644 index 00000000000..6147f522c08 --- /dev/null +++ b/extern/bFTGL/include/FTVector.h @@ -0,0 +1,190 @@ +#ifndef __FTVector__ +#define __FTVector__ + +#include "FTGL.h" + +/** + * Provides a non-STL alternative to the STL vector + */ +template +class FTGL_EXPORT FTVector +{ + public: + typedef FT_VECTOR_ITEM_TYPE value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef size_t size_type; + + FTVector() + { + Capacity = Size = 0; + Items = 0; + } + + + virtual ~FTVector() + { + clear(); + } + + FTVector& operator =(const FTVector& v) + { + reserve(v.capacity()); + + iterator ptr = begin(); + const_iterator vbegin = v.begin(); + const_iterator vend = v.end(); + + while( vbegin != vend) + { + *ptr++ = *vbegin++; + } + + Size = v.size(); + return *this; + } + + size_type size() const + { + return Size; + } + + size_type capacity() const + { + return Capacity; + } + + iterator begin() + { + return Items; + } + + const_iterator begin() const + { + return Items; + } + + iterator end() + { + return begin() + size(); + } + + const_iterator end() const + { + return begin() + size(); + } + + bool empty() const + { + return size() == 0; + } + + reference operator [](size_type pos) + { + return( *(begin() + pos)); + } + + const_reference operator []( size_type pos) const + { + return( *(begin() + pos)); + } + + void clear() + { + if( Capacity) + { + delete [] Items; + Capacity = Size = 0; + Items = 0; + } + } + + void reserve( size_type n) + { + if( capacity() < n) + { + expand(n); + } + } + + void push_back(const value_type& x) + { + if( size() == capacity()) + { + expand(); + } + + ( *this)[size()] = x; + ++Size; + } + + void resize(size_type n, value_type x) + { + if( n == size()) + { + return; + } + + reserve(n); + iterator begin, end; + + if( n >= Size) + { + begin = this->end(); + end = this->begin() + n; + } + else + { + begin = this->begin() + n; + end = this->end(); + } + + while( begin != end) + { + *begin++ = x; + } + + Size = n; + } + + + private: + void expand(size_type capacity_hint = 0) + { + size_type new_capacity =( capacity() == 0) ? 256 : capacity()* 2; + if( capacity_hint) + { + while( new_capacity < capacity_hint) + { + new_capacity *= 2; + } + } + + value_type *new_items = new value_type[new_capacity]; + + iterator begin = this->begin(); + iterator end = this->end(); + value_type *ptr = new_items; + + while( begin != end) + { + *ptr++ = *begin++; + } + + if( Capacity) + { + delete [] Items; + } + + Items = new_items; + Capacity = new_capacity; + } + + size_type Capacity; + size_type Size; + value_type* Items; +}; + +#endif // __FTVector__ diff --git a/extern/bFTGL/include/FTVectoriser.h b/extern/bFTGL/include/FTVectoriser.h new file mode 100644 index 00000000000..7150560ce07 --- /dev/null +++ b/extern/bFTGL/include/FTVectoriser.h @@ -0,0 +1,275 @@ +#ifndef __FTVectoriser__ +#define __FTVectoriser__ + + +#include "FTContour.h" +#include "FTList.h" +#include "FTPoint.h" +#include "FTVector.h" +#include "FTGL.h" + + +#ifndef CALLBACK +#define CALLBACK +#endif + + +/** + * FTTesselation captures points that are output by OpenGL's gluTesselator. + */ +class FTGL_EXPORT FTTesselation +{ + public: + /** + * Default constructor + */ + FTTesselation( GLenum m) + : meshType(m) + { + pointList.reserve( 128); + } + + /** + * Destructor + */ + ~FTTesselation() + { + pointList.clear(); + } + + /** + * Add a point to the mesh. + */ + void AddPoint( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) + { + pointList.push_back( FTPoint( x, y, z)); + } + + /** + * The number of points in this mesh + */ + size_t PointCount() const { return pointList.size();} + + /** + * + */ + const FTPoint& Point( unsigned int index) const { return pointList[index];} + + /** + * Return the OpenGL polygon type. + */ + GLenum PolygonType() const { return meshType;} + + private: + /** + * Points generated by gluTesselator. + */ + typedef FTVector PointVector; + PointVector pointList; + + /** + * OpenGL primitive type from gluTesselator. + */ + GLenum meshType; +}; + + +/** + * FTMesh is a container of FTTesselation's that make up a polygon glyph + */ +class FTGL_EXPORT FTMesh +{ + typedef FTVector TesselationVector; + typedef FTList PointList; + + public: + /** + * Default constructor + */ + FTMesh(); + + /** + * Destructor + */ + ~FTMesh(); + + /** + * + */ + void AddPoint( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z); + + /** + * + */ + FTGL_DOUBLE* Combine( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z); + + /** + * + */ + void Begin( GLenum meshType); + + /** + * + */ + void End(); + + /** + * + */ + void Error( GLenum e) { err = e;} + + /** + * + */ + unsigned int TesselationCount() const { return tesselationList.size();} + + /** + * + */ + const FTTesselation* const Tesselation( unsigned int index) const; + + /** + * + */ + const PointList& TempPointList() const { return tempPointList;} + + /** + * Get the GL ERROR returned by the glu tesselator + */ + GLenum Error() const { return err;} + + private: + /** + * The current sub mesh that we are constructing. + */ + FTTesselation* currentTesselation; + + /** + * Holds each sub mesh that comprises this glyph. + */ + TesselationVector tesselationList; + + /** + * Holds extra points created by gluTesselator. See ftglCombine. + */ + PointList tempPointList; + + /** + * GL ERROR returned by the glu tesselator + */ + GLenum err; + +}; + +const FTGL_DOUBLE FTGL_FRONT_FACING = 1.0; +const FTGL_DOUBLE FTGL_BACK_FACING = -1.0; + +/** + * FTVectoriser class is a helper class that converts font outlines into + * point data. + * + * @see FTExtrdGlyph + * @see FTOutlineGlyph + * @see FTPolyGlyph + * @see FTContour + * @see FTPoint + * + */ +class FTGL_EXPORT FTVectoriser +{ + public: + /** + * Constructor + * + * @param glyph The freetype glyph to be processed + */ + FTVectoriser( const FT_GlyphSlot glyph); + + /** + * Destructor + */ + virtual ~FTVectoriser(); + + /** + * Build an FTMesh from the vector outline data. + * + * @param zNormal The direction of the z axis of the normal + * for this mesh + */ + void MakeMesh( FTGL_DOUBLE zNormal = FTGL_FRONT_FACING); + + /** + * Get the current mesh. + */ + const FTMesh* const GetMesh() const { return mesh;} + + /** + * Get the total count of points in this outline + * + * @return the number of points + */ + size_t PointCount(); + + /** + * Get the count of contours in this outline + * + * @return the number of contours + */ + size_t ContourCount() const { return ftContourCount;} + + /** + * Return a contour at index + * + * @return the number of contours + */ + const FTContour* const Contour( unsigned int index) const; + + /** + * Get the number of points in a specific contour in this outline + * + * @param c The contour index + * @return the number of points in contour[c] + */ + size_t ContourSize( int c) const { return contourList[c]->PointCount();} + + /** + * Get the flag for the tesselation rule for this outline + * + * @return The contour flag + */ + int ContourFlag() const { return contourFlag;} + + private: + /** + * Process the freetype outline data into contours of points + */ + void ProcessContours(); + + /** + * The list of contours in the glyph + */ + FTContour** contourList; + + /** + * A Mesh for tesselations + */ + FTMesh* mesh; + + /** + * The number of contours reported by Freetype + */ + short ftContourCount; + + /** + * A flag indicating the tesselation rule for the glyph + */ + int contourFlag; + + /** + * A Freetype outline + */ + FT_Outline outline; +}; + + +#endif // __FTVectoriser__ diff --git a/extern/bFTGL/license.txt b/extern/bFTGL/license.txt new file mode 100644 index 00000000000..b9fd0dbb580 --- /dev/null +++ b/extern/bFTGL/license.txt @@ -0,0 +1,27 @@ +FTGL + +Herewith is a license. I've also chucked in a gnu (see COPYING.txt) license +for those that are that way inclined. Basically I want you to use this +software and if you think this license is preventing you from doing so +let me know. + +Copyright (C) 2001-3 Henry Maddocks + +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. diff --git a/extern/bFTGL/make/msvc_7_0/ftgl_static_lib.vcproj b/extern/bFTGL/make/msvc_7_0/ftgl_static_lib.vcproj new file mode 100644 index 00000000000..a2dcf685ed2 --- /dev/null +++ b/extern/bFTGL/make/msvc_7_0/ftgl_static_lib.vcproj @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/bFTGL/src/FTBitmapGlyph.cpp b/extern/bFTGL/src/FTBitmapGlyph.cpp new file mode 100644 index 00000000000..5db33f10c79 --- /dev/null +++ b/extern/bFTGL/src/FTBitmapGlyph.cpp @@ -0,0 +1,66 @@ +#include + +#include "FTBitmapGlyph.h" + +FTBitmapGlyph::FTBitmapGlyph( FT_GlyphSlot glyph) +: FTGlyph( glyph), + destWidth(0), + destHeight(0), + data(0) +{ + err = FT_Render_Glyph( glyph, FT_RENDER_MODE_MONO); + if( err || ft_glyph_format_bitmap != glyph->format) + { + return; + } + + FT_Bitmap bitmap = glyph->bitmap; + + unsigned int srcWidth = bitmap.width; + unsigned int srcHeight = bitmap.rows; + unsigned int srcPitch = bitmap.pitch; + + destWidth = srcWidth; + destHeight = srcHeight; + destPitch = srcPitch; + + if( destWidth && destHeight) + { + data = new unsigned char[destPitch * destHeight]; + unsigned char* dest = data + (( destHeight - 1) * destPitch); + + unsigned char* src = bitmap.buffer; + + for( unsigned int y = 0; y < srcHeight; ++y) + { + memcpy( dest, src, srcPitch); + dest -= destPitch; + src += srcPitch; + } + } + + pos.x = glyph->bitmap_left; + pos.y = static_cast(srcHeight) - glyph->bitmap_top; +} + + +FTBitmapGlyph::~FTBitmapGlyph() +{ + delete [] data; +} + + +float FTBitmapGlyph::Render( const FTPoint& pen) +{ + if( data) + { + glBitmap( 0, 0, 0.0, 0.0, pen.x + pos.x, pen.y - pos.y, (const GLubyte*)0 ); + + glPixelStorei( GL_UNPACK_ROW_LENGTH, destPitch * 8); + glBitmap( destWidth, destHeight, 0.0f, 0.0, 0.0, 0.0, (const GLubyte*)data); + + glBitmap( 0, 0, 0.0, 0.0, -pen.x - pos.x, -pen.y + pos.y, (const GLubyte*)0 ); + } + + return advance; +} diff --git a/extern/bFTGL/src/FTBufferGlyph.cpp b/extern/bFTGL/src/FTBufferGlyph.cpp new file mode 100644 index 00000000000..27310103152 --- /dev/null +++ b/extern/bFTGL/src/FTBufferGlyph.cpp @@ -0,0 +1,59 @@ +#include "FTBufferGlyph.h" + +FTBufferGlyph::FTBufferGlyph( FT_GlyphSlot glyph, unsigned char* b) +: FTGlyph( glyph), + destWidth(0), + destHeight(0), + data(0), + buffer(b) +{ + err = FT_Render_Glyph( glyph, FT_RENDER_MODE_NORMAL); + if( err || ft_glyph_format_bitmap != glyph->format) + { + return; + } + + FT_Bitmap bitmap = glyph->bitmap; + + unsigned int srcWidth = bitmap.width; + unsigned int srcHeight = bitmap.rows; + unsigned int srcPitch = bitmap.pitch; + + destWidth = srcWidth; + destHeight = srcHeight; + destPitch = srcPitch; + + if( destWidth && destHeight) + { + data = new unsigned char[destPitch * destHeight]; + unsigned char* dest = data + (( destHeight - 1) * destPitch); + + unsigned char* src = bitmap.buffer; + + for( unsigned int y = 0; y < srcHeight; ++y) + { + memcpy( dest, src, srcPitch); + dest -= destPitch; + src += srcPitch; + } + } + + pos.x = glyph->bitmap_left; + pos.y = srcHeight - glyph->bitmap_top; +} + + +FTBufferGlyph::~FTBufferGlyph() +{ + delete [] data; +} + + +float FTBufferGlyph::Render( const FTPoint& pen) +{ + if( data && buffer) + { + } + + return advance; +} diff --git a/extern/bFTGL/src/FTCharmap.cpp b/extern/bFTGL/src/FTCharmap.cpp new file mode 100644 index 00000000000..00e8cfceca5 --- /dev/null +++ b/extern/bFTGL/src/FTCharmap.cpp @@ -0,0 +1,62 @@ +#include "FTFace.h" +#include "FTCharmap.h" + + +FTCharmap::FTCharmap( FTFace* face) +: ftFace( *(face->Face())), + err(0) +{ + if( !ftFace->charmap) + { + err = FT_Set_Charmap( ftFace, ftFace->charmaps[0]); + } + + ftEncoding = ftFace->charmap->encoding; +} + + +FTCharmap::~FTCharmap() +{ + charMap.clear(); +} + + +bool FTCharmap::CharMap( FT_Encoding encoding) +{ + if( ftEncoding == encoding) + { + return true; + } + + err = FT_Select_Charmap( ftFace, encoding ); + + if( !err) + { + ftEncoding = encoding; + } + else + { + ftEncoding = ft_encoding_none; + } + + charMap.clear(); + return !err; +} + + +unsigned int FTCharmap::GlyphListIndex( const unsigned int characterCode ) +{ + return charMap.find( characterCode); +} + + +unsigned int FTCharmap::FontIndex( const unsigned int characterCode ) +{ + return FT_Get_Char_Index( ftFace, characterCode); +} + + +void FTCharmap::InsertIndex( const unsigned int characterCode, const unsigned int containerIndex) +{ + charMap.insert( characterCode, containerIndex); +} diff --git a/extern/bFTGL/src/FTContour.cpp b/extern/bFTGL/src/FTContour.cpp new file mode 100644 index 00000000000..6b0cf8a23e1 --- /dev/null +++ b/extern/bFTGL/src/FTContour.cpp @@ -0,0 +1,149 @@ +#include "FTContour.h" + +static const float BEZIER_STEP_SIZE = 0.2f; + + +void FTContour::AddPoint( FTPoint point) +{ + if( pointList.empty() || point != pointList[pointList.size() - 1]) + { + pointList.push_back( point); + } +} + + +void FTContour::AddPoint( float x, float y) +{ + AddPoint( FTPoint( x, y, 0.0f)); +} + + +void FTContour::evaluateQuadraticCurve() +{ + for( unsigned int i = 0; i <= ( 1.0f / BEZIER_STEP_SIZE); i++) + { + float bezierValues[2][2]; + + float t = static_cast(i) * BEZIER_STEP_SIZE; + + bezierValues[0][0] = (1.0f - t) * controlPoints[0][0] + t * controlPoints[1][0]; + bezierValues[0][1] = (1.0f - t) * controlPoints[0][1] + t * controlPoints[1][1]; + + bezierValues[1][0] = (1.0f - t) * controlPoints[1][0] + t * controlPoints[2][0]; + bezierValues[1][1] = (1.0f - t) * controlPoints[1][1] + t * controlPoints[2][1]; + + bezierValues[0][0] = (1.0f - t) * bezierValues[0][0] + t * bezierValues[1][0]; + bezierValues[0][1] = (1.0f - t) * bezierValues[0][1] + t * bezierValues[1][1]; + + AddPoint( bezierValues[0][0], bezierValues[0][1]); + } +} + +void FTContour::evaluateCubicCurve() +{ + for( unsigned int i = 0; i <= ( 1.0f / BEZIER_STEP_SIZE); i++) + { + float bezierValues[3][2]; + + float t = static_cast(i) * BEZIER_STEP_SIZE; + + bezierValues[0][0] = (1.0f - t) * controlPoints[0][0] + t * controlPoints[1][0]; + bezierValues[0][1] = (1.0f - t) * controlPoints[0][1] + t * controlPoints[1][1]; + + bezierValues[1][0] = (1.0f - t) * controlPoints[1][0] + t * controlPoints[2][0]; + bezierValues[1][1] = (1.0f - t) * controlPoints[1][1] + t * controlPoints[2][1]; + + bezierValues[2][0] = (1.0f - t) * controlPoints[2][0] + t * controlPoints[3][0]; + bezierValues[2][1] = (1.0f - t) * controlPoints[2][1] + t * controlPoints[3][1]; + + bezierValues[0][0] = (1.0f - t) * bezierValues[0][0] + t * bezierValues[1][0]; + bezierValues[0][1] = (1.0f - t) * bezierValues[0][1] + t * bezierValues[1][1]; + + bezierValues[1][0] = (1.0f - t) * bezierValues[1][0] + t * bezierValues[2][0]; + bezierValues[1][1] = (1.0f - t) * bezierValues[1][1] + t * bezierValues[2][1]; + + bezierValues[0][0] = (1.0f - t) * bezierValues[0][0] + t * bezierValues[1][0]; + bezierValues[0][1] = (1.0f - t) * bezierValues[0][1] + t * bezierValues[1][1]; + + AddPoint( bezierValues[0][0], bezierValues[0][1]); + } +} + + +FTContour::FTContour( FT_Vector* contour, char* pointTags, unsigned int numberOfPoints) +{ + for( unsigned int pointIndex = 0; pointIndex < numberOfPoints; ++ pointIndex) + { + char pointTag = pointTags[pointIndex]; + + if( pointTag == FT_Curve_Tag_On || numberOfPoints < 2) + { + AddPoint( contour[pointIndex].x, contour[pointIndex].y); + continue; + } + + FTPoint controlPoint( contour[pointIndex]); + FTPoint previousPoint = ( 0 == pointIndex) + ? FTPoint( contour[numberOfPoints - 1]) + : pointList[pointList.size() - 1]; + + FTPoint nextPoint = ( pointIndex == numberOfPoints - 1) + ? pointList[0] + : FTPoint( contour[pointIndex + 1]); + + if( pointTag == FT_Curve_Tag_Conic) + { + char nextPointTag = ( pointIndex == numberOfPoints - 1) + ? pointTags[0] + : pointTags[pointIndex + 1]; + + while( nextPointTag == FT_Curve_Tag_Conic) + { + nextPoint = FTPoint( static_cast( controlPoint.x + nextPoint.x) * 0.5f, + static_cast( controlPoint.y + nextPoint.y) * 0.5f, + 0); + + controlPoints[0][0] = previousPoint.x; controlPoints[0][1] = previousPoint.y; + controlPoints[1][0] = controlPoint.x; controlPoints[1][1] = controlPoint.y; + controlPoints[2][0] = nextPoint.x; controlPoints[2][1] = nextPoint.y; + + evaluateQuadraticCurve(); + ++pointIndex; + + previousPoint = nextPoint; + controlPoint = FTPoint( contour[pointIndex]); + nextPoint = ( pointIndex == numberOfPoints - 1) + ? pointList[0] + : FTPoint( contour[pointIndex + 1]); + nextPointTag = ( pointIndex == numberOfPoints - 1) + ? pointTags[0] + : pointTags[pointIndex + 1]; + } + + controlPoints[0][0] = previousPoint.x; controlPoints[0][1] = previousPoint.y; + controlPoints[1][0] = controlPoint.x; controlPoints[1][1] = controlPoint.y; + controlPoints[2][0] = nextPoint.x; controlPoints[2][1] = nextPoint.y; + + evaluateQuadraticCurve(); + continue; + } + + if( pointTag == FT_Curve_Tag_Cubic) + { + FTPoint controlPoint2 = nextPoint; + + FTPoint nextPoint = ( pointIndex == numberOfPoints - 2) + ? pointList[0] + : FTPoint( contour[pointIndex + 2]); + + controlPoints[0][0] = previousPoint.x; controlPoints[0][1] = previousPoint.y; + controlPoints[1][0] = controlPoint.x; controlPoints[1][1] = controlPoint.y; + controlPoints[2][0] = controlPoint2.x; controlPoints[2][1] = controlPoint2.y; + controlPoints[3][0] = nextPoint.x; controlPoints[3][1] = nextPoint.y; + + evaluateCubicCurve(); + ++pointIndex; + continue; + } + } +} diff --git a/extern/bFTGL/src/FTExtrdGlyph.cpp b/extern/bFTGL/src/FTExtrdGlyph.cpp new file mode 100644 index 00000000000..0b120e68709 --- /dev/null +++ b/extern/bFTGL/src/FTExtrdGlyph.cpp @@ -0,0 +1,141 @@ +#include + +#include "FTExtrdGlyph.h" +#include "FTVectoriser.h" + + +FTExtrdGlyph::FTExtrdGlyph( FT_GlyphSlot glyph, float d) +: FTGlyph( glyph), + glList(0), + depth(d) +{ + bBox.SetDepth( -depth); + + if( ft_glyph_format_outline != glyph->format) + { + err = 0x14; // Invalid_Outline + return; + } + + FTVectoriser vectoriser( glyph); + if ( ( vectoriser.ContourCount() < 1) || ( vectoriser.PointCount() < 3)) + { + return; + } + + unsigned int tesselationIndex; + glList = glGenLists(1); + glNewList( glList, GL_COMPILE); + + vectoriser.MakeMesh( 1.0); + glNormal3d(0.0, 0.0, 1.0); + + const FTMesh* mesh = vectoriser.GetMesh(); + for( tesselationIndex = 0; tesselationIndex < mesh->TesselationCount(); ++tesselationIndex) + { + const FTTesselation* subMesh = mesh->Tesselation( tesselationIndex); + unsigned int polyonType = subMesh->PolygonType(); + + glBegin( polyonType); + for( unsigned int pointIndex = 0; pointIndex < subMesh->PointCount(); ++pointIndex) + { + glVertex3f( subMesh->Point( pointIndex).x / 64.0f, + subMesh->Point( pointIndex).y / 64.0f, + 0.0f); + } + glEnd(); + } + + vectoriser.MakeMesh( -1.0); + glNormal3d(0.0, 0.0, -1.0); + + mesh = vectoriser.GetMesh(); + for( tesselationIndex = 0; tesselationIndex < mesh->TesselationCount(); ++tesselationIndex) + { + const FTTesselation* subMesh = mesh->Tesselation( tesselationIndex); + unsigned int polyonType = subMesh->PolygonType(); + + glBegin( polyonType); + for( unsigned int pointIndex = 0; pointIndex < subMesh->PointCount(); ++pointIndex) + { + glVertex3f( subMesh->Point( pointIndex).x / 64.0f, + subMesh->Point( pointIndex).y / 64.0f, + -depth); + } + glEnd(); + } + + int contourFlag = vectoriser.ContourFlag(); + + for( size_t c = 0; c < vectoriser.ContourCount(); ++c) + { + const FTContour* contour = vectoriser.Contour(c); + unsigned int numberOfPoints = contour->PointCount(); + + glBegin( GL_QUAD_STRIP); + for( unsigned int j = 0; j <= numberOfPoints; ++j) + { + unsigned int index = ( j == numberOfPoints) ? 0 : j; + unsigned int nextIndex = ( index == numberOfPoints - 1) ? 0 : index + 1; + + FTPoint normal = GetNormal( contour->Point(index), contour->Point(nextIndex)); + glNormal3f( normal.x, normal.y, 0.0f); + + if( contourFlag & ft_outline_reverse_fill) + { + glVertex3f( contour->Point(index).x / 64.0f, contour->Point(index).y / 64.0f, 0.0f); + glVertex3f( contour->Point(index).x / 64.0f, contour->Point(index).y / 64.0f, -depth); + } + else + { + glVertex3f( contour->Point(index).x / 64.0f, contour->Point(index).y / 64.0f, -depth); + glVertex3f( contour->Point(index).x / 64.0f, contour->Point(index).y / 64.0f, 0.0f); + } + } + glEnd(); + } + + glEndList(); +} + + +FTExtrdGlyph::~FTExtrdGlyph() +{ + glDeleteLists( glList, 1); +} + + +float FTExtrdGlyph::Render( const FTPoint& pen) +{ + if( glList) + { + glTranslatef( pen.x, pen.y, 0); + glCallList( glList); + glTranslatef( -pen.x, -pen.y, 0); + } + + return advance; +} + + +FTPoint FTExtrdGlyph::GetNormal( const FTPoint &a, const FTPoint &b) +{ + float vectorX = a.x - b.x; + float vectorY = a.y - b.y; + + float length = sqrt( vectorX * vectorX + vectorY * vectorY ); + + if( length > 0.0f) + { + length = 1 / length; + } + else + { + length = 0.0f; + } + + return FTPoint( -vectorY * length, + vectorX * length, + 0.0f); +} + diff --git a/extern/bFTGL/src/FTFace.cpp b/extern/bFTGL/src/FTFace.cpp new file mode 100644 index 00000000000..0385e234d6c --- /dev/null +++ b/extern/bFTGL/src/FTFace.cpp @@ -0,0 +1,154 @@ +#include "FTFace.h" +#include "FTLibrary.h" + +#include FT_TRUETYPE_TABLES_H + +FTFace::FTFace( const char* filename) +: numGlyphs(0), + fontEncodingList(0), + err(0) +{ + const FT_Long DEFAULT_FACE_INDEX = 0; + ftFace = new FT_Face; + + err = FT_New_Face( *FTLibrary::Instance().GetLibrary(), filename, DEFAULT_FACE_INDEX, ftFace); + + if( err) + { + delete ftFace; + ftFace = 0; + } + else + { + numGlyphs = (*ftFace)->num_glyphs; + } +} + + +FTFace::FTFace( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: numGlyphs(0), + err(0) +{ + const FT_Long DEFAULT_FACE_INDEX = 0; + ftFace = new FT_Face; + + err = FT_New_Memory_Face( *FTLibrary::Instance().GetLibrary(), (FT_Byte *)pBufferBytes, bufferSizeInBytes, DEFAULT_FACE_INDEX, ftFace); + + if( err) + { + delete ftFace; + ftFace = 0; + } + else + { + numGlyphs = (*ftFace)->num_glyphs; + } +} + + +FTFace::~FTFace() +{ + Close(); +} + + +bool FTFace::Attach( const char* filename) +{ + err = FT_Attach_File( *ftFace, filename); + return !err; +} + + +bool FTFace::Attach( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +{ + FT_Open_Args open; + + open.flags = FT_OPEN_MEMORY; + open.memory_base = (FT_Byte *)pBufferBytes; + open.memory_size = bufferSizeInBytes; + + err = FT_Attach_Stream( *ftFace, &open); + return !err; +} + + +void FTFace::Close() +{ + if( ftFace) + { + FT_Done_Face( *ftFace); + delete ftFace; + ftFace = 0; + } +} + + +const FTSize& FTFace::Size( const unsigned int size, const unsigned int res) +{ + charSize.CharSize( ftFace, size, res, res); + err = charSize.Error(); + + return charSize; +} + + +unsigned int FTFace::CharMapCount() +{ + return (*ftFace)->num_charmaps; +} + + +FT_Encoding* FTFace::CharMapList() +{ + if( 0 == fontEncodingList) + { + fontEncodingList = new FT_Encoding[CharMapCount()]; + for( size_t encodingIndex = 0; encodingIndex < CharMapCount(); ++encodingIndex) + { + fontEncodingList[encodingIndex] = (*ftFace)->charmaps[encodingIndex]->encoding; + } + } + + return fontEncodingList; +} + + +unsigned int FTFace::UnitsPerEM() const +{ + return (*ftFace)->units_per_EM; +} + + +FTPoint FTFace::KernAdvance( unsigned int index1, unsigned int index2) +{ + float x, y; + x = y = 0.0f; + + if( FT_HAS_KERNING((*ftFace)) && index1 && index2) + { + FT_Vector kernAdvance; + kernAdvance.x = kernAdvance.y = 0; + + err = FT_Get_Kerning( *ftFace, index1, index2, ft_kerning_unfitted, &kernAdvance); + if( !err) + { + x = static_cast( kernAdvance.x) / 64.0f; + y = static_cast( kernAdvance.y) / 64.0f; + } + } + + return FTPoint( x, y, 0.0); +} + + +FT_GlyphSlot FTFace::Glyph( unsigned int index, FT_Int load_flags) +{ + err = FT_Load_Glyph( *ftFace, index, load_flags); + if( err) + { + return NULL; + } + + return (*ftFace)->glyph; +} + diff --git a/extern/bFTGL/src/FTFont.cpp b/extern/bFTGL/src/FTFont.cpp new file mode 100644 index 00000000000..c06d883104b --- /dev/null +++ b/extern/bFTGL/src/FTFont.cpp @@ -0,0 +1,271 @@ +#include "FTFace.h" +#include "FTFont.h" +#include "FTGlyphContainer.h" +#include "FTBBox.h" + + +FTFont::FTFont( const char* fontname) +: face( fontname), + glyphList(0) +{ + err = face.Error(); + if( err == 0) + { + glyphList = new FTGlyphContainer( &face); + } +} + + +FTFont::FTFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: face( pBufferBytes, bufferSizeInBytes), + glyphList(0) +{ + err = face.Error(); + if( err == 0) + { + glyphList = new FTGlyphContainer( &face); + } +} + + +FTFont::~FTFont() +{ + delete glyphList; +} + + +bool FTFont::Attach( const char* filename) +{ + if( face.Attach( filename)) + { + err = 0; + return true; + } + else + { + err = face.Error(); + return false; + } +} + + +bool FTFont::Attach( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +{ + if( face.Attach( pBufferBytes, bufferSizeInBytes)) + { + err = 0; + return true; + } + else + { + err = face.Error(); + return false; + } +} + + +bool FTFont::FaceSize( const unsigned int size, const unsigned int res ) +{ + charSize = face.Size( size, res); + + if( face.Error()) + { + return false; + } + + if( glyphList != NULL) + { + delete glyphList; + } + + glyphList = new FTGlyphContainer( &face); + return true; +} + + +unsigned int FTFont::FaceSize() const +{ + return charSize.CharSize(); +} + + +bool FTFont::CharMap( FT_Encoding encoding) +{ + bool result = glyphList->CharMap( encoding); + err = glyphList->Error(); + return result; +} + + +unsigned int FTFont::CharMapCount() +{ + return face.CharMapCount(); +} + + +FT_Encoding* FTFont::CharMapList() +{ + return face.CharMapList(); +} + + +float FTFont::Ascender() const +{ + return charSize.Ascender(); +} + + +float FTFont::Descender() const +{ + return charSize.Descender(); +} + + +void FTFont::BBox( const char* string, + float& llx, float& lly, float& llz, float& urx, float& ury, float& urz) +{ + FTBBox totalBBox; + + if((NULL != string) && ('\0' != *string)) + { + const unsigned char* c = (unsigned char*)string; + + CheckGlyph( *c); + + totalBBox = glyphList->BBox( *c); + float advance = glyphList->Advance( *c, *(c + 1)); + ++c; + + while( *c) + { + CheckGlyph( *c); + FTBBox tempBBox = glyphList->BBox( *c); + tempBBox.Move( FTPoint( advance, 0.0f, 0.0f)); + totalBBox += tempBBox; + advance += glyphList->Advance( *c, *(c + 1)); + ++c; + } + } + + llx = totalBBox.lowerX; + lly = totalBBox.lowerY; + llz = totalBBox.lowerZ; + urx = totalBBox.upperX; + ury = totalBBox.upperY; + urz = totalBBox.upperZ; +} + + +void FTFont::BBox( const wchar_t* string, + float& llx, float& lly, float& llz, float& urx, float& ury, float& urz) +{ + FTBBox totalBBox; + + if((NULL != string) && ('\0' != *string)) + { + const wchar_t* c = string; + + CheckGlyph( *c); + + totalBBox = glyphList->BBox( *c); + float advance = glyphList->Advance( *c, *(c + 1)); + ++c; + + while( *c) + { + CheckGlyph( *c); + FTBBox tempBBox = glyphList->BBox( *c); + tempBBox.Move( FTPoint( advance, 0.0f, 0.0f)); + totalBBox += tempBBox; + advance += glyphList->Advance( *c, *(c + 1)); + ++c; + } + } + + llx = totalBBox.lowerX; + lly = totalBBox.lowerY; + llz = totalBBox.lowerZ; + urx = totalBBox.upperX; + ury = totalBBox.upperY; + urz = totalBBox.upperZ; +} + + +float FTFont::Advance( const wchar_t* string) +{ + const wchar_t* c = string; + float width = 0.0f; + + while( *c) + { + CheckGlyph( *c); + width += glyphList->Advance( *c, *(c + 1)); + ++c; + } + + return width; +} + + +float FTFont::Advance( const char* string) +{ + const unsigned char* c = (unsigned char*)string; + float width = 0.0f; + + while( *c) + { + CheckGlyph( *c); + width += glyphList->Advance( *c, *(c + 1)); + ++c; + } + + return width; +} + + +void FTFont::Render( const char* string ) +{ + const unsigned char* c = (unsigned char*)string; + pen.x = 0; pen.y = 0; + + while( *c) + { + DoRender( *c, *(c + 1)); + ++c; + } +} + + +void FTFont::Render( const wchar_t* string ) +{ + const wchar_t* c = string; + pen.x = 0; pen.y = 0; + + while( *c) + { + DoRender( *c, *(c + 1)); + ++c; + } +} + + +void FTFont::DoRender( const unsigned int chr, const unsigned int nextChr) +{ + CheckGlyph( chr); + + FTPoint kernAdvance = glyphList->Render( chr, nextChr, pen); + + pen.x += kernAdvance.x; + pen.y += kernAdvance.y; +} + + +void FTFont::CheckGlyph( const unsigned int characterCode) +{ + if( NULL == glyphList->Glyph( characterCode)) + { + unsigned int glyphIndex = glyphList->FontIndex( characterCode); + glyphList->Add( MakeGlyph( glyphIndex), characterCode); + } +} + diff --git a/extern/bFTGL/src/FTGLBitmapFont.cpp b/extern/bFTGL/src/FTGLBitmapFont.cpp new file mode 100644 index 00000000000..7e982a608da --- /dev/null +++ b/extern/bFTGL/src/FTGLBitmapFont.cpp @@ -0,0 +1,66 @@ +#include "FTGLBitmapFont.h" +#include "FTBitmapGlyph.h" + + +FTGLBitmapFont::FTGLBitmapFont( const char* fontname) +: FTFont( fontname) +{} + + +FTGLBitmapFont::FTGLBitmapFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: FTFont( pBufferBytes, bufferSizeInBytes) +{} + + +FTGLBitmapFont::~FTGLBitmapFont() +{} + + +FTGlyph* FTGLBitmapFont::MakeGlyph( unsigned int g) +{ + FT_GlyphSlot ftGlyph = face.Glyph( g, FT_LOAD_DEFAULT); + + if( ftGlyph) + { + FTBitmapGlyph* tempGlyph = new FTBitmapGlyph( ftGlyph); + return tempGlyph; + } + + err = face.Error(); + return NULL; +} + + +void FTGLBitmapFont::Render( const char* string) +{ + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT); + glPushAttrib( GL_ENABLE_BIT); + + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1); + + glDisable( GL_BLEND); + + FTFont::Render( string); + + glPopAttrib(); + glPopClientAttrib(); +} + + +void FTGLBitmapFont::Render( const wchar_t* string) +{ + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT); + glPushAttrib( GL_ENABLE_BIT); + + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1); + + glDisable( GL_BLEND); + + FTFont::Render( string); + + glPopAttrib(); + glPopClientAttrib(); +} + diff --git a/extern/bFTGL/src/FTGLBufferFont.cpp b/extern/bFTGL/src/FTGLBufferFont.cpp new file mode 100644 index 00000000000..b8af0fcb05f --- /dev/null +++ b/extern/bFTGL/src/FTGLBufferFont.cpp @@ -0,0 +1,53 @@ +#include "FTGLBufferFont.h" +#include "FTBufferGlyph.h" + + +FTGLBufferFont::FTGLBufferFont( const char* fontname) +: FTFont( fontname), + buffer(0) +{} + + +FTGLBufferFont::FTGLBufferFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: FTFont( pBufferBytes, bufferSizeInBytes), + buffer(0) +{} + + +FTGLBufferFont::~FTGLBufferFont() +{} + + +FTGlyph* FTGLBufferFont::MakeGlyph( unsigned int g) +{ + FT_GlyphSlot ftGlyph = face.Glyph( g, FT_LOAD_NO_HINTING); + + if( ftGlyph) + { + FTBufferGlyph* tempGlyph = new FTBufferGlyph( ftGlyph, buffer); + return tempGlyph; + } + + err = face.Error(); + return NULL; +} + + +void FTGLBufferFont::Render( const char* string) +{ + if( NULL != buffer) + { + FTFont::Render( string); + } +} + + +void FTGLBufferFont::Render( const wchar_t* string) +{ + if( NULL != buffer) + { + FTFont::Render( string); + } +} + + diff --git a/extern/bFTGL/src/FTGLExtrdFont.cpp b/extern/bFTGL/src/FTGLExtrdFont.cpp new file mode 100644 index 00000000000..37d89333a60 --- /dev/null +++ b/extern/bFTGL/src/FTGLExtrdFont.cpp @@ -0,0 +1,35 @@ +#include "FTGLExtrdFont.h" +#include "FTExtrdGlyph.h" + + +FTGLExtrdFont::FTGLExtrdFont( const char* fontname) +: FTFont( fontname), + depth( 0.0f) +{} + + +FTGLExtrdFont::FTGLExtrdFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: FTFont( pBufferBytes, bufferSizeInBytes), + depth( 0.0f) +{} + + +FTGLExtrdFont::~FTGLExtrdFont() +{} + + +FTGlyph* FTGLExtrdFont::MakeGlyph( unsigned int glyphIndex) +{ + FT_GlyphSlot ftGlyph = face.Glyph( glyphIndex, FT_LOAD_NO_HINTING); + + if( ftGlyph) + { + FTExtrdGlyph* tempGlyph = new FTExtrdGlyph( ftGlyph, depth); + return tempGlyph; + } + + err = face.Error(); + return NULL; +} + + diff --git a/extern/bFTGL/src/FTGLOutlineFont.cpp b/extern/bFTGL/src/FTGLOutlineFont.cpp new file mode 100644 index 00000000000..b9fd187e862 --- /dev/null +++ b/extern/bFTGL/src/FTGLOutlineFont.cpp @@ -0,0 +1,66 @@ +#include "FTGLOutlineFont.h" +#include "FTOutlineGlyph.h" + + +FTGLOutlineFont::FTGLOutlineFont( const char* fontname) +: FTFont( fontname) +{} + + +FTGLOutlineFont::FTGLOutlineFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: FTFont( pBufferBytes, bufferSizeInBytes) +{} + + +FTGLOutlineFont::~FTGLOutlineFont() +{} + + +FTGlyph* FTGLOutlineFont::MakeGlyph( unsigned int g) +{ + FT_GlyphSlot ftGlyph = face.Glyph( g, FT_LOAD_NO_HINTING); + + if( ftGlyph) + { + FTOutlineGlyph* tempGlyph = new FTOutlineGlyph( ftGlyph); + return tempGlyph; + } + + err = face.Error(); + return NULL; +} + + +void FTGLOutlineFont::Render( const char* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT); + + glDisable( GL_TEXTURE_2D); + + glEnable( GL_LINE_SMOOTH); + glHint( GL_LINE_SMOOTH_HINT, GL_DONT_CARE); + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE + + FTFont::Render( string); + + glPopAttrib(); +} + + +void FTGLOutlineFont::Render( const wchar_t* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT); + + glDisable( GL_TEXTURE_2D); + + glEnable( GL_LINE_SMOOTH); + glHint( GL_LINE_SMOOTH_HINT, GL_DONT_CARE); + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE + + FTFont::Render( string); + + glPopAttrib(); +} + diff --git a/extern/bFTGL/src/FTGLPixmapFont.cpp b/extern/bFTGL/src/FTGLPixmapFont.cpp new file mode 100644 index 00000000000..2654b85e31e --- /dev/null +++ b/extern/bFTGL/src/FTGLPixmapFont.cpp @@ -0,0 +1,68 @@ +#include "FTGLPixmapFont.h" +#include "FTPixmapGlyph.h" + + +FTGLPixmapFont::FTGLPixmapFont( const char* fontname) +: FTFont( fontname) +{} + + +FTGLPixmapFont::FTGLPixmapFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: FTFont( pBufferBytes, bufferSizeInBytes) +{} + + +FTGLPixmapFont::~FTGLPixmapFont() +{} + + +FTGlyph* FTGLPixmapFont::MakeGlyph( unsigned int g) +{ + FT_GlyphSlot ftGlyph = face.Glyph( g, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP); + + if( ftGlyph) + { + FTPixmapGlyph* tempGlyph = new FTPixmapGlyph( ftGlyph); + return tempGlyph; + } + + err = face.Error(); + return NULL; +} + + +void FTGLPixmapFont::Render( const char* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT); + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT); + + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable( GL_TEXTURE_2D); + + FTFont::Render( string); + + glPopClientAttrib(); + glPopAttrib(); +} + + +void FTGLPixmapFont::Render( const wchar_t* string) +{ + //glPushAttrib( GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT); + // glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT); + + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable( GL_TEXTURE_2D); + + FTFont::Render( string); + + glDisable(GL_BLEND); + // glPopClientAttrib(); + // glPopAttrib(); +} + + diff --git a/extern/bFTGL/src/FTGLPolygonFont.cpp b/extern/bFTGL/src/FTGLPolygonFont.cpp new file mode 100644 index 00000000000..2d4dfa1f26a --- /dev/null +++ b/extern/bFTGL/src/FTGLPolygonFont.cpp @@ -0,0 +1,33 @@ +#include "FTGLPolygonFont.h" +#include "FTPolyGlyph.h" + + +FTGLPolygonFont::FTGLPolygonFont( const char* fontname) +: FTFont( fontname) +{} + + +FTGLPolygonFont::FTGLPolygonFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: FTFont( pBufferBytes, bufferSizeInBytes) +{} + + +FTGLPolygonFont::~FTGLPolygonFont() +{} + + +FTGlyph* FTGLPolygonFont::MakeGlyph( unsigned int g) +{ + FT_GlyphSlot ftGlyph = face.Glyph( g, FT_LOAD_NO_HINTING); + + if( ftGlyph) + { + FTPolyGlyph* tempGlyph = new FTPolyGlyph( ftGlyph); + return tempGlyph; + } + + err = face.Error(); + return NULL; +} + + diff --git a/extern/bFTGL/src/FTGLTextureFont.cpp b/extern/bFTGL/src/FTGLTextureFont.cpp new file mode 100644 index 00000000000..92f14be50f2 --- /dev/null +++ b/extern/bFTGL/src/FTGLTextureFont.cpp @@ -0,0 +1,178 @@ +#include // For memset + +#include "FTGLTextureFont.h" +#include "FTTextureGlyph.h" + + +inline GLuint NextPowerOf2( GLuint in) +{ + in -= 1; + + in |= in >> 16; + in |= in >> 8; + in |= in >> 4; + in |= in >> 2; + in |= in >> 1; + + return in + 1; +} + + +FTGLTextureFont::FTGLTextureFont( const char* fontname) +: FTFont( fontname), + maxTextSize(0), + textureWidth(0), + textureHeight(0), + glyphHeight(0), + glyphWidth(0), + padding(3), + xOffset(0), + yOffset(0) +{ + remGlyphs = numGlyphs = face.GlyphCount(); +} + + +FTGLTextureFont::FTGLTextureFont( const unsigned char *pBufferBytes, size_t bufferSizeInBytes) +: FTFont( pBufferBytes, bufferSizeInBytes), + maxTextSize(0), + textureWidth(0), + textureHeight(0), + glyphHeight(0), + glyphWidth(0), + padding(3), + xOffset(0), + yOffset(0) +{ + remGlyphs = numGlyphs = face.GlyphCount(); +} + + +FTGLTextureFont::~FTGLTextureFont() +{ + glDeleteTextures( textureIDList.size(), (const GLuint*)&textureIDList[0]); +} + + +FTGlyph* FTGLTextureFont::MakeGlyph( unsigned int glyphIndex) +{ + FT_GlyphSlot ftGlyph = face.Glyph( glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP); + + if( ftGlyph) + { + glyphHeight = static_cast( charSize.Height()); + glyphWidth = static_cast( charSize.Width()); + + if( textureIDList.empty()) + { + textureIDList.push_back( CreateTexture()); + xOffset = yOffset = padding; + } + + if( xOffset > ( textureWidth - glyphWidth)) + { + xOffset = padding; + yOffset += glyphHeight; + + if( yOffset > ( textureHeight - glyphHeight)) + { + textureIDList.push_back( CreateTexture()); + yOffset = padding; + } + } + + FTTextureGlyph* tempGlyph = new FTTextureGlyph( ftGlyph, textureIDList[textureIDList.size() - 1], + xOffset, yOffset, textureWidth, textureHeight); + xOffset += static_cast( tempGlyph->BBox().upperX - tempGlyph->BBox().lowerX + padding); + + --remGlyphs; + return tempGlyph; + } + + err = face.Error(); + return NULL; +} + + +void FTGLTextureFont::CalculateTextureSize() +{ + if( !maxTextSize) + { + glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*)&maxTextSize); + } + + textureWidth = NextPowerOf2( (remGlyphs * glyphWidth) + ( padding * 2)); + if( textureWidth > maxTextSize) + { + textureWidth = maxTextSize; + } + + int h = static_cast( (textureWidth - ( padding * 2)) / glyphWidth); + + textureHeight = NextPowerOf2( (( numGlyphs / h) + 1) * glyphHeight); + textureHeight = textureHeight > maxTextSize ? maxTextSize : textureHeight; +} + + +GLuint FTGLTextureFont::CreateTexture() +{ + CalculateTextureSize(); + + int totalMemory = textureWidth * textureHeight; + unsigned char* textureMemory = new unsigned char[totalMemory]; + memset( textureMemory, 0, totalMemory); + + GLuint textID; + glGenTextures( 1, (GLuint*)&textID); + + glBindTexture( GL_TEXTURE_2D, textID); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, textureWidth, textureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, textureMemory); + + delete [] textureMemory; + + return textID; +} + + +bool FTGLTextureFont::FaceSize( const unsigned int size, const unsigned int res) +{ + if( !textureIDList.empty()) + { + glDeleteTextures( textureIDList.size(), (const GLuint*)&textureIDList[0]); + remGlyphs = numGlyphs = face.GlyphCount(); + } + + return FTFont::FaceSize( size, res); +} + + +void FTGLTextureFont::Render( const char* string) +{ +// glPushAttrib( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); + + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE + + FTFont::Render( string); + +// glPopAttrib(); +} + + +void FTGLTextureFont::Render( const wchar_t* string) +{ +// glPushAttrib( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); + + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE + + FTFont::Render( string); + +// glPopAttrib(); +} + diff --git a/extern/bFTGL/src/FTGlyph.cpp b/extern/bFTGL/src/FTGlyph.cpp new file mode 100644 index 00000000000..c68632949c2 --- /dev/null +++ b/extern/bFTGL/src/FTGlyph.cpp @@ -0,0 +1,17 @@ +#include "FTGlyph.h" + + +FTGlyph::FTGlyph( FT_GlyphSlot glyph) +: advance(0.0f), + err(0) +{ + if( glyph) + { + bBox = FTBBox( glyph); + advance = static_cast( glyph->advance.x) / 64.0f; + } +} + + +FTGlyph::~FTGlyph() +{} diff --git a/extern/bFTGL/src/FTGlyphContainer.cpp b/extern/bFTGL/src/FTGlyphContainer.cpp new file mode 100644 index 00000000000..2c1881bbfff --- /dev/null +++ b/extern/bFTGL/src/FTGlyphContainer.cpp @@ -0,0 +1,93 @@ +#include "FTGlyphContainer.h" +#include "FTGlyph.h" +#include "FTFace.h" +#include "FTCharmap.h" + + +FTGlyphContainer::FTGlyphContainer( FTFace* f) +: face(f), + err(0) +{ + glyphs.push_back( NULL); + charMap = new FTCharmap( face); +} + + +FTGlyphContainer::~FTGlyphContainer() +{ + GlyphVector::iterator glyphIterator; + for( glyphIterator = glyphs.begin(); glyphIterator != glyphs.end(); ++glyphIterator) + { + delete *glyphIterator; + } + + glyphs.clear(); + delete charMap; +} + + +bool FTGlyphContainer::CharMap( FT_Encoding encoding) +{ + bool result = charMap->CharMap( encoding); + err = charMap->Error(); + return result; +} + + +unsigned int FTGlyphContainer::FontIndex( const unsigned int characterCode) const +{ + return charMap->FontIndex( characterCode); +} + + +void FTGlyphContainer::Add( FTGlyph* tempGlyph, const unsigned int characterCode) +{ + charMap->InsertIndex( characterCode, glyphs.size()); + glyphs.push_back( tempGlyph); +} + + +const FTGlyph* const FTGlyphContainer::Glyph( const unsigned int characterCode) const +{ + signed int index = charMap->GlyphListIndex( characterCode); + return glyphs[index]; +} + + +FTBBox FTGlyphContainer::BBox( const unsigned int characterCode) const +{ + return glyphs[charMap->GlyphListIndex( characterCode)]->BBox(); +} + + +float FTGlyphContainer::Advance( const unsigned int characterCode, const unsigned int nextCharacterCode) +{ + unsigned int left = charMap->FontIndex( characterCode); + unsigned int right = charMap->FontIndex( nextCharacterCode); + + float width = face->KernAdvance( left, right).x; + width += glyphs[charMap->GlyphListIndex( characterCode)]->Advance(); + + return width; +} + + +FTPoint FTGlyphContainer::Render( const unsigned int characterCode, const unsigned int nextCharacterCode, FTPoint penPosition) +{ + FTPoint kernAdvance; + float advance = 0; + + unsigned int left = charMap->FontIndex( characterCode); + unsigned int right = charMap->FontIndex( nextCharacterCode); + + kernAdvance = face->KernAdvance( left, right); + + if( !face->Error()) + { + advance = glyphs[charMap->GlyphListIndex( characterCode)]->Render( penPosition); + } + + kernAdvance.x = advance + kernAdvance.x; +// kernAdvance.y = advance.y + kernAdvance.y; + return kernAdvance; +} diff --git a/extern/bFTGL/src/FTLibrary.cpp b/extern/bFTGL/src/FTLibrary.cpp new file mode 100644 index 00000000000..29ab5ae2693 --- /dev/null +++ b/extern/bFTGL/src/FTLibrary.cpp @@ -0,0 +1,64 @@ +#include "FTLibrary.h" + + +FTLibrary& FTLibrary::Instance() +{ + static FTLibrary ftlib; + return ftlib; +} + + +FTLibrary::~FTLibrary() +{ + if( library != 0) + { + FT_Done_FreeType( *library); + + delete library; + library= 0; + } + +// if( manager != 0) +// { +// FTC_Manager_Done( manager ); +// +// delete manager; +// manager= 0; +// } +} + + +FTLibrary::FTLibrary() +: library(0), + err(0) +{ + Initialise(); +} + + +bool FTLibrary::Initialise() +{ + if( library != 0) + return true; + + library = new FT_Library; + + err = FT_Init_FreeType( library); + if( err) + { + delete library; + library = 0; + return false; + } + +// FTC_Manager* manager; +// +// if( FTC_Manager_New( lib, 0, 0, 0, my_face_requester, 0, manager ) +// { +// delete manager; +// manager= 0; +// return false; +// } + + return true; +} diff --git a/extern/bFTGL/src/FTOutlineGlyph.cpp b/extern/bFTGL/src/FTOutlineGlyph.cpp new file mode 100644 index 00000000000..340c7804140 --- /dev/null +++ b/extern/bFTGL/src/FTOutlineGlyph.cpp @@ -0,0 +1,57 @@ +#include "FTOutlineGlyph.h" +#include "FTVectoriser.h" + + +FTOutlineGlyph::FTOutlineGlyph( FT_GlyphSlot glyph) +: FTGlyph( glyph), + glList(0) +{ + if( ft_glyph_format_outline != glyph->format) + { + err = 0x14; // Invalid_Outline + return; + } + + FTVectoriser vectoriser( glyph); + + size_t numContours = vectoriser.ContourCount(); + if ( ( numContours < 1) || ( vectoriser.PointCount() < 3)) + { + return; + } + + glList = glGenLists(1); + glNewList( glList, GL_COMPILE); + for( unsigned int c = 0; c < numContours; ++c) + { + const FTContour* contour = vectoriser.Contour(c); + + glBegin( GL_LINE_LOOP); + for( unsigned int p = 0; p < contour->PointCount(); ++p) + { + glVertex2f( contour->Point(p).x / 64.0f, contour->Point(p).y / 64.0f); + } + glEnd(); + } + glEndList(); +} + + +FTOutlineGlyph::~FTOutlineGlyph() +{ + glDeleteLists( glList, 1); +} + + +float FTOutlineGlyph::Render( const FTPoint& pen) +{ + if( glList) + { + glTranslatef( pen.x, pen.y, 0); + glCallList( glList); + glTranslatef( -pen.x, -pen.y, 0); + } + + return advance; +} + diff --git a/extern/bFTGL/src/FTPixmapGlyph.cpp b/extern/bFTGL/src/FTPixmapGlyph.cpp new file mode 100644 index 00000000000..b051a06b6e3 --- /dev/null +++ b/extern/bFTGL/src/FTPixmapGlyph.cpp @@ -0,0 +1,109 @@ +#include "FTPixmapGlyph.h" + +FTPixmapGlyph::FTPixmapGlyph( FT_GlyphSlot glyph) +: FTGlyph( glyph), + destWidth(0), + destHeight(0), + data(0) +{ + err = FT_Render_Glyph( glyph, FT_RENDER_MODE_NORMAL); + if( err || ft_glyph_format_bitmap != glyph->format) + { + return; + } + + FT_Bitmap bitmap = glyph->bitmap; + + //check the pixel mode + //ft_pixel_mode_grays + + int srcWidth = bitmap.width; + int srcHeight = bitmap.rows; + + // FIXME What about dest alignment? + destWidth = srcWidth; + destHeight = srcHeight; + + if( destWidth && destHeight) + { + data = new unsigned char[destWidth * destHeight * 4]; + + // Get the current glColor. + float ftglColour[4]; +// glGetFloatv( GL_CURRENT_COLOR, ftglColour); + ftglColour[0] = ftglColour[1] = ftglColour[2] = ftglColour[3] = 1.0; + + unsigned char redComponent = static_cast( ftglColour[0] * 255.0f); + unsigned char greenComponent = static_cast( ftglColour[1] * 255.0f); + unsigned char blueComponent = static_cast( ftglColour[2] * 255.0f); + + unsigned char* src = bitmap.buffer; + + unsigned char* dest = data + ((destHeight - 1) * destWidth) * 4; + size_t destStep = destWidth * 4 * 2; + + if( ftglColour[3] == 1.0f) + { + for( int y = 0; y < srcHeight; ++y) + { + for( int x = 0; x < srcWidth; ++x) + { + *dest++ = redComponent; + *dest++ = greenComponent; + *dest++ = blueComponent; + *dest++ = *src++; + } + dest -= destStep; + } + } + else + { + for( int y = 0; y < srcHeight; ++y) + { + for( int x = 0; x < srcWidth; ++x) + { + *dest++ = redComponent; + *dest++ = greenComponent; + *dest++ = blueComponent; + *dest++ = static_cast(ftglColour[3] * *src++); + } + dest -= destStep; + } + } + + destHeight = srcHeight; + } + + pos.x = glyph->bitmap_left; + pos.y = srcHeight - glyph->bitmap_top; +} + + +FTPixmapGlyph::~FTPixmapGlyph() +{ + delete [] data; +} + +#include +float FTPixmapGlyph::Render( const FTPoint& pen) +{ + if( data) + { + float dx, dy; + + dx= floor( (pen.x + pos.x ) ); + dy= ( (pen.y - pos.y ) ); + + // Move the glyph origin + glBitmap( 0, 0, 0.0f, 0.0f, dx, dy, (const GLubyte*)0); + + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0); + + glDrawPixels( destWidth, destHeight, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)data); + + // Restore the glyph origin + glBitmap( 0, 0, 0.0f, 0.0f, -dx, -dy, (const GLubyte*)0); + } + + return advance; +} diff --git a/extern/bFTGL/src/FTPoint.cpp b/extern/bFTGL/src/FTPoint.cpp new file mode 100644 index 00000000000..e4678bc9564 --- /dev/null +++ b/extern/bFTGL/src/FTPoint.cpp @@ -0,0 +1,14 @@ +#include "FTPoint.h" + + +bool operator == ( const FTPoint &a, const FTPoint &b) +{ + return((a.x == b.x) && (a.y == b.y) && (a.z == b.z)); +} + +bool operator != ( const FTPoint &a, const FTPoint &b) +{ + return((a.x != b.x) || (a.y != b.y) || (a.z != b.z)); +} + + diff --git a/extern/bFTGL/src/FTPolyGlyph.cpp b/extern/bFTGL/src/FTPolyGlyph.cpp new file mode 100644 index 00000000000..7e0d695493c --- /dev/null +++ b/extern/bFTGL/src/FTPolyGlyph.cpp @@ -0,0 +1,62 @@ +#include "FTPolyGlyph.h" +#include "FTVectoriser.h" + + +FTPolyGlyph::FTPolyGlyph( FT_GlyphSlot glyph) +: FTGlyph( glyph), + glList(0) +{ + if( ft_glyph_format_outline != glyph->format) + { + err = 0x14; // Invalid_Outline + return; + } + + FTVectoriser vectoriser( glyph); + + if(( vectoriser.ContourCount() < 1) || ( vectoriser.PointCount() < 3)) + { + return; + } + + vectoriser.MakeMesh( 1.0); + + glList = glGenLists( 1); + glNewList( glList, GL_COMPILE); + + const FTMesh* mesh = vectoriser.GetMesh(); + for( unsigned int index = 0; index < mesh->TesselationCount(); ++index) + { + const FTTesselation* subMesh = mesh->Tesselation( index); + unsigned int polyonType = subMesh->PolygonType(); + + glBegin( polyonType); + for( unsigned int x = 0; x < subMesh->PointCount(); ++x) + { + glVertex3f( subMesh->Point(x).x / 64.0f, + subMesh->Point(x).y / 64.0f, + 0.0f); + } + glEnd(); + } + glEndList(); +} + + +FTPolyGlyph::~FTPolyGlyph() +{ + glDeleteLists( glList, 1); +} + + +float FTPolyGlyph::Render( const FTPoint& pen) +{ + if( glList) + { + glTranslatef( pen.x, pen.y, 0); + glCallList( glList); + glTranslatef( -pen.x, -pen.y, 0); + } + + return advance; +} diff --git a/extern/bFTGL/src/FTSize.cpp b/extern/bFTGL/src/FTSize.cpp new file mode 100644 index 00000000000..5fb8ffba157 --- /dev/null +++ b/extern/bFTGL/src/FTSize.cpp @@ -0,0 +1,105 @@ +#include "FTSize.h" + + +FTSize::FTSize() +: ftFace(0), + ftSize(0), + size(0), + err(0) +{} + + +FTSize::~FTSize() +{} + + +bool FTSize::CharSize( FT_Face* face, unsigned int point_size, unsigned int x_resolution, unsigned int y_resolution ) +{ + err = FT_Set_Char_Size( *face, 0L, point_size * 64, x_resolution, y_resolution); + + if( !err) + { + ftFace = face; + size = point_size; + ftSize = (*ftFace)->size; + } + else + { + ftFace = 0; + size = 0; + ftSize = 0; + } + + return !err; +} + + +unsigned int FTSize::CharSize() const +{ + return size; +} + + +float FTSize::Ascender() const +{ + return ftSize == 0 ? 0.0f : static_cast( ftSize->metrics.ascender) / 64.0f; +} + + +float FTSize::Descender() const +{ + return ftSize == 0 ? 0.0f : static_cast( ftSize->metrics.descender) / 64.0f; +} + + +float FTSize::Height() const +{ + if( 0 == ftSize) + { + return 0.0f; + } + + if( FT_IS_SCALABLE((*ftFace))) + { + return ( (*ftFace)->bbox.yMax - (*ftFace)->bbox.yMin) * ( (float)ftSize->metrics.y_ppem / (float)(*ftFace)->units_per_EM); + } + else + { + return static_cast( ftSize->metrics.height) / 64.0f; + } +} + + +float FTSize::Width() const +{ + if( 0 == ftSize) + { + return 0.0f; + } + + if( FT_IS_SCALABLE((*ftFace))) + { + return ( (*ftFace)->bbox.xMax - (*ftFace)->bbox.xMin) * ( static_cast(ftSize->metrics.x_ppem) / static_cast((*ftFace)->units_per_EM)); + } + else + { + return static_cast( ftSize->metrics.max_advance) / 64.0f; + } +} + + +float FTSize::Underline() const +{ + return 0.0f; +} + +unsigned int FTSize::XPixelsPerEm() const +{ + return ftSize == 0 ? 0 : ftSize->metrics.x_ppem; +} + +unsigned int FTSize::YPixelsPerEm() const +{ + return ftSize == 0 ? 0 : ftSize->metrics.y_ppem; +} + diff --git a/extern/bFTGL/src/FTTextureGlyph.cpp b/extern/bFTGL/src/FTTextureGlyph.cpp new file mode 100644 index 00000000000..b8267dcce89 --- /dev/null +++ b/extern/bFTGL/src/FTTextureGlyph.cpp @@ -0,0 +1,87 @@ +#include "FTTextureGlyph.h" + + +FTTextureGlyph::FTTextureGlyph( FT_GlyphSlot glyph, int id, int xOffset, int yOffset, GLsizei width, GLsizei height) +: FTGlyph( glyph), + destWidth(0), + destHeight(0), + glTextureID(id), + activeTextureID(0) +{ + err = FT_Render_Glyph( glyph, FT_RENDER_MODE_NORMAL); + if( err || glyph->format != ft_glyph_format_bitmap) + { + return; + } + + FT_Bitmap bitmap = glyph->bitmap; + + destWidth = bitmap.width; + destHeight = bitmap.rows; + + if( destWidth && destHeight) + { + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT); + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1); + + glBindTexture( GL_TEXTURE_2D, glTextureID); + glTexSubImage2D( GL_TEXTURE_2D, 0, xOffset, yOffset, destWidth, destHeight, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer); + + glPopClientAttrib(); + } + + +// 0 +// +----+ +// | | +// | | +// | | +// +----+ +// 1 + + uv[0].x = static_cast(xOffset) / static_cast(width); + uv[0].y = static_cast(yOffset) / static_cast(height); + uv[1].x = static_cast( xOffset + destWidth) / static_cast(width); + uv[1].y = static_cast( yOffset + destHeight) / static_cast(height); + + pos.x = glyph->bitmap_left; + pos.y = glyph->bitmap_top; +} + + +FTTextureGlyph::~FTTextureGlyph() +{} + +#include + +float FTTextureGlyph::Render( const FTPoint& pen) +{ + float dx; + + glGetIntegerv( GL_TEXTURE_2D_BINDING_EXT, &activeTextureID); + if( activeTextureID != glTextureID) + { + glBindTexture( GL_TEXTURE_2D, (GLuint)glTextureID); + } + + dx= floor( (pen.x + pos.x ) ); + + glBegin( GL_QUADS); + glTexCoord2f( uv[0].x, uv[0].y); + glVertex2f( dx, pen.y + pos.y); + + glTexCoord2f( uv[0].x, uv[1].y); + glVertex2f( dx, pen.y + pos.y - destHeight); + + glTexCoord2f( uv[1].x, uv[1].y); + glVertex2f( dx + destWidth, pen.y + pos.y - destHeight); + + glTexCoord2f( uv[1].x, uv[0].y); + glVertex2f( dx + destWidth, pen.y + pos.y); + glEnd(); + + return advance; +} + diff --git a/extern/bFTGL/src/FTVectoriser.cpp b/extern/bFTGL/src/FTVectoriser.cpp new file mode 100644 index 00000000000..82dcb0c0f51 --- /dev/null +++ b/extern/bFTGL/src/FTVectoriser.cpp @@ -0,0 +1,229 @@ +#include "FTVectoriser.h" +#include "FTGL.h" + +#ifndef CALLBACK +#define CALLBACK +#endif + +#if defined(__APPLE_CC__) + #if __APPLE_CC__ >= 5465 + typedef GLvoid (*GLUTesselatorFunction)(); + #else + typedef GLvoid (*GLUTesselatorFunction)(...); + #endif +#elif defined( __mips ) || defined( __linux__ ) || defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __sun ) || defined (__CYGWIN__) + typedef GLvoid (*GLUTesselatorFunction)(); +#elif defined ( WIN32) + typedef GLvoid (CALLBACK *GLUTesselatorFunction)( ); +#else + #error "Error - need to define type GLUTesselatorFunction for this platform/compiler" +#endif + + +void CALLBACK ftglError( GLenum errCode, FTMesh* mesh) +{ + mesh->Error( errCode); +} + + +void CALLBACK ftglVertex( void* data, FTMesh* mesh) +{ + FTGL_DOUBLE* vertex = static_cast(data); + mesh->AddPoint( vertex[0], vertex[1], vertex[2]); +} + + +void CALLBACK ftglCombine( FTGL_DOUBLE coords[3], void* vertex_data[4], GLfloat weight[4], void** outData, FTMesh* mesh) +{ + FTGL_DOUBLE* vertex = static_cast(coords); + *outData = mesh->Combine( vertex[0], vertex[1], vertex[2]); +} + + +void CALLBACK ftglBegin( GLenum type, FTMesh* mesh) +{ + mesh->Begin( type); +} + + +void CALLBACK ftglEnd( FTMesh* mesh) +{ + mesh->End(); +} + + +FTMesh::FTMesh() +: currentTesselation(0), + err(0) +{ + tesselationList.reserve( 16); +} + + +FTMesh::~FTMesh() +{ + for( size_t t = 0; t < tesselationList.size(); ++t) + { + delete tesselationList[t]; + } + + tesselationList.clear(); +} + + +void FTMesh::AddPoint( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) +{ + currentTesselation->AddPoint( x, y, z); +} + + +FTGL_DOUBLE* FTMesh::Combine( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) +{ + tempPointList.push_back( FTPoint( x, y,z)); + return &tempPointList.back().x; +} + + +void FTMesh::Begin( GLenum meshType) +{ + currentTesselation = new FTTesselation( meshType); +} + + +void FTMesh::End() +{ + tesselationList.push_back( currentTesselation); +} + + +const FTTesselation* const FTMesh::Tesselation( unsigned int index) const +{ + return ( index < tesselationList.size()) ? tesselationList[index] : NULL; +} + + +FTVectoriser::FTVectoriser( const FT_GlyphSlot glyph) +: contourList(0), + mesh(0), + ftContourCount(0), + contourFlag(0) +{ + if( glyph) + { + outline = glyph->outline; + + ftContourCount = outline.n_contours;; + contourList = 0; + contourFlag = outline.flags; + + ProcessContours(); + } +} + + +FTVectoriser::~FTVectoriser() +{ + for( size_t c = 0; c < ContourCount(); ++c) + { + delete contourList[c]; + } + + delete [] contourList; + delete mesh; +} + + +void FTVectoriser::ProcessContours() +{ + short contourLength = 0; + short startIndex = 0; + short endIndex = 0; + + contourList = new FTContour*[ftContourCount]; + + for( short contourIndex = 0; contourIndex < ftContourCount; ++contourIndex) + { + FT_Vector* pointList = &outline.points[startIndex]; + char* tagList = &outline.tags[startIndex]; + + endIndex = outline.contours[contourIndex]; + contourLength = ( endIndex - startIndex) + 1; + + FTContour* contour = new FTContour( pointList, tagList, contourLength); + + contourList[contourIndex] = contour; + + startIndex = endIndex + 1; + } +} + + +size_t FTVectoriser::PointCount() +{ + size_t s = 0; + for( size_t c = 0; c < ContourCount(); ++c) + { + s += contourList[c]->PointCount(); + } + + return s; +} + + +const FTContour* const FTVectoriser::Contour( unsigned int index) const +{ + return ( index < ContourCount()) ? contourList[index] : NULL; +} + + +void FTVectoriser::MakeMesh( FTGL_DOUBLE zNormal) +{ + if( mesh) + { + delete mesh; + } + + mesh = new FTMesh; + + GLUtesselator* tobj = gluNewTess(); + + gluTessCallback( tobj, GLU_TESS_BEGIN_DATA, (GLUTesselatorFunction)ftglBegin); + gluTessCallback( tobj, GLU_TESS_VERTEX_DATA, (GLUTesselatorFunction)ftglVertex); + gluTessCallback( tobj, GLU_TESS_COMBINE_DATA, (GLUTesselatorFunction)ftglCombine); + gluTessCallback( tobj, GLU_TESS_END_DATA, (GLUTesselatorFunction)ftglEnd); + gluTessCallback( tobj, GLU_TESS_ERROR_DATA, (GLUTesselatorFunction)ftglError); + + if( contourFlag & ft_outline_even_odd_fill) // ft_outline_reverse_fill + { + gluTessProperty( tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); + } + else + { + gluTessProperty( tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); + } + + + gluTessProperty( tobj, GLU_TESS_TOLERANCE, 0); + gluTessNormal( tobj, 0.0f, 0.0f, zNormal); + gluTessBeginPolygon( tobj, mesh); + + for( size_t c = 0; c < ContourCount(); ++c) + { + const FTContour* contour = contourList[c]; + + gluTessBeginContour( tobj); + + for( size_t p = 0; p < contour->PointCount(); ++p) + { + FTGL_DOUBLE* d = const_cast(&contour->Point(p).x); + gluTessVertex( tobj, d, d); + } + + gluTessEndContour( tobj); + } + + gluTessEndPolygon( tobj); + + gluDeleteTess( tobj); +} + diff --git a/extern/bFTGL/src/Makefile b/extern/bFTGL/src/Makefile new file mode 100644 index 00000000000..064480fbd16 --- /dev/null +++ b/extern/bFTGL/src/Makefile @@ -0,0 +1,62 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = ftgl +DIR = $(OCGDIR)/extern/$(LIBNAME) + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CSRCS = +CCSRCS = FTBitmapGlyph.cpp FTCharmap.cpp FTContour.cpp FTExtrdGlyph.cpp \ + FTFace.cpp FTFont.cpp FTGLBitmapFont.cpp FTGLExtrdFont.cpp \ + FTGLOutlineFont.cpp FTGLPixmapFont.cpp FTGLPolygonFont.cpp \ + FTGLTextureFont.cpp FTGlyph.cpp FTGlyphContainer.cpp FTLibrary.cpp \ + FTOutlineGlyph.cpp FTPixmapGlyph.cpp FTPoint.cpp FTPolyGlyph.cpp \ + FTSize.cpp FTTextureGlyph.cpp FTVectoriser.cpp + +include nan_compile.mk +CPPFLAGS += -I../include +CPPFLAGS += -I$(NAN_FREETYPE)/include -I$(NAN_FREETYPE)/include/freetype2 + +install: all debug + @[ -d $(NAN_FTGL) ] || mkdir -p $(NAN_FTGL) + @[ -d $(NAN_FTGL)/include ] || mkdir -p $(NAN_FTGL)/include + @[ -d $(NAN_FTGL)/lib ] || mkdir -p $(NAN_FTGL)/lib + @[ -d $(NAN_FTGL)/lib/debug ] || mkdir -p $(NAN_FTGL)/lib/debug + @$(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/lib$(LIBNAME).a $(NAN_FTGL)/lib/ +# @$(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/debug/lib$(LIBNAME).a $(NAN_FTGL)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_FTGL)/lib/lib$(LIBNAME).a +endif + @$(NANBLENDERHOME)/intern/tools/cpifdiff.sh ../include/*.h $(NAN_FTGL)/include/ + diff --git a/extern/bFTGL/win32_vcpp/README_WIN32.txt b/extern/bFTGL/win32_vcpp/README_WIN32.txt new file mode 100644 index 00000000000..bc92bbb9591 --- /dev/null +++ b/extern/bFTGL/win32_vcpp/README_WIN32.txt @@ -0,0 +1,206 @@ +FTGL 1.31 + +NOTES FOR COMPILING ON WINDOWS + +14 Feb 2002 + +Ellers, ellers@iinet.net.au + + + + + +SUPPORTED COMPILERS + + + +I have rebuilt the FTGL project files for Visual C++ (version 6). There are + +presently no other compilers or environments supported but feel free to + +contribute them. + + + + + +QUICK GUIDE: COMPILING FTGL + + + + - Start up MSVC++ with ftgl.dsw. + + - Tell MSVC++ where FreeType is. You'll need to do something like this: + + + + * select Project>Settings + + * select ftgl_static (for a start) + + * select "All Configurations" + + * go to the tab C++ > PreProcessor + + * Set additional include directories appropriately. For me it is: + + D:\cots\freetype-2.0.5\include + + * repeat for all configurations of ftgl_dll + + + + + +QUICK GUIDE: COMPILING/RUNNING SUPPLIED DEMO PROGRAM + + + + - The program expects the first argument to be the name of a truetype file. + + I copied timesbi.ttf from the windows directory to C:\TEMP and then edit + + the settings of the project: + + + + * select Project>Settings + + * select Demo project + + * select panel Debug>General + + * set Program Arguments to be "C:\TEMP\timesbi.ttf" + + + + + +QUICK GUIDE: COMPILING YOUR PROGRAM TO USE FTGL + + + + - Choose dynamic or static library linkage + + * if you want to link to a static FTGL library ensure that + + FTGL_LIBRARY_STATIC is defined in the preprocessor section + + + + + +CONFIGURATION / CODE GENERATION / C LIBRARIES + + + +FTGL can be built in various configurations (inspired by Freetype and libpng): + + + + - static library (.lib) + + - dynamic library (.dll) + + + +MSVC++ requires selection of "code generation" option, which seems to be + +mostly to do with which version of the Standard C library is linked with the + +library. + + + +The following modes are supported: + + + + - static/dynamic + + - single threaded (ST) or multithreaded (MT) + + NOTE: the multithreaded DLL (MD) mode was NOT included, as freetype itself + + doesn't support that mode so I figure there's no point yet. + + - debug/release (debug has _d suffix) + + + +So the static multithreaded release library is: + + + + ftgl_static_MT.lib + + + +The same library built in DEBUG mode: + + + + ftgl_static_MT_d.lib + + + +If you're not sure which one is appropriate (and if you're a novice don't + +been too put off...) start with making the decision about debug or release. + +This should be easy because if you're building the debug version of your + +app its probably a good idea to link with the debug version of FTGL (but + +not compulsory). Once thats done, you may get errors like: + + + + LIBCMTD.lib(crt0init.obj) : warning LNK4098: defaultlib "libcmt.lib" conflicts with use of other libs; use /NODEFAULTLIB:library + + + +This will happen, for example, when you link a glut app with an FTGL library + +compiled with different codegen options than the GLUT library. + + + +MSVC++ "sort of" + +requires that all libs be linked with the same codegen option. GLUT is built + +in XXX mode, so if you're linking with GLUT, you can get rid of the warning + +by linking with the XXX version of FTGL. The various versions are particularly + +useful if you're doing std C stuff, like printf etc. + + + + + + + +FAQ + + + +Q: "But... do I HAVE to use all these DIFFERENT build modes, like multi- + + threaded, debug single threaded, etc?" + + + +A: No. Sometimes library makers only generate one style anyway. It depends + + on your needs. Unless you're linking with standard C stuff (e.g. printf) + + then it probably won't make a great deal of difference. If you get + + warnings about "default lib libcmt.lib conflicts" etc, then you can make + + use of the different libraries. + + + diff --git a/extern/bFTGL/win32_vcpp/ftgl.dsw b/extern/bFTGL/win32_vcpp/ftgl.dsw new file mode 100644 index 00000000000..17b8fbe6f12 --- /dev/null +++ b/extern/bFTGL/win32_vcpp/ftgl.dsw @@ -0,0 +1,92 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ftgl_demo"=".\ftgl_demo\ftgl_demo.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ftgl_dll + End Project Dependency + Begin Project Dependency + Project_Dep_Name ftgl_static_lib + End Project Dependency +}}} + +############################################################################### + +Project: "ftgl_demo_2"=".\ftgl_demo\ftgl_demo_2.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ftgl_dll + End Project Dependency + Begin Project Dependency + Project_Dep_Name ftgl_static_lib + End Project Dependency +}}} + +############################################################################### + +Project: "ftgl_dll"=".\ftgl_dll\ftgl_dll.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ftgl_static_lib"=".\ftgl_static_lib\ftgl_static_lib.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "unit_tests"=".\unit_tests\unit_tests.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ftgl_static_lib + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/extern/bFTGL/win32_vcpp/ftgl_dll/ftgl_dll.dsp b/extern/bFTGL/win32_vcpp/ftgl_dll/ftgl_dll.dsp new file mode 100644 index 00000000000..7e297df9111 --- /dev/null +++ b/extern/bFTGL/win32_vcpp/ftgl_dll/ftgl_dll.dsp @@ -0,0 +1,357 @@ +# Microsoft Developer Studio Project File - Name="ftgl_dll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=ftgl_dll - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ftgl_dll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ftgl_dll.mak" CFG="ftgl_dll - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ftgl_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ftgl_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ftgl_dll - Win32 Release MT" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ftgl_dll - Win32 Debug MT" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ftgl_dll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_ST" +# PROP BASE Intermediate_Dir "Release_ST" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../Build" +# PROP Intermediate_Dir "Release_ST" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "../Build" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FTGL_DLL_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "D:\cots\freetype-2.0.5\include" /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FTGL_LIBRARY" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib freetype204.lib /nologo /dll /machine:I386 /out:"../Build/ftgl_dynamic_MT.dll" /libpath:"D:\cots\freetype-2.0.5\objs" + +!ELSEIF "$(CFG)" == "ftgl_dll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_ST" +# PROP BASE Intermediate_Dir "Debug_ST" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../Build" +# PROP Intermediate_Dir "Debug_ST" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "../Build" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FTGL_DLL_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "D:\cots\freetype-2.0.5\include" /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FTGL_LIBRARY" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib freetype204_D.lib /nologo /dll /pdb:"Debug_ST/ftgl_dynamic_ST_d.pdb" /debug /machine:I386 /out:"../Build/ftgl_dynamic_MT_d.dll" /pdbtype:sept /libpath:"D:\cots\freetype-2.0.5\objs" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "ftgl_dll - Win32 Release MT" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_MT" +# PROP BASE Intermediate_Dir "Release_MT" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../Build" +# PROP Intermediate_Dir "Release_MT" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "../Build" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FTGL_DLL_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "D:\cots\freetype-2.0.5\include" /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FTGL_LIBRARY" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib freetype204MT.lib /nologo /dll /machine:I386 /out:"../Build/ftgl_dynamic_MTD.dll" /libpath:"D:\cots\freetype-2.0.5\objs" + +!ELSEIF "$(CFG)" == "ftgl_dll - Win32 Debug MT" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_MT" +# PROP BASE Intermediate_Dir "Debug_MT" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../Build" +# PROP Intermediate_Dir "Debug_MT" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "../Build" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FTGL_DLL_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "D:\cots\freetype-2.0.5\include" /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FTGL_LIBRARY" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib freetype204MT_D.lib /nologo /dll /pdb:"Debug_ST/ftgl_dynamic_MT_d.pdb" /debug /machine:I386 /out:"../Build/ftgl_dynamic_MTD_d.dll" /pdbtype:sept /libpath:"D:\cots\freetype-2.0.5\objs" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "ftgl_dll - Win32 Release" +# Name "ftgl_dll - Win32 Debug" +# Name "ftgl_dll - Win32 Release MT" +# Name "ftgl_dll - Win32 Debug MT" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\src\FTBitmapGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTCharmap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTContour.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTExtrdGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTFace.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLBitmapFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLExtrdFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLOutlineFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLPixmapFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLPolygonFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLTextureFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGlyphContainer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTLibrary.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTOutlineGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTPixmapGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTPoint.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTPolyGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTSize.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTTextureGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTVectoriser.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\include\FTBBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTBitmapGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTCharmap.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTCharToGlyphIndexMap.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTContour.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTExtrdGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTFace.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGL.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLBitmapFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLExtrdFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLOutlineFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLPixmapFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLPolygonFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLTextureFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGlyphContainer.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTLibrary.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTList.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTOutlineGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTPixmapGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTPoint.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTPolyGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTSize.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTTextureGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTVectoriser.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/extern/bFTGL/win32_vcpp/ftgl_static_lib/ftgl_static_lib.dsp b/extern/bFTGL/win32_vcpp/ftgl_static_lib/ftgl_static_lib.dsp new file mode 100644 index 00000000000..bc2c77cb0b6 --- /dev/null +++ b/extern/bFTGL/win32_vcpp/ftgl_static_lib/ftgl_static_lib.dsp @@ -0,0 +1,342 @@ +# Microsoft Developer Studio Project File - Name="ftgl_static_lib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=ftgl_static_lib - Win32 Debug MT +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ftgl_static_lib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ftgl_static_lib.mak" CFG="ftgl_static_lib - Win32 Debug MT" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ftgl_static_lib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "ftgl_static_lib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "ftgl_static_lib - Win32 Debug MT" (based on "Win32 (x86) Static Library") +!MESSAGE "ftgl_static_lib - Win32 Release MT" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ftgl_static_lib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_ST" +# PROP BASE Intermediate_Dir "Release_ST" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_ST" +# PROP Intermediate_Dir "Release_ST" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\freetype\include" /I "..\..\include" /I "..\..\..\..\..\lib\windows\freetype\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FTGL_LIBRARY_STATIC" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\Build\ftgl_static_ST.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying lib to lib\windows\ftgl\lib XCOPY /Y ..\Build\*lib ..\..\..\..\..\lib\windows\ftgl\lib +# End Special Build Tool + +!ELSEIF "$(CFG)" == "ftgl_static_lib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_ST" +# PROP BASE Intermediate_Dir "Debug_ST" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_ST" +# PROP Intermediate_Dir "Debug_ST" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "D:\cots\freetype-2.0.5\include" /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FTGL_LIBRARY_STATIC" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\Build\ftgl_static_MT_d.lib" + +!ELSEIF "$(CFG)" == "ftgl_static_lib - Win32 Debug MT" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_MT" +# PROP BASE Intermediate_Dir "Debug_MT" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_MT" +# PROP Intermediate_Dir "Debug_MT" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "D:\cots\freetype-2.0.5\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FTGL_LIBRARY_STATIC" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "D:\cots\freetype-2.0.5\include" /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FTGL_LIBRARY_STATIC" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\Build\ftgl_static_MTD_d.lib" + +!ELSEIF "$(CFG)" == "ftgl_static_lib - Win32 Release MT" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_MT" +# PROP BASE Intermediate_Dir "Release_MT" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_MT" +# PROP Intermediate_Dir "Release_MT" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FTGL_LIBRARY_STATIC" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "D:\cots\freetype-2.0.5\include" /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "FTGL_LIBRARY_STATIC" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\Build\ftgl_static_MTD.lib" + +!ENDIF + +# Begin Target + +# Name "ftgl_static_lib - Win32 Release" +# Name "ftgl_static_lib - Win32 Debug" +# Name "ftgl_static_lib - Win32 Debug MT" +# Name "ftgl_static_lib - Win32 Release MT" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\src\FTBitmapGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTCharmap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTContour.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTExtrdGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTFace.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLBitmapFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLExtrdFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLOutlineFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLPixmapFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLPolygonFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGLTextureFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTGlyphContainer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTLibrary.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTOutlineGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTPixmapGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTPoint.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTPolyGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTSize.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTTextureGlyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\src\FTVectoriser.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\include\FTBBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTBitmapGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTCharmap.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTCharToGlyphIndexMap.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTContour.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTExtrdGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTFace.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGL.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLBitmapFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLExtrdFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLOutlineFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLPixmapFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLPolygonFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGLTextureFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTGlyphContainer.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTLibrary.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTList.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTOutlineGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTPixmapGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTPoint.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTPolyGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTSize.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTTextureGlyph.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\FTVectoriser.h +# End Source File +# End Group +# End Target +# End Project diff --git a/extern/bFTGL/win32_vcpp/unit_tests/unit_tests.dsp b/extern/bFTGL/win32_vcpp/unit_tests/unit_tests.dsp new file mode 100644 index 00000000000..f68dfe9b2d8 --- /dev/null +++ b/extern/bFTGL/win32_vcpp/unit_tests/unit_tests.dsp @@ -0,0 +1,168 @@ +# Microsoft Developer Studio Project File - Name="unit_tests" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=unit_tests - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "unit_tests.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "unit_tests.mak" CFG="unit_tests - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "unit_tests - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "unit_tests - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "unit_tests - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "$(MIC_COTS_CPPUNIT_DIR)/include" /I "../../include" /I "../../extras" /I "D:\cots\freetype-2.0.5\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "FTGL_LIBRARY_STATIC" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 freetype204MT.lib ftgl_static_MT.lib cppunit.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\Build" /libpath:"D:\cots\freetype-2.0.5\objs" /libpath:"D:\cots\cppunit-1.9.8\lib" + +!ELSEIF "$(CFG)" == "unit_tests - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "$(MIC_COTS_CPPUNIT_DIR)/include" /I "../../include" /I "../../extras" /I "D:\cots\freetype-2.0.5\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "FTGL_LIBRARY_STATIC" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 freetype204MT_D.lib ftgl_static_MT_d.lib cppunitd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\Build" /libpath:"D:\cots\freetype-2.0.5\objs" /libpath:"D:\cots\cppunit-1.9.8\lib" + +!ENDIF + +# Begin Target + +# Name "unit_tests - Win32 Release" +# Name "unit_tests - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\test\FTBBox-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTCharmap-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTContour-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTFace-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTFont-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTGlyphContainer-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTLibrary-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTList-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTMesh-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTPoint-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTSize-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTTesselation-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTVector-Test.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\test\FTVectoriser-Test.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\test\HPGCalc_afm.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\test\HPGCalc_pfb.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\test\TestMain.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\test\Fontdefs.h +# End Source File +# End Group +# End Target +# End Project diff --git a/extern/bullet2/CMakeLists.txt b/extern/bullet2/CMakeLists.txt new file mode 100644 index 00000000000..19dc6e2ba77 --- /dev/null +++ b/extern/bullet2/CMakeLists.txt @@ -0,0 +1,46 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurai, Erwin Coumans +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . src) + +FILE(GLOB SRC + src/LinearMath/*.cpp + src/BulletCollision/BroadphaseCollision/*.cpp + src/BulletCollision/CollisionShapes/*.cpp + src/BulletCollision/NarrowPhaseCollision/*.cpp + src/BulletCollision//CollisionDispatch/*.cpp + src/BulletDynamics/ConstraintSolver/*.cpp + src/BulletDynamics/Vehicle/*.cpp + src/BulletDynamics/Dynamics/*.cpp +) + +ADD_DEFINITIONS(-D_LIB) + +BLENDERLIB(extern_bullet "${SRC}" "${INC}") +#, libtype=['game2', 'player'], priority=[20, 170], compileflags=cflags ) diff --git a/extern/bullet2/Makefile b/extern/bullet2/Makefile new file mode 100644 index 00000000000..be242c290ff --- /dev/null +++ b/extern/bullet2/Makefile @@ -0,0 +1,64 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2002 by Hans Lambermont +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +LIBNAME = bullet2 +include nan_definitions.mk +SOURCEDIR = extern/$(LIBNAME) +DIR = $(OCGDIR)/extern/$(LIBNAME) +DIRS = src +DISTDIR = src + +BULLETDIRS = \ +LinearMath \ +BulletCollision/BroadphaseCollision \ +BulletCollision/CollisionShapes \ +BulletCollision/NarrowPhaseCollision \ +BulletCollision//CollisionDispatch \ +BulletDynamics/ConstraintSolver \ +BulletDynamics/Vehicle \ +BulletDynamics/Dynamics + +include nan_subdirs.mk + +CP = $(NANBLENDERHOME)/intern/tools/cpifdiff.sh + +install: all debug + @[ -d $(NAN_BULLET2) ] || mkdir -p $(NAN_BULLET2) + @[ -d $(NAN_BULLET2)/include ] || mkdir -p $(NAN_BULLET2)/include + @for i in $(BULLETDIRS); do \ + [ -d $(NAN_BULLET2)/include/$$i ] || mkdir -p $(NAN_BULLET2)/include/$$i; \ + $(CP) $(DISTDIR)/$$i/*.h $(NAN_BULLET2)/include/$$i; \ + done + @[ -d $(NAN_BULLET2)/lib ] || mkdir -p $(NAN_BULLET2)/lib + @$(CP) $(DISTDIR)/*.h $(NAN_BULLET2)/include + @$(CP) $(OCGDIR)/extern/bullet2/libbullet2.a $(NAN_BULLET2)/lib +ifeq ($(OS),darwin) + ranlib $(NAN_BULLET2)/lib/libbullet2.a +endif diff --git a/extern/bullet2/make/msvc_7_0/Bullet_vc7.vcproj b/extern/bullet2/make/msvc_7_0/Bullet_vc7.vcproj new file mode 100644 index 00000000000..87a1e4546d1 --- /dev/null +++ b/extern/bullet2/make/msvc_7_0/Bullet_vc7.vcproj @@ -0,0 +1,921 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/bullet2/readme.txt b/extern/bullet2/readme.txt new file mode 100644 index 00000000000..4d1a4c11706 --- /dev/null +++ b/extern/bullet2/readme.txt @@ -0,0 +1,12 @@ + +*** These files in extern/bullet2 are NOT part of the Blender build yet *** + +This is the new refactored version of Bullet physics library version 2.x + +Soon this will replace the old Bullet version in extern/bullet. +First the integration in Blender Game Engine needs to be updated. +Once that is done all build systems can be updated to use/build extern/bullet2 files. + +Questions? mail blender at erwincoumans.com, or check the bf-blender mailing list. +Thanks, +Erwin diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp new file mode 100644 index 00000000000..be4a11506df --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp @@ -0,0 +1,660 @@ + +//Bullet Continuous Collision Detection and Physics Library +//Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + + +// +// btAxisSweep3 +// +// Copyright (c) 2006 Simon Hobbs +// +// This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +#include "btAxisSweep3.h" + +#include + +#ifdef DEBUG_BROADPHASE +#include +void btAxisSweep3::debugPrintAxis(int axis, bool checkCardinality) +{ + int numEdges = m_pHandles[0].m_maxEdges[axis]; + printf("SAP Axis %d, numEdges=%d\n",axis,numEdges); + + int i; + for (i=0;im_handle); + int handleIndex = pEdge->IsMax()? pHandlePrev->m_maxEdges[axis] : pHandlePrev->m_minEdges[axis]; + char beginOrEnd; + beginOrEnd=pEdge->IsMax()?'E':'B'; + printf(" [%c,h=%d,p=%x,i=%d]\n",beginOrEnd,pEdge->m_handle,pEdge->m_pos,handleIndex); + } + + if (checkCardinality) + assert(numEdges == m_numHandles*2+1); +} +#endif //DEBUG_BROADPHASE + + +btBroadphaseProxy* btAxisSweep3::createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask) +{ + (void)shapeType; + BP_FP_INT_TYPE handleId = addHandle(min,max, userPtr,collisionFilterGroup,collisionFilterMask); + + Handle* handle = getHandle(handleId); + + return handle; +} + +void btAxisSweep3::destroyProxy(btBroadphaseProxy* proxy) +{ + Handle* handle = static_cast(proxy); + removeHandle(handle->m_handleId); +} + +void btAxisSweep3::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax) +{ + Handle* handle = static_cast(proxy); + updateHandle(handle->m_handleId,aabbMin,aabbMax); + +} + + + + + + +btAxisSweep3::btAxisSweep3(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, int maxHandles) +:btOverlappingPairCache() +{ + m_invalidPair = 0; + //assert(bounds.HasVolume()); + + // 1 handle is reserved as sentinel + btAssert(maxHandles > 1 && maxHandles < BP_MAX_HANDLES); + + // init bounds + m_worldAabbMin = worldAabbMin; + m_worldAabbMax = worldAabbMax; + + btVector3 aabbSize = m_worldAabbMax - m_worldAabbMin; + + BP_FP_INT_TYPE maxInt = BP_HANDLE_SENTINEL; + + m_quantize = btVector3(btScalar(maxInt),btScalar(maxInt),btScalar(maxInt)) / aabbSize; + + // allocate handles buffer and put all handles on free list + m_pHandles = new Handle[maxHandles]; + m_maxHandles = maxHandles; + m_numHandles = 0; + + // handle 0 is reserved as the null index, and is also used as the sentinel + m_firstFreeHandle = 1; + { + for (BP_FP_INT_TYPE i = m_firstFreeHandle; i < maxHandles; i++) + m_pHandles[i].SetNextFree(i + 1); + m_pHandles[maxHandles - 1].SetNextFree(0); + } + + { + // allocate edge buffers + for (int i = 0; i < 3; i++) + m_pEdges[i] = new Edge[maxHandles * 2]; + } + //removed overlap management + + // make boundary sentinels + + m_pHandles[0].m_clientObject = 0; + + for (int axis = 0; axis < 3; axis++) + { + m_pHandles[0].m_minEdges[axis] = 0; + m_pHandles[0].m_maxEdges[axis] = 1; + + m_pEdges[axis][0].m_pos = 0; + m_pEdges[axis][0].m_handle = 0; + m_pEdges[axis][1].m_pos = BP_HANDLE_SENTINEL; + m_pEdges[axis][1].m_handle = 0; +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis); +#endif //DEBUG_BROADPHASE + + } + +} + +btAxisSweep3::~btAxisSweep3() +{ + + for (int i = 2; i >= 0; i--) + delete[] m_pEdges[i]; + delete[] m_pHandles; +} + +void btAxisSweep3::quantize(BP_FP_INT_TYPE* out, const btPoint3& point, int isMax) const +{ + btPoint3 clampedPoint(point); + + + + clampedPoint.setMax(m_worldAabbMin); + clampedPoint.setMin(m_worldAabbMax); + + btVector3 v = (clampedPoint - m_worldAabbMin) * m_quantize; + out[0] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getX() & BP_HANDLE_MASK) | isMax); + out[1] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getY() & BP_HANDLE_MASK) | isMax); + out[2] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getZ() & BP_HANDLE_MASK) | isMax); + +} + + + +BP_FP_INT_TYPE btAxisSweep3::allocHandle() +{ + assert(m_firstFreeHandle); + + BP_FP_INT_TYPE handle = m_firstFreeHandle; + m_firstFreeHandle = getHandle(handle)->GetNextFree(); + m_numHandles++; + + return handle; +} + +void btAxisSweep3::freeHandle(BP_FP_INT_TYPE handle) +{ + assert(handle > 0 && handle < m_maxHandles); + + getHandle(handle)->SetNextFree(m_firstFreeHandle); + m_firstFreeHandle = handle; + + m_numHandles--; +} + + + +BP_FP_INT_TYPE btAxisSweep3::addHandle(const btPoint3& aabbMin,const btPoint3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask) +{ + // quantize the bounds + BP_FP_INT_TYPE min[3], max[3]; + quantize(min, aabbMin, 0); + quantize(max, aabbMax, 1); + + // allocate a handle + BP_FP_INT_TYPE handle = allocHandle(); + assert(handle!= 0xcdcd); + + Handle* pHandle = getHandle(handle); + + pHandle->m_handleId = handle; + //pHandle->m_pOverlaps = 0; + pHandle->m_clientObject = pOwner; + pHandle->m_collisionFilterGroup = collisionFilterGroup; + pHandle->m_collisionFilterMask = collisionFilterMask; + + // compute current limit of edge arrays + BP_FP_INT_TYPE limit = m_numHandles * 2; + + + // insert new edges just inside the max boundary edge + for (BP_FP_INT_TYPE axis = 0; axis < 3; axis++) + { + + m_pHandles[0].m_maxEdges[axis] += 2; + + m_pEdges[axis][limit + 1] = m_pEdges[axis][limit - 1]; + + m_pEdges[axis][limit - 1].m_pos = min[axis]; + m_pEdges[axis][limit - 1].m_handle = handle; + + m_pEdges[axis][limit].m_pos = max[axis]; + m_pEdges[axis][limit].m_handle = handle; + + pHandle->m_minEdges[axis] = limit - 1; + pHandle->m_maxEdges[axis] = limit; + } + + // now sort the new edges to their correct position + sortMinDown(0, pHandle->m_minEdges[0], false); + sortMaxDown(0, pHandle->m_maxEdges[0], false); + sortMinDown(1, pHandle->m_minEdges[1], false); + sortMaxDown(1, pHandle->m_maxEdges[1], false); + sortMinDown(2, pHandle->m_minEdges[2], true); + sortMaxDown(2, pHandle->m_maxEdges[2], true); + + + return handle; +} + + +void btAxisSweep3::removeHandle(BP_FP_INT_TYPE handle) +{ + + Handle* pHandle = getHandle(handle); + + //explicitly remove the pairs containing the proxy + //we could do it also in the sortMinUp (passing true) + //todo: compare performance + removeOverlappingPairsContainingProxy(pHandle); + + + // compute current limit of edge arrays + int limit = m_numHandles * 2; + + int axis; + + for (axis = 0;axis<3;axis++) + { + m_pHandles[0].m_maxEdges[axis] -= 2; + } + + // remove the edges by sorting them up to the end of the list + for ( axis = 0; axis < 3; axis++) + { + Edge* pEdges = m_pEdges[axis]; + BP_FP_INT_TYPE max = pHandle->m_maxEdges[axis]; + pEdges[max].m_pos = BP_HANDLE_SENTINEL; + + sortMaxUp(axis,max,false); + + + BP_FP_INT_TYPE i = pHandle->m_minEdges[axis]; + pEdges[i].m_pos = BP_HANDLE_SENTINEL; + + + sortMinUp(axis,i,false); + + pEdges[limit-1].m_handle = 0; + pEdges[limit-1].m_pos = BP_HANDLE_SENTINEL; + +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis,false); +#endif //DEBUG_BROADPHASE + + + } + + + // free the handle + freeHandle(handle); + + +} + +extern int gOverlappingPairs; + + +void btAxisSweep3::refreshOverlappingPairs() +{ + +} +void btAxisSweep3::processAllOverlappingPairs(btOverlapCallback* callback) +{ + + //perform a sort, to find duplicates and to sort 'invalid' pairs to the end + m_overlappingPairArray.heapSort(btBroadphasePairSortPredicate()); + + //remove the 'invalid' ones +#ifdef USE_POPBACK_REMOVAL + while (m_invalidPair>0) + { + m_invalidPair--; + m_overlappingPairArray.pop_back(); + } +#else + m_overlappingPairArray.resize(m_overlappingPairArray.size() - m_invalidPair); + m_invalidPair = 0; +#endif + + + int i; + + btBroadphasePair previousPair; + previousPair.m_pProxy0 = 0; + previousPair.m_pProxy1 = 0; + previousPair.m_algorithm = 0; + + + for (i=0;iprocessOverlap(pair); + } else + { + needsRemoval = true; + } + } else + { + //remove duplicate + needsRemoval = true; + //should have no algorithm + btAssert(!pair.m_algorithm); + } + + if (needsRemoval) + { + cleanOverlappingPair(pair); + + // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); + // m_overlappingPairArray.pop_back(); + pair.m_pProxy0 = 0; + pair.m_pProxy1 = 0; + m_invalidPair++; + gOverlappingPairs--; + } + + } +} + + +bool btAxisSweep3::testOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) +{ + const Handle* pHandleA = static_cast(proxy0); + const Handle* pHandleB = static_cast(proxy1); + + //optimization 1: check the array index (memory address), instead of the m_pos + + for (int axis = 0; axis < 3; axis++) + { + if (pHandleA->m_maxEdges[axis] < pHandleB->m_minEdges[axis] || + pHandleB->m_maxEdges[axis] < pHandleA->m_minEdges[axis]) + { + return false; + } + } + return true; +} + +bool btAxisSweep3::testOverlap(int ignoreAxis,const Handle* pHandleA, const Handle* pHandleB) +{ + //optimization 1: check the array index (memory address), instead of the m_pos + + for (int axis = 0; axis < 3; axis++) + { + if (axis != ignoreAxis) + { + if (pHandleA->m_maxEdges[axis] < pHandleB->m_minEdges[axis] || + pHandleB->m_maxEdges[axis] < pHandleA->m_minEdges[axis]) + { + return false; + } + } + } + + //optimization 2: only 2 axis need to be tested (conflicts with 'delayed removal' optimization) + + /*for (int axis = 0; axis < 3; axis++) + { + if (m_pEdges[axis][pHandleA->m_maxEdges[axis]].m_pos < m_pEdges[axis][pHandleB->m_minEdges[axis]].m_pos || + m_pEdges[axis][pHandleB->m_maxEdges[axis]].m_pos < m_pEdges[axis][pHandleA->m_minEdges[axis]].m_pos) + { + return false; + } + } + */ + + return true; +} + +void btAxisSweep3::updateHandle(BP_FP_INT_TYPE handle, const btPoint3& aabbMin,const btPoint3& aabbMax) +{ +// assert(bounds.IsFinite()); + //assert(bounds.HasVolume()); + + Handle* pHandle = getHandle(handle); + + // quantize the new bounds + BP_FP_INT_TYPE min[3], max[3]; + quantize(min, aabbMin, 0); + quantize(max, aabbMax, 1); + + // update changed edges + for (int axis = 0; axis < 3; axis++) + { + BP_FP_INT_TYPE emin = pHandle->m_minEdges[axis]; + BP_FP_INT_TYPE emax = pHandle->m_maxEdges[axis]; + + int dmin = (int)min[axis] - (int)m_pEdges[axis][emin].m_pos; + int dmax = (int)max[axis] - (int)m_pEdges[axis][emax].m_pos; + + m_pEdges[axis][emin].m_pos = min[axis]; + m_pEdges[axis][emax].m_pos = max[axis]; + + // expand (only adds overlaps) + if (dmin < 0) + sortMinDown(axis, emin); + + if (dmax > 0) + sortMaxUp(axis, emax); + + // shrink (only removes overlaps) + if (dmin > 0) + sortMinUp(axis, emin); + + if (dmax < 0) + sortMaxDown(axis, emax); + +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis); +#endif //DEBUG_BROADPHASE + } + + +} + + + + +// sorting a min edge downwards can only ever *add* overlaps +void btAxisSweep3::sortMinDown(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps) +{ + + Edge* pEdge = m_pEdges[axis] + edge; + Edge* pPrev = pEdge - 1; + Handle* pHandleEdge = getHandle(pEdge->m_handle); + + while (pEdge->m_pos < pPrev->m_pos) + { + Handle* pHandlePrev = getHandle(pPrev->m_handle); + + if (pPrev->IsMax()) + { + // if previous edge is a maximum check the bounds and add an overlap if necessary + if (updateOverlaps && testOverlap(axis,pHandleEdge, pHandlePrev)) + { + addOverlappingPair(pHandleEdge,pHandlePrev); + + //AddOverlap(pEdge->m_handle, pPrev->m_handle); + + } + + // update edge reference in other handle + pHandlePrev->m_maxEdges[axis]++; + } + else + pHandlePrev->m_minEdges[axis]++; + + pHandleEdge->m_minEdges[axis]--; + + // swap the edges + Edge swap = *pEdge; + *pEdge = *pPrev; + *pPrev = swap; + + // decrement + pEdge--; + pPrev--; + } + +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis); +#endif //DEBUG_BROADPHASE + +} + +// sorting a min edge upwards can only ever *remove* overlaps +void btAxisSweep3::sortMinUp(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps) +{ + Edge* pEdge = m_pEdges[axis] + edge; + Edge* pNext = pEdge + 1; + Handle* pHandleEdge = getHandle(pEdge->m_handle); + + while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos)) + { + Handle* pHandleNext = getHandle(pNext->m_handle); + + if (pNext->IsMax()) + { + // if next edge is maximum remove any overlap between the two handles + if (updateOverlaps) + { + /* + Handle* handle0 = getHandle(pEdge->m_handle); + Handle* handle1 = getHandle(pNext->m_handle); + btBroadphasePair tmpPair(*handle0,*handle1); + removeOverlappingPair(tmpPair); + */ + + } + + // update edge reference in other handle + pHandleNext->m_maxEdges[axis]--; + } + else + pHandleNext->m_minEdges[axis]--; + + pHandleEdge->m_minEdges[axis]++; + + // swap the edges + Edge swap = *pEdge; + *pEdge = *pNext; + *pNext = swap; + + // increment + pEdge++; + pNext++; + } + + +} + +// sorting a max edge downwards can only ever *remove* overlaps +void btAxisSweep3::sortMaxDown(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps) +{ + + Edge* pEdge = m_pEdges[axis] + edge; + Edge* pPrev = pEdge - 1; + Handle* pHandleEdge = getHandle(pEdge->m_handle); + + while (pEdge->m_pos < pPrev->m_pos) + { + Handle* pHandlePrev = getHandle(pPrev->m_handle); + + if (!pPrev->IsMax()) + { + // if previous edge was a minimum remove any overlap between the two handles + if (updateOverlaps) + { + //this is done during the overlappingpairarray iteration/narrowphase collision + /* + Handle* handle0 = getHandle(pEdge->m_handle); + Handle* handle1 = getHandle(pPrev->m_handle); + btBroadphasePair* pair = findPair(handle0,handle1); + //assert(pair); + + if (pair) + { + removeOverlappingPair(*pair); + } + */ + + } + + // update edge reference in other handle + pHandlePrev->m_minEdges[axis]++;; + } + else + pHandlePrev->m_maxEdges[axis]++; + + pHandleEdge->m_maxEdges[axis]--; + + // swap the edges + Edge swap = *pEdge; + *pEdge = *pPrev; + *pPrev = swap; + + // decrement + pEdge--; + pPrev--; + } + + +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis); +#endif //DEBUG_BROADPHASE + +} + +// sorting a max edge upwards can only ever *add* overlaps +void btAxisSweep3::sortMaxUp(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps) +{ + Edge* pEdge = m_pEdges[axis] + edge; + Edge* pNext = pEdge + 1; + Handle* pHandleEdge = getHandle(pEdge->m_handle); + + while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos)) + { + Handle* pHandleNext = getHandle(pNext->m_handle); + + if (!pNext->IsMax()) + { + // if next edge is a minimum check the bounds and add an overlap if necessary + if (updateOverlaps && testOverlap(axis, pHandleEdge, pHandleNext)) + { + Handle* handle0 = getHandle(pEdge->m_handle); + Handle* handle1 = getHandle(pNext->m_handle); + addOverlappingPair(handle0,handle1); + } + + // update edge reference in other handle + pHandleNext->m_minEdges[axis]--; + } + else + pHandleNext->m_maxEdges[axis]--; + + pHandleEdge->m_maxEdges[axis]++; + + // swap the edges + Edge swap = *pEdge; + *pEdge = *pNext; + *pNext = swap; + + // increment + pEdge++; + pNext++; + } + +} diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h new file mode 100644 index 00000000000..57bbb368672 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h @@ -0,0 +1,138 @@ +//Bullet Continuous Collision Detection and Physics Library +//Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +// +// btAxisSweep3.h +// +// Copyright (c) 2006 Simon Hobbs +// +// This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef AXIS_SWEEP_3_H +#define AXIS_SWEEP_3_H + +#include "../../LinearMath/btPoint3.h" +#include "../../LinearMath/btVector3.h" +#include "btOverlappingPairCache.h" +#include "btBroadphaseProxy.h" + + +//Enable BP_USE_FIXEDPOINT_INT_32 if you need more then 32767 objects +//#define BP_USE_FIXEDPOINT_INT_32 1 + +#ifdef BP_USE_FIXEDPOINT_INT_32 + #define BP_FP_INT_TYPE unsigned int + #define BP_MAX_HANDLES 1500000 //arbitrary maximum number of handles + #define BP_HANDLE_SENTINEL 0x7fffffff + #define BP_HANDLE_MASK 0xfffffffe +#else + #define BP_FP_INT_TYPE unsigned short int + #define BP_MAX_HANDLES 32767 + #define BP_HANDLE_SENTINEL 0xffff + #define BP_HANDLE_MASK 0xfffe +#endif //BP_USE_FIXEDPOINT_INT_32 + +//#define DEBUG_BROADPHASE 1 + +/// btAxisSweep3 is an efficient implementation of the 3d axis sweep and prune broadphase. +/// It uses arrays rather then lists for storage of the 3 axis. Also it operates using integer coordinates instead of floats. +/// The testOverlap check is optimized to check the array index, rather then the actual AABB coordinates/pos +class btAxisSweep3 : public btOverlappingPairCache +{ + +public: + + + class Edge + { + public: + BP_FP_INT_TYPE m_pos; // low bit is min/max + BP_FP_INT_TYPE m_handle; + + BP_FP_INT_TYPE IsMax() const {return m_pos & 1;} + }; + +public: + class Handle : public btBroadphaseProxy + { + public: + + // indexes into the edge arrays + BP_FP_INT_TYPE m_minEdges[3], m_maxEdges[3]; // 6 * 2 = 12 + BP_FP_INT_TYPE m_handleId; + BP_FP_INT_TYPE m_pad; + + //void* m_pOwner; this is now in btBroadphaseProxy.m_clientObject + + inline void SetNextFree(BP_FP_INT_TYPE next) {m_minEdges[0] = next;} + inline BP_FP_INT_TYPE GetNextFree() const {return m_minEdges[0];} + }; // 24 bytes + 24 for Edge structures = 44 bytes total per entry + + +private: + btPoint3 m_worldAabbMin; // overall system bounds + btPoint3 m_worldAabbMax; // overall system bounds + + btVector3 m_quantize; // scaling factor for quantization + + BP_FP_INT_TYPE m_numHandles; // number of active handles + int m_maxHandles; // max number of handles + Handle* m_pHandles; // handles pool + BP_FP_INT_TYPE m_firstFreeHandle; // free handles list + + Edge* m_pEdges[3]; // edge arrays for the 3 axes (each array has m_maxHandles * 2 + 2 sentinel entries) + + int m_invalidPair; + + // allocation/deallocation + BP_FP_INT_TYPE allocHandle(); + void freeHandle(BP_FP_INT_TYPE handle); + + + bool testOverlap(int ignoreAxis,const Handle* pHandleA, const Handle* pHandleB); + +#ifdef DEBUG_BROADPHASE + void debugPrintAxis(int axis,bool checkCardinality=true); +#endif //DEBUG_BROADPHASE + + //Overlap* AddOverlap(BP_FP_INT_TYPE handleA, BP_FP_INT_TYPE handleB); + //void RemoveOverlap(BP_FP_INT_TYPE handleA, BP_FP_INT_TYPE handleB); + + void quantize(BP_FP_INT_TYPE* out, const btPoint3& point, int isMax) const; + + void sortMinDown(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps = true); + void sortMinUp(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps = true); + void sortMaxDown(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps = true); + void sortMaxUp(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps = true); + +public: + btAxisSweep3(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, int maxHandles = 16384); + virtual ~btAxisSweep3(); + + virtual void refreshOverlappingPairs(); + + BP_FP_INT_TYPE addHandle(const btPoint3& aabbMin,const btPoint3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask); + void removeHandle(BP_FP_INT_TYPE handle); + void updateHandle(BP_FP_INT_TYPE handle, const btPoint3& aabbMin,const btPoint3& aabbMax); + inline Handle* getHandle(BP_FP_INT_TYPE index) const {return m_pHandles + index;} + + void processAllOverlappingPairs(btOverlapCallback* callback); + + //Broadphase Interface + virtual btBroadphaseProxy* createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask); + virtual void destroyProxy(btBroadphaseProxy* proxy); + virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax); + bool testOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); + +}; + +#endif + diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h new file mode 100644 index 00000000000..b6ace03c07a --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h @@ -0,0 +1,40 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BROADPHASE_INTERFACE_H +#define BROADPHASE_INTERFACE_H + + + +struct btDispatcherInfo; +class btDispatcher; +struct btBroadphaseProxy; +#include "../../LinearMath/btVector3.h" + +///BroadphaseInterface for aabb-overlapping object pairs +class btBroadphaseInterface +{ +public: + virtual ~btBroadphaseInterface() {} + + virtual btBroadphaseProxy* createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask) =0; + virtual void destroyProxy(btBroadphaseProxy* proxy)=0; + virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax)=0; + virtual void cleanProxyFromPairs(btBroadphaseProxy* proxy)=0; + + +}; + +#endif //BROADPHASE_INTERFACE_H diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp new file mode 100644 index 00000000000..f4d7341f8dd --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp @@ -0,0 +1,17 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btBroadphaseProxy.h" + diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h new file mode 100644 index 00000000000..40d9748ffa9 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h @@ -0,0 +1,204 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BROADPHASE_PROXY_H +#define BROADPHASE_PROXY_H + +#include "../../LinearMath/btScalar.h" //for SIMD_FORCE_INLINE + + +/// btDispatcher uses these types +/// IMPORTANT NOTE:The types are ordered polyhedral, implicit convex and concave +/// to facilitate type checking +enum BroadphaseNativeTypes +{ +// polyhedral convex shapes + BOX_SHAPE_PROXYTYPE, + TRIANGLE_SHAPE_PROXYTYPE, + TETRAHEDRAL_SHAPE_PROXYTYPE, + CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE, + CONVEX_HULL_SHAPE_PROXYTYPE, +//implicit convex shapes +IMPLICIT_CONVEX_SHAPES_START_HERE, + SPHERE_SHAPE_PROXYTYPE, + MULTI_SPHERE_SHAPE_PROXYTYPE, + CAPSULE_SHAPE_PROXYTYPE, + CONE_SHAPE_PROXYTYPE, + CONVEX_SHAPE_PROXYTYPE, + CYLINDER_SHAPE_PROXYTYPE, + MINKOWSKI_SUM_SHAPE_PROXYTYPE, + MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE, +//concave shapes +CONCAVE_SHAPES_START_HERE, + //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! + TRIANGLE_MESH_SHAPE_PROXYTYPE, + ///used for demo integration FAST/Swift collision library and Bullet + FAST_CONCAVE_MESH_PROXYTYPE, + //terrain + TERRAIN_SHAPE_PROXYTYPE, +///Used for GIMPACT Trimesh integration + GIMPACT_SHAPE_PROXYTYPE, + + EMPTY_SHAPE_PROXYTYPE, + STATIC_PLANE_PROXYTYPE, +CONCAVE_SHAPES_END_HERE, + + COMPOUND_SHAPE_PROXYTYPE, + + MAX_BROADPHASE_COLLISION_TYPES +}; + + +///btBroadphaseProxy +struct btBroadphaseProxy +{ + + ///optional filtering to cull potential collisions + enum CollisionFilterGroups + { + DefaultFilter = 1, + StaticFilter = 2, + KinematicFilter = 4, + DebrisFilter = 8, + SensorTrigger = 16, + AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger + }; + + //Usually the client btCollisionObject or Rigidbody class + void* m_clientObject; + short int m_collisionFilterGroup; + short int m_collisionFilterMask; + + //used for memory pools + btBroadphaseProxy() :m_clientObject(0){} + + btBroadphaseProxy(void* userPtr,short int collisionFilterGroup, short int collisionFilterMask) + :m_clientObject(userPtr), + m_collisionFilterGroup(collisionFilterGroup), + m_collisionFilterMask(collisionFilterMask) + { + } + + static inline bool isPolyhedral(int proxyType) + { + return (proxyType < IMPLICIT_CONVEX_SHAPES_START_HERE); + } + + static inline bool isConvex(int proxyType) + { + return (proxyType < CONCAVE_SHAPES_START_HERE); + } + + static inline bool isConcave(int proxyType) + { + return ((proxyType > CONCAVE_SHAPES_START_HERE) && + (proxyType < CONCAVE_SHAPES_END_HERE)); + } + static inline bool isCompound(int proxyType) + { + return (proxyType == COMPOUND_SHAPE_PROXYTYPE); + } + static inline bool isInfinite(int proxyType) + { + return (proxyType == STATIC_PLANE_PROXYTYPE); + } + +} +; + +class btCollisionAlgorithm; + +struct btBroadphaseProxy; + + + +/// contains a pair of aabb-overlapping objects +struct btBroadphasePair +{ + btBroadphasePair () + : + m_pProxy0(0), + m_pProxy1(0), + m_algorithm(0), + m_userInfo(0) + { + } + + btBroadphasePair(const btBroadphasePair& other) + : m_pProxy0(other.m_pProxy0), + m_pProxy1(other.m_pProxy1), + m_algorithm(other.m_algorithm), + m_userInfo(other.m_userInfo) + { + } + btBroadphasePair(btBroadphaseProxy& proxy0,btBroadphaseProxy& proxy1) + { + + //keep them sorted, so the std::set operations work + if (&proxy0 < &proxy1) + { + m_pProxy0 = &proxy0; + m_pProxy1 = &proxy1; + } + else + { + m_pProxy0 = &proxy1; + m_pProxy1 = &proxy0; + } + + m_algorithm = 0; + m_userInfo = 0; + + } + + btBroadphaseProxy* m_pProxy0; + btBroadphaseProxy* m_pProxy1; + + mutable btCollisionAlgorithm* m_algorithm; + mutable void* m_userInfo; + +}; + +/* +//comparison for set operation, see Solid DT_Encounter +SIMD_FORCE_INLINE bool operator<(const btBroadphasePair& a, const btBroadphasePair& b) +{ + return a.m_pProxy0 < b.m_pProxy0 || + (a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 < b.m_pProxy1); +} +*/ + + +class btBroadphasePairSortPredicate +{ + public: + + bool operator() ( const btBroadphasePair& a, const btBroadphasePair& b ) + { + return a.m_pProxy0 > b.m_pProxy0 || + (a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 > b.m_pProxy1) || + (a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 == b.m_pProxy1 && a.m_algorithm > b.m_algorithm); + } +}; + + +SIMD_FORCE_INLINE bool operator==(const btBroadphasePair& a, const btBroadphasePair& b) +{ + return (a.m_pProxy0 == b.m_pProxy0) && (a.m_pProxy1 == b.m_pProxy1); +} + + +#endif //BROADPHASE_PROXY_H + diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp new file mode 100644 index 00000000000..2ad0c86d8a2 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp @@ -0,0 +1,23 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btCollisionAlgorithm.h" +#include "btDispatcher.h" + +btCollisionAlgorithm::btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) +{ + m_dispatcher = ci.m_dispatcher; +} + diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h new file mode 100644 index 00000000000..55cec386a7b --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h @@ -0,0 +1,77 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef COLLISION_ALGORITHM_H +#define COLLISION_ALGORITHM_H + +#include "../../LinearMath/btScalar.h" + +struct btBroadphaseProxy; +class btDispatcher; +class btManifoldResult; +class btCollisionObject; +struct btDispatcherInfo; +class btPersistentManifold; + + +struct btCollisionAlgorithmConstructionInfo +{ + btCollisionAlgorithmConstructionInfo() + :m_dispatcher(0), + m_manifold(0) + { + } + btCollisionAlgorithmConstructionInfo(btDispatcher* dispatcher,int temp) + :m_dispatcher(dispatcher) + { + (void)temp; + } + + btDispatcher* m_dispatcher; + btPersistentManifold* m_manifold; + + int getDispatcherId(); + +}; + + +///btCollisionAlgorithm is an collision interface that is compatible with the Broadphase and btDispatcher. +///It is persistent over frames +class btCollisionAlgorithm +{ + +protected: + + btDispatcher* m_dispatcher; + +protected: + int getDispatcherId(); + +public: + + btCollisionAlgorithm() {}; + + btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci); + + virtual ~btCollisionAlgorithm() {}; + + virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; + + virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; + +}; + + +#endif //COLLISION_ALGORITHM_H diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.cpp new file mode 100644 index 00000000000..20768225b3a --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.cpp @@ -0,0 +1,22 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btDispatcher.h" + +btDispatcher::~btDispatcher() +{ + +} + diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.h new file mode 100644 index 00000000000..3d958cc8fef --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.h @@ -0,0 +1,93 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef _DISPATCHER_H +#define _DISPATCHER_H + +#include "../../LinearMath/btScalar.h" + +class btCollisionAlgorithm; +struct btBroadphaseProxy; +class btRigidBody; +class btCollisionObject; +class btOverlappingPairCache; + + +class btPersistentManifold; +class btStackAlloc; + +struct btDispatcherInfo +{ + enum DispatchFunc + { + DISPATCH_DISCRETE = 1, + DISPATCH_CONTINUOUS + }; + btDispatcherInfo() + :m_timeStep(btScalar(0.)), + m_stepCount(0), + m_dispatchFunc(DISPATCH_DISCRETE), + m_timeOfImpact(btScalar(1.)), + m_useContinuous(false), + m_debugDraw(0), + m_enableSatConvex(false), + m_enableSPU(false), + m_stackAllocator(0) + { + + } + btScalar m_timeStep; + int m_stepCount; + int m_dispatchFunc; + btScalar m_timeOfImpact; + bool m_useContinuous; + class btIDebugDraw* m_debugDraw; + bool m_enableSatConvex; + bool m_enableSPU; + btStackAlloc* m_stackAllocator; + +}; + +/// btDispatcher can be used in combination with broadphase to dispatch overlapping pairs. +/// For example for pairwise collision detection or user callbacks (game logic). +class btDispatcher +{ + + +public: + virtual ~btDispatcher() ; + + virtual btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold=0) = 0; + + virtual btPersistentManifold* getNewManifold(void* body0,void* body1)=0; + + virtual void releaseManifold(btPersistentManifold* manifold)=0; + + virtual void clearManifold(btPersistentManifold* manifold)=0; + + virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1) = 0; + + virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1)=0; + + virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo)=0; + + virtual int getNumManifolds() const = 0; + + virtual btPersistentManifold* getManifoldByIndexInternal(int index) = 0; + +}; + + +#endif //_DISPATCHER_H diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp new file mode 100644 index 00000000000..60f0a41a9d7 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp @@ -0,0 +1,196 @@ + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#include "btOverlappingPairCache.h" + +#include "btDispatcher.h" +#include "btCollisionAlgorithm.h" + +int gOverlappingPairs = 0; + +btOverlappingPairCache::btOverlappingPairCache(): +m_blockedForChanges(false), +m_overlapFilterCallback(0) +//m_NumOverlapBroadphasePair(0) +{ +} + + +btOverlappingPairCache::~btOverlappingPairCache() +{ + //todo/test: show we erase/delete data, or is it automatic +} + + +void btOverlappingPairCache::removeOverlappingPair(btBroadphasePair& findPair) +{ + + int findIndex = m_overlappingPairArray.findLinearSearch(findPair); + if (findIndex < m_overlappingPairArray.size()) + { + gOverlappingPairs--; + btBroadphasePair& pair = m_overlappingPairArray[findIndex]; + cleanOverlappingPair(pair); + + m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.size()-1); + m_overlappingPairArray.pop_back(); + } +} + + +void btOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair) +{ + if (pair.m_algorithm) + { + { + delete pair.m_algorithm;; + pair.m_algorithm=0; + } + } +} + + + + + +void btOverlappingPairCache::addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) +{ + //don't add overlap with own + assert(proxy0 != proxy1); + + if (!needsBroadphaseCollision(proxy0,proxy1)) + return; + + + btBroadphasePair pair(*proxy0,*proxy1); + + m_overlappingPairArray.push_back(pair); + gOverlappingPairs++; + +} + +///this findPair becomes really slow. Either sort the list to speedup the query, or +///use a different solution. It is mainly used for Removing overlapping pairs. Removal could be delayed. +///we could keep a linked list in each proxy, and store pair in one of the proxies (with lowest memory address) +///Also we can use a 2D bitmap, which can be useful for a future GPU implementation + btBroadphasePair* btOverlappingPairCache::findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) +{ + if (!needsBroadphaseCollision(proxy0,proxy1)) + return 0; + + btBroadphasePair tmpPair(*proxy0,*proxy1); + int findIndex = m_overlappingPairArray.findLinearSearch(tmpPair); + + if (findIndex < m_overlappingPairArray.size()) + { + //assert(it != m_overlappingPairSet.end()); + btBroadphasePair* pair = &m_overlappingPairArray[findIndex]; + return pair; + } + return 0; +} + + + + + +void btOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy) +{ + + class CleanPairCallback : public btOverlapCallback + { + btBroadphaseProxy* m_cleanProxy; + btOverlappingPairCache* m_pairCache; + + public: + CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache) + :m_cleanProxy(cleanProxy), + m_pairCache(pairCache) + { + } + virtual bool processOverlap(btBroadphasePair& pair) + { + if ((pair.m_pProxy0 == m_cleanProxy) || + (pair.m_pProxy1 == m_cleanProxy)) + { + m_pairCache->cleanOverlappingPair(pair); + } + return false; + } + + }; + + CleanPairCallback cleanPairs(proxy,this); + + processAllOverlappingPairs(&cleanPairs); + +} + + + +void btOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy) +{ + + class RemovePairCallback : public btOverlapCallback + { + btBroadphaseProxy* m_obsoleteProxy; + + public: + RemovePairCallback(btBroadphaseProxy* obsoleteProxy) + :m_obsoleteProxy(obsoleteProxy) + { + } + virtual bool processOverlap(btBroadphasePair& pair) + { + return ((pair.m_pProxy0 == m_obsoleteProxy) || + (pair.m_pProxy1 == m_obsoleteProxy)); + } + + }; + + + RemovePairCallback removeCallback(proxy); + + processAllOverlappingPairs(&removeCallback); +} + + + +void btOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback) +{ + + int i; + + for (i=0;iprocessOverlap(*pair)) + { + cleanOverlappingPair(*pair); + + m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); + m_overlappingPairArray.pop_back(); + gOverlappingPairs--; + } else + { + i++; + } + } +} + diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h new file mode 100644 index 00000000000..a81fe3264df --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h @@ -0,0 +1,120 @@ + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef OVERLAPPING_PAIR_CACHE_H +#define OVERLAPPING_PAIR_CACHE_H + + +#include "btBroadphaseInterface.h" +#include "btBroadphaseProxy.h" +#include "../../LinearMath/btPoint3.h" +#include "../../LinearMath/btAlignedObjectArray.h" + + +struct btOverlapCallback +{ + virtual ~btOverlapCallback() + {} + //return true for deletion of the pair + virtual bool processOverlap(btBroadphasePair& pair) = 0; +}; + +struct btOverlapFilterCallback +{ + virtual ~btOverlapFilterCallback() + {} + // return true when pairs need collision + virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const = 0; +}; + +///btOverlappingPairCache maintains the objects with overlapping AABB +///Typically managed by the Broadphase, Axis3Sweep or btSimpleBroadphase +class btOverlappingPairCache : public btBroadphaseInterface +{ + protected: + //avoid brute-force finding all the time + btAlignedObjectArray m_overlappingPairArray; + + //during the dispatch, check that user doesn't destroy/create proxy + bool m_blockedForChanges; + + //if set, use the callback instead of the built in filter in needBroadphaseCollision + btOverlapFilterCallback* m_overlapFilterCallback; + public: + + btOverlappingPairCache(); + virtual ~btOverlappingPairCache(); + + virtual void processAllOverlappingPairs(btOverlapCallback*); + + void removeOverlappingPair(btBroadphasePair& pair); + + void cleanOverlappingPair(btBroadphasePair& pair); + + void addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); + + btBroadphasePair* findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); + + + void cleanProxyFromPairs(btBroadphaseProxy* proxy); + + void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy); + + + inline bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const + { + if (m_overlapFilterCallback) + return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); + + bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; + collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); + + return collides; + } + + + + virtual void refreshOverlappingPairs() =0; + + btBroadphasePair* getOverlappingPairArrayPtr() + { + return &m_overlappingPairArray[0]; + } + + const btBroadphasePair* getOverlappingPairArrayPtr() const + { + return &m_overlappingPairArray[0]; + } + + int getNumOverlappingPairs() const + { + return m_overlappingPairArray.size(); + } + + btOverlapFilterCallback* getOverlapFilterCallback() + { + return m_overlapFilterCallback; + } + + void setOverlapFilterCallback(btOverlapFilterCallback* callback) + { + m_overlapFilterCallback = callback; + } + +}; +#endif //OVERLAPPING_PAIR_CACHE_H + + diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp new file mode 100644 index 00000000000..30bcbe0c5f1 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp @@ -0,0 +1,222 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btSimpleBroadphase.h" +#include +#include + +#include "LinearMath/btVector3.h" +#include "LinearMath/btTransform.h" +#include "LinearMath/btMatrix3x3.h" +#include + + +void btSimpleBroadphase::validate() +{ + for (int i=0;i=0;i--) + { + BP_Proxy* proxy = m_pProxies[i]; + destroyProxy(proxy); + } + */ +} + + +btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask) +{ + if (m_numProxies >= m_maxProxies) + { + assert(0); + return 0; //should never happen, but don't let the game crash ;-) + } + assert(min[0]<= max[0] && min[1]<= max[1] && min[2]<= max[2]); + + int freeIndex= m_freeProxies[m_firstFreeProxy]; + btSimpleBroadphaseProxy* proxy = new (&m_proxies[freeIndex])btSimpleBroadphaseProxy(min,max,shapeType,userPtr,collisionFilterGroup,collisionFilterMask); + m_firstFreeProxy++; + + btSimpleBroadphaseProxy* proxy1 = &m_proxies[0]; + + int index = int(proxy - proxy1); + btAssert(index == freeIndex); + + m_pProxies[m_numProxies] = proxy; + m_numProxies++; + //validate(); + + return proxy; +} + +class RemovingOverlapCallback : public btOverlapCallback +{ +protected: + virtual bool processOverlap(btBroadphasePair& pair) + { + (void)pair; + btAssert(0); + return false; + } +}; + +class RemovePairContainingProxy +{ + + btBroadphaseProxy* m_targetProxy; + public: + virtual ~RemovePairContainingProxy() + { + } +protected: + virtual bool processOverlap(btBroadphasePair& pair) + { + btSimpleBroadphaseProxy* proxy0 = static_cast(pair.m_pProxy0); + btSimpleBroadphaseProxy* proxy1 = static_cast(pair.m_pProxy1); + + return ((m_targetProxy == proxy0 || m_targetProxy == proxy1)); + }; +}; + +void btSimpleBroadphase::destroyProxy(btBroadphaseProxy* proxyOrg) +{ + + int i; + + btSimpleBroadphaseProxy* proxy0 = static_cast(proxyOrg); + btSimpleBroadphaseProxy* proxy1 = &m_proxies[0]; + + int index = int(proxy0 - proxy1); + btAssert (index < m_maxProxies); + m_freeProxies[--m_firstFreeProxy] = index; + + removeOverlappingPairsContainingProxy(proxyOrg); + + for (i=0;im_min = aabbMin; + sbp->m_max = aabbMax; +} + + + + + + + + + +bool btSimpleBroadphase::aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1) +{ + return proxy0->m_min[0] <= proxy1->m_max[0] && proxy1->m_min[0] <= proxy0->m_max[0] && + proxy0->m_min[1] <= proxy1->m_max[1] && proxy1->m_min[1] <= proxy0->m_max[1] && + proxy0->m_min[2] <= proxy1->m_max[2] && proxy1->m_min[2] <= proxy0->m_max[2]; + +} + + + +//then remove non-overlapping ones +class CheckOverlapCallback : public btOverlapCallback +{ +public: + virtual bool processOverlap(btBroadphasePair& pair) + { + return (!btSimpleBroadphase::aabbOverlap(static_cast(pair.m_pProxy0),static_cast(pair.m_pProxy1))); + } +}; + +void btSimpleBroadphase::refreshOverlappingPairs() +{ + //first check for new overlapping pairs + int i,j; + + for (i=0;i(proxy); + return proxy0; + } + + + void validate(); + +protected: + + + virtual void refreshOverlappingPairs(); +public: + btSimpleBroadphase(int maxProxies=16384); + virtual ~btSimpleBroadphase(); + + + static bool aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1); + + + virtual btBroadphaseProxy* createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask); + + + virtual void destroyProxy(btBroadphaseProxy* proxy); + virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax); + + + + + + +}; + + + +#endif //SIMPLE_BROADPHASE_H + diff --git a/extern/bullet2/src/BulletCollision/CMakeLists.txt b/extern/bullet2/src/BulletCollision/CMakeLists.txt new file mode 100644 index 00000000000..e565bf7edea --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CMakeLists.txt @@ -0,0 +1,60 @@ + +INCLUDE_DIRECTORIES( +${BULLET_PHYSICS_SOURCE_DIR}/src } +) + +ADD_LIBRARY(LibBulletCollision + BroadphaseCollision/btAxisSweep3.cpp + BroadphaseCollision/btBroadphaseProxy.cpp + BroadphaseCollision/btCollisionAlgorithm.cpp + BroadphaseCollision/btDispatcher.cpp + BroadphaseCollision/btOverlappingPairCache.cpp + BroadphaseCollision/btSimpleBroadphase.cpp + CollisionDispatch/btCollisionDispatcher.cpp + CollisionDispatch/btCollisionObject.cpp + CollisionDispatch/btCollisionWorld.cpp + CollisionDispatch/btCompoundCollisionAlgorithm.cpp + CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp + CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp + CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp + CollisionDispatch/btConvexConvexAlgorithm.cpp + CollisionDispatch/btEmptyCollisionAlgorithm.cpp + CollisionDispatch/btManifoldResult.cpp + CollisionDispatch/btSimulationIslandManager.cpp + CollisionDispatch/btUnionFind.cpp + CollisionShapes/btBoxShape.cpp + CollisionShapes/btBvhTriangleMeshShape.cpp + CollisionShapes/btCollisionShape.cpp + CollisionShapes/btCompoundShape.cpp + CollisionShapes/btConcaveShape.cpp + CollisionShapes/btConeShape.cpp + CollisionShapes/btConvexHullShape.cpp + CollisionShapes/btConvexShape.cpp + CollisionShapes/btConvexTriangleMeshShape.cpp + CollisionShapes/btCylinderShape.cpp + CollisionShapes/btEmptyShape.cpp + CollisionShapes/btMinkowskiSumShape.cpp + CollisionShapes/btMultiSphereShape.cpp + CollisionShapes/btOptimizedBvh.cpp + CollisionShapes/btPolyhedralConvexShape.cpp + CollisionShapes/btTetrahedronShape.cpp + CollisionShapes/btSphereShape.cpp + CollisionShapes/btStaticPlaneShape.cpp + CollisionShapes/btStridingMeshInterface.cpp + CollisionShapes/btTriangleCallback.cpp + CollisionShapes/btTriangleBuffer.cpp + CollisionShapes/btTriangleIndexVertexArray.cpp + CollisionShapes/btTriangleMesh.cpp + CollisionShapes/btTriangleMeshShape.cpp + NarrowPhaseCollision/btContinuousConvexCollision.cpp + NarrowPhaseCollision/btGjkEpa.cpp + NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp + NarrowPhaseCollision/btConvexCast.cpp + NarrowPhaseCollision/btGjkConvexCast.cpp + NarrowPhaseCollision/btGjkPairDetector.cpp + NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp + NarrowPhaseCollision/btPersistentManifold.cpp + NarrowPhaseCollision/btRaycastCallback.cpp + NarrowPhaseCollision/btSubSimplexConvexCast.cpp + NarrowPhaseCollision/btVoronoiSimplexSolver.cpp +) diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp new file mode 100644 index 00000000000..81133670f0c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp @@ -0,0 +1,200 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "LinearMath/btScalar.h" +#include "SphereTriangleDetector.h" +#include "BulletCollision/CollisionShapes/btTriangleShape.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" + + +SphereTriangleDetector::SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle) +:m_sphere(sphere), +m_triangle(triangle) +{ + +} + +void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw) +{ + + (void)debugDraw; + const btTransform& transformA = input.m_transformA; + const btTransform& transformB = input.m_transformB; + + btVector3 point,normal; + btScalar timeOfImpact = btScalar(1.); + btScalar depth = btScalar(0.); +// output.m_distance = btScalar(1e30); + //move sphere into triangle space + btTransform sphereInTr = transformB.inverseTimes(transformA); + + if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact)) + { + output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth); + } + +} + +#define MAX_OVERLAP btScalar(0.) + + + +// See also geometrictools.com +// Basic idea: D = |p - (lo + t0*lv)| where t0 = lv . (p - lo) / lv . lv +btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) { + btVector3 diff = p - from; + btVector3 v = to - from; + btScalar t = v.dot(diff); + + if (t > 0) { + btScalar dotVV = v.dot(v); + if (t < dotVV) { + t /= dotVV; + diff -= t*v; + } else { + t = 1; + diff -= v; + } + } else + t = 0; + + nearest = from + t*v; + return diff.dot(diff); +} + +bool SphereTriangleDetector::facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal) { + btVector3 lp(p); + btVector3 lnormal(normal); + + return pointInTriangle(vertices, lnormal, &lp); +} + +///combined discrete/continuous sphere-triangle +bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact) +{ + + const btVector3* vertices = &m_triangle->getVertexPtr(0); + const btVector3& c = sphereCenter; + btScalar r = m_sphere->getRadius(); + + btVector3 delta (0,0,0); + + btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]); + normal.normalize(); + btVector3 p1ToCentre = c - vertices[0]; + btScalar distanceFromPlane = p1ToCentre.dot(normal); + + if (distanceFromPlane < btScalar(0.)) + { + //triangle facing the other way + + distanceFromPlane *= btScalar(-1.); + normal *= btScalar(-1.); + } + + ///todo: move this gContactBreakingThreshold into a proper structure + extern btScalar gContactBreakingThreshold; + + btScalar contactMargin = gContactBreakingThreshold; + bool isInsideContactPlane = distanceFromPlane < r + contactMargin; + bool isInsideShellPlane = distanceFromPlane < r; + + btScalar deltaDotNormal = delta.dot(normal); + if (!isInsideShellPlane && deltaDotNormal >= btScalar(0.0)) + return false; + + // Check for contact / intersection + bool hasContact = false; + btVector3 contactPoint; + if (isInsideContactPlane) { + if (facecontains(c,vertices,normal)) { + // Inside the contact wedge - touches a point on the shell plane + hasContact = true; + contactPoint = c - normal*distanceFromPlane; + } else { + // Could be inside one of the contact capsules + btScalar contactCapsuleRadiusSqr = (r + contactMargin) * (r + contactMargin); + btVector3 nearestOnEdge; + for (int i = 0; i < m_triangle->getNumEdges(); i++) { + + btPoint3 pa; + btPoint3 pb; + + m_triangle->getEdge(i,pa,pb); + + btScalar distanceSqr = SegmentSqrDistance(pa,pb,c, nearestOnEdge); + if (distanceSqr < contactCapsuleRadiusSqr) { + // Yep, we're inside a capsule + hasContact = true; + contactPoint = nearestOnEdge; + } + + } + } + } + + if (hasContact) { + btVector3 contactToCentre = c - contactPoint; + btScalar distanceSqr = contactToCentre.length2(); + if (distanceSqr < (r - MAX_OVERLAP)*(r - MAX_OVERLAP)) { + btScalar distance = btSqrt(distanceSqr); + resultNormal = contactToCentre; + resultNormal.normalize(); + point = contactPoint; + depth = -(r-distance); + return true; + } + + if (delta.dot(contactToCentre) >= btScalar(0.0)) + return false; + + // Moving towards the contact point -> collision + point = contactPoint; + timeOfImpact = btScalar(0.0); + return true; + } + + return false; +} + + +bool SphereTriangleDetector::pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p ) +{ + const btVector3* p1 = &vertices[0]; + const btVector3* p2 = &vertices[1]; + const btVector3* p3 = &vertices[2]; + + btVector3 edge1( *p2 - *p1 ); + btVector3 edge2( *p3 - *p2 ); + btVector3 edge3( *p1 - *p3 ); + + btVector3 p1_to_p( *p - *p1 ); + btVector3 p2_to_p( *p - *p2 ); + btVector3 p3_to_p( *p - *p3 ); + + btVector3 edge1_normal( edge1.cross(normal)); + btVector3 edge2_normal( edge2.cross(normal)); + btVector3 edge3_normal( edge3.cross(normal)); + + btScalar r1, r2, r3; + r1 = edge1_normal.dot( p1_to_p ); + r2 = edge2_normal.dot( p2_to_p ); + r3 = edge3_normal.dot( p3_to_p ); + if ( ( r1 > 0 && r2 > 0 && r3 > 0 ) || + ( r1 <= 0 && r2 <= 0 && r3 <= 0 ) ) + return true; + return false; + +} diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h new file mode 100644 index 00000000000..b32806a6846 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h @@ -0,0 +1,49 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SPHERE_TRIANGLE_DETECTOR_H +#define SPHERE_TRIANGLE_DETECTOR_H + +#include "../NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" +#include "../../LinearMath/btPoint3.h" + + +class btSphereShape; +class btTriangleShape; + + + +/// sphere-triangle to match the btDiscreteCollisionDetectorInterface +struct SphereTriangleDetector : public btDiscreteCollisionDetectorInterface +{ + virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw); + + SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle); + + virtual ~SphereTriangleDetector() {}; + +private: + + bool collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact); + bool pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p ); + bool facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal); + + btSphereShape* m_sphere; + btTriangleShape* m_triangle; + + +}; +#endif //SPHERE_TRIANGLE_DETECTOR_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h new file mode 100644 index 00000000000..d51a59af7f0 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h @@ -0,0 +1,46 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef COLLISION_CREATE_FUNC +#define COLLISION_CREATE_FUNC + +#include "../../LinearMath/btAlignedObjectArray.h" +typedef btAlignedObjectArray btCollisionObjectArray; +class btCollisionAlgorithm; +class btCollisionObject; + +struct btCollisionAlgorithmConstructionInfo; + +///Used by the btCollisionDispatcher to register and create instances for btCollisionAlgorithm +struct btCollisionAlgorithmCreateFunc +{ + bool m_swapped; + + btCollisionAlgorithmCreateFunc() + :m_swapped(false) + { + } + virtual ~btCollisionAlgorithmCreateFunc(){}; + + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& , btCollisionObject* body0,btCollisionObject* body1) + { + + (void)body0; + (void)body1; + return 0; + } +}; +#endif //COLLISION_CREATE_FUNC + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp new file mode 100644 index 00000000000..b535fac6563 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp @@ -0,0 +1,367 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#include "btCollisionDispatcher.h" + + +#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h" +#include "BulletCollision/CollisionShapes/btCollisionShape.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" + +int gNumManifold = 0; + +#include + + +btCollisionDispatcher::btCollisionDispatcher(bool noDefaultAlgorithms): +m_count(0), +m_useIslands(true), +m_convexConvexCreateFunc(0), +m_convexConcaveCreateFunc(0), +m_swappedConvexConcaveCreateFunc(0), +m_compoundCreateFunc(0), +m_swappedCompoundCreateFunc(0), +m_emptyCreateFunc(0) +{ + (void)noDefaultAlgorithms; + int i; + + setNearCallback(defaultNearCallback); + + m_emptyCreateFunc = new btEmptyAlgorithm::CreateFunc; + for (i=0;iclearManifold(); +} + + +void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold) +{ + + gNumManifold--; + + //printf("releaseManifold: gNumManifold %d\n",gNumManifold); + clearManifold(manifold); + + ///todo: this can be improved a lot, linear search might be slow part! + int findIndex = m_manifoldsPtr.findLinearSearch(manifold); + if (findIndex < m_manifoldsPtr.size()) + { + m_manifoldsPtr.swap(findIndex,m_manifoldsPtr.size()-1); + m_manifoldsPtr.pop_back(); + delete manifold; + } + +} + + + +btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold) +{ + +#ifdef USE_DISPATCH_REGISTRY_ARRAY + + btCollisionAlgorithmConstructionInfo ci; + ci.m_dispatcher = this; + ci.m_manifold = sharedManifold; + btCollisionAlgorithm* algo = m_doubleDispatch[body0->getCollisionShape()->getShapeType()][body1->getCollisionShape()->getShapeType()] + ->CreateCollisionAlgorithm(ci,body0,body1); +#else + btCollisionAlgorithm* algo = internalFindAlgorithm(body0,body1); +#endif //USE_DISPATCH_REGISTRY_ARRAY + return algo; +} + + +#ifndef BT_EXCLUDE_DEFAULT_COLLISIONALGORITHM_REGISTRATION + +btCollisionAlgorithmCreateFunc* btCollisionDispatcher::internalFindCreateFunc(int proxyType0,int proxyType1) +{ + + if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1)) + { + return m_convexConvexCreateFunc; + } + + if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1)) + { + return m_convexConcaveCreateFunc; + } + + if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0)) + { + return m_swappedConvexConcaveCreateFunc; + } + + if (btBroadphaseProxy::isCompound(proxyType0)) + { + return m_compoundCreateFunc; + } else + { + if (btBroadphaseProxy::isCompound(proxyType1)) + { + return m_swappedCompoundCreateFunc; + } + } + + //failed to find an algorithm + return m_emptyCreateFunc; +} + +#endif //BT_EXCLUDE_DEFAULT_COLLISIONALGORITHM_REGISTRATION + + +#ifndef USE_DISPATCH_REGISTRY_ARRAY + +btCollisionAlgorithm* btCollisionDispatcher::internalFindAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold) +{ + m_count++; + + btCollisionAlgorithmConstructionInfo ci; + ci.m_dispatcher = this; + + if (body0->getCollisionShape()->isConvex() && body1->getCollisionShape()->isConvex() ) + { + return new btConvexConvexAlgorithm(sharedManifold,ci,body0,body1); + } + + if (body0->getCollisionShape()->isConvex() && body1->getCollisionShape()->isConcave()) + { + return new btConvexConcaveCollisionAlgorithm(ci,body0,body1,false); + } + + if (body1->getCollisionShape()->isConvex() && body0->getCollisionShape()->isConcave()) + { + return new btConvexConcaveCollisionAlgorithm(ci,body0,body1,true); + } + + if (body0->getCollisionShape()->isCompound()) + { + return new btCompoundCollisionAlgorithm(ci,body0,body1,false); + } else + { + if (body1->getCollisionShape()->isCompound()) + { + return new btCompoundCollisionAlgorithm(ci,body0,body1,true); + } + } + + //failed to find an algorithm + return new btEmptyAlgorithm(ci); + +} +#endif //USE_DISPATCH_REGISTRY_ARRAY + +bool btCollisionDispatcher::needsResponse(btCollisionObject* body0,btCollisionObject* body1) +{ + //here you can do filtering + bool hasResponse = + (body0->hasContactResponse() && body1->hasContactResponse()); + //no response between two static/kinematic bodies: + hasResponse = hasResponse && + ((!body0->isStaticOrKinematicObject()) ||(! body1->isStaticOrKinematicObject())); + return hasResponse; +} + +bool btCollisionDispatcher::needsCollision(btCollisionObject* body0,btCollisionObject* body1) +{ + assert(body0); + assert(body1); + + bool needsCollision = true; + + //broadphase filtering already deals with this + if ((body0->isStaticObject() || body0->isKinematicObject()) && + (body1->isStaticObject() || body1->isKinematicObject())) + { + printf("warning btCollisionDispatcher::needsCollision: static-static collision!\n"); + } + + if ((!body0->isActive()) && (!body1->isActive())) + needsCollision = false; + else if (!body0->checkCollideWith(body1)) + needsCollision = false; + + return needsCollision ; + +} + + + +///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc) +///this is useful for the collision dispatcher. +class btCollisionPairCallback : public btOverlapCallback +{ + btDispatcherInfo& m_dispatchInfo; + btCollisionDispatcher* m_dispatcher; + +public: + + btCollisionPairCallback(btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher) + :m_dispatchInfo(dispatchInfo), + m_dispatcher(dispatcher) + { + } + + btCollisionPairCallback& operator=(btCollisionPairCallback& other) + { + m_dispatchInfo = other.m_dispatchInfo; + m_dispatcher = other.m_dispatcher; + return *this; + } + + virtual ~btCollisionPairCallback() {} + + + virtual bool processOverlap(btBroadphasePair& pair) + { + (*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo); + + return false; + } +}; + + +void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo) +{ + //m_blockedForChanges = true; + + btCollisionPairCallback collisionCallback(dispatchInfo,this); + + pairCache->processAllOverlappingPairs(&collisionCallback); + + //m_blockedForChanges = false; + +} + + + + +//by default, Bullet will use this near callback +void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo) +{ + btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; + btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; + + if (dispatcher.needsCollision(colObj0,colObj1)) + { + //dispatcher will keep algorithms persistent in the collision pair + if (!collisionPair.m_algorithm) + { + collisionPair.m_algorithm = dispatcher.findAlgorithm(colObj0,colObj1); + } + + if (collisionPair.m_algorithm) + { + btManifoldResult contactPointResult(colObj0,colObj1); + + if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE) + { + //discrete collision detection query + collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult); + } else + { + //continuous collision detection query, time of impact (toi) + btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult); + if (dispatchInfo.m_timeOfImpact > toi) + dispatchInfo.m_timeOfImpact = toi; + + } + } + } + +} diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h new file mode 100644 index 00000000000..ca5aba8f01c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h @@ -0,0 +1,135 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef COLLISION__DISPATCHER_H +#define COLLISION__DISPATCHER_H + +#include "../BroadphaseCollision/btDispatcher.h" +#include "../NarrowPhaseCollision/btPersistentManifold.h" + +#include "../CollisionDispatch/btManifoldResult.h" + +#include "../BroadphaseCollision/btBroadphaseProxy.h" +#include "../../LinearMath/btAlignedObjectArray.h" + +class btIDebugDraw; +class btOverlappingPairCache; + + +#include "btCollisionCreateFunc.h" + +#define USE_DISPATCH_REGISTRY_ARRAY 1 + +class btCollisionDispatcher; +///user can override this nearcallback for collision filtering and more finegrained control over collision detection +typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo); + + +///btCollisionDispatcher supports algorithms that handle ConvexConvex and ConvexConcave collision pairs. +///Time of Impact, Closest Points and Penetration Depth. +class btCollisionDispatcher : public btDispatcher +{ + int m_count; + + btAlignedObjectArray m_manifoldsPtr; + + bool m_useIslands; + + btManifoldResult m_defaultManifoldResult; + + btNearCallback m_nearCallback; + + btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; + + btCollisionAlgorithmCreateFunc* internalFindCreateFunc(int proxyType0,int proxyType1); + + //default CreationFunctions, filling the m_doubleDispatch table + btCollisionAlgorithmCreateFunc* m_convexConvexCreateFunc; + btCollisionAlgorithmCreateFunc* m_convexConcaveCreateFunc; + btCollisionAlgorithmCreateFunc* m_swappedConvexConcaveCreateFunc; + btCollisionAlgorithmCreateFunc* m_compoundCreateFunc; + btCollisionAlgorithmCreateFunc* m_swappedCompoundCreateFunc; + btCollisionAlgorithmCreateFunc* m_emptyCreateFunc; + +#ifndef USE_DISPATCH_REGISTRY_ARRAY + btCollisionAlgorithm* internalFindAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold = 0); +#endif //USE_DISPATCH_REGISTRY_ARRAY + +public: + + ///registerCollisionCreateFunc allows registration of custom/alternative collision create functions + void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc); + + int getNumManifolds() const + { + return int( m_manifoldsPtr.size()); + } + + btPersistentManifold** getInternalManifoldPointer() + { + return &m_manifoldsPtr[0]; + } + + btPersistentManifold* getManifoldByIndexInternal(int index) + { + return m_manifoldsPtr[index]; + } + + const btPersistentManifold* getManifoldByIndexInternal(int index) const + { + return m_manifoldsPtr[index]; + } + + ///the default constructor creates/register default collision algorithms, for convex, compound and concave shape support + btCollisionDispatcher (); + + ///a special constructor that doesn't create/register the default collision algorithms + btCollisionDispatcher(bool noDefaultAlgorithms); + + virtual ~btCollisionDispatcher(); + + virtual btPersistentManifold* getNewManifold(void* b0,void* b1); + + virtual void releaseManifold(btPersistentManifold* manifold); + + + virtual void clearManifold(btPersistentManifold* manifold); + + + btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold = 0); + + virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1); + + virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1); + + virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo); + + void setNearCallback(btNearCallback nearCallback) + { + m_nearCallback = nearCallback; + } + + btNearCallback getNearCallback() const + { + return m_nearCallback; + } + + //by default, Bullet will use this near callback + static void defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo); + +}; + +#endif //COLLISION__DISPATCHER_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp new file mode 100644 index 00000000000..d4c0a4e8cb3 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp @@ -0,0 +1,57 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btCollisionObject.h" + +btCollisionObject::btCollisionObject() + : m_broadphaseHandle(0), + m_collisionShape(0), + m_collisionFlags(0), + m_activationState1(1), + m_deactivationTime(btScalar(0.)), + m_userObjectPointer(0), + m_hitFraction(btScalar(1.)), + m_ccdSweptSphereRadius(btScalar(0.)), + m_ccdSquareMotionThreshold(btScalar(0.)), + m_checkCollideWith(false) +{ + +} + +btCollisionObject::~btCollisionObject() +{ +} + +void btCollisionObject::setActivationState(int newState) +{ + if ( (m_activationState1 != DISABLE_DEACTIVATION) && (m_activationState1 != DISABLE_SIMULATION)) + m_activationState1 = newState; +} + +void btCollisionObject::forceActivationState(int newState) +{ + m_activationState1 = newState; +} + +void btCollisionObject::activate(bool forceActivation) +{ + if (forceActivation || !(m_collisionFlags & (CF_STATIC_OBJECT|CF_KINEMATIC_OBJECT))) + { + setActivationState(ACTIVE_TAG); + m_deactivationTime = btScalar(0.); + } +} + + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h new file mode 100644 index 00000000000..9fb6a67c4a3 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h @@ -0,0 +1,346 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef COLLISION_OBJECT_H +#define COLLISION_OBJECT_H + +#include "../../LinearMath/btTransform.h" + +//island management, m_activationState1 +#define ACTIVE_TAG 1 +#define ISLAND_SLEEPING 2 +#define WANTS_DEACTIVATION 3 +#define DISABLE_DEACTIVATION 4 +#define DISABLE_SIMULATION 5 + +struct btBroadphaseProxy; +class btCollisionShape; +#include "../../LinearMath/btMotionState.h" + + + +/// btCollisionObject can be used to manage collision detection objects. +/// btCollisionObject maintains all information that is needed for a collision detection: Shape, Transform and AABB proxy. +/// They can be added to the btCollisionWorld. +ATTRIBUTE_ALIGNED16(class) btCollisionObject +{ + +protected: + + btTransform m_worldTransform; + + ///m_interpolationWorldTransform is used for CCD and interpolation + ///it can be either previous or future (predicted) transform + btTransform m_interpolationWorldTransform; + //those two are experimental: just added for bullet time effect, so you can still apply impulses (directly modifying velocities) + //without destroying the continuous interpolated motion (which uses this interpolation velocities) + btVector3 m_interpolationLinearVelocity; + btVector3 m_interpolationAngularVelocity; + btBroadphaseProxy* m_broadphaseHandle; + btCollisionShape* m_collisionShape; + + int m_collisionFlags; + + int m_islandTag1; + int m_companionId; + + int m_activationState1; + btScalar m_deactivationTime; + + btScalar m_friction; + btScalar m_restitution; + + ///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer + void* m_userObjectPointer; + + ///m_internalOwner is reserved to point to Bullet's btRigidBody. Don't use this, use m_userObjectPointer instead. + void* m_internalOwner; + + ///time of impact calculation + btScalar m_hitFraction; + + ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: + btScalar m_ccdSweptSphereRadius; + + /// Don't do continuous collision detection if square motion (in one step) is less then m_ccdSquareMotionThreshold + btScalar m_ccdSquareMotionThreshold; + + /// If some object should have elaborate collision filtering by sub-classes + bool m_checkCollideWith; + + char m_pad[7]; + + virtual bool checkCollideWithOverride(btCollisionObject* co) + { + return true; + } + +public: + + enum CollisionFlags + { + CF_STATIC_OBJECT= 1, + CF_KINEMATIC_OBJECT= 2, + CF_NO_CONTACT_RESPONSE = 4, + CF_CUSTOM_MATERIAL_CALLBACK = 8//this allows per-triangle material (friction/restitution) + }; + + + inline bool mergesSimulationIslands() const + { + ///static objects, kinematic and object without contact response don't merge islands + return ((m_collisionFlags & (CF_STATIC_OBJECT | CF_KINEMATIC_OBJECT | CF_NO_CONTACT_RESPONSE) )==0); + } + + + inline bool isStaticObject() const { + return (m_collisionFlags & CF_STATIC_OBJECT) != 0; + } + + inline bool isKinematicObject() const + { + return (m_collisionFlags & CF_KINEMATIC_OBJECT) != 0; + } + + inline bool isStaticOrKinematicObject() const + { + return (m_collisionFlags & (CF_KINEMATIC_OBJECT | CF_STATIC_OBJECT)) != 0 ; + } + + inline bool hasContactResponse() const { + return (m_collisionFlags & CF_NO_CONTACT_RESPONSE)==0; + } + + + btCollisionObject(); + + virtual ~btCollisionObject(); + + void setCollisionShape(btCollisionShape* collisionShape) + { + m_collisionShape = collisionShape; + } + + const btCollisionShape* getCollisionShape() const + { + return m_collisionShape; + } + + btCollisionShape* getCollisionShape() + { + return m_collisionShape; + } + + + + + int getActivationState() const { return m_activationState1;} + + void setActivationState(int newState); + + void setDeactivationTime(btScalar time) + { + m_deactivationTime = time; + } + btScalar getDeactivationTime() const + { + return m_deactivationTime; + } + + void forceActivationState(int newState); + + void activate(bool forceActivation = false); + + inline bool isActive() const + { + return ((getActivationState() != ISLAND_SLEEPING) && (getActivationState() != DISABLE_SIMULATION)); + } + + void setRestitution(btScalar rest) + { + m_restitution = rest; + } + btScalar getRestitution() const + { + return m_restitution; + } + void setFriction(btScalar frict) + { + m_friction = frict; + } + btScalar getFriction() const + { + return m_friction; + } + + ///reserved for Bullet internal usage + void* getInternalOwner() + { + return m_internalOwner; + } + + const void* getInternalOwner() const + { + return m_internalOwner; + } + + btTransform& getWorldTransform() + { + return m_worldTransform; + } + + const btTransform& getWorldTransform() const + { + return m_worldTransform; + } + + void setWorldTransform(const btTransform& worldTrans) + { + m_worldTransform = worldTrans; + } + + + btBroadphaseProxy* getBroadphaseHandle() + { + return m_broadphaseHandle; + } + + const btBroadphaseProxy* getBroadphaseHandle() const + { + return m_broadphaseHandle; + } + + void setBroadphaseHandle(btBroadphaseProxy* handle) + { + m_broadphaseHandle = handle; + } + + + const btTransform& getInterpolationWorldTransform() const + { + return m_interpolationWorldTransform; + } + + btTransform& getInterpolationWorldTransform() + { + return m_interpolationWorldTransform; + } + + void setInterpolationWorldTransform(const btTransform& trans) + { + m_interpolationWorldTransform = trans; + } + + + const btVector3& getInterpolationLinearVelocity() const + { + return m_interpolationLinearVelocity; + } + + const btVector3& getInterpolationAngularVelocity() const + { + return m_interpolationAngularVelocity; + } + + const int getIslandTag() const + { + return m_islandTag1; + } + + void setIslandTag(int tag) + { + m_islandTag1 = tag; + } + + const int getCompanionId() const + { + return m_companionId; + } + + void setCompanionId(int id) + { + m_companionId = id; + } + + const btScalar getHitFraction() const + { + return m_hitFraction; + } + + void setHitFraction(btScalar hitFraction) + { + m_hitFraction = hitFraction; + } + + + const int getCollisionFlags() const + { + return m_collisionFlags; + } + + void setCollisionFlags(int flags) + { + m_collisionFlags = flags; + } + + ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: + btScalar getCcdSweptSphereRadius() const + { + return m_ccdSweptSphereRadius; + } + + ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: + void setCcdSweptSphereRadius(btScalar radius) + { + m_ccdSweptSphereRadius = radius; + } + + btScalar getCcdSquareMotionThreshold() const + { + return m_ccdSquareMotionThreshold; + } + + + /// Don't do continuous collision detection if square motion (in one step) is less then m_ccdSquareMotionThreshold + void setCcdSquareMotionThreshold(btScalar ccdSquareMotionThreshold) + { + m_ccdSquareMotionThreshold = ccdSquareMotionThreshold; + } + + ///users can point to their objects, userPointer is not used by Bullet + void* getUserPointer() const + { + return m_userObjectPointer; + } + + ///users can point to their objects, userPointer is not used by Bullet + void setUserPointer(void* userPointer) + { + m_userObjectPointer = userPointer; + } + + inline bool checkCollideWith(btCollisionObject* co) + { + if (m_checkCollideWith) + return checkCollideWithOverride(co); + + return true; + } + + +} +; + +#endif //COLLISION_OBJECT_H diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp new file mode 100644 index 00000000000..b49036a5b50 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp @@ -0,0 +1,362 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btCollisionWorld.h" +#include "btCollisionDispatcher.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionShapes/btCollisionShape.h" +#include "BulletCollision/CollisionShapes/btConvexShape.h" + +#include "BulletCollision/CollisionShapes/btSphereShape.h" //for raycasting +#include "BulletCollision/CollisionShapes/btTriangleMeshShape.h" //for raycasting +#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" +#include "BulletCollision/CollisionShapes/btCompoundShape.h" +#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" +#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" +#include "LinearMath/btAabbUtil2.h" +#include "LinearMath/btQuickprof.h" +#include "LinearMath/btStackAlloc.h" + +//When the user doesn't provide dispatcher or broadphase, create basic versions (and delete them in destructor) +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" + + +btCollisionWorld::btCollisionWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache, int stackSize) +:m_dispatcher1(dispatcher), +m_broadphasePairCache(pairCache), +m_ownsDispatcher(false), +m_ownsBroadphasePairCache(false) +{ + m_stackAlloc = new btStackAlloc(stackSize); + m_dispatchInfo.m_stackAllocator = m_stackAlloc; +} + + +btCollisionWorld::~btCollisionWorld() +{ + m_stackAlloc->destroy(); + delete m_stackAlloc; + + //clean up remaining objects + int i; + for (i=0;igetBroadphaseHandle(); + if (bp) + { + // + // only clear the cached algorithms + // + getBroadphase()->cleanProxyFromPairs(bp); + getBroadphase()->destroyProxy(bp); + } + } + + if (m_ownsDispatcher) + delete m_dispatcher1; + if (m_ownsBroadphasePairCache) + delete m_broadphasePairCache; + +} + + + + + + + + + + +void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup,short int collisionFilterMask) +{ + + //check that the object isn't already added + btAssert( m_collisionObjects.findLinearSearch(collisionObject) == m_collisionObjects.size()); + + m_collisionObjects.push_back(collisionObject); + + //calculate new AABB + btTransform trans = collisionObject->getWorldTransform(); + + btVector3 minAabb; + btVector3 maxAabb; + collisionObject->getCollisionShape()->getAabb(trans,minAabb,maxAabb); + + int type = collisionObject->getCollisionShape()->getShapeType(); + collisionObject->setBroadphaseHandle( getBroadphase()->createProxy( + minAabb, + maxAabb, + type, + collisionObject, + collisionFilterGroup, + collisionFilterMask + )) ; + + + + + +} + + + + +void btCollisionWorld::performDiscreteCollisionDetection() +{ + btDispatcherInfo& dispatchInfo = getDispatchInfo(); + + BEGIN_PROFILE("perform Broadphase Collision Detection"); + + + //update aabb (of all moved objects) + + btVector3 aabbMin,aabbMax; + for (int i=0;igetCollisionShape()->getAabb(m_collisionObjects[i]->getWorldTransform(),aabbMin,aabbMax); + m_broadphasePairCache->setAabb(m_collisionObjects[i]->getBroadphaseHandle(),aabbMin,aabbMax); + } + + m_broadphasePairCache->refreshOverlappingPairs(); + + + END_PROFILE("perform Broadphase Collision Detection"); + + BEGIN_PROFILE("performDiscreteCollisionDetection"); + + btDispatcher* dispatcher = getDispatcher(); + if (dispatcher) + dispatcher->dispatchAllCollisionPairs(m_broadphasePairCache,dispatchInfo); + + END_PROFILE("performDiscreteCollisionDetection"); + +} + + +void btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject) +{ + + + //bool removeFromBroadphase = false; + + { + + btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle(); + if (bp) + { + // + // only clear the cached algorithms + // + getBroadphase()->cleanProxyFromPairs(bp); + getBroadphase()->destroyProxy(bp); + collisionObject->setBroadphaseHandle(0); + } + } + + + //swapremove + m_collisionObjects.remove(collisionObject); + +} + + + +void btCollisionWorld::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, + btCollisionObject* collisionObject, + const btCollisionShape* collisionShape, + const btTransform& colObjWorldTransform, + RayResultCallback& resultCallback,short int collisionFilterMask) +{ + + btSphereShape pointShape(btScalar(0.0)); + pointShape.setMargin(0.f); + + objectQuerySingle(&pointShape,rayFromTrans,rayToTrans, + collisionObject, + collisionShape, + colObjWorldTransform, + resultCallback,collisionFilterMask); +} + +void btCollisionWorld::objectQuerySingle(const btConvexShape* castShape,const btTransform& rayFromTrans,const btTransform& rayToTrans, + btCollisionObject* collisionObject, + const btCollisionShape* collisionShape, + const btTransform& colObjWorldTransform, + RayResultCallback& resultCallback,short int collisionFilterMask) +{ + + + if (collisionShape->isConvex()) + { + btConvexCast::CastResult castResult; + castResult.m_fraction = btScalar(1.);//?? + + btConvexShape* convexShape = (btConvexShape*) collisionShape; + btVoronoiSimplexSolver simplexSolver; + btSubsimplexConvexCast convexCaster(castShape,convexShape,&simplexSolver); + //GjkConvexCast convexCaster(castShape,convexShape,&simplexSolver); + //ContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0); + + if (convexCaster.calcTimeOfImpact(rayFromTrans,rayToTrans,colObjWorldTransform,colObjWorldTransform,castResult)) + { + //add hit + if (castResult.m_normal.length2() > btScalar(0.0001)) + { + castResult.m_normal.normalize(); + if (castResult.m_fraction < resultCallback.m_closestHitFraction) + { + + btCollisionWorld::LocalRayResult localRayResult + ( + collisionObject, + 0, + castResult.m_normal, + castResult.m_fraction + ); + + resultCallback.AddSingleResult(localRayResult); + + } + } + } + } + else + { + + if (collisionShape->isConcave()) + { + + btTriangleMeshShape* triangleMesh = (btTriangleMeshShape*)collisionShape; + + btTransform worldTocollisionObject = colObjWorldTransform.inverse(); + + btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin(); + btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin(); + + //ConvexCast::CastResult + + struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback + { + btCollisionWorld::RayResultCallback* m_resultCallback; + btCollisionObject* m_collisionObject; + btTriangleMeshShape* m_triangleMesh; + + BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to, + btCollisionWorld::RayResultCallback* resultCallback, btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh): + btTriangleRaycastCallback(from,to), + m_resultCallback(resultCallback), + m_collisionObject(collisionObject), + m_triangleMesh(triangleMesh) + { + } + + + virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex ) + { + btCollisionWorld::LocalShapeInfo shapeInfo; + shapeInfo.m_shapePart = partId; + shapeInfo.m_triangleIndex = triangleIndex; + + btCollisionWorld::LocalRayResult rayResult + (m_collisionObject, + &shapeInfo, + hitNormalLocal, + hitFraction); + + return m_resultCallback->AddSingleResult(rayResult); + + + } + + }; + + + BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObject,triangleMesh); + rcb.m_hitFraction = resultCallback.m_closestHitFraction; + + btVector3 rayAabbMinLocal = rayFromLocal; + rayAabbMinLocal.setMin(rayToLocal); + btVector3 rayAabbMaxLocal = rayFromLocal; + rayAabbMaxLocal.setMax(rayToLocal); + + triangleMesh->processAllTriangles(&rcb,rayAabbMinLocal,rayAabbMaxLocal); + + } else + { + //todo: use AABB tree or other BVH acceleration structure! + if (collisionShape->isCompound()) + { + const btCompoundShape* compoundShape = static_cast(collisionShape); + int i=0; + for (i=0;igetNumChildShapes();i++) + { + btTransform childTrans = compoundShape->getChildTransform(i); + const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i); + btTransform childWorldTrans = colObjWorldTransform * childTrans; + objectQuerySingle(castShape, rayFromTrans,rayToTrans, + collisionObject, + childCollisionShape, + childWorldTrans, + resultCallback, collisionFilterMask); + + } + + + } + } + } +} + +void btCollisionWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback,short int collisionFilterMask) +{ + + + btTransform rayFromTrans,rayToTrans; + rayFromTrans.setIdentity(); + rayFromTrans.setOrigin(rayFromWorld); + rayToTrans.setIdentity(); + + rayToTrans.setOrigin(rayToWorld); + + /// go over all objects, and if the ray intersects their aabb, do a ray-shape query using convexCaster (CCD) + + int i; + for (i=0;igetBroadphaseHandle()->m_collisionFilterGroup & collisionFilterMask) { + //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); + btVector3 collisionObjectAabbMin,collisionObjectAabbMax; + collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); + + btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing + btVector3 hitNormal; + if (btRayAabb(rayFromWorld,rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal)) + { + rayTestSingle(rayFromTrans,rayToTrans, + collisionObject, + collisionObject->getCollisionShape(), + collisionObject->getWorldTransform(), + resultCallback); + } + } + } + +} diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h new file mode 100644 index 00000000000..b6d80233ab7 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h @@ -0,0 +1,255 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +/** + * @mainpage Bullet Documentation + * + * @section intro_sec Introduction + * Bullet Collision Detection & Physics SDK + * + * Bullet is a Collision Detection and Rigid Body Dynamics Library. The Library is Open Source and free for commercial use, under the ZLib license ( http://opensource.org/licenses/zlib-license.php ). + * + * There is the Physics Forum for Feedback and bteral Collision Detection and Physics discussions. + * Please visit http://www.continuousphysics.com/Bullet/phpBB2/index.php + * + * @section install_sec Installation + * + * @subsection step1 Step 1: Download + * You can download the Bullet Physics Library from our website: http://www.continuousphysics.com/Bullet/ + * @subsection step2 Step 2: Building + * Bullet comes with autogenerated Project Files for Microsoft Visual Studio 6, 7, 7.1 and 8. + * The main Workspace/Solution is located in Bullet/msvc/8/wksbullet.sln (replace 8 with your version). + * + * Under other platforms, like Linux or Mac OS-X, Bullet can be build using either using cmake, http://www.cmake.org, or jam, http://www.perforce.com/jam/jam.html . cmake can autogenerate Xcode, KDevelop, MSVC and other build systems. just run cmake . in the root of Bullet. + * Jam is a build system that can build the library, demos and also autogenerate the MSVC Project Files. + * So if you are not using MSVC, you can run configure and jam . + * If you don't have jam installed, you can make jam from the included jam-2.5 sources, or download jam from ftp://ftp.perforce.com/pub/jam/ + * + * @subsection step3 Step 3: Testing demos + * Try to run and experiment with CcdPhysicsDemo executable as a starting point. + * Bullet can be used in several ways, as Full Rigid Body simulation, as Collision Detector Library or Low Level / Snippets like the GJK Closest Point calculation. + * The Dependencies can be seen in this documentation under Directories + * + * @subsection step4 Step 4: Integrating in your application, Full Rigid Body Simulation + * Check out CcdPhysicsDemo how to create a btDynamicsWorld, btRigidBody and btCollisionShape, Stepping the simulation and synchronizing your graphics object transform. + * PLEASE NOTE THE CcdPhysicsEnvironment and CcdPhysicsController is obsolete and will be removed. It has been replaced by classes derived frmo btDynamicsWorld and btRididBody + * @subsection step5 Step 5 : Integrate the Collision Detection Library (without Dynamics and other Extras) + * Bullet Collision Detection can also be used without the Dynamics/Extras. + * Check out btCollisionWorld and btCollisionObject, and the CollisionInterfaceDemo. Also in Extras/test_BulletOde.cpp there is a sample Collision Detection integration with Open Dynamics Engine, ODE, http://www.ode.org + * @subsection step6 Step 6 : Use Snippets like the GJK Closest Point calculation. + * Bullet has been designed in a modular way keeping dependencies to a minimum. The ConvexHullDistance demo demonstrates direct use of btGjkPairDetector. + * + * @section copyright Copyright + * Copyright (C) 2005-2007 Erwin Coumans, some contributions Copyright Gino van den Bergen, Christer Ericson, Simon Hobbs, Ricardo Padrela, F Richter(res), Stephane Redon + * Special thanks to all visitors of the Bullet Physics forum, and in particular above contributors, Dave Eberle, Dirk Gregorius, Erin Catto, Dave Eberle, Adam Moravanszky, + * Pierre Terdiman, Kenny Erleben, Russell Smith, Oliver Strunk, Jan Paul van Waveren, Marten Svanfeldt. + * + */ + + + +#ifndef COLLISION_WORLD_H +#define COLLISION_WORLD_H + +class btStackAlloc; +class btCollisionShape; +class btConvexShape; +class btBroadphaseInterface; +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btTransform.h" +#include "btCollisionObject.h" +#include "btCollisionDispatcher.h" //for definition of btCollisionObjectArray +#include "../BroadphaseCollision/btOverlappingPairCache.h" +#include "../../LinearMath/btAlignedObjectArray.h" + +///CollisionWorld is interface and container for the collision detection +class btCollisionWorld +{ + + +protected: + + btAlignedObjectArray m_collisionObjects; + + btDispatcher* m_dispatcher1; + + btDispatcherInfo m_dispatchInfo; + + btStackAlloc* m_stackAlloc; + + btOverlappingPairCache* m_broadphasePairCache; + + bool m_ownsDispatcher; + bool m_ownsBroadphasePairCache; + +public: + + //this constructor doesn't own the dispatcher and paircache/broadphase + btCollisionWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache, int stackSize = 2*1024*1024); + + virtual ~btCollisionWorld(); + + + btBroadphaseInterface* getBroadphase() + { + return m_broadphasePairCache; + } + + btOverlappingPairCache* getPairCache() + { + return m_broadphasePairCache; + } + + + btDispatcher* getDispatcher() + { + return m_dispatcher1; + } + + ///LocalShapeInfo gives extra information for complex shapes + ///Currently, only btTriangleMeshShape is available, so it just contains triangleIndex and subpart + struct LocalShapeInfo + { + int m_shapePart; + int m_triangleIndex; + + //const btCollisionShape* m_shapeTemp; + //const btTransform* m_shapeLocalTransform; + }; + + struct LocalRayResult + { + LocalRayResult(btCollisionObject* collisionObject, + LocalShapeInfo* localShapeInfo, + const btVector3& hitNormalLocal, + btScalar hitFraction) + :m_collisionObject(collisionObject), + m_localShapeInfo(localShapeInfo), + m_hitNormalLocal(hitNormalLocal), + m_hitFraction(hitFraction) + { + } + + btCollisionObject* m_collisionObject; + LocalShapeInfo* m_localShapeInfo; + btVector3 m_hitNormalLocal; + btScalar m_hitFraction; + + }; + + ///RayResultCallback is used to report new raycast results + struct RayResultCallback + { + virtual ~RayResultCallback() + { + } + btScalar m_closestHitFraction; + bool HasHit() + { + return (m_closestHitFraction < btScalar(1.)); + } + + RayResultCallback() + :m_closestHitFraction(btScalar(1.)) + { + } + virtual btScalar AddSingleResult(LocalRayResult& rayResult) = 0; + }; + + struct ClosestRayResultCallback : public RayResultCallback + { + ClosestRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld) + :m_rayFromWorld(rayFromWorld), + m_rayToWorld(rayToWorld), + m_collisionObject(0) + { + } + + btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction + btVector3 m_rayToWorld; + + btVector3 m_hitNormalWorld; + btVector3 m_hitPointWorld; + btCollisionObject* m_collisionObject; + + virtual btScalar AddSingleResult(LocalRayResult& rayResult) + { + +//caller already does the filter on the m_closestHitFraction + assert(rayResult.m_hitFraction <= m_closestHitFraction); + + m_closestHitFraction = rayResult.m_hitFraction; + m_collisionObject = rayResult.m_collisionObject; + m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal; + m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction); + return rayResult.m_hitFraction; + } + }; + + + + + int getNumCollisionObjects() const + { + return int(m_collisionObjects.size()); + } + + /// rayTest performs a raycast on all objects in the btCollisionWorld, and calls the resultCallback + /// This allows for several queries: first hit, all hits, any hit, dependent on the value returned by the callback. + void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback, short int collisionFilterMask=-1); + + /// rayTestSingle performs a raycast call and calls the resultCallback. It is used internally by rayTest. + /// In a future implementation, we consider moving the ray test as a virtual method in btCollisionShape. + /// This allows more customization. + static void rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, + btCollisionObject* collisionObject, + const btCollisionShape* collisionShape, + const btTransform& colObjWorldTransform, + RayResultCallback& resultCallback, short int collisionFilterMask=-1); + + /// objectQuerySingle performs a collision detection query and calls the resultCallback. It is used internally by rayTest. + static void objectQuerySingle(const btConvexShape* castShape, const btTransform& rayFromTrans,const btTransform& rayToTrans, + btCollisionObject* collisionObject, + const btCollisionShape* collisionShape, + const btTransform& colObjWorldTransform, + RayResultCallback& resultCallback, short int collisionFilterMask=-1); + + void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=1,short int collisionFilterMask=1); + + btCollisionObjectArray& getCollisionObjectArray() + { + return m_collisionObjects; + } + + const btCollisionObjectArray& getCollisionObjectArray() const + { + return m_collisionObjects; + } + + + void removeCollisionObject(btCollisionObject* collisionObject); + + virtual void performDiscreteCollisionDetection(); + + btDispatcherInfo& getDispatchInfo() + { + return m_dispatchInfo; + } + +}; + + +#endif //COLLISION_WORLD_H diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp new file mode 100644 index 00000000000..92f4c8b28a6 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp @@ -0,0 +1,140 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionShapes/btCompoundShape.h" + + +btCompoundCollisionAlgorithm::btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) +:m_isSwapped(isSwapped) +{ + btCollisionObject* colObj = m_isSwapped? body1 : body0; + btCollisionObject* otherObj = m_isSwapped? body0 : body1; + assert (colObj->getCollisionShape()->isCompound()); + + btCompoundShape* compoundShape = static_cast(colObj->getCollisionShape()); + int numChildren = compoundShape->getNumChildShapes(); + int i; + + m_childCollisionAlgorithms.resize(numChildren); + for (i=0;igetChildShape(i); + btCollisionShape* orgShape = colObj->getCollisionShape(); + colObj->setCollisionShape( childShape ); + m_childCollisionAlgorithms[i] = ci.m_dispatcher->findAlgorithm(colObj,otherObj); + colObj->setCollisionShape( orgShape ); + } +} + + +btCompoundCollisionAlgorithm::~btCompoundCollisionAlgorithm() +{ + int numChildren = m_childCollisionAlgorithms.size(); + int i; + for (i=0;igetCollisionShape()->isCompound()); + btCompoundShape* compoundShape = static_cast(colObj->getCollisionShape()); + + //We will use the OptimizedBVH, AABB tree to cull potential child-overlaps + //If both proxies are Compound, we will deal with that directly, by performing sequential/parallel tree traversals + //given Proxy0 and Proxy1, if both have a tree, Tree0 and Tree1, this means: + //determine overlapping nodes of Proxy1 using Proxy0 AABB against Tree1 + //then use each overlapping node AABB against Tree0 + //and vise versa. + + int numChildren = m_childCollisionAlgorithms.size(); + int i; + for (i=0;igetChildShape(i); + + //backup + btTransform orgTrans = colObj->getWorldTransform(); + btCollisionShape* orgShape = colObj->getCollisionShape(); + + const btTransform& childTrans = compoundShape->getChildTransform(i); + //btTransform newChildWorldTrans = orgTrans*childTrans ; + colObj->setWorldTransform( orgTrans*childTrans ); + //the contactpoint is still projected back using the original inverted worldtrans + colObj->setCollisionShape( childShape ); + m_childCollisionAlgorithms[i]->processCollision(colObj,otherObj,dispatchInfo,resultOut); + //revert back + colObj->setCollisionShape( orgShape); + colObj->setWorldTransform( orgTrans ); + } +} + +btScalar btCompoundCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + + btCollisionObject* colObj = m_isSwapped? body1 : body0; + btCollisionObject* otherObj = m_isSwapped? body0 : body1; + + assert (colObj->getCollisionShape()->isCompound()); + + btCompoundShape* compoundShape = static_cast(colObj->getCollisionShape()); + + //We will use the OptimizedBVH, AABB tree to cull potential child-overlaps + //If both proxies are Compound, we will deal with that directly, by performing sequential/parallel tree traversals + //given Proxy0 and Proxy1, if both have a tree, Tree0 and Tree1, this means: + //determine overlapping nodes of Proxy1 using Proxy0 AABB against Tree1 + //then use each overlapping node AABB against Tree0 + //and vise versa. + + btScalar hitFraction = btScalar(1.); + + int numChildren = m_childCollisionAlgorithms.size(); + int i; + for (i=0;igetChildShape(i); + + //backup + btTransform orgTrans = colObj->getWorldTransform(); + btCollisionShape* orgShape = colObj->getCollisionShape(); + + const btTransform& childTrans = compoundShape->getChildTransform(i); + //btTransform newChildWorldTrans = orgTrans*childTrans ; + colObj->setWorldTransform( orgTrans*childTrans ); + + colObj->setCollisionShape( childShape ); + btScalar frac = m_childCollisionAlgorithms[i]->calculateTimeOfImpact(colObj,otherObj,dispatchInfo,resultOut); + if (fracsetCollisionShape( orgShape); + colObj->setWorldTransform( orgTrans); + } + return hitFraction; + +} + + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h new file mode 100644 index 00000000000..7091b233b46 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h @@ -0,0 +1,64 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef COMPOUND_COLLISION_ALGORITHM_H +#define COMPOUND_COLLISION_ALGORITHM_H + +#include "../BroadphaseCollision/btCollisionAlgorithm.h" +#include "../BroadphaseCollision/btDispatcher.h" +#include "../BroadphaseCollision/btBroadphaseInterface.h" + +#include "../NarrowPhaseCollision/btPersistentManifold.h" +class btDispatcher; +#include "../BroadphaseCollision/btBroadphaseProxy.h" +#include "btCollisionCreateFunc.h" +#include "../../LinearMath/btAlignedObjectArray.h" + +/// btCompoundCollisionAlgorithm supports collision between CompoundCollisionShapes and other collision shapes +/// Place holder, not fully implemented yet +class btCompoundCollisionAlgorithm : public btCollisionAlgorithm +{ + btAlignedObjectArray m_childCollisionAlgorithms; + bool m_isSwapped; + +public: + + btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); + + virtual ~btCompoundCollisionAlgorithm(); + + virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + struct CreateFunc :public btCollisionAlgorithmCreateFunc + { + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + return new btCompoundCollisionAlgorithm(ci,body0,body1,false); + } + }; + + struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc + { + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + return new btCompoundCollisionAlgorithm(ci,body0,body1,true); + } + }; + +}; + +#endif //COMPOUND_COLLISION_ALGORITHM_H diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp new file mode 100644 index 00000000000..24ceacfd40d --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp @@ -0,0 +1,312 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btConvexConcaveCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionShapes/btMultiSphereShape.h" +#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" +#include "BulletCollision/CollisionShapes/btConcaveShape.h" +#include "BulletCollision/CollisionDispatch/btManifoldResult.h" +#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" +#include "BulletCollision/CollisionShapes/btTriangleShape.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" +#include "LinearMath/btIDebugDraw.h" +#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" + +btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) +: btCollisionAlgorithm(ci), +m_isSwapped(isSwapped), +m_btConvexTriangleCallback(ci.m_dispatcher,body0,body1,isSwapped) +{ +} + +btConvexConcaveCollisionAlgorithm::~btConvexConcaveCollisionAlgorithm() +{ +} + + + +btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped): + m_dispatcher(dispatcher), + m_dispatchInfoPtr(0) +{ + m_convexBody = isSwapped? body1:body0; + m_triBody = isSwapped? body0:body1; + + // + // create the manifold from the dispatcher 'manifold pool' + // + m_manifoldPtr = m_dispatcher->getNewManifold(m_convexBody,m_triBody); + + clearCache(); +} + +btConvexTriangleCallback::~btConvexTriangleCallback() +{ + clearCache(); + m_dispatcher->releaseManifold( m_manifoldPtr ); + +} + + +void btConvexTriangleCallback::clearCache() +{ + m_dispatcher->clearManifold(m_manifoldPtr); +}; + + + +void btConvexTriangleCallback::processTriangle(btVector3* triangle,int partId, int triangleIndex) +{ + + //just for debugging purposes + //printf("triangle %d",m_triangleCount++); + + + //aabb filter is already applied! + + btCollisionAlgorithmConstructionInfo ci; + ci.m_dispatcher = m_dispatcher; + + btCollisionObject* ob = static_cast(m_triBody); + + + + ///debug drawing of the overlapping triangles + if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && m_dispatchInfoPtr->m_debugDraw->getDebugMode() > 0) + { + btVector3 color(255,255,0); + btTransform& tr = ob->getWorldTransform(); + m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color); + m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(triangle[2]),color); + m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(triangle[0]),color); + + //btVector3 center = triangle[0] + triangle[1]+triangle[2]; + //center *= btScalar(0.333333); + //m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(center),color); + //m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(center),color); + //m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(center),color); + + } + + + //btCollisionObject* colObj = static_cast(m_convexProxy->m_clientObject); + + if (m_convexBody->getCollisionShape()->isConvex()) + { + btTriangleShape tm(triangle[0],triangle[1],triangle[2]); + tm.setMargin(m_collisionMarginTriangle); + + + btCollisionShape* tmpShape = ob->getCollisionShape(); + ob->setCollisionShape( &tm ); + + + btCollisionAlgorithm* colAlgo = ci.m_dispatcher->findAlgorithm(m_convexBody,m_triBody,m_manifoldPtr); + ///this should use the btDispatcher, so the actual registered algorithm is used + // btConvexConvexAlgorithm cvxcvxalgo(m_manifoldPtr,ci,m_convexBody,m_triBody); + + m_resultOut->setShapeIdentifiers(-1,-1,partId,triangleIndex); + // cvxcvxalgo.setShapeIdentifiers(-1,-1,partId,triangleIndex); +// cvxcvxalgo.processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); + colAlgo->processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); + delete colAlgo; + ob->setCollisionShape( tmpShape ); + + } + + + +} + + + +void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + m_dispatchInfoPtr = &dispatchInfo; + m_collisionMarginTriangle = collisionMarginTriangle; + m_resultOut = resultOut; + + //recalc aabbs + btTransform convexInTriangleSpace; + convexInTriangleSpace = m_triBody->getWorldTransform().inverse() * m_convexBody->getWorldTransform(); + btCollisionShape* convexShape = static_cast(m_convexBody->getCollisionShape()); + //CollisionShape* triangleShape = static_cast(triBody->m_collisionShape); + convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax); + btScalar extraMargin = collisionMarginTriangle; + btVector3 extra(extraMargin,extraMargin,extraMargin); + + m_aabbMax += extra; + m_aabbMin -= extra; + +} + +void btConvexConcaveCollisionAlgorithm::clearCache() +{ + m_btConvexTriangleCallback.clearCache(); + +} + +void btConvexConcaveCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + + + btCollisionObject* convexBody = m_isSwapped ? body1 : body0; + btCollisionObject* triBody = m_isSwapped ? body0 : body1; + + if (triBody->getCollisionShape()->isConcave()) + { + + + btCollisionObject* triOb = triBody; + btConcaveShape* concaveShape = static_cast( triOb->getCollisionShape()); + + if (convexBody->getCollisionShape()->isConvex()) + { + btScalar collisionMarginTriangle = concaveShape->getMargin(); + + resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr); + m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle,dispatchInfo,resultOut); + + //Disable persistency. previously, some older algorithm calculated all contacts in one go, so you can clear it here. + //m_dispatcher->clearManifold(m_btConvexTriangleCallback.m_manifoldPtr); + + m_btConvexTriangleCallback.m_manifoldPtr->setBodies(convexBody,triBody); + + concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax()); + + + } + + } + +} + + +btScalar btConvexConcaveCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + (void)resultOut; + (void)dispatchInfo; + btCollisionObject* convexbody = m_isSwapped ? body1 : body0; + btCollisionObject* triBody = m_isSwapped ? body0 : body1; + + + //quick approximation using raycast, todo: hook up to the continuous collision detection (one of the btConvexCast) + + //only perform CCD above a certain threshold, this prevents blocking on the long run + //because object in a blocked ccd state (hitfraction<1) get their linear velocity halved each frame... + btScalar squareMot0 = (convexbody->getInterpolationWorldTransform().getOrigin() - convexbody->getWorldTransform().getOrigin()).length2(); + if (squareMot0 < convexbody->getCcdSquareMotionThreshold()) + { + return btScalar(1.); + } + + //const btVector3& from = convexbody->m_worldTransform.getOrigin(); + //btVector3 to = convexbody->m_interpolationWorldTransform.getOrigin(); + //todo: only do if the motion exceeds the 'radius' + + btTransform triInv = triBody->getWorldTransform().inverse(); + btTransform convexFromLocal = triInv * convexbody->getWorldTransform(); + btTransform convexToLocal = triInv * convexbody->getInterpolationWorldTransform(); + + struct LocalTriangleSphereCastCallback : public btTriangleCallback + { + btTransform m_ccdSphereFromTrans; + btTransform m_ccdSphereToTrans; + btTransform m_meshTransform; + + btScalar m_ccdSphereRadius; + btScalar m_hitFraction; + + + LocalTriangleSphereCastCallback(const btTransform& from,const btTransform& to,btScalar ccdSphereRadius,btScalar hitFraction) + :m_ccdSphereFromTrans(from), + m_ccdSphereToTrans(to), + m_ccdSphereRadius(ccdSphereRadius), + m_hitFraction(hitFraction) + { + } + + + virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) + { + (void)partId; + (void)triangleIndex; + //do a swept sphere for now + btTransform ident; + ident.setIdentity(); + btConvexCast::CastResult castResult; + castResult.m_fraction = m_hitFraction; + btSphereShape pointShape(m_ccdSphereRadius); + btTriangleShape triShape(triangle[0],triangle[1],triangle[2]); + btVoronoiSimplexSolver simplexSolver; + btSubsimplexConvexCast convexCaster(&pointShape,&triShape,&simplexSolver); + //GjkConvexCast convexCaster(&pointShape,convexShape,&simplexSolver); + //ContinuousConvexCollision convexCaster(&pointShape,convexShape,&simplexSolver,0); + //local space? + + if (convexCaster.calcTimeOfImpact(m_ccdSphereFromTrans,m_ccdSphereToTrans, + ident,ident,castResult)) + { + if (m_hitFraction > castResult.m_fraction) + m_hitFraction = castResult.m_fraction; + } + + } + + }; + + + + + + if (triBody->getCollisionShape()->isConcave()) + { + btVector3 rayAabbMin = convexFromLocal.getOrigin(); + rayAabbMin.setMin(convexToLocal.getOrigin()); + btVector3 rayAabbMax = convexFromLocal.getOrigin(); + rayAabbMax.setMax(convexToLocal.getOrigin()); + btScalar ccdRadius0 = convexbody->getCcdSweptSphereRadius(); + rayAabbMin -= btVector3(ccdRadius0,ccdRadius0,ccdRadius0); + rayAabbMax += btVector3(ccdRadius0,ccdRadius0,ccdRadius0); + + btScalar curHitFraction = btScalar(1.); //is this available? + LocalTriangleSphereCastCallback raycastCallback(convexFromLocal,convexToLocal, + convexbody->getCcdSweptSphereRadius(),curHitFraction); + + raycastCallback.m_hitFraction = convexbody->getHitFraction(); + + btCollisionObject* concavebody = triBody; + + btConcaveShape* triangleMesh = (btConcaveShape*) concavebody->getCollisionShape(); + + if (triangleMesh) + { + triangleMesh->processAllTriangles(&raycastCallback,rayAabbMin,rayAabbMax); + } + + + + if (raycastCallback.m_hitFraction < convexbody->getHitFraction()) + { + convexbody->setHitFraction( raycastCallback.m_hitFraction); + return raycastCallback.m_hitFraction; + } + } + + return btScalar(1.); + +} diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h new file mode 100644 index 00000000000..4915b6c20c8 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h @@ -0,0 +1,111 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef CONVEX_CONCAVE_COLLISION_ALGORITHM_H +#define CONVEX_CONCAVE_COLLISION_ALGORITHM_H + +#include "../BroadphaseCollision/btCollisionAlgorithm.h" +#include "../BroadphaseCollision/btDispatcher.h" +#include "../BroadphaseCollision/btBroadphaseInterface.h" +#include "../CollisionShapes/btTriangleCallback.h" +#include "../NarrowPhaseCollision/btPersistentManifold.h" +class btDispatcher; +#include "../BroadphaseCollision/btBroadphaseProxy.h" +#include "btCollisionCreateFunc.h" + +///For each triangle in the concave mesh that overlaps with the AABB of a convex (m_convexProxy), processTriangle is called. +class btConvexTriangleCallback : public btTriangleCallback +{ + btCollisionObject* m_convexBody; + btCollisionObject* m_triBody; + + btVector3 m_aabbMin; + btVector3 m_aabbMax ; + + btManifoldResult* m_resultOut; + + btDispatcher* m_dispatcher; + const btDispatcherInfo* m_dispatchInfoPtr; + btScalar m_collisionMarginTriangle; + +public: +int m_triangleCount; + + btPersistentManifold* m_manifoldPtr; + + btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); + + void setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + virtual ~btConvexTriangleCallback(); + + virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); + + void clearCache(); + + inline const btVector3& getAabbMin() const + { + return m_aabbMin; + } + inline const btVector3& getAabbMax() const + { + return m_aabbMax; + } + +}; + + + + +/// btConvexConcaveCollisionAlgorithm supports collision between convex shapes and (concave) trianges meshes. +class btConvexConcaveCollisionAlgorithm : public btCollisionAlgorithm +{ + + bool m_isSwapped; + + btConvexTriangleCallback m_btConvexTriangleCallback; + + +public: + + btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); + + virtual ~btConvexConcaveCollisionAlgorithm(); + + virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + void clearCache(); + + struct CreateFunc :public btCollisionAlgorithmCreateFunc + { + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + return new btConvexConcaveCollisionAlgorithm(ci,body0,body1,false); + } + }; + + struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc + { + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + return new btConvexConcaveCollisionAlgorithm(ci,body0,body1,true); + } + }; + +}; + +#endif //CONVEX_CONCAVE_COLLISION_ALGORITHM_H diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp new file mode 100644 index 00000000000..9105fe20b49 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp @@ -0,0 +1,254 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btConvexConvexAlgorithm.h" + +#include +#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" +#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionShapes/btConvexShape.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" +#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/CollisionShapes/btBoxShape.h" +#include "BulletCollision/CollisionDispatch/btManifoldResult.h" + +#include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" +#include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" +#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" + + + +#include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" +#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" + +#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" + +#include "BulletCollision/NarrowPhaseCollision/btGjkEpa.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" + + + + + + + +btConvexConvexAlgorithm::CreateFunc::CreateFunc() +{ + m_ownsSolvers = true; + m_simplexSolver = new btVoronoiSimplexSolver(); + m_pdSolver = new btGjkEpaPenetrationDepthSolver; +} + +btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) +{ + m_ownsSolvers = false; + m_simplexSolver = simplexSolver; + m_pdSolver = pdSolver; +} + +btConvexConvexAlgorithm::CreateFunc::~CreateFunc() +{ + if (m_ownsSolvers){ + delete m_simplexSolver; + delete m_pdSolver; + } +} + +btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) +: btCollisionAlgorithm(ci), +m_gjkPairDetector(0,0,simplexSolver,pdSolver), +m_ownManifold (false), +m_manifoldPtr(mf), +m_lowLevelOfDetail(false) +{ + (void)body0; + (void)body1; + + +} + + + + +btConvexConvexAlgorithm::~btConvexConvexAlgorithm() +{ + if (m_ownManifold) + { + if (m_manifoldPtr) + m_dispatcher->releaseManifold(m_manifoldPtr); + } +} + +void btConvexConvexAlgorithm ::setLowLevelOfDetail(bool useLowLevel) +{ + m_lowLevelOfDetail = useLowLevel; +} + + + + + +// +// Convex-Convex collision algorithm +// +void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + + if (!m_manifoldPtr) + { + //swapped? + m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); + m_ownManifold = true; + } + resultOut->setPersistentManifold(m_manifoldPtr); + +#ifdef USE_BT_GJKEPA + btConvexShape* shape0(static_cast(body0->getCollisionShape())); + btConvexShape* shape1(static_cast(body1->getCollisionShape())); + const btScalar radialmargin(0/*shape0->getMargin()+shape1->getMargin()*/); + btGjkEpaSolver::sResults results; + if(btGjkEpaSolver::Collide( shape0,body0->getWorldTransform(), + shape1,body1->getWorldTransform(), + radialmargin,results)) + { + dispatchInfo.m_debugDraw->drawLine(results.witnesses[1],results.witnesses[1]+results.normal,btVector3(255,0,0)); + resultOut->addContactPoint(results.normal,results.witnesses[1],-results.depth); + } +#else + + btConvexShape* min0 = static_cast(body0->getCollisionShape()); + btConvexShape* min1 = static_cast(body1->getCollisionShape()); + + btGjkPairDetector::ClosestPointInput input; + + //TODO: if (dispatchInfo.m_useContinuous) + m_gjkPairDetector.setMinkowskiA(min0); + m_gjkPairDetector.setMinkowskiB(min1); + input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); + input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; + input.m_stackAlloc = dispatchInfo.m_stackAllocator; + +// input.m_maximumDistanceSquared = btScalar(1e30); + + input.m_transformA = body0->getWorldTransform(); + input.m_transformB = body1->getWorldTransform(); + + m_gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); +#endif + +} + + + +bool disableCcd = false; +btScalar btConvexConvexAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + (void)resultOut; + (void)dispatchInfo; + ///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold + + ///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold + ///col0->m_worldTransform, + btScalar resultFraction = btScalar(1.); + + + btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2(); + btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2(); + + if (squareMot0 < col0->getCcdSquareMotionThreshold() && + squareMot1 < col1->getCcdSquareMotionThreshold()) + return resultFraction; + + if (disableCcd) + return btScalar(1.); + + + //An adhoc way of testing the Continuous Collision Detection algorithms + //One object is approximated as a sphere, to simplify things + //Starting in penetration should report no time of impact + //For proper CCD, better accuracy and handling of 'allowed' penetration should be added + //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies) + + + /// Convex0 against sphere for Convex1 + { + btConvexShape* convex0 = static_cast(col0->getCollisionShape()); + + btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation + btConvexCast::CastResult result; + btVoronoiSimplexSolver voronoiSimplex; + //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); + ///Simplification, one object is simplified as a sphere + btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex); + //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); + if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), + col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) + { + + //store result.m_fraction in both bodies + + if (col0->getHitFraction()> result.m_fraction) + col0->setHitFraction( result.m_fraction ); + + if (col1->getHitFraction() > result.m_fraction) + col1->setHitFraction( result.m_fraction); + + if (resultFraction > result.m_fraction) + resultFraction = result.m_fraction; + + } + + + + + } + + /// Sphere (for convex0) against Convex1 + { + btConvexShape* convex1 = static_cast(col1->getCollisionShape()); + + btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation + btConvexCast::CastResult result; + btVoronoiSimplexSolver voronoiSimplex; + //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); + ///Simplification, one object is simplified as a sphere + btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex); + //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); + if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), + col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) + { + + //store result.m_fraction in both bodies + + if (col0->getHitFraction() > result.m_fraction) + col0->setHitFraction( result.m_fraction); + + if (col1->getHitFraction() > result.m_fraction) + col1->setHitFraction( result.m_fraction); + + if (resultFraction > result.m_fraction) + resultFraction = result.m_fraction; + + } + } + + return resultFraction; + +} + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h new file mode 100644 index 00000000000..cbea9a92b75 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h @@ -0,0 +1,76 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef CONVEX_CONVEX_ALGORITHM_H +#define CONVEX_CONVEX_ALGORITHM_H + +#include "../BroadphaseCollision/btCollisionAlgorithm.h" +#include "../NarrowPhaseCollision/btGjkPairDetector.h" +#include "../NarrowPhaseCollision/btPersistentManifold.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" +#include "../NarrowPhaseCollision/btVoronoiSimplexSolver.h" +#include "btCollisionCreateFunc.h" + +class btConvexPenetrationDepthSolver; + +///ConvexConvexAlgorithm collision algorithm implements time of impact, convex closest points and penetration depth calculations. +class btConvexConvexAlgorithm : public btCollisionAlgorithm +{ + btGjkPairDetector m_gjkPairDetector; +public: + + bool m_ownManifold; + btPersistentManifold* m_manifoldPtr; + bool m_lowLevelOfDetail; + + +public: + + btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); + + virtual ~btConvexConvexAlgorithm(); + + virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + void setLowLevelOfDetail(bool useLowLevel); + + + const btPersistentManifold* getManifold() + { + return m_manifoldPtr; + } + + struct CreateFunc :public btCollisionAlgorithmCreateFunc + { + btConvexPenetrationDepthSolver* m_pdSolver; + btSimplexSolverInterface* m_simplexSolver; + bool m_ownsSolvers; + + CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); + CreateFunc(); + virtual ~CreateFunc(); + + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + return new btConvexConvexAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver); + } + }; + + +}; + +#endif //CONVEX_CONVEX_ALGORITHM_H diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp new file mode 100644 index 00000000000..936054387c4 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp @@ -0,0 +1,34 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btEmptyCollisionAlgorithm.h" + + + +btEmptyAlgorithm::btEmptyAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) + : btCollisionAlgorithm(ci) +{ +} + +void btEmptyAlgorithm::processCollision (btCollisionObject* ,btCollisionObject* ,const btDispatcherInfo& ,btManifoldResult* ) +{ +} + +btScalar btEmptyAlgorithm::calculateTimeOfImpact(btCollisionObject* ,btCollisionObject* ,const btDispatcherInfo& ,btManifoldResult* ) +{ + return btScalar(1.); +} + + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h new file mode 100644 index 00000000000..b1a193d2cfd --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h @@ -0,0 +1,48 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef EMPTY_ALGORITH +#define EMPTY_ALGORITH +#include "../BroadphaseCollision/btCollisionAlgorithm.h" +#include "btCollisionCreateFunc.h" + +#define ATTRIBUTE_ALIGNED(a) + +///EmptyAlgorithm is a stub for unsupported collision pairs. +///The dispatcher can dispatch a persistent btEmptyAlgorithm to avoid a search every frame. +class btEmptyAlgorithm : public btCollisionAlgorithm +{ + +public: + + btEmptyAlgorithm(const btCollisionAlgorithmConstructionInfo& ci); + + virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + struct CreateFunc :public btCollisionAlgorithmCreateFunc + { + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + (void)body0; + (void)body1; + return new btEmptyAlgorithm(ci); + } + }; + +} ATTRIBUTE_ALIGNED(16); + +#endif //EMPTY_ALGORITH diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp new file mode 100644 index 00000000000..490acc0b611 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp @@ -0,0 +1,109 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btManifoldResult.h" +#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" + + +///This is to allow MaterialCombiner/Custom Friction/Restitution values +ContactAddedCallback gContactAddedCallback=0; + +///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback; +inline btScalar calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1) +{ + btScalar friction = body0->getFriction() * body1->getFriction(); + + const btScalar MAX_FRICTION = btScalar(10.); + if (friction < -MAX_FRICTION) + friction = -MAX_FRICTION; + if (friction > MAX_FRICTION) + friction = MAX_FRICTION; + return friction; + +} + +inline btScalar calculateCombinedRestitution(const btCollisionObject* body0,const btCollisionObject* body1) +{ + return body0->getRestitution() * body1->getRestitution(); +} + + + +btManifoldResult::btManifoldResult(btCollisionObject* body0,btCollisionObject* body1) + :m_manifoldPtr(0), + m_body0(body0), + m_body1(body1) +{ + m_rootTransA = body0->getWorldTransform(); + m_rootTransB = body1->getWorldTransform(); +} + + +void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) +{ + assert(m_manifoldPtr); + //order in manifold needs to match + + if (depth > m_manifoldPtr->getContactBreakingThreshold()) + return; + + bool isSwapped = m_manifoldPtr->getBody0() != m_body0; + + btVector3 pointA = pointInWorld + normalOnBInWorld * depth; + + btVector3 localA; + btVector3 localB; + + if (isSwapped) + { + localA = m_rootTransB.invXform(pointA ); + localB = m_rootTransA.invXform(pointInWorld); + } else + { + localA = m_rootTransA.invXform(pointA ); + localB = m_rootTransB.invXform(pointInWorld); + } + + btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth); + + int insertIndex = m_manifoldPtr->getCacheEntry(newPt); + + newPt.m_combinedFriction = calculateCombinedFriction(m_body0,m_body1); + newPt.m_combinedRestitution = calculateCombinedRestitution(m_body0,m_body1); + + //User can override friction and/or restitution + if (gContactAddedCallback && + //and if either of the two bodies requires custom material + ((m_body0->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK) || + (m_body1->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK))) + { + //experimental feature info, for per-triangle material etc. + btCollisionObject* obj0 = isSwapped? m_body1 : m_body0; + btCollisionObject* obj1 = isSwapped? m_body0 : m_body1; + (*gContactAddedCallback)(newPt,obj0,m_partId0,m_index0,obj1,m_partId1,m_index1); + } + + if (insertIndex >= 0) + { + //const btManifoldPoint& oldPoint = m_manifoldPtr->getContactPoint(insertIndex); + m_manifoldPtr->replaceContactPoint(newPt,insertIndex); + } else + { + m_manifoldPtr->AddManifoldPoint(newPt); + } +} + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.h new file mode 100644 index 00000000000..77192625513 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.h @@ -0,0 +1,77 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef MANIFOLD_RESULT_H +#define MANIFOLD_RESULT_H + +class btCollisionObject; +class btPersistentManifold; +class btManifoldPoint; + +#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" + +#include "../../LinearMath/btTransform.h" + +typedef bool (*ContactAddedCallback)(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1); +extern ContactAddedCallback gContactAddedCallback; + + + +///btManifoldResult is a helper class to manage contact results. +class btManifoldResult : public btDiscreteCollisionDetectorInterface::Result +{ + btPersistentManifold* m_manifoldPtr; + + //we need this for compounds + btTransform m_rootTransA; + btTransform m_rootTransB; + + btCollisionObject* m_body0; + btCollisionObject* m_body1; + int m_partId0; + int m_partId1; + int m_index0; + int m_index1; +public: + + btManifoldResult() + { + } + + btManifoldResult(btCollisionObject* body0,btCollisionObject* body1); + + virtual ~btManifoldResult() {}; + + void setPersistentManifold(btPersistentManifold* manifoldPtr) + { + m_manifoldPtr = manifoldPtr; + } + + virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1) + { + m_partId0=partId0; + m_partId1=partId1; + m_index0=index0; + m_index1=index1; + } + + virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth); + + + +}; + +#endif //MANIFOLD_RESULT_H diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp new file mode 100644 index 00000000000..ac2e8554c3a --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp @@ -0,0 +1,357 @@ + + +#include "LinearMath/btScalar.h" +#include "btSimulationIslandManager.h" +#include "BulletCollision/BroadphaseCollision/btDispatcher.h" +#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" + +#include +#include "LinearMath/btQuickprof.h" + +btSimulationIslandManager::btSimulationIslandManager() +{ +} + +btSimulationIslandManager::~btSimulationIslandManager() +{ +} + + +void btSimulationIslandManager::initUnionFind(int n) +{ + m_unionFind.reset(n); +} + + +void btSimulationIslandManager::findUnions(btDispatcher* dispatcher) +{ + + { + for (int i=0;igetNumManifolds();i++) + { + const btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i); + //static objects (invmass btScalar(0.)) don't merge ! + + const btCollisionObject* colObj0 = static_cast(manifold->getBody0()); + const btCollisionObject* colObj1 = static_cast(manifold->getBody1()); + + if (((colObj0) && ((colObj0)->mergesSimulationIslands())) && + ((colObj1) && ((colObj1)->mergesSimulationIslands()))) + { + + m_unionFind.unite((colObj0)->getIslandTag(), + (colObj1)->getIslandTag()); + } + } + } +} + + +void btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher) +{ + + initUnionFind( int (colWorld->getCollisionObjectArray().size())); + + // put the index into m_controllers into m_tag + { + + int index = 0; + int i; + for (i=0;igetCollisionObjectArray().size(); i++) + { + btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; + collisionObject->setIslandTag(index); + collisionObject->setCompanionId(-1); + collisionObject->setHitFraction(btScalar(1.)); + index++; + + } + } + // do the union find + + findUnions(dispatcher); + + + +} + + + + +void btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld) +{ + // put the islandId ('find' value) into m_tag + { + + + int index = 0; + int i; + for (i=0;igetCollisionObjectArray().size();i++) + { + btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; + if (collisionObject->mergesSimulationIslands()) + { + collisionObject->setIslandTag( m_unionFind.find(index) ); + collisionObject->setCompanionId(-1); + } else + { + collisionObject->setIslandTag(-1); + collisionObject->setCompanionId(-2); + } + index++; + } + } +} + +inline int getIslandId(const btPersistentManifold* lhs) +{ + int islandId; + const btCollisionObject* rcolObj0 = static_cast(lhs->getBody0()); + const btCollisionObject* rcolObj1 = static_cast(lhs->getBody1()); + islandId= rcolObj0->getIslandTag()>=0?rcolObj0->getIslandTag():rcolObj1->getIslandTag(); + return islandId; + +} + + + +/// function object that routes calls to operator< +class btPersistentManifoldSortPredicate +{ + public: + + SIMD_FORCE_INLINE bool operator() ( const btPersistentManifold* lhs, const btPersistentManifold* rhs ) + { + return getIslandId(lhs) < getIslandId(rhs); + } +}; + + + + + +// +// todo: this is random access, it can be walked 'cache friendly'! +// +void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionObjectArray& collisionObjects, IslandCallback* callback) +{ + + + + /*if (0) + { + int maxNumManifolds = dispatcher->getNumManifolds(); + btCollisionDispatcher* colDis = (btCollisionDispatcher*)dispatcher; + btPersistentManifold** manifold = colDis->getInternalManifoldPointer(); + callback->ProcessIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, 0); + return; + } + */ + + + BEGIN_PROFILE("islandUnionFindAndHeapSort"); + + //we are going to sort the unionfind array, and store the element id in the size + //afterwards, we clean unionfind, to make sure no-one uses it anymore + + getUnionFind().sortIslands(); + int numElem = getUnionFind().getNumElements(); + + int endIslandIndex=1; + int startIslandIndex; + + + //update the sleeping state for bodies, if all are sleeping + for ( startIslandIndex=0;startIslandIndexgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) + { + printf("error in island management\n"); + } + + assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); + if (colObj0->getIslandTag() == islandId) + { + if (colObj0->getActivationState()== ACTIVE_TAG) + { + allSleeping = false; + } + if (colObj0->getActivationState()== DISABLE_DEACTIVATION) + { + allSleeping = false; + } + } + } + + + if (allSleeping) + { + int idx; + for (idx=startIslandIndex;idxgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) + { + printf("error in island management\n"); + } + + assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); + + if (colObj0->getIslandTag() == islandId) + { + colObj0->setActivationState( ISLAND_SLEEPING ); + } + } + } else + { + + int idx; + for (idx=startIslandIndex;idxgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) + { + printf("error in island management\n"); + } + + assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); + + if (colObj0->getIslandTag() == islandId) + { + if ( colObj0->getActivationState() == ISLAND_SLEEPING) + { + colObj0->setActivationState( WANTS_DEACTIVATION); + } + } + } + } + } + + btAlignedObjectArray islandmanifold; + int i; + int maxNumManifolds = dispatcher->getNumManifolds(); + islandmanifold.reserve(maxNumManifolds); + + for (i=0;igetManifoldByIndexInternal(i); + + btCollisionObject* colObj0 = static_cast(manifold->getBody0()); + btCollisionObject* colObj1 = static_cast(manifold->getBody1()); + + //todo: check sleeping conditions! + if (((colObj0) && colObj0->getActivationState() != ISLAND_SLEEPING) || + ((colObj1) && colObj1->getActivationState() != ISLAND_SLEEPING)) + { + + //kinematic objects don't merge islands, but wake up all connected objects + if (colObj0->isStaticOrKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING) + { + colObj1->activate(); + } + if (colObj1->isStaticOrKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING) + { + colObj0->activate(); + } + + //filtering for response + if (dispatcher->needsResponse(colObj0,colObj1)) + islandmanifold.push_back(manifold); + } + } + + int numManifolds = int (islandmanifold.size()); + + // Sort manifolds, based on islands + // Sort the vector using predicate and std::sort + //std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate); + + //we should do radix sort, it it much faster (O(n) instead of O (n log2(n)) + islandmanifold.heapSort(btPersistentManifoldSortPredicate()); + + //now process all active islands (sets of manifolds for now) + + int startManifoldIndex = 0; + int endManifoldIndex = 1; + + //int islandId; + + END_PROFILE("islandUnionFindAndHeapSort"); + + btAlignedObjectArray islandBodies; + + + //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated + for ( startIslandIndex=0;startIslandIndexisActive()) + islandSleeping = true; + } + + + //find the accompanying contact manifold for this islandId + int numIslandManifolds = 0; + btPersistentManifold** startManifold = 0; + + if (startManifoldIndexProcessIsland(&islandBodies[0],islandBodies.size(),startManifold,numIslandManifolds, islandId); + } + + if (numIslandManifolds) + { + startManifoldIndex = endManifoldIndex; + } + + islandBodies.resize(0); + } + + +} diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h new file mode 100644 index 00000000000..d91ed1c20eb --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h @@ -0,0 +1,61 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SIMULATION_ISLAND_MANAGER_H +#define SIMULATION_ISLAND_MANAGER_H + +#include "../CollisionDispatch/btUnionFind.h" +#include "btCollisionCreateFunc.h" + +class btCollisionObject; +class btCollisionWorld; +class btDispatcher; + +///SimulationIslandManager creates and handles simulation islands, using btUnionFind +class btSimulationIslandManager +{ + btUnionFind m_unionFind; + +public: + btSimulationIslandManager(); + virtual ~btSimulationIslandManager(); + + + void initUnionFind(int n); + + + btUnionFind& getUnionFind() { return m_unionFind;} + + virtual void updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher); + virtual void storeIslandActivationState(btCollisionWorld* world); + + + void findUnions(btDispatcher* dispatcher); + + + + struct IslandCallback + { + virtual ~IslandCallback() {}; + + virtual void ProcessIsland(btCollisionObject** bodies,int numBodies,class btPersistentManifold** manifolds,int numManifolds, int islandId) = 0; + }; + + void buildAndProcessIslands(btDispatcher* dispatcher,btCollisionObjectArray& collisionObjects, IslandCallback* callback); + +}; + +#endif //SIMULATION_ISLAND_MANAGER_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp new file mode 100644 index 00000000000..05556bd34e2 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp @@ -0,0 +1,249 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btSphereBoxCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" +#include "BulletCollision/CollisionShapes/btBoxShape.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +//#include + +btSphereBoxCollisionAlgorithm::btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped) +: btCollisionAlgorithm(ci), +m_ownManifold(false), +m_manifoldPtr(mf), +m_isSwapped(isSwapped) +{ + btCollisionObject* sphereObj = m_isSwapped? col1 : col0; + btCollisionObject* boxObj = m_isSwapped? col0 : col1; + + if (!m_manifoldPtr && m_dispatcher->needsCollision(sphereObj,boxObj)) + { + m_manifoldPtr = m_dispatcher->getNewManifold(sphereObj,boxObj); + m_ownManifold = true; + } +} + + +btSphereBoxCollisionAlgorithm::~btSphereBoxCollisionAlgorithm() +{ + if (m_ownManifold) + { + if (m_manifoldPtr) + m_dispatcher->releaseManifold(m_manifoldPtr); + } +} + + + +void btSphereBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + (void)dispatchInfo; + (void)resultOut; + if (!m_manifoldPtr) + return; + + btCollisionObject* sphereObj = m_isSwapped? body1 : body0; + btCollisionObject* boxObj = m_isSwapped? body0 : body1; + + + btSphereShape* sphere0 = (btSphereShape*)sphereObj->getCollisionShape(); + + btVector3 normalOnSurfaceB; + btVector3 pOnBox,pOnSphere; + btVector3 sphereCenter = sphereObj->getWorldTransform().getOrigin(); + btScalar radius = sphere0->getRadius(); + + btScalar dist = getSphereDistance(boxObj,pOnBox,pOnSphere,sphereCenter,radius); + + if (dist < SIMD_EPSILON) + { + btVector3 normalOnSurfaceB = (pOnBox- pOnSphere).normalize(); + + /// report a contact. internally this will be kept persistent, and contact reduction is done + + resultOut->setPersistentManifold(m_manifoldPtr); + resultOut->addContactPoint(normalOnSurfaceB,pOnBox,dist); + + } + + + +} + +btScalar btSphereBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + (void)resultOut; + (void)dispatchInfo; + (void)col0; + (void)col1; + + //not yet + return btScalar(1.); +} + + +btScalar btSphereBoxCollisionAlgorithm::getSphereDistance(btCollisionObject* boxObj, btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius ) +{ + + btScalar margins; + btVector3 bounds[2]; + btBoxShape* boxShape= (btBoxShape*)boxObj->getCollisionShape(); + + bounds[0] = -boxShape->getHalfExtents(); + bounds[1] = boxShape->getHalfExtents(); + + margins = boxShape->getMargin();//also add sphereShape margin? + + const btTransform& m44T = boxObj->getWorldTransform(); + + btVector3 boundsVec[2]; + btScalar fPenetration; + + boundsVec[0] = bounds[0]; + boundsVec[1] = bounds[1]; + + btVector3 marginsVec( margins, margins, margins ); + + // add margins + bounds[0] += marginsVec; + bounds[1] -= marginsVec; + + ///////////////////////////////////////////////// + + btVector3 tmp, prel, n[6], normal, v3P; + btScalar fSep = btScalar(10000000.0), fSepThis; + + n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); + n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); + n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); + n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) ); + n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) ); + n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) ); + + // convert point in local space + prel = m44T.invXform( sphereCenter); + + bool bFound = false; + + v3P = prel; + + for (int i=0;i<6;i++) + { + int j = i<3? 0:1; + if ( (fSepThis = ((v3P-bounds[j]) .dot(n[i]))) > btScalar(0.0) ) + { + v3P = v3P - n[i]*fSepThis; + bFound = true; + } + } + + // + + if ( bFound ) + { + bounds[0] = boundsVec[0]; + bounds[1] = boundsVec[1]; + + normal = (prel - v3P).normalize(); + pointOnBox = v3P + normal*margins; + v3PointOnSphere = prel - normal*fRadius; + + if ( ((v3PointOnSphere - pointOnBox) .dot (normal)) > btScalar(0.0) ) + { + return btScalar(1.0); + } + + // transform back in world space + tmp = m44T( pointOnBox); + pointOnBox = tmp; + tmp = m44T( v3PointOnSphere); + v3PointOnSphere = tmp; + btScalar fSeps2 = (pointOnBox-v3PointOnSphere).length2(); + + //if this fails, fallback into deeper penetration case, below + if (fSeps2 > SIMD_EPSILON) + { + fSep = - btSqrt(fSeps2); + normal = (pointOnBox-v3PointOnSphere); + normal *= btScalar(1.)/fSep; + } + + return fSep; + } + + ////////////////////////////////////////////////// + // Deep penetration case + + fPenetration = getSpherePenetration( boxObj,pointOnBox, v3PointOnSphere, sphereCenter, fRadius,bounds[0],bounds[1] ); + + bounds[0] = boundsVec[0]; + bounds[1] = boundsVec[1]; + + if ( fPenetration <= btScalar(0.0) ) + return (fPenetration-margins); + else + return btScalar(1.0); +} + +btScalar btSphereBoxCollisionAlgorithm::getSpherePenetration( btCollisionObject* boxObj,btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax) +{ + + btVector3 bounds[2]; + + bounds[0] = aabbMin; + bounds[1] = aabbMax; + + btVector3 p0, tmp, prel, n[6], normal; + btScalar fSep = btScalar(-10000000.0), fSepThis; + + n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); + n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); + n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); + n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) ); + n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) ); + n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) ); + + const btTransform& m44T = boxObj->getWorldTransform(); + + // convert point in local space + prel = m44T.invXform( sphereCenter); + + /////////// + + for (int i=0;i<6;i++) + { + int j = i<3 ? 0:1; + if ( (fSepThis = ((prel-bounds[j]) .dot( n[i]))-fRadius) > btScalar(0.0) ) return btScalar(1.0); + if ( fSepThis > fSep ) + { + p0 = bounds[j]; normal = (btVector3&)n[i]; + fSep = fSepThis; + } + } + + pointOnBox = prel - normal*(normal.dot((prel-p0))); + v3PointOnSphere = pointOnBox + normal*fSep; + + // transform back in world space + tmp = m44T( pointOnBox); + pointOnBox = tmp; + tmp = m44T( v3PointOnSphere); v3PointOnSphere = tmp; + normal = (pointOnBox-v3PointOnSphere).normalize(); + + return fSep; + +} + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h new file mode 100644 index 00000000000..07592909200 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h @@ -0,0 +1,64 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SPHERE_BOX_COLLISION_ALGORITHM_H +#define SPHERE_BOX_COLLISION_ALGORITHM_H + +#include "../BroadphaseCollision/btCollisionAlgorithm.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" +#include "../CollisionDispatch/btCollisionCreateFunc.h" +class btPersistentManifold; +#include "../../LinearMath/btVector3.h" + +/// btSphereBoxCollisionAlgorithm provides sphere-box collision detection. +/// Other features are frame-coherency (persistent data) and collision response. +class btSphereBoxCollisionAlgorithm : public btCollisionAlgorithm +{ + bool m_ownManifold; + btPersistentManifold* m_manifoldPtr; + bool m_isSwapped; + +public: + + btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped); + + virtual ~btSphereBoxCollisionAlgorithm(); + + virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + btScalar getSphereDistance( btCollisionObject* boxObj,btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius ); + + btScalar getSpherePenetration( btCollisionObject* boxObj, btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax); + + struct CreateFunc :public btCollisionAlgorithmCreateFunc + { + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + if (!m_swapped) + { + return new btSphereBoxCollisionAlgorithm(0,ci,body0,body1,false); + } else + { + return new btSphereBoxCollisionAlgorithm(0,ci,body0,body1,true); + } + } + }; + +}; + +#endif //SPHERE_BOX_COLLISION_ALGORITHM_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp new file mode 100644 index 00000000000..424ff432f84 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp @@ -0,0 +1,85 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btSphereSphereCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" + +btSphereSphereCollisionAlgorithm::btSphereSphereCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1) +: btCollisionAlgorithm(ci), +m_ownManifold(false), +m_manifoldPtr(mf) +{ + if (!m_manifoldPtr) + { + m_manifoldPtr = m_dispatcher->getNewManifold(col0,col1); + m_ownManifold = true; + } +} + +btSphereSphereCollisionAlgorithm::~btSphereSphereCollisionAlgorithm() +{ + if (m_ownManifold) + { + if (m_manifoldPtr) + m_dispatcher->releaseManifold(m_manifoldPtr); + } +} + +void btSphereSphereCollisionAlgorithm::processCollision (btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + (void)dispatchInfo; + + if (!m_manifoldPtr) + return; + + btSphereShape* sphere0 = (btSphereShape*)col0->getCollisionShape(); + btSphereShape* sphere1 = (btSphereShape*)col1->getCollisionShape(); + + btVector3 diff = col0->getWorldTransform().getOrigin()- col1->getWorldTransform().getOrigin(); + btScalar len = diff.length(); + btScalar radius0 = sphere0->getRadius(); + btScalar radius1 = sphere1->getRadius(); + + ///iff distance positive, don't generate a new contact + if ( len > (radius0+radius1)) + return; + + ///distance (negative means penetration) + btScalar dist = len - (radius0+radius1); + + btVector3 normalOnSurfaceB = diff / len; + ///point on A (worldspace) + btVector3 pos0 = col0->getWorldTransform().getOrigin() - radius0 * normalOnSurfaceB; + ///point on B (worldspace) + btVector3 pos1 = col1->getWorldTransform().getOrigin() + radius1* normalOnSurfaceB; + + /// report a contact. internally this will be kept persistent, and contact reduction is done + resultOut->setPersistentManifold(m_manifoldPtr); + resultOut->addContactPoint(normalOnSurfaceB,pos1,dist); + +} + +btScalar btSphereSphereCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + (void)col0; + (void)col1; + (void)dispatchInfo; + (void)resultOut; + + //not yet + return btScalar(1.); +} diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h new file mode 100644 index 00000000000..7a19ff31edf --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h @@ -0,0 +1,56 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SPHERE_SPHERE_COLLISION_ALGORITHM_H +#define SPHERE_SPHERE_COLLISION_ALGORITHM_H + +#include "../BroadphaseCollision/btCollisionAlgorithm.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" +#include "../CollisionDispatch/btCollisionCreateFunc.h" +class btPersistentManifold; + +/// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. +/// Other features are frame-coherency (persistent data) and collision response. +/// Also provides the most basic sample for custom/user btCollisionAlgorithm +class btSphereSphereCollisionAlgorithm : public btCollisionAlgorithm +{ + bool m_ownManifold; + btPersistentManifold* m_manifoldPtr; + +public: + btSphereSphereCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); + + btSphereSphereCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) + : btCollisionAlgorithm(ci) {} + + virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + + virtual ~btSphereSphereCollisionAlgorithm(); + + struct CreateFunc :public btCollisionAlgorithmCreateFunc + { + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + return new btSphereSphereCollisionAlgorithm(0,ci,body0,body1); + } + }; + +}; + +#endif //SPHERE_SPHERE_COLLISION_ALGORITHM_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp new file mode 100644 index 00000000000..b011b707e3f --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp @@ -0,0 +1,76 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btSphereTriangleCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "SphereTriangleDetector.h" + + +btSphereTriangleCollisionAlgorithm::btSphereTriangleCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1,bool swapped) +: btCollisionAlgorithm(ci), +m_ownManifold(false), +m_manifoldPtr(mf), +m_swapped(swapped) +{ + if (!m_manifoldPtr) + { + m_manifoldPtr = m_dispatcher->getNewManifold(col0,col1); + m_ownManifold = true; + } +} + +btSphereTriangleCollisionAlgorithm::~btSphereTriangleCollisionAlgorithm() +{ + if (m_ownManifold) + { + if (m_manifoldPtr) + m_dispatcher->releaseManifold(m_manifoldPtr); + } +} + +void btSphereTriangleCollisionAlgorithm::processCollision (btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + if (!m_manifoldPtr) + return; + + btSphereShape* sphere = (btSphereShape*)col0->getCollisionShape(); + btTriangleShape* triangle = (btTriangleShape*)col1->getCollisionShape(); + + /// report a contact. internally this will be kept persistent, and contact reduction is done + resultOut->setPersistentManifold(m_manifoldPtr); + SphereTriangleDetector detector(sphere,triangle); + + btDiscreteCollisionDetectorInterface::ClosestPointInput input; + input.m_maximumDistanceSquared = btScalar(1e30);//todo: tighter bounds + input.m_transformA = col0->getWorldTransform(); + input.m_transformB = col1->getWorldTransform(); + + detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); + +} + +btScalar btSphereTriangleCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + (void)resultOut; + (void)dispatchInfo; + (void)col0; + (void)col1; + + //not yet + return btScalar(1.); +} diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h new file mode 100644 index 00000000000..57c6e6af619 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h @@ -0,0 +1,59 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SPHERE_TRIANGLE_COLLISION_ALGORITHM_H +#define SPHERE_TRIANGLE_COLLISION_ALGORITHM_H + +#include "../BroadphaseCollision/btCollisionAlgorithm.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" +#include "../CollisionDispatch/btCollisionCreateFunc.h" +class btPersistentManifold; + +/// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. +/// Other features are frame-coherency (persistent data) and collision response. +/// Also provides the most basic sample for custom/user btCollisionAlgorithm +class btSphereTriangleCollisionAlgorithm : public btCollisionAlgorithm +{ + bool m_ownManifold; + btPersistentManifold* m_manifoldPtr; + bool m_swapped; + +public: + btSphereTriangleCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool swapped); + + btSphereTriangleCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) + : btCollisionAlgorithm(ci) {} + + virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); + + + virtual ~btSphereTriangleCollisionAlgorithm(); + + struct CreateFunc :public btCollisionAlgorithmCreateFunc + { + + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) + { + + return new btSphereTriangleCollisionAlgorithm(ci.m_manifold,ci,body0,body1,m_swapped); + } + }; + +}; + +#endif //SPHERE_TRIANGLE_COLLISION_ALGORITHM_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.cpp new file mode 100644 index 00000000000..62254335796 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.cpp @@ -0,0 +1,83 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btUnionFind.h" +#include + + + +btUnionFind::~btUnionFind() +{ + Free(); + +} + +btUnionFind::btUnionFind() +{ + +} + +void btUnionFind::allocate(int N) +{ + m_elements.resize(N); +} +void btUnionFind::Free() +{ + m_elements.clear(); +} + + +void btUnionFind::reset(int N) +{ + allocate(N); + + for (int i = 0; i < N; i++) + { + m_elements[i].m_id = i; m_elements[i].m_sz = 1; + } +} + + +class btUnionFindElementSortPredicate +{ + public: + + bool operator() ( const btElement& lhs, const btElement& rhs ) + { + return lhs.m_id < rhs.m_id; + } +}; + +///this is a special operation, destroying the content of btUnionFind. +///it sorts the elements, based on island id, in order to make it easy to iterate over islands +void btUnionFind::sortIslands() +{ + + //first store the original body index, and islandId + int numElements = m_elements.size(); + + for (int i=0;i m_elements; + + public: + + btUnionFind(); + ~btUnionFind(); + + + //this is a special operation, destroying the content of btUnionFind. + //it sorts the elements, based on island id, in order to make it easy to iterate over islands + void sortIslands(); + + void reset(int N); + + inline int getNumElements() const + { + return int(m_elements.size()); + } + inline bool isRoot(int x) const + { + return (x == m_elements[x].m_id); + } + + btElement& getElement(int index) + { + return m_elements[index]; + } + const btElement& getElement(int index) const + { + return m_elements[index]; + } + + void allocate(int N); + void Free(); + + + + + int find(int p, int q) + { + return (find(p) == find(q)); + } + + void unite(int p, int q) + { + int i = find(p), j = find(q); + if (i == j) + return; + +#ifndef USE_PATH_COMPRESSION + //weighted quick union, this keeps the 'trees' balanced, and keeps performance of unite O( log(n) ) + if (m_elements[i].m_sz < m_elements[j].m_sz) + { + m_elements[i].m_id = j; m_elements[j].m_sz += m_elements[i].m_sz; + } + else + { + m_elements[j].m_id = i; m_elements[i].m_sz += m_elements[j].m_sz; + } +#else + m_elements[i].m_id = j; m_elements[j].m_sz += m_elements[i].m_sz; +#endif //USE_PATH_COMPRESSION + } + + int find(int x) + { + //assert(x < m_N); + //assert(x >= 0); + + while (x != m_elements[x].m_id) + { + //not really a reason not to use path compression, and it flattens the trees/improves find performance dramatically + + #ifdef USE_PATH_COMPRESSION + // + m_elements[x].m_id = m_elements[m_elements[x].m_id].m_id; + #endif // + x = m_elements[x].m_id; + //assert(x < m_N); + //assert(x >= 0); + + } + return x; + } + + + }; + + +#endif //UNION_FIND_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.cpp new file mode 100644 index 00000000000..636b0046c13 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.cpp @@ -0,0 +1,57 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btBoxShape.h" + +btVector3 btBoxShape::getHalfExtents() const +{ + return m_implicitShapeDimensions * m_localScaling; +} +//{ + + +void btBoxShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const +{ + btVector3 halfExtents = getHalfExtents(); + + btMatrix3x3 abs_b = t.getBasis().absolute(); + btPoint3 center = t.getOrigin(); + btVector3 extent = btVector3(abs_b[0].dot(halfExtents), + abs_b[1].dot(halfExtents), + abs_b[2].dot(halfExtents)); + extent += btVector3(getMargin(),getMargin(),getMargin()); + + aabbMin = center - extent; + aabbMax = center + extent; + + +} + + +void btBoxShape::calculateLocalInertia(btScalar mass,btVector3& inertia) +{ + //btScalar margin = btScalar(0.); + btVector3 halfExtents = getHalfExtents(); + + btScalar lx=btScalar(2.)*(halfExtents.x()); + btScalar ly=btScalar(2.)*(halfExtents.y()); + btScalar lz=btScalar(2.)*(halfExtents.z()); + + inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), + mass/(btScalar(12.0)) * (lx*lx + lz*lz), + mass/(btScalar(12.0)) * (lx*lx + ly*ly)); + +} + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.h new file mode 100644 index 00000000000..bc42f146c7c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.h @@ -0,0 +1,293 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef OBB_BOX_MINKOWSKI_H +#define OBB_BOX_MINKOWSKI_H + +#include "btPolyhedralConvexShape.h" +#include "btCollisionMargin.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" +#include "../../LinearMath/btPoint3.h" +#include "../../LinearMath/btSimdMinMax.h" + +///btBoxShape implements both a feature based (vertex/edge/plane) and implicit (getSupportingVertex) Box +class btBoxShape: public btPolyhedralConvexShape +{ + + //btVector3 m_boxHalfExtents1; //use m_implicitShapeDimensions instead + + +public: + + btVector3 getHalfExtents() const; + + virtual int getShapeType() const { return BOX_SHAPE_PROXYTYPE;} + + virtual btVector3 localGetSupportingVertex(const btVector3& vec) const + { + + btVector3 halfExtents = getHalfExtents(); + + btVector3 supVertex; + supVertex = btPoint3(vec.x() < btScalar(0.0) ? -halfExtents.x() : halfExtents.x(), + vec.y() < btScalar(0.0) ? -halfExtents.y() : halfExtents.y(), + vec.z() < btScalar(0.0) ? -halfExtents.z() : halfExtents.z()); + + return supVertex; + } + + virtual inline btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const + { + btVector3 halfExtents = getHalfExtents(); + btVector3 margin(getMargin(),getMargin(),getMargin()); + halfExtents -= margin; + + return btVector3(vec.x() < btScalar(0.0) ? -halfExtents.x() : halfExtents.x(), + vec.y() < btScalar(0.0) ? -halfExtents.y() : halfExtents.y(), + vec.z() < btScalar(0.0) ? -halfExtents.z() : halfExtents.z()); + } + + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const + { + btVector3 halfExtents = getHalfExtents(); + btVector3 margin(getMargin(),getMargin(),getMargin()); + halfExtents -= margin; + + + for (int i=0;i>1)) - halfExtents.y() * ((i&2)>>1), + halfExtents.z() * (1-((i&4)>>2)) - halfExtents.z() * ((i&4)>>2)); + } + + + virtual void getPlaneEquation(btVector4& plane,int i) const + { + btVector3 halfExtents = getHalfExtents(); + + switch (i) + { + case 0: + plane.setValue(btScalar(1.),btScalar(0.),btScalar(0.)); + plane[3] = -halfExtents.x(); + break; + case 1: + plane.setValue(btScalar(-1.),btScalar(0.),btScalar(0.)); + plane[3] = -halfExtents.x(); + break; + case 2: + plane.setValue(btScalar(0.),btScalar(1.),btScalar(0.)); + plane[3] = -halfExtents.y(); + break; + case 3: + plane.setValue(btScalar(0.),btScalar(-1.),btScalar(0.)); + plane[3] = -halfExtents.y(); + break; + case 4: + plane.setValue(btScalar(0.),btScalar(0.),btScalar(1.)); + plane[3] = -halfExtents.z(); + break; + case 5: + plane.setValue(btScalar(0.),btScalar(0.),btScalar(-1.)); + plane[3] = -halfExtents.z(); + break; + default: + assert(0); + } + } + + + virtual void getEdge(int i,btPoint3& pa,btPoint3& pb) const + //virtual void getEdge(int i,Edge& edge) const + { + int edgeVert0 = 0; + int edgeVert1 = 0; + + switch (i) + { + case 0: + edgeVert0 = 0; + edgeVert1 = 1; + break; + case 1: + edgeVert0 = 0; + edgeVert1 = 2; + break; + case 2: + edgeVert0 = 1; + edgeVert1 = 3; + + break; + case 3: + edgeVert0 = 2; + edgeVert1 = 3; + break; + case 4: + edgeVert0 = 0; + edgeVert1 = 4; + break; + case 5: + edgeVert0 = 1; + edgeVert1 = 5; + + break; + case 6: + edgeVert0 = 2; + edgeVert1 = 6; + break; + case 7: + edgeVert0 = 3; + edgeVert1 = 7; + break; + case 8: + edgeVert0 = 4; + edgeVert1 = 5; + break; + case 9: + edgeVert0 = 4; + edgeVert1 = 6; + break; + case 10: + edgeVert0 = 5; + edgeVert1 = 7; + break; + case 11: + edgeVert0 = 6; + edgeVert1 = 7; + break; + default: + btAssert(0); + + } + + getVertex(edgeVert0,pa ); + getVertex(edgeVert1,pb ); + } + + + + + + virtual bool isInside(const btPoint3& pt,btScalar tolerance) const + { + btVector3 halfExtents = getHalfExtents(); + + //btScalar minDist = 2*tolerance; + + bool result = (pt.x() <= (halfExtents.x()+tolerance)) && + (pt.x() >= (-halfExtents.x()-tolerance)) && + (pt.y() <= (halfExtents.y()+tolerance)) && + (pt.y() >= (-halfExtents.y()-tolerance)) && + (pt.z() <= (halfExtents.z()+tolerance)) && + (pt.z() >= (-halfExtents.z()-tolerance)); + + return result; + } + + + //debugging + virtual char* getName()const + { + return "Box"; + } + + virtual int getNumPreferredPenetrationDirections() const + { + return 6; + } + + virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const + { + switch (index) + { + case 0: + penetrationVector.setValue(btScalar(1.),btScalar(0.),btScalar(0.)); + break; + case 1: + penetrationVector.setValue(btScalar(-1.),btScalar(0.),btScalar(0.)); + break; + case 2: + penetrationVector.setValue(btScalar(0.),btScalar(1.),btScalar(0.)); + break; + case 3: + penetrationVector.setValue(btScalar(0.),btScalar(-1.),btScalar(0.)); + break; + case 4: + penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(1.)); + break; + case 5: + penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(-1.)); + break; + default: + assert(0); + } + } + +}; + +#endif //OBB_BOX_MINKOWSKI_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp new file mode 100644 index 00000000000..8da554ef14d --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp @@ -0,0 +1,173 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +//#define DISABLE_BVH + +#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" +#include "BulletCollision/CollisionShapes/btOptimizedBvh.h" + + +///Bvh Concave triangle mesh is a static-triangle mesh shape with Bounding Volume Hierarchy optimization. +///Uses an interface to access the triangles to allow for sharing graphics/physics triangles. +btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) +:btTriangleMeshShape(meshInterface),m_useQuantizedAabbCompression(useQuantizedAabbCompression) +{ + //construct bvh from meshInterface +#ifndef DISABLE_BVH + + m_bvh = new btOptimizedBvh(); + btVector3 bvhAabbMin,bvhAabbMax; + meshInterface->calculateAabbBruteForce(bvhAabbMin,bvhAabbMax); + m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax); + +#endif //DISABLE_BVH + +} + +btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax) +:btTriangleMeshShape(meshInterface),m_useQuantizedAabbCompression(useQuantizedAabbCompression) +{ + //construct bvh from meshInterface +#ifndef DISABLE_BVH + + m_bvh = new btOptimizedBvh(); + m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax); + +#endif //DISABLE_BVH + +} + +void btBvhTriangleMeshShape::partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax) +{ + m_bvh->refitPartial( m_meshInterface,aabbMin,aabbMax ); + + m_localAabbMin.setMin(aabbMin); + m_localAabbMax.setMax(aabbMax); +} + + +void btBvhTriangleMeshShape::refitTree() +{ + m_bvh->refit( m_meshInterface ); + + recalcLocalAabb(); +} + +btBvhTriangleMeshShape::~btBvhTriangleMeshShape() +{ + delete m_bvh; +} + +//perform bvh tree traversal and report overlapping triangles to 'callback' +void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const +{ + +#ifdef DISABLE_BVH + //brute force traverse all triangles + btTriangleMeshShape::processAllTriangles(callback,aabbMin,aabbMax); +#else + + //first get all the nodes + + + struct MyNodeOverlapCallback : public btNodeOverlapCallback + { + btStridingMeshInterface* m_meshInterface; + btTriangleCallback* m_callback; + btVector3 m_triangle[3]; + + + MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) + :m_meshInterface(meshInterface), + m_callback(callback) + { + } + + virtual void processNode(int nodeSubPart, int nodeTriangleIndex) + { + const unsigned char *vertexbase; + int numverts; + PHY_ScalarType type; + int stride; + const unsigned char *indexbase; + int indexstride; + int numfaces; + PHY_ScalarType indicestype; + + + m_meshInterface->getLockedReadOnlyVertexIndexBase( + &vertexbase, + numverts, + type, + stride, + &indexbase, + indexstride, + numfaces, + indicestype, + nodeSubPart); + + int* gfxbase = (int*)(indexbase+nodeTriangleIndex*indexstride); + + const btVector3& meshScaling = m_meshInterface->getScaling(); + for (int j=2;j>=0;j--) + { + + int graphicsindex = gfxbase[j]; + + +#ifdef DEBUG_TRIANGLE_MESH + printf("%d ,",graphicsindex); +#endif //DEBUG_TRIANGLE_MESH + btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride); + + m_triangle[j] = btVector3( + graphicsbase[0]*meshScaling.getX(), + graphicsbase[1]*meshScaling.getY(), + graphicsbase[2]*meshScaling.getZ()); +#ifdef DEBUG_TRIANGLE_MESH + printf("triangle vertices:%f,%f,%f\n",triangle[j].x(),triangle[j].y(),triangle[j].z()); +#endif //DEBUG_TRIANGLE_MESH + } + + m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); + m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); + } + + }; + + MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); + + m_bvh->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); + + +#endif//DISABLE_BVH + + +} + + +void btBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling) +{ + if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON) + { + btTriangleMeshShape::setLocalScaling(scaling); + delete m_bvh; + ///m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could just scale aabb, but this needs some more work + m_bvh = new btOptimizedBvh(); + //rebuild the bvh... + m_bvh->build(m_meshInterface,m_useQuantizedAabbCompression,m_localAabbMin,m_localAabbMax); + + } +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h new file mode 100644 index 00000000000..4914d9f959c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h @@ -0,0 +1,75 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BVH_TRIANGLE_MESH_SHAPE_H +#define BVH_TRIANGLE_MESH_SHAPE_H + +#include "btTriangleMeshShape.h" +#include "btOptimizedBvh.h" + +///Bvh Concave triangle mesh is a static-triangle mesh shape with Bounding Volume Hierarchy optimization. +///Uses an interface to access the triangles to allow for sharing graphics/physics triangles. +ATTRIBUTE_ALIGNED16(class) btBvhTriangleMeshShape : public btTriangleMeshShape +{ + + btOptimizedBvh* m_bvh; + bool m_useQuantizedAabbCompression; + bool m_pad[12];////need padding due to alignment + +public: + + btBvhTriangleMeshShape() :btTriangleMeshShape(0) {}; + btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression); + + ///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb + btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax); + + virtual ~btBvhTriangleMeshShape(); + + + /* + virtual int getShapeType() const + { + return TRIANGLE_MESH_SHAPE_PROXYTYPE; + } + */ + + + + virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; + + void refitTree(); + + ///for a fast incremental refit of parts of the tree. Note: the entire AABB of the tree will become more conservative, it never shrinks + void partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax); + + //debugging + virtual char* getName()const {return "BVHTRIANGLEMESH";} + + + virtual void setLocalScaling(const btVector3& scaling); + + btOptimizedBvh* getOptimizedBvh() + { + return m_bvh; + } + bool usesQuantizedAabbCompression() const + { + return m_useQuantizedAabbCompression; + } +} +; + +#endif //BVH_TRIANGLE_MESH_SHAPE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp new file mode 100644 index 00000000000..b7e15172da2 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp @@ -0,0 +1,146 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btCapsuleShape.h" + +#include "BulletCollision/CollisionShapes/btCollisionMargin.h" +#include "LinearMath/btQuaternion.h" + +btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) +{ + m_implicitShapeDimensions.setValue(radius,0.5f*height,radius); +} + + + btVector3 btCapsuleShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const +{ + + btVector3 supVec(0,0,0); + + btScalar maxDot(btScalar(-1e30)); + + btVector3 vec = vec0; + btScalar lenSqr = vec.length2(); + if (lenSqr < btScalar(0.0001)) + { + vec.setValue(1,0,0); + } else + { + btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); + vec *= rlen; + } + + btVector3 vtx; + btScalar newDot; + + btScalar radius = getRadius(); + + + { + btVector3 pos(0,getHalfHeight(),0); + vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); + newDot = vec.dot(vtx); + if (newDot > maxDot) + { + maxDot = newDot; + supVec = vtx; + } + } + { + btVector3 pos(0,-getHalfHeight(),0); + vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); + newDot = vec.dot(vtx); + if (newDot > maxDot) + { + maxDot = newDot; + supVec = vtx; + } + } + + return supVec; + +} + + void btCapsuleShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + + + btScalar radius = getRadius(); + + for (int j=0;j maxDot) + { + maxDot = newDot; + supportVerticesOut[j] = vtx; + } + } + { + btVector3 pos(0,-getHalfHeight(),0); + vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); + newDot = vec.dot(vtx); + if (newDot > maxDot) + { + maxDot = newDot; + supportVerticesOut[j] = vtx; + } + } + + } +} + + +void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia) +{ + //as an approximation, take the inertia of the box that bounds the spheres + + btTransform ident; + ident.setIdentity(); + + + btScalar radius = getRadius(); + + btVector3 halfExtents(radius,radius+getHalfHeight(),radius); + + btScalar margin = CONVEX_DISTANCE_MARGIN; + + btScalar lx=btScalar(2.)*(halfExtents[0]+margin); + btScalar ly=btScalar(2.)*(halfExtents[1]+margin); + btScalar lz=btScalar(2.)*(halfExtents[2]+margin); + const btScalar x2 = lx*lx; + const btScalar y2 = ly*ly; + const btScalar z2 = lz*lz; + const btScalar scaledmass = mass * btScalar(.08333333); + + inertia[0] = scaledmass * (y2+z2); + inertia[1] = scaledmass * (x2+z2); + inertia[2] = scaledmass * (x2+y2); + +} + + + + + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h new file mode 100644 index 00000000000..27da8adefa5 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h @@ -0,0 +1,60 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_CAPSULE_SHAPE_H +#define BT_CAPSULE_SHAPE_H + +#include "btConvexShape.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types + + +///btCapsuleShape represents a capsule around the Y axis +///A more general solution that can represent capsules is the btMultiSphereShape +class btCapsuleShape : public btConvexShape +{ + +public: + btCapsuleShape(btScalar radius,btScalar height); + + ///CollisionShape Interface + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); + + /// btConvexShape Interface + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; + + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; + + virtual int getShapeType() const { return CAPSULE_SHAPE_PROXYTYPE; } + + virtual char* getName()const + { + return "CapsuleShape"; + } + + btScalar getRadius() const + { + return m_implicitShapeDimensions.getX(); + } + + btScalar getHalfHeight() const + { + return m_implicitShapeDimensions.getY(); + } + +}; + + + +#endif //BT_CAPSULE_SHAPE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionMargin.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionMargin.h new file mode 100644 index 00000000000..4730264d3df --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionMargin.h @@ -0,0 +1,26 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef COLLISION_MARGIN_H +#define COLLISION_MARGIN_H + +//used by Gjk and some other algorithms + +#define CONVEX_DISTANCE_MARGIN btScalar(0.04)// btScalar(0.1)//;//btScalar(0.01) + + + +#endif //COLLISION_MARGIN_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.cpp new file mode 100644 index 00000000000..81d82428f4c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.cpp @@ -0,0 +1,85 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "BulletCollision/CollisionShapes/btCollisionShape.h" + + +/* + Make sure this dummy function never changes so that it + can be used by probes that are checking whether the + library is actually installed. +*/ +extern "C" void btBulletCollisionProbe () {} + + + +void btCollisionShape::getBoundingSphere(btVector3& center,btScalar& radius) const +{ + btTransform tr; + tr.setIdentity(); + btVector3 aabbMin,aabbMax; + + getAabb(tr,aabbMin,aabbMax); + + radius = (aabbMax-aabbMin).length()*btScalar(0.5); + center = (aabbMin+aabbMax)*btScalar(0.5); +} + +btScalar btCollisionShape::getAngularMotionDisc() const +{ + btVector3 center; + btScalar disc; + getBoundingSphere(center,disc); + disc += (center).length(); + return disc; +} + +void btCollisionShape::calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) +{ + //start with static aabb + getAabb(curTrans,temporalAabbMin,temporalAabbMax); + + btScalar temporalAabbMaxx = temporalAabbMax.getX(); + btScalar temporalAabbMaxy = temporalAabbMax.getY(); + btScalar temporalAabbMaxz = temporalAabbMax.getZ(); + btScalar temporalAabbMinx = temporalAabbMin.getX(); + btScalar temporalAabbMiny = temporalAabbMin.getY(); + btScalar temporalAabbMinz = temporalAabbMin.getZ(); + + // add linear motion + btVector3 linMotion = linvel*timeStep; + //todo: simd would have a vector max/min operation, instead of per-element access + if (linMotion.x() > btScalar(0.)) + temporalAabbMaxx += linMotion.x(); + else + temporalAabbMinx += linMotion.x(); + if (linMotion.y() > btScalar(0.)) + temporalAabbMaxy += linMotion.y(); + else + temporalAabbMiny += linMotion.y(); + if (linMotion.z() > btScalar(0.)) + temporalAabbMaxz += linMotion.z(); + else + temporalAabbMinz += linMotion.z(); + + //add conservative angular motion + btScalar angularMotion = angvel.length() * getAngularMotionDisc() * timeStep; + btVector3 angularMotion3d(angularMotion,angularMotion,angularMotion); + temporalAabbMin = btVector3(temporalAabbMinx,temporalAabbMiny,temporalAabbMinz); + temporalAabbMax = btVector3(temporalAabbMaxx,temporalAabbMaxy,temporalAabbMaxz); + + temporalAabbMin -= angularMotion3d; + temporalAabbMax += angularMotion3d; +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h new file mode 100644 index 00000000000..96268734a83 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h @@ -0,0 +1,94 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef COLLISION_SHAPE_H +#define COLLISION_SHAPE_H + +#include "../../LinearMath/btTransform.h" +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btMatrix3x3.h" +#include "../../LinearMath/btPoint3.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" //for the shape types + +///btCollisionShape provides interface for collision shapes that can be shared among btCollisionObjects. +class btCollisionShape +{ +public: + + btCollisionShape() + { + } + virtual ~btCollisionShape() + { + } + + ///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t. + virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const =0; + + virtual void getBoundingSphere(btVector3& center,btScalar& radius) const; + + ///getAngularMotionDisc returns the maximus radius needed for Conservative Advancement to handle time-of-impact with rotations. + virtual btScalar getAngularMotionDisc() const; + + + ///calculateTemporalAabb calculates the enclosing aabb for the moving object over interval [0..timeStep) + ///result is conservative + void calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax); + +#ifndef __SPU__ + + inline bool isPolyhedral() const + { + return btBroadphaseProxy::isPolyhedral(getShapeType()); + } + + inline bool isConvex() const + { + return btBroadphaseProxy::isConvex(getShapeType()); + } + inline bool isConcave() const + { + return btBroadphaseProxy::isConcave(getShapeType()); + } + inline bool isCompound() const + { + return btBroadphaseProxy::isCompound(getShapeType()); + } + + ///isInfinite is used to catch simulation error (aabb check) + inline bool isInfinite() const + { + return btBroadphaseProxy::isInfinite(getShapeType()); + } + + virtual int getShapeType() const=0; + virtual void setLocalScaling(const btVector3& scaling) =0; + virtual const btVector3& getLocalScaling() const =0; + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) = 0; + + +//debugging support + virtual char* getName()const =0 ; +#endif //__SPU__ + + + + virtual void setMargin(btScalar margin) = 0; + virtual btScalar getMargin() const = 0; + +}; + +#endif //COLLISION_SHAPE_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp new file mode 100644 index 00000000000..a4712b3e925 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp @@ -0,0 +1,100 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btCompoundShape.h" + + +#include "btCollisionShape.h" + + +btCompoundShape::btCompoundShape() +:m_localAabbMin(btScalar(1e30),btScalar(1e30),btScalar(1e30)), +m_localAabbMax(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)), +m_aabbTree(0), +m_collisionMargin(btScalar(0.)), +m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)) +{ +} + + +btCompoundShape::~btCompoundShape() +{ +} + +void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisionShape* shape) +{ + m_childTransforms.push_back(localTransform); + m_childShapes.push_back(shape); + + //extend the local aabbMin/aabbMax + btVector3 localAabbMin,localAabbMax; + shape->getAabb(localTransform,localAabbMin,localAabbMax); + for (int i=0;i<3;i++) + { + if (m_localAabbMin[i] > localAabbMin[i]) + { + m_localAabbMin[i] = localAabbMin[i]; + } + if (m_localAabbMax[i] < localAabbMax[i]) + { + m_localAabbMax[i] = localAabbMax[i]; + } + + } +} + + + + ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version +void btCompoundShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const +{ + btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin); + btVector3 localCenter = btScalar(0.5)*(m_localAabbMax+m_localAabbMin); + + btMatrix3x3 abs_b = trans.getBasis().absolute(); + + btPoint3 center = trans(localCenter); + + btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), + abs_b[1].dot(localHalfExtents), + abs_b[2].dot(localHalfExtents)); + extent += btVector3(getMargin(),getMargin(),getMargin()); + + aabbMin = center - extent; + aabbMax = center + extent; +} + +void btCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) +{ + //approximation: take the inertia from the aabb for now + btTransform ident; + ident.setIdentity(); + btVector3 aabbMin,aabbMax; + getAabb(ident,aabbMin,aabbMax); + + btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); + + btScalar lx=btScalar(2.)*(halfExtents.x()); + btScalar ly=btScalar(2.)*(halfExtents.y()); + btScalar lz=btScalar(2.)*(halfExtents.z()); + + inertia[0] = mass/(btScalar(12.0)) * (ly*ly + lz*lz); + inertia[1] = mass/(btScalar(12.0)) * (lx*lx + lz*lz); + inertia[2] = mass/(btScalar(12.0)) * (lx*lx + ly*ly); + +} + + + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h new file mode 100644 index 00000000000..86dc1f80947 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h @@ -0,0 +1,117 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef COMPOUND_SHAPE_H +#define COMPOUND_SHAPE_H + +#include "btCollisionShape.h" + +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btTransform.h" +#include "../../LinearMath/btMatrix3x3.h" +#include "btCollisionMargin.h" +#include "../../LinearMath/btAlignedObjectArray.h" + +class btOptimizedBvh; + +/// btCompoundShape allows to store multiple other btCollisionShapes +/// This allows for concave collision objects. This is more general then the Static Concave btTriangleMeshShape. +class btCompoundShape : public btCollisionShape +{ + btAlignedObjectArray m_childTransforms; + btAlignedObjectArray m_childShapes; + btVector3 m_localAabbMin; + btVector3 m_localAabbMax; + + btOptimizedBvh* m_aabbTree; + +public: + btCompoundShape(); + + virtual ~btCompoundShape(); + + void addChildShape(const btTransform& localTransform,btCollisionShape* shape); + + int getNumChildShapes() const + { + return int (m_childShapes.size()); + } + + btCollisionShape* getChildShape(int index) + { + return m_childShapes[index]; + } + const btCollisionShape* getChildShape(int index) const + { + return m_childShapes[index]; + } + + btTransform& getChildTransform(int index) + { + return m_childTransforms[index]; + } + const btTransform& getChildTransform(int index) const + { + return m_childTransforms[index]; + } + + ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version + void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; + + + virtual void setLocalScaling(const btVector3& scaling) + { + m_localScaling = scaling; + } + virtual const btVector3& getLocalScaling() const + { + return m_localScaling; + } + + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); + + virtual int getShapeType() const { return COMPOUND_SHAPE_PROXYTYPE;} + + virtual void setMargin(btScalar margin) + { + m_collisionMargin = margin; + } + virtual btScalar getMargin() const + { + return m_collisionMargin; + } + virtual char* getName()const + { + return "Compound"; + } + + //this is optional, but should make collision queries faster, by culling non-overlapping nodes + void createAabbTreeFromChildren(); + + const btOptimizedBvh* getAabbTree() const + { + return m_aabbTree; + } + +private: + btScalar m_collisionMargin; +protected: + btVector3 m_localScaling; + +}; + + + +#endif //COMPOUND_SHAPE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.cpp new file mode 100644 index 00000000000..5103500a012 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.cpp @@ -0,0 +1,28 @@ + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btConcaveShape.h" + +btConcaveShape::btConcaveShape() : m_collisionMargin(btScalar(0.)) +{ + +} + +btConcaveShape::~btConcaveShape() +{ + +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.h new file mode 100644 index 00000000000..73f974e4ee9 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.h @@ -0,0 +1,50 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef CONCAVE_SHAPE_H +#define CONCAVE_SHAPE_H + +#include "btCollisionShape.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types +#include "btTriangleCallback.h" + + +///Concave shape proves an interface concave shapes that can produce triangles that overlapping a given AABB. +///Static triangle mesh, infinite plane, height field/landscapes are example that implement this interface. +class btConcaveShape : public btCollisionShape +{ +protected: + btScalar m_collisionMargin; + +public: + btConcaveShape(); + + virtual ~btConcaveShape(); + + virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const = 0; + + virtual btScalar getMargin() const { + return m_collisionMargin; + } + virtual void setMargin(btScalar collisionMargin) + { + m_collisionMargin = collisionMargin; + } + + + +}; + +#endif //CONCAVE_SHAPE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.cpp new file mode 100644 index 00000000000..207b3024bc3 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.cpp @@ -0,0 +1,133 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btConeShape.h" +#include "LinearMath/btPoint3.h" + + + +btConeShape::btConeShape (btScalar radius,btScalar height): +m_radius (radius), +m_height(height) +{ + setConeUpIndex(1); + btVector3 halfExtents; + m_sinAngle = (m_radius / btSqrt(m_radius * m_radius + m_height * m_height)); +} + +btConeShapeZ::btConeShapeZ (btScalar radius,btScalar height): +btConeShape(radius,height) +{ + setConeUpIndex(2); +} + +btConeShapeX::btConeShapeX (btScalar radius,btScalar height): +btConeShape(radius,height) +{ + setConeUpIndex(0); +} + +///choose upAxis index +void btConeShape::setConeUpIndex(int upIndex) +{ + switch (upIndex) + { + case 0: + m_coneIndices[0] = 1; + m_coneIndices[1] = 0; + m_coneIndices[2] = 2; + break; + case 1: + m_coneIndices[0] = 0; + m_coneIndices[1] = 1; + m_coneIndices[2] = 2; + break; + case 2: + m_coneIndices[0] = 0; + m_coneIndices[1] = 2; + m_coneIndices[2] = 1; + break; + default: + assert(0); + }; +} + +btVector3 btConeShape::coneLocalSupport(const btVector3& v) const +{ + + btScalar halfHeight = m_height * btScalar(0.5); + + if (v[m_coneIndices[1]] > v.length() * m_sinAngle) + { + btVector3 tmp; + + tmp[m_coneIndices[0]] = btScalar(0.); + tmp[m_coneIndices[1]] = halfHeight; + tmp[m_coneIndices[2]] = btScalar(0.); + return tmp; + } + else { + btScalar s = btSqrt(v[m_coneIndices[0]] * v[m_coneIndices[0]] + v[m_coneIndices[2]] * v[m_coneIndices[2]]); + if (s > SIMD_EPSILON) { + btScalar d = m_radius / s; + btVector3 tmp; + tmp[m_coneIndices[0]] = v[m_coneIndices[0]] * d; + tmp[m_coneIndices[1]] = -halfHeight; + tmp[m_coneIndices[2]] = v[m_coneIndices[2]] * d; + return tmp; + } + else { + btVector3 tmp; + tmp[m_coneIndices[0]] = btScalar(0.); + tmp[m_coneIndices[1]] = -halfHeight; + tmp[m_coneIndices[2]] = btScalar(0.); + return tmp; + } + } + +} + +btVector3 btConeShape::localGetSupportingVertexWithoutMargin(const btVector3& vec) const +{ + return coneLocalSupport(vec); +} + +void btConeShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + for (int i=0;i maxDot) + { + maxDot = newDot; + supVec = vtx; + } + } + return supVec; +} + +void btConvexHullShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + btScalar newDot; + //use 'w' component of supportVerticesOut? + { + for (int i=0;i supportVerticesOut[j][3]) + { + //WARNING: don't swap next lines, the w component would get overwritten! + supportVerticesOut[j] = vtx; + supportVerticesOut[j][3] = newDot; + } + } + } + + + +} + + + +btVector3 btConvexHullShape::localGetSupportingVertex(const btVector3& vec)const +{ + btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); + + if ( getMargin()!=btScalar(0.) ) + { + btVector3 vecnorm = vec; + if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) + { + vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); + } + vecnorm.normalize(); + supVertex+= getMargin() * vecnorm; + } + return supVertex; +} + + + + + + + + + +//currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection +//Please note that you can debug-draw btConvexHullShape with the Raytracer Demo +int btConvexHullShape::getNumVertices() const +{ + return m_points.size(); +} + +int btConvexHullShape::getNumEdges() const +{ + return m_points.size(); +} + +void btConvexHullShape::getEdge(int i,btPoint3& pa,btPoint3& pb) const +{ + + int index0 = i%m_points.size(); + int index1 = (i+1)%m_points.size(); + pa = m_points[index0]*m_localScaling; + pb = m_points[index1]*m_localScaling; +} + +void btConvexHullShape::getVertex(int i,btPoint3& vtx) const +{ + vtx = m_points[i]*m_localScaling; +} + +int btConvexHullShape::getNumPlanes() const +{ + return 0; +} + +void btConvexHullShape::getPlane(btVector3& ,btPoint3& ,int ) const +{ + + btAssert(0); +} + +//not yet +bool btConvexHullShape::isInside(const btPoint3& ,btScalar ) const +{ + assert(0); + return false; +} + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.h new file mode 100644 index 00000000000..3fd5e382525 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.h @@ -0,0 +1,76 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef CONVEX_HULL_SHAPE_H +#define CONVEX_HULL_SHAPE_H + +#include "btPolyhedralConvexShape.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types +#include "../../LinearMath/btAlignedObjectArray.h" + +///ConvexHullShape implements an implicit (getSupportingVertex) Convex Hull of a Point Cloud (vertices) +///No connectivity is needed. localGetSupportingVertex iterates linearly though all vertices. +///on modern hardware, due to cache coherency this isn't that bad. Complex algorithms tend to trash the cash. +///(memory is much slower then the cpu) +ATTRIBUTE_ALIGNED16(class) btConvexHullShape : public btPolyhedralConvexShape +{ + btAlignedObjectArray m_points; + +public: + + + ///this constructor optionally takes in a pointer to points. Each point is assumed to be 3 consecutive btScalar (x,y,z), the striding defines the number of bytes between each point, in memory. + ///It is easier to not pass any points in the constructor, and just add one point at a time, using addPoint. + ///btConvexHullShape make an internal copy of the points. + btConvexHullShape(const btScalar* points=0,int numPoints=0, int stride=sizeof(btPoint3)); + + void addPoint(const btPoint3& point); + + btPoint3* getPoints() + { + return &m_points[0]; + } + + int getNumPoints() + { + return m_points.size(); + } + + virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; + + + virtual int getShapeType()const { return CONVEX_HULL_SHAPE_PROXYTYPE; } + + //debugging + virtual char* getName()const {return "Convex";} + + + virtual int getNumVertices() const; + virtual int getNumEdges() const; + virtual void getEdge(int i,btPoint3& pa,btPoint3& pb) const; + virtual void getVertex(int i,btPoint3& vtx) const; + virtual int getNumPlanes() const; + virtual void getPlane(btVector3& planeNormal,btPoint3& planeSupport,int i ) const; + virtual bool isInside(const btPoint3& pt,btScalar tolerance) const; + + + +}; + + +#endif //CONVEX_HULL_SHAPE_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp new file mode 100644 index 00000000000..7edf1ea6db8 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp @@ -0,0 +1,77 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btConvexShape.h" + + +btConvexShape::btConvexShape() +: m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)), +m_collisionMargin(CONVEX_DISTANCE_MARGIN) +{ +} + + +void btConvexShape::setLocalScaling(const btVector3& scaling) +{ + m_localScaling = scaling; +} + + + +void btConvexShape::getAabbSlow(const btTransform& trans,btVector3&minAabb,btVector3&maxAabb) const +{ + + btScalar margin = getMargin(); + for (int i=0;i<3;i++) + { + btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); + vec[i] = btScalar(1.); + + btVector3 sv = localGetSupportingVertex(vec*trans.getBasis()); + + btVector3 tmp = trans(sv); + maxAabb[i] = tmp[i]+margin; + vec[i] = btScalar(-1.); + tmp = trans(localGetSupportingVertex(vec*trans.getBasis())); + minAabb[i] = tmp[i]-margin; + } +}; + + +btVector3 btConvexShape::localGetSupportingVertex(const btVector3& vec)const +{ +#ifndef __SPU__ + + btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); + + if ( getMargin()!=btScalar(0.) ) + { + btVector3 vecnorm = vec; + if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) + { + vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); + } + vecnorm.normalize(); + supVertex+= getMargin() * vecnorm; + } + return supVertex; + +#else + return btVector3(0,0,0); +#endif //__SPU__ + + } + + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h new file mode 100644 index 00000000000..746f383dfc7 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h @@ -0,0 +1,127 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef CONVEX_SHAPE_INTERFACE1 +#define CONVEX_SHAPE_INTERFACE1 + +#include "btCollisionShape.h" + +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btTransform.h" +#include "../../LinearMath/btMatrix3x3.h" +#include "btCollisionMargin.h" + +//todo: get rid of this btConvexCastResult thing! +struct btConvexCastResult; +#define MAX_PREFERRED_PENETRATION_DIRECTIONS 10 + +/// btConvexShape is an abstract shape interface. +/// The explicit part provides plane-equations, the implicit part provides GetClosestPoint interface. +/// used in combination with GJK or btConvexCast +ATTRIBUTE_ALIGNED16(class) btConvexShape : public btCollisionShape +{ + +protected: + + //local scaling. collisionMargin is not scaled ! + btVector3 m_localScaling; + + btVector3 m_implicitShapeDimensions; + + btScalar m_collisionMargin; + + btScalar m_padding[2]; + + + + +public: + btConvexShape(); + + virtual ~btConvexShape() + { + + } + + + virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; +#ifndef __SPU__ + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const= 0; + + //notice that the vectors should be unit length + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const= 0; +#endif //#ifndef __SPU__ + + const btVector3& getImplicitShapeDimensions() const + { + return m_implicitShapeDimensions; + } + + ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version + void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const + { + getAabbSlow(t,aabbMin,aabbMax); + } + + + + virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; + + + virtual void setLocalScaling(const btVector3& scaling); + virtual const btVector3& getLocalScaling() const + { + return m_localScaling; + } + + const btVector3& getLocalScalingNV() const + { + return m_localScaling; + } + + virtual void setMargin(btScalar margin) + { + m_collisionMargin = margin; + } + virtual btScalar getMargin() const + { + return m_collisionMargin; + } + + btScalar getMarginNV() const + { + return m_collisionMargin; + } + + virtual int getNumPreferredPenetrationDirections() const + { + return 0; + } + + virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const + { + (void)penetrationVector; + (void)index; + btAssert(0); + } + + + +} +; + + + +#endif //CONVEX_SHAPE_INTERFACE1 diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp new file mode 100644 index 00000000000..614ec977793 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp @@ -0,0 +1,205 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +#include "btConvexTriangleMeshShape.h" +#include "BulletCollision/CollisionShapes/btCollisionMargin.h" + +#include "LinearMath/btQuaternion.h" +#include "BulletCollision/CollisionShapes/btStridingMeshInterface.h" + + +btConvexTriangleMeshShape ::btConvexTriangleMeshShape (btStridingMeshInterface* meshInterface) +:m_stridingMesh(meshInterface) +{ + recalcLocalAabb(); +} + + + + +///It's not nice to have all this virtual function overhead, so perhaps we can also gather the points once +///but then we are duplicating +class LocalSupportVertexCallback: public btInternalTriangleIndexCallback +{ + + btVector3 m_supportVertexLocal; +public: + + btScalar m_maxDot; + btVector3 m_supportVecLocal; + + LocalSupportVertexCallback(const btVector3& supportVecLocal) + : m_supportVertexLocal(btScalar(0.),btScalar(0.),btScalar(0.)), + m_maxDot(btScalar(-1e30)), + m_supportVecLocal(supportVecLocal) + { + } + + virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) + { + (void)triangleIndex; + (void)partId; + + for (int i=0;i<3;i++) + { + btScalar dot = m_supportVecLocal.dot(triangle[i]); + if (dot > m_maxDot) + { + m_maxDot = dot; + m_supportVertexLocal = triangle[i]; + } + } + } + + btVector3 GetSupportVertexLocal() + { + return m_supportVertexLocal; + } + +}; + + + + + +btVector3 btConvexTriangleMeshShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const +{ + btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.)); + + btVector3 vec = vec0; + btScalar lenSqr = vec.length2(); + if (lenSqr < btScalar(0.0001)) + { + vec.setValue(1,0,0); + } else + { + btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); + vec *= rlen; + } + + LocalSupportVertexCallback supportCallback(vec); + btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + m_stridingMesh->InternalProcessAllTriangles(&supportCallback,-aabbMax,aabbMax); + supVec = supportCallback.GetSupportVertexLocal(); + + return supVec; +} + +void btConvexTriangleMeshShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + //use 'w' component of supportVerticesOut? + { + for (int i=0;iInternalProcessAllTriangles(&supportCallback,-aabbMax,aabbMax); + supportVerticesOut[j] = supportCallback.GetSupportVertexLocal(); + } + +} + + + +btVector3 btConvexTriangleMeshShape::localGetSupportingVertex(const btVector3& vec)const +{ + btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); + + if ( getMargin()!=btScalar(0.) ) + { + btVector3 vecnorm = vec; + if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) + { + vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); + } + vecnorm.normalize(); + supVertex+= getMargin() * vecnorm; + } + return supVertex; +} + + + + + + + + + +//currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection +//Please note that you can debug-draw btConvexTriangleMeshShape with the Raytracer Demo +int btConvexTriangleMeshShape::getNumVertices() const +{ + //cache this? + return 0; + +} + +int btConvexTriangleMeshShape::getNumEdges() const +{ + return 0; +} + +void btConvexTriangleMeshShape::getEdge(int ,btPoint3& ,btPoint3& ) const +{ + btAssert(0); +} + +void btConvexTriangleMeshShape::getVertex(int ,btPoint3& ) const +{ + btAssert(0); +} + +int btConvexTriangleMeshShape::getNumPlanes() const +{ + return 0; +} + +void btConvexTriangleMeshShape::getPlane(btVector3& ,btPoint3& ,int ) const +{ + btAssert(0); +} + +//not yet +bool btConvexTriangleMeshShape::isInside(const btPoint3& ,btScalar ) const +{ + btAssert(0); + return false; +} + + + +void btConvexTriangleMeshShape::setLocalScaling(const btVector3& scaling) +{ + m_stridingMesh->setScaling(scaling); + + recalcLocalAabb(); + +} + + +const btVector3& btConvexTriangleMeshShape::getLocalScaling() const +{ + return m_stridingMesh->getScaling(); +} \ No newline at end of file diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h new file mode 100644 index 00000000000..34ee7af744c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h @@ -0,0 +1,51 @@ +#ifndef CONVEX_TRIANGLEMESH_SHAPE_H +#define CONVEX_TRIANGLEMESH_SHAPE_H + + +#include "btPolyhedralConvexShape.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types + + +/// btConvexTriangleMeshShape is a convex hull of a triangle mesh. If you just have a point cloud, you can use btConvexHullShape instead. +/// It uses the btStridingMeshInterface instead of a point cloud. This can avoid the duplication of the triangle mesh data. +class btConvexTriangleMeshShape : public btPolyhedralConvexShape +{ + + class btStridingMeshInterface* m_stridingMesh; + +public: + btConvexTriangleMeshShape(btStridingMeshInterface* meshInterface); + + class btStridingMeshInterface* getStridingMesh() + { + return m_stridingMesh; + } + + virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; + + virtual int getShapeType()const { return CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE; } + + //debugging + virtual char* getName()const {return "ConvexTrimesh";} + + virtual int getNumVertices() const; + virtual int getNumEdges() const; + virtual void getEdge(int i,btPoint3& pa,btPoint3& pb) const; + virtual void getVertex(int i,btPoint3& vtx) const; + virtual int getNumPlanes() const; + virtual void getPlane(btVector3& planeNormal,btPoint3& planeSupport,int i ) const; + virtual bool isInside(const btPoint3& pt,btScalar tolerance) const; + + + virtual void setLocalScaling(const btVector3& scaling); + virtual const btVector3& getLocalScaling() const; + +}; + + + +#endif //CONVEX_TRIANGLEMESH_SHAPE_H + + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.cpp new file mode 100644 index 00000000000..1666afb3b88 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.cpp @@ -0,0 +1,206 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +#include "btCylinderShape.h" +#include "LinearMath/btPoint3.h" + +btCylinderShape::btCylinderShape (const btVector3& halfExtents) +:btBoxShape(halfExtents), +m_upAxis(1) +{ + recalcLocalAabb(); +} + + +btCylinderShapeX::btCylinderShapeX (const btVector3& halfExtents) +:btCylinderShape(halfExtents) +{ + m_upAxis = 0; + recalcLocalAabb(); +} + + +btCylinderShapeZ::btCylinderShapeZ (const btVector3& halfExtents) +:btCylinderShape(halfExtents) +{ + m_upAxis = 2; + recalcLocalAabb(); +} + +void btCylinderShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const +{ + //skip the box 'getAabb' + btPolyhedralConvexShape::getAabb(t,aabbMin,aabbMax); +} + + +inline btVector3 CylinderLocalSupportX(const btVector3& halfExtents,const btVector3& v) +{ +const int cylinderUpAxis = 0; +const int XX = 1; +const int YY = 0; +const int ZZ = 2; + + //mapping depends on how cylinder local orientation is + // extents of the cylinder is: X,Y is for radius, and Z for height + + + btScalar radius = halfExtents[XX]; + btScalar halfHeight = halfExtents[cylinderUpAxis]; + + + btVector3 tmp; + btScalar d ; + + btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); + if (s != btScalar(0.0)) + { + d = radius / s; + tmp[XX] = v[XX] * d; + tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; + tmp[ZZ] = v[ZZ] * d; + return tmp; + } + else + { + tmp[XX] = radius; + tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; + tmp[ZZ] = btScalar(0.0); + return tmp; + } + + +} + + + + + + +inline btVector3 CylinderLocalSupportY(const btVector3& halfExtents,const btVector3& v) +{ + +const int cylinderUpAxis = 1; +const int XX = 0; +const int YY = 1; +const int ZZ = 2; + + + btScalar radius = halfExtents[XX]; + btScalar halfHeight = halfExtents[cylinderUpAxis]; + + + btVector3 tmp; + btScalar d ; + + btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); + if (s != btScalar(0.0)) + { + d = radius / s; + tmp[XX] = v[XX] * d; + tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; + tmp[ZZ] = v[ZZ] * d; + return tmp; + } + else + { + tmp[XX] = radius; + tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; + tmp[ZZ] = btScalar(0.0); + return tmp; + } + +} + +inline btVector3 CylinderLocalSupportZ(const btVector3& halfExtents,const btVector3& v) +{ +const int cylinderUpAxis = 2; +const int XX = 0; +const int YY = 2; +const int ZZ = 1; + + //mapping depends on how cylinder local orientation is + // extents of the cylinder is: X,Y is for radius, and Z for height + + + btScalar radius = halfExtents[XX]; + btScalar halfHeight = halfExtents[cylinderUpAxis]; + + + btVector3 tmp; + btScalar d ; + + btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); + if (s != btScalar(0.0)) + { + d = radius / s; + tmp[XX] = v[XX] * d; + tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; + tmp[ZZ] = v[ZZ] * d; + return tmp; + } + else + { + tmp[XX] = radius; + tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; + tmp[ZZ] = btScalar(0.0); + return tmp; + } + + +} + +btVector3 btCylinderShapeX::localGetSupportingVertexWithoutMargin(const btVector3& vec)const +{ + return CylinderLocalSupportX(getHalfExtents(),vec); +} + + +btVector3 btCylinderShapeZ::localGetSupportingVertexWithoutMargin(const btVector3& vec)const +{ + return CylinderLocalSupportZ(getHalfExtents(),vec); +} +btVector3 btCylinderShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const +{ + return CylinderLocalSupportY(getHalfExtents(),vec); +} + +void btCylinderShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + for (int i=0;i=0); + btAssert(y>=0); + btAssert(xstartX) + startX = quantizedAabbMin[1]; + if (quantizedAabbMax[1]startJ) + startJ = quantizedAabbMin[2]; + if (quantizedAabbMax[2]startX) + startX = quantizedAabbMin[0]; + if (quantizedAabbMax[0]startJ) + startJ = quantizedAabbMin[2]; + if (quantizedAabbMax[2]startX) + startX = quantizedAabbMin[0]; + if (quantizedAabbMax[0]startJ) + startJ = quantizedAabbMin[1]; + if (quantizedAabbMax[1]processTriangle(vertices,x,j); + //second triangle + getVertex(x,j,vertices[0]); + getVertex(x+1,j+1,vertices[1]); + getVertex(x,j+1,vertices[2]); + callback->processTriangle(vertices,x,j); + } else + { + //first triangle + getVertex(x,j,vertices[0]); + getVertex(x,j+1,vertices[1]); + getVertex(x+1,j,vertices[2]); + callback->processTriangle(vertices,x,j); + //second triangle + getVertex(x+1,j,vertices[0]); + getVertex(x,j+1,vertices[1]); + getVertex(x+1,j+1,vertices[2]); + callback->processTriangle(vertices,x,j); + } + } + } + + + +} + +void btHeightfieldTerrainShape::calculateLocalInertia(btScalar ,btVector3& inertia) +{ + //moving concave objects not supported + + inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); +} + +void btHeightfieldTerrainShape::setLocalScaling(const btVector3& scaling) +{ + m_localScaling = scaling; +} +const btVector3& btHeightfieldTerrainShape::getLocalScaling() const +{ + return m_localScaling; +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h new file mode 100644 index 00000000000..49f3e106733 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h @@ -0,0 +1,88 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef HEIGHTFIELD_TERRAIN_SHAPE_H +#define HEIGHTFIELD_TERRAIN_SHAPE_H + +#include "btConcaveShape.h" + +///btHeightfieldTerrainShape simulates a 2D heightfield terrain +class btHeightfieldTerrainShape : public btConcaveShape +{ +protected: + btVector3 m_localAabbMin; + btVector3 m_localAabbMax; + + ///terrain data + int m_width; + int m_length; + btScalar m_maxHeight; + union + { + unsigned char* m_heightfieldDataUnsignedChar; + btScalar* m_heightfieldDataFloat; + void* m_heightfieldDataUnknown; + }; + + bool m_useFloatData; + bool m_flipQuadEdges; + bool m_useDiamondSubdivision; + + int m_upAxis; + + btVector3 m_localScaling; + + virtual btScalar getHeightFieldValue(int x,int y) const; + void quantizeWithClamp(int* out, const btVector3& point) const; + void getVertex(int x,int y,btVector3& vertex) const; + + inline bool testQuantizedAabbAgainstQuantizedAabb(int* aabbMin1, int* aabbMax1,const int* aabbMin2,const int* aabbMax2) const + { + bool overlap = true; + overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap; + overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap; + overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap; + return overlap; + } + +public: + btHeightfieldTerrainShape(int width,int height,void* heightfieldData, btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges); + + virtual ~btHeightfieldTerrainShape(); + + + void setUseDiamondSubdivision(bool useDiamondSubdivision=true) { m_useDiamondSubdivision = useDiamondSubdivision;} + + virtual int getShapeType() const + { + return TERRAIN_SHAPE_PROXYTYPE; + } + + virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; + + virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; + + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); + + virtual void setLocalScaling(const btVector3& scaling); + + virtual const btVector3& getLocalScaling() const; + + //debugging + virtual char* getName()const {return "HEIGHTFIELD";} + +}; + +#endif //HEIGHTFIELD_TERRAIN_SHAPE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp new file mode 100644 index 00000000000..015314bc09f --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp @@ -0,0 +1,57 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btMinkowskiSumShape.h" + + +btMinkowskiSumShape::btMinkowskiSumShape(const btConvexShape* shapeA,const btConvexShape* shapeB) +:m_shapeA(shapeA), +m_shapeB(shapeB) +{ + m_transA.setIdentity(); + m_transB.setIdentity(); +} + +btVector3 btMinkowskiSumShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const +{ + btVector3 supVertexA = m_transA(m_shapeA->localGetSupportingVertexWithoutMargin(vec*m_transA.getBasis())); + btVector3 supVertexB = m_transB(m_shapeB->localGetSupportingVertexWithoutMargin(vec*m_transB.getBasis())); + return supVertexA + supVertexB; +} + +void btMinkowskiSumShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + //todo: could make recursive use of batching. probably this shape is not used frequently. + for (int i=0;igetMargin() + m_shapeB->getMargin(); +} + + +void btMinkowskiSumShape::calculateLocalInertia(btScalar mass,btVector3& inertia) +{ + (void)mass; + btAssert(0); + inertia.setValue(0,0,0); +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h new file mode 100644 index 00000000000..198faaff9f9 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h @@ -0,0 +1,62 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef MINKOWSKI_SUM_SHAPE_H +#define MINKOWSKI_SUM_SHAPE_H + +#include "btConvexShape.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types + +/// btMinkowskiSumShape represents implicit (getSupportingVertex) based minkowski sum of two convex implicit shapes. +class btMinkowskiSumShape : public btConvexShape +{ + + btTransform m_transA; + btTransform m_transB; + const btConvexShape* m_shapeA; + const btConvexShape* m_shapeB; + +public: + + btMinkowskiSumShape(const btConvexShape* shapeA,const btConvexShape* shapeB); + + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; + + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; + + + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); + + void setTransformA(const btTransform& transA) { m_transA = transA;} + void setTransformB(const btTransform& transB) { m_transB = transB;} + + const btTransform& getTransformA()const { return m_transA;} + const btTransform& GetTransformB()const { return m_transB;} + + + virtual int getShapeType() const { return MINKOWSKI_SUM_SHAPE_PROXYTYPE; } + + virtual btScalar getMargin() const; + + const btConvexShape* getShapeA() const { return m_shapeA;} + const btConvexShape* getShapeB() const { return m_shapeB;} + + virtual char* getName()const + { + return "MinkowskiSum"; + } +}; + +#endif //MINKOWSKI_SUM_SHAPE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp new file mode 100644 index 00000000000..6015a618082 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp @@ -0,0 +1,148 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btMultiSphereShape.h" +#include "BulletCollision/CollisionShapes/btCollisionMargin.h" +#include "LinearMath/btQuaternion.h" + +btMultiSphereShape::btMultiSphereShape (const btVector3& inertiaHalfExtents,const btVector3* positions,const btScalar* radi,int numSpheres) +:m_inertiaHalfExtents(inertiaHalfExtents) +{ + btScalar startMargin = btScalar(1e30); + + m_numSpheres = numSpheres; + for (int i=0;i maxDot) + { + maxDot = newDot; + supVec = vtx; + } + } + + return supVec; + +} + + void btMultiSphereShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + + for (int j=0;j maxDot) + { + maxDot = newDot; + supportVerticesOut[j] = vtx; + } + } + } +} + + + + + + + + +void btMultiSphereShape::calculateLocalInertia(btScalar mass,btVector3& inertia) +{ + //as an approximation, take the inertia of the box that bounds the spheres + + btTransform ident; + ident.setIdentity(); +// btVector3 aabbMin,aabbMax; + +// getAabb(ident,aabbMin,aabbMax); + + btVector3 halfExtents = m_inertiaHalfExtents;//(aabbMax - aabbMin)* btScalar(0.5); + + btScalar margin = CONVEX_DISTANCE_MARGIN; + + btScalar lx=btScalar(2.)*(halfExtents[0]+margin); + btScalar ly=btScalar(2.)*(halfExtents[1]+margin); + btScalar lz=btScalar(2.)*(halfExtents[2]+margin); + const btScalar x2 = lx*lx; + const btScalar y2 = ly*ly; + const btScalar z2 = lz*lz; + const btScalar scaledmass = mass * btScalar(.08333333); + + inertia[0] = scaledmass * (y2+z2); + inertia[1] = scaledmass * (x2+z2); + inertia[2] = scaledmass * (x2+y2); + +} + + + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.h new file mode 100644 index 00000000000..1897b474057 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.h @@ -0,0 +1,74 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef MULTI_SPHERE_MINKOWSKI_H +#define MULTI_SPHERE_MINKOWSKI_H + +#include "btConvexShape.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types + +#define MAX_NUM_SPHERES 5 + +///btMultiSphereShape represents implicit convex hull of a collection of spheres (using getSupportingVertex) +class btMultiSphereShape : public btConvexShape + +{ + + btVector3 m_localPositions[MAX_NUM_SPHERES]; + btScalar m_radi[MAX_NUM_SPHERES]; + btVector3 m_inertiaHalfExtents; + + int m_numSpheres; + + + + +public: + btMultiSphereShape (const btVector3& inertiaHalfExtents,const btVector3* positions,const btScalar* radi,int numSpheres); + + ///CollisionShape Interface + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); + + /// btConvexShape Interface + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; + + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; + + int getSphereCount() const + { + return m_numSpheres; + } + + const btVector3& getSpherePosition(int index) const + { + return m_localPositions[index]; + } + + btScalar getSphereRadius(int index) const + { + return m_radi[index]; + } + + virtual int getShapeType() const { return MULTI_SPHERE_SHAPE_PROXYTYPE; } + + virtual char* getName()const + { + return "MultiSphere"; + } + +}; + + +#endif //MULTI_SPHERE_MINKOWSKI_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp new file mode 100644 index 00000000000..44438a24455 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp @@ -0,0 +1,845 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btOptimizedBvh.h" +#include "btStridingMeshInterface.h" +#include "LinearMath/btAabbUtil2.h" +#include "LinearMath/btIDebugDraw.h" + + + +btOptimizedBvh::btOptimizedBvh() : m_useQuantization(false), + m_traversalMode(TRAVERSAL_STACKLESS_CACHE_FRIENDLY) + //m_traversalMode(TRAVERSAL_STACKLESS) + //m_traversalMode(TRAVERSAL_RECURSIVE) +{ + +} + + +void btOptimizedBvh::build(btStridingMeshInterface* triangles, bool useQuantizedAabbCompression, const btVector3& bvhAabbMin, const btVector3& bvhAabbMax) +{ + m_useQuantization = useQuantizedAabbCompression; + + + // NodeArray triangleNodes; + + struct NodeTriangleCallback : public btInternalTriangleIndexCallback + { + + NodeArray& m_triangleNodes; + + NodeTriangleCallback& operator=(NodeTriangleCallback& other) + { + m_triangleNodes = other.m_triangleNodes; + return *this; + } + + NodeTriangleCallback(NodeArray& triangleNodes) + :m_triangleNodes(triangleNodes) + { + } + + virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) + { + btOptimizedBvhNode node; + btVector3 aabbMin,aabbMax; + aabbMin.setValue(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + aabbMax.setValue(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)); + aabbMin.setMin(triangle[0]); + aabbMax.setMax(triangle[0]); + aabbMin.setMin(triangle[1]); + aabbMax.setMax(triangle[1]); + aabbMin.setMin(triangle[2]); + aabbMax.setMax(triangle[2]); + + //with quantization? + node.m_aabbMinOrg = aabbMin; + node.m_aabbMaxOrg = aabbMax; + + node.m_escapeIndex = -1; + + //for child nodes + node.m_subPart = partId; + node.m_triangleIndex = triangleIndex; + m_triangleNodes.push_back(node); + } + }; + struct QuantizedNodeTriangleCallback : public btInternalTriangleIndexCallback + { + QuantizedNodeArray& m_triangleNodes; + const btOptimizedBvh* m_optimizedTree; // for quantization + + QuantizedNodeTriangleCallback& operator=(QuantizedNodeTriangleCallback& other) + { + m_triangleNodes = other.m_triangleNodes; + m_optimizedTree = other.m_optimizedTree; + return *this; + } + + QuantizedNodeTriangleCallback(QuantizedNodeArray& triangleNodes,const btOptimizedBvh* tree) + :m_triangleNodes(triangleNodes),m_optimizedTree(tree) + { + } + + virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) + { + btAssert(partId==0); + //negative indices are reserved for escapeIndex + btAssert(triangleIndex>=0); + + btQuantizedBvhNode node; + btVector3 aabbMin,aabbMax; + aabbMin.setValue(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + aabbMax.setValue(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)); + aabbMin.setMin(triangle[0]); + aabbMax.setMax(triangle[0]); + aabbMin.setMin(triangle[1]); + aabbMax.setMax(triangle[1]); + aabbMin.setMin(triangle[2]); + aabbMax.setMax(triangle[2]); + + m_optimizedTree->quantizeWithClamp(&node.m_quantizedAabbMin[0],aabbMin); + m_optimizedTree->quantizeWithClamp(&node.m_quantizedAabbMax[0],aabbMax); + + node.m_escapeIndexOrTriangleIndex = triangleIndex; + + m_triangleNodes.push_back(node); + } + }; + + + + int numLeafNodes = 0; + + + if (m_useQuantization) + { + + //initialize quantization values + setQuantizationValues(bvhAabbMin,bvhAabbMax); + + QuantizedNodeTriangleCallback callback(m_quantizedLeafNodes,this); + + + triangles->InternalProcessAllTriangles(&callback,m_bvhAabbMin,m_bvhAabbMax); + + //now we have an array of leafnodes in m_leafNodes + numLeafNodes = m_quantizedLeafNodes.size(); + + + m_quantizedContiguousNodes.resize(2*numLeafNodes); + + + } else + { + NodeTriangleCallback callback(m_leafNodes); + + btVector3 aabbMin(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)); + btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + + triangles->InternalProcessAllTriangles(&callback,aabbMin,aabbMax); + + //now we have an array of leafnodes in m_leafNodes + numLeafNodes = m_leafNodes.size(); + + m_contiguousNodes.resize(2*numLeafNodes); + } + + m_curNodeIndex = 0; + + buildTree(0,numLeafNodes); + + ///if the entire tree is small then subtree size, we need to create a header info for the tree + if(m_useQuantization && !m_SubtreeHeaders.size()) + { + btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); + subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[0]); + subtree.m_rootNodeIndex = 0; + subtree.m_subtreeSize = m_quantizedContiguousNodes[0].isLeafNode() ? 1 : m_quantizedContiguousNodes[0].getEscapeIndex(); + } +} + + + +void btOptimizedBvh::refitPartial(btStridingMeshInterface* meshInterface,const btVector3& aabbMin,const btVector3& aabbMax) +{ + //incrementally initialize quantization values + btAssert(m_useQuantization); + + btAssert(aabbMin.getX() > m_bvhAabbMin.getX()); + btAssert(aabbMin.getY() > m_bvhAabbMin.getY()); + btAssert(aabbMin.getZ() > m_bvhAabbMin.getZ()); + + btAssert(aabbMax.getX() < m_bvhAabbMax.getX()); + btAssert(aabbMax.getY() < m_bvhAabbMax.getY()); + btAssert(aabbMax.getZ() < m_bvhAabbMax.getZ()); + + ///we should update all quantization values, using updateBvhNodes(meshInterface); + ///but we only update chunks that overlap the given aabb + + unsigned short quantizedQueryAabbMin[3]; + unsigned short quantizedQueryAabbMax[3]; + + quantizeWithClamp(&quantizedQueryAabbMin[0],aabbMin); + quantizeWithClamp(&quantizedQueryAabbMax[0],aabbMax); + + int i; + for (i=0;im_SubtreeHeaders.size();i++) + { + btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; + + bool overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); + if (overlap) + { + updateBvhNodes(meshInterface,subtree.m_rootNodeIndex,subtree.m_rootNodeIndex+subtree.m_subtreeSize,i); + + subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]); + } + } + +} + +///just for debugging, to visualize the individual patches/subtrees +#ifdef DEBUG_PATCH_COLORS +btVector3 color[4]= +{ + btVector3(255,0,0), + btVector3(0,255,0), + btVector3(0,0,255), + btVector3(0,255,255) +}; +#endif //DEBUG_PATCH_COLORS + + +void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index) +{ + (void)index; + + btAssert(m_useQuantization); + + int nodeSubPart=0; + + //get access info to trianglemesh data + const unsigned char *vertexbase; + int numverts; + PHY_ScalarType type; + int stride; + const unsigned char *indexbase; + int indexstride; + int numfaces; + PHY_ScalarType indicestype; + meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,nodeSubPart); + + btVector3 triangleVerts[3]; + btVector3 aabbMin,aabbMax; + const btVector3& meshScaling = meshInterface->getScaling(); + + int i; + for (i=endNode-1;i>=firstNode;i--) + { + + + btQuantizedBvhNode& curNode = m_quantizedContiguousNodes[i]; + if (curNode.isLeafNode()) + { + //recalc aabb from triangle data + int nodeTriangleIndex = curNode.getTriangleIndex(); + //triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts, + + int* gfxbase = (int*)(indexbase+nodeTriangleIndex*indexstride); + + + for (int j=2;j>=0;j--) + { + + int graphicsindex = gfxbase[j]; + btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride); +#ifdef DEBUG_PATCH_COLORS + btVector3 mycolor = color[index&3]; + graphicsbase[8] = mycolor.getX(); + graphicsbase[9] = mycolor.getY(); + graphicsbase[10] = mycolor.getZ(); +#endif //DEBUG_PATCH_COLORS + + + triangleVerts[j] = btVector3( + graphicsbase[0]*meshScaling.getX(), + graphicsbase[1]*meshScaling.getY(), + graphicsbase[2]*meshScaling.getZ()); + } + + + + aabbMin.setValue(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + aabbMax.setValue(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)); + aabbMin.setMin(triangleVerts[0]); + aabbMax.setMax(triangleVerts[0]); + aabbMin.setMin(triangleVerts[1]); + aabbMax.setMax(triangleVerts[1]); + aabbMin.setMin(triangleVerts[2]); + aabbMax.setMax(triangleVerts[2]); + + quantizeWithClamp(&curNode.m_quantizedAabbMin[0],aabbMin); + quantizeWithClamp(&curNode.m_quantizedAabbMax[0],aabbMax); + + } else + { + //combine aabb from both children + + btQuantizedBvhNode* leftChildNode = &m_quantizedContiguousNodes[i+1]; + + btQuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? &m_quantizedContiguousNodes[i+2] : + &m_quantizedContiguousNodes[i+1+leftChildNode->getEscapeIndex()]; + + + { + for (int i=0;i<3;i++) + { + curNode.m_quantizedAabbMin[i] = leftChildNode->m_quantizedAabbMin[i]; + if (curNode.m_quantizedAabbMin[i]>rightChildNode->m_quantizedAabbMin[i]) + curNode.m_quantizedAabbMin[i]=rightChildNode->m_quantizedAabbMin[i]; + + curNode.m_quantizedAabbMax[i] = leftChildNode->m_quantizedAabbMax[i]; + if (curNode.m_quantizedAabbMax[i] < rightChildNode->m_quantizedAabbMax[i]) + curNode.m_quantizedAabbMax[i] = rightChildNode->m_quantizedAabbMax[i]; + } + } + } + + } + + meshInterface->unLockReadOnlyVertexBase(nodeSubPart); + + +} + +void btOptimizedBvh::setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin) +{ + //enlarge the AABB to avoid division by zero when initializing the quantization values + btVector3 clampValue(quantizationMargin,quantizationMargin,quantizationMargin); + m_bvhAabbMin = bvhAabbMin - clampValue; + m_bvhAabbMax = bvhAabbMax + clampValue; + btVector3 aabbSize = m_bvhAabbMax - m_bvhAabbMin; + m_bvhQuantization = btVector3(btScalar(65535.0),btScalar(65535.0),btScalar(65535.0)) / aabbSize; +} + + +void btOptimizedBvh::refit(btStridingMeshInterface* meshInterface) +{ + if (m_useQuantization) + { + //calculate new aabb + btVector3 aabbMin,aabbMax; + meshInterface->calculateAabbBruteForce(aabbMin,aabbMax); + + setQuantizationValues(aabbMin,aabbMax); + + updateBvhNodes(meshInterface,0,m_curNodeIndex,0); + + ///now update all subtree headers + + int i; + for (i=0;i gMaxStackDepth) + gMaxStackDepth = gStackDepth; +#endif //DEBUG_TREE_BUILDING + + + int splitAxis, splitIndex, i; + int numIndices =endIndex-startIndex; + int curIndex = m_curNodeIndex; + + assert(numIndices>0); + + if (numIndices==1) + { +#ifdef DEBUG_TREE_BUILDING + gStackDepth--; +#endif //DEBUG_TREE_BUILDING + + assignInternalNodeFromLeafNode(m_curNodeIndex,startIndex); + + m_curNodeIndex++; + return; + } + //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'. + + splitAxis = calcSplittingAxis(startIndex,endIndex); + + splitIndex = sortAndCalcSplittingIndex(startIndex,endIndex,splitAxis); + + int internalNodeIndex = m_curNodeIndex; + + setInternalNodeAabbMax(m_curNodeIndex,btVector3(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30))); + setInternalNodeAabbMin(m_curNodeIndex,btVector3(btScalar(1e30),btScalar(1e30),btScalar(1e30))); + + for (i=startIndex;im_escapeIndex; + + int leftChildNodexIndex = m_curNodeIndex; + + //build left child tree + buildTree(startIndex,splitIndex); + + int rightChildNodexIndex = m_curNodeIndex; + //build right child tree + buildTree(splitIndex,endIndex); + +#ifdef DEBUG_TREE_BUILDING + gStackDepth--; +#endif //DEBUG_TREE_BUILDING + + int escapeIndex = m_curNodeIndex - curIndex; + + if (m_useQuantization) + { + //escapeIndex is the number of nodes of this subtree + const int sizeQuantizedNode =sizeof(btQuantizedBvhNode); + const int treeSizeInBytes = escapeIndex * sizeQuantizedNode; + if (treeSizeInBytes > MAX_SUBTREE_SIZE_IN_BYTES) + { + updateSubtreeHeaders(leftChildNodexIndex,rightChildNodexIndex); + } + } + + setInternalNodeEscapeIndex(internalNodeIndex,escapeIndex); + +} + +void btOptimizedBvh::updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex) +{ + btAssert(m_useQuantization); + + btQuantizedBvhNode& leftChildNode = m_quantizedContiguousNodes[leftChildNodexIndex]; + int leftSubTreeSize = leftChildNode.isLeafNode() ? 1 : leftChildNode.getEscapeIndex(); + int leftSubTreeSizeInBytes = leftSubTreeSize * sizeof(btQuantizedBvhNode); + + btQuantizedBvhNode& rightChildNode = m_quantizedContiguousNodes[rightChildNodexIndex]; + int rightSubTreeSize = rightChildNode.isLeafNode() ? 1 : rightChildNode.getEscapeIndex(); + int rightSubTreeSizeInBytes = rightSubTreeSize * sizeof(btQuantizedBvhNode); + + if(leftSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES) + { + btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); + subtree.setAabbFromQuantizeNode(leftChildNode); + subtree.m_rootNodeIndex = leftChildNodexIndex; + subtree.m_subtreeSize = leftSubTreeSize; + } + + if(rightSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES) + { + btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); + subtree.setAabbFromQuantizeNode(rightChildNode); + subtree.m_rootNodeIndex = rightChildNodexIndex; + subtree.m_subtreeSize = rightSubTreeSize; + } +} + + +int btOptimizedBvh::sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis) +{ + int i; + int splitIndex =startIndex; + int numIndices = endIndex - startIndex; + btScalar splitValue; + + btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.)); + for (i=startIndex;i splitValue) + { + //swap + swapLeafNodes(i,splitIndex); + splitIndex++; + } + } + + //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex + //otherwise the tree-building might fail due to stack-overflows in certain cases. + //unbalanced1 is unsafe: it can cause stack overflows + //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1))); + + //unbalanced2 should work too: always use center (perfect balanced trees) + //bool unbalanced2 = true; + + //this should be safe too: + int rangeBalancedIndices = numIndices/3; + bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices))); + + if (unbalanced) + { + splitIndex = startIndex+ (numIndices>>1); + } + + bool unbal = (splitIndex==startIndex) || (splitIndex == (endIndex)); + btAssert(!unbal); + + return splitIndex; +} + + +int btOptimizedBvh::calcSplittingAxis(int startIndex,int endIndex) +{ + int i; + + btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.)); + btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.)); + int numIndices = endIndex-startIndex; + + for (i=startIndex;im_aabbMinOrg,rootNode->m_aabbMaxOrg); + isLeafNode = rootNode->m_escapeIndex == -1; + + if (isLeafNode && aabbOverlap) + { + nodeCallback->processNode(rootNode->m_subPart,rootNode->m_triangleIndex); + } + + if (aabbOverlap || isLeafNode) + { + rootNode++; + curIndex++; + } else + { + escapeIndex = rootNode->m_escapeIndex; + rootNode += escapeIndex; + curIndex += escapeIndex; + } + } + if (maxIterations < walkIterations) + maxIterations = walkIterations; + +} + +/* +///this was the original recursive traversal, before we optimized towards stackless traversal +void btOptimizedBvh::walkTree(btOptimizedBvhNode* rootNode,btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const +{ + bool isLeafNode, aabbOverlap = TestAabbAgainstAabb2(aabbMin,aabbMax,rootNode->m_aabbMin,rootNode->m_aabbMax); + if (aabbOverlap) + { + isLeafNode = (!rootNode->m_leftChild && !rootNode->m_rightChild); + if (isLeafNode) + { + nodeCallback->processNode(rootNode); + } else + { + walkTree(rootNode->m_leftChild,nodeCallback,aabbMin,aabbMax); + walkTree(rootNode->m_rightChild,nodeCallback,aabbMin,aabbMax); + } + } + +} +*/ + +void btOptimizedBvh::walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const +{ + btAssert(m_useQuantization); + + bool aabbOverlap, isLeafNode; + + aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,currentNode->m_quantizedAabbMin,currentNode->m_quantizedAabbMax); + isLeafNode = currentNode->isLeafNode(); + + if (aabbOverlap) + { + if (isLeafNode) + { + nodeCallback->processNode(0,currentNode->getTriangleIndex()); + } else + { + //process left and right children + const btQuantizedBvhNode* leftChildNode = currentNode+1; + walkRecursiveQuantizedTreeAgainstQueryAabb(leftChildNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax); + + const btQuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? leftChildNode+1:leftChildNode+leftChildNode->getEscapeIndex(); + walkRecursiveQuantizedTreeAgainstQueryAabb(rightChildNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax); + } + } +} + + + + + + + +void btOptimizedBvh::walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const +{ + btAssert(m_useQuantization); + + int curIndex = startNodeIndex; + int walkIterations = 0; + int subTreeSize = endNodeIndex - startNodeIndex; + + const btQuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[startNodeIndex]; + int escapeIndex; + + bool aabbOverlap, isLeafNode; + + while (curIndex < endNodeIndex) + { + +//#define VISUALLY_ANALYZE_BVH 1 +#ifdef VISUALLY_ANALYZE_BVH + //some code snippet to debugDraw aabb, to visually analyze bvh structure + static int drawPatch = 0; + //need some global access to a debugDrawer + extern btIDebugDraw* debugDrawerPtr; + if (curIndex==drawPatch) + { + btVector3 aabbMin,aabbMax; + aabbMin = unQuantize(rootNode->m_quantizedAabbMin); + aabbMax = unQuantize(rootNode->m_quantizedAabbMax); + btVector3 color(1,0,0); + debugDrawerPtr->drawAabb(aabbMin,aabbMax,color); + } +#endif//VISUALLY_ANALYZE_BVH + + //catch bugs in tree data + assert (walkIterations < subTreeSize); + + walkIterations++; + aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,rootNode->m_quantizedAabbMin,rootNode->m_quantizedAabbMax); + isLeafNode = rootNode->isLeafNode(); + + if (isLeafNode && aabbOverlap) + { + nodeCallback->processNode(0,rootNode->getTriangleIndex()); + } + + if (aabbOverlap || isLeafNode) + { + rootNode++; + curIndex++; + } else + { + escapeIndex = rootNode->getEscapeIndex(); + rootNode += escapeIndex; + curIndex += escapeIndex; + } + } + if (maxIterations < walkIterations) + maxIterations = walkIterations; + +} + +//This traversal can be called from Playstation 3 SPU +void btOptimizedBvh::walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const +{ + btAssert(m_useQuantization); + + int i; + + + for (i=0;im_SubtreeHeaders.size();i++) + { + const btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; + + bool overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); + if (overlap) + { + walkStacklessQuantizedTree(nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax, + subtree.m_rootNodeIndex, + subtree.m_rootNodeIndex+subtree.m_subtreeSize); + } + } +} + + + + +void btOptimizedBvh::reportSphereOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const +{ + (void)nodeCallback; + (void)aabbMin; + (void)aabbMax; + //not yet, please use aabb + btAssert(0); +} + + +void btOptimizedBvh::quantizeWithClamp(unsigned short* out, const btVector3& point) const +{ + + btAssert(m_useQuantization); + + btVector3 clampedPoint(point); + clampedPoint.setMax(m_bvhAabbMin); + clampedPoint.setMin(m_bvhAabbMax); + + btVector3 v = (clampedPoint - m_bvhAabbMin) * m_bvhQuantization; + out[0] = (unsigned short)(v.getX()+0.5f); + out[1] = (unsigned short)(v.getY()+0.5f); + out[2] = (unsigned short)(v.getZ()+0.5f); +} + +btVector3 btOptimizedBvh::unQuantize(const unsigned short* vecIn) const +{ + btVector3 vecOut; + vecOut.setValue( + (btScalar)(vecIn[0]) / (m_bvhQuantization.getX()), + (btScalar)(vecIn[1]) / (m_bvhQuantization.getY()), + (btScalar)(vecIn[2]) / (m_bvhQuantization.getZ())); + vecOut += m_bvhAabbMin; + return vecOut; +} + + +void btOptimizedBvh::swapLeafNodes(int i,int splitIndex) +{ + if (m_useQuantization) + { + btQuantizedBvhNode tmp = m_quantizedLeafNodes[i]; + m_quantizedLeafNodes[i] = m_quantizedLeafNodes[splitIndex]; + m_quantizedLeafNodes[splitIndex] = tmp; + } else + { + btOptimizedBvhNode tmp = m_leafNodes[i]; + m_leafNodes[i] = m_leafNodes[splitIndex]; + m_leafNodes[splitIndex] = tmp; + } +} + +void btOptimizedBvh::assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex) +{ + if (m_useQuantization) + { + m_quantizedContiguousNodes[internalNode] = m_quantizedLeafNodes[leafNodeIndex]; + } else + { + m_contiguousNodes[internalNode] = m_leafNodes[leafNodeIndex]; + } +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.h new file mode 100644 index 00000000000..d5159586344 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.h @@ -0,0 +1,330 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef OPTIMIZED_BVH_H +#define OPTIMIZED_BVH_H + + +#include "../../LinearMath/btVector3.h" + + +//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf__m128.asp + + + +class btStridingMeshInterface; + +//Note: currently we have 16 bytes per quantized node +#define MAX_SUBTREE_SIZE_IN_BYTES 2048 + + +///btQuantizedBvhNode is a compressed aabb node, 16 bytes. +///Node can be used for leafnode or internal node. Leafnodes can point to 32-bit triangle index (non-negative range). +ATTRIBUTE_ALIGNED16 (struct) btQuantizedBvhNode +{ + + //12 bytes + unsigned short int m_quantizedAabbMin[3]; + unsigned short int m_quantizedAabbMax[3]; + //4 bytes + int m_escapeIndexOrTriangleIndex; + + bool isLeafNode() const + { + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (m_escapeIndexOrTriangleIndex >= 0); + } + int getEscapeIndex() const + { + btAssert(!isLeafNode()); + return -m_escapeIndexOrTriangleIndex; + } + int getTriangleIndex() const + { + btAssert(isLeafNode()); + return m_escapeIndexOrTriangleIndex; + } +} +; + +/// btOptimizedBvhNode contains both internal and leaf node information. +/// Total node size is 44 bytes / node. You can use the compressed version of 16 bytes. +ATTRIBUTE_ALIGNED16 (struct) btOptimizedBvhNode +{ + //32 bytes + btVector3 m_aabbMinOrg; + btVector3 m_aabbMaxOrg; + + //4 + int m_escapeIndex; + + //8 + //for child nodes + int m_subPart; + int m_triangleIndex; + int m_padding[5];//bad, due to alignment + + +}; + + +///btBvhSubtreeInfo provides info to gather a subtree of limited size +ATTRIBUTE_ALIGNED16(class) btBvhSubtreeInfo +{ +public: + //12 bytes + unsigned short int m_quantizedAabbMin[3]; + unsigned short int m_quantizedAabbMax[3]; + //4 bytes, points to the root of the subtree + int m_rootNodeIndex; + //4 bytes + int m_subtreeSize; + int m_padding[3]; + + + void setAabbFromQuantizeNode(const btQuantizedBvhNode& quantizedNode) + { + m_quantizedAabbMin[0] = quantizedNode.m_quantizedAabbMin[0]; + m_quantizedAabbMin[1] = quantizedNode.m_quantizedAabbMin[1]; + m_quantizedAabbMin[2] = quantizedNode.m_quantizedAabbMin[2]; + m_quantizedAabbMax[0] = quantizedNode.m_quantizedAabbMax[0]; + m_quantizedAabbMax[1] = quantizedNode.m_quantizedAabbMax[1]; + m_quantizedAabbMax[2] = quantizedNode.m_quantizedAabbMax[2]; + } +} +; + + +class btNodeOverlapCallback +{ +public: + virtual ~btNodeOverlapCallback() {}; + + virtual void processNode(int subPart, int triangleIndex) = 0; +}; + +#include "../../LinearMath/btAlignedAllocator.h" +#include "../../LinearMath/btAlignedObjectArray.h" + + + +///for code readability: +typedef btAlignedObjectArray NodeArray; +typedef btAlignedObjectArray QuantizedNodeArray; +typedef btAlignedObjectArray BvhSubtreeInfoArray; + + +///OptimizedBvh store an AABB tree that can be quickly traversed on CPU (and SPU,GPU in future) +ATTRIBUTE_ALIGNED16(class) btOptimizedBvh +{ + NodeArray m_leafNodes; + NodeArray m_contiguousNodes; + + QuantizedNodeArray m_quantizedLeafNodes; + + QuantizedNodeArray m_quantizedContiguousNodes; + + int m_curNodeIndex; + + + //quantization data + bool m_useQuantization; + btVector3 m_bvhAabbMin; + btVector3 m_bvhAabbMax; + btVector3 m_bvhQuantization; + + enum btTraversalMode + { + TRAVERSAL_STACKLESS = 0, + TRAVERSAL_STACKLESS_CACHE_FRIENDLY, + TRAVERSAL_RECURSIVE + }; + + btTraversalMode m_traversalMode; + + + + + BvhSubtreeInfoArray m_SubtreeHeaders; + + + ///two versions, one for quantized and normal nodes. This allows code-reuse while maintaining readability (no template/macro!) + ///this might be refactored into a virtual, it is usually not calculated at run-time + void setInternalNodeAabbMin(int nodeIndex, const btVector3& aabbMin) + { + if (m_useQuantization) + { + quantizeWithClamp(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] ,aabbMin); + } else + { + m_contiguousNodes[nodeIndex].m_aabbMinOrg = aabbMin; + + } + } + void setInternalNodeAabbMax(int nodeIndex,const btVector3& aabbMax) + { + if (m_useQuantization) + { + quantizeWithClamp(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0],aabbMax); + } else + { + m_contiguousNodes[nodeIndex].m_aabbMaxOrg = aabbMax; + } + } + + btVector3 getAabbMin(int nodeIndex) const + { + if (m_useQuantization) + { + return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMin[0]); + } + //non-quantized + return m_leafNodes[nodeIndex].m_aabbMinOrg; + + } + btVector3 getAabbMax(int nodeIndex) const + { + if (m_useQuantization) + { + return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMax[0]); + } + //non-quantized + return m_leafNodes[nodeIndex].m_aabbMaxOrg; + + } + + void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.0)); + + void setInternalNodeEscapeIndex(int nodeIndex, int escapeIndex) + { + if (m_useQuantization) + { + m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = -escapeIndex; + } + else + { + m_contiguousNodes[nodeIndex].m_escapeIndex = escapeIndex; + } + + } + + void mergeInternalNodeAabb(int nodeIndex,const btVector3& newAabbMin,const btVector3& newAabbMax) + { + if (m_useQuantization) + { + unsigned short int quantizedAabbMin[3]; + unsigned short int quantizedAabbMax[3]; + quantizeWithClamp(quantizedAabbMin,newAabbMin); + quantizeWithClamp(quantizedAabbMax,newAabbMax); + for (int i=0;i<3;i++) + { + if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] > quantizedAabbMin[i]) + m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] = quantizedAabbMin[i]; + + if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] < quantizedAabbMax[i]) + m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] = quantizedAabbMax[i]; + + } + } else + { + //non-quantized + m_contiguousNodes[nodeIndex].m_aabbMinOrg.setMin(newAabbMin); + m_contiguousNodes[nodeIndex].m_aabbMaxOrg.setMax(newAabbMax); + } + } + + void swapLeafNodes(int firstIndex,int secondIndex); + + void assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex); + +protected: + + + + void buildTree (int startIndex,int endIndex); + + int calcSplittingAxis(int startIndex,int endIndex); + + int sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis); + + void walkStacklessTree(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; + + void walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const; + + ///tree traversal designed for small-memory processors like PS3 SPU + void walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const; + + ///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal + void walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const; + + ///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal + void walkRecursiveQuantizedTreeAgainstQuantizedTree(const btQuantizedBvhNode* treeNodeA,const btQuantizedBvhNode* treeNodeB,btNodeOverlapCallback* nodeCallback) const; + + + inline bool testQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) const + { + bool overlap = true; + overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap; + overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap; + overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap; + return overlap; + } + + void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex); + +public: + btOptimizedBvh(); + + virtual ~btOptimizedBvh(); + + void build(btStridingMeshInterface* triangles,bool useQuantizedAabbCompression, const btVector3& bvhAabbMin, const btVector3& bvhAabbMax); + + void reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; + + void reportSphereOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; + + void quantizeWithClamp(unsigned short* out, const btVector3& point) const; + + btVector3 unQuantize(const unsigned short* vecIn) const; + + ///setTraversalMode let's you choose between stackless, recursive or stackless cache friendly tree traversal. Note this is only implemented for quantized trees. + void setTraversalMode(btTraversalMode traversalMode) + { + m_traversalMode = traversalMode; + } + + void refit(btStridingMeshInterface* triangles); + + void refitPartial(btStridingMeshInterface* triangles,const btVector3& aabbMin, const btVector3& aabbMax); + + void updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index); + + + QuantizedNodeArray& getQuantizedNodeArray() + { + return m_quantizedContiguousNodes; + } + + BvhSubtreeInfoArray& getSubtreeInfoArray() + { + return m_SubtreeHeaders; + } + +} +; + + +#endif //OPTIMIZED_BVH_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp new file mode 100644 index 00000000000..bbc4ba62af6 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp @@ -0,0 +1,148 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include + +btPolyhedralConvexShape::btPolyhedralConvexShape() +:m_localAabbMin(1,1,1), +m_localAabbMax(-1,-1,-1), +m_isLocalAabbValid(false), +m_optionalHull(0) +{ + +} + + + +btVector3 btPolyhedralConvexShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const +{ + int i; + btVector3 supVec(0,0,0); + + btScalar maxDot(btScalar(-1e30)); + + btVector3 vec = vec0; + btScalar lenSqr = vec.length2(); + if (lenSqr < btScalar(0.0001)) + { + vec.setValue(1,0,0); + } else + { + btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); + vec *= rlen; + } + + btVector3 vtx; + btScalar newDot; + + for (i=0;i maxDot) + { + maxDot = newDot; + supVec = vtx; + } + } + + return supVec; + +} + +void btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + int i; + + btVector3 vtx; + btScalar newDot; + + for (i=0;i supportVerticesOut[j][3]) + { + //WARNING: don't swap next lines, the w component would get overwritten! + supportVerticesOut[j] = vtx; + supportVerticesOut[j][3] = newDot; + } + } + } +} + + + +void btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& inertia) +{ + //not yet, return box inertia + + btScalar margin = getMargin(); + + btTransform ident; + ident.setIdentity(); + btVector3 aabbMin,aabbMax; + getAabb(ident,aabbMin,aabbMax); + btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); + + btScalar lx=btScalar(2.)*(halfExtents.x()+margin); + btScalar ly=btScalar(2.)*(halfExtents.y()+margin); + btScalar lz=btScalar(2.)*(halfExtents.z()+margin); + const btScalar x2 = lx*lx; + const btScalar y2 = ly*ly; + const btScalar z2 = lz*lz; + const btScalar scaledmass = mass * btScalar(0.08333333); + + inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); + +} + + + +void btPolyhedralConvexShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const +{ + getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin()); +} + + + + +void btPolyhedralConvexShape::recalcLocalAabb() +{ + m_isLocalAabbValid = true; + + for (int i=0;i<3;i++) + { + btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); + vec[i] = btScalar(1.); + btVector3 tmp = localGetSupportingVertex(vec); + m_localAabbMax[i] = tmp[i]+m_collisionMargin; + vec[i] = btScalar(-1.); + tmp = localGetSupportingVertex(vec); + m_localAabbMin[i] = tmp[i]-m_collisionMargin; + } +} + + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h new file mode 100644 index 00000000000..c35f7512663 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h @@ -0,0 +1,93 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BU_SHAPE +#define BU_SHAPE + +#include "../../LinearMath/btPoint3.h" +#include "../../LinearMath/btMatrix3x3.h" +#include "btConvexShape.h" + + +///PolyhedralConvexShape is an interface class for feature based (vertex/edge/face) convex shapes. +class btPolyhedralConvexShape : public btConvexShape +{ + +protected: + btVector3 m_localAabbMin; + btVector3 m_localAabbMax; + bool m_isLocalAabbValid; + +public: + + btPolyhedralConvexShape(); + + //brute force implementations + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; + + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); + + + inline void getNonvirtualAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax, btScalar margin) const + { + + //lazy evaluation of local aabb + btAssert(m_isLocalAabbValid); + + btAssert(m_localAabbMin.getX() <= m_localAabbMax.getX()); + btAssert(m_localAabbMin.getY() <= m_localAabbMax.getY()); + btAssert(m_localAabbMin.getZ() <= m_localAabbMax.getZ()); + + + btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin); + btVector3 localCenter = btScalar(0.5)*(m_localAabbMax+m_localAabbMin); + + btMatrix3x3 abs_b = trans.getBasis().absolute(); + + btPoint3 center = trans(localCenter); + + btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), + abs_b[1].dot(localHalfExtents), + abs_b[2].dot(localHalfExtents)); + extent += btVector3(margin,margin,margin); + + aabbMin = center - extent; + aabbMax = center + extent; + + + } + + + virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; + + void recalcLocalAabb(); + + virtual int getNumVertices() const = 0 ; + virtual int getNumEdges() const = 0; + virtual void getEdge(int i,btPoint3& pa,btPoint3& pb) const = 0; + virtual void getVertex(int i,btPoint3& vtx) const = 0; + virtual int getNumPlanes() const = 0; + virtual void getPlane(btVector3& planeNormal,btPoint3& planeSupport,int i ) const = 0; +// virtual int getIndex(int i) const = 0 ; + + virtual bool isInside(const btPoint3& pt,btScalar tolerance) const = 0; + + /// optional Hull is for optional Separating Axis Test Hull collision detection, see Hull.cpp + class Hull* m_optionalHull; + +}; + +#endif //BU_SHAPE diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.cpp new file mode 100644 index 00000000000..ca65dd03f3e --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.cpp @@ -0,0 +1,77 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btSphereShape.h" +#include "BulletCollision/CollisionShapes/btCollisionMargin.h" + +#include "LinearMath/btQuaternion.h" + + +btSphereShape ::btSphereShape (btScalar radius) +{ + m_implicitShapeDimensions.setX(radius); +} + +btVector3 btSphereShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const +{ + (void)vec; + return btVector3(btScalar(0.),btScalar(0.),btScalar(0.)); +} + +void btSphereShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const +{ + (void)vectors; + + for (int i=0;iprocessTriangle(triangle,0,0); + + triangle[0] = projectedCenter - tangentDir0*radius - tangentDir1*radius; + triangle[1] = projectedCenter - tangentDir0*radius + tangentDir1*radius; + triangle[2] = projectedCenter + tangentDir0*radius + tangentDir1*radius; + + callback->processTriangle(triangle,0,1); + +} + +void btStaticPlaneShape::calculateLocalInertia(btScalar mass,btVector3& inertia) +{ + (void)mass; + + //moving concave objects not supported + + inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); +} + +void btStaticPlaneShape::setLocalScaling(const btVector3& scaling) +{ + m_localScaling = scaling; +} +const btVector3& btStaticPlaneShape::getLocalScaling() const +{ + return m_localScaling; +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h new file mode 100644 index 00000000000..f59cc0c3347 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h @@ -0,0 +1,61 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef STATIC_PLANE_SHAPE_H +#define STATIC_PLANE_SHAPE_H + +#include "btConcaveShape.h" + + +///StaticPlaneShape simulates an 'infinite' plane by dynamically reporting triangles approximated by intersection of the plane with the AABB. +///Assumed is that the other objects is not also infinite, so a reasonable sized AABB. +class btStaticPlaneShape : public btConcaveShape +{ +protected: + btVector3 m_localAabbMin; + btVector3 m_localAabbMax; + + btVector3 m_planeNormal; + btScalar m_planeConstant; + btVector3 m_localScaling; + +public: + btStaticPlaneShape(const btVector3& planeNormal,btScalar planeConstant); + + virtual ~btStaticPlaneShape(); + + + virtual int getShapeType() const + { + return STATIC_PLANE_PROXYTYPE; + } + + virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; + + virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; + + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); + + virtual void setLocalScaling(const btVector3& scaling); + virtual const btVector3& getLocalScaling() const; + + + //debugging + virtual char* getName()const {return "STATICPLANE";} + + +}; + +#endif //STATIC_PLANE_SHAPE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp new file mode 100644 index 00000000000..03ca1ae7736 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp @@ -0,0 +1,124 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btStridingMeshInterface.h" + +btStridingMeshInterface::~btStridingMeshInterface() +{ + +} + + +void btStridingMeshInterface::InternalProcessAllTriangles(btInternalTriangleIndexCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const +{ + (void)aabbMin; + (void)aabbMax; + int numtotalphysicsverts = 0; + int part,graphicssubparts = getNumSubParts(); + const unsigned char * vertexbase; + const unsigned char * indexbase; + int indexstride; + PHY_ScalarType type; + PHY_ScalarType gfxindextype; + int stride,numverts,numtriangles; + int gfxindex; + btVector3 triangle[3]; + btScalar* graphicsbase; + + btVector3 meshScaling = getScaling(); + + ///if the number of parts is big, the performance might drop due to the innerloop switch on indextype + for (part=0;partinternalProcessTriangleIndex(triangle,part,gfxindex); + } + break; + } + case PHY_SHORT: + { + for (gfxindex=0;gfxindexinternalProcessTriangleIndex(triangle,part,gfxindex); + } + break; + } + default: + btAssert((gfxindextype == PHY_INTEGER) || (gfxindextype == PHY_SHORT)); + } + + unLockReadOnlyVertexBase(part); + } +} + +void btStridingMeshInterface::calculateAabbBruteForce(btVector3& aabbMin,btVector3& aabbMax) +{ + + struct AabbCalculationCallback : public btInternalTriangleIndexCallback + { + btVector3 m_aabbMin; + btVector3 m_aabbMax; + + AabbCalculationCallback() + { + m_aabbMin.setValue(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + m_aabbMax.setValue(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)); + } + + virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) + { + (void)partId; + (void)triangleIndex; + + m_aabbMin.setMin(triangle[0]); + m_aabbMax.setMax(triangle[0]); + m_aabbMin.setMin(triangle[1]); + m_aabbMax.setMax(triangle[1]); + m_aabbMin.setMin(triangle[2]); + m_aabbMax.setMax(triangle[2]); + } + }; + + //first calculate the total aabb for all triangles + AabbCalculationCallback aabbCallback; + aabbMin.setValue(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)); + aabbMax.setValue(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + InternalProcessAllTriangles(&aabbCallback,aabbMin,aabbMax); + + aabbMin = aabbCallback.m_aabbMin; + aabbMax = aabbCallback.m_aabbMax; +} \ No newline at end of file diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.h new file mode 100644 index 00000000000..d7b354b7855 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.h @@ -0,0 +1,89 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef STRIDING_MESHINTERFACE_H +#define STRIDING_MESHINTERFACE_H + +#include "../../LinearMath/btVector3.h" +#include "btTriangleCallback.h" + +/// PHY_ScalarType enumerates possible scalar types. +/// See the btStridingMeshInterface for its use +typedef enum PHY_ScalarType { + PHY_FLOAT, + PHY_DOUBLE, + PHY_INTEGER, + PHY_SHORT, + PHY_FIXEDPOINT88 +} PHY_ScalarType; + +/// btStridingMeshInterface is the interface class for high performance access to triangle meshes +/// It allows for sharing graphics and collision meshes. Also it provides locking/unlocking of graphics meshes that are in gpu memory. +class btStridingMeshInterface +{ + protected: + + btVector3 m_scaling; + + public: + btStridingMeshInterface() :m_scaling(btScalar(1.),btScalar(1.),btScalar(1.)) + { + + } + + virtual ~btStridingMeshInterface(); + + + + void InternalProcessAllTriangles(btInternalTriangleIndexCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; + + ///brute force method to calculate aabb + void calculateAabbBruteForce(btVector3& aabbMin,btVector3& aabbMax); + + /// get read and write access to a subpart of a triangle mesh + /// this subpart has a continuous array of vertices and indices + /// in this way the mesh can be handled as chunks of memory with striding + /// very similar to OpenGL vertexarray support + /// make a call to unLockVertexBase when the read and write access is finished + virtual void getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0)=0; + + virtual void getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0) const=0; + + /// unLockVertexBase finishes the access to a subpart of the triangle mesh + /// make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished + virtual void unLockVertexBase(int subpart)=0; + + virtual void unLockReadOnlyVertexBase(int subpart) const=0; + + + /// getNumSubParts returns the number of seperate subparts + /// each subpart has a continuous array of vertices and indices + virtual int getNumSubParts() const=0; + + virtual void preallocateVertices(int numverts)=0; + virtual void preallocateIndices(int numindices)=0; + + const btVector3& getScaling() const { + return m_scaling; + } + void setScaling(const btVector3& scaling) + { + m_scaling = scaling; + } + + +}; + +#endif //STRIDING_MESHINTERFACE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp new file mode 100644 index 00000000000..3aa1eda9964 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp @@ -0,0 +1,195 @@ + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +#include "btTetrahedronShape.h" +#include "LinearMath/btMatrix3x3.h" + +btBU_Simplex1to4::btBU_Simplex1to4() +:m_numVertices(0) +{ +} + +btBU_Simplex1to4::btBU_Simplex1to4(const btPoint3& pt0) +:m_numVertices(0) +{ + addVertex(pt0); +} + +btBU_Simplex1to4::btBU_Simplex1to4(const btPoint3& pt0,const btPoint3& pt1) +:m_numVertices(0) +{ + addVertex(pt0); + addVertex(pt1); +} + +btBU_Simplex1to4::btBU_Simplex1to4(const btPoint3& pt0,const btPoint3& pt1,const btPoint3& pt2) +:m_numVertices(0) +{ + addVertex(pt0); + addVertex(pt1); + addVertex(pt2); +} + +btBU_Simplex1to4::btBU_Simplex1to4(const btPoint3& pt0,const btPoint3& pt1,const btPoint3& pt2,const btPoint3& pt3) +:m_numVertices(0) +{ + addVertex(pt0); + addVertex(pt1); + addVertex(pt2); + addVertex(pt3); +} + + + + + +void btBU_Simplex1to4::addVertex(const btPoint3& pt) +{ + m_vertices[m_numVertices++] = pt; + + recalcLocalAabb(); +} + + +int btBU_Simplex1to4::getNumVertices() const +{ + return m_numVertices; +} + +int btBU_Simplex1to4::getNumEdges() const +{ + //euler formula, F-E+V = 2, so E = F+V-2 + + switch (m_numVertices) + { + case 0: + return 0; + case 1: return 0; + case 2: return 1; + case 3: return 3; + case 4: return 6; + + + } + + return 0; +} + +void btBU_Simplex1to4::getEdge(int i,btPoint3& pa,btPoint3& pb) const +{ + + switch (m_numVertices) + { + + case 2: + pa = m_vertices[0]; + pb = m_vertices[1]; + break; + case 3: + switch (i) + { + case 0: + pa = m_vertices[0]; + pb = m_vertices[1]; + break; + case 1: + pa = m_vertices[1]; + pb = m_vertices[2]; + break; + case 2: + pa = m_vertices[2]; + pb = m_vertices[0]; + break; + + } + break; + case 4: + switch (i) + { + case 0: + pa = m_vertices[0]; + pb = m_vertices[1]; + break; + case 1: + pa = m_vertices[1]; + pb = m_vertices[2]; + break; + case 2: + pa = m_vertices[2]; + pb = m_vertices[0]; + break; + case 3: + pa = m_vertices[0]; + pb = m_vertices[3]; + break; + case 4: + pa = m_vertices[1]; + pb = m_vertices[3]; + break; + case 5: + pa = m_vertices[2]; + pb = m_vertices[3]; + break; + } + + } + + + + +} + +void btBU_Simplex1to4::getVertex(int i,btPoint3& vtx) const +{ + vtx = m_vertices[i]; +} + +int btBU_Simplex1to4::getNumPlanes() const +{ + switch (m_numVertices) + { + case 0: + return 0; + case 1: + return 0; + case 2: + return 0; + case 3: + return 2; + case 4: + return 4; + default: + { + } + } + return 0; +} + + +void btBU_Simplex1to4::getPlane(btVector3&, btPoint3& ,int ) const +{ + +} + +int btBU_Simplex1to4::getIndex(int ) const +{ + return 0; +} + +bool btBU_Simplex1to4::isInside(const btPoint3& ,btScalar ) const +{ + return false; +} + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.h new file mode 100644 index 00000000000..94bc4ec0fa5 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.h @@ -0,0 +1,75 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BU_SIMPLEX_1TO4_SHAPE +#define BU_SIMPLEX_1TO4_SHAPE + + +#include "btPolyhedralConvexShape.h" +#include "../BroadphaseCollision/btBroadphaseProxy.h" + + +///BU_Simplex1to4 implements feature based and implicit simplex of up to 4 vertices (tetrahedron, triangle, line, vertex). +class btBU_Simplex1to4 : public btPolyhedralConvexShape +{ +protected: + + int m_numVertices; + btPoint3 m_vertices[4]; + +public: + btBU_Simplex1to4(); + + btBU_Simplex1to4(const btPoint3& pt0); + btBU_Simplex1to4(const btPoint3& pt0,const btPoint3& pt1); + btBU_Simplex1to4(const btPoint3& pt0,const btPoint3& pt1,const btPoint3& pt2); + btBU_Simplex1to4(const btPoint3& pt0,const btPoint3& pt1,const btPoint3& pt2,const btPoint3& pt3); + + + void reset() + { + m_numVertices = 0; + } + + + virtual int getShapeType() const{ return TETRAHEDRAL_SHAPE_PROXYTYPE; } + + void addVertex(const btPoint3& pt); + + //PolyhedralConvexShape interface + + virtual int getNumVertices() const; + + virtual int getNumEdges() const; + + virtual void getEdge(int i,btPoint3& pa,btPoint3& pb) const; + + virtual void getVertex(int i,btPoint3& vtx) const; + + virtual int getNumPlanes() const; + + virtual void getPlane(btVector3& planeNormal,btPoint3& planeSupport,int i) const; + + virtual int getIndex(int i) const; + + virtual bool isInside(const btPoint3& pt,btScalar tolerance) const; + + + ///getName is for debugging + virtual char* getName()const { return "btBU_Simplex1to4";} + +}; + +#endif //BU_SIMPLEX_1TO4_SHAPE diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp new file mode 100644 index 00000000000..54864c32f3a --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp @@ -0,0 +1,42 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btTriangleBuffer.h" + + +///example usage of this class: +// btTriangleBuffer triBuf; +// concaveShape->processAllTriangles(&triBuf,aabbMin, aabbMax); +// for (int i=0;i m_triangleBuffer; + +public: + + + virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); + + int getNumTriangles() const + { + return int(m_triangleBuffer.size()); + } + + const btTriangle& getTriangle(int index) const + { + return m_triangleBuffer[index]; + } + + void clearBuffer() + { + m_triangleBuffer.clear(); + } + +}; + + +#endif //BT_TRIANGLE_BUFFER_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.cpp new file mode 100644 index 00000000000..a020746db5f --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.cpp @@ -0,0 +1,28 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btTriangleCallback.h" + +btTriangleCallback::~btTriangleCallback() +{ + +} + + +btInternalTriangleIndexCallback::~btInternalTriangleIndexCallback() +{ + +} + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.h new file mode 100644 index 00000000000..fbb87bc4fd8 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.h @@ -0,0 +1,40 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef TRIANGLE_CALLBACK_H +#define TRIANGLE_CALLBACK_H + +#include "../../LinearMath/btVector3.h" + + +class btTriangleCallback +{ +public: + + virtual ~btTriangleCallback(); + virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) = 0; +}; + +class btInternalTriangleIndexCallback +{ +public: + + virtual ~btInternalTriangleIndexCallback(); + virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) = 0; +}; + + + +#endif //TRIANGLE_CALLBACK_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp new file mode 100644 index 00000000000..00847861cf1 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp @@ -0,0 +1,65 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btTriangleIndexVertexArray.h" + +btTriangleIndexVertexArray::btTriangleIndexVertexArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride,int numVertices,btScalar* vertexBase,int vertexStride) +{ + btIndexedMesh mesh; + + mesh.m_numTriangles = numTriangles; + mesh.m_triangleIndexBase = (const unsigned char *)triangleIndexBase; + mesh.m_triangleIndexStride = triangleIndexStride; + mesh.m_numVertices = numVertices; + mesh.m_vertexBase = (const unsigned char *)vertexBase; + mesh.m_vertexStride = vertexStride; + + addIndexedMesh(mesh); + +} + +void btTriangleIndexVertexArray::getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart) +{ + btAssert(subpart< getNumSubParts() ); + + btIndexedMesh& mesh = m_indexedMeshes[subpart]; + + numverts = mesh.m_numVertices; + (*vertexbase) = (unsigned char *) mesh.m_vertexBase; + type = PHY_FLOAT; + vertexStride = mesh.m_vertexStride; + + numfaces = mesh.m_numTriangles; + + (*indexbase) = (unsigned char *)mesh.m_triangleIndexBase; + indexstride = mesh.m_triangleIndexStride; + indicestype = PHY_INTEGER; +} + +void btTriangleIndexVertexArray::getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart) const +{ + const btIndexedMesh& mesh = m_indexedMeshes[subpart]; + + numverts = mesh.m_numVertices; + (*vertexbase) = (const unsigned char *)mesh.m_vertexBase; + type = PHY_FLOAT; + vertexStride = mesh.m_vertexStride; + + numfaces = mesh.m_numTriangles; + (*indexbase) = (const unsigned char *)mesh.m_triangleIndexBase; + indexstride = mesh.m_triangleIndexStride; + indicestype = PHY_INTEGER; +} + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h new file mode 100644 index 00000000000..6ab6a762b39 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h @@ -0,0 +1,97 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_TRIANGLE_INDEX_VERTEX_ARRAY_H +#define BT_TRIANGLE_INDEX_VERTEX_ARRAY_H + +#include "btStridingMeshInterface.h" +#include "../../LinearMath/btAlignedObjectArray.h" + +///IndexedMesh indexes into existing vertex and index arrays, in a similar way OpenGL glDrawElements +///instead of the number of indices, we pass the number of triangles +///todo: explain with pictures +ATTRIBUTE_ALIGNED16( struct) btIndexedMesh +{ + int m_numTriangles; + const unsigned char * m_triangleIndexBase; + int m_triangleIndexStride; + int m_numVertices; + const unsigned char * m_vertexBase; + int m_vertexStride; + int pad[2]; +} +; + + +typedef btAlignedObjectArray IndexedMeshArray; + +///TriangleIndexVertexArray allows to use multiple meshes, by indexing into existing triangle/index arrays. +///Additional meshes can be added using addIndexedMesh +///No duplcate is made of the vertex/index data, it only indexes into external vertex/index arrays. +///So keep those arrays around during the lifetime of this btTriangleIndexVertexArray. +ATTRIBUTE_ALIGNED16( class) btTriangleIndexVertexArray : public btStridingMeshInterface +{ + IndexedMeshArray m_indexedMeshes; + int m_pad[3]; + + +public: + + btTriangleIndexVertexArray() + { + } + + //just to be backwards compatible + btTriangleIndexVertexArray(int numTriangleIndices,int* triangleIndexBase,int triangleIndexStride,int numVertices,btScalar* vertexBase,int vertexStride); + + void addIndexedMesh(const btIndexedMesh& mesh) + { + m_indexedMeshes.push_back(mesh); + } + + + virtual void getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0); + + virtual void getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0) const; + + /// unLockVertexBase finishes the access to a subpart of the triangle mesh + /// make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished + virtual void unLockVertexBase(int subpart) {(void)subpart;} + + virtual void unLockReadOnlyVertexBase(int subpart) const {(void)subpart;} + + /// getNumSubParts returns the number of seperate subparts + /// each subpart has a continuous array of vertices and indices + virtual int getNumSubParts() const { + return (int)m_indexedMeshes.size(); + } + + IndexedMeshArray& getIndexedMeshArray() + { + return m_indexedMeshes; + } + + const IndexedMeshArray& getIndexedMeshArray() const + { + return m_indexedMeshes; + } + + virtual void preallocateVertices(int numverts){(void) numverts;} + virtual void preallocateIndices(int numindices){(void) numindices;} + +} +; + +#endif //BT_TRIANGLE_INDEX_VERTEX_ARRAY_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp new file mode 100644 index 00000000000..98c54ef45f8 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp @@ -0,0 +1,60 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btTriangleMesh.h" +#include + + +btTriangleMesh::btTriangleMesh () +{ + +} + +void btTriangleMesh::getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart) +{ + (void)subpart; + numverts = m_vertices.size(); + *vertexbase = (unsigned char*)&m_vertices[0]; + type = PHY_FLOAT; + stride = sizeof(btVector3); + + numfaces = m_indices.size()/3; + *indexbase = (unsigned char*) &m_indices[0]; + indicestype = PHY_INTEGER; + indexstride = 3*sizeof(int); + +} + +void btTriangleMesh::getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart) const +{ + (void)subpart; + numverts = m_vertices.size(); + *vertexbase = (unsigned char*)&m_vertices[0]; + type = PHY_FLOAT; + stride = sizeof(btVector3); + + numfaces = m_indices.size()/3; + *indexbase = (unsigned char*) &m_indices[0]; + indicestype = PHY_INTEGER; + indexstride = 3*sizeof(int); + +} + + + +int btTriangleMesh::getNumSubParts() const +{ + return 1; +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h new file mode 100644 index 00000000000..525f5336b48 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h @@ -0,0 +1,75 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef TRIANGLE_MESH_H +#define TRIANGLE_MESH_H + +#include "btStridingMeshInterface.h" +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btAlignedObjectArray.h" + +///TriangleMesh provides storage for a concave triangle mesh. It can be used as data for the btTriangleMeshShape. +class btTriangleMesh : public btStridingMeshInterface +{ + btAlignedObjectArray m_vertices; + btAlignedObjectArray m_indices; + + public: + btTriangleMesh (); + + void addTriangle(const btVector3& vertex0,const btVector3& vertex1,const btVector3& vertex2) + { + int curIndex = m_indices.size(); + m_vertices.push_back(vertex0); + m_vertices.push_back(vertex1); + m_vertices.push_back(vertex2); + + m_indices.push_back(curIndex++); + m_indices.push_back(curIndex++); + m_indices.push_back(curIndex++); + } + + int getNumTriangles() const + { + return m_indices.size() / 3; + } + + + +//StridingMeshInterface interface implementation + + virtual void getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0); + + virtual void getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0) const; + + /// unLockVertexBase finishes the access to a subpart of the triangle mesh + /// make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished + virtual void unLockVertexBase(int subpart) {(void) subpart;} + + virtual void unLockReadOnlyVertexBase(int subpart) const { (void) subpart;} + + /// getNumSubParts returns the number of seperate subparts + /// each subpart has a continuous array of vertices and indices + virtual int getNumSubParts() const; + + virtual void preallocateVertices(int numverts){(void) numverts;} + virtual void preallocateIndices(int numindices){(void) numindices;} + + +}; + +#endif //TRIANGLE_MESH_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp new file mode 100644 index 00000000000..ed81897b515 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp @@ -0,0 +1,203 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btTriangleMeshShape.h" +#include "LinearMath/btVector3.h" +#include "LinearMath/btQuaternion.h" +#include "btStridingMeshInterface.h" +#include "LinearMath/btAabbUtil2.h" +#include "BulletCollision/CollisionShapes/btCollisionMargin.h" + +#include "stdio.h" + +btTriangleMeshShape::btTriangleMeshShape(btStridingMeshInterface* meshInterface) +: m_meshInterface(meshInterface) +{ + recalcLocalAabb(); +} + + +btTriangleMeshShape::~btTriangleMeshShape() +{ + +} + + + + +void btTriangleMeshShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const +{ + + btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin); + btVector3 localCenter = btScalar(0.5)*(m_localAabbMax+m_localAabbMin); + + btMatrix3x3 abs_b = trans.getBasis().absolute(); + + btPoint3 center = trans(localCenter); + + btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), + abs_b[1].dot(localHalfExtents), + abs_b[2].dot(localHalfExtents)); + extent += btVector3(getMargin(),getMargin(),getMargin()); + + aabbMin = center - extent; + aabbMax = center + extent; + + +} + +void btTriangleMeshShape::recalcLocalAabb() +{ + for (int i=0;i<3;i++) + { + btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); + vec[i] = btScalar(1.); + btVector3 tmp = localGetSupportingVertex(vec); + m_localAabbMax[i] = tmp[i]+m_collisionMargin; + vec[i] = btScalar(-1.); + tmp = localGetSupportingVertex(vec); + m_localAabbMin[i] = tmp[i]-m_collisionMargin; + } +} + + + +class SupportVertexCallback : public btTriangleCallback +{ + + btVector3 m_supportVertexLocal; +public: + + btTransform m_worldTrans; + btScalar m_maxDot; + btVector3 m_supportVecLocal; + + SupportVertexCallback(const btVector3& supportVecWorld,const btTransform& trans) + : m_supportVertexLocal(btScalar(0.),btScalar(0.),btScalar(0.)), m_worldTrans(trans) ,m_maxDot(btScalar(-1e30)) + + { + m_supportVecLocal = supportVecWorld * m_worldTrans.getBasis(); + } + + virtual void processTriangle( btVector3* triangle,int partId, int triangleIndex) + { + (void)partId; + (void)triangleIndex; + for (int i=0;i<3;i++) + { + btScalar dot = m_supportVecLocal.dot(triangle[i]); + if (dot > m_maxDot) + { + m_maxDot = dot; + m_supportVertexLocal = triangle[i]; + } + } + } + + btVector3 GetSupportVertexWorldSpace() + { + return m_worldTrans(m_supportVertexLocal); + } + + btVector3 GetSupportVertexLocal() + { + return m_supportVertexLocal; + } + +}; + + +void btTriangleMeshShape::setLocalScaling(const btVector3& scaling) +{ + m_meshInterface->setScaling(scaling); + recalcLocalAabb(); +} + +const btVector3& btTriangleMeshShape::getLocalScaling() const +{ + return m_meshInterface->getScaling(); +} + + + + + + +//#define DEBUG_TRIANGLE_MESH + + +void btTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const +{ + struct FilteredCallback : public btInternalTriangleIndexCallback + { + btTriangleCallback* m_callback; + btVector3 m_aabbMin; + btVector3 m_aabbMax; + + FilteredCallback(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) + :m_callback(callback), + m_aabbMin(aabbMin), + m_aabbMax(aabbMax) + { + } + + virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) + { + if (TestTriangleAgainstAabb2(&triangle[0],m_aabbMin,m_aabbMax)) + { + //check aabb in triangle-space, before doing this + m_callback->processTriangle(triangle,partId,triangleIndex); + } + + } + + }; + + FilteredCallback filterCallback(callback,aabbMin,aabbMax); + + m_meshInterface->InternalProcessAllTriangles(&filterCallback,aabbMin,aabbMax); +} + + + + + + +void btTriangleMeshShape::calculateLocalInertia(btScalar mass,btVector3& inertia) +{ + (void)mass; + //moving concave objects not supported + btAssert(0); + inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); +} + + +btVector3 btTriangleMeshShape::localGetSupportingVertex(const btVector3& vec) const +{ + btVector3 supportVertex; + + btTransform ident; + ident.setIdentity(); + + SupportVertexCallback supportCallback(vec,ident); + + btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + + processAllTriangles(&supportCallback,-aabbMax,aabbMax); + + supportVertex = supportCallback.GetSupportVertexLocal(); + + return supportVertex; +} diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.h new file mode 100644 index 00000000000..e6173e47640 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.h @@ -0,0 +1,78 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef TRIANGLE_MESH_SHAPE_H +#define TRIANGLE_MESH_SHAPE_H + +#include "btConcaveShape.h" +#include "btStridingMeshInterface.h" + + +///Concave triangle mesh. Uses an interface to access the triangles to allow for sharing graphics/physics triangles. +class btTriangleMeshShape : public btConcaveShape +{ +protected: + btVector3 m_localAabbMin; + btVector3 m_localAabbMax; + btStridingMeshInterface* m_meshInterface; + + +public: + btTriangleMeshShape(btStridingMeshInterface* meshInterface); + + virtual ~btTriangleMeshShape(); + + virtual btVector3 localGetSupportingVertex(const btVector3& vec) const; + + virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const + { + assert(0); + return localGetSupportingVertex(vec); + } + + void recalcLocalAabb(); + + virtual int getShapeType() const + { + return TRIANGLE_MESH_SHAPE_PROXYTYPE; + } + + virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; + + virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; + + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); + + virtual void setLocalScaling(const btVector3& scaling); + virtual const btVector3& getLocalScaling() const; + + btStridingMeshInterface* getMeshInterface() + { + return m_meshInterface; + } + + const btStridingMeshInterface* getMeshInterface() const + { + return m_meshInterface; + } + + + //debugging + virtual char* getName()const {return "TRIANGLEMESH";} + + +}; + +#endif //TRIANGLE_MESH_SHAPE_H diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleShape.h new file mode 100644 index 00000000000..c2e240c051c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleShape.h @@ -0,0 +1,179 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef OBB_TRIANGLE_MINKOWSKI_H +#define OBB_TRIANGLE_MINKOWSKI_H + +#include "btConvexShape.h" +#include "btBoxShape.h" + +class btTriangleShape : public btPolyhedralConvexShape +{ + + +public: + + btVector3 m_vertices1[3]; + + + virtual int getNumVertices() const + { + return 3; + } + + const btVector3& getVertexPtr(int index) const + { + return m_vertices1[index]; + } + virtual void getVertex(int index,btVector3& vert) const + { + vert = m_vertices1[index]; + } + virtual int getShapeType() const + { + return TRIANGLE_SHAPE_PROXYTYPE; + } + + virtual int getNumEdges() const + { + return 3; + } + + virtual void getEdge(int i,btPoint3& pa,btPoint3& pb) const + { + getVertex(i,pa); + getVertex((i+1)%3,pb); + } + + + virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax)const + { +// btAssert(0); + getAabbSlow(t,aabbMin,aabbMax); + } + + btVector3 localGetSupportingVertexWithoutMargin(const btVector3& dir)const + { + btVector3 dots(dir.dot(m_vertices1[0]), dir.dot(m_vertices1[1]), dir.dot(m_vertices1[2])); + return m_vertices1[dots.maxAxis()]; + + } + + virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const + { + for (int i=0;i= -tolerance && dist <= tolerance) + { + //inside check on edge-planes + int i; + for (i=0;i<3;i++) + { + btPoint3 pa,pb; + getEdge(i,pa,pb); + btVector3 edge = pb-pa; + btVector3 edgeNormal = edge.cross(normal); + edgeNormal.normalize(); + btScalar dist = pt.dot( edgeNormal); + btScalar edgeConst = pa.dot(edgeNormal); + dist -= edgeConst; + if (dist < -tolerance) + return false; + } + + return true; + } + + return false; + } + //debugging + virtual char* getName()const + { + return "Triangle"; + } + + virtual int getNumPreferredPenetrationDirections() const + { + return 2; + } + + virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const + { + calcNormal(penetrationVector); + if (index) + penetrationVector *= btScalar(-1.); + } + + +}; + +#endif //OBB_TRIANGLE_MINKOWSKI_H + diff --git a/extern/bullet2/src/BulletCollision/Doxyfile b/extern/bullet2/src/BulletCollision/Doxyfile new file mode 100644 index 00000000000..4ecb6acb62f --- /dev/null +++ b/extern/bullet2/src/BulletCollision/Doxyfile @@ -0,0 +1,746 @@ +# Doxyfile 1.2.4 + +# This file describes the settings to be used by doxygen for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. +PROJECT_NAME = "Bullet Continuous Collision Detection Library" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian, +# Polish, Portuguese and Slovene. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. + +CLASS_DIAGRAMS = YES + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +FILE_PATTERNS = *.h *.cpp *.c + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse. + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side pannel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript and frames is required (for instance Netscape 4.0+ +# or Internet explorer 4.0+). + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = ../../generic/extern + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = c:\program files\doxygen\bin + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp new file mode 100644 index 00000000000..2c565734e97 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp @@ -0,0 +1,200 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btContinuousConvexCollision.h" +#include "BulletCollision/CollisionShapes/btConvexShape.h" +#include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" +#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" +#include "LinearMath/btTransformUtil.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" + +#include "btGjkPairDetector.h" +#include "btPointCollector.h" + + + +btContinuousConvexCollision::btContinuousConvexCollision ( btConvexShape* convexA,btConvexShape* convexB,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* penetrationDepthSolver) +:m_simplexSolver(simplexSolver), +m_penetrationDepthSolver(penetrationDepthSolver), +m_convexA(convexA),m_convexB(convexB) +{ +} + +/// This maximum should not be necessary. It allows for untested/degenerate cases in production code. +/// You don't want your game ever to lock-up. +#define MAX_ITERATIONS 1000 + +bool btContinuousConvexCollision::calcTimeOfImpact( + const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + CastResult& result) +{ + + m_simplexSolver->reset(); + + /// compute linear and angular velocity for this interval, to interpolate + btVector3 linVelA,angVelA,linVelB,angVelB; + btTransformUtil::calculateVelocity(fromA,toA,btScalar(1.),linVelA,angVelA); + btTransformUtil::calculateVelocity(fromB,toB,btScalar(1.),linVelB,angVelB); + + btScalar boundingRadiusA = m_convexA->getAngularMotionDisc(); + btScalar boundingRadiusB = m_convexB->getAngularMotionDisc(); + + btScalar maxAngularProjectedVelocity = angVelA.length() * boundingRadiusA + angVelB.length() * boundingRadiusB; + + btScalar radius = btScalar(0.001); + + btScalar lambda = btScalar(0.); + btVector3 v(1,0,0); + + int maxIter = MAX_ITERATIONS; + + btVector3 n; + n.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); + bool hasResult = false; + btVector3 c; + + btScalar lastLambda = lambda; + //btScalar epsilon = btScalar(0.001); + + int numIter = 0; + //first solution, using GJK + + + btTransform identityTrans; + identityTrans.setIdentity(); + + btSphereShape raySphere(btScalar(0.0)); + raySphere.setMargin(btScalar(0.)); + + +// result.drawCoordSystem(sphereTr); + + btPointCollector pointCollector1; + + { + + btGjkPairDetector gjk(m_convexA,m_convexB,m_simplexSolver,m_penetrationDepthSolver); + btGjkPairDetector::ClosestPointInput input; + + //we don't use margins during CCD + gjk.setIgnoreMargin(true); + + input.m_transformA = fromA; + input.m_transformB = fromB; + gjk.getClosestPoints(input,pointCollector1,0); + + hasResult = pointCollector1.m_hasResult; + c = pointCollector1.m_pointInWorld; + } + + if (hasResult) + { + btScalar dist; + dist = pointCollector1.m_distance; + n = pointCollector1.m_normalOnBInWorld; + + //not close enough + while (dist > radius) + { + numIter++; + if (numIter > maxIter) + return false; //todo: report a failure + + btScalar dLambda = btScalar(0.); + + //calculate safe moving fraction from distance / (linear+rotational velocity) + + //btScalar clippedDist = GEN_min(angularConservativeRadius,dist); + //btScalar clippedDist = dist; + + btScalar projectedLinearVelocity = (linVelB-linVelA).dot(n); + + dLambda = dist / (projectedLinearVelocity+ maxAngularProjectedVelocity); + + lambda = lambda + dLambda; + + if (lambda > btScalar(1.)) + return false; + + if (lambda < btScalar(0.)) + return false; + + //todo: next check with relative epsilon + if (lambda <= lastLambda) + break; + lastLambda = lambda; + + + + //interpolate to next lambda + btTransform interpolatedTransA,interpolatedTransB,relativeTrans; + + btTransformUtil::integrateTransform(fromA,linVelA,angVelA,lambda,interpolatedTransA); + btTransformUtil::integrateTransform(fromB,linVelB,angVelB,lambda,interpolatedTransB); + relativeTrans = interpolatedTransB.inverseTimes(interpolatedTransA); + + result.DebugDraw( lambda ); + + btPointCollector pointCollector; + btGjkPairDetector gjk(m_convexA,m_convexB,m_simplexSolver,m_penetrationDepthSolver); + btGjkPairDetector::ClosestPointInput input; + input.m_transformA = interpolatedTransA; + input.m_transformB = interpolatedTransB; + gjk.getClosestPoints(input,pointCollector,0); + if (pointCollector.m_hasResult) + { + if (pointCollector.m_distance < btScalar(0.)) + { + //degenerate ?! + result.m_fraction = lastLambda; + result.m_normal = n; + return true; + } + c = pointCollector.m_pointInWorld; + + dist = pointCollector.m_distance; + } else + { + //?? + return false; + } + + } + + result.m_fraction = lambda; + result.m_normal = n; + return true; + } + + return false; + +/* +//todo: + //if movement away from normal, discard result + btVector3 move = transBLocalTo.getOrigin() - transBLocalFrom.getOrigin(); + if (result.m_fraction < btScalar(1.)) + { + if (move.dot(result.m_normal) <= btScalar(0.)) + { + } + } +*/ + +} + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h new file mode 100644 index 00000000000..9901bab4b45 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h @@ -0,0 +1,52 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef CONTINUOUS_COLLISION_CONVEX_CAST_H +#define CONTINUOUS_COLLISION_CONVEX_CAST_H + +#include "btConvexCast.h" +#include "btSimplexSolverInterface.h" +class btConvexPenetrationDepthSolver; +class btConvexShape; + +/// btContinuousConvexCollision implements angular and linear time of impact for convex objects. +/// Based on Brian Mirtich's Conservative Advancement idea (PhD thesis). +/// Algorithm operates in worldspace, in order to keep inbetween motion globally consistent. +/// It uses GJK at the moment. Future improvement would use minkowski sum / supporting vertex, merging innerloops +class btContinuousConvexCollision : public btConvexCast +{ + btSimplexSolverInterface* m_simplexSolver; + btConvexPenetrationDepthSolver* m_penetrationDepthSolver; + btConvexShape* m_convexA; + btConvexShape* m_convexB; + + +public: + + btContinuousConvexCollision (btConvexShape* shapeA,btConvexShape* shapeB ,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver); + + virtual bool calcTimeOfImpact( + const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + CastResult& result); + + +}; + +#endif //CONTINUOUS_COLLISION_CONVEX_CAST_H + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp new file mode 100644 index 00000000000..d2a1310b232 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp @@ -0,0 +1,20 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btConvexCast.h" + +btConvexCast::~btConvexCast() +{ +} diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.h new file mode 100644 index 00000000000..3101b59993d --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.h @@ -0,0 +1,71 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef CONVEX_CAST_H +#define CONVEX_CAST_H + +#include "../../LinearMath/btTransform.h" +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btScalar.h" +class btMinkowskiSumShape; +#include "../../LinearMath/btIDebugDraw.h" + +/// btConvexCast is an interface for Casting +class btConvexCast +{ +public: + + + virtual ~btConvexCast(); + + ///RayResult stores the closest result + /// alternatively, add a callback method to decide about closest/all results + struct CastResult + { + //virtual bool addRayResult(const btVector3& normal,btScalar fraction) = 0; + + virtual void DebugDraw(btScalar fraction) {(void)fraction;} + virtual void drawCoordSystem(const btTransform& trans) {(void)trans;} + + CastResult() + :m_fraction(btScalar(1e30)), + m_debugDrawer(0) + { + } + + + virtual ~CastResult() {}; + + btVector3 m_normal; + btScalar m_fraction; + btTransform m_hitTransformA; + btTransform m_hitTransformB; + + btIDebugDraw* m_debugDrawer; + + }; + + + /// cast a convex against another convex object + virtual bool calcTimeOfImpact( + const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + CastResult& result) = 0; +}; + +#endif //CONVEX_CAST_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h new file mode 100644 index 00000000000..7caeba4be45 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h @@ -0,0 +1,43 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef CONVEX_PENETRATION_DEPTH_H +#define CONVEX_PENETRATION_DEPTH_H + +class btStackAlloc; +class btVector3; +#include "btSimplexSolverInterface.h" +class btConvexShape; +#include "../../LinearMath/btPoint3.h" +class btTransform; + +///ConvexPenetrationDepthSolver provides an interface for penetration depth calculation. +class btConvexPenetrationDepthSolver +{ +public: + + virtual ~btConvexPenetrationDepthSolver() {}; + virtual bool calcPenDepth( btSimplexSolverInterface& simplexSolver, + btConvexShape* convexA,btConvexShape* convexB, + const btTransform& transA,const btTransform& transB, + btVector3& v, btPoint3& pa, btPoint3& pb, + class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc + ) = 0; + + +}; +#endif //CONVEX_PENETRATION_DEPTH_H + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h new file mode 100644 index 00000000000..15000c1ab61 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h @@ -0,0 +1,88 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef DISCRETE_COLLISION_DETECTOR1_INTERFACE_H +#define DISCRETE_COLLISION_DETECTOR1_INTERFACE_H +#include "../../LinearMath/btTransform.h" +#include "../../LinearMath/btVector3.h" +class btStackAlloc; + +/// This interface is made to be used by an iterative approach to do TimeOfImpact calculations +/// This interface allows to query for closest points and penetration depth between two (convex) objects +/// the closest point is on the second object (B), and the normal points from the surface on B towards A. +/// distance is between closest points on B and closest point on A. So you can calculate closest point on A +/// by taking closestPointInA = closestPointInB + m_distance * m_normalOnSurfaceB +struct btDiscreteCollisionDetectorInterface +{ + + struct Result + { + + virtual ~Result(){} + + ///setShapeIdentifiers provides experimental support for per-triangle material / custom material combiner + virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1)=0; + virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth)=0; + }; + + struct ClosestPointInput + { + ClosestPointInput() + :m_maximumDistanceSquared(btScalar(1e30)), + m_stackAlloc(0) + { + } + + btTransform m_transformA; + btTransform m_transformB; + btScalar m_maximumDistanceSquared; + btStackAlloc* m_stackAlloc; + }; + + virtual ~btDiscreteCollisionDetectorInterface() {}; + + // + // give either closest points (distance > 0) or penetration (distance) + // the normal always points from B towards A + // + virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw) = 0; + +}; + +struct btStorageResult : public btDiscreteCollisionDetectorInterface::Result +{ + btVector3 m_normalOnSurfaceB; + btVector3 m_closestPointInB; + btScalar m_distance; //negative means penetration ! + + btStorageResult() : m_distance(btScalar(1e30)) + { + + } + virtual ~btStorageResult() {}; + + virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) + { + if (depth < m_distance) + { + m_normalOnSurfaceB = normalOnBInWorld; + m_closestPointInB = pointInWorld; + m_distance = depth; + } + } +}; + +#endif //DISCRETE_COLLISION_DETECTOR_INTERFACE1_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp new file mode 100644 index 00000000000..93edffeafd6 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp @@ -0,0 +1,174 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#include "btGjkConvexCast.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" +#include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" +#include "btGjkPairDetector.h" +#include "btPointCollector.h" + + +btGjkConvexCast::btGjkConvexCast(btConvexShape* convexA,btConvexShape* convexB,btSimplexSolverInterface* simplexSolver) +:m_simplexSolver(simplexSolver), +m_convexA(convexA), +m_convexB(convexB) +{ +} + +bool btGjkConvexCast::calcTimeOfImpact( + const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + CastResult& result) +{ + + + btMinkowskiSumShape combi(m_convexA,m_convexB); + btMinkowskiSumShape* convex = &combi; + + btTransform rayFromLocalA; + btTransform rayToLocalA; + + rayFromLocalA = fromA.inverse()* fromB; + rayToLocalA = toA.inverse()* toB; + + + btTransform trA,trB; + trA = btTransform(fromA); + trB = btTransform(fromB); + trA.setOrigin(btPoint3(0,0,0)); + trB.setOrigin(btPoint3(0,0,0)); + + convex->setTransformA(trA); + convex->setTransformB(trB); + + + + + btScalar radius = btScalar(0.01); + + btScalar lambda = btScalar(0.); + btVector3 s = rayFromLocalA.getOrigin(); + btVector3 r = rayToLocalA.getOrigin()-rayFromLocalA.getOrigin(); + btVector3 x = s; + btVector3 n; + n.setValue(0,0,0); + bool hasResult = false; + btVector3 c; + + btScalar lastLambda = lambda; + + //first solution, using GJK + + //no penetration support for now, perhaps pass a pointer when we really want it + btConvexPenetrationDepthSolver* penSolverPtr = 0; + + btTransform identityTrans; + identityTrans.setIdentity(); + + btSphereShape raySphere(btScalar(0.0)); + raySphere.setMargin(btScalar(0.)); + + btTransform sphereTr; + sphereTr.setIdentity(); + sphereTr.setOrigin( rayFromLocalA.getOrigin()); + + result.drawCoordSystem(sphereTr); + { + btPointCollector pointCollector1; + btGjkPairDetector gjk(&raySphere,convex,m_simplexSolver,penSolverPtr); + + btGjkPairDetector::ClosestPointInput input; + input.m_transformA = sphereTr; + input.m_transformB = identityTrans; + gjk.getClosestPoints(input,pointCollector1,0); + + hasResult = pointCollector1.m_hasResult; + c = pointCollector1.m_pointInWorld; + n = pointCollector1.m_normalOnBInWorld; + } + + + + if (hasResult) + { + btScalar dist; + dist = (c-x).length(); + if (dist < radius) + { + //penetration + lastLambda = btScalar(1.); + } + + //not close enough + while (dist > radius) + { + + n = x - c; + btScalar nDotr = n.dot(r); + + if (nDotr >= -(SIMD_EPSILON*SIMD_EPSILON)) + return false; + + lambda = lambda - n.dot(n) / nDotr; + if (lambda <= lastLambda) + break; + + lastLambda = lambda; + + x = s + lambda * r; + + sphereTr.setOrigin( x ); + result.drawCoordSystem(sphereTr); + btPointCollector pointCollector; + btGjkPairDetector gjk(&raySphere,convex,m_simplexSolver,penSolverPtr); + btGjkPairDetector::ClosestPointInput input; + input.m_transformA = sphereTr; + input.m_transformB = identityTrans; + gjk.getClosestPoints(input,pointCollector,0); + if (pointCollector.m_hasResult) + { + if (pointCollector.m_distance < btScalar(0.)) + { + //degeneracy, report a hit + result.m_fraction = lastLambda; + result.m_normal = n; + return true; + } + c = pointCollector.m_pointInWorld; + dist = (c-x).length(); + } else + { + //?? + return false; + } + + } + + if (lastLambda < btScalar(1.)) + { + + result.m_fraction = lastLambda; + result.m_normal = n; + return true; + } + } + + return false; +} + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h new file mode 100644 index 00000000000..3905c45e6d6 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h @@ -0,0 +1,50 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef GJK_CONVEX_CAST_H +#define GJK_CONVEX_CAST_H + +#include "../CollisionShapes/btCollisionMargin.h" + +#include "../../LinearMath/btVector3.h" +#include "btConvexCast.h" +class btConvexShape; +class btMinkowskiSumShape; +#include "btSimplexSolverInterface.h" + +///GjkConvexCast performs a raycast on a convex object using support mapping. +class btGjkConvexCast : public btConvexCast +{ + btSimplexSolverInterface* m_simplexSolver; + btConvexShape* m_convexA; + btConvexShape* m_convexB; + +public: + + btGjkConvexCast(btConvexShape* convexA,btConvexShape* convexB,btSimplexSolverInterface* simplexSolver); + + /// cast a convex against another convex object + virtual bool calcTimeOfImpact( + const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + CastResult& result); + +}; + +#endif //GJK_CONVEX_CAST_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa.cpp new file mode 100644 index 00000000000..8abdfdbb7e5 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa.cpp @@ -0,0 +1,628 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the +use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in a +product, an acknowledgment in the product documentation would be appreciated +but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +/* +GJK-EPA collision solver by Nathanael Presson +Nov.2006 +*/ + +#include "btGjkEpa.h" +#include //for memset +#include + +#if defined(DEBUG) || defined (_DEBUG) +#include //for debug printf +#ifdef __SPU__ +#include +#define printf spu_printf +#endif //__SPU__ +#endif + +namespace gjkepa_impl +{ + +// +// Port. typedefs +// + +typedef btScalar F; +typedef bool Z; +typedef int I; +typedef unsigned int U; +typedef unsigned char U1; +typedef unsigned short U2; + +typedef btVector3 Vector3; +typedef btMatrix3x3 Rotation; + +// +// Config +// + +#if 0 +#define BTLOCALSUPPORT localGetSupportingVertexWithoutMargin +#else +#define BTLOCALSUPPORT localGetSupportingVertex +#endif + +// +// Const +// + + +#define cstInf SIMD_INFINITY +#define cstPi SIMD_PI +#define cst2Pi SIMD_2_PI +#define GJK_maxiterations (128) +#define GJK_hashsize (1<<6) +#define GJK_hashmask (GJK_hashsize-1) +#define GJK_insimplex_eps F(0.0001) +#define GJK_sqinsimplex_eps (GJK_insimplex_eps*GJK_insimplex_eps) +#define EPA_maxiterations 256 +#define EPA_inface_eps F(0.01) +#define EPA_accuracy F(0.001) + +// +// Utils +// + +static inline F Abs(F v) { return(v<0?-v:v); } +static inline F Sign(F v) { return(F(v<0?-1:1)); } +template static inline void Swap(T& a,T& b) { T +t(a);a=b;b=t; } +template static inline T Min(const T& a,const T& b) { +return(a static inline T Max(const T& a,const T& b) { +return(a>b?a:b); } +static inline void ClearMemory(void* p,U sz) { memset(p,0,(size_t)sz); +} +#if 0 +template static inline void Raise(const T& object) { +throw(object); } +#else +template static inline void Raise(const T&) {} +#endif + + + +// +// GJK +// +struct GJK + { + struct Mkv + { + Vector3 w; /* Minkowski vertice */ + Vector3 r; /* Ray */ + }; + struct He + { + Vector3 v; + He* n; + }; + btStackAlloc* sa; + btBlock* sablock; + He* table[GJK_hashsize]; + Rotation wrotations[2]; + Vector3 positions[2]; + const btConvexShape* shapes[2]; + Mkv simplex[5]; + Vector3 ray; + U order; + U iterations; + F margin; + Z failed; + // + GJK(btStackAlloc* psa, + const Rotation& wrot0,const Vector3& pos0,const btConvexShape* shape0, + const Rotation& wrot1,const Vector3& pos1,const btConvexShape* shape1, + F pmargin=0) + { + wrotations[0]=wrot0;positions[0]=pos0;shapes[0]=shape0; + wrotations[1]=wrot1;positions[1]=pos1;shapes[1]=shape1; + sa =psa; + sablock =sa->beginBlock(); + margin =pmargin; + failed =false; + } + // + ~GJK() + { + sa->endBlock(sablock); + } + // vdh : very dumm hash + static inline U Hash(const Vector3& v) + { + //this doesn't compile under GCC 3.3.5, so add the ()... + //const U h(U(v[0]*15461)^U(v[1]*83003)^U(v[2]*15473)); + //return(((*((const U*)&h))*169639)&GJK_hashmask); + const U h((U)(v[0]*15461)^(U)(v[1]*83003)^(U)(v[2]*15473)); + return(((*((const U*)&h))*169639)&GJK_hashmask); + } + // + inline Vector3 LocalSupport(const Vector3& d,U i) const + { + return(wrotations[i]*shapes[i]->BTLOCALSUPPORT(d*wrotations[i])+positions[i]); + } + // + inline void Support(const Vector3& d,Mkv& v) const + { + v.r = d; + v.w = LocalSupport(d,0)-LocalSupport(-d,1)+d*margin; + } + #define SPX(_i_) simplex[_i_] + #define SPXW(_i_) simplex[_i_].w + // + inline Z FetchSupport() + { + const U h(Hash(ray)); + He* e = (He*)(table[h]); + while(e) { if(e->v==ray) { --order;return(false); } else e=e->n; } + e=(He*)sa->allocate(sizeof(He));e->v=ray;e->n=table[h];table[h]=e; + Support(ray,simplex[++order]); + return(ray.dot(SPXW(order))>0); + } + // + inline Z SolveSimplex2(const Vector3& ao,const Vector3& ab) + { + if(ab.dot(ao)>=0) + { + const Vector3 cabo(cross(ab,ao)); + if(cabo.length2()>GJK_sqinsimplex_eps) + { ray=cross(cabo,ab); } + else + { return(true); } + } + else + { order=0;SPX(0)=SPX(1);ray=ao; } + return(false); + } + // + inline Z SolveSimplex3(const Vector3& ao,const Vector3& ab,const Vector3& +ac) + { + return(SolveSimplex3a(ao,ab,ac,cross(ab,ac))); + } + // + inline Z SolveSimplex3a(const Vector3& ao,const Vector3& ab,const Vector3& +ac,const Vector3& cabc) + { + if((cross(cabc,ab)).dot(ao)<-GJK_insimplex_eps) + { order=1;SPX(0)=SPX(1);SPX(1)=SPX(2);return(SolveSimplex2(ao,ab)); } + else if((cross(cabc,ac)).dot(ao)>+GJK_insimplex_eps) + { order=1;SPX(1)=SPX(2);return(SolveSimplex2(ao,ac)); } + else + { + const F d(cabc.dot(ao)); + if(Abs(d)>GJK_insimplex_eps) + { + if(d>0) + { ray=cabc; } + else + { ray=-cabc;Swap(SPX(0),SPX(1)); } + return(false); + } else return(true); + } + } + // + inline Z SolveSimplex4(const Vector3& ao,const Vector3& ab,const Vector3& +ac,const Vector3& ad) + { + Vector3 crs; + if((crs=cross(ab,ac)).dot(ao)>GJK_insimplex_eps) + { +order=2;SPX(0)=SPX(1);SPX(1)=SPX(2);SPX(2)=SPX(3);return(SolveSimplex3a(ao,ab,ac,crs)); +} + else if((crs=cross(ac,ad)).dot(ao)>GJK_insimplex_eps) + { order=2;SPX(2)=SPX(3);return(SolveSimplex3a(ao,ac,ad,crs)); } + else if((crs=cross(ad,ab)).dot(ao)>GJK_insimplex_eps) + { +order=2;SPX(1)=SPX(0);SPX(0)=SPX(2);SPX(2)=SPX(3);return(SolveSimplex3a(ao,ad,ab,crs)); +} + else return(true); + } + // + inline Z SearchOrigin(const Vector3& initray=Vector3(1,0,0)) + { + iterations = 0; + order = (U)-1; + failed = false; + ray = initray.normalized(); + ClearMemory(table,sizeof(void*)*GJK_hashsize); + FetchSupport(); + ray = -SPXW(0); + for(;iterations0?rl:1; + if(FetchSupport()) + { + Z found(false); + switch(order) + { + case 1: found=SolveSimplex2(-SPXW(1),SPXW(0)-SPXW(1));break; + case 2: found=SolveSimplex3(-SPXW(2),SPXW(1)-SPXW(2),SPXW(0)-SPXW(2));break; + case 3: found=SolveSimplex4(-SPXW(3),SPXW(2)-SPXW(3),SPXW(1)-SPXW(3),SPXW(0)-SPXW(3));break; + } + if(found) return(true); + } else return(false); + } + failed=true; + return(false); + } + // + inline Z EncloseOrigin() + { + switch(order) + { + /* Point */ + case 0: break; + /* Line */ + case 1: + { + const Vector3 ab(SPXW(1)-SPXW(0)); + const Vector3 b[]={ cross(ab,Vector3(1,0,0)), + cross(ab,Vector3(0,1,0)), + cross(ab,Vector3(0,0,1))}; + const F m[]={b[0].length2(),b[1].length2(),b[2].length2()}; + const Rotation r(btQuaternion(ab.normalized(),cst2Pi/3)); + Vector3 w(b[m[0]>m[1]?m[0]>m[2]?0:2:m[1]>m[2]?1:2]); + Support(w.normalized(),simplex[4]);w=r*w; + Support(w.normalized(),simplex[2]);w=r*w; + Support(w.normalized(),simplex[3]);w=r*w; + order=4; + return(true); + } + break; + /* Triangle */ + case 2: + { + const +Vector3 n(cross((SPXW(1)-SPXW(0)),(SPXW(2)-SPXW(0))).normalized()); + Support( n,simplex[3]); + Support(-n,simplex[4]); + order=4; + return(true); + } + break; + /* Tetrahedron */ + case 3: return(true); + /* Hexahedron */ + case 4: return(true); + } + return(false); + } + #undef SPX + #undef SPXW + }; + +// +// EPA +// +struct EPA + { + // + struct Face + { + const GJK::Mkv* v[3]; + Face* f[3]; + U e[3]; + Vector3 n; + F d; + U mark; + Face* prev; + Face* next; + Face() {} + }; + // + GJK* gjk; + btStackAlloc* sa; + Face* root; + U nfaces; + U iterations; + Vector3 features[2][3]; + Vector3 nearest[2]; + Vector3 normal; + F depth; + Z failed; + // + EPA(GJK* pgjk) + { + gjk = pgjk; + sa = pgjk->sa; + } + // + ~EPA() + { + } + // + inline Vector3 GetCoordinates(const Face* face) const + { + const Vector3 o(face->n*-face->d); + const F a[]={ cross(face->v[0]->w-o,face->v[1]->w-o).length(), + cross(face->v[1]->w-o,face->v[2]->w-o).length(), + cross(face->v[2]->w-o,face->v[0]->w-o).length()}; + const F sm(a[0]+a[1]+a[2]); + return(Vector3(a[1],a[2],a[0])/(sm>0?sm:1)); + } + // + inline Face* FindBest() const + { + Face* bf = 0; + if(root) + { + Face* cf = root; + F bd(cstInf); + do { + if(cf->dd;bf=cf; } + } while(0!=(cf=cf->next)); + } + return(bf); + } + // + inline Z Set(Face* f,const GJK::Mkv* a,const GJK::Mkv* b,const GJK::Mkv* +c) const + { + const Vector3 nrm(cross(b->w-a->w,c->w-a->w)); + const F len(nrm.length()); + const Z valid( (cross(a->w,b->w).dot(nrm)>=-EPA_inface_eps)&& + (cross(b->w,c->w).dot(nrm)>=-EPA_inface_eps)&& + (cross(c->w,a->w).dot(nrm)>=-EPA_inface_eps)); + f->v[0] = a; + f->v[1] = b; + f->v[2] = c; + f->mark = 0; + f->n = nrm/(len>0?len:cstInf); + f->d = Max(0,-f->n.dot(a->w)); + return(valid); + } + // + inline Face* NewFace(const GJK::Mkv* a,const GJK::Mkv* b,const GJK::Mkv* c) + { + Face* pf = (Face*)sa->allocate(sizeof(Face)); + if(Set(pf,a,b,c)) + { + if(root) root->prev=pf; + pf->prev=0; + pf->next=root; + root =pf; + ++nfaces; + } + else + { + pf->prev=pf->next=0; + } + return(pf); + } + // + inline void Detach(Face* face) + { + if(face->prev||face->next) + { + --nfaces; + if(face==root) + { root=face->next;root->prev=0; } + else + { + if(face->next==0) + { face->prev->next=0; } + else + { face->prev->next=face->next;face->next->prev=face->prev; } + } + face->prev=face->next=0; + } + } + // + inline void Link(Face* f0,U e0,Face* f1,U e1) const + { + f0->f[e0]=f1;f1->e[e1]=e0; + f1->f[e1]=f0;f0->e[e0]=e1; + } + // + GJK::Mkv* Support(const Vector3& w) const + { + GJK::Mkv* v =(GJK::Mkv*)sa->allocate(sizeof(GJK::Mkv)); + gjk->Support(w,*v); + return(v); + } + // + U BuildHorizon(U markid,const GJK::Mkv* w,Face& f,U e,Face*& cf,Face*& +ff) + { + static const U mod3[]={0,1,2,0,1}; + U ne(0); + if(f.mark!=markid) + { + const U e1(mod3[e+1]); + if((f.n.dot(w->w)+f.d)>0) + { + Face* nf = NewFace(f.v[e1],f.v[e],w); + Link(nf,0,&f,e); + if(cf) Link(cf,1,nf,2); else ff=nf; + cf=nf;ne=1; + } + else + { + const U e2(mod3[e+2]); + Detach(&f); + f.mark = markid; + ne += BuildHorizon(markid,w,*f.f[e1],f.e[e1],cf,ff); + ne += BuildHorizon(markid,w,*f.f[e2],f.e[e2],cf,ff); + } + } + return(ne); + } + // + inline F EvaluatePD(F accuracy=EPA_accuracy) + { + btBlock* sablock = sa->beginBlock(); + Face* bestface = 0; + U markid(1); + depth = -cstInf; + normal = Vector3(0,0,0); + root = 0; + nfaces = 0; + iterations = 0; + failed = false; + /* Prepare hull */ + if(gjk->EncloseOrigin()) + { + const U* pfidx = 0; + U nfidx= 0; + const U* peidx = 0; + U neidx = 0; + GJK::Mkv* basemkv[5]; + Face* basefaces[6]; + switch(gjk->order) + { + /* Tetrahedron */ + case 3: { + static const U fidx[4][3]={{2,1,0},{3,0,1},{3,1,2},{3,2,0}}; + static const +U eidx[6][4]={{0,0,2,1},{0,1,1,1},{0,2,3,1},{1,0,3,2},{2,0,1,2},{3,0,2,2}}; + pfidx=(const U*)fidx;nfidx=4;peidx=(const U*)eidx;neidx=6; + } break; + /* Hexahedron */ + case 4: { + static const +U fidx[6][3]={{2,0,4},{4,1,2},{1,4,0},{0,3,1},{0,2,3},{1,3,2}}; + static const +U eidx[9][4]={{0,0,4,0},{0,1,2,1},{0,2,1,2},{1,1,5,2},{1,0,2,0},{2,2,3,2},{3,1,5,0},{3,0,4,2},{5,1,4,1}}; + pfidx=(const U*)fidx;nfidx=6;peidx=(const U*)eidx;neidx=9; + } break; + } + U i; + + for( i=0;i<=gjk->order;++i) { +basemkv[i]=(GJK::Mkv*)sa->allocate(sizeof(GJK::Mkv));*basemkv[i]=gjk->simplex[i]; +} + for( i=0;iendBlock(sablock); + return(depth); + } + /* Expand hull */ + for(;iterationsn); + const F d(bf->n.dot(w->w)+bf->d); + bestface = bf; + if(d<-accuracy) + { + Face* cf =0; + Face* ff =0; + U nf = 0; + Detach(bf); + bf->mark=++markid; + for(U i=0;i<3;++i) { +nf+=BuildHorizon(markid,w,*bf->f[i],bf->e[i],cf,ff); } + if(nf<=2) { break; } + Link(cf,1,ff,2); + } else break; + } else break; + } + /* Extract contact */ + if(bestface) + { + const Vector3 b(GetCoordinates(bestface)); + normal = bestface->n; + depth = Max(0,bestface->d); + for(U i=0;i<2;++i) + { + const F s(F(i?-1:1)); + for(U j=0;j<3;++j) + { + features[i][j]=gjk->LocalSupport(s*bestface->v[j]->r,i); + } + } + nearest[0] = features[0][0]*b.x()+features[0][1]*b.y()+features[0][2]*b.z(); + nearest[1] = features[1][0]*b.x()+features[1][1]*b.y()+features[1][2]*b.z(); + } else failed=true; + sa->endBlock(sablock); + return(depth); + } + }; +} + +// +// Api +// + +using namespace gjkepa_impl; + + + +// +bool btGjkEpaSolver::Collide(btConvexShape *shape0,const btTransform &wtrs0, + btConvexShape *shape1,const btTransform &wtrs1, + btScalar radialmargin, + btStackAlloc* stackAlloc, + sResults& results) +{ + + +/* Initialize */ +results.witnesses[0] = +results.witnesses[1] = +results.normal = Vector3(0,0,0); +results.depth = 0; +results.status = sResults::Separated; +results.epa_iterations = 0; +results.gjk_iterations = 0; +/* Use GJK to locate origin */ +GJK gjk(stackAlloc, + wtrs0.getBasis(),wtrs0.getOrigin(),shape0, + wtrs1.getBasis(),wtrs1.getOrigin(),shape1, + radialmargin+EPA_accuracy); +const Z collide(gjk.SearchOrigin()); +results.gjk_iterations = gjk.iterations+1; +if(collide) + { + /* Then EPA for penetration depth */ + EPA epa(&gjk); + const F pd(epa.EvaluatePD()); + results.epa_iterations = epa.iterations+1; + if(pd>0) + { + results.status = sResults::Penetrating; + results.normal = epa.normal; + results.depth = pd; + results.witnesses[0] = epa.nearest[0]; + results.witnesses[1] = epa.nearest[1]; + return(true); + } else { if(epa.failed) results.status=sResults::EPA_Failed; } + } else { if(gjk.failed) results.status=sResults::GJK_Failed; } +return(false); +} + + + + + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa.h new file mode 100644 index 00000000000..759b30bb17f --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa.h @@ -0,0 +1,53 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +/* +GJK-EPA collision solver by Nathanael Presson +Nov.2006 +*/ + + +#ifndef _05E48D53_04E0_49ad_BB0A_D74FE62E7366_ +#define _05E48D53_04E0_49ad_BB0A_D74FE62E7366_ +#include "../CollisionShapes/btConvexShape.h" + +class btStackAlloc; + +///btGjkEpaSolver contributed under zlib by Nathanael Presson +struct btGjkEpaSolver +{ +struct sResults + { + enum eStatus + { + Separated, /* Shapes doesnt penetrate */ + Penetrating, /* Shapes are penetrating */ + GJK_Failed, /* GJK phase fail, no big issue, shapes are probably just 'touching' */ + EPA_Failed, /* EPA phase fail, bigger problem, need to save parameters, and debug */ + } status; + btVector3 witnesses[2]; + btVector3 normal; + btScalar depth; + int epa_iterations; + int gjk_iterations; + }; +static bool Collide(btConvexShape* shape0,const btTransform& wtrs0, + btConvexShape* shape1,const btTransform& wtrs1, + btScalar radialmargin, + btStackAlloc* stackAlloc, + sResults& results); +}; + +#endif diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp new file mode 100644 index 00000000000..87330493b60 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp @@ -0,0 +1,50 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +EPA Copyright (c) Ricardo Padrela 2006 + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "BulletCollision/CollisionShapes/btConvexShape.h" +#include "btGjkEpaPenetrationDepthSolver.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkEpa.h" + +bool btGjkEpaPenetrationDepthSolver::calcPenDepth( btSimplexSolverInterface& simplexSolver, + btConvexShape* pConvexA, btConvexShape* pConvexB, + const btTransform& transformA, const btTransform& transformB, + btVector3& v, btPoint3& wWitnessOnA, btPoint3& wWitnessOnB, + class btIDebugDraw* debugDraw, btStackAlloc* stackAlloc ) +{ + + (void)debugDraw; + (void)v; + (void)simplexSolver; + + const btScalar radialmargin(btScalar(0.)); + + btGjkEpaSolver::sResults results; + if(btGjkEpaSolver::Collide( pConvexA,transformA, + pConvexB,transformB, + radialmargin,stackAlloc,results)) + { + // debugDraw->drawLine(results.witnesses[1],results.witnesses[1]+results.normal,btVector3(255,0,0)); + //resultOut->addContactPoint(results.normal,results.witnesses[1],-results.depth); + wWitnessOnA = results.witnesses[0]; + wWitnessOnB = results.witnesses[1]; + return true; + } + + return false; +} + + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h new file mode 100644 index 00000000000..3916ba0776c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h @@ -0,0 +1,39 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +EPA Copyright (c) Ricardo Padrela 2006 + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +#ifndef BT_GJP_EPA_PENETRATION_DEPTH_H +#define BT_GJP_EPA_PENETRATION_DEPTH_H + +#include "btConvexPenetrationDepthSolver.h" + +///EpaPenetrationDepthSolver uses the Expanding Polytope Algorithm to +///calculate the penetration depth between two convex shapes. +class btGjkEpaPenetrationDepthSolver : public btConvexPenetrationDepthSolver +{ + public : + + bool calcPenDepth( btSimplexSolverInterface& simplexSolver, + btConvexShape* pConvexA, btConvexShape* pConvexB, + const btTransform& transformA, const btTransform& transformB, + btVector3& v, btPoint3& wWitnessOnA, btPoint3& wWitnessOnB, + class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc ); + + private : + +}; + +#endif // BT_GJP_EPA_PENETRATION_DEPTH_H + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp new file mode 100644 index 00000000000..f1f3f7f7f6c --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp @@ -0,0 +1,299 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btGjkPairDetector.h" +#include "BulletCollision/CollisionShapes/btConvexShape.h" +#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" +#include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" + +#if defined(DEBUG) || defined (_DEBUG) +#include //for debug printf +#ifdef __SPU__ +#include +#define printf spu_printf +#endif //__SPU__ +#endif + +//must be above the machine epsilon +#define REL_ERROR2 btScalar(1.0e-6) + +//temp globals, to improve GJK/EPA/penetration calculations +int gNumDeepPenetrationChecks = 0; +int gNumGjkChecks = 0; + + + +btGjkPairDetector::btGjkPairDetector(btConvexShape* objectA,btConvexShape* objectB,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver) +:m_cachedSeparatingAxis(btScalar(0.),btScalar(0.),btScalar(1.)), +m_penetrationDepthSolver(penetrationDepthSolver), +m_simplexSolver(simplexSolver), +m_minkowskiA(objectA), +m_minkowskiB(objectB), +m_ignoreMargin(false), +m_lastUsedMethod(-1), +m_catchDegeneracies(1) +{ +} + +void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw) +{ + btScalar distance=btScalar(0.); + btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.)); + btVector3 pointOnA,pointOnB; + btTransform localTransA = input.m_transformA; + btTransform localTransB = input.m_transformB; + btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5); + localTransA.getOrigin() -= positionOffset; + localTransB.getOrigin() -= positionOffset; + + btScalar marginA = m_minkowskiA->getMargin(); + btScalar marginB = m_minkowskiB->getMargin(); + + gNumGjkChecks++; + + //for CCD we don't use margins + if (m_ignoreMargin) + { + marginA = btScalar(0.); + marginB = btScalar(0.); + } + + m_curIter = 0; + int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN? + m_cachedSeparatingAxis.setValue(0,1,0); + + bool isValid = false; + bool checkSimplex = false; + bool checkPenetration = true; + m_degenerateSimplex = 0; + + m_lastUsedMethod = -1; + + { + btScalar squaredDistance = SIMD_INFINITY; + btScalar delta = btScalar(0.); + + btScalar margin = marginA + marginB; + + + + m_simplexSolver->reset(); + + for ( ; ; ) + //while (true) + { + + btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis(); + btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis(); + + btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA); + btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB); + btPoint3 pWorld = localTransA(pInA); + btPoint3 qWorld = localTransB(qInB); + + btVector3 w = pWorld - qWorld; + delta = m_cachedSeparatingAxis.dot(w); + + // potential exit, they don't overlap + if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared)) + { + checkPenetration = false; + break; + } + + //exit 0: the new point is already in the simplex, or we didn't come any closer + if (m_simplexSolver->inSimplex(w)) + { + m_degenerateSimplex = 1; + checkSimplex = true; + break; + } + // are we getting any closer ? + btScalar f0 = squaredDistance - delta; + btScalar f1 = squaredDistance * REL_ERROR2; + + if (f0 <= f1) + { + if (f0 <= btScalar(0.)) + { + m_degenerateSimplex = 2; + } + checkSimplex = true; + break; + } + //add current vertex to simplex + m_simplexSolver->addVertex(w, pWorld, qWorld); + + //calculate the closest point to the origin (update vector v) + if (!m_simplexSolver->closest(m_cachedSeparatingAxis)) + { + m_degenerateSimplex = 3; + checkSimplex = true; + break; + } + + btScalar previousSquaredDistance = squaredDistance; + squaredDistance = m_cachedSeparatingAxis.length2(); + + //redundant m_simplexSolver->compute_points(pointOnA, pointOnB); + + //are we getting any closer ? + if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance) + { + m_simplexSolver->backup_closest(m_cachedSeparatingAxis); + checkSimplex = true; + break; + } + + //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject + if (m_curIter++ > gGjkMaxIter) + { + #if defined(DEBUG) || defined (_DEBUG) + + printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter); + printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n", + m_cachedSeparatingAxis.getX(), + m_cachedSeparatingAxis.getY(), + m_cachedSeparatingAxis.getZ(), + squaredDistance, + m_minkowskiA->getShapeType(), + m_minkowskiB->getShapeType()); + + #endif + break; + + } + + + bool check = (!m_simplexSolver->fullSimplex()); + //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex()); + + if (!check) + { + //do we need this backup_closest here ? + m_simplexSolver->backup_closest(m_cachedSeparatingAxis); + break; + } + } + + if (checkSimplex) + { + m_simplexSolver->compute_points(pointOnA, pointOnB); + normalInB = pointOnA-pointOnB; + btScalar lenSqr = m_cachedSeparatingAxis.length2(); + //valid normal + if (lenSqr < 0.0001) + { + m_degenerateSimplex = 5; + } + if (lenSqr > SIMD_EPSILON*SIMD_EPSILON) + { + btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); + normalInB *= rlen; //normalize + btScalar s = btSqrt(squaredDistance); + + btAssert(s > btScalar(0.0)); + pointOnA -= m_cachedSeparatingAxis * (marginA / s); + pointOnB += m_cachedSeparatingAxis * (marginB / s); + distance = ((btScalar(1.)/rlen) - margin); + isValid = true; + + m_lastUsedMethod = 1; + } else + { + m_lastUsedMethod = 2; + } + } + + bool catchDegeneratePenetrationCase = + (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01)); + + //if (checkPenetration && !isValid) + if (checkPenetration && (!isValid || catchDegeneratePenetrationCase )) + { + //penetration case + + //if there is no way to handle penetrations, bail out + if (m_penetrationDepthSolver) + { + // Penetration depth case. + btVector3 tmpPointOnA,tmpPointOnB; + + gNumDeepPenetrationChecks++; + + bool isValid2 = m_penetrationDepthSolver->calcPenDepth( + *m_simplexSolver, + m_minkowskiA,m_minkowskiB, + localTransA,localTransB, + m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB, + debugDraw,input.m_stackAlloc + ); + + if (isValid2) + { + btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA; + btScalar lenSqr = tmpNormalInB.length2(); + if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON)) + { + tmpNormalInB /= btSqrt(lenSqr); + btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length(); + //only replace valid penetrations when the result is deeper (check) + if (!isValid || (distance2 < distance)) + { + distance = distance2; + pointOnA = tmpPointOnA; + pointOnB = tmpPointOnB; + normalInB = tmpNormalInB; + isValid = true; + m_lastUsedMethod = 3; + } else + { + + } + } else + { + //isValid = false; + m_lastUsedMethod = 4; + } + } else + { + m_lastUsedMethod = 5; + } + + } + } + } + + if (isValid) + { +#ifdef __SPU__ + //spu_printf("distance\n"); +#endif //__CELLOS_LV2__ + + + output.addContactPoint( + normalInB, + pointOnB+positionOffset, + distance); + //printf("gjk add:%f",distance); + } + + +} + + + + + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h new file mode 100644 index 00000000000..af0fe32f6c7 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h @@ -0,0 +1,85 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + + +#ifndef GJK_PAIR_DETECTOR_H +#define GJK_PAIR_DETECTOR_H + +#include "btDiscreteCollisionDetectorInterface.h" +#include "../../LinearMath/btPoint3.h" +#include "../CollisionShapes/btCollisionMargin.h" + +class btConvexShape; +#include "btSimplexSolverInterface.h" +class btConvexPenetrationDepthSolver; + +/// btGjkPairDetector uses GJK to implement the btDiscreteCollisionDetectorInterface +class btGjkPairDetector : public btDiscreteCollisionDetectorInterface +{ + + + btVector3 m_cachedSeparatingAxis; + btConvexPenetrationDepthSolver* m_penetrationDepthSolver; + btSimplexSolverInterface* m_simplexSolver; + btConvexShape* m_minkowskiA; + btConvexShape* m_minkowskiB; + bool m_ignoreMargin; + + +public: + + //some debugging to fix degeneracy problems + int m_lastUsedMethod; + int m_curIter; + int m_degenerateSimplex; + int m_catchDegeneracies; + + + btGjkPairDetector(btConvexShape* objectA,btConvexShape* objectB,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver); + virtual ~btGjkPairDetector() {}; + + virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw); + + void setMinkowskiA(btConvexShape* minkA) + { + m_minkowskiA = minkA; + } + + void setMinkowskiB(btConvexShape* minkB) + { + m_minkowskiB = minkB; + } + void setCachedSeperatingAxis(const btVector3& seperatingAxis) + { + m_cachedSeparatingAxis = seperatingAxis; + } + + void setPenetrationDepthSolver(btConvexPenetrationDepthSolver* penetrationDepthSolver) + { + m_penetrationDepthSolver = penetrationDepthSolver; + } + + ///don't use setIgnoreMargin, it's for Bullet's internal use + void setIgnoreMargin(bool ignoreMargin) + { + m_ignoreMargin = ignoreMargin; + } + + +}; + +#endif //GJK_PAIR_DETECTOR_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h new file mode 100644 index 00000000000..f6a893151da --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h @@ -0,0 +1,99 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef MANIFOLD_CONTACT_POINT_H +#define MANIFOLD_CONTACT_POINT_H + +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btTransformUtil.h" + + + + + +/// ManifoldContactPoint collects and maintains persistent contactpoints. +/// used to improve stability and performance of rigidbody dynamics response. +class btManifoldPoint + { + public: + btManifoldPoint() + :m_userPersistentData(0), + m_lifeTime(0) + { + } + + btManifoldPoint( const btVector3 &pointA, const btVector3 &pointB, + const btVector3 &normal, + btScalar distance ) : + m_localPointA( pointA ), + m_localPointB( pointB ), + m_normalWorldOnB( normal ), + m_distance1( distance ), + m_combinedFriction(btScalar(0.)), + m_combinedRestitution(btScalar(0.)), + m_userPersistentData(0), + m_lifeTime(0) + { + + + } + + + + btVector3 m_localPointA; + btVector3 m_localPointB; + btVector3 m_positionWorldOnB; + ///m_positionWorldOnA is redundant information, see getPositionWorldOnA(), but for clarity + btVector3 m_positionWorldOnA; + btVector3 m_normalWorldOnB; + + btScalar m_distance1; + btScalar m_combinedFriction; + btScalar m_combinedRestitution; + + + mutable void* m_userPersistentData; + + int m_lifeTime;//lifetime of the contactpoint in frames + + btScalar getDistance() const + { + return m_distance1; + } + int getLifeTime() const + { + return m_lifeTime; + } + + const btVector3& getPositionWorldOnA() const { + return m_positionWorldOnA; +// return m_positionWorldOnB + m_normalWorldOnB * m_distance1; + } + + const btVector3& getPositionWorldOnB() const + { + return m_positionWorldOnB; + } + + void setDistance(btScalar dist) + { + m_distance1 = dist; + } + + + + }; + +#endif //MANIFOLD_CONTACT_POINT_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp new file mode 100644 index 00000000000..c4bab3a134a --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp @@ -0,0 +1,334 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btMinkowskiPenetrationDepthSolver.h" +#include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" +#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" +#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" + + + + +#define NUM_UNITSPHERE_POINTS 42 +static btVector3 sPenetrationDirections[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2] = +{ +btVector3(btScalar(0.000000) , btScalar(-0.000000),btScalar(-1.000000)), +btVector3(btScalar(0.723608) , btScalar(-0.525725),btScalar(-0.447219)), +btVector3(btScalar(-0.276388) , btScalar(-0.850649),btScalar(-0.447219)), +btVector3(btScalar(-0.894426) , btScalar(-0.000000),btScalar(-0.447216)), +btVector3(btScalar(-0.276388) , btScalar(0.850649),btScalar(-0.447220)), +btVector3(btScalar(0.723608) , btScalar(0.525725),btScalar(-0.447219)), +btVector3(btScalar(0.276388) , btScalar(-0.850649),btScalar(0.447220)), +btVector3(btScalar(-0.723608) , btScalar(-0.525725),btScalar(0.447219)), +btVector3(btScalar(-0.723608) , btScalar(0.525725),btScalar(0.447219)), +btVector3(btScalar(0.276388) , btScalar(0.850649),btScalar(0.447219)), +btVector3(btScalar(0.894426) , btScalar(0.000000),btScalar(0.447216)), +btVector3(btScalar(-0.000000) , btScalar(0.000000),btScalar(1.000000)), +btVector3(btScalar(0.425323) , btScalar(-0.309011),btScalar(-0.850654)), +btVector3(btScalar(-0.162456) , btScalar(-0.499995),btScalar(-0.850654)), +btVector3(btScalar(0.262869) , btScalar(-0.809012),btScalar(-0.525738)), +btVector3(btScalar(0.425323) , btScalar(0.309011),btScalar(-0.850654)), +btVector3(btScalar(0.850648) , btScalar(-0.000000),btScalar(-0.525736)), +btVector3(btScalar(-0.525730) , btScalar(-0.000000),btScalar(-0.850652)), +btVector3(btScalar(-0.688190) , btScalar(-0.499997),btScalar(-0.525736)), +btVector3(btScalar(-0.162456) , btScalar(0.499995),btScalar(-0.850654)), +btVector3(btScalar(-0.688190) , btScalar(0.499997),btScalar(-0.525736)), +btVector3(btScalar(0.262869) , btScalar(0.809012),btScalar(-0.525738)), +btVector3(btScalar(0.951058) , btScalar(0.309013),btScalar(0.000000)), +btVector3(btScalar(0.951058) , btScalar(-0.309013),btScalar(0.000000)), +btVector3(btScalar(0.587786) , btScalar(-0.809017),btScalar(0.000000)), +btVector3(btScalar(0.000000) , btScalar(-1.000000),btScalar(0.000000)), +btVector3(btScalar(-0.587786) , btScalar(-0.809017),btScalar(0.000000)), +btVector3(btScalar(-0.951058) , btScalar(-0.309013),btScalar(-0.000000)), +btVector3(btScalar(-0.951058) , btScalar(0.309013),btScalar(-0.000000)), +btVector3(btScalar(-0.587786) , btScalar(0.809017),btScalar(-0.000000)), +btVector3(btScalar(-0.000000) , btScalar(1.000000),btScalar(-0.000000)), +btVector3(btScalar(0.587786) , btScalar(0.809017),btScalar(-0.000000)), +btVector3(btScalar(0.688190) , btScalar(-0.499997),btScalar(0.525736)), +btVector3(btScalar(-0.262869) , btScalar(-0.809012),btScalar(0.525738)), +btVector3(btScalar(-0.850648) , btScalar(0.000000),btScalar(0.525736)), +btVector3(btScalar(-0.262869) , btScalar(0.809012),btScalar(0.525738)), +btVector3(btScalar(0.688190) , btScalar(0.499997),btScalar(0.525736)), +btVector3(btScalar(0.525730) , btScalar(0.000000),btScalar(0.850652)), +btVector3(btScalar(0.162456) , btScalar(-0.499995),btScalar(0.850654)), +btVector3(btScalar(-0.425323) , btScalar(-0.309011),btScalar(0.850654)), +btVector3(btScalar(-0.425323) , btScalar(0.309011),btScalar(0.850654)), +btVector3(btScalar(0.162456) , btScalar(0.499995),btScalar(0.850654)) +}; + + +bool btMinkowskiPenetrationDepthSolver::calcPenDepth(btSimplexSolverInterface& simplexSolver, + btConvexShape* convexA,btConvexShape* convexB, + const btTransform& transA,const btTransform& transB, + btVector3& v, btPoint3& pa, btPoint3& pb, + class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc + ) +{ + + (void)stackAlloc; + (void)v; + + + struct btIntermediateResult : public btDiscreteCollisionDetectorInterface::Result + { + + btIntermediateResult():m_hasResult(false) + { + } + + btVector3 m_normalOnBInWorld; + btVector3 m_pointInWorld; + btScalar m_depth; + bool m_hasResult; + + virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1) + { + (void)partId0; + (void)index0; + (void)partId1; + (void)index1; + } + void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) + { + m_normalOnBInWorld = normalOnBInWorld; + m_pointInWorld = pointInWorld; + m_depth = depth; + m_hasResult = true; + } + }; + + //just take fixed number of orientation, and sample the penetration depth in that direction + btScalar minProj = btScalar(1e30); + btVector3 minNorm; + btVector3 minVertex; + btVector3 minA,minB; + btVector3 seperatingAxisInA,seperatingAxisInB; + btVector3 pInA,qInB,pWorld,qWorld,w; + +#define USE_BATCHED_SUPPORT 1 +#ifdef USE_BATCHED_SUPPORT + + btVector3 supportVerticesABatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; + btVector3 supportVerticesBBatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; + btVector3 seperatingAxisInABatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; + btVector3 seperatingAxisInBBatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; + int i; + + int numSampleDirections = NUM_UNITSPHERE_POINTS; + + for (i=0;igetNumPreferredPenetrationDirections(); + if (numPDA) + { + for (int i=0;igetPreferredPenetrationDirection(i,norm); + norm = transA.getBasis() * norm; + sPenetrationDirections[numSampleDirections] = norm; + seperatingAxisInABatch[numSampleDirections] = (-norm) * transA.getBasis(); + seperatingAxisInBBatch[numSampleDirections] = norm * transB.getBasis(); + numSampleDirections++; + } + } + } + + { + int numPDB = convexB->getNumPreferredPenetrationDirections(); + if (numPDB) + { + for (int i=0;igetPreferredPenetrationDirection(i,norm); + norm = transB.getBasis() * norm; + sPenetrationDirections[numSampleDirections] = norm; + seperatingAxisInABatch[numSampleDirections] = (-norm) * transA.getBasis(); + seperatingAxisInBBatch[numSampleDirections] = norm * transB.getBasis(); + numSampleDirections++; + } + } + } + + + + convexA->batchedUnitVectorGetSupportingVertexWithoutMargin(seperatingAxisInABatch,supportVerticesABatch,numSampleDirections); + convexB->batchedUnitVectorGetSupportingVertexWithoutMargin(seperatingAxisInBBatch,supportVerticesBBatch,numSampleDirections); + + for (i=0;igetNumPreferredPenetrationDirections(); + if (numPDA) + { + for (int i=0;igetPreferredPenetrationDirection(i,norm); + norm = transA.getBasis() * norm; + sPenetrationDirections[numSampleDirections] = norm; + numSampleDirections++; + } + } + } + + { + int numPDB = convexB->getNumPreferredPenetrationDirections(); + if (numPDB) + { + for (int i=0;igetPreferredPenetrationDirection(i,norm); + norm = transB.getBasis() * norm; + sPenetrationDirections[numSampleDirections] = norm; + numSampleDirections++; + } + } + } + + for (int i=0;ilocalGetSupportingVertexWithoutMargin(seperatingAxisInA); + qInB = convexB->localGetSupportingVertexWithoutMargin(seperatingAxisInB); + pWorld = transA(pInA); + qWorld = transB(qInB); + w = qWorld - pWorld; + btScalar delta = norm.dot(w); + //find smallest delta + if (delta < minProj) + { + minProj = delta; + minNorm = norm; + minA = pWorld; + minB = qWorld; + } + } +#endif //USE_BATCHED_SUPPORT + + //add the margins + + minA += minNorm*convexA->getMargin(); + minB -= minNorm*convexB->getMargin(); + //no penetration + if (minProj < btScalar(0.)) + return false; + + minProj += (convexA->getMargin() + convexB->getMargin()); + + + + + +//#define DEBUG_DRAW 1 +#ifdef DEBUG_DRAW + if (debugDraw) + { + btVector3 color(0,1,0); + debugDraw->drawLine(minA,minB,color); + color = btVector3 (1,1,1); + btVector3 vec = minB-minA; + btScalar prj2 = minNorm.dot(vec); + debugDraw->drawLine(minA,minA+(minNorm*minProj),color); + + } +#endif //DEBUG_DRAW + + + + btGjkPairDetector gjkdet(convexA,convexB,&simplexSolver,0); + + btScalar offsetDist = minProj; + btVector3 offset = minNorm * offsetDist; + + + + btGjkPairDetector::ClosestPointInput input; + + btVector3 newOrg = transA.getOrigin() + offset; + + btTransform displacedTrans = transA; + displacedTrans.setOrigin(newOrg); + + input.m_transformA = displacedTrans; + input.m_transformB = transB; + input.m_maximumDistanceSquared = btScalar(1e30);//minProj; + + btIntermediateResult res; + gjkdet.getClosestPoints(input,res,debugDraw); + + btScalar correctedMinNorm = minProj - res.m_depth; + + + //the penetration depth is over-estimated, relax it + btScalar penetration_relaxation= btScalar(1.); + minNorm*=penetration_relaxation; + + if (res.m_hasResult) + { + + pa = res.m_pointInWorld - minNorm * correctedMinNorm; + pb = res.m_pointInWorld; + +#ifdef DEBUG_DRAW + if (debugDraw) + { + btVector3 color(1,0,0); + debugDraw->drawLine(pa,pb,color); + } +#endif//DEBUG_DRAW + + + } + return res.m_hasResult; +} + + + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h new file mode 100644 index 00000000000..b348b21b52a --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h @@ -0,0 +1,37 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef MINKOWSKI_PENETRATION_DEPTH_SOLVER_H +#define MINKOWSKI_PENETRATION_DEPTH_SOLVER_H + +#include "btConvexPenetrationDepthSolver.h" + +///MinkowskiPenetrationDepthSolver implements bruteforce penetration depth estimation. +///Implementation is based on sampling the depth using support mapping, and using GJK step to get the witness points. +class btMinkowskiPenetrationDepthSolver : public btConvexPenetrationDepthSolver +{ +public: + + virtual bool calcPenDepth( btSimplexSolverInterface& simplexSolver, + btConvexShape* convexA,btConvexShape* convexB, + const btTransform& transA,const btTransform& transB, + btVector3& v, btPoint3& pa, btPoint3& pb, + class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc + ); + +}; + +#endif //MINKOWSKI_PENETRATION_DEPTH_SOLVER_H + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp new file mode 100644 index 00000000000..08cb3ed334d --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp @@ -0,0 +1,246 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btPersistentManifold.h" +#include "LinearMath/btTransform.h" +#include + +btScalar gContactBreakingThreshold = btScalar(0.02); +ContactDestroyedCallback gContactDestroyedCallback = 0; + + + +btPersistentManifold::btPersistentManifold() +:m_body0(0), +m_body1(0), +m_cachedPoints (0), +m_index1(0) +{ +} + + +void btPersistentManifold::clearManifold() +{ + int i; + for (i=0;i +void btPersistentManifold::DebugPersistency() +{ + int i; + printf("DebugPersistency : numPoints %d\n",m_cachedPoints); + for (i=0;i1) + printf("error in clearUserCache\n"); + } + } + assert(occurance<=0); +#endif //DEBUG_PERSISTENCY + + if (pt.m_userPersistentData && gContactDestroyedCallback) + { + (*gContactDestroyedCallback)(pt.m_userPersistentData); + pt.m_userPersistentData = 0; + } + +#ifdef DEBUG_PERSISTENCY + DebugPersistency(); +#endif + } + + +} + + +int btPersistentManifold::sortCachedPoints(const btManifoldPoint& pt) +{ + + //calculate 4 possible cases areas, and take biggest area + //also need to keep 'deepest' + + int maxPenetrationIndex = -1; +#define KEEP_DEEPEST_POINT 1 +#ifdef KEEP_DEEPEST_POINT + btScalar maxPenetration = pt.getDistance(); + for (int i=0;i<4;i++) + { + if (m_pointCache[i].getDistance() < maxPenetration) + { + maxPenetrationIndex = i; + maxPenetration = m_pointCache[i].getDistance(); + } + } +#endif //KEEP_DEEPEST_POINT + + btScalar res0(btScalar(0.)),res1(btScalar(0.)),res2(btScalar(0.)),res3(btScalar(0.)); + if (maxPenetrationIndex != 0) + { + btVector3 a0 = pt.m_localPointA-m_pointCache[1].m_localPointA; + btVector3 b0 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; + btVector3 cross = a0.cross(b0); + res0 = cross.length2(); + } + if (maxPenetrationIndex != 1) + { + btVector3 a1 = pt.m_localPointA-m_pointCache[0].m_localPointA; + btVector3 b1 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; + btVector3 cross = a1.cross(b1); + res1 = cross.length2(); + } + + if (maxPenetrationIndex != 2) + { + btVector3 a2 = pt.m_localPointA-m_pointCache[0].m_localPointA; + btVector3 b2 = m_pointCache[3].m_localPointA-m_pointCache[1].m_localPointA; + btVector3 cross = a2.cross(b2); + res2 = cross.length2(); + } + + if (maxPenetrationIndex != 3) + { + btVector3 a3 = pt.m_localPointA-m_pointCache[0].m_localPointA; + btVector3 b3 = m_pointCache[2].m_localPointA-m_pointCache[1].m_localPointA; + btVector3 cross = a3.cross(b3); + res3 = cross.length2(); + } + + btVector4 maxvec(res0,res1,res2,res3); + int biggestarea = maxvec.closestAxis4(); + return biggestarea; +} + + +int btPersistentManifold::getCacheEntry(const btManifoldPoint& newPoint) const +{ + btScalar shortestDist = getContactBreakingThreshold() * getContactBreakingThreshold(); + int size = getNumContacts(); + int nearestPoint = -1; + for( int i = 0; i < size; i++ ) + { + const btManifoldPoint &mp = m_pointCache[i]; + + btVector3 diffA = mp.m_localPointA- newPoint.m_localPointA; + const btScalar distToManiPoint = diffA.dot(diffA); + if( distToManiPoint < shortestDist ) + { + shortestDist = distToManiPoint; + nearestPoint = i; + } + } + return nearestPoint; +} + +void btPersistentManifold::AddManifoldPoint(const btManifoldPoint& newPoint) +{ + assert(validContactDistance(newPoint)); + + int insertIndex = getNumContacts(); + if (insertIndex == MANIFOLD_CACHE_SIZE) + { +#if MANIFOLD_CACHE_SIZE >= 4 + //sort cache so best points come first, based on area + insertIndex = sortCachedPoints(newPoint); +#else + insertIndex = 0; +#endif + + + } else + { + m_cachedPoints++; + + + } + replaceContactPoint(newPoint,insertIndex); +} + +btScalar btPersistentManifold::getContactBreakingThreshold() const +{ + return gContactBreakingThreshold; +} + +void btPersistentManifold::refreshContactPoints(const btTransform& trA,const btTransform& trB) +{ + int i; + + /// first refresh worldspace positions and distance + for (i=getNumContacts()-1;i>=0;i--) + { + btManifoldPoint &manifoldPoint = m_pointCache[i]; + manifoldPoint.m_positionWorldOnA = trA( manifoldPoint.m_localPointA ); + manifoldPoint.m_positionWorldOnB = trB( manifoldPoint.m_localPointB ); + manifoldPoint.m_distance1 = (manifoldPoint.m_positionWorldOnA - manifoldPoint.m_positionWorldOnB).dot(manifoldPoint.m_normalWorldOnB); + manifoldPoint.m_lifeTime++; + } + + /// then + btScalar distance2d; + btVector3 projectedDifference,projectedPoint; + for (i=getNumContacts()-1;i>=0;i--) + { + + btManifoldPoint &manifoldPoint = m_pointCache[i]; + //contact becomes invalid when signed distance exceeds margin (projected on contactnormal direction) + if (!validContactDistance(manifoldPoint)) + { + removeContactPoint(i); + } else + { + //contact also becomes invalid when relative movement orthogonal to normal exceeds margin + projectedPoint = manifoldPoint.m_positionWorldOnA - manifoldPoint.m_normalWorldOnB * manifoldPoint.m_distance1; + projectedDifference = manifoldPoint.m_positionWorldOnB - projectedPoint; + distance2d = projectedDifference.dot(projectedDifference); + if (distance2d > getContactBreakingThreshold()*getContactBreakingThreshold() ) + { + removeContactPoint(i); + } + } + } +#ifdef DEBUG_PERSISTENCY + DebugPersistency(); +#endif // +} + + + + + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h new file mode 100644 index 00000000000..a5918b84db3 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h @@ -0,0 +1,161 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef PERSISTENT_MANIFOLD_H +#define PERSISTENT_MANIFOLD_H + + +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btTransform.h" +#include "btManifoldPoint.h" + +struct btCollisionResult; + +///contact breaking and merging threshold +extern btScalar gContactBreakingThreshold; + +typedef bool (*ContactDestroyedCallback)(void* userPersistentData); +extern ContactDestroyedCallback gContactDestroyedCallback; + + + + +#define MANIFOLD_CACHE_SIZE 4 + +///btPersistentManifold maintains contact points, and reduces them to 4. +///It does contact filtering/contact reduction. +ATTRIBUTE_ALIGNED16( class) btPersistentManifold +{ + + btManifoldPoint m_pointCache[MANIFOLD_CACHE_SIZE]; + + /// this two body pointers can point to the physics rigidbody class. + /// void* will allow any rigidbody class + void* m_body0; + void* m_body1; + int m_cachedPoints; + + + /// sort cached points so most isolated points come first + int sortCachedPoints(const btManifoldPoint& pt); + + int findContactPoint(const btManifoldPoint* unUsed, int numUnused,const btManifoldPoint& pt); + +public: + + int m_index1; + + btPersistentManifold(); + + btPersistentManifold(void* body0,void* body1) + : m_body0(body0),m_body1(body1),m_cachedPoints(0) + { + } + + inline void* getBody0() { return m_body0;} + inline void* getBody1() { return m_body1;} + + inline const void* getBody0() const { return m_body0;} + inline const void* getBody1() const { return m_body1;} + + void setBodies(void* body0,void* body1) + { + m_body0 = body0; + m_body1 = body1; + } + + void clearUserCache(btManifoldPoint& pt); + +#ifdef DEBUG_PERSISTENCY + void DebugPersistency(); +#endif // + + inline int getNumContacts() const { return m_cachedPoints;} + + inline const btManifoldPoint& getContactPoint(int index) const + { + btAssert(index < m_cachedPoints); + return m_pointCache[index]; + } + + inline btManifoldPoint& getContactPoint(int index) + { + btAssert(index < m_cachedPoints); + return m_pointCache[index]; + } + + /// todo: get this margin from the current physics / collision environment + btScalar getContactBreakingThreshold() const; + + int getCacheEntry(const btManifoldPoint& newPoint) const; + + void AddManifoldPoint( const btManifoldPoint& newPoint); + + void removeContactPoint (int index) + { + clearUserCache(m_pointCache[index]); + + int lastUsedIndex = getNumContacts() - 1; +// m_pointCache[index] = m_pointCache[lastUsedIndex]; + if(index != lastUsedIndex) + { + m_pointCache[index] = m_pointCache[lastUsedIndex]; + //get rid of duplicated userPersistentData pointer + m_pointCache[lastUsedIndex].m_userPersistentData = 0; + } + + btAssert(m_pointCache[lastUsedIndex].m_userPersistentData==0); + m_cachedPoints--; + } + void replaceContactPoint(const btManifoldPoint& newPoint,int insertIndex) + { + btAssert(validContactDistance(newPoint)); + +#define MAINTAIN_PERSISTENCY 1 +#ifdef MAINTAIN_PERSISTENCY + int lifeTime = m_pointCache[insertIndex].getLifeTime(); + btAssert(lifeTime>=0); + void* cache = m_pointCache[insertIndex].m_userPersistentData; + + m_pointCache[insertIndex] = newPoint; + + m_pointCache[insertIndex].m_userPersistentData = cache; + m_pointCache[insertIndex].m_lifeTime = lifeTime; +#else + clearUserCache(m_pointCache[insertIndex]); + m_pointCache[insertIndex] = newPoint; + +#endif + } + + bool validContactDistance(const btManifoldPoint& pt) const + { + return pt.m_distance1 <= getContactBreakingThreshold(); + } + /// calculated new worldspace coordinates and depth, and reject points that exceed the collision margin + void refreshContactPoints( const btTransform& trA,const btTransform& trB); + + void clearManifold(); + + + +} +; + + + + + +#endif //PERSISTENT_MANIFOLD_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPointCollector.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPointCollector.h new file mode 100644 index 00000000000..6262f44b9f1 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPointCollector.h @@ -0,0 +1,61 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef POINT_COLLECTOR_H +#define POINT_COLLECTOR_H + +#include "btDiscreteCollisionDetectorInterface.h" + + + +struct btPointCollector : public btDiscreteCollisionDetectorInterface::Result +{ + + + btVector3 m_normalOnBInWorld; + btVector3 m_pointInWorld; + btScalar m_distance;//negative means penetration + + bool m_hasResult; + + btPointCollector () + : m_distance(btScalar(1e30)),m_hasResult(false) + { + } + + virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1) + { + (void)partId0; + (void)index0; + (void)partId1; + (void)index1; + //?? + } + + virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) + { + if (depth< m_distance) + { + m_hasResult = true; + m_normalOnBInWorld = normalOnBInWorld; + m_pointInWorld = pointInWorld; + //negative means penetration + m_distance = depth; + } + } +}; + +#endif //POINT_COLLECTOR_H + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp new file mode 100644 index 00000000000..31b91467777 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp @@ -0,0 +1,101 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btRaycastCallback.h" + +btTriangleRaycastCallback::btTriangleRaycastCallback(const btVector3& from,const btVector3& to) + : + m_from(from), + m_to(to), + m_hitFraction(btScalar(1.)) +{ + +} + + + +void btTriangleRaycastCallback::processTriangle(btVector3* triangle,int partId, int triangleIndex) +{ + + + const btVector3 &vert0=triangle[0]; + const btVector3 &vert1=triangle[1]; + const btVector3 &vert2=triangle[2]; + + btVector3 v10; v10 = vert1 - vert0 ; + btVector3 v20; v20 = vert2 - vert0 ; + + btVector3 triangleNormal; triangleNormal = v10.cross( v20 ); + + const btScalar dist = vert0.dot(triangleNormal); + btScalar dist_a = triangleNormal.dot(m_from) ; + dist_a-= dist; + btScalar dist_b = triangleNormal.dot(m_to); + dist_b -= dist; + + if ( dist_a * dist_b >= btScalar(0.0) ) + { + return ; // same sign + } + + const btScalar proj_length=dist_a-dist_b; + const btScalar distance = (dist_a)/(proj_length); + // Now we have the intersection point on the plane, we'll see if it's inside the triangle + // Add an epsilon as a tolerance for the raycast, + // in case the ray hits exacly on the edge of the triangle. + // It must be scaled for the triangle size. + + if(distance < m_hitFraction) + { + + + btScalar edge_tolerance =triangleNormal.length2(); + edge_tolerance *= btScalar(-0.0001); + btVector3 point; point.setInterpolate3( m_from, m_to, distance); + { + btVector3 v0p; v0p = vert0 - point; + btVector3 v1p; v1p = vert1 - point; + btVector3 cp0; cp0 = v0p.cross( v1p ); + + if ( (btScalar)(cp0.dot(triangleNormal)) >=edge_tolerance) + { + + + btVector3 v2p; v2p = vert2 - point; + btVector3 cp1; + cp1 = v1p.cross( v2p); + if ( (btScalar)(cp1.dot(triangleNormal)) >=edge_tolerance) + { + btVector3 cp2; + cp2 = v2p.cross(v0p); + + if ( (btScalar)(cp2.dot(triangleNormal)) >=edge_tolerance) + { + + if ( dist_a > 0 ) + { + m_hitFraction = reportHit(triangleNormal,distance,partId,triangleIndex); + } + else + { + m_hitFraction = reportHit(-triangleNormal,distance,partId,triangleIndex); + } + } + } + } + } + } +} diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h new file mode 100644 index 00000000000..a0bbc9f8fe9 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h @@ -0,0 +1,42 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef RAYCAST_TRI_CALLBACK_H +#define RAYCAST_TRI_CALLBACK_H + +#include "../CollisionShapes/btTriangleCallback.h" +struct btBroadphaseProxy; + + +class btTriangleRaycastCallback: public btTriangleCallback +{ +public: + + //input + btVector3 m_from; + btVector3 m_to; + + btScalar m_hitFraction; + + btTriangleRaycastCallback(const btVector3& from,const btVector3& to); + + virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); + + virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex ) = 0; + +}; + +#endif //RAYCAST_TRI_CALLBACK_H + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h new file mode 100644 index 00000000000..58393b2eab9 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h @@ -0,0 +1,64 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef SIMPLEX_SOLVER_INTERFACE_H +#define SIMPLEX_SOLVER_INTERFACE_H + +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btPoint3.h" + +#define NO_VIRTUAL_INTERFACE 1 +#ifdef NO_VIRTUAL_INTERFACE +#include "btVoronoiSimplexSolver.h" +#define btSimplexSolverInterface btVoronoiSimplexSolver +#else + +/// btSimplexSolverInterface can incrementally calculate distance between origin and up to 4 vertices +/// Used by GJK or Linear Casting. Can be implemented by the Johnson-algorithm or alternative approaches based on +/// voronoi regions or barycentric coordinates +class btSimplexSolverInterface +{ + public: + virtual ~btSimplexSolverInterface() {}; + + virtual void reset() = 0; + + virtual void addVertex(const btVector3& w, const btPoint3& p, const btPoint3& q) = 0; + + virtual bool closest(btVector3& v) = 0; + + virtual btScalar maxVertex() = 0; + + virtual bool fullSimplex() const = 0; + + virtual int getSimplex(btPoint3 *pBuf, btPoint3 *qBuf, btVector3 *yBuf) const = 0; + + virtual bool inSimplex(const btVector3& w) = 0; + + virtual void backup_closest(btVector3& v) = 0; + + virtual bool emptySimplex() const = 0; + + virtual void compute_points(btPoint3& p1, btPoint3& p2) = 0; + + virtual int numVertices() const =0; + + +}; +#endif +#endif //SIMPLEX_SOLVER_INTERFACE_H + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp new file mode 100644 index 00000000000..687738b7fa9 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp @@ -0,0 +1,139 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btSubSimplexConvexCast.h" +#include "BulletCollision/CollisionShapes/btConvexShape.h" +#include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" +#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" + + +btSubsimplexConvexCast::btSubsimplexConvexCast (const btConvexShape* convexA,const btConvexShape* convexB,btSimplexSolverInterface* simplexSolver) +:m_simplexSolver(simplexSolver), +m_convexA(convexA),m_convexB(convexB) +{ +} + +///Typically the conservative advancement reaches solution in a few iterations, clip it to 32 for degenerate cases. +///See discussion about this here http://continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=565 +#ifdef BT_USE_DOUBLE_PRECISION +#define MAX_ITERATIONS 64 +#else +#define MAX_ITERATIONS 32 +#endif +bool btSubsimplexConvexCast::calcTimeOfImpact( + const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + CastResult& result) +{ + + btMinkowskiSumShape combi(m_convexA,m_convexB); + btMinkowskiSumShape* convex = &combi; + + btTransform rayFromLocalA; + btTransform rayToLocalA; + + rayFromLocalA = fromA.inverse()* fromB; + rayToLocalA = toA.inverse()* toB; + + + m_simplexSolver->reset(); + + convex->setTransformB(btTransform(rayFromLocalA.getBasis())); + + //btScalar radius = btScalar(0.01); + + btScalar lambda = btScalar(0.); + //todo: need to verify this: + //because of minkowski difference, we need the inverse direction + + btVector3 s = -rayFromLocalA.getOrigin(); + btVector3 r = -(rayToLocalA.getOrigin()-rayFromLocalA.getOrigin()); + btVector3 x = s; + btVector3 v; + btVector3 arbitraryPoint = convex->localGetSupportingVertex(r); + + v = x - arbitraryPoint; + + int maxIter = MAX_ITERATIONS; + + btVector3 n; + n.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); + bool hasResult = false; + btVector3 c; + + btScalar lastLambda = lambda; + + + btScalar dist2 = v.length2(); +#ifdef BT_USE_DOUBLE_PRECISION + btScalar epsilon = btScalar(0.0001); +#else + btScalar epsilon = btScalar(0.0001); +#endif //BT_USE_DOUBLE_PRECISION + btVector3 w,p; + btScalar VdotR; + + while ( (dist2 > epsilon) && maxIter--) + { + p = convex->localGetSupportingVertex( v); + w = x - p; + + btScalar VdotW = v.dot(w); + + if ( VdotW > btScalar(0.)) + { + VdotR = v.dot(r); + + if (VdotR >= -(SIMD_EPSILON*SIMD_EPSILON)) + return false; + else + { + lambda = lambda - VdotW / VdotR; + x = s + lambda * r; + m_simplexSolver->reset(); + //check next line + w = x-p; + lastLambda = lambda; + n = v; + hasResult = true; + } + } + m_simplexSolver->addVertex( w, x , p); + if (m_simplexSolver->closest(v)) + { + dist2 = v.length2(); + hasResult = true; + //printf("V=%f , %f, %f\n",v[0],v[1],v[2]); + //printf("DIST2=%f\n",dist2); + //printf("numverts = %i\n",m_simplexSolver->numVertices()); + } else + { + dist2 = btScalar(0.); + } + } + + //int numiter = MAX_ITERATIONS - maxIter; +// printf("number of iterations: %d", numiter); + result.m_fraction = lambda; + result.m_normal = n; + + return true; +} + + + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h new file mode 100644 index 00000000000..05662db5d23 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h @@ -0,0 +1,50 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef SUBSIMPLEX_CONVEX_CAST_H +#define SUBSIMPLEX_CONVEX_CAST_H + +#include "btConvexCast.h" +#include "btSimplexSolverInterface.h" +class btConvexShape; + +/// btSubsimplexConvexCast implements Gino van den Bergens' paper +///"Ray Casting against bteral Convex Objects with Application to Continuous Collision Detection" +/// GJK based Ray Cast, optimized version +/// Objects should not start in overlap, otherwise results are not defined. +class btSubsimplexConvexCast : public btConvexCast +{ + btSimplexSolverInterface* m_simplexSolver; + const btConvexShape* m_convexA; + const btConvexShape* m_convexB; + +public: + + btSubsimplexConvexCast (const btConvexShape* shapeA,const btConvexShape* shapeB,btSimplexSolverInterface* simplexSolver); + + //virtual ~btSubsimplexConvexCast(); + ///SimsimplexConvexCast calculateTimeOfImpact calculates the time of impact+normal for the linear cast (sweep) between two moving objects. + ///Precondition is that objects should not penetration/overlap at the start from the interval. Overlap can be tested using btGjkPairDetector. + virtual bool calcTimeOfImpact( + const btTransform& fromA, + const btTransform& toA, + const btTransform& fromB, + const btTransform& toB, + CastResult& result); + +}; + +#endif //SUBSIMPLEX_CONVEX_CAST_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp new file mode 100644 index 00000000000..105b7eccefa --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp @@ -0,0 +1,607 @@ + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + + Elsevier CDROM license agreements grants nonexclusive license to use the software + for any purpose, commercial or non-commercial as long as the following credit is included + identifying the original source of the software: + + Parts of the source are "from the book Real-Time Collision Detection by + Christer Ericson, published by Morgan Kaufmann Publishers, + (c) 2005 Elsevier Inc." + +*/ + + +#include "btVoronoiSimplexSolver.h" +#include +#include + +#define VERTA 0 +#define VERTB 1 +#define VERTC 2 +#define VERTD 3 + +#define CATCH_DEGENERATE_TETRAHEDRON 1 +void btVoronoiSimplexSolver::removeVertex(int index) +{ + + assert(m_numVertices>0); + m_numVertices--; + m_simplexVectorW[index] = m_simplexVectorW[m_numVertices]; + m_simplexPointsP[index] = m_simplexPointsP[m_numVertices]; + m_simplexPointsQ[index] = m_simplexPointsQ[m_numVertices]; +} + +void btVoronoiSimplexSolver::reduceVertices (const btUsageBitfield& usedVerts) +{ + if ((numVertices() >= 4) && (!usedVerts.usedVertexD)) + removeVertex(3); + + if ((numVertices() >= 3) && (!usedVerts.usedVertexC)) + removeVertex(2); + + if ((numVertices() >= 2) && (!usedVerts.usedVertexB)) + removeVertex(1); + + if ((numVertices() >= 1) && (!usedVerts.usedVertexA)) + removeVertex(0); + +} + + + + + +//clear the simplex, remove all the vertices +void btVoronoiSimplexSolver::reset() +{ + m_cachedValidClosest = false; + m_numVertices = 0; + m_needsUpdate = true; + m_lastW = btVector3(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + m_cachedBC.reset(); +} + + + + //add a vertex +void btVoronoiSimplexSolver::addVertex(const btVector3& w, const btPoint3& p, const btPoint3& q) +{ + m_lastW = w; + m_needsUpdate = true; + + m_simplexVectorW[m_numVertices] = w; + m_simplexPointsP[m_numVertices] = p; + m_simplexPointsQ[m_numVertices] = q; + + m_numVertices++; +} + +bool btVoronoiSimplexSolver::updateClosestVectorAndPoints() +{ + + if (m_needsUpdate) + { + m_cachedBC.reset(); + + m_needsUpdate = false; + + switch (numVertices()) + { + case 0: + m_cachedValidClosest = false; + break; + case 1: + { + m_cachedP1 = m_simplexPointsP[0]; + m_cachedP2 = m_simplexPointsQ[0]; + m_cachedV = m_cachedP1-m_cachedP2; //== m_simplexVectorW[0] + m_cachedBC.reset(); + m_cachedBC.setBarycentricCoordinates(btScalar(1.),btScalar(0.),btScalar(0.),btScalar(0.)); + m_cachedValidClosest = m_cachedBC.isValid(); + break; + }; + case 2: + { + //closest point origin from line segment + const btVector3& from = m_simplexVectorW[0]; + const btVector3& to = m_simplexVectorW[1]; + btVector3 nearest; + + btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); + btVector3 diff = p - from; + btVector3 v = to - from; + btScalar t = v.dot(diff); + + if (t > 0) { + btScalar dotVV = v.dot(v); + if (t < dotVV) { + t /= dotVV; + diff -= t*v; + m_cachedBC.m_usedVertices.usedVertexA = true; + m_cachedBC.m_usedVertices.usedVertexB = true; + } else { + t = 1; + diff -= v; + //reduce to 1 point + m_cachedBC.m_usedVertices.usedVertexB = true; + } + } else + { + t = 0; + //reduce to 1 point + m_cachedBC.m_usedVertices.usedVertexA = true; + } + m_cachedBC.setBarycentricCoordinates(1-t,t); + nearest = from + t*v; + + m_cachedP1 = m_simplexPointsP[0] + t * (m_simplexPointsP[1] - m_simplexPointsP[0]); + m_cachedP2 = m_simplexPointsQ[0] + t * (m_simplexPointsQ[1] - m_simplexPointsQ[0]); + m_cachedV = m_cachedP1 - m_cachedP2; + + reduceVertices(m_cachedBC.m_usedVertices); + + m_cachedValidClosest = m_cachedBC.isValid(); + break; + } + case 3: + { + //closest point origin from triangle + btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); + + const btVector3& a = m_simplexVectorW[0]; + const btVector3& b = m_simplexVectorW[1]; + const btVector3& c = m_simplexVectorW[2]; + + closestPtPointTriangle(p,a,b,c,m_cachedBC); + m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] + + m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] + + m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2]; + + m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] + + m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] + + m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2]; + + m_cachedV = m_cachedP1-m_cachedP2; + + reduceVertices (m_cachedBC.m_usedVertices); + m_cachedValidClosest = m_cachedBC.isValid(); + + break; + } + case 4: + { + + + btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); + + const btVector3& a = m_simplexVectorW[0]; + const btVector3& b = m_simplexVectorW[1]; + const btVector3& c = m_simplexVectorW[2]; + const btVector3& d = m_simplexVectorW[3]; + + bool hasSeperation = closestPtPointTetrahedron(p,a,b,c,d,m_cachedBC); + + if (hasSeperation) + { + + m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] + + m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] + + m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] + + m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3]; + + m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] + + m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] + + m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] + + m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3]; + + m_cachedV = m_cachedP1-m_cachedP2; + reduceVertices (m_cachedBC.m_usedVertices); + } else + { +// printf("sub distance got penetration\n"); + + if (m_cachedBC.m_degenerate) + { + m_cachedValidClosest = false; + } else + { + m_cachedValidClosest = true; + //degenerate case == false, penetration = true + zero + m_cachedV.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); + } + break; + } + + m_cachedValidClosest = m_cachedBC.isValid(); + + //closest point origin from tetrahedron + break; + } + default: + { + m_cachedValidClosest = false; + } + }; + } + + return m_cachedValidClosest; + +} + +//return/calculate the closest vertex +bool btVoronoiSimplexSolver::closest(btVector3& v) +{ + bool succes = updateClosestVectorAndPoints(); + v = m_cachedV; + return succes; +} + + + +btScalar btVoronoiSimplexSolver::maxVertex() +{ + int i, numverts = numVertices(); + btScalar maxV = btScalar(0.); + for (i=0;i= btScalar(0.0) && d4 <= d3) + { + result.m_closestPointOnSimplex = b; + result.m_usedVertices.usedVertexB = true; + result.setBarycentricCoordinates(0,1,0); + + return true; // b; // barycentric coordinates (0,1,0) + } + // Check if P in edge region of AB, if so return projection of P onto AB + btScalar vc = d1*d4 - d3*d2; + if (vc <= btScalar(0.0) && d1 >= btScalar(0.0) && d3 <= btScalar(0.0)) { + btScalar v = d1 / (d1 - d3); + result.m_closestPointOnSimplex = a + v * ab; + result.m_usedVertices.usedVertexA = true; + result.m_usedVertices.usedVertexB = true; + result.setBarycentricCoordinates(1-v,v,0); + return true; + //return a + v * ab; // barycentric coordinates (1-v,v,0) + } + + // Check if P in vertex region outside C + btVector3 cp = p - c; + btScalar d5 = ab.dot(cp); + btScalar d6 = ac.dot(cp); + if (d6 >= btScalar(0.0) && d5 <= d6) + { + result.m_closestPointOnSimplex = c; + result.m_usedVertices.usedVertexC = true; + result.setBarycentricCoordinates(0,0,1); + return true;//c; // barycentric coordinates (0,0,1) + } + + // Check if P in edge region of AC, if so return projection of P onto AC + btScalar vb = d5*d2 - d1*d6; + if (vb <= btScalar(0.0) && d2 >= btScalar(0.0) && d6 <= btScalar(0.0)) { + btScalar w = d2 / (d2 - d6); + result.m_closestPointOnSimplex = a + w * ac; + result.m_usedVertices.usedVertexA = true; + result.m_usedVertices.usedVertexC = true; + result.setBarycentricCoordinates(1-w,0,w); + return true; + //return a + w * ac; // barycentric coordinates (1-w,0,w) + } + + // Check if P in edge region of BC, if so return projection of P onto BC + btScalar va = d3*d6 - d5*d4; + if (va <= btScalar(0.0) && (d4 - d3) >= btScalar(0.0) && (d5 - d6) >= btScalar(0.0)) { + btScalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); + + result.m_closestPointOnSimplex = b + w * (c - b); + result.m_usedVertices.usedVertexB = true; + result.m_usedVertices.usedVertexC = true; + result.setBarycentricCoordinates(0,1-w,w); + return true; + // return b + w * (c - b); // barycentric coordinates (0,1-w,w) + } + + // P inside face region. Compute Q through its barycentric coordinates (u,v,w) + btScalar denom = btScalar(1.0) / (va + vb + vc); + btScalar v = vb * denom; + btScalar w = vc * denom; + + result.m_closestPointOnSimplex = a + ab * v + ac * w; + result.m_usedVertices.usedVertexA = true; + result.m_usedVertices.usedVertexB = true; + result.m_usedVertices.usedVertexC = true; + result.setBarycentricCoordinates(1-v-w,v,w); + + return true; +// return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = btScalar(1.0) - v - w + +} + + + + + +/// Test if point p and d lie on opposite sides of plane through abc +int btVoronoiSimplexSolver::pointOutsideOfPlane(const btPoint3& p, const btPoint3& a, const btPoint3& b, const btPoint3& c, const btPoint3& d) +{ + btVector3 normal = (b-a).cross(c-a); + + btScalar signp = (p - a).dot(normal); // [AP AB AC] + btScalar signd = (d - a).dot( normal); // [AD AB AC] + +#ifdef CATCH_DEGENERATE_TETRAHEDRON +#ifdef BT_USE_DOUBLE_PRECISION +if (signd * signd < (btScalar(1e-8) * btScalar(1e-8))) + { + return -1; + } +#else + if (signd * signd < (btScalar(1e-4) * btScalar(1e-4))) + { +// printf("affine dependent/degenerate\n");// + return -1; + } +#endif + +#endif + // Points on opposite sides if expression signs are opposite + return signp * signd < btScalar(0.); +} + + +bool btVoronoiSimplexSolver::closestPtPointTetrahedron(const btPoint3& p, const btPoint3& a, const btPoint3& b, const btPoint3& c, const btPoint3& d, btSubSimplexClosestResult& finalResult) +{ + btSubSimplexClosestResult tempResult; + + // Start out assuming point inside all halfspaces, so closest to itself + finalResult.m_closestPointOnSimplex = p; + finalResult.m_usedVertices.reset(); + finalResult.m_usedVertices.usedVertexA = true; + finalResult.m_usedVertices.usedVertexB = true; + finalResult.m_usedVertices.usedVertexC = true; + finalResult.m_usedVertices.usedVertexD = true; + + int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d); + int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b); + int pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c); + int pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a); + + if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0) + { + finalResult.m_degenerate = true; + return false; + } + + if (!pointOutsideABC && !pointOutsideACD && !pointOutsideADB && !pointOutsideBDC) + { + return false; + } + + + btScalar bestSqDist = FLT_MAX; + // If point outside face abc then compute closest point on abc + if (pointOutsideABC) + { + closestPtPointTriangle(p, a, b, c,tempResult); + btPoint3 q = tempResult.m_closestPointOnSimplex; + + btScalar sqDist = (q - p).dot( q - p); + // Update best closest point if (squared) distance is less than current best + if (sqDist < bestSqDist) { + bestSqDist = sqDist; + finalResult.m_closestPointOnSimplex = q; + //convert result bitmask! + finalResult.m_usedVertices.reset(); + finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; + finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexB; + finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC; + finalResult.setBarycentricCoordinates( + tempResult.m_barycentricCoords[VERTA], + tempResult.m_barycentricCoords[VERTB], + tempResult.m_barycentricCoords[VERTC], + 0 + ); + + } + } + + + // Repeat test for face acd + if (pointOutsideACD) + { + closestPtPointTriangle(p, a, c, d,tempResult); + btPoint3 q = tempResult.m_closestPointOnSimplex; + //convert result bitmask! + + btScalar sqDist = (q - p).dot( q - p); + if (sqDist < bestSqDist) + { + bestSqDist = sqDist; + finalResult.m_closestPointOnSimplex = q; + finalResult.m_usedVertices.reset(); + finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; + + finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexB; + finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexC; + finalResult.setBarycentricCoordinates( + tempResult.m_barycentricCoords[VERTA], + 0, + tempResult.m_barycentricCoords[VERTB], + tempResult.m_barycentricCoords[VERTC] + ); + + } + } + // Repeat test for face adb + + + if (pointOutsideADB) + { + closestPtPointTriangle(p, a, d, b,tempResult); + btPoint3 q = tempResult.m_closestPointOnSimplex; + //convert result bitmask! + + btScalar sqDist = (q - p).dot( q - p); + if (sqDist < bestSqDist) + { + bestSqDist = sqDist; + finalResult.m_closestPointOnSimplex = q; + finalResult.m_usedVertices.reset(); + finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; + finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexC; + + finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB; + finalResult.setBarycentricCoordinates( + tempResult.m_barycentricCoords[VERTA], + tempResult.m_barycentricCoords[VERTC], + 0, + tempResult.m_barycentricCoords[VERTB] + ); + + } + } + // Repeat test for face bdc + + + if (pointOutsideBDC) + { + closestPtPointTriangle(p, b, d, c,tempResult); + btPoint3 q = tempResult.m_closestPointOnSimplex; + //convert result bitmask! + btScalar sqDist = (q - p).dot( q - p); + if (sqDist < bestSqDist) + { + bestSqDist = sqDist; + finalResult.m_closestPointOnSimplex = q; + finalResult.m_usedVertices.reset(); + // + finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexA; + finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC; + finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB; + + finalResult.setBarycentricCoordinates( + 0, + tempResult.m_barycentricCoords[VERTA], + tempResult.m_barycentricCoords[VERTC], + tempResult.m_barycentricCoords[VERTB] + ); + + } + } + + //help! we ended up full ! + + if (finalResult.m_usedVertices.usedVertexA && + finalResult.m_usedVertices.usedVertexB && + finalResult.m_usedVertices.usedVertexC && + finalResult.m_usedVertices.usedVertexD) + { + return true; + } + + return true; +} + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h new file mode 100644 index 00000000000..356d335bc93 --- /dev/null +++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h @@ -0,0 +1,157 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef btVoronoiSimplexSolver_H +#define btVoronoiSimplexSolver_H + +#include "btSimplexSolverInterface.h" + + + +#define VORONOI_SIMPLEX_MAX_VERTS 5 + +struct btUsageBitfield{ + btUsageBitfield() + { + reset(); + } + + void reset() + { + usedVertexA = false; + usedVertexB = false; + usedVertexC = false; + usedVertexD = false; + } + unsigned short usedVertexA : 1; + unsigned short usedVertexB : 1; + unsigned short usedVertexC : 1; + unsigned short usedVertexD : 1; + unsigned short unused1 : 1; + unsigned short unused2 : 1; + unsigned short unused3 : 1; + unsigned short unused4 : 1; +}; + + +struct btSubSimplexClosestResult +{ + btPoint3 m_closestPointOnSimplex; + //MASK for m_usedVertices + //stores the simplex vertex-usage, using the MASK, + // if m_usedVertices & MASK then the related vertex is used + btUsageBitfield m_usedVertices; + btScalar m_barycentricCoords[4]; + bool m_degenerate; + + void reset() + { + m_degenerate = false; + setBarycentricCoordinates(); + m_usedVertices.reset(); + } + bool isValid() + { + bool valid = (m_barycentricCoords[0] >= btScalar(0.)) && + (m_barycentricCoords[1] >= btScalar(0.)) && + (m_barycentricCoords[2] >= btScalar(0.)) && + (m_barycentricCoords[3] >= btScalar(0.)); + + + return valid; + } + void setBarycentricCoordinates(btScalar a=btScalar(0.),btScalar b=btScalar(0.),btScalar c=btScalar(0.),btScalar d=btScalar(0.)) + { + m_barycentricCoords[0] = a; + m_barycentricCoords[1] = b; + m_barycentricCoords[2] = c; + m_barycentricCoords[3] = d; + } + +}; + +/// btVoronoiSimplexSolver is an implementation of the closest point distance algorithm from a 1-4 points simplex to the origin. +/// Can be used with GJK, as an alternative to Johnson distance algorithm. +#ifdef NO_VIRTUAL_INTERFACE +class btVoronoiSimplexSolver +#else +class btVoronoiSimplexSolver : public btSimplexSolverInterface +#endif +{ +public: + + int m_numVertices; + + btVector3 m_simplexVectorW[VORONOI_SIMPLEX_MAX_VERTS]; + btPoint3 m_simplexPointsP[VORONOI_SIMPLEX_MAX_VERTS]; + btPoint3 m_simplexPointsQ[VORONOI_SIMPLEX_MAX_VERTS]; + + + + btPoint3 m_cachedP1; + btPoint3 m_cachedP2; + btVector3 m_cachedV; + btVector3 m_lastW; + bool m_cachedValidClosest; + + btSubSimplexClosestResult m_cachedBC; + + bool m_needsUpdate; + + void removeVertex(int index); + void reduceVertices (const btUsageBitfield& usedVerts); + bool updateClosestVectorAndPoints(); + + bool closestPtPointTetrahedron(const btPoint3& p, const btPoint3& a, const btPoint3& b, const btPoint3& c, const btPoint3& d, btSubSimplexClosestResult& finalResult); + int pointOutsideOfPlane(const btPoint3& p, const btPoint3& a, const btPoint3& b, const btPoint3& c, const btPoint3& d); + bool closestPtPointTriangle(const btPoint3& p, const btPoint3& a, const btPoint3& b, const btPoint3& c,btSubSimplexClosestResult& result); + +public: + + void reset(); + + void addVertex(const btVector3& w, const btPoint3& p, const btPoint3& q); + + + bool closest(btVector3& v); + + btScalar maxVertex(); + + bool fullSimplex() const + { + return (m_numVertices == 4); + } + + int getSimplex(btPoint3 *pBuf, btPoint3 *qBuf, btVector3 *yBuf) const; + + bool inSimplex(const btVector3& w); + + void backup_closest(btVector3& v) ; + + bool emptySimplex() const ; + + void compute_points(btPoint3& p1, btPoint3& p2) ; + + int numVertices() const + { + return m_numVertices; + } + + +}; + +#endif //VoronoiSimplexSolver diff --git a/extern/bullet2/src/BulletDynamics/CMakeLists.txt b/extern/bullet2/src/BulletDynamics/CMakeLists.txt new file mode 100644 index 00000000000..79e07b7f77b --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/CMakeLists.txt @@ -0,0 +1,19 @@ +INCLUDE_DIRECTORIES( +${BULLET_PHYSICS_SOURCE_DIR}/src } +) + +ADD_LIBRARY(LibBulletDynamics + + ConstraintSolver/btContactConstraint.cpp + ConstraintSolver/btGeneric6DofConstraint.cpp + ConstraintSolver/btHingeConstraint.cpp + ConstraintSolver/btPoint2PointConstraint.cpp + ConstraintSolver/btSequentialImpulseConstraintSolver.cpp + ConstraintSolver/btSolve2LinearConstraint.cpp + ConstraintSolver/btTypedConstraint.cpp + Dynamics/btDiscreteDynamicsWorld.cpp + Dynamics/btSimpleDynamicsWorld.cpp + Dynamics/btRigidBody.cpp + Vehicle/btRaycastVehicle.cpp + Vehicle/btWheelInfo.cpp +) diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp new file mode 100644 index 00000000000..12a33d7851e --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp @@ -0,0 +1,286 @@ +/* +Bullet Continuous Collision Detection and Physics Library +btConeTwistConstraint is Copyright (c) 2007 Starbreeze Studios + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Written by: Marcus Hennix +*/ + + +#include "btConeTwistConstraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "LinearMath/btTransformUtil.h" +#include "LinearMath/btSimdMinMax.h" +#include + +btConeTwistConstraint::btConeTwistConstraint() +{ +} + + +btConeTwistConstraint::btConeTwistConstraint(btRigidBody& rbA,btRigidBody& rbB, + const btTransform& rbAFrame,const btTransform& rbBFrame) + :btTypedConstraint(rbA,rbB),m_rbAFrame(rbAFrame),m_rbBFrame(rbBFrame), + m_angularOnly(false) +{ + // flip axis for correct angles + m_rbBFrame.getBasis()[1][0] *= btScalar(-1.); + m_rbBFrame.getBasis()[1][1] *= btScalar(-1.); + m_rbBFrame.getBasis()[1][2] *= btScalar(-1.); + + m_swingSpan1 = btScalar(1e30); + m_swingSpan2 = btScalar(1e30); + m_twistSpan = btScalar(1e30); + m_biasFactor = 0.3f; + m_relaxationFactor = 1.0f; + + m_solveTwistLimit = false; + m_solveSwingLimit = false; + +} + +btConeTwistConstraint::btConeTwistConstraint(btRigidBody& rbA,const btTransform& rbAFrame) + :btTypedConstraint(rbA),m_rbAFrame(rbAFrame), + m_angularOnly(false) +{ + m_rbBFrame = m_rbAFrame; + + // flip axis for correct angles + m_rbBFrame.getBasis()[1][0] *= btScalar(-1.); + m_rbBFrame.getBasis()[1][1] *= btScalar(-1.); + m_rbBFrame.getBasis()[1][2] *= btScalar(-1.); + + m_rbBFrame.getBasis()[2][0] *= btScalar(-1.); + m_rbBFrame.getBasis()[2][1] *= btScalar(-1.); + m_rbBFrame.getBasis()[2][2] *= btScalar(-1.); + + m_swingSpan1 = btScalar(1e30); + m_swingSpan2 = btScalar(1e30); + m_twistSpan = btScalar(1e30); + m_biasFactor = 0.3f; + m_relaxationFactor = 1.0f; + + m_solveTwistLimit = false; + m_solveSwingLimit = false; + +} + +void btConeTwistConstraint::buildJacobian() +{ + m_appliedImpulse = btScalar(0.); + + //set bias, sign, clear accumulator + m_swingCorrection = btScalar(0.); + m_twistLimitSign = btScalar(0.); + m_solveTwistLimit = false; + m_solveSwingLimit = false; + m_accTwistLimitImpulse = btScalar(0.); + m_accSwingLimitImpulse = btScalar(0.); + + if (!m_angularOnly) + { + btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin(); + btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin(); + btVector3 relPos = pivotBInW - pivotAInW; + + btVector3 normal[3]; + if (relPos.length2() > SIMD_EPSILON) + { + normal[0] = relPos.normalized(); + } + else + { + normal[0].setValue(btScalar(1.0),0,0); + } + + btPlaneSpace1(normal[0], normal[1], normal[2]); + + for (int i=0;i<3;i++) + { + new (&m_jac[i]) btJacobianEntry( + m_rbA.getCenterOfMassTransform().getBasis().transpose(), + m_rbB.getCenterOfMassTransform().getBasis().transpose(), + pivotAInW - m_rbA.getCenterOfMassPosition(), + pivotBInW - m_rbB.getCenterOfMassPosition(), + normal[i], + m_rbA.getInvInertiaDiagLocal(), + m_rbA.getInvMass(), + m_rbB.getInvInertiaDiagLocal(), + m_rbB.getInvMass()); + } + } + + btVector3 b1Axis1,b1Axis2,b1Axis3; + btVector3 b2Axis1,b2Axis2; + + b1Axis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(0); + b2Axis1 = getRigidBodyB().getCenterOfMassTransform().getBasis() * this->m_rbBFrame.getBasis().getColumn(0); + + btScalar swing1=btScalar(0.),swing2 = btScalar(0.); + + // Get Frame into world space + if (m_swingSpan1 >= btScalar(0.05f)) + { + b1Axis2 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(1); + swing1 = btAtan2Fast( b2Axis1.dot(b1Axis2),b2Axis1.dot(b1Axis1) ); + } + + if (m_swingSpan2 >= btScalar(0.05f)) + { + b1Axis3 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(2); + swing2 = btAtan2Fast( b2Axis1.dot(b1Axis3),b2Axis1.dot(b1Axis1) ); + } + + btScalar RMaxAngle1Sq = 1.0f / (m_swingSpan1*m_swingSpan1); + btScalar RMaxAngle2Sq = 1.0f / (m_swingSpan2*m_swingSpan2); + btScalar EllipseAngle = btFabs(swing1)* RMaxAngle1Sq + btFabs(swing2) * RMaxAngle2Sq; + + if (EllipseAngle > 1.0f) + { + m_swingCorrection = EllipseAngle-1.0f; + m_solveSwingLimit = true; + + // Calculate necessary axis & factors + m_swingAxis = b2Axis1.cross(b1Axis2* b2Axis1.dot(b1Axis2) + b1Axis3* b2Axis1.dot(b1Axis3)); + m_swingAxis.normalize(); + + btScalar swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f; + m_swingAxis *= swingAxisSign; + + m_kSwing = btScalar(1.) / (getRigidBodyA().computeAngularImpulseDenominator(m_swingAxis) + + getRigidBodyB().computeAngularImpulseDenominator(m_swingAxis)); + + } + + // Twist limits + if (m_twistSpan >= btScalar(0.)) + { + btVector3 b2Axis2 = getRigidBodyB().getCenterOfMassTransform().getBasis() * this->m_rbBFrame.getBasis().getColumn(1); + btQuaternion rotationArc = shortestArcQuat(b2Axis1,b1Axis1); + btVector3 TwistRef = quatRotate(rotationArc,b2Axis2); + btScalar twist = btAtan2Fast( TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2) ); + + btScalar lockedFreeFactor = (m_twistSpan > btScalar(0.05f)) ? m_limitSoftness : btScalar(0.); + if (twist <= -m_twistSpan*lockedFreeFactor) + { + m_twistCorrection = -(twist + m_twistSpan); + m_solveTwistLimit = true; + + m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f; + m_twistAxis.normalize(); + m_twistAxis *= -1.0f; + + m_kTwist = btScalar(1.) / (getRigidBodyA().computeAngularImpulseDenominator(m_twistAxis) + + getRigidBodyB().computeAngularImpulseDenominator(m_twistAxis)); + + } else + if (twist > m_twistSpan*lockedFreeFactor) + { + m_twistCorrection = (twist - m_twistSpan); + m_solveTwistLimit = true; + + m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f; + m_twistAxis.normalize(); + + m_kTwist = btScalar(1.) / (getRigidBodyA().computeAngularImpulseDenominator(m_twistAxis) + + getRigidBodyB().computeAngularImpulseDenominator(m_twistAxis)); + + } + } +} + +void btConeTwistConstraint::solveConstraint(btScalar timeStep) +{ + + btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin(); + btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin(); + + btScalar tau = btScalar(0.3); + btScalar damping = btScalar(1.); + + //linear part + if (!m_angularOnly) + { + btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); + btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); + + btVector3 vel1 = m_rbA.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = m_rbB.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + for (int i=0;i<3;i++) + { + const btVector3& normal = m_jac[i].m_linearJointAxis; + btScalar jacDiagABInv = btScalar(1.) / m_jac[i].getDiagonal(); + + btScalar rel_vel; + rel_vel = normal.dot(vel); + //positional error (zeroth order error) + btScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal + btScalar impulse = depth*tau/timeStep * jacDiagABInv - rel_vel * jacDiagABInv; + m_appliedImpulse += impulse; + btVector3 impulse_vector = normal * impulse; + m_rbA.applyImpulse(impulse_vector, pivotAInW - m_rbA.getCenterOfMassPosition()); + m_rbB.applyImpulse(-impulse_vector, pivotBInW - m_rbB.getCenterOfMassPosition()); + } + } + + { + ///solve angular part + const btVector3& angVelA = getRigidBodyA().getAngularVelocity(); + const btVector3& angVelB = getRigidBodyB().getAngularVelocity(); + + // solve swing limit + if (m_solveSwingLimit) + { + btScalar amplitude = ((angVelB - angVelA).dot( m_swingAxis )*m_relaxationFactor*m_relaxationFactor + m_swingCorrection*(btScalar(1.)/timeStep)*m_biasFactor); + btScalar impulseMag = amplitude * m_kSwing; + + // Clamp the accumulated impulse + btScalar temp = m_accSwingLimitImpulse; + m_accSwingLimitImpulse = btMax(m_accSwingLimitImpulse + impulseMag, 0.0f ); + impulseMag = m_accSwingLimitImpulse - temp; + + btVector3 impulse = m_swingAxis * impulseMag; + + m_rbA.applyTorqueImpulse(impulse); + m_rbB.applyTorqueImpulse(-impulse); + + } + + // solve twist limit + if (m_solveTwistLimit) + { + btScalar amplitude = ((angVelB - angVelA).dot( m_twistAxis )*m_relaxationFactor*m_relaxationFactor + m_twistCorrection*(btScalar(1.)/timeStep)*m_biasFactor ); + btScalar impulseMag = amplitude * m_kTwist; + + // Clamp the accumulated impulse + btScalar temp = m_accTwistLimitImpulse; + m_accTwistLimitImpulse = btMax(m_accTwistLimitImpulse + impulseMag, 0.0f ); + impulseMag = m_accTwistLimitImpulse - temp; + + btVector3 impulse = m_twistAxis * impulseMag; + + m_rbA.applyTorqueImpulse(impulse); + m_rbB.applyTorqueImpulse(-impulse); + + } + + } + +} + +void btConeTwistConstraint::updateRHS(btScalar timeStep) +{ + (void)timeStep; + +} diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h new file mode 100644 index 00000000000..874669c80b3 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h @@ -0,0 +1,123 @@ +/* +Bullet Continuous Collision Detection and Physics Library +btConeTwistConstraint is Copyright (c) 2007 Starbreeze Studios + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Written by: Marcus Hennix +*/ + + + +#ifndef CONETWISTCONSTRAINT_H +#define CONETWISTCONSTRAINT_H + +#include "../../LinearMath/btVector3.h" +#include "btJacobianEntry.h" +#include "btTypedConstraint.h" + +class btRigidBody; + + +///btConeTwistConstraint can be used to simulate ragdoll joints (upper arm, leg etc) +class btConeTwistConstraint : public btTypedConstraint +{ + btJacobianEntry m_jac[3]; //3 orthogonal linear constraints + + btTransform m_rbAFrame; + btTransform m_rbBFrame; + + btScalar m_limitSoftness; + btScalar m_biasFactor; + btScalar m_relaxationFactor; + + btScalar m_swingSpan1; + btScalar m_swingSpan2; + btScalar m_twistSpan; + + btVector3 m_swingAxis; + btVector3 m_twistAxis; + + btScalar m_kSwing; + btScalar m_kTwist; + + btScalar m_twistLimitSign; + btScalar m_swingCorrection; + btScalar m_twistCorrection; + + btScalar m_accSwingLimitImpulse; + btScalar m_accTwistLimitImpulse; + + bool m_angularOnly; + bool m_solveTwistLimit; + bool m_solveSwingLimit; + + +public: + + btConeTwistConstraint(btRigidBody& rbA,btRigidBody& rbB,const btTransform& rbAFrame, const btTransform& rbBFrame); + + btConeTwistConstraint(btRigidBody& rbA,const btTransform& rbAFrame); + + btConeTwistConstraint(); + + virtual void buildJacobian(); + + virtual void solveConstraint(btScalar timeStep); + + void updateRHS(btScalar timeStep); + + const btRigidBody& getRigidBodyA() const + { + return m_rbA; + } + const btRigidBody& getRigidBodyB() const + { + return m_rbB; + } + + void setAngularOnly(bool angularOnly) + { + m_angularOnly = angularOnly; + } + + void setLimit(btScalar _swingSpan1,btScalar _swingSpan2,btScalar _twistSpan, btScalar _softness = 0.8f, btScalar _biasFactor = 0.3f, btScalar _relaxationFactor = 1.0f) + { + m_swingSpan1 = _swingSpan1; + m_swingSpan2 = _swingSpan2; + m_twistSpan = _twistSpan; + + m_limitSoftness = _softness; + m_biasFactor = _biasFactor; + m_relaxationFactor = _relaxationFactor; + } + + const btTransform& getAFrame() { return m_rbAFrame; }; + const btTransform& getBFrame() { return m_rbBFrame; }; + + inline int getSolveTwistLimit() + { + return m_solveTwistLimit; + } + + inline int getSolveSwingLimit() + { + return m_solveTwistLimit; + } + + inline btScalar getTwistLimitSign() + { + return m_twistLimitSign; + } + +}; + +#endif //CONETWISTCONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h new file mode 100644 index 00000000000..7e8458c2c7b --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h @@ -0,0 +1,45 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef CONSTRAINT_SOLVER_H +#define CONSTRAINT_SOLVER_H + +#include "../../LinearMath/btScalar.h" + +class btPersistentManifold; +class btRigidBody; +class btCollisionObject; +class btTypedConstraint; +struct btContactSolverInfo; +struct btBroadphaseProxy; +class btIDebugDraw; +class btStackAlloc; + +/// btConstraintSolver provides solver interface +class btConstraintSolver +{ + +public: + + virtual ~btConstraintSolver() {} + + virtual btScalar solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints, const btContactSolverInfo& info,class btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc) = 0; + +}; + + + + +#endif //CONSTRAINT_SOLVER_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp new file mode 100644 index 00000000000..bb3fe832592 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp @@ -0,0 +1,417 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btContactConstraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "LinearMath/btVector3.h" +#include "btJacobianEntry.h" +#include "btContactSolverInfo.h" +#include "LinearMath/btMinMax.h" +#include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" + +#define ASSERT2 assert + +#define USE_INTERNAL_APPLY_IMPULSE 1 + + +//bilateral constraint between two dynamic objects +void resolveSingleBilateral(btRigidBody& body1, const btVector3& pos1, + btRigidBody& body2, const btVector3& pos2, + btScalar distance, const btVector3& normal,btScalar& impulse ,btScalar timeStep) +{ + (void)timeStep; + (void)distance; + + + btScalar normalLenSqr = normal.length2(); + ASSERT2(btFabs(normalLenSqr) < btScalar(1.1)); + if (normalLenSqr > btScalar(1.1)) + { + impulse = btScalar(0.); + return; + } + btVector3 rel_pos1 = pos1 - body1.getCenterOfMassPosition(); + btVector3 rel_pos2 = pos2 - body2.getCenterOfMassPosition(); + //this jacobian entry could be re-used for all iterations + + btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + + btJacobianEntry jac(body1.getCenterOfMassTransform().getBasis().transpose(), + body2.getCenterOfMassTransform().getBasis().transpose(), + rel_pos1,rel_pos2,normal,body1.getInvInertiaDiagLocal(),body1.getInvMass(), + body2.getInvInertiaDiagLocal(),body2.getInvMass()); + + btScalar jacDiagAB = jac.getDiagonal(); + btScalar jacDiagABInv = btScalar(1.) / jacDiagAB; + + btScalar rel_vel = jac.getRelativeVelocity( + body1.getLinearVelocity(), + body1.getCenterOfMassTransform().getBasis().transpose() * body1.getAngularVelocity(), + body2.getLinearVelocity(), + body2.getCenterOfMassTransform().getBasis().transpose() * body2.getAngularVelocity()); + btScalar a; + a=jacDiagABInv; + + + rel_vel = normal.dot(vel); + + //todo: move this into proper structure + btScalar contactDamping = btScalar(0.2); + +#ifdef ONLY_USE_LINEAR_MASS + btScalar massTerm = btScalar(1.) / (body1.getInvMass() + body2.getInvMass()); + impulse = - contactDamping * rel_vel * massTerm; +#else + btScalar velocityImpulse = -contactDamping * rel_vel * jacDiagABInv; + impulse = velocityImpulse; +#endif +} + + + +//response between two dynamic objects with friction +btScalar resolveSingleCollision( + btRigidBody& body1, + btRigidBody& body2, + btManifoldPoint& contactPoint, + const btContactSolverInfo& solverInfo) +{ + + const btVector3& pos1_ = contactPoint.getPositionWorldOnA(); + const btVector3& pos2_ = contactPoint.getPositionWorldOnB(); + const btVector3& normal = contactPoint.m_normalWorldOnB; + + //constant over all iterations + btVector3 rel_pos1 = pos1_ - body1.getCenterOfMassPosition(); + btVector3 rel_pos2 = pos2_ - body2.getCenterOfMassPosition(); + + btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + btScalar rel_vel; + rel_vel = normal.dot(vel); + + btScalar Kfps = btScalar(1.) / solverInfo.m_timeStep ; + + // btScalar damping = solverInfo.m_damping ; + btScalar Kerp = solverInfo.m_erp; + btScalar Kcor = Kerp *Kfps; + + btConstraintPersistentData* cpd = (btConstraintPersistentData*) contactPoint.m_userPersistentData; + assert(cpd); + btScalar distance = cpd->m_penetration; + btScalar positionalError = Kcor *-distance; + btScalar velocityError = cpd->m_restitution - rel_vel;// * damping; + + btScalar penetrationImpulse = positionalError * cpd->m_jacDiagABInv; + + btScalar velocityImpulse = velocityError * cpd->m_jacDiagABInv; + + btScalar normalImpulse = penetrationImpulse+velocityImpulse; + + // See Erin Catto's GDC 2006 paper: Clamp the accumulated impulse + btScalar oldNormalImpulse = cpd->m_appliedImpulse; + btScalar sum = oldNormalImpulse + normalImpulse; + cpd->m_appliedImpulse = btScalar(0.) > sum ? btScalar(0.): sum; + + normalImpulse = cpd->m_appliedImpulse - oldNormalImpulse; + +#ifdef USE_INTERNAL_APPLY_IMPULSE + if (body1.getInvMass()) + { + body1.internalApplyImpulse(contactPoint.m_normalWorldOnB*body1.getInvMass(),cpd->m_angularComponentA,normalImpulse); + } + if (body2.getInvMass()) + { + body2.internalApplyImpulse(contactPoint.m_normalWorldOnB*body2.getInvMass(),cpd->m_angularComponentB,-normalImpulse); + } +#else //USE_INTERNAL_APPLY_IMPULSE + body1.applyImpulse(normal*(normalImpulse), rel_pos1); + body2.applyImpulse(-normal*(normalImpulse), rel_pos2); +#endif //USE_INTERNAL_APPLY_IMPULSE + + return normalImpulse; +} + + +btScalar resolveSingleFriction( + btRigidBody& body1, + btRigidBody& body2, + btManifoldPoint& contactPoint, + const btContactSolverInfo& solverInfo) +{ + + (void)solverInfo; + + const btVector3& pos1 = contactPoint.getPositionWorldOnA(); + const btVector3& pos2 = contactPoint.getPositionWorldOnB(); + + btVector3 rel_pos1 = pos1 - body1.getCenterOfMassPosition(); + btVector3 rel_pos2 = pos2 - body2.getCenterOfMassPosition(); + + btConstraintPersistentData* cpd = (btConstraintPersistentData*) contactPoint.m_userPersistentData; + assert(cpd); + + btScalar combinedFriction = cpd->m_friction; + + btScalar limit = cpd->m_appliedImpulse * combinedFriction; + + if (cpd->m_appliedImpulse>btScalar(0.)) + //friction + { + //apply friction in the 2 tangential directions + + // 1st tangent + btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + btScalar j1,j2; + + { + + btScalar vrel = cpd->m_frictionWorldTangential0.dot(vel); + + // calculate j that moves us to zero relative velocity + j1 = -vrel * cpd->m_jacDiagABInvTangent0; + btScalar oldTangentImpulse = cpd->m_accumulatedTangentImpulse0; + cpd->m_accumulatedTangentImpulse0 = oldTangentImpulse + j1; + GEN_set_min(cpd->m_accumulatedTangentImpulse0, limit); + GEN_set_max(cpd->m_accumulatedTangentImpulse0, -limit); + j1 = cpd->m_accumulatedTangentImpulse0 - oldTangentImpulse; + + } + { + // 2nd tangent + + btScalar vrel = cpd->m_frictionWorldTangential1.dot(vel); + + // calculate j that moves us to zero relative velocity + j2 = -vrel * cpd->m_jacDiagABInvTangent1; + btScalar oldTangentImpulse = cpd->m_accumulatedTangentImpulse1; + cpd->m_accumulatedTangentImpulse1 = oldTangentImpulse + j2; + GEN_set_min(cpd->m_accumulatedTangentImpulse1, limit); + GEN_set_max(cpd->m_accumulatedTangentImpulse1, -limit); + j2 = cpd->m_accumulatedTangentImpulse1 - oldTangentImpulse; + } + +#ifdef USE_INTERNAL_APPLY_IMPULSE + if (body1.getInvMass()) + { + body1.internalApplyImpulse(cpd->m_frictionWorldTangential0*body1.getInvMass(),cpd->m_frictionAngularComponent0A,j1); + body1.internalApplyImpulse(cpd->m_frictionWorldTangential1*body1.getInvMass(),cpd->m_frictionAngularComponent1A,j2); + } + if (body2.getInvMass()) + { + body2.internalApplyImpulse(cpd->m_frictionWorldTangential0*body2.getInvMass(),cpd->m_frictionAngularComponent0B,-j1); + body2.internalApplyImpulse(cpd->m_frictionWorldTangential1*body2.getInvMass(),cpd->m_frictionAngularComponent1B,-j2); + } +#else //USE_INTERNAL_APPLY_IMPULSE + body1.applyImpulse((j1 * cpd->m_frictionWorldTangential0)+(j2 * cpd->m_frictionWorldTangential1), rel_pos1); + body2.applyImpulse((j1 * -cpd->m_frictionWorldTangential0)+(j2 * -cpd->m_frictionWorldTangential1), rel_pos2); +#endif //USE_INTERNAL_APPLY_IMPULSE + + + } + return cpd->m_appliedImpulse; +} + + +btScalar resolveSingleFrictionOriginal( + btRigidBody& body1, + btRigidBody& body2, + btManifoldPoint& contactPoint, + const btContactSolverInfo& solverInfo) +{ + + (void)solverInfo; + + const btVector3& pos1 = contactPoint.getPositionWorldOnA(); + const btVector3& pos2 = contactPoint.getPositionWorldOnB(); + + btVector3 rel_pos1 = pos1 - body1.getCenterOfMassPosition(); + btVector3 rel_pos2 = pos2 - body2.getCenterOfMassPosition(); + + btConstraintPersistentData* cpd = (btConstraintPersistentData*) contactPoint.m_userPersistentData; + assert(cpd); + + btScalar combinedFriction = cpd->m_friction; + + btScalar limit = cpd->m_appliedImpulse * combinedFriction; + //if (contactPoint.m_appliedImpulse>btScalar(0.)) + //friction + { + //apply friction in the 2 tangential directions + + { + // 1st tangent + btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + btScalar vrel = cpd->m_frictionWorldTangential0.dot(vel); + + // calculate j that moves us to zero relative velocity + btScalar j = -vrel * cpd->m_jacDiagABInvTangent0; + btScalar total = cpd->m_accumulatedTangentImpulse0 + j; + GEN_set_min(total, limit); + GEN_set_max(total, -limit); + j = total - cpd->m_accumulatedTangentImpulse0; + cpd->m_accumulatedTangentImpulse0 = total; + body1.applyImpulse(j * cpd->m_frictionWorldTangential0, rel_pos1); + body2.applyImpulse(j * -cpd->m_frictionWorldTangential0, rel_pos2); + } + + + { + // 2nd tangent + btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + btScalar vrel = cpd->m_frictionWorldTangential1.dot(vel); + + // calculate j that moves us to zero relative velocity + btScalar j = -vrel * cpd->m_jacDiagABInvTangent1; + btScalar total = cpd->m_accumulatedTangentImpulse1 + j; + GEN_set_min(total, limit); + GEN_set_max(total, -limit); + j = total - cpd->m_accumulatedTangentImpulse1; + cpd->m_accumulatedTangentImpulse1 = total; + body1.applyImpulse(j * cpd->m_frictionWorldTangential1, rel_pos1); + body2.applyImpulse(j * -cpd->m_frictionWorldTangential1, rel_pos2); + } + } + return cpd->m_appliedImpulse; +} + + +//velocity + friction +//response between two dynamic objects with friction +btScalar resolveSingleCollisionCombined( + btRigidBody& body1, + btRigidBody& body2, + btManifoldPoint& contactPoint, + const btContactSolverInfo& solverInfo) +{ + + const btVector3& pos1 = contactPoint.getPositionWorldOnA(); + const btVector3& pos2 = contactPoint.getPositionWorldOnB(); + const btVector3& normal = contactPoint.m_normalWorldOnB; + + btVector3 rel_pos1 = pos1 - body1.getCenterOfMassPosition(); + btVector3 rel_pos2 = pos2 - body2.getCenterOfMassPosition(); + + btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + btScalar rel_vel; + rel_vel = normal.dot(vel); + + btScalar Kfps = btScalar(1.) / solverInfo.m_timeStep ; + + //btScalar damping = solverInfo.m_damping ; + btScalar Kerp = solverInfo.m_erp; + btScalar Kcor = Kerp *Kfps; + + btConstraintPersistentData* cpd = (btConstraintPersistentData*) contactPoint.m_userPersistentData; + assert(cpd); + btScalar distance = cpd->m_penetration; + btScalar positionalError = Kcor *-distance; + btScalar velocityError = cpd->m_restitution - rel_vel;// * damping; + + btScalar penetrationImpulse = positionalError * cpd->m_jacDiagABInv; + + btScalar velocityImpulse = velocityError * cpd->m_jacDiagABInv; + + btScalar normalImpulse = penetrationImpulse+velocityImpulse; + + // See Erin Catto's GDC 2006 paper: Clamp the accumulated impulse + btScalar oldNormalImpulse = cpd->m_appliedImpulse; + btScalar sum = oldNormalImpulse + normalImpulse; + cpd->m_appliedImpulse = btScalar(0.) > sum ? btScalar(0.): sum; + + normalImpulse = cpd->m_appliedImpulse - oldNormalImpulse; + + +#ifdef USE_INTERNAL_APPLY_IMPULSE + if (body1.getInvMass()) + { + body1.internalApplyImpulse(contactPoint.m_normalWorldOnB*body1.getInvMass(),cpd->m_angularComponentA,normalImpulse); + } + if (body2.getInvMass()) + { + body2.internalApplyImpulse(contactPoint.m_normalWorldOnB*body2.getInvMass(),cpd->m_angularComponentB,-normalImpulse); + } +#else //USE_INTERNAL_APPLY_IMPULSE + body1.applyImpulse(normal*(normalImpulse), rel_pos1); + body2.applyImpulse(-normal*(normalImpulse), rel_pos2); +#endif //USE_INTERNAL_APPLY_IMPULSE + + { + //friction + btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + rel_vel = normal.dot(vel); + + + btVector3 lat_vel = vel - normal * rel_vel; + btScalar lat_rel_vel = lat_vel.length(); + + btScalar combinedFriction = cpd->m_friction; + + if (cpd->m_appliedImpulse > 0) + if (lat_rel_vel > SIMD_EPSILON) + { + lat_vel /= lat_rel_vel; + btVector3 temp1 = body1.getInvInertiaTensorWorld() * rel_pos1.cross(lat_vel); + btVector3 temp2 = body2.getInvInertiaTensorWorld() * rel_pos2.cross(lat_vel); + btScalar friction_impulse = lat_rel_vel / + (body1.getInvMass() + body2.getInvMass() + lat_vel.dot(temp1.cross(rel_pos1) + temp2.cross(rel_pos2))); + btScalar normal_impulse = cpd->m_appliedImpulse * combinedFriction; + + GEN_set_min(friction_impulse, normal_impulse); + GEN_set_max(friction_impulse, -normal_impulse); + body1.applyImpulse(lat_vel * -friction_impulse, rel_pos1); + body2.applyImpulse(lat_vel * friction_impulse, rel_pos2); + } + } + + + + return normalImpulse; +} + +btScalar resolveSingleFrictionEmpty( + btRigidBody& body1, + btRigidBody& body2, + btManifoldPoint& contactPoint, + const btContactSolverInfo& solverInfo) +{ + (void)contactPoint; + (void)body1; + (void)body2; + (void)solverInfo; + + + return btScalar(0.); +}; + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.h new file mode 100644 index 00000000000..0834deddeac --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.h @@ -0,0 +1,122 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef CONTACT_CONSTRAINT_H +#define CONTACT_CONSTRAINT_H + +//todo: make into a proper class working with the iterative constraint solver + +class btRigidBody; +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btScalar.h" +struct btContactSolverInfo; +class btManifoldPoint; + +enum { + DEFAULT_CONTACT_SOLVER_TYPE=0, + CONTACT_SOLVER_TYPE1, + CONTACT_SOLVER_TYPE2, + USER_CONTACT_SOLVER_TYPE1, + MAX_CONTACT_SOLVER_TYPES +}; + + +typedef btScalar (*ContactSolverFunc)(btRigidBody& body1, + btRigidBody& body2, + class btManifoldPoint& contactPoint, + const btContactSolverInfo& info); + +///stores some extra information to each contact point. It is not in the contact point, because that want to keep the collision detection independent from the constraint solver. +struct btConstraintPersistentData +{ + inline btConstraintPersistentData() + :m_appliedImpulse(btScalar(0.)), + m_prevAppliedImpulse(btScalar(0.)), + m_accumulatedTangentImpulse0(btScalar(0.)), + m_accumulatedTangentImpulse1(btScalar(0.)), + m_jacDiagABInv(btScalar(0.)), + m_persistentLifeTime(0), + m_restitution(btScalar(0.)), + m_friction(btScalar(0.)), + m_penetration(btScalar(0.)), + m_contactSolverFunc(0), + m_frictionSolverFunc(0) + { + } + + + /// total applied impulse during most recent frame + btScalar m_appliedImpulse; + btScalar m_prevAppliedImpulse; + btScalar m_accumulatedTangentImpulse0; + btScalar m_accumulatedTangentImpulse1; + + btScalar m_jacDiagABInv; + btScalar m_jacDiagABInvTangent0; + btScalar m_jacDiagABInvTangent1; + int m_persistentLifeTime; + btScalar m_restitution; + btScalar m_friction; + btScalar m_penetration; + btVector3 m_frictionWorldTangential0; + btVector3 m_frictionWorldTangential1; + + btVector3 m_frictionAngularComponent0A; + btVector3 m_frictionAngularComponent0B; + btVector3 m_frictionAngularComponent1A; + btVector3 m_frictionAngularComponent1B; + + //some data doesn't need to be persistent over frames: todo: clean/reuse this + btVector3 m_angularComponentA; + btVector3 m_angularComponentB; + + ContactSolverFunc m_contactSolverFunc; + ContactSolverFunc m_frictionSolverFunc; + +}; + +///bilateral constraint between two dynamic objects +///positive distance = separation, negative distance = penetration +void resolveSingleBilateral(btRigidBody& body1, const btVector3& pos1, + btRigidBody& body2, const btVector3& pos2, + btScalar distance, const btVector3& normal,btScalar& impulse ,btScalar timeStep); + + +///contact constraint resolution: +///calculate and apply impulse to satisfy non-penetration and non-negative relative velocity constraint +///positive distance = separation, negative distance = penetration +btScalar resolveSingleCollision( + btRigidBody& body1, + btRigidBody& body2, + btManifoldPoint& contactPoint, + const btContactSolverInfo& info); + +btScalar resolveSingleFriction( + btRigidBody& body1, + btRigidBody& body2, + btManifoldPoint& contactPoint, + const btContactSolverInfo& solverInfo + ); + + + +btScalar resolveSingleCollisionCombined( + btRigidBody& body1, + btRigidBody& body2, + btManifoldPoint& contactPoint, + const btContactSolverInfo& solverInfo + ); + +#endif //CONTACT_CONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h new file mode 100644 index 00000000000..c3c73e300f4 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h @@ -0,0 +1,47 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef CONTACT_SOLVER_INFO +#define CONTACT_SOLVER_INFO + + +struct btContactSolverInfo +{ + + inline btContactSolverInfo() + { + m_tau = btScalar(0.6); + m_damping = btScalar(1.0); + m_friction = btScalar(0.3); + m_restitution = btScalar(0.); + m_maxErrorReduction = btScalar(20.); + m_numIterations = 10; + m_erp = btScalar(0.4); + m_sor = btScalar(1.3); + } + + btScalar m_tau; + btScalar m_damping; + btScalar m_friction; + btScalar m_timeStep; + btScalar m_restitution; + int m_numIterations; + btScalar m_maxErrorReduction; + btScalar m_sor; + btScalar m_erp; + +}; + +#endif //CONTACT_SOLVER_INFO diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp new file mode 100644 index 00000000000..747d10d1f8b --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp @@ -0,0 +1,389 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btGeneric6DofConstraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "LinearMath/btTransformUtil.h" +#include + +static const btScalar kSign[] = { btScalar(1.0), btScalar(-1.0), btScalar(1.0) }; +static const int kAxisA[] = { 1, 0, 0 }; +static const int kAxisB[] = { 2, 2, 1 }; +#define GENERIC_D6_DISABLE_WARMSTARTING 1 + +btGeneric6DofConstraint::btGeneric6DofConstraint() +{ +} + +btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB) +: btTypedConstraint(rbA, rbB) +, m_frameInA(frameInA) +, m_frameInB(frameInB) +{ + //free means upper < lower, + //locked means upper == lower + //limited means upper > lower + //so start all locked + for (int i=0; i<6;++i) + { + m_lowerLimit[i] = btScalar(0.0); + m_upperLimit[i] = btScalar(0.0); + m_accumulatedImpulse[i] = btScalar(0.0); + } + +} + + +void btGeneric6DofConstraint::buildJacobian() +{ + btVector3 localNormalInA(0,0,0); + + const btVector3& pivotInA = m_frameInA.getOrigin(); + const btVector3& pivotInB = m_frameInB.getOrigin(); + + btVector3 pivotAInW = m_rbA.getCenterOfMassTransform() * m_frameInA.getOrigin(); + btVector3 pivotBInW = m_rbB.getCenterOfMassTransform() * m_frameInB.getOrigin(); + + btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); + btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); + + int i; + //linear part + for (i=0;i<3;i++) + { + if (isLimited(i)) + { + localNormalInA[i] = 1; + btVector3 normalWorld = m_rbA.getCenterOfMassTransform().getBasis() * localNormalInA; + + + // Create linear atom + new (&m_jacLinear[i]) btJacobianEntry( + m_rbA.getCenterOfMassTransform().getBasis().transpose(), + m_rbB.getCenterOfMassTransform().getBasis().transpose(), + m_rbA.getCenterOfMassTransform()*pivotInA - m_rbA.getCenterOfMassPosition(), + m_rbB.getCenterOfMassTransform()*pivotInB - m_rbB.getCenterOfMassPosition(), + normalWorld, + m_rbA.getInvInertiaDiagLocal(), + m_rbA.getInvMass(), + m_rbB.getInvInertiaDiagLocal(), + m_rbB.getInvMass()); + + //optionally disable warmstarting +#ifdef GENERIC_D6_DISABLE_WARMSTARTING + m_accumulatedImpulse[i] = btScalar(0.); +#endif //GENERIC_D6_DISABLE_WARMSTARTING + + // Apply accumulated impulse + btVector3 impulse_vector = m_accumulatedImpulse[i] * normalWorld; + + m_rbA.applyImpulse( impulse_vector, rel_pos1); + m_rbB.applyImpulse(-impulse_vector, rel_pos2); + + localNormalInA[i] = 0; + } + } + + // angular part + for (i=0;i<3;i++) + { + if (isLimited(i+3)) + { + btVector3 axisA = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn( kAxisA[i] ); + btVector3 axisB = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn( kAxisB[i] ); + + // Dirk: This is IMO mathematically the correct way, but we should consider axisA and axisB being near parallel maybe + btVector3 axis = kSign[i] * axisA.cross(axisB); + + // Create angular atom + new (&m_jacAng[i]) btJacobianEntry(axis, + m_rbA.getCenterOfMassTransform().getBasis().transpose(), + m_rbB.getCenterOfMassTransform().getBasis().transpose(), + m_rbA.getInvInertiaDiagLocal(), + m_rbB.getInvInertiaDiagLocal()); + +#ifdef GENERIC_D6_DISABLE_WARMSTARTING + m_accumulatedImpulse[i + 3] = btScalar(0.); +#endif //GENERIC_D6_DISABLE_WARMSTARTING + + // Apply accumulated impulse + btVector3 impulse_vector = m_accumulatedImpulse[i + 3] * axis; + + m_rbA.applyTorqueImpulse( impulse_vector); + m_rbB.applyTorqueImpulse(-impulse_vector); + } + } +} + +btScalar getMatrixElem(const btMatrix3x3& mat,int index) +{ + int row = index%3; + int col = index / 3; + return mat[row][col]; +} + +///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html +bool MatrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz) +{ + // rot = cy*cz -cy*sz sy + // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx + // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy + +/// 0..8 + + if (getMatrixElem(mat,2) < btScalar(1.0)) + { + if (getMatrixElem(mat,2) > btScalar(-1.0)) + { + xyz[0] = btAtan2(-getMatrixElem(mat,5),getMatrixElem(mat,8)); + xyz[1] = btAsin(getMatrixElem(mat,2)); + xyz[2] = btAtan2(-getMatrixElem(mat,1),getMatrixElem(mat,0)); + return true; + } + else + { + // WARNING. Not unique. XA - ZA = -atan2(r10,r11) + xyz[0] = -btAtan2(getMatrixElem(mat,3),getMatrixElem(mat,4)); + xyz[1] = -SIMD_HALF_PI; + xyz[2] = btScalar(0.0); + return false; + } + } + else + { + // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11) + xyz[0] = btAtan2(getMatrixElem(mat,3),getMatrixElem(mat,4)); + xyz[1] = SIMD_HALF_PI; + xyz[2] = 0.0; + + } + + return false; +} + + +void btGeneric6DofConstraint::solveConstraint(btScalar timeStep) +{ + btScalar tau = btScalar(0.1); + btScalar damping = btScalar(1.0); + + btVector3 pivotAInW = m_rbA.getCenterOfMassTransform() * m_frameInA.getOrigin(); + btVector3 pivotBInW = m_rbB.getCenterOfMassTransform() * m_frameInB.getOrigin(); + + btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); + btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); + + btVector3 localNormalInA(0,0,0); + int i; + + // linear + for (i=0;i<3;i++) + { + if (isLimited(i)) + { + btVector3 angvelA = m_rbA.getCenterOfMassTransform().getBasis().transpose() * m_rbA.getAngularVelocity(); + btVector3 angvelB = m_rbB.getCenterOfMassTransform().getBasis().transpose() * m_rbB.getAngularVelocity(); + + localNormalInA.setValue(0,0,0); + localNormalInA[i] = 1; + btVector3 normalWorld = m_rbA.getCenterOfMassTransform().getBasis() * localNormalInA; + + btScalar jacDiagABInv = btScalar(1.) / m_jacLinear[i].getDiagonal(); + + //velocity error (first order error) + btScalar rel_vel = m_jacLinear[i].getRelativeVelocity(m_rbA.getLinearVelocity(),angvelA, + m_rbB.getLinearVelocity(),angvelB); + + //positional error (zeroth order error) + btScalar depth = -(pivotAInW - pivotBInW).dot(normalWorld); + btScalar lo = btScalar(-1e30); + btScalar hi = btScalar(1e30); + + //handle the limits + if (m_lowerLimit[i] < m_upperLimit[i]) + { + { + if (depth > m_upperLimit[i]) + { + depth -= m_upperLimit[i]; + lo = btScalar(0.); + + } else + { + if (depth < m_lowerLimit[i]) + { + depth -= m_lowerLimit[i]; + hi = btScalar(0.); + } else + { + continue; + } + } + } + } + + btScalar normalImpulse= (tau*depth/timeStep - damping*rel_vel) * jacDiagABInv; + btScalar oldNormalImpulse = m_accumulatedImpulse[i]; + btScalar sum = oldNormalImpulse + normalImpulse; + m_accumulatedImpulse[i] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum; + normalImpulse = m_accumulatedImpulse[i] - oldNormalImpulse; + + btVector3 impulse_vector = normalWorld * normalImpulse; + m_rbA.applyImpulse( impulse_vector, rel_pos1); + m_rbB.applyImpulse(-impulse_vector, rel_pos2); + + localNormalInA[i] = 0; + } + } + + btVector3 axis; + btScalar angle; + btTransform frameAWorld = m_rbA.getCenterOfMassTransform() * m_frameInA; + btTransform frameBWorld = m_rbB.getCenterOfMassTransform() * m_frameInB; + + btTransformUtil::calculateDiffAxisAngle(frameAWorld,frameBWorld,axis,angle); + btQuaternion diff(axis,angle); + btMatrix3x3 diffMat (diff); + btVector3 xyz; + ///this is not perfect, we can first check which axis are limited, and choose a more appropriate order + MatrixToEulerXYZ(diffMat,xyz); + + // angular + for (i=0;i<3;i++) + { + if (isLimited(i+3)) + { + btVector3 angvelA = m_rbA.getCenterOfMassTransform().getBasis().transpose() * m_rbA.getAngularVelocity(); + btVector3 angvelB = m_rbB.getCenterOfMassTransform().getBasis().transpose() * m_rbB.getAngularVelocity(); + + btScalar jacDiagABInv = btScalar(1.) / m_jacAng[i].getDiagonal(); + + //velocity error (first order error) + btScalar rel_vel = m_jacAng[i].getRelativeVelocity(m_rbA.getLinearVelocity(),angvelA, + m_rbB.getLinearVelocity(),angvelB); + + //positional error (zeroth order error) + btVector3 axisA = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn( kAxisA[i] ); + btVector3 axisB = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn( kAxisB[i] ); + + btScalar rel_pos = kSign[i] * axisA.dot(axisB); + + btScalar lo = btScalar(-1e30); + btScalar hi = btScalar(1e30); + + //handle the twist limit + if (m_lowerLimit[i+3] < m_upperLimit[i+3]) + { + //clamp the values + btScalar loLimit = m_lowerLimit[i+3] > -3.1415 ? m_lowerLimit[i+3] : btScalar(-1e30); + btScalar hiLimit = m_upperLimit[i+3] < 3.1415 ? m_upperLimit[i+3] : btScalar(1e30); + + btScalar projAngle = btScalar(-1.)*xyz[i]; + + if (projAngle < loLimit) + { + hi = btScalar(0.); + rel_pos = (loLimit - projAngle); + } else + { + if (projAngle > hiLimit) + { + lo = btScalar(0.); + rel_pos = (hiLimit - projAngle); + } else + { + continue; + } + } + } + + //impulse + + btScalar normalImpulse= -(tau*rel_pos/timeStep + damping*rel_vel) * jacDiagABInv; + btScalar oldNormalImpulse = m_accumulatedImpulse[i+3]; + btScalar sum = oldNormalImpulse + normalImpulse; + m_accumulatedImpulse[i+3] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum; + normalImpulse = m_accumulatedImpulse[i+3] - oldNormalImpulse; + + // Dirk: Not needed - we could actually project onto Jacobian entry here (same as above) + btVector3 axis = kSign[i] * axisA.cross(axisB); + btVector3 impulse_vector = axis * normalImpulse; + + m_rbA.applyTorqueImpulse( impulse_vector); + m_rbB.applyTorqueImpulse(-impulse_vector); + } + } +} + +void btGeneric6DofConstraint::updateRHS(btScalar timeStep) +{ + (void)timeStep; + +} + +btScalar btGeneric6DofConstraint::computeAngle(int axis) const + { + btScalar angle = btScalar(0.f); + + switch (axis) + { + case 0: + { + btVector3 v1 = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn(1); + btVector3 v2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(1); + btVector3 w2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(2); + + btScalar s = v1.dot(w2); + btScalar c = v1.dot(v2); + + angle = btAtan2( s, c ); + } + break; + + case 1: + { + btVector3 w1 = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn(2); + btVector3 w2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(2); + btVector3 u2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(0); + + btScalar s = w1.dot(u2); + btScalar c = w1.dot(w2); + + angle = btAtan2( s, c ); + } + break; + + case 2: + { + btVector3 u1 = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn(0); + btVector3 u2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(0); + btVector3 v2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(1); + + btScalar s = u1.dot(v2); + btScalar c = u1.dot(u2); + + angle = btAtan2( s, c ); + } + break; + default: + btAssert ( 0 ) ; + + break ; + } + + return angle; + } + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h new file mode 100644 index 00000000000..b114e54fa69 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h @@ -0,0 +1,120 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef GENERIC_6DOF_CONSTRAINT_H +#define GENERIC_6DOF_CONSTRAINT_H + +#include "../../LinearMath/btVector3.h" +#include "btJacobianEntry.h" +#include "btTypedConstraint.h" + +class btRigidBody; + + + +/// btGeneric6DofConstraint between two rigidbodies each with a pivotpoint that descibes the axis location in local space +/// btGeneric6DofConstraint can leave any of the 6 degree of freedom 'free' or 'locked' +/// Work in progress (is still a Hinge actually) +class btGeneric6DofConstraint : public btTypedConstraint +{ + btJacobianEntry m_jacLinear[3]; // 3 orthogonal linear constraints + btJacobianEntry m_jacAng[3]; // 3 orthogonal angular constraints + + btTransform m_frameInA; // the constraint space w.r.t body A + btTransform m_frameInB; // the constraint space w.r.t body B + + btScalar m_lowerLimit[6]; // the constraint lower limits + btScalar m_upperLimit[6]; // the constraint upper limits + + btScalar m_accumulatedImpulse[6]; + + btGeneric6DofConstraint& operator=(btGeneric6DofConstraint& other) + { + btAssert(0); + (void) other; + return *this; + } + +public: + btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ); + + btGeneric6DofConstraint(); + + + virtual void buildJacobian(); + + virtual void solveConstraint(btScalar timeStep); + + void updateRHS(btScalar timeStep); + + btScalar computeAngle(int axis) const; + + void setLinearLowerLimit(const btVector3& linearLower) + { + m_lowerLimit[0] = linearLower.getX(); + m_lowerLimit[1] = linearLower.getY(); + m_lowerLimit[2] = linearLower.getZ(); + } + + void setLinearUpperLimit(const btVector3& linearUpper) + { + m_upperLimit[0] = linearUpper.getX(); + m_upperLimit[1] = linearUpper.getY(); + m_upperLimit[2] = linearUpper.getZ(); + } + + void setAngularLowerLimit(const btVector3& angularLower) + { + m_lowerLimit[3] = angularLower.getX(); + m_lowerLimit[4] = angularLower.getY(); + m_lowerLimit[5] = angularLower.getZ(); + } + + void setAngularUpperLimit(const btVector3& angularUpper) + { + m_upperLimit[3] = angularUpper.getX(); + m_upperLimit[4] = angularUpper.getY(); + m_upperLimit[5] = angularUpper.getZ(); + } + + //first 3 are linear, next 3 are angular + void SetLimit(int axis, btScalar lo, btScalar hi) + { + m_lowerLimit[axis] = lo; + m_upperLimit[axis] = hi; + } + + //free means upper < lower, + //locked means upper == lower + //limited means upper > lower + //limitIndex: first 3 are linear, next 3 are angular + bool isLimited(int limitIndex) + { + return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]); + } + + const btRigidBody& getRigidBodyA() const + { + return m_rbA; + } + const btRigidBody& getRigidBodyB() const + { + return m_rbB; + } + + +}; + +#endif //GENERIC_6DOF_CONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp new file mode 100644 index 00000000000..27e30987549 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp @@ -0,0 +1,229 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btHingeConstraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "LinearMath/btTransformUtil.h" +#include + +btHingeConstraint::btHingeConstraint(): +m_enableAngularMotor(false) +{ +} + +btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB, + btVector3& axisInA,btVector3& axisInB) +:btTypedConstraint(rbA,rbB),m_pivotInA(pivotInA),m_pivotInB(pivotInB), +m_axisInA(axisInA), +m_axisInB(-axisInB), +m_angularOnly(false), +m_enableAngularMotor(false) +{ + +} + + +btHingeConstraint::btHingeConstraint(btRigidBody& rbA,const btVector3& pivotInA,btVector3& axisInA) +:btTypedConstraint(rbA),m_pivotInA(pivotInA),m_pivotInB(rbA.getCenterOfMassTransform()(pivotInA)), +m_axisInA(axisInA), +//fixed axis in worldspace +m_axisInB(rbA.getCenterOfMassTransform().getBasis() * -axisInA), +m_angularOnly(false), +m_enableAngularMotor(false) +{ + +} + +void btHingeConstraint::buildJacobian() +{ + m_appliedImpulse = btScalar(0.); + + btVector3 normal(0,0,0); + + if (!m_angularOnly) + { + for (int i=0;i<3;i++) + { + normal[i] = 1; + new (&m_jac[i]) btJacobianEntry( + m_rbA.getCenterOfMassTransform().getBasis().transpose(), + m_rbB.getCenterOfMassTransform().getBasis().transpose(), + m_rbA.getCenterOfMassTransform()*m_pivotInA - m_rbA.getCenterOfMassPosition(), + m_rbB.getCenterOfMassTransform()*m_pivotInB - m_rbB.getCenterOfMassPosition(), + normal, + m_rbA.getInvInertiaDiagLocal(), + m_rbA.getInvMass(), + m_rbB.getInvInertiaDiagLocal(), + m_rbB.getInvMass()); + normal[i] = 0; + } + } + + //calculate two perpendicular jointAxis, orthogonal to hingeAxis + //these two jointAxis require equal angular velocities for both bodies + + //this is unused for now, it's a todo + btVector3 jointAxis0local; + btVector3 jointAxis1local; + + btPlaneSpace1(m_axisInA,jointAxis0local,jointAxis1local); + + getRigidBodyA().getCenterOfMassTransform().getBasis() * m_axisInA; + btVector3 jointAxis0 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis0local; + btVector3 jointAxis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis1local; + btVector3 hingeAxisWorld = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_axisInA; + + new (&m_jacAng[0]) btJacobianEntry(jointAxis0, + m_rbA.getCenterOfMassTransform().getBasis().transpose(), + m_rbB.getCenterOfMassTransform().getBasis().transpose(), + m_rbA.getInvInertiaDiagLocal(), + m_rbB.getInvInertiaDiagLocal()); + + new (&m_jacAng[1]) btJacobianEntry(jointAxis1, + m_rbA.getCenterOfMassTransform().getBasis().transpose(), + m_rbB.getCenterOfMassTransform().getBasis().transpose(), + m_rbA.getInvInertiaDiagLocal(), + m_rbB.getInvInertiaDiagLocal()); + + new (&m_jacAng[2]) btJacobianEntry(hingeAxisWorld, + m_rbA.getCenterOfMassTransform().getBasis().transpose(), + m_rbB.getCenterOfMassTransform().getBasis().transpose(), + m_rbA.getInvInertiaDiagLocal(), + m_rbB.getInvInertiaDiagLocal()); + + + +} + +void btHingeConstraint::solveConstraint(btScalar timeStep) +{ + + btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_pivotInA; + btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_pivotInB; + + btVector3 normal(0,0,0); + btScalar tau = btScalar(0.3); + btScalar damping = btScalar(1.); + +//linear part + if (!m_angularOnly) + { + for (int i=0;i<3;i++) + { + normal[i] = 1; + btScalar jacDiagABInv = btScalar(1.) / m_jac[i].getDiagonal(); + + btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); + btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); + + btVector3 vel1 = m_rbA.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = m_rbB.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + btScalar rel_vel; + rel_vel = normal.dot(vel); + //positional error (zeroth order error) + btScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal + btScalar impulse = depth*tau/timeStep * jacDiagABInv - damping * rel_vel * jacDiagABInv * damping; + m_appliedImpulse += impulse; + btVector3 impulse_vector = normal * impulse; + m_rbA.applyImpulse(impulse_vector, pivotAInW - m_rbA.getCenterOfMassPosition()); + m_rbB.applyImpulse(-impulse_vector, pivotBInW - m_rbB.getCenterOfMassPosition()); + + normal[i] = 0; + } + } + + + { + ///solve angular part + + // get axes in world space + btVector3 axisA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_axisInA; + btVector3 axisB = getRigidBodyB().getCenterOfMassTransform().getBasis() * m_axisInB; + + const btVector3& angVelA = getRigidBodyA().getAngularVelocity(); + const btVector3& angVelB = getRigidBodyB().getAngularVelocity(); + + btVector3 angVelAroundHingeAxisA = axisA * axisA.dot(angVelA); + btVector3 angVelAroundHingeAxisB = axisB * axisB.dot(angVelB); + + btVector3 angAorthog = angVelA - angVelAroundHingeAxisA; + btVector3 angBorthog = angVelB - angVelAroundHingeAxisB; + btVector3 velrelOrthog = angAorthog-angBorthog; + { + //solve orthogonal angular velocity correction + btScalar relaxation = btScalar(1.); + btScalar len = velrelOrthog.length(); + if (len > btScalar(0.00001)) + { + btVector3 normal = velrelOrthog.normalized(); + btScalar denom = getRigidBodyA().computeAngularImpulseDenominator(normal) + + getRigidBodyB().computeAngularImpulseDenominator(normal); + // scale for mass and relaxation + //todo: expose this 0.9 factor to developer + velrelOrthog *= (btScalar(1.)/denom) * btScalar(0.9); + } + + //solve angular positional correction + btVector3 angularError = -axisA.cross(axisB) *(btScalar(1.)/timeStep); + btScalar len2 = angularError.length(); + if (len2>btScalar(0.00001)) + { + btVector3 normal2 = angularError.normalized(); + btScalar denom2 = getRigidBodyA().computeAngularImpulseDenominator(normal2) + + getRigidBodyB().computeAngularImpulseDenominator(normal2); + angularError *= (btScalar(1.)/denom2) * relaxation; + } + + m_rbA.applyTorqueImpulse(-velrelOrthog+angularError); + m_rbB.applyTorqueImpulse(velrelOrthog-angularError); + } + + //apply motor + if (m_enableAngularMotor) + { + //todo: add limits too + btVector3 angularLimit(0,0,0); + + btVector3 velrel = angVelAroundHingeAxisA - angVelAroundHingeAxisB; + btScalar projRelVel = velrel.dot(axisA); + + btScalar desiredMotorVel = m_motorTargetVelocity; + btScalar motor_relvel = desiredMotorVel - projRelVel; + + btScalar denom3 = getRigidBodyA().computeAngularImpulseDenominator(axisA) + + getRigidBodyB().computeAngularImpulseDenominator(axisA); + + btScalar unclippedMotorImpulse = (btScalar(1.)/denom3) * motor_relvel;; + //todo: should clip against accumulated impulse + btScalar clippedMotorImpulse = unclippedMotorImpulse > m_maxMotorImpulse ? m_maxMotorImpulse : unclippedMotorImpulse; + clippedMotorImpulse = clippedMotorImpulse < -m_maxMotorImpulse ? -m_maxMotorImpulse : clippedMotorImpulse; + btVector3 motorImp = clippedMotorImpulse * axisA; + + m_rbA.applyTorqueImpulse(motorImp+angularLimit); + m_rbB.applyTorqueImpulse(-motorImp-angularLimit); + + } + } + +} + +void btHingeConstraint::updateRHS(btScalar timeStep) +{ + (void)timeStep; + +} + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h new file mode 100644 index 00000000000..5c1ceafbc5b --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h @@ -0,0 +1,81 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef HINGECONSTRAINT_H +#define HINGECONSTRAINT_H + +#include "../../LinearMath/btVector3.h" +#include "btJacobianEntry.h" +#include "btTypedConstraint.h" + +class btRigidBody; + + +/// hinge constraint between two rigidbodies each with a pivotpoint that descibes the axis location in local space +/// axis defines the orientation of the hinge axis +class btHingeConstraint : public btTypedConstraint +{ + btJacobianEntry m_jac[3]; //3 orthogonal linear constraints + btJacobianEntry m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor + + btVector3 m_pivotInA; + btVector3 m_pivotInB; + btVector3 m_axisInA; + btVector3 m_axisInB; + + bool m_angularOnly; + + btScalar m_motorTargetVelocity; + btScalar m_maxMotorImpulse; + bool m_enableAngularMotor; + +public: + + btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB,btVector3& axisInA,btVector3& axisInB); + + btHingeConstraint(btRigidBody& rbA,const btVector3& pivotInA,btVector3& axisInA); + + btHingeConstraint(); + + virtual void buildJacobian(); + + virtual void solveConstraint(btScalar timeStep); + + void updateRHS(btScalar timeStep); + + const btRigidBody& getRigidBodyA() const + { + return m_rbA; + } + const btRigidBody& getRigidBodyB() const + { + return m_rbB; + } + + void setAngularOnly(bool angularOnly) + { + m_angularOnly = angularOnly; + } + + void enableAngularMotor(bool enableMotor,btScalar targetVelocity,btScalar maxMotorImpulse) + { + m_enableAngularMotor = enableMotor; + m_motorTargetVelocity = targetVelocity; + m_maxMotorImpulse = maxMotorImpulse; + } + +}; + +#endif //HINGECONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h new file mode 100644 index 00000000000..aae3ed0373f --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h @@ -0,0 +1,156 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef JACOBIAN_ENTRY_H +#define JACOBIAN_ENTRY_H + +#include "../../LinearMath/btVector3.h" +#include "../Dynamics/btRigidBody.h" + + +//notes: +// Another memory optimization would be to store m_1MinvJt in the remaining 3 w components +// which makes the btJacobianEntry memory layout 16 bytes +// if you only are interested in angular part, just feed massInvA and massInvB zero + +/// Jacobian entry is an abstraction that allows to describe constraints +/// it can be used in combination with a constraint solver +/// Can be used to relate the effect of an impulse to the constraint error +class btJacobianEntry +{ +public: + btJacobianEntry() {}; + //constraint between two different rigidbodies + btJacobianEntry( + const btMatrix3x3& world2A, + const btMatrix3x3& world2B, + const btVector3& rel_pos1,const btVector3& rel_pos2, + const btVector3& jointAxis, + const btVector3& inertiaInvA, + const btScalar massInvA, + const btVector3& inertiaInvB, + const btScalar massInvB) + :m_linearJointAxis(jointAxis) + { + m_aJ = world2A*(rel_pos1.cross(m_linearJointAxis)); + m_bJ = world2B*(rel_pos2.cross(-m_linearJointAxis)); + m_0MinvJt = inertiaInvA * m_aJ; + m_1MinvJt = inertiaInvB * m_bJ; + m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ); + + btAssert(m_Adiag > btScalar(0.0)); + } + + //angular constraint between two different rigidbodies + btJacobianEntry(const btVector3& jointAxis, + const btMatrix3x3& world2A, + const btMatrix3x3& world2B, + const btVector3& inertiaInvA, + const btVector3& inertiaInvB) + :m_linearJointAxis(btVector3(btScalar(0.),btScalar(0.),btScalar(0.))) + { + m_aJ= world2A*jointAxis; + m_bJ = world2B*-jointAxis; + m_0MinvJt = inertiaInvA * m_aJ; + m_1MinvJt = inertiaInvB * m_bJ; + m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ); + + btAssert(m_Adiag > btScalar(0.0)); + } + + //angular constraint between two different rigidbodies + btJacobianEntry(const btVector3& axisInA, + const btVector3& axisInB, + const btVector3& inertiaInvA, + const btVector3& inertiaInvB) + : m_linearJointAxis(btVector3(btScalar(0.),btScalar(0.),btScalar(0.))) + , m_aJ(axisInA) + , m_bJ(-axisInB) + { + m_0MinvJt = inertiaInvA * m_aJ; + m_1MinvJt = inertiaInvB * m_bJ; + m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ); + + btAssert(m_Adiag > btScalar(0.0)); + } + + //constraint on one rigidbody + btJacobianEntry( + const btMatrix3x3& world2A, + const btVector3& rel_pos1,const btVector3& rel_pos2, + const btVector3& jointAxis, + const btVector3& inertiaInvA, + const btScalar massInvA) + :m_linearJointAxis(jointAxis) + { + m_aJ= world2A*(rel_pos1.cross(jointAxis)); + m_bJ = world2A*(rel_pos2.cross(-jointAxis)); + m_0MinvJt = inertiaInvA * m_aJ; + m_1MinvJt = btVector3(btScalar(0.),btScalar(0.),btScalar(0.)); + m_Adiag = massInvA + m_0MinvJt.dot(m_aJ); + + btAssert(m_Adiag > btScalar(0.0)); + } + + btScalar getDiagonal() const { return m_Adiag; } + + // for two constraints on the same rigidbody (for example vehicle friction) + btScalar getNonDiagonal(const btJacobianEntry& jacB, const btScalar massInvA) const + { + const btJacobianEntry& jacA = *this; + btScalar lin = massInvA * jacA.m_linearJointAxis.dot(jacB.m_linearJointAxis); + btScalar ang = jacA.m_0MinvJt.dot(jacB.m_aJ); + return lin + ang; + } + + + + // for two constraints on sharing two same rigidbodies (for example two contact points between two rigidbodies) + btScalar getNonDiagonal(const btJacobianEntry& jacB,const btScalar massInvA,const btScalar massInvB) const + { + const btJacobianEntry& jacA = *this; + btVector3 lin = jacA.m_linearJointAxis * jacB.m_linearJointAxis; + btVector3 ang0 = jacA.m_0MinvJt * jacB.m_aJ; + btVector3 ang1 = jacA.m_1MinvJt * jacB.m_bJ; + btVector3 lin0 = massInvA * lin ; + btVector3 lin1 = massInvB * lin; + btVector3 sum = ang0+ang1+lin0+lin1; + return sum[0]+sum[1]+sum[2]; + } + + btScalar getRelativeVelocity(const btVector3& linvelA,const btVector3& angvelA,const btVector3& linvelB,const btVector3& angvelB) + { + btVector3 linrel = linvelA - linvelB; + btVector3 angvela = angvelA * m_aJ; + btVector3 angvelb = angvelB * m_bJ; + linrel *= m_linearJointAxis; + angvela += angvelb; + angvela += linrel; + btScalar rel_vel2 = angvela[0]+angvela[1]+angvela[2]; + return rel_vel2 + SIMD_EPSILON; + } +//private: + + btVector3 m_linearJointAxis; + btVector3 m_aJ; + btVector3 m_bJ; + btVector3 m_0MinvJt; + btVector3 m_1MinvJt; + //Optimization: can be stored in the w/last component of one of the vectors + btScalar m_Adiag; + +}; + +#endif //JACOBIAN_ENTRY_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp new file mode 100644 index 00000000000..aacb0a3ea66 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp @@ -0,0 +1,116 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btPoint2PointConstraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include + + + +btPoint2PointConstraint::btPoint2PointConstraint() +{ +} + +btPoint2PointConstraint::btPoint2PointConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB) +:btTypedConstraint(rbA,rbB),m_pivotInA(pivotInA),m_pivotInB(pivotInB) +{ + +} + + +btPoint2PointConstraint::btPoint2PointConstraint(btRigidBody& rbA,const btVector3& pivotInA) +:btTypedConstraint(rbA),m_pivotInA(pivotInA),m_pivotInB(rbA.getCenterOfMassTransform()(pivotInA)) +{ + +} + +void btPoint2PointConstraint::buildJacobian() +{ + m_appliedImpulse = btScalar(0.); + + btVector3 normal(0,0,0); + + for (int i=0;i<3;i++) + { + normal[i] = 1; + new (&m_jac[i]) btJacobianEntry( + m_rbA.getCenterOfMassTransform().getBasis().transpose(), + m_rbB.getCenterOfMassTransform().getBasis().transpose(), + m_rbA.getCenterOfMassTransform()*m_pivotInA - m_rbA.getCenterOfMassPosition(), + m_rbB.getCenterOfMassTransform()*m_pivotInB - m_rbB.getCenterOfMassPosition(), + normal, + m_rbA.getInvInertiaDiagLocal(), + m_rbA.getInvMass(), + m_rbB.getInvInertiaDiagLocal(), + m_rbB.getInvMass()); + normal[i] = 0; + } + +} + +void btPoint2PointConstraint::solveConstraint(btScalar timeStep) +{ + btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_pivotInA; + btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_pivotInB; + + + btVector3 normal(0,0,0); + + +// btVector3 angvelA = m_rbA.getCenterOfMassTransform().getBasis().transpose() * m_rbA.getAngularVelocity(); +// btVector3 angvelB = m_rbB.getCenterOfMassTransform().getBasis().transpose() * m_rbB.getAngularVelocity(); + + for (int i=0;i<3;i++) + { + normal[i] = 1; + btScalar jacDiagABInv = btScalar(1.) / m_jac[i].getDiagonal(); + + btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); + btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); + //this jacobian entry could be re-used for all iterations + + btVector3 vel1 = m_rbA.getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = m_rbB.getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + btScalar rel_vel; + rel_vel = normal.dot(vel); + + /* + //velocity error (first order error) + btScalar rel_vel = m_jac[i].getRelativeVelocity(m_rbA.getLinearVelocity(),angvelA, + m_rbB.getLinearVelocity(),angvelB); + */ + + //positional error (zeroth order error) + btScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal + + btScalar impulse = depth*m_setting.m_tau/timeStep * jacDiagABInv - m_setting.m_damping * rel_vel * jacDiagABInv; + m_appliedImpulse+=impulse; + btVector3 impulse_vector = normal * impulse; + m_rbA.applyImpulse(impulse_vector, pivotAInW - m_rbA.getCenterOfMassPosition()); + m_rbB.applyImpulse(-impulse_vector, pivotBInW - m_rbB.getCenterOfMassPosition()); + + normal[i] = 0; + } +} + +void btPoint2PointConstraint::updateRHS(btScalar timeStep) +{ + (void)timeStep; + +} + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h new file mode 100644 index 00000000000..71da8ac0347 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h @@ -0,0 +1,77 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef POINT2POINTCONSTRAINT_H +#define POINT2POINTCONSTRAINT_H + +#include "../../LinearMath/btVector3.h" +#include "btJacobianEntry.h" +#include "btTypedConstraint.h" + +class btRigidBody; + +struct btConstraintSetting +{ + btConstraintSetting() : + m_tau(btScalar(0.3)), + m_damping(btScalar(1.)) + { + } + btScalar m_tau; + btScalar m_damping; +}; + +/// point to point constraint between two rigidbodies each with a pivotpoint that descibes the 'ballsocket' location in local space +class btPoint2PointConstraint : public btTypedConstraint +{ + btJacobianEntry m_jac[3]; //3 orthogonal linear constraints + + btVector3 m_pivotInA; + btVector3 m_pivotInB; + + + +public: + + btConstraintSetting m_setting; + + btPoint2PointConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB); + + btPoint2PointConstraint(btRigidBody& rbA,const btVector3& pivotInA); + + btPoint2PointConstraint(); + + virtual void buildJacobian(); + + + virtual void solveConstraint(btScalar timeStep); + + void updateRHS(btScalar timeStep); + + void setPivotA(const btVector3& pivotA) + { + m_pivotInA = pivotA; + } + + void setPivotB(const btVector3& pivotB) + { + m_pivotInB = pivotB; + } + + + +}; + +#endif //POINT2POINTCONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp new file mode 100644 index 00000000000..14b36ad44fd --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -0,0 +1,1158 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btSequentialImpulseConstraintSolver.h" +#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "btContactConstraint.h" +#include "btSolve2LinearConstraint.h" +#include "btContactSolverInfo.h" +#include "LinearMath/btIDebugDraw.h" +#include "btJacobianEntry.h" +#include "LinearMath/btMinMax.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" +#include +#include "LinearMath/btStackAlloc.h" +#include "LinearMath/btQuickprof.h" +#include "btSolverBody.h" +#include "btSolverConstraint.h" + +#include "LinearMath/btAlignedObjectArray.h" + +#ifdef USE_PROFILE +#include "LinearMath/btQuickprof.h" +#endif //USE_PROFILE + +int totalCpd = 0; + +int gTotalContactPoints = 0; + +struct btOrderIndex +{ + int m_manifoldIndex; + int m_pointIndex; +}; + + + +#define SEQUENTIAL_IMPULSE_MAX_SOLVER_POINTS 16384 +static btOrderIndex gOrder[SEQUENTIAL_IMPULSE_MAX_SOLVER_POINTS]; + + +unsigned long btSequentialImpulseConstraintSolver::btRand2() +{ + m_btSeed2 = (1664525L*m_btSeed2 + 1013904223L) & 0xffffffff; + return m_btSeed2; +} + + + +//See ODE: adam's all-int straightforward(?) dRandInt (0..n-1) +int btSequentialImpulseConstraintSolver::btRandInt2 (int n) +{ + // seems good; xor-fold and modulus + const unsigned long un = n; + unsigned long r = btRand2(); + + // note: probably more aggressive than it needs to be -- might be + // able to get away without one or two of the innermost branches. + if (un <= 0x00010000UL) { + r ^= (r >> 16); + if (un <= 0x00000100UL) { + r ^= (r >> 8); + if (un <= 0x00000010UL) { + r ^= (r >> 4); + if (un <= 0x00000004UL) { + r ^= (r >> 2); + if (un <= 0x00000002UL) { + r ^= (r >> 1); + } + } + } + } + } + + return (int) (r % un); +} + + + + + +bool MyContactDestroyedCallback(void* userPersistentData) +{ + assert (userPersistentData); + btConstraintPersistentData* cpd = (btConstraintPersistentData*)userPersistentData; + delete cpd; + totalCpd--; + //printf("totalCpd = %i. DELETED Ptr %x\n",totalCpd,userPersistentData); + return true; +} + + + +btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver() +:m_solverMode(SOLVER_RANDMIZE_ORDER | SOLVER_CACHE_FRIENDLY), //not using SOLVER_USE_WARMSTARTING, +m_btSeed2(0) +{ + gContactDestroyedCallback = &MyContactDestroyedCallback; + + //initialize default friction/contact funcs + int i,j; + for (i=0;im_angularVelocity = rigidbody->getAngularVelocity(); + solverBody->m_centerOfMassPosition = rigidbody->getCenterOfMassPosition(); + solverBody->m_friction = rigidbody->getFriction(); +// solverBody->m_invInertiaWorld = rigidbody->getInvInertiaTensorWorld(); + solverBody->m_invMass = rigidbody->getInvMass(); + solverBody->m_linearVelocity = rigidbody->getLinearVelocity(); + solverBody->m_originalBody = rigidbody; + solverBody->m_angularFactor = rigidbody->getAngularFactor(); +} + +btScalar penetrationResolveFactor = btScalar(0.9); +btScalar restitutionCurve(btScalar rel_vel, btScalar restitution) +{ + btScalar rest = restitution * -rel_vel; + return rest; +} + + + + + + +//velocity + friction +//response between two dynamic objects with friction +SIMD_FORCE_INLINE btScalar resolveSingleCollisionCombinedCacheFriendly( + btSolverBody& body1, + btSolverBody& body2, + btSolverConstraint& contactConstraint, + const btContactSolverInfo& solverInfo) +{ + (void)solverInfo; + + btScalar normalImpulse(0.f); + { + if (contactConstraint.m_penetration < 0.f) + return 0.f; + + // Optimized version of projected relative velocity, use precomputed cross products with normal + // body1.getVelocityInLocalPoint(contactConstraint.m_rel_posA,vel1); + // body2.getVelocityInLocalPoint(contactConstraint.m_rel_posB,vel2); + // btVector3 vel = vel1 - vel2; + // btScalar rel_vel = contactConstraint.m_contactNormal.dot(vel); + + btScalar rel_vel; + btScalar vel1Dotn = contactConstraint.m_contactNormal.dot(body1.m_linearVelocity) + + contactConstraint.m_relpos1CrossNormal.dot(body1.m_angularVelocity); + btScalar vel2Dotn = contactConstraint.m_contactNormal.dot(body2.m_linearVelocity) + + contactConstraint.m_relpos2CrossNormal.dot(body2.m_angularVelocity); + + rel_vel = vel1Dotn-vel2Dotn; + + + btScalar positionalError = contactConstraint.m_penetration; + btScalar velocityError = contactConstraint.m_restitution - rel_vel;// * damping; + + btScalar penetrationImpulse = positionalError * contactConstraint.m_jacDiagABInv; + btScalar velocityImpulse = velocityError * contactConstraint.m_jacDiagABInv; + btScalar normalImpulse = penetrationImpulse+velocityImpulse; + + // See Erin Catto's GDC 2006 paper: Clamp the accumulated impulse + btScalar oldNormalImpulse = contactConstraint.m_appliedImpulse; + btScalar sum = oldNormalImpulse + normalImpulse; + contactConstraint.m_appliedImpulse = btScalar(0.) > sum ? btScalar(0.): sum; + + btScalar oldVelocityImpulse = contactConstraint.m_appliedVelocityImpulse; + btScalar velocitySum = oldVelocityImpulse + velocityImpulse; + contactConstraint.m_appliedVelocityImpulse = btScalar(0.) > velocitySum ? btScalar(0.): velocitySum; + + normalImpulse = contactConstraint.m_appliedImpulse - oldNormalImpulse; + + if (body1.m_invMass) + { + body1.internalApplyImpulse(contactConstraint.m_contactNormal*body1.m_invMass, + contactConstraint.m_angularComponentA,normalImpulse); + } + if (body2.m_invMass) + { + body2.internalApplyImpulse(contactConstraint.m_contactNormal*body2.m_invMass, + contactConstraint.m_angularComponentB,-normalImpulse); + } + + } + + + + return normalImpulse; +} + + +#ifndef NO_FRICTION_TANGENTIALS + +SIMD_FORCE_INLINE btScalar resolveSingleFrictionCacheFriendly( + btSolverBody& body1, + btSolverBody& body2, + btSolverConstraint& contactConstraint, + const btContactSolverInfo& solverInfo, + btScalar appliedNormalImpulse) +{ + (void)solverInfo; + + + const btScalar combinedFriction = contactConstraint.m_friction; + + const btScalar limit = appliedNormalImpulse * combinedFriction; + + if (appliedNormalImpulse>btScalar(0.)) + //friction + { + + btScalar j1; + { + + btScalar rel_vel; + const btScalar vel1Dotn = contactConstraint.m_contactNormal.dot(body1.m_linearVelocity) + + contactConstraint.m_relpos1CrossNormal.dot(body1.m_angularVelocity); + const btScalar vel2Dotn = contactConstraint.m_contactNormal.dot(body2.m_linearVelocity) + + contactConstraint.m_relpos2CrossNormal.dot(body2.m_angularVelocity); + rel_vel = vel1Dotn-vel2Dotn; + + // calculate j that moves us to zero relative velocity + j1 = -rel_vel * contactConstraint.m_jacDiagABInv; + btScalar oldTangentImpulse = contactConstraint.m_appliedImpulse; + contactConstraint.m_appliedImpulse = oldTangentImpulse + j1; + GEN_set_min(contactConstraint.m_appliedImpulse, limit); + GEN_set_max(contactConstraint.m_appliedImpulse, -limit); + j1 = contactConstraint.m_appliedImpulse - oldTangentImpulse; + + } + + if (body1.m_invMass) + { + body1.internalApplyImpulse(contactConstraint.m_contactNormal*body1.m_invMass,contactConstraint.m_angularComponentA,j1); + } + if (body2.m_invMass) + { + body2.internalApplyImpulse(contactConstraint.m_contactNormal*body2.m_invMass,contactConstraint.m_angularComponentB,-j1); + } + + } + return 0.f; +} + + +#else + +//velocity + friction +//response between two dynamic objects with friction +btScalar resolveSingleFrictionCacheFriendly( + btSolverBody& body1, + btSolverBody& body2, + btSolverConstraint& contactConstraint, + const btContactSolverInfo& solverInfo) +{ + + btVector3 vel1; + btVector3 vel2; + btScalar normalImpulse(0.f); + + { + const btVector3& normal = contactConstraint.m_contactNormal; + if (contactConstraint.m_penetration < 0.f) + return 0.f; + + + body1.getVelocityInLocalPoint(contactConstraint.m_rel_posA,vel1); + body2.getVelocityInLocalPoint(contactConstraint.m_rel_posB,vel2); + btVector3 vel = vel1 - vel2; + btScalar rel_vel; + rel_vel = normal.dot(vel); + + btVector3 lat_vel = vel - normal * rel_vel; + btScalar lat_rel_vel = lat_vel.length2(); + + btScalar combinedFriction = contactConstraint.m_friction; + const btVector3& rel_pos1 = contactConstraint.m_rel_posA; + const btVector3& rel_pos2 = contactConstraint.m_rel_posB; + + + //if (contactConstraint.m_appliedVelocityImpulse > 0.f) + if (lat_rel_vel > SIMD_EPSILON*SIMD_EPSILON) + { + lat_rel_vel = btSqrt(lat_rel_vel); + + lat_vel /= lat_rel_vel; + btVector3 temp1 = body1.m_invInertiaWorld * rel_pos1.cross(lat_vel); + btVector3 temp2 = body2.m_invInertiaWorld * rel_pos2.cross(lat_vel); + btScalar friction_impulse = lat_rel_vel / + (body1.m_invMass + body2.m_invMass + lat_vel.dot(temp1.cross(rel_pos1) + temp2.cross(rel_pos2))); + btScalar normal_impulse = contactConstraint.m_appliedVelocityImpulse * combinedFriction; + + GEN_set_min(friction_impulse, normal_impulse); + GEN_set_max(friction_impulse, -normal_impulse); + body1.applyImpulse(lat_vel * -friction_impulse, rel_pos1); + body2.applyImpulse(lat_vel * friction_impulse, rel_pos2); + } + } + + return normalImpulse; +} + +#endif //NO_FRICTION_TANGENTIALS + +btAlignedObjectArray tmpSolverBodyPool; +btAlignedObjectArray tmpSolverConstraintPool; +btAlignedObjectArray tmpSolverFrictionConstraintPool; + + +btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendly(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc) +{ + (void)stackAlloc; + (void)debugDrawer; + + if (!(numConstraints + numManifolds)) + { +// printf("empty\n"); + return 0.f; + } + + BEGIN_PROFILE("refreshManifolds"); + + int i; + for (i=0;igetBody0(); + btRigidBody* rb1 = (btRigidBody*)manifold->getBody1(); + + manifold->refreshContactPoints(rb0->getCenterOfMassTransform(),rb1->getCenterOfMassTransform()); + + } + + END_PROFILE("refreshManifolds"); + + + BEGIN_PROFILE("gatherSolverData"); + + //int sizeofSB = sizeof(btSolverBody); + //int sizeofSC = sizeof(btSolverConstraint); + + + //if (1) + { + //if m_stackAlloc, try to pack bodies/constraints to speed up solving +// btBlock* sablock; +// sablock = stackAlloc->beginBlock(); + + // int memsize = 16; +// unsigned char* stackMemory = stackAlloc->allocate(memsize); + + + //todo: use stack allocator for this temp memory + int minReservation = numManifolds*2; + + tmpSolverBodyPool.reserve(minReservation); + + { + for (int i=0;igetIslandTag() >= 0)) + { + btAssert(rb->getCompanionId() < 0); + int solverBodyId = tmpSolverBodyPool.size(); + btSolverBody& solverBody = tmpSolverBodyPool.expand(); + initSolverBody(&solverBody,rb); + rb->setCompanionId(solverBodyId); + } + } + } + + + tmpSolverConstraintPool.reserve(minReservation); + tmpSolverFrictionConstraintPool.reserve(minReservation); + { + int i; + + for (i=0;igetBody0(); + btRigidBody* rb1 = (btRigidBody*)manifold->getBody1(); + + + int solverBodyIdA=-1; + int solverBodyIdB=-1; + + if (manifold->getNumContacts()) + { + + + + if (rb0->getIslandTag() >= 0) + { + solverBodyIdA = rb0->getCompanionId(); + } else + { + //create a static body + solverBodyIdA = tmpSolverBodyPool.size(); + btSolverBody& solverBody = tmpSolverBodyPool.expand(); + initSolverBody(&solverBody,rb0); + } + + if (rb1->getIslandTag() >= 0) + { + solverBodyIdB = rb1->getCompanionId(); + } else + { + //create a static body + solverBodyIdB = tmpSolverBodyPool.size(); + btSolverBody& solverBody = tmpSolverBodyPool.expand(); + initSolverBody(&solverBody,rb1); + } + } + + for (int j=0;jgetNumContacts();j++) + { + + btManifoldPoint& cp = manifold->getContactPoint(j); + + int frictionIndex = tmpSolverConstraintPool.size(); + + if (cp.getDistance() <= btScalar(0.)) + { + + const btVector3& pos1 = cp.getPositionWorldOnA(); + const btVector3& pos2 = cp.getPositionWorldOnB(); + + btVector3 rel_pos1 = pos1 - rb0->getCenterOfMassPosition(); + btVector3 rel_pos2 = pos2 - rb1->getCenterOfMassPosition(); + + + btScalar relaxation = 1.f; + + { + btSolverConstraint& solverConstraint = tmpSolverConstraintPool.expand(); + + solverConstraint.m_solverBodyIdA = solverBodyIdA; + solverConstraint.m_solverBodyIdB = solverBodyIdB; + solverConstraint.m_constraintType = btSolverConstraint::BT_SOLVER_CONTACT_1D; + + + + { + //can be optimized, the cross products are already calculated + btScalar denom0 = rb0->computeImpulseDenominator(pos1,cp.m_normalWorldOnB); + btScalar denom1 = rb1->computeImpulseDenominator(pos2,cp.m_normalWorldOnB); + btScalar denom = relaxation/(denom0+denom1); + solverConstraint.m_jacDiagABInv = denom; + } + + solverConstraint.m_contactNormal = cp.m_normalWorldOnB; + solverConstraint.m_relpos1CrossNormal = rel_pos1.cross(cp.m_normalWorldOnB); + solverConstraint.m_relpos2CrossNormal = rel_pos2.cross(cp.m_normalWorldOnB); + + + btVector3 vel1 = rb0->getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = rb1->getVelocityInLocalPoint(rel_pos2); + + btVector3 vel = vel1 - vel2; + btScalar rel_vel; + rel_vel = cp.m_normalWorldOnB.dot(vel); + + + solverConstraint.m_penetration = cp.getDistance();///btScalar(infoGlobal.m_numIterations); + solverConstraint.m_friction = cp.m_combinedFriction; + btScalar rest = restitutionCurve(rel_vel, cp.m_combinedRestitution); + if (rest <= btScalar(0.)) + { + rest = 0.f; + }; + + btScalar penVel = -solverConstraint.m_penetration/infoGlobal.m_timeStep; + if (rest > penVel) + { + rest = btScalar(0.); + } + solverConstraint.m_restitution = rest; + + solverConstraint.m_penetration *= -(infoGlobal.m_erp/infoGlobal.m_timeStep); + + solverConstraint.m_appliedImpulse = 0.f; + solverConstraint.m_appliedVelocityImpulse = 0.f; + + + btVector3 torqueAxis0 = rel_pos1.cross(cp.m_normalWorldOnB); + solverConstraint.m_angularComponentA = rb0->getInvInertiaTensorWorld()*torqueAxis0; + btVector3 torqueAxis1 = rel_pos2.cross(cp.m_normalWorldOnB); + solverConstraint.m_angularComponentB = rb1->getInvInertiaTensorWorld()*torqueAxis1; + } + + //create 2 '1d axis' constraints for 2 tangential friction directions + + //re-calculate friction direction every frame, todo: check if this is really needed + btVector3 frictionTangential0a, frictionTangential1b; + + btPlaneSpace1(cp.m_normalWorldOnB,frictionTangential0a,frictionTangential1b); + + { + btSolverConstraint& solverConstraint = tmpSolverFrictionConstraintPool.expand(); + solverConstraint.m_contactNormal = frictionTangential0a; + + solverConstraint.m_solverBodyIdA = solverBodyIdA; + solverConstraint.m_solverBodyIdB = solverBodyIdB; + solverConstraint.m_constraintType = btSolverConstraint::BT_SOLVER_FRICTION_1D; + solverConstraint.m_frictionIndex = frictionIndex; + + solverConstraint.m_friction = cp.m_combinedFriction; + + solverConstraint.m_appliedImpulse = btScalar(0.); + solverConstraint.m_appliedVelocityImpulse = 0.f; + + btScalar denom0 = rb0->computeImpulseDenominator(pos1,solverConstraint.m_contactNormal); + btScalar denom1 = rb1->computeImpulseDenominator(pos2,solverConstraint.m_contactNormal); + btScalar denom = relaxation/(denom0+denom1); + solverConstraint.m_jacDiagABInv = denom; + + { + btVector3 ftorqueAxis0 = rel_pos1.cross(solverConstraint.m_contactNormal); + solverConstraint.m_relpos1CrossNormal = ftorqueAxis0; + solverConstraint.m_angularComponentA = rb0->getInvInertiaTensorWorld()*ftorqueAxis0; + } + { + btVector3 ftorqueAxis0 = rel_pos2.cross(solverConstraint.m_contactNormal); + solverConstraint.m_relpos2CrossNormal = ftorqueAxis0; + solverConstraint.m_angularComponentB = rb1->getInvInertiaTensorWorld()*ftorqueAxis0; + } + + } + + + { + + btSolverConstraint& solverConstraint = tmpSolverFrictionConstraintPool.expand(); + solverConstraint.m_contactNormal = frictionTangential1b; + + solverConstraint.m_solverBodyIdA = solverBodyIdA; + solverConstraint.m_solverBodyIdB = solverBodyIdB; + solverConstraint.m_constraintType = btSolverConstraint::BT_SOLVER_FRICTION_1D; + solverConstraint.m_frictionIndex = frictionIndex; + + solverConstraint.m_friction = cp.m_combinedFriction; + + solverConstraint.m_appliedImpulse = btScalar(0.); + solverConstraint.m_appliedVelocityImpulse = 0.f; + + btScalar denom0 = rb0->computeImpulseDenominator(pos1,solverConstraint.m_contactNormal); + btScalar denom1 = rb1->computeImpulseDenominator(pos2,solverConstraint.m_contactNormal); + btScalar denom = relaxation/(denom0+denom1); + solverConstraint.m_jacDiagABInv = denom; + { + btVector3 ftorqueAxis1 = rel_pos1.cross(solverConstraint.m_contactNormal); + solverConstraint.m_relpos1CrossNormal = ftorqueAxis1; + solverConstraint.m_angularComponentA = rb0->getInvInertiaTensorWorld()*ftorqueAxis1; + } + { + btVector3 ftorqueAxis1 = rel_pos2.cross(solverConstraint.m_contactNormal); + solverConstraint.m_relpos2CrossNormal = ftorqueAxis1; + solverConstraint.m_angularComponentB = rb1->getInvInertiaTensorWorld()*ftorqueAxis1; + } + } + + } + } + } + } + } + END_PROFILE("gatherSolverData"); + + BEGIN_PROFILE("prepareConstraints"); + + btContactSolverInfo info = infoGlobal; + + { + int j; + for (j=0;jbuildJacobian(); + } + } + + btAlignedObjectArray gOrderTmpConstraintPool; + btAlignedObjectArray gOrderFrictionConstraintPool; + + int numConstraintPool = tmpSolverConstraintPool.size(); + int numFrictionPool = tmpSolverFrictionConstraintPool.size(); + + ///todo: use stack allocator for such temporarily memory, same for solver bodies/constraints + gOrderTmpConstraintPool.resize(numConstraintPool); + gOrderFrictionConstraintPool.resize(numFrictionPool); + { + int i; + for (i=0;igetRigidBodyA().getIslandTag() >= 0) && (constraint->getRigidBodyA().getCompanionId() >= 0)) + { + tmpSolverBodyPool[constraint->getRigidBodyA().getCompanionId()].writebackVelocity(); + } + if ((constraint->getRigidBodyB().getIslandTag() >= 0) && (constraint->getRigidBodyB().getCompanionId() >= 0)) + { + tmpSolverBodyPool[constraint->getRigidBodyB().getCompanionId()].writebackVelocity(); + } + + constraint->solveConstraint(info.m_timeStep); + + if ((constraint->getRigidBodyA().getIslandTag() >= 0) && (constraint->getRigidBodyA().getCompanionId() >= 0)) + { + tmpSolverBodyPool[constraint->getRigidBodyA().getCompanionId()].readVelocity(); + } + if ((constraint->getRigidBodyB().getIslandTag() >= 0) && (constraint->getRigidBodyB().getCompanionId() >= 0)) + { + tmpSolverBodyPool[constraint->getRigidBodyB().getCompanionId()].readVelocity(); + } + + } + + { + int numPoolConstraints = tmpSolverConstraintPool.size(); + for (j=0;jgetNumContacts();p++) + { + gOrder[totalPoints].m_manifoldIndex = j; + gOrder[totalPoints].m_pointIndex = p; + totalPoints++; + } + } + } + + { + int j; + for (j=0;jbuildJacobian(); + } + } + + END_PROFILE("prepareConstraints"); + + + BEGIN_PROFILE("solveConstraints"); + + //should traverse the contacts random order... + int iteration; + + { + for ( iteration = 0;iterationsolveConstraint(info.m_timeStep); + } + + for (j=0;jgetBody0(), + (btRigidBody*)manifold->getBody1() + ,manifold->getContactPoint(gOrder[j].m_pointIndex),info,iteration,debugDrawer); + } + + for (j=0;jgetBody0(), + (btRigidBody*)manifold->getBody1(),manifold->getContactPoint(gOrder[j].m_pointIndex),info,iteration,debugDrawer); + } + } + } + + END_PROFILE("solveConstraints"); + + +#ifdef USE_PROFILE + btProfiler::endBlock("solve"); +#endif //USE_PROFILE + + + + + return btScalar(0.); +} + + + + + + + +void btSequentialImpulseConstraintSolver::prepareConstraints(btPersistentManifold* manifoldPtr, const btContactSolverInfo& info,btIDebugDraw* debugDrawer) +{ + + (void)debugDrawer; + + btRigidBody* body0 = (btRigidBody*)manifoldPtr->getBody0(); + btRigidBody* body1 = (btRigidBody*)manifoldPtr->getBody1(); + + + //only necessary to refresh the manifold once (first iteration). The integration is done outside the loop + { + manifoldPtr->refreshContactPoints(body0->getCenterOfMassTransform(),body1->getCenterOfMassTransform()); + + int numpoints = manifoldPtr->getNumContacts(); + + gTotalContactPoints += numpoints; + + btVector3 color(0,1,0); + for (int i=0;igetContactPoint(i); + if (cp.getDistance() <= btScalar(0.)) + { + const btVector3& pos1 = cp.getPositionWorldOnA(); + const btVector3& pos2 = cp.getPositionWorldOnB(); + + btVector3 rel_pos1 = pos1 - body0->getCenterOfMassPosition(); + btVector3 rel_pos2 = pos2 - body1->getCenterOfMassPosition(); + + + //this jacobian entry is re-used for all iterations + btJacobianEntry jac(body0->getCenterOfMassTransform().getBasis().transpose(), + body1->getCenterOfMassTransform().getBasis().transpose(), + rel_pos1,rel_pos2,cp.m_normalWorldOnB,body0->getInvInertiaDiagLocal(),body0->getInvMass(), + body1->getInvInertiaDiagLocal(),body1->getInvMass()); + + + btScalar jacDiagAB = jac.getDiagonal(); + + btConstraintPersistentData* cpd = (btConstraintPersistentData*) cp.m_userPersistentData; + if (cpd) + { + //might be invalid + cpd->m_persistentLifeTime++; + if (cpd->m_persistentLifeTime != cp.getLifeTime()) + { + //printf("Invalid: cpd->m_persistentLifeTime = %i cp.getLifeTime() = %i\n",cpd->m_persistentLifeTime,cp.getLifeTime()); + new (cpd) btConstraintPersistentData; + cpd->m_persistentLifeTime = cp.getLifeTime(); + + } else + { + //printf("Persistent: cpd->m_persistentLifeTime = %i cp.getLifeTime() = %i\n",cpd->m_persistentLifeTime,cp.getLifeTime()); + + } + } else + { + + cpd = new btConstraintPersistentData; + assert(cpd); + + totalCpd ++; + //printf("totalCpd = %i Created Ptr %x\n",totalCpd,cpd); + cp.m_userPersistentData = cpd; + cpd->m_persistentLifeTime = cp.getLifeTime(); + //printf("CREATED: %x . cpd->m_persistentLifeTime = %i cp.getLifeTime() = %i\n",cpd,cpd->m_persistentLifeTime,cp.getLifeTime()); + + } + assert(cpd); + + cpd->m_jacDiagABInv = btScalar(1.) / jacDiagAB; + + //Dependent on Rigidbody A and B types, fetch the contact/friction response func + //perhaps do a similar thing for friction/restutution combiner funcs... + + cpd->m_frictionSolverFunc = m_frictionDispatch[body0->m_frictionSolverType][body1->m_frictionSolverType]; + cpd->m_contactSolverFunc = m_contactDispatch[body0->m_contactSolverType][body1->m_contactSolverType]; + + btVector3 vel1 = body0->getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = body1->getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + btScalar rel_vel; + rel_vel = cp.m_normalWorldOnB.dot(vel); + + btScalar combinedRestitution = cp.m_combinedRestitution; + + cpd->m_penetration = cp.getDistance();///btScalar(info.m_numIterations); + cpd->m_friction = cp.m_combinedFriction; + cpd->m_restitution = restitutionCurve(rel_vel, combinedRestitution); + if (cpd->m_restitution <= btScalar(0.)) + { + cpd->m_restitution = btScalar(0.0); + + }; + + //restitution and penetration work in same direction so + //rel_vel + + btScalar penVel = -cpd->m_penetration/info.m_timeStep; + + if (cpd->m_restitution > penVel) + { + cpd->m_penetration = btScalar(0.); + } + + + + btScalar relaxation = info.m_damping; + if (m_solverMode & SOLVER_USE_WARMSTARTING) + { + cpd->m_appliedImpulse *= relaxation; + } else + { + cpd->m_appliedImpulse =btScalar(0.); + } + + //for friction + cpd->m_prevAppliedImpulse = cpd->m_appliedImpulse; + + //re-calculate friction direction every frame, todo: check if this is really needed + btPlaneSpace1(cp.m_normalWorldOnB,cpd->m_frictionWorldTangential0,cpd->m_frictionWorldTangential1); + + +#define NO_FRICTION_WARMSTART 1 + + #ifdef NO_FRICTION_WARMSTART + cpd->m_accumulatedTangentImpulse0 = btScalar(0.); + cpd->m_accumulatedTangentImpulse1 = btScalar(0.); + #endif //NO_FRICTION_WARMSTART + btScalar denom0 = body0->computeImpulseDenominator(pos1,cpd->m_frictionWorldTangential0); + btScalar denom1 = body1->computeImpulseDenominator(pos2,cpd->m_frictionWorldTangential0); + btScalar denom = relaxation/(denom0+denom1); + cpd->m_jacDiagABInvTangent0 = denom; + + + denom0 = body0->computeImpulseDenominator(pos1,cpd->m_frictionWorldTangential1); + denom1 = body1->computeImpulseDenominator(pos2,cpd->m_frictionWorldTangential1); + denom = relaxation/(denom0+denom1); + cpd->m_jacDiagABInvTangent1 = denom; + + btVector3 totalImpulse = + #ifndef NO_FRICTION_WARMSTART + cpd->m_frictionWorldTangential0*cpd->m_accumulatedTangentImpulse0+ + cpd->m_frictionWorldTangential1*cpd->m_accumulatedTangentImpulse1+ + #endif //NO_FRICTION_WARMSTART + cp.m_normalWorldOnB*cpd->m_appliedImpulse; + + + + /// + { + btVector3 torqueAxis0 = rel_pos1.cross(cp.m_normalWorldOnB); + cpd->m_angularComponentA = body0->getInvInertiaTensorWorld()*torqueAxis0; + btVector3 torqueAxis1 = rel_pos2.cross(cp.m_normalWorldOnB); + cpd->m_angularComponentB = body1->getInvInertiaTensorWorld()*torqueAxis1; + } + { + btVector3 ftorqueAxis0 = rel_pos1.cross(cpd->m_frictionWorldTangential0); + cpd->m_frictionAngularComponent0A = body0->getInvInertiaTensorWorld()*ftorqueAxis0; + } + { + btVector3 ftorqueAxis1 = rel_pos1.cross(cpd->m_frictionWorldTangential1); + cpd->m_frictionAngularComponent1A = body0->getInvInertiaTensorWorld()*ftorqueAxis1; + } + { + btVector3 ftorqueAxis0 = rel_pos2.cross(cpd->m_frictionWorldTangential0); + cpd->m_frictionAngularComponent0B = body1->getInvInertiaTensorWorld()*ftorqueAxis0; + } + { + btVector3 ftorqueAxis1 = rel_pos2.cross(cpd->m_frictionWorldTangential1); + cpd->m_frictionAngularComponent1B = body1->getInvInertiaTensorWorld()*ftorqueAxis1; + } + + /// + + + + //apply previous frames impulse on both bodies + body0->applyImpulse(totalImpulse, rel_pos1); + body1->applyImpulse(-totalImpulse, rel_pos2); + } + + } + } +} + + +btScalar btSequentialImpulseConstraintSolver::solveCombinedContactFriction(btRigidBody* body0,btRigidBody* body1, btManifoldPoint& cp, const btContactSolverInfo& info,int iter,btIDebugDraw* debugDrawer) +{ + btScalar maxImpulse = btScalar(0.); + + { + + btVector3 color(0,1,0); + { + if (cp.getDistance() <= btScalar(0.)) + { + + if (iter == 0) + { + if (debugDrawer) + debugDrawer->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color); + } + + { + + //btConstraintPersistentData* cpd = (btConstraintPersistentData*) cp.m_userPersistentData; + btScalar impulse = resolveSingleCollisionCombined( + *body0,*body1, + cp, + info); + + if (maxImpulse < impulse) + maxImpulse = impulse; + + } + } + } + } + return maxImpulse; +} + + + +btScalar btSequentialImpulseConstraintSolver::solve(btRigidBody* body0,btRigidBody* body1, btManifoldPoint& cp, const btContactSolverInfo& info,int iter,btIDebugDraw* debugDrawer) +{ + + btScalar maxImpulse = btScalar(0.); + + { + + btVector3 color(0,1,0); + { + if (cp.getDistance() <= btScalar(0.)) + { + + if (iter == 0) + { + if (debugDrawer) + debugDrawer->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color); + } + + { + + btConstraintPersistentData* cpd = (btConstraintPersistentData*) cp.m_userPersistentData; + btScalar impulse = cpd->m_contactSolverFunc( + *body0,*body1, + cp, + info); + + if (maxImpulse < impulse) + maxImpulse = impulse; + + } + } + } + } + return maxImpulse; +} + +btScalar btSequentialImpulseConstraintSolver::solveFriction(btRigidBody* body0,btRigidBody* body1, btManifoldPoint& cp, const btContactSolverInfo& info,int iter,btIDebugDraw* debugDrawer) +{ + + (void)debugDrawer; + (void)iter; + + + { + + btVector3 color(0,1,0); + { + + if (cp.getDistance() <= btScalar(0.)) + { + + btConstraintPersistentData* cpd = (btConstraintPersistentData*) cp.m_userPersistentData; + cpd->m_frictionSolverFunc( + *body0,*body1, + cp, + info); + + + } + } + + + } + return btScalar(0.); +} diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h new file mode 100644 index 00000000000..13e70c41be4 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h @@ -0,0 +1,109 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_H +#define SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_H + +#include "btConstraintSolver.h" +class btIDebugDraw; +#include "btContactConstraint.h" + + + +/// btSequentialImpulseConstraintSolver uses a Propagation Method and Sequentially applies impulses +/// The approach is the 3D version of Erin Catto's GDC 2006 tutorial. See http://www.gphysics.com +/// Although Sequential Impulse is more intuitive, it is mathematically equivalent to Projected Successive Overrelaxation (iterative LCP) +/// Applies impulses for combined restitution and penetration recovery and to simulate friction +class btSequentialImpulseConstraintSolver : public btConstraintSolver +{ + +protected: + btScalar solve(btRigidBody* body0,btRigidBody* body1, btManifoldPoint& cp, const btContactSolverInfo& info,int iter,btIDebugDraw* debugDrawer); + btScalar solveFriction(btRigidBody* body0,btRigidBody* body1, btManifoldPoint& cp, const btContactSolverInfo& info,int iter,btIDebugDraw* debugDrawer); + void prepareConstraints(btPersistentManifold* manifoldPtr, const btContactSolverInfo& info,btIDebugDraw* debugDrawer); + + ContactSolverFunc m_contactDispatch[MAX_CONTACT_SOLVER_TYPES][MAX_CONTACT_SOLVER_TYPES]; + ContactSolverFunc m_frictionDispatch[MAX_CONTACT_SOLVER_TYPES][MAX_CONTACT_SOLVER_TYPES]; + + //choose between several modes, different friction model etc. + int m_solverMode; + ///m_btSeed2 is used for re-arranging the constraint rows. improves convergence/quality of friction + unsigned long m_btSeed2; + +public: + + enum eSolverMode + { + SOLVER_RANDMIZE_ORDER = 1, + SOLVER_FRICTION_SEPARATE = 2, + SOLVER_USE_WARMSTARTING = 4, + SOLVER_CACHE_FRIENDLY = 8 + }; + + btSequentialImpulseConstraintSolver(); + + ///Advanced: Override the default contact solving function for contacts, for certain types of rigidbody + ///See btRigidBody::m_contactSolverType and btRigidBody::m_frictionSolverType + void setContactSolverFunc(ContactSolverFunc func,int type0,int type1) + { + m_contactDispatch[type0][type1] = func; + } + + ///Advanced: Override the default friction solving function for contacts, for certain types of rigidbody + ///See btRigidBody::m_contactSolverType and btRigidBody::m_frictionSolverType + void SetFrictionSolverFunc(ContactSolverFunc func,int type0,int type1) + { + m_frictionDispatch[type0][type1] = func; + } + + virtual ~btSequentialImpulseConstraintSolver() {} + + virtual btScalar solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc); + + virtual btScalar solveGroupCacheFriendly(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc); + + btScalar solveCombinedContactFriction(btRigidBody* body0,btRigidBody* body1, btManifoldPoint& cp, const btContactSolverInfo& info,int iter,btIDebugDraw* debugDrawer); + + + void setSolverMode(int mode) + { + m_solverMode = mode; + } + + int getSolverMode() const + { + return m_solverMode; + } + + unsigned long btRand2(); + + int btRandInt2 (int n); + + void setRandSeed(unsigned long seed) + { + m_btSeed2 = seed; + } + unsigned long getRandSeed() const + { + return m_btSeed2; + } + +}; + + + + +#endif //SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_H + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp new file mode 100644 index 00000000000..0c7dbd668bb --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp @@ -0,0 +1,255 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#include "btSolve2LinearConstraint.h" + +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "LinearMath/btVector3.h" +#include "btJacobianEntry.h" + + +void btSolve2LinearConstraint::resolveUnilateralPairConstraint( + btRigidBody* body1, + btRigidBody* body2, + + const btMatrix3x3& world2A, + const btMatrix3x3& world2B, + + const btVector3& invInertiaADiag, + const btScalar invMassA, + const btVector3& linvelA,const btVector3& angvelA, + const btVector3& rel_posA1, + const btVector3& invInertiaBDiag, + const btScalar invMassB, + const btVector3& linvelB,const btVector3& angvelB, + const btVector3& rel_posA2, + + btScalar depthA, const btVector3& normalA, + const btVector3& rel_posB1,const btVector3& rel_posB2, + btScalar depthB, const btVector3& normalB, + btScalar& imp0,btScalar& imp1) +{ + (void)linvelA; + (void)linvelB; + (void)angvelB; + (void)angvelA; + + + + imp0 = btScalar(0.); + imp1 = btScalar(0.); + + btScalar len = btFabs(normalA.length()) - btScalar(1.); + if (btFabs(len) >= SIMD_EPSILON) + return; + + btAssert(len < SIMD_EPSILON); + + + //this jacobian entry could be re-used for all iterations + btJacobianEntry jacA(world2A,world2B,rel_posA1,rel_posA2,normalA,invInertiaADiag,invMassA, + invInertiaBDiag,invMassB); + btJacobianEntry jacB(world2A,world2B,rel_posB1,rel_posB2,normalB,invInertiaADiag,invMassA, + invInertiaBDiag,invMassB); + + //const btScalar vel0 = jacA.getRelativeVelocity(linvelA,angvelA,linvelB,angvelB); + //const btScalar vel1 = jacB.getRelativeVelocity(linvelA,angvelA,linvelB,angvelB); + + const btScalar vel0 = normalA.dot(body1->getVelocityInLocalPoint(rel_posA1)-body2->getVelocityInLocalPoint(rel_posA1)); + const btScalar vel1 = normalB.dot(body1->getVelocityInLocalPoint(rel_posB1)-body2->getVelocityInLocalPoint(rel_posB1)); + +// btScalar penetrationImpulse = (depth*contactTau*timeCorrection) * massTerm;//jacDiagABInv + btScalar massTerm = btScalar(1.) / (invMassA + invMassB); + + + // calculate rhs (or error) terms + const btScalar dv0 = depthA * m_tau * massTerm - vel0 * m_damping; + const btScalar dv1 = depthB * m_tau * massTerm - vel1 * m_damping; + + + // dC/dv * dv = -C + + // jacobian * impulse = -error + // + + //impulse = jacobianInverse * -error + + // inverting 2x2 symmetric system (offdiagonal are equal!) + // + + + btScalar nonDiag = jacA.getNonDiagonal(jacB,invMassA,invMassB); + btScalar invDet = btScalar(1.0) / (jacA.getDiagonal() * jacB.getDiagonal() - nonDiag * nonDiag ); + + //imp0 = dv0 * jacA.getDiagonal() * invDet + dv1 * -nonDiag * invDet; + //imp1 = dv1 * jacB.getDiagonal() * invDet + dv0 * - nonDiag * invDet; + + imp0 = dv0 * jacA.getDiagonal() * invDet + dv1 * -nonDiag * invDet; + imp1 = dv1 * jacB.getDiagonal() * invDet + dv0 * - nonDiag * invDet; + + //[a b] [d -c] + //[c d] inverse = (1 / determinant) * [-b a] where determinant is (ad - bc) + + //[jA nD] * [imp0] = [dv0] + //[nD jB] [imp1] [dv1] + +} + + + +void btSolve2LinearConstraint::resolveBilateralPairConstraint( + btRigidBody* body1, + btRigidBody* body2, + const btMatrix3x3& world2A, + const btMatrix3x3& world2B, + + const btVector3& invInertiaADiag, + const btScalar invMassA, + const btVector3& linvelA,const btVector3& angvelA, + const btVector3& rel_posA1, + const btVector3& invInertiaBDiag, + const btScalar invMassB, + const btVector3& linvelB,const btVector3& angvelB, + const btVector3& rel_posA2, + + btScalar depthA, const btVector3& normalA, + const btVector3& rel_posB1,const btVector3& rel_posB2, + btScalar depthB, const btVector3& normalB, + btScalar& imp0,btScalar& imp1) +{ + + (void)linvelA; + (void)linvelB; + (void)angvelA; + (void)angvelB; + + + + imp0 = btScalar(0.); + imp1 = btScalar(0.); + + btScalar len = btFabs(normalA.length()) - btScalar(1.); + if (btFabs(len) >= SIMD_EPSILON) + return; + + btAssert(len < SIMD_EPSILON); + + + //this jacobian entry could be re-used for all iterations + btJacobianEntry jacA(world2A,world2B,rel_posA1,rel_posA2,normalA,invInertiaADiag,invMassA, + invInertiaBDiag,invMassB); + btJacobianEntry jacB(world2A,world2B,rel_posB1,rel_posB2,normalB,invInertiaADiag,invMassA, + invInertiaBDiag,invMassB); + + //const btScalar vel0 = jacA.getRelativeVelocity(linvelA,angvelA,linvelB,angvelB); + //const btScalar vel1 = jacB.getRelativeVelocity(linvelA,angvelA,linvelB,angvelB); + + const btScalar vel0 = normalA.dot(body1->getVelocityInLocalPoint(rel_posA1)-body2->getVelocityInLocalPoint(rel_posA1)); + const btScalar vel1 = normalB.dot(body1->getVelocityInLocalPoint(rel_posB1)-body2->getVelocityInLocalPoint(rel_posB1)); + + // calculate rhs (or error) terms + const btScalar dv0 = depthA * m_tau - vel0 * m_damping; + const btScalar dv1 = depthB * m_tau - vel1 * m_damping; + + // dC/dv * dv = -C + + // jacobian * impulse = -error + // + + //impulse = jacobianInverse * -error + + // inverting 2x2 symmetric system (offdiagonal are equal!) + // + + + btScalar nonDiag = jacA.getNonDiagonal(jacB,invMassA,invMassB); + btScalar invDet = btScalar(1.0) / (jacA.getDiagonal() * jacB.getDiagonal() - nonDiag * nonDiag ); + + //imp0 = dv0 * jacA.getDiagonal() * invDet + dv1 * -nonDiag * invDet; + //imp1 = dv1 * jacB.getDiagonal() * invDet + dv0 * - nonDiag * invDet; + + imp0 = dv0 * jacA.getDiagonal() * invDet + dv1 * -nonDiag * invDet; + imp1 = dv1 * jacB.getDiagonal() * invDet + dv0 * - nonDiag * invDet; + + //[a b] [d -c] + //[c d] inverse = (1 / determinant) * [-b a] where determinant is (ad - bc) + + //[jA nD] * [imp0] = [dv0] + //[nD jB] [imp1] [dv1] + + if ( imp0 > btScalar(0.0)) + { + if ( imp1 > btScalar(0.0) ) + { + //both positive + } + else + { + imp1 = btScalar(0.); + + // now imp0>0 imp1<0 + imp0 = dv0 / jacA.getDiagonal(); + if ( imp0 > btScalar(0.0) ) + { + } else + { + imp0 = btScalar(0.); + } + } + } + else + { + imp0 = btScalar(0.); + + imp1 = dv1 / jacB.getDiagonal(); + if ( imp1 <= btScalar(0.0) ) + { + imp1 = btScalar(0.); + // now imp0>0 imp1<0 + imp0 = dv0 / jacA.getDiagonal(); + if ( imp0 > btScalar(0.0) ) + { + } else + { + imp0 = btScalar(0.); + } + } else + { + } + } +} + + +/* +void btSolve2LinearConstraint::resolveAngularConstraint( const btMatrix3x3& invInertiaAWS, + const btScalar invMassA, + const btVector3& linvelA,const btVector3& angvelA, + const btVector3& rel_posA1, + const btMatrix3x3& invInertiaBWS, + const btScalar invMassB, + const btVector3& linvelB,const btVector3& angvelB, + const btVector3& rel_posA2, + + btScalar depthA, const btVector3& normalA, + const btVector3& rel_posB1,const btVector3& rel_posB2, + btScalar depthB, const btVector3& normalB, + btScalar& imp0,btScalar& imp1) +{ + +} +*/ + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h new file mode 100644 index 00000000000..e7d26645c6a --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h @@ -0,0 +1,107 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SOLVE_2LINEAR_CONSTRAINT_H +#define SOLVE_2LINEAR_CONSTRAINT_H + +#include "../../LinearMath/btMatrix3x3.h" +#include "../../LinearMath/btVector3.h" + + +class btRigidBody; + + + +/// constraint class used for lateral tyre friction. +class btSolve2LinearConstraint +{ + btScalar m_tau; + btScalar m_damping; + +public: + + btSolve2LinearConstraint(btScalar tau,btScalar damping) + { + m_tau = tau; + m_damping = damping; + } + // + // solve unilateral constraint (equality, direct method) + // + void resolveUnilateralPairConstraint( + btRigidBody* body0, + btRigidBody* body1, + + const btMatrix3x3& world2A, + const btMatrix3x3& world2B, + + const btVector3& invInertiaADiag, + const btScalar invMassA, + const btVector3& linvelA,const btVector3& angvelA, + const btVector3& rel_posA1, + const btVector3& invInertiaBDiag, + const btScalar invMassB, + const btVector3& linvelB,const btVector3& angvelB, + const btVector3& rel_posA2, + + btScalar depthA, const btVector3& normalA, + const btVector3& rel_posB1,const btVector3& rel_posB2, + btScalar depthB, const btVector3& normalB, + btScalar& imp0,btScalar& imp1); + + + // + // solving 2x2 lcp problem (inequality, direct solution ) + // + void resolveBilateralPairConstraint( + btRigidBody* body0, + btRigidBody* body1, + const btMatrix3x3& world2A, + const btMatrix3x3& world2B, + + const btVector3& invInertiaADiag, + const btScalar invMassA, + const btVector3& linvelA,const btVector3& angvelA, + const btVector3& rel_posA1, + const btVector3& invInertiaBDiag, + const btScalar invMassB, + const btVector3& linvelB,const btVector3& angvelB, + const btVector3& rel_posA2, + + btScalar depthA, const btVector3& normalA, + const btVector3& rel_posB1,const btVector3& rel_posB2, + btScalar depthB, const btVector3& normalB, + btScalar& imp0,btScalar& imp1); + +/* + void resolveAngularConstraint( const btMatrix3x3& invInertiaAWS, + const btScalar invMassA, + const btVector3& linvelA,const btVector3& angvelA, + const btVector3& rel_posA1, + const btMatrix3x3& invInertiaBWS, + const btScalar invMassB, + const btVector3& linvelB,const btVector3& angvelB, + const btVector3& rel_posA2, + + btScalar depthA, const btVector3& normalA, + const btVector3& rel_posB1,const btVector3& rel_posB2, + btScalar depthB, const btVector3& normalB, + btScalar& imp0,btScalar& imp1); + +*/ + +}; + +#endif //SOLVE_2LINEAR_CONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h new file mode 100644 index 00000000000..0ab536f42b3 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h @@ -0,0 +1,71 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_SOLVER_BODY_H +#define BT_SOLVER_BODY_H + +class btRigidBody; +#include "LinearMath/btVector3.h" +#include "LinearMath/btMatrix3x3.h" + + + + +ATTRIBUTE_ALIGNED16 (struct) btSolverBody +{ + btVector3 m_centerOfMassPosition; + btVector3 m_linearVelocity; + btVector3 m_angularVelocity; + btRigidBody* m_originalBody; + float m_invMass; + float m_friction; + float m_angularFactor; + + inline void getVelocityInLocalPoint(const btVector3& rel_pos, btVector3& velocity ) const + { + velocity = m_linearVelocity + m_angularVelocity.cross(rel_pos); + } + + //Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position + inline void internalApplyImpulse(const btVector3& linearComponent, const btVector3& angularComponent,btScalar impulseMagnitude) + { + m_linearVelocity += linearComponent*impulseMagnitude; + m_angularVelocity += angularComponent*impulseMagnitude*m_angularFactor; + } + + void writebackVelocity() + { + if (m_invMass) + { + m_originalBody->setLinearVelocity(m_linearVelocity); + m_originalBody->setAngularVelocity(m_angularVelocity); + } + } + + void readVelocity() + { + if (m_invMass) + { + m_linearVelocity = m_originalBody->getLinearVelocity(); + m_angularVelocity = m_originalBody->getAngularVelocity(); + } + } + + + + +}; + +#endif //BT_SOLVER_BODY_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverConstraint.h new file mode 100644 index 00000000000..f1f40ffdf19 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverConstraint.h @@ -0,0 +1,63 @@ + + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_SOLVER_CONSTRAINT_H +#define BT_SOLVER_CONSTRAINT_H + +class btRigidBody; +#include "LinearMath/btVector3.h" +#include "LinearMath/btMatrix3x3.h" + +//#define NO_FRICTION_TANGENTIALS 1 + +///1D constraint along a normal axis between bodyA and bodyB. It can be combined to solve contact and friction constraints. +ATTRIBUTE_ALIGNED16 (struct) btSolverConstraint +{ + btVector3 m_relpos1CrossNormal; + btVector3 m_relpos2CrossNormal; + btVector3 m_contactNormal; + btVector3 m_angularComponentA; + btVector3 m_angularComponentB; + + btScalar m_appliedVelocityImpulse; + int m_solverBodyIdA; + int m_solverBodyIdB; + btScalar m_friction; + btScalar m_restitution; + btScalar m_jacDiagABInv; + btScalar m_penetration; + btScalar m_appliedImpulse; + + int m_constraintType; + int m_frictionIndex; + int m_unusedPadding[2]; + + enum btSolverConstraintType + { + BT_SOLVER_CONTACT_1D = 0, + BT_SOLVER_FRICTION_1D + }; +}; + + + + + + +#endif //BT_SOLVER_CONSTRAINT_H + + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp new file mode 100644 index 00000000000..a15b3e026cd --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp @@ -0,0 +1,53 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btTypedConstraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" + +static btRigidBody s_fixed(0, 0,0); + +btTypedConstraint::btTypedConstraint() +: m_userConstraintType(-1), +m_userConstraintId(-1), +m_rbA(s_fixed), +m_rbB(s_fixed), +m_appliedImpulse(btScalar(0.)) +{ + s_fixed.setMassProps(btScalar(0.),btVector3(btScalar(0.),btScalar(0.),btScalar(0.))); +} +btTypedConstraint::btTypedConstraint(btRigidBody& rbA) +: m_userConstraintType(-1), +m_userConstraintId(-1), +m_rbA(rbA), +m_rbB(s_fixed), +m_appliedImpulse(btScalar(0.)) +{ + s_fixed.setMassProps(btScalar(0.),btVector3(btScalar(0.),btScalar(0.),btScalar(0.))); + +} + + +btTypedConstraint::btTypedConstraint(btRigidBody& rbA,btRigidBody& rbB) +: m_userConstraintType(-1), +m_userConstraintId(-1), +m_rbA(rbA), +m_rbB(rbB), +m_appliedImpulse(btScalar(0.)) +{ + s_fixed.setMassProps(btScalar(0.),btVector3(btScalar(0.),btScalar(0.),btScalar(0.))); + +} + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h new file mode 100644 index 00000000000..dfee6e80d0e --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h @@ -0,0 +1,96 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef TYPED_CONSTRAINT_H +#define TYPED_CONSTRAINT_H + +class btRigidBody; +#include "../../LinearMath/btScalar.h" + +///TypedConstraint is the baseclass for Bullet constraints and vehicles +class btTypedConstraint +{ + int m_userConstraintType; + int m_userConstraintId; + + btTypedConstraint& operator=(btTypedConstraint& other) + { + btAssert(0); + (void) other; + return *this; + } + +protected: + btRigidBody& m_rbA; + btRigidBody& m_rbB; + btScalar m_appliedImpulse; + + +public: + + btTypedConstraint(); + virtual ~btTypedConstraint() {}; + btTypedConstraint(btRigidBody& rbA); + + btTypedConstraint(btRigidBody& rbA,btRigidBody& rbB); + + virtual void buildJacobian() = 0; + + virtual void solveConstraint(btScalar timeStep) = 0; + + const btRigidBody& getRigidBodyA() const + { + return m_rbA; + } + const btRigidBody& getRigidBodyB() const + { + return m_rbB; + } + + btRigidBody& getRigidBodyA() + { + return m_rbA; + } + btRigidBody& getRigidBodyB() + { + return m_rbB; + } + + int getUserConstraintType() const + { + return m_userConstraintType ; + } + + void setUserConstraintType(int userConstraintType) + { + m_userConstraintType = userConstraintType; + }; + + void setUserConstraintId(int uid) + { + m_userConstraintId = uid; + } + + int getUserConstraintId() + { + return m_userConstraintId; + } + btScalar getAppliedImpulse() + { + return m_appliedImpulse; + } +}; + +#endif //TYPED_CONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp new file mode 100644 index 00000000000..29719ec9a3e --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp @@ -0,0 +1,954 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "btDiscreteDynamicsWorld.h" + +//collision detection +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" +#include "BulletCollision/CollisionShapes/btCollisionShape.h" +#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" +#include + +//rigidbody & constraints +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" +#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" + +//for debug rendering +#include "BulletCollision/CollisionShapes/btBoxShape.h" +#include "BulletCollision/CollisionShapes/btCapsuleShape.h" +#include "BulletCollision/CollisionShapes/btCompoundShape.h" +#include "BulletCollision/CollisionShapes/btConeShape.h" +#include "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h" +#include "BulletCollision/CollisionShapes/btCylinderShape.h" +#include "BulletCollision/CollisionShapes/btMultiSphereShape.h" +#include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" +#include "BulletCollision/CollisionShapes/btTriangleCallback.h" +#include "BulletCollision/CollisionShapes/btTriangleMeshShape.h" +#include "LinearMath/btIDebugDraw.h" + + + +//vehicle +#include "BulletDynamics/Vehicle/btRaycastVehicle.h" +#include "BulletDynamics/Vehicle/btVehicleRaycaster.h" +#include "BulletDynamics/Vehicle/btWheelInfo.h" +#include "LinearMath/btIDebugDraw.h" +#include "LinearMath/btQuickprof.h" +#include "LinearMath/btMotionState.h" + + + + + +btDiscreteDynamicsWorld::btDiscreteDynamicsWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache,btConstraintSolver* constraintSolver) +:btDynamicsWorld(dispatcher,pairCache), +m_constraintSolver(constraintSolver? constraintSolver: new btSequentialImpulseConstraintSolver), +m_debugDrawer(0), +m_gravity(0,-10,0), +m_localTime(btScalar(1.)/btScalar(60.)), +m_profileTimings(0) +{ + m_islandManager = new btSimulationIslandManager(); + m_ownsIslandManager = true; + m_ownsConstraintSolver = (constraintSolver==0); +} + + +btDiscreteDynamicsWorld::~btDiscreteDynamicsWorld() +{ + //only delete it when we created it + if (m_ownsIslandManager) + delete m_islandManager; + if (m_ownsConstraintSolver) + delete m_constraintSolver; +} + +void btDiscreteDynamicsWorld::saveKinematicState(btScalar timeStep) +{ + + for (int i=0;igetActivationState() != ISLAND_SLEEPING) + { + if (body->isKinematicObject()) + { + //to calculate velocities next frame + body->saveKinematicState(timeStep); + } + } + } + } +} + +void btDiscreteDynamicsWorld::synchronizeMotionStates() +{ + //debug vehicle wheels + + + { + //todo: iterate over awake simulation islands! + for ( int i=0;igetDebugMode() & btIDebugDraw::DBG_DrawWireframe) + { + btVector3 color(btScalar(255.),btScalar(255.),btScalar(255.)); + switch(colObj->getActivationState()) + { + case ACTIVE_TAG: + color = btVector3(btScalar(255.),btScalar(255.),btScalar(255.)); break; + case ISLAND_SLEEPING: + color = btVector3(btScalar(0.),btScalar(255.),btScalar(0.));break; + case WANTS_DEACTIVATION: + color = btVector3(btScalar(0.),btScalar(255.),btScalar(255.));break; + case DISABLE_DEACTIVATION: + color = btVector3(btScalar(255.),btScalar(0.),btScalar(0.));break; + case DISABLE_SIMULATION: + color = btVector3(btScalar(255.),btScalar(255.),btScalar(0.));break; + default: + { + color = btVector3(btScalar(255.),btScalar(0.),btScalar(0.)); + } + }; + + debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color); + } + btRigidBody* body = btRigidBody::upcast(colObj); + if (body && body->getMotionState() && !body->isStaticOrKinematicObject()) + { + //we need to call the update at least once, even for sleeping objects + //otherwise the 'graphics' transform never updates properly + //so todo: add 'dirty' flag + //if (body->getActivationState() != ISLAND_SLEEPING) + { + btTransform interpolatedTransform; + btTransformUtil::integrateTransform(body->getInterpolationWorldTransform(), + body->getInterpolationLinearVelocity(),body->getInterpolationAngularVelocity(),m_localTime,interpolatedTransform); + body->getMotionState()->setWorldTransform(interpolatedTransform); + } + } + } + } + + if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawWireframe) + { + for ( int i=0;im_vehicles.size();i++) + { + for (int v=0;vgetNumWheels();v++) + { + btVector3 wheelColor(0,255,255); + if (m_vehicles[i]->getWheelInfo(v).m_raycastInfo.m_isInContact) + { + wheelColor.setValue(0,0,255); + } else + { + wheelColor.setValue(255,0,255); + } + + //synchronize the wheels with the (interpolated) chassis worldtransform + m_vehicles[i]->updateWheelTransform(v,true); + + btVector3 wheelPosWS = m_vehicles[i]->getWheelInfo(v).m_worldTransform.getOrigin(); + + btVector3 axle = btVector3( + m_vehicles[i]->getWheelInfo(v).m_worldTransform.getBasis()[0][m_vehicles[i]->getRightAxis()], + m_vehicles[i]->getWheelInfo(v).m_worldTransform.getBasis()[1][m_vehicles[i]->getRightAxis()], + m_vehicles[i]->getWheelInfo(v).m_worldTransform.getBasis()[2][m_vehicles[i]->getRightAxis()]); + + + //m_vehicles[i]->getWheelInfo(v).m_raycastInfo.m_wheelAxleWS + //debug wheels (cylinders) + m_debugDrawer->drawLine(wheelPosWS,wheelPosWS+axle,wheelColor); + m_debugDrawer->drawLine(wheelPosWS,m_vehicles[i]->getWheelInfo(v).m_raycastInfo.m_contactPointWS,wheelColor); + + } + } + } + +} + + +int btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep) +{ + int numSimulationSubSteps = 0; + + if (maxSubSteps) + { + //fixed timestep with interpolation + m_localTime += timeStep; + if (m_localTime >= fixedTimeStep) + { + numSimulationSubSteps = int( m_localTime / fixedTimeStep); + m_localTime -= numSimulationSubSteps * fixedTimeStep; + } + } else + { + //variable timestep + fixedTimeStep = timeStep; + m_localTime = timeStep; + if (btFuzzyZero(timeStep)) + { + numSimulationSubSteps = 0; + maxSubSteps = 0; + } else + { + numSimulationSubSteps = 1; + maxSubSteps = 1; + } + } + + //process some debugging flags + if (getDebugDrawer()) + { + gDisableDeactivation = (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0; + } + if (numSimulationSubSteps) + { + + saveKinematicState(fixedTimeStep); + + //clamp the number of substeps, to prevent simulation grinding spiralling down to a halt + int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps)? maxSubSteps : numSimulationSubSteps; + + for (int i=0;isetGravity(gravity); + } + } +} + + +void btDiscreteDynamicsWorld::removeRigidBody(btRigidBody* body) +{ + removeCollisionObject(body); +} + +void btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body) +{ + if (!body->isStaticOrKinematicObject()) + { + body->setGravity(m_gravity); + } + + if (body->getCollisionShape()) + { + bool isDynamic = !(body->isStaticObject() || body->isKinematicObject()); + short collisionFilterGroup = isDynamic? short(btBroadphaseProxy::DefaultFilter) : short(btBroadphaseProxy::StaticFilter); + short collisionFilterMask = isDynamic? short(btBroadphaseProxy::AllFilter) : short(btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); + + addCollisionObject(body,collisionFilterGroup,collisionFilterMask); + } +} + +void btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body, short group, short mask) +{ + if (!body->isStaticOrKinematicObject()) + { + body->setGravity(m_gravity); + } + + if (body->getCollisionShape()) + { + addCollisionObject(body,group,mask); + } +} + + +void btDiscreteDynamicsWorld::updateVehicles(btScalar timeStep) +{ + BEGIN_PROFILE("updateVehicles"); + + for ( int i=0;iupdateVehicle( timeStep); + } + END_PROFILE("updateVehicles"); +} + +void btDiscreteDynamicsWorld::updateActivationState(btScalar timeStep) +{ + BEGIN_PROFILE("updateActivationState"); + + for ( int i=0;iupdateDeactivation(timeStep); + + if (body->wantsSleeping()) + { + if (body->isStaticOrKinematicObject()) + { + body->setActivationState(ISLAND_SLEEPING); + } else + { + if (body->getActivationState() == ACTIVE_TAG) + body->setActivationState( WANTS_DEACTIVATION ); + } + } else + { + if (body->getActivationState() != DISABLE_DEACTIVATION) + body->setActivationState( ACTIVE_TAG ); + } + } + } + END_PROFILE("updateActivationState"); +} + +void btDiscreteDynamicsWorld::addConstraint(btTypedConstraint* constraint,bool disableCollisionsBetweenLinkedBodies) +{ + m_constraints.push_back(constraint); + if (disableCollisionsBetweenLinkedBodies) + { + constraint->getRigidBodyA().addConstraintRef(constraint); + constraint->getRigidBodyB().addConstraintRef(constraint); + } +} + +void btDiscreteDynamicsWorld::removeConstraint(btTypedConstraint* constraint) +{ + m_constraints.remove(constraint); + constraint->getRigidBodyA().removeConstraintRef(constraint); + constraint->getRigidBodyB().removeConstraintRef(constraint); +} + +void btDiscreteDynamicsWorld::addVehicle(btRaycastVehicle* vehicle) +{ + m_vehicles.push_back(vehicle); +} + +void btDiscreteDynamicsWorld::removeVehicle(btRaycastVehicle* vehicle) +{ + m_vehicles.remove(vehicle); +} + +inline int btGetConstraintIslandId(const btTypedConstraint* lhs) +{ + int islandId; + + const btCollisionObject& rcolObj0 = lhs->getRigidBodyA(); + const btCollisionObject& rcolObj1 = lhs->getRigidBodyB(); + islandId= rcolObj0.getIslandTag()>=0?rcolObj0.getIslandTag():rcolObj1.getIslandTag(); + return islandId; + +} + + +class btSortConstraintOnIslandPredicate +{ + public: + + bool operator() ( const btTypedConstraint* lhs, const btTypedConstraint* rhs ) + { + int rIslandId0,lIslandId0; + rIslandId0 = btGetConstraintIslandId(rhs); + lIslandId0 = btGetConstraintIslandId(lhs); + return lIslandId0 < rIslandId0; + } +}; + + + + +void btDiscreteDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) +{ + + struct InplaceSolverIslandCallback : public btSimulationIslandManager::IslandCallback + { + + btContactSolverInfo& m_solverInfo; + btConstraintSolver* m_solver; + btTypedConstraint** m_sortedConstraints; + int m_numConstraints; + btIDebugDraw* m_debugDrawer; + btStackAlloc* m_stackAlloc; + + + InplaceSolverIslandCallback( + btContactSolverInfo& solverInfo, + btConstraintSolver* solver, + btTypedConstraint** sortedConstraints, + int numConstraints, + btIDebugDraw* debugDrawer, + btStackAlloc* stackAlloc) + :m_solverInfo(solverInfo), + m_solver(solver), + m_sortedConstraints(sortedConstraints), + m_numConstraints(numConstraints), + m_debugDrawer(debugDrawer), + m_stackAlloc(stackAlloc) + { + + } + + InplaceSolverIslandCallback& operator=(InplaceSolverIslandCallback& other) + { + btAssert(0); + (void)other; + return *this; + } + virtual void ProcessIsland(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifolds,int numManifolds, int islandId) + { + //also add all non-contact constraints/joints for this island + btTypedConstraint** startConstraint = 0; + int numCurConstraints = 0; + int i; + + //find the first constraint for this island + for (i=0;isolveGroup( bodies,numBodies,manifolds, numManifolds,startConstraint,numCurConstraints,m_solverInfo,m_debugDrawer,m_stackAlloc); + } + + }; + + //sorted version of all btTypedConstraint, based on islandId + btAlignedObjectArray sortedConstraints; + sortedConstraints.resize( m_constraints.size()); + int i; + for (i=0;ibuildAndProcessIslands(getCollisionWorld()->getDispatcher(),getCollisionWorld()->getCollisionObjectArray(),&solverCallback); + + +} + + + + +void btDiscreteDynamicsWorld::calculateSimulationIslands() +{ + BEGIN_PROFILE("calculateSimulationIslands"); + + getSimulationIslandManager()->updateActivationState(getCollisionWorld(),getCollisionWorld()->getDispatcher()); + + { + int i; + int numConstraints = int(m_constraints.size()); + for (i=0;i< numConstraints ; i++ ) + { + btTypedConstraint* constraint = m_constraints[i]; + + const btRigidBody* colObj0 = &constraint->getRigidBodyA(); + const btRigidBody* colObj1 = &constraint->getRigidBodyB(); + + if (((colObj0) && ((colObj0)->mergesSimulationIslands())) && + ((colObj1) && ((colObj1)->mergesSimulationIslands()))) + { + if (colObj0->isActive() || colObj1->isActive()) + { + + getSimulationIslandManager()->getUnionFind().unite((colObj0)->getIslandTag(), + (colObj1)->getIslandTag()); + } + } + } + } + + //Store the island id in each body + getSimulationIslandManager()->storeIslandActivationState(getCollisionWorld()); + + END_PROFILE("calculateSimulationIslands"); + +} + + +void btDiscreteDynamicsWorld::updateAabbs() +{ + BEGIN_PROFILE("updateAabbs"); + + btVector3 colorvec(1,0,0); + btTransform predictedTrans; + for ( int i=0;iIsActive() && (!body->IsStatic())) + { + btPoint3 minAabb,maxAabb; + colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb); + btBroadphaseInterface* bp = (btBroadphaseInterface*)m_broadphasePairCache; + + //moving objects should be moderately sized, probably something wrong if not + if ( colObj->isStaticObject() || ((maxAabb-minAabb).length2() < btScalar(1e12))) + { + bp->setAabb(body->getBroadphaseHandle(),minAabb,maxAabb); + } else + { + //something went wrong, investigate + //this assert is unwanted in 3D modelers (danger of loosing work) + body->setActivationState(DISABLE_SIMULATION); + + static bool reportMe = true; + if (reportMe && m_debugDrawer) + { + reportMe = false; + m_debugDrawer->reportErrorWarning("Overflow in AABB, object removed from simulation"); + m_debugDrawer->reportErrorWarning("If you can reproduce this, please email bugs@continuousphysics.com\n"); + m_debugDrawer->reportErrorWarning("Please include above information, your Platform, version of OS.\n"); + m_debugDrawer->reportErrorWarning("Thanks.\n"); + } + + + } + if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) + { + m_debugDrawer->drawAabb(minAabb,maxAabb,colorvec); + } + } + } + } + + END_PROFILE("updateAabbs"); +} + +void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) +{ + BEGIN_PROFILE("integrateTransforms"); + btTransform predictedTrans; + for ( int i=0;iisActive() && (!body->isStaticOrKinematicObject())) + { + body->predictIntegratedTransform(timeStep, predictedTrans); + body->proceedToTransform( predictedTrans); + } + } + } + END_PROFILE("integrateTransforms"); +} + + + +void btDiscreteDynamicsWorld::predictUnconstraintMotion(btScalar timeStep) +{ + BEGIN_PROFILE("predictUnconstraintMotion"); + for ( int i=0;iisStaticOrKinematicObject()) + { + if (body->isActive()) + { + body->applyForces( timeStep); + body->integrateVelocities( timeStep); + body->predictIntegratedTransform(timeStep,body->getInterpolationWorldTransform()); + } + } + } + } + END_PROFILE("predictUnconstraintMotion"); +} + + +void btDiscreteDynamicsWorld::startProfiling(btScalar timeStep) +{ + (void)timeStep; + #ifdef USE_QUICKPROF + + + //toggle btProfiler + if ( m_debugDrawer && m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_ProfileTimings) + { + if (!m_profileTimings) + { + m_profileTimings = 1; + // To disable profiling, simply comment out the following line. + static int counter = 0; + + char filename[128]; + sprintf(filename,"quickprof_bullet_timings%i.csv",counter++); + btProfiler::init(filename, btProfiler::BLOCK_CYCLE_SECONDS);//BLOCK_TOTAL_MICROSECONDS + } else + { + btProfiler::endProfilingCycle(); + } + + } else + { + if (m_profileTimings) + { + btProfiler::endProfilingCycle(); + + m_profileTimings = 0; + btProfiler::destroy(); + } + } +#endif //USE_QUICKPROF +} + + + + + + +class DebugDrawcallback : public btTriangleCallback, public btInternalTriangleIndexCallback +{ + btIDebugDraw* m_debugDrawer; + btVector3 m_color; + btTransform m_worldTrans; + +public: + + DebugDrawcallback(btIDebugDraw* debugDrawer,const btTransform& worldTrans,const btVector3& color) : + m_debugDrawer(debugDrawer), + m_color(color), + m_worldTrans(worldTrans) + { + } + + virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) + { + processTriangle(triangle,partId,triangleIndex); + } + + virtual void processTriangle(btVector3* triangle,int partId, int triangleIndex) + { + (void)partId; + (void)triangleIndex; + + btVector3 wv0,wv1,wv2; + wv0 = m_worldTrans*triangle[0]; + wv1 = m_worldTrans*triangle[1]; + wv2 = m_worldTrans*triangle[2]; + m_debugDrawer->drawLine(wv0,wv1,m_color); + m_debugDrawer->drawLine(wv1,wv2,m_color); + m_debugDrawer->drawLine(wv2,wv0,m_color); + } +}; + +void btDiscreteDynamicsWorld::debugDrawSphere(btScalar radius, const btTransform& transform, const btVector3& color) +{ + btVector3 start = transform.getOrigin(); + + const btVector3 xoffs = transform.getBasis() * btVector3(radius,0,0); + const btVector3 yoffs = transform.getBasis() * btVector3(0,radius,0); + const btVector3 zoffs = transform.getBasis() * btVector3(0,0,radius); + + // XY + getDebugDrawer()->drawLine(start-xoffs, start+yoffs, color); + getDebugDrawer()->drawLine(start+yoffs, start+xoffs, color); + getDebugDrawer()->drawLine(start+xoffs, start-yoffs, color); + getDebugDrawer()->drawLine(start-yoffs, start-xoffs, color); + + // XZ + getDebugDrawer()->drawLine(start-xoffs, start+zoffs, color); + getDebugDrawer()->drawLine(start+zoffs, start+xoffs, color); + getDebugDrawer()->drawLine(start+xoffs, start-zoffs, color); + getDebugDrawer()->drawLine(start-zoffs, start-xoffs, color); + + // YZ + getDebugDrawer()->drawLine(start-yoffs, start+zoffs, color); + getDebugDrawer()->drawLine(start+zoffs, start+yoffs, color); + getDebugDrawer()->drawLine(start+yoffs, start-zoffs, color); + getDebugDrawer()->drawLine(start-zoffs, start-yoffs, color); +} + +void btDiscreteDynamicsWorld::debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color) +{ + // Draw a small simplex at the center of the object + { + btVector3 start = worldTransform.getOrigin(); + getDebugDrawer()->drawLine(start, start+worldTransform.getBasis() * btVector3(1,0,0), btVector3(1,0,0)); + getDebugDrawer()->drawLine(start, start+worldTransform.getBasis() * btVector3(0,1,0), btVector3(0,1,0)); + getDebugDrawer()->drawLine(start, start+worldTransform.getBasis() * btVector3(0,0,1), btVector3(0,0,1)); + } + + if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) + { + const btCompoundShape* compoundShape = static_cast(shape); + for (int i=compoundShape->getNumChildShapes()-1;i>=0;i--) + { + btTransform childTrans = compoundShape->getChildTransform(i); + const btCollisionShape* colShape = compoundShape->getChildShape(i); + debugDrawObject(worldTransform*childTrans,colShape,color); + } + + } else + { + switch (shape->getShapeType()) + { + + case SPHERE_SHAPE_PROXYTYPE: + { + const btSphereShape* sphereShape = static_cast(shape); + btScalar radius = sphereShape->getMargin();//radius doesn't include the margin, so draw with margin + + debugDrawSphere(radius, worldTransform, color); + break; + } + case MULTI_SPHERE_SHAPE_PROXYTYPE: + { + const btMultiSphereShape* multiSphereShape = static_cast(shape); + + for (int i = multiSphereShape->getSphereCount()-1; i>=0;i--) + { + btTransform childTransform = worldTransform; + childTransform.getOrigin() += multiSphereShape->getSpherePosition(i); + debugDrawSphere(multiSphereShape->getSphereRadius(i), childTransform, color); + } + + break; + } + case CAPSULE_SHAPE_PROXYTYPE: + { + const btCapsuleShape* capsuleShape = static_cast(shape); + + btScalar radius = capsuleShape->getRadius(); + btScalar halfHeight = capsuleShape->getHalfHeight(); + + // Draw the ends + { + btTransform childTransform = worldTransform; + childTransform.getOrigin() = worldTransform * btVector3(0,halfHeight,0); + debugDrawSphere(radius, childTransform, color); + } + + { + btTransform childTransform = worldTransform; + childTransform.getOrigin() = worldTransform * btVector3(0,-halfHeight,0); + debugDrawSphere(radius, childTransform, color); + } + + // Draw some additional lines + btVector3 start = worldTransform.getOrigin(); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(-radius,halfHeight,0),start+worldTransform.getBasis() * btVector3(-radius,-halfHeight,0), color); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(radius,halfHeight,0),start+worldTransform.getBasis() * btVector3(radius,-halfHeight,0), color); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(0,halfHeight,-radius),start+worldTransform.getBasis() * btVector3(0,-halfHeight,-radius), color); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(0,halfHeight,radius),start+worldTransform.getBasis() * btVector3(0,-halfHeight,radius), color); + + break; + } + case CONE_SHAPE_PROXYTYPE: + { + const btConeShape* coneShape = static_cast(shape); + btScalar radius = coneShape->getRadius();//+coneShape->getMargin(); + btScalar height = coneShape->getHeight();//+coneShape->getMargin(); + btVector3 start = worldTransform.getOrigin(); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(btScalar(0.),btScalar(0.),btScalar(0.5)*height),start+worldTransform.getBasis() * btVector3(radius,btScalar(0.),btScalar(-0.5)*height),color); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(btScalar(0.),btScalar(0.),btScalar(0.5)*height),start+worldTransform.getBasis() * btVector3(-radius,btScalar(0.),btScalar(-0.5)*height),color); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(btScalar(0.),btScalar(0.),btScalar(0.5)*height),start+worldTransform.getBasis() * btVector3(btScalar(0.),radius,btScalar(-0.5)*height),color); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * btVector3(btScalar(0.),btScalar(0.),btScalar(0.5)*height),start+worldTransform.getBasis() * btVector3(btScalar(0.),-radius,btScalar(-0.5)*height),color); + break; + + } + case CYLINDER_SHAPE_PROXYTYPE: + { + const btCylinderShape* cylinder = static_cast(shape); + int upAxis = cylinder->getUpAxis(); + btScalar radius = cylinder->getRadius(); + btScalar halfHeight = cylinder->getHalfExtents()[upAxis]; + btVector3 start = worldTransform.getOrigin(); + btVector3 offsetHeight(0,0,0); + offsetHeight[upAxis] = halfHeight; + btVector3 offsetRadius(0,0,0); + offsetRadius[(upAxis+1)%3] = radius; + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight+offsetRadius),start+worldTransform.getBasis() * (-offsetHeight+offsetRadius),color); + getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight-offsetRadius),start+worldTransform.getBasis() * (-offsetHeight-offsetRadius),color); + break; + } + default: + { + + if (shape->isConcave()) + { + btConcaveShape* concaveMesh = (btConcaveShape*) shape; + + //todo pass camera, for some culling + btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + btVector3 aabbMin(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)); + + DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color); + concaveMesh->processAllTriangles(&drawCallback,aabbMin,aabbMax); + + } + + if (shape->getShapeType() == CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE) + { + btConvexTriangleMeshShape* convexMesh = (btConvexTriangleMeshShape*) shape; + //todo: pass camera for some culling + btVector3 aabbMax(btScalar(1e30),btScalar(1e30),btScalar(1e30)); + btVector3 aabbMin(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)); + //DebugDrawcallback drawCallback; + DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color); + convexMesh->getStridingMesh()->InternalProcessAllTriangles(&drawCallback,aabbMin,aabbMax); + } + + + /// for polyhedral shapes + if (shape->isPolyhedral()) + { + btPolyhedralConvexShape* polyshape = (btPolyhedralConvexShape*) shape; + + int i; + for (i=0;igetNumEdges();i++) + { + btPoint3 a,b; + polyshape->getEdge(i,a,b); + btVector3 wa = worldTransform * a; + btVector3 wb = worldTransform * b; + getDebugDrawer()->drawLine(wa,wb,color); + + } + + + } + } + } + } +} + + +void btDiscreteDynamicsWorld::setConstraintSolver(btConstraintSolver* solver) +{ + if (m_ownsConstraintSolver) + { + delete m_constraintSolver; + } + m_ownsConstraintSolver = false; + m_constraintSolver = solver; +} + +int btDiscreteDynamicsWorld::getNumConstraints() const +{ + return int(m_constraints.size()); +} +btTypedConstraint* btDiscreteDynamicsWorld::getConstraint(int index) +{ + return m_constraints[index]; +} +const btTypedConstraint* btDiscreteDynamicsWorld::getConstraint(int index) const +{ + return m_constraints[index]; +} diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h b/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h new file mode 100644 index 00000000000..83b90bfeebc --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h @@ -0,0 +1,157 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_DISCRETE_DYNAMICS_WORLD_H +#define BT_DISCRETE_DYNAMICS_WORLD_H + +#include "btDynamicsWorld.h" + +class btDispatcher; +class btOverlappingPairCache; +class btConstraintSolver; +class btSimulationIslandManager; +class btTypedConstraint; +#include "../ConstraintSolver/btContactSolverInfo.h" + +class btRaycastVehicle; +class btIDebugDraw; +#include "../../LinearMath/btAlignedObjectArray.h" + + +///btDiscreteDynamicsWorld provides discrete rigid body simulation +///those classes replace the obsolete CcdPhysicsEnvironment/CcdPhysicsController +class btDiscreteDynamicsWorld : public btDynamicsWorld +{ +protected: + + btConstraintSolver* m_constraintSolver; + + btSimulationIslandManager* m_islandManager; + + btAlignedObjectArray m_constraints; + + btIDebugDraw* m_debugDrawer; + + btVector3 m_gravity; + + //for variable timesteps + btScalar m_localTime; + //for variable timesteps + + bool m_ownsIslandManager; + bool m_ownsConstraintSolver; + + btContactSolverInfo m_solverInfo; + + + btAlignedObjectArray m_vehicles; + + int m_profileTimings; + + void predictUnconstraintMotion(btScalar timeStep); + + void integrateTransforms(btScalar timeStep); + + void calculateSimulationIslands(); + + void solveConstraints(btContactSolverInfo& solverInfo); + + void updateActivationState(btScalar timeStep); + + void updateVehicles(btScalar timeStep); + + void startProfiling(btScalar timeStep); + + virtual void internalSingleStepSimulation( btScalar timeStep); + + void synchronizeMotionStates(); + + void saveKinematicState(btScalar timeStep); + + void debugDrawSphere(btScalar radius, const btTransform& transform, const btVector3& color); + +public: + + + ///this btDiscreteDynamicsWorld constructor gets created objects from the user, and will not delete those + btDiscreteDynamicsWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache,btConstraintSolver* constraintSolver); + + virtual ~btDiscreteDynamicsWorld(); + + ///if maxSubSteps > 0, it will interpolate motion between fixedTimeStep's + virtual int stepSimulation( btScalar timeStep,int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.)); + + virtual void updateAabbs(); + + void addConstraint(btTypedConstraint* constraint, bool disableCollisionsBetweenLinkedBodies=false); + + void removeConstraint(btTypedConstraint* constraint); + + void addVehicle(btRaycastVehicle* vehicle); + + void removeVehicle(btRaycastVehicle* vehicle); + + btSimulationIslandManager* getSimulationIslandManager() + { + return m_islandManager; + } + + const btSimulationIslandManager* getSimulationIslandManager() const + { + return m_islandManager; + } + + btCollisionWorld* getCollisionWorld() + { + return this; + } + + virtual void setDebugDrawer(btIDebugDraw* debugDrawer) + { + m_debugDrawer = debugDrawer; + } + + virtual btIDebugDraw* getDebugDrawer() + { + return m_debugDrawer; + } + + virtual void setGravity(const btVector3& gravity); + + virtual void addRigidBody(btRigidBody* body); + + virtual void addRigidBody(btRigidBody* body, short group, short mask); + + virtual void removeRigidBody(btRigidBody* body); + + void debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color); + + virtual void setConstraintSolver(btConstraintSolver* solver); + + virtual int getNumConstraints() const; + + virtual btTypedConstraint* getConstraint(int index) ; + + virtual const btTypedConstraint* getConstraint(int index) const; + + btContactSolverInfo& getSolverInfo() + { + return m_solverInfo; + } + + +}; + +#endif //BT_DISCRETE_DYNAMICS_WORLD_H diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btDynamicsWorld.h b/extern/bullet2/src/BulletDynamics/Dynamics/btDynamicsWorld.h new file mode 100644 index 00000000000..65b63fad4b5 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Dynamics/btDynamicsWorld.h @@ -0,0 +1,78 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_DYNAMICS_WORLD_H +#define BT_DYNAMICS_WORLD_H + +#include "../../BulletCollision/CollisionDispatch/btCollisionWorld.h" +class btTypedConstraint; +class btRaycastVehicle; +class btConstraintSolver; + + +///btDynamicsWorld is the baseclass for several dynamics implementation, basic, discrete, parallel, and continuous +class btDynamicsWorld : public btCollisionWorld +{ + public: + + + btDynamicsWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache) + :btCollisionWorld(dispatcher,pairCache) + { + } + + virtual ~btDynamicsWorld() + { + } + + ///stepSimulation proceeds the simulation over timeStep units + ///if maxSubSteps > 0, it will interpolate time steps + virtual int stepSimulation( btScalar timeStep,int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.))=0; + + virtual void updateAabbs() = 0; + + virtual void addConstraint(btTypedConstraint* constraint, bool disableCollisionsBetweenLinkedBodies=false) { (void)constraint;}; + + virtual void removeConstraint(btTypedConstraint* constraint) {(void)constraint;}; + + virtual void addVehicle(btRaycastVehicle* vehicle) {(void)vehicle;}; + + virtual void removeVehicle(btRaycastVehicle* vehicle) {(void)vehicle;}; + + + virtual void setDebugDrawer(btIDebugDraw* debugDrawer) = 0; + + virtual btIDebugDraw* getDebugDrawer() = 0; + + //once a rigidbody is added to the dynamics world, it will get this gravity assigned + //existing rigidbodies in the world get gravity assigned too, during this method + virtual void setGravity(const btVector3& gravity) = 0; + + virtual void addRigidBody(btRigidBody* body) = 0; + + virtual void removeRigidBody(btRigidBody* body) = 0; + + virtual void setConstraintSolver(btConstraintSolver* solver) = 0; + + virtual int getNumConstraints() const { return 0; } + + virtual btTypedConstraint* getConstraint(int index) { (void)index; return 0; } + + virtual const btTypedConstraint* getConstraint(int index) const { (void)index; return 0; } + +}; + +#endif //BT_DYNAMICS_WORLD_H + diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp new file mode 100644 index 00000000000..02cf44d0cfa --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp @@ -0,0 +1,345 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btRigidBody.h" +#include "BulletCollision/CollisionShapes/btConvexShape.h" +#include "LinearMath/btMinMax.h" +#include "LinearMath/btTransformUtil.h" +#include "LinearMath/btMotionState.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" + +btScalar gLinearAirDamping = btScalar(1.); +//'temporarily' global variables +btScalar gDeactivationTime = btScalar(2.); +bool gDisableDeactivation = false; + +btScalar gLinearSleepingThreshold = btScalar(0.8); +btScalar gAngularSleepingThreshold = btScalar(1.0); +static int uniqueId = 0; + +btRigidBody::btRigidBody(btScalar mass, btMotionState* motionState, btCollisionShape* collisionShape, const btVector3& localInertia,btScalar linearDamping,btScalar angularDamping,btScalar friction,btScalar restitution) +: + m_linearVelocity(btScalar(0.0), btScalar(0.0), btScalar(0.0)), + m_angularVelocity(btScalar(0.),btScalar(0.),btScalar(0.)), + m_angularFactor(btScalar(1.)), + m_gravity(btScalar(0.0), btScalar(0.0), btScalar(0.0)), + m_totalForce(btScalar(0.0), btScalar(0.0), btScalar(0.0)), + m_totalTorque(btScalar(0.0), btScalar(0.0), btScalar(0.0)), + m_linearDamping(btScalar(0.)), + m_angularDamping(btScalar(0.5)), + m_optionalMotionState(motionState), + m_contactSolverType(0), + m_frictionSolverType(0) +{ + + if (motionState) + { + motionState->getWorldTransform(m_worldTransform); + } else + { + m_worldTransform = btTransform::getIdentity(); + } + + m_interpolationWorldTransform = m_worldTransform; + m_interpolationLinearVelocity.setValue(0,0,0); + m_interpolationAngularVelocity.setValue(0,0,0); + + //moved to btCollisionObject + m_friction = friction; + m_restitution = restitution; + + m_collisionShape = collisionShape; + m_debugBodyId = uniqueId++; + + //m_internalOwner is to allow upcasting from collision object to rigid body + m_internalOwner = this; + + setMassProps(mass, localInertia); + setDamping(linearDamping, angularDamping); + updateInertiaTensor(); + +} + +#ifdef OBSOLETE_MOTIONSTATE_LESS +btRigidBody::btRigidBody( btScalar mass,const btTransform& worldTransform,btCollisionShape* collisionShape,const btVector3& localInertia,btScalar linearDamping,btScalar angularDamping,btScalar friction,btScalar restitution) +: + m_gravity(btScalar(0.0), btScalar(0.0), btScalar(0.0)), + m_totalForce(btScalar(0.0), btScalar(0.0), btScalar(0.0)), + m_totalTorque(btScalar(0.0), btScalar(0.0), btScalar(0.0)), + m_linearVelocity(btScalar(0.0), btScalar(0.0), btScalar(0.0)), + m_angularVelocity(btScalar(0.),btScalar(0.),btScalar(0.)), + m_linearDamping(btScalar(0.)), + m_angularDamping(btScalar(0.5)), + m_optionalMotionState(0), + m_contactSolverType(0), + m_frictionSolverType(0) +{ + + m_worldTransform = worldTransform; + m_interpolationWorldTransform = m_worldTransform; + m_interpolationLinearVelocity.setValue(0,0,0); + m_interpolationAngularVelocity.setValue(0,0,0); + + //moved to btCollisionObject + m_friction = friction; + m_restitution = restitution; + + m_collisionShape = collisionShape; + m_debugBodyId = uniqueId++; + + //m_internalOwner is to allow upcasting from collision object to rigid body + m_internalOwner = this; + + setMassProps(mass, localInertia); + setDamping(linearDamping, angularDamping); + updateInertiaTensor(); + +} + +#endif //OBSOLETE_MOTIONSTATE_LESS + + + + +//#define EXPERIMENTAL_JITTER_REMOVAL 1 +#ifdef EXPERIMENTAL_JITTER_REMOVAL +//Bullet 2.20b has experimental damping code to reduce jitter just before objects fall asleep/deactivate +//doesn't work very well yet (value 0 disabled this damping) +//note there this influences deactivation thresholds! +btScalar gClippedAngvelThresholdSqr = btScalar(0.01); +btScalar gClippedLinearThresholdSqr = btScalar(0.01); +#endif //EXPERIMENTAL_JITTER_REMOVAL + +btScalar gJitterVelocityDampingFactor = btScalar(0.7); + +void btRigidBody::predictIntegratedTransform(btScalar timeStep,btTransform& predictedTransform) +{ + +#ifdef EXPERIMENTAL_JITTER_REMOVAL + //if (wantsSleeping()) + { + //clip to avoid jitter + if ((m_angularVelocity.length2() < gClippedAngvelThresholdSqr) && + (m_linearVelocity.length2() < gClippedLinearThresholdSqr)) + { + m_angularVelocity *= gJitterVelocityDampingFactor; + m_linearVelocity *= gJitterVelocityDampingFactor; + } + } + +#endif //EXPERIMENTAL_JITTER_REMOVAL + + btTransformUtil::integrateTransform(m_worldTransform,m_linearVelocity,m_angularVelocity,timeStep,predictedTransform); +} + +void btRigidBody::saveKinematicState(btScalar timeStep) +{ + //todo: clamp to some (user definable) safe minimum timestep, to limit maximum angular/linear velocities + if (timeStep != btScalar(0.)) + { + //if we use motionstate to synchronize world transforms, get the new kinematic/animated world transform + if (getMotionState()) + getMotionState()->getWorldTransform(m_worldTransform); + btVector3 linVel,angVel; + + btTransformUtil::calculateVelocity(m_interpolationWorldTransform,m_worldTransform,timeStep,m_linearVelocity,m_angularVelocity); + m_interpolationLinearVelocity = m_linearVelocity; + m_interpolationAngularVelocity = m_angularVelocity; + m_interpolationWorldTransform = m_worldTransform; + //printf("angular = %f %f %f\n",m_angularVelocity.getX(),m_angularVelocity.getY(),m_angularVelocity.getZ()); + } +} + +void btRigidBody::getAabb(btVector3& aabbMin,btVector3& aabbMax) const +{ + getCollisionShape()->getAabb(m_worldTransform,aabbMin,aabbMax); +} + + + + +void btRigidBody::setGravity(const btVector3& acceleration) +{ + if (m_inverseMass != btScalar(0.0)) + { + m_gravity = acceleration * (btScalar(1.0) / m_inverseMass); + } +} + + + + + + +void btRigidBody::setDamping(btScalar lin_damping, btScalar ang_damping) +{ + m_linearDamping = GEN_clamped(lin_damping, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); + m_angularDamping = GEN_clamped(ang_damping, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); +} + + + +#include + + +void btRigidBody::applyForces(btScalar step) +{ + if (isStaticOrKinematicObject()) + return; + + applyCentralForce(m_gravity); + + m_linearVelocity *= GEN_clamped((btScalar(1.) - step * gLinearAirDamping * m_linearDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); + m_angularVelocity *= GEN_clamped((btScalar(1.) - step * m_angularDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); + +#define FORCE_VELOCITY_DAMPING 1 +#ifdef FORCE_VELOCITY_DAMPING + btScalar speed = m_linearVelocity.length(); + if (speed < m_linearDamping) + { + btScalar dampVel = btScalar(0.005); + if (speed > dampVel) + { + btVector3 dir = m_linearVelocity.normalized(); + m_linearVelocity -= dir * dampVel; + } else + { + m_linearVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); + } + } + + btScalar angSpeed = m_angularVelocity.length(); + if (angSpeed < m_angularDamping) + { + btScalar angDampVel = btScalar(0.005); + if (angSpeed > angDampVel) + { + btVector3 dir = m_angularVelocity.normalized(); + m_angularVelocity -= dir * angDampVel; + } else + { + m_angularVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); + } + } +#endif //FORCE_VELOCITY_DAMPING + +} + +void btRigidBody::proceedToTransform(const btTransform& newTrans) +{ + setCenterOfMassTransform( newTrans ); +} + + +void btRigidBody::setMassProps(btScalar mass, const btVector3& inertia) +{ + if (mass == btScalar(0.)) + { + m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT; + m_inverseMass = btScalar(0.); + } else + { + m_collisionFlags &= (~btCollisionObject::CF_STATIC_OBJECT); + m_inverseMass = btScalar(1.0) / mass; + } + + m_invInertiaLocal.setValue(inertia.x() != btScalar(0.0) ? btScalar(1.0) / inertia.x(): btScalar(0.0), + inertia.y() != btScalar(0.0) ? btScalar(1.0) / inertia.y(): btScalar(0.0), + inertia.z() != btScalar(0.0) ? btScalar(1.0) / inertia.z(): btScalar(0.0)); + +} + + + +void btRigidBody::updateInertiaTensor() +{ + m_invInertiaTensorWorld = m_worldTransform.getBasis().scaled(m_invInertiaLocal) * m_worldTransform.getBasis().transpose(); +} + + +void btRigidBody::integrateVelocities(btScalar step) +{ + if (isStaticOrKinematicObject()) + return; + + m_linearVelocity += m_totalForce * (m_inverseMass * step); + m_angularVelocity += m_invInertiaTensorWorld * m_totalTorque * step; + +#define MAX_ANGVEL SIMD_HALF_PI + /// clamp angular velocity. collision calculations will fail on higher angular velocities + btScalar angvel = m_angularVelocity.length(); + if (angvel*step > MAX_ANGVEL) + { + m_angularVelocity *= (MAX_ANGVEL/step) /angvel; + } + + clearForces(); +} + +btQuaternion btRigidBody::getOrientation() const +{ + btQuaternion orn; + m_worldTransform.getBasis().getRotation(orn); + return orn; +} + + +void btRigidBody::setCenterOfMassTransform(const btTransform& xform) +{ + + if (isStaticOrKinematicObject()) + { + m_interpolationWorldTransform = m_worldTransform; + } else + { + m_interpolationWorldTransform = xform; + } + m_interpolationLinearVelocity = getLinearVelocity(); + m_interpolationAngularVelocity = getAngularVelocity(); + m_worldTransform = xform; + updateInertiaTensor(); +} + + +bool btRigidBody::checkCollideWithOverride(btCollisionObject* co) +{ + btRigidBody* otherRb = btRigidBody::upcast(co); + if (!otherRb) + return true; + + for (int i = 0; i < m_constraintRefs.size(); ++i) + { + btTypedConstraint* c = m_constraintRefs[i]; + if (&c->getRigidBodyA() == otherRb || &c->getRigidBodyB() == otherRb) + return false; + } + + return true; +} + +void btRigidBody::addConstraintRef(btTypedConstraint* c) +{ + int index = m_constraintRefs.findLinearSearch(c); + if (index == m_constraintRefs.size()) + m_constraintRefs.push_back(c); + + m_checkCollideWith = true; +} + +void btRigidBody::removeConstraintRef(btTypedConstraint* c) +{ + m_constraintRefs.remove(c); + m_checkCollideWith = m_constraintRefs.size() > 0; +} \ No newline at end of file diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h new file mode 100644 index 00000000000..0707595d48e --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h @@ -0,0 +1,357 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef RIGIDBODY_H +#define RIGIDBODY_H + +#include "../../LinearMath/btAlignedObjectArray.h" +#include "../../LinearMath/btPoint3.h" +#include "../../LinearMath/btTransform.h" +#include "../../BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" +#include "../../BulletCollision/CollisionDispatch/btCollisionObject.h" + +class btCollisionShape; +class btMotionState; +class btTypedConstraint; + + +extern btScalar gLinearAirDamping; + +extern btScalar gDeactivationTime; +extern bool gDisableDeactivation; +extern btScalar gLinearSleepingThreshold; +extern btScalar gAngularSleepingThreshold; + + +/// btRigidBody class for btRigidBody Dynamics +/// +class btRigidBody : public btCollisionObject +{ + + btMatrix3x3 m_invInertiaTensorWorld; + btVector3 m_linearVelocity; + btVector3 m_angularVelocity; + btScalar m_inverseMass; + btScalar m_angularFactor; + + btVector3 m_gravity; + btVector3 m_invInertiaLocal; + btVector3 m_totalForce; + btVector3 m_totalTorque; + + btScalar m_linearDamping; + btScalar m_angularDamping; + + + //m_optionalMotionState allows to automatic synchronize the world transform for active objects + btMotionState* m_optionalMotionState; + + //keep track of typed constraints referencing this rigid body + btAlignedObjectArray m_constraintRefs; + +public: + +#ifdef OBSOLETE_MOTIONSTATE_LESS + //not supported, please use btMotionState + btRigidBody(btScalar mass, const btTransform& worldTransform, btCollisionShape* collisionShape, const btVector3& localInertia=btVector3(0,0,0),btScalar linearDamping=btScalar(0.),btScalar angularDamping=btScalar(0.),btScalar friction=btScalar(0.5),btScalar restitution=btScalar(0.)); +#endif //OBSOLETE_MOTIONSTATE_LESS + + btRigidBody(btScalar mass, btMotionState* motionState, btCollisionShape* collisionShape, const btVector3& localInertia=btVector3(0,0,0),btScalar linearDamping=btScalar(0.),btScalar angularDamping=btScalar(0.),btScalar friction=btScalar(0.5),btScalar restitution=btScalar(0.)); + + void proceedToTransform(const btTransform& newTrans); + + ///to keep collision detection and dynamics separate we don't store a rigidbody pointer + ///but a rigidbody is derived from btCollisionObject, so we can safely perform an upcast + static const btRigidBody* upcast(const btCollisionObject* colObj) + { + return (const btRigidBody*)colObj->getInternalOwner(); + } + static btRigidBody* upcast(btCollisionObject* colObj) + { + return (btRigidBody*)colObj->getInternalOwner(); + } + + /// continuous collision detection needs prediction + void predictIntegratedTransform(btScalar step, btTransform& predictedTransform) ; + + void saveKinematicState(btScalar step); + + + void applyForces(btScalar step); + + void setGravity(const btVector3& acceleration); + + const btVector3& getGravity() const + { + return m_gravity; + } + + void setDamping(btScalar lin_damping, btScalar ang_damping); + + inline const btCollisionShape* getCollisionShape() const { + return m_collisionShape; + } + + inline btCollisionShape* getCollisionShape() { + return m_collisionShape; + } + + void setMassProps(btScalar mass, const btVector3& inertia); + + btScalar getInvMass() const { return m_inverseMass; } + const btMatrix3x3& getInvInertiaTensorWorld() const { + return m_invInertiaTensorWorld; + } + + void integrateVelocities(btScalar step); + + void setCenterOfMassTransform(const btTransform& xform); + + void applyCentralForce(const btVector3& force) + { + m_totalForce += force; + } + + const btVector3& getInvInertiaDiagLocal() + { + return m_invInertiaLocal; + }; + + void setInvInertiaDiagLocal(const btVector3& diagInvInertia) + { + m_invInertiaLocal = diagInvInertia; + } + + void applyTorque(const btVector3& torque) + { + m_totalTorque += torque; + } + + void applyForce(const btVector3& force, const btVector3& rel_pos) + { + applyCentralForce(force); + applyTorque(rel_pos.cross(force)); + } + + void applyCentralImpulse(const btVector3& impulse) + { + m_linearVelocity += impulse * m_inverseMass; + } + + void applyTorqueImpulse(const btVector3& torque) + { + m_angularVelocity += m_invInertiaTensorWorld * torque; + } + + void applyImpulse(const btVector3& impulse, const btVector3& rel_pos) + { + if (m_inverseMass != btScalar(0.)) + { + applyCentralImpulse(impulse); + if (m_angularFactor) + { + applyTorqueImpulse(rel_pos.cross(impulse)*m_angularFactor); + } + } + } + + //Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position + inline void internalApplyImpulse(const btVector3& linearComponent, const btVector3& angularComponent,btScalar impulseMagnitude) + { + if (m_inverseMass != btScalar(0.)) + { + m_linearVelocity += linearComponent*impulseMagnitude; + if (m_angularFactor) + { + m_angularVelocity += angularComponent*impulseMagnitude*m_angularFactor; + } + } + } + + void clearForces() + { + m_totalForce.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); + m_totalTorque.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); + } + + void updateInertiaTensor(); + + const btPoint3& getCenterOfMassPosition() const { + return m_worldTransform.getOrigin(); + } + btQuaternion getOrientation() const; + + const btTransform& getCenterOfMassTransform() const { + return m_worldTransform; + } + const btVector3& getLinearVelocity() const { + return m_linearVelocity; + } + const btVector3& getAngularVelocity() const { + return m_angularVelocity; + } + + + inline void setLinearVelocity(const btVector3& lin_vel) + { + assert (m_collisionFlags != btCollisionObject::CF_STATIC_OBJECT); + m_linearVelocity = lin_vel; + } + + inline void setAngularVelocity(const btVector3& ang_vel) { + assert (m_collisionFlags != btCollisionObject::CF_STATIC_OBJECT); + { + m_angularVelocity = ang_vel; + } + } + + btVector3 getVelocityInLocalPoint(const btVector3& rel_pos) const + { + //we also calculate lin/ang velocity for kinematic objects + return m_linearVelocity + m_angularVelocity.cross(rel_pos); + + //for kinematic objects, we could also use use: + // return (m_worldTransform(rel_pos) - m_interpolationWorldTransform(rel_pos)) / m_kinematicTimeStep; + } + + void translate(const btVector3& v) + { + m_worldTransform.getOrigin() += v; + } + + + void getAabb(btVector3& aabbMin,btVector3& aabbMax) const; + + + + + + inline btScalar computeImpulseDenominator(const btPoint3& pos, const btVector3& normal) const + { + btVector3 r0 = pos - getCenterOfMassPosition(); + + btVector3 c0 = (r0).cross(normal); + + btVector3 vec = (c0 * getInvInertiaTensorWorld()).cross(r0); + + return m_inverseMass + normal.dot(vec); + + } + + inline btScalar computeAngularImpulseDenominator(const btVector3& axis) const + { + btVector3 vec = axis * getInvInertiaTensorWorld(); + return axis.dot(vec); + } + + inline void updateDeactivation(btScalar timeStep) + { + if ( (getActivationState() == ISLAND_SLEEPING) || (getActivationState() == DISABLE_DEACTIVATION)) + return; + + if ((getLinearVelocity().length2() < gLinearSleepingThreshold*gLinearSleepingThreshold) && + (getAngularVelocity().length2() < gAngularSleepingThreshold*gAngularSleepingThreshold)) + { + m_deactivationTime += timeStep; + } else + { + m_deactivationTime=btScalar(0.); + setActivationState(0); + } + + } + + inline bool wantsSleeping() + { + + if (getActivationState() == DISABLE_DEACTIVATION) + return false; + + //disable deactivation + if (gDisableDeactivation || (gDeactivationTime == btScalar(0.))) + return false; + + if ( (getActivationState() == ISLAND_SLEEPING) || (getActivationState() == WANTS_DEACTIVATION)) + return true; + + if (m_deactivationTime> gDeactivationTime) + { + return true; + } + return false; + } + + + + const btBroadphaseProxy* getBroadphaseProxy() const + { + return m_broadphaseHandle; + } + btBroadphaseProxy* getBroadphaseProxy() + { + return m_broadphaseHandle; + } + void setNewBroadphaseProxy(btBroadphaseProxy* broadphaseProxy) + { + m_broadphaseHandle = broadphaseProxy; + } + + //btMotionState allows to automatic synchronize the world transform for active objects + btMotionState* getMotionState() + { + return m_optionalMotionState; + } + const btMotionState* getMotionState() const + { + return m_optionalMotionState; + } + void setMotionState(btMotionState* motionState) + { + m_optionalMotionState = motionState; + if (m_optionalMotionState) + motionState->getWorldTransform(m_worldTransform); + } + + //for experimental overriding of friction/contact solver func + int m_contactSolverType; + int m_frictionSolverType; + + void setAngularFactor(btScalar angFac) + { + m_angularFactor = angFac; + } + btScalar getAngularFactor() const + { + return m_angularFactor; + } + + //is this rigidbody added to a btCollisionWorld/btDynamicsWorld/btBroadphase? + bool isInWorld() const + { + return (getBroadphaseProxy() != 0); + } + + virtual bool checkCollideWithOverride(btCollisionObject* co); + + void addConstraintRef(btTypedConstraint* c); + void removeConstraintRef(btTypedConstraint* c); + + int m_debugBodyId; +}; + + + +#endif + diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp new file mode 100644 index 00000000000..4ebcb8e7517 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp @@ -0,0 +1,211 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btSimpleDynamicsWorld.h" +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" +#include "BulletCollision/CollisionShapes/btCollisionShape.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" +#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" + + +/* + Make sure this dummy function never changes so that it + can be used by probes that are checking whether the + library is actually installed. +*/ +extern "C" void btBulletDynamicsProbe () {} + + + + +btSimpleDynamicsWorld::btSimpleDynamicsWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache,btConstraintSolver* constraintSolver) +:btDynamicsWorld(dispatcher,pairCache), +m_constraintSolver(constraintSolver), +m_ownsConstraintSolver(false), +m_debugDrawer(0), +m_gravity(0,0,-10) +{ + +} + + +btSimpleDynamicsWorld::~btSimpleDynamicsWorld() +{ + if (m_ownsConstraintSolver) + delete m_constraintSolver; +} + +int btSimpleDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep) +{ + (void)fixedTimeStep; + (void)maxSubSteps; + + + ///apply gravity, predict motion + predictUnconstraintMotion(timeStep); + + btDispatcherInfo& dispatchInfo = getDispatchInfo(); + dispatchInfo.m_timeStep = timeStep; + dispatchInfo.m_stepCount = 0; + dispatchInfo.m_debugDraw = getDebugDrawer(); + + ///perform collision detection + performDiscreteCollisionDetection(); + + ///solve contact constraints + int numManifolds = m_dispatcher1->getNumManifolds(); + if (numManifolds) + { + btPersistentManifold** manifoldPtr = ((btCollisionDispatcher*)m_dispatcher1)->getInternalManifoldPointer(); + + btContactSolverInfo infoGlobal; + infoGlobal.m_timeStep = timeStep; + + m_constraintSolver->solveGroup(0,0,manifoldPtr, numManifolds,0,0,infoGlobal,m_debugDrawer, m_stackAlloc); + } + + ///integrate transforms + integrateTransforms(timeStep); + + updateAabbs(); + + synchronizeMotionStates(); + + return 1; + +} + + +void btSimpleDynamicsWorld::setGravity(const btVector3& gravity) +{ + m_gravity = gravity; + for ( int i=0;isetGravity(gravity); + } + } +} + +void btSimpleDynamicsWorld::removeRigidBody(btRigidBody* body) +{ + removeCollisionObject(body); +} + +void btSimpleDynamicsWorld::addRigidBody(btRigidBody* body) +{ + body->setGravity(m_gravity); + + if (body->getCollisionShape()) + { + addCollisionObject(body); + } +} + +void btSimpleDynamicsWorld::updateAabbs() +{ + btTransform predictedTrans; + for ( int i=0;iisActive() && (!body->isStaticObject())) + { + btPoint3 minAabb,maxAabb; + colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb); + btBroadphaseInterface* bp = getBroadphase(); + bp->setAabb(body->getBroadphaseHandle(),minAabb,maxAabb); + } + } + } +} + +void btSimpleDynamicsWorld::integrateTransforms(btScalar timeStep) +{ + btTransform predictedTrans; + for ( int i=0;iisActive() && (!body->isStaticObject())) + { + body->predictIntegratedTransform(timeStep, predictedTrans); + body->proceedToTransform( predictedTrans); + } + } + } +} + + + +void btSimpleDynamicsWorld::predictUnconstraintMotion(btScalar timeStep) +{ + for ( int i=0;iisStaticObject()) + { + if (body->isActive()) + { + body->applyForces( timeStep); + body->integrateVelocities( timeStep); + body->predictIntegratedTransform(timeStep,body->getInterpolationWorldTransform()); + } + } + } + } +} + + +void btSimpleDynamicsWorld::synchronizeMotionStates() +{ + //todo: iterate over awake simulation islands! + for ( int i=0;igetMotionState()) + { + if (body->getActivationState() != ISLAND_SLEEPING) + { + body->getMotionState()->setWorldTransform(body->getWorldTransform()); + } + } + } + +} + + +void btSimpleDynamicsWorld::setConstraintSolver(btConstraintSolver* solver) +{ + if (m_ownsConstraintSolver) + { + delete m_constraintSolver; + } + m_ownsConstraintSolver = false; + m_constraintSolver = solver; +} diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h b/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h new file mode 100644 index 00000000000..25f4ccd8e68 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h @@ -0,0 +1,82 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_SIMPLE_DYNAMICS_WORLD_H +#define BT_SIMPLE_DYNAMICS_WORLD_H + +#include "btDynamicsWorld.h" + +class btDispatcher; +class btOverlappingPairCache; +class btConstraintSolver; + +///btSimpleDynamicsWorld demonstrates very basic usage of Bullet rigid body dynamics +///It can be used for basic simulations, and as a starting point for porting Bullet +///btSimpleDynamicsWorld lacks object deactivation, island management and other concepts. +///For more complicated simulations, btDiscreteDynamicsWorld and btContinuousDynamicsWorld are recommended +///those classes replace the obsolete CcdPhysicsEnvironment/CcdPhysicsController +class btSimpleDynamicsWorld : public btDynamicsWorld +{ +protected: + + btConstraintSolver* m_constraintSolver; + + bool m_ownsConstraintSolver; + + btIDebugDraw* m_debugDrawer; + + void predictUnconstraintMotion(btScalar timeStep); + + void integrateTransforms(btScalar timeStep); + + btVector3 m_gravity; + +public: + + + + ///this btSimpleDynamicsWorld constructor creates dispatcher, broadphase pairCache and constraintSolver + btSimpleDynamicsWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache,btConstraintSolver* constraintSolver); + + virtual ~btSimpleDynamicsWorld(); + + ///maxSubSteps/fixedTimeStep for interpolation is currently ignored for btSimpleDynamicsWorld, use btDiscreteDynamicsWorld instead + virtual int stepSimulation( btScalar timeStep,int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.)); + + virtual void setDebugDrawer(btIDebugDraw* debugDrawer) + { + m_debugDrawer = debugDrawer; + }; + + virtual btIDebugDraw* getDebugDrawer() + { + return m_debugDrawer; + } + + virtual void setGravity(const btVector3& gravity); + + virtual void addRigidBody(btRigidBody* body); + + virtual void removeRigidBody(btRigidBody* body); + + virtual void updateAabbs(); + + void synchronizeMotionStates(); + + virtual void setConstraintSolver(btConstraintSolver* solver); + +}; + +#endif //BT_SIMPLE_DYNAMICS_WORLD_H diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp b/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp new file mode 100644 index 00000000000..d53de7f3687 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp @@ -0,0 +1,733 @@ +/* + * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. + * It is provided "as is" without express or implied warranty. +*/ + +#include "LinearMath/btVector3.h" +#include "btRaycastVehicle.h" + +#include "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h" +#include "BulletDynamics/ConstraintSolver/btJacobianEntry.h" +#include "LinearMath/btQuaternion.h" +#include "BulletDynamics/Dynamics/btDynamicsWorld.h" +#include "btVehicleRaycaster.h" +#include "btWheelInfo.h" +#include "LinearMath/btMinMax.h" + + +#include "BulletDynamics/ConstraintSolver/btContactConstraint.h" + + + +static btRigidBody s_fixedObject( 0,0,0); + +btRaycastVehicle::btRaycastVehicle(const btVehicleTuning& tuning,btRigidBody* chassis, btVehicleRaycaster* raycaster ) +:m_vehicleRaycaster(raycaster), +m_pitchControl(btScalar(0.)) +{ + m_chassisBody = chassis; + m_indexRightAxis = 0; + m_indexUpAxis = 2; + m_indexForwardAxis = 1; + defaultInit(tuning); +} + + +void btRaycastVehicle::defaultInit(const btVehicleTuning& tuning) +{ + (void)tuning; + m_currentVehicleSpeedKmHour = btScalar(0.); + m_steeringValue = btScalar(0.); + +} + + + +btRaycastVehicle::~btRaycastVehicle() +{ +} + + +// +// basically most of the code is general for 2 or 4 wheel vehicles, but some of it needs to be reviewed +// +btWheelInfo& btRaycastVehicle::addWheel( const btVector3& connectionPointCS, const btVector3& wheelDirectionCS0,const btVector3& wheelAxleCS, btScalar suspensionRestLength, btScalar wheelRadius,const btVehicleTuning& tuning, bool isFrontWheel) +{ + + btWheelInfoConstructionInfo ci; + + ci.m_chassisConnectionCS = connectionPointCS; + ci.m_wheelDirectionCS = wheelDirectionCS0; + ci.m_wheelAxleCS = wheelAxleCS; + ci.m_suspensionRestLength = suspensionRestLength; + ci.m_wheelRadius = wheelRadius; + ci.m_suspensionStiffness = tuning.m_suspensionStiffness; + ci.m_wheelsDampingCompression = tuning.m_suspensionCompression; + ci.m_wheelsDampingRelaxation = tuning.m_suspensionDamping; + ci.m_frictionSlip = tuning.m_frictionSlip; + ci.m_bIsFrontWheel = isFrontWheel; + ci.m_maxSuspensionTravelCm = tuning.m_maxSuspensionTravelCm; + + m_wheelInfo.push_back( btWheelInfo(ci)); + + btWheelInfo& wheel = m_wheelInfo[getNumWheels()-1]; + + updateWheelTransformsWS( wheel , false ); + updateWheelTransform(getNumWheels()-1,false); + return wheel; +} + + + + +const btTransform& btRaycastVehicle::getWheelTransformWS( int wheelIndex ) const +{ + assert(wheelIndex < getNumWheels()); + const btWheelInfo& wheel = m_wheelInfo[wheelIndex]; + return wheel.m_worldTransform; + +} + +void btRaycastVehicle::updateWheelTransform( int wheelIndex , bool interpolatedTransform) +{ + + btWheelInfo& wheel = m_wheelInfo[ wheelIndex ]; + updateWheelTransformsWS(wheel,interpolatedTransform); + btVector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS; + const btVector3& right = wheel.m_raycastInfo.m_wheelAxleWS; + btVector3 fwd = up.cross(right); + fwd = fwd.normalize(); +// up = right.cross(fwd); +// up.normalize(); + + //rotate around steering over de wheelAxleWS + btScalar steering = wheel.m_steering; + + btQuaternion steeringOrn(up,steering);//wheel.m_steering); + btMatrix3x3 steeringMat(steeringOrn); + + btQuaternion rotatingOrn(right,-wheel.m_rotation); + btMatrix3x3 rotatingMat(rotatingOrn); + + btMatrix3x3 basis2( + right[0],fwd[0],up[0], + right[1],fwd[1],up[1], + right[2],fwd[2],up[2] + ); + + wheel.m_worldTransform.setBasis(steeringMat * rotatingMat * basis2); + wheel.m_worldTransform.setOrigin( + wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength + ); +} + +void btRaycastVehicle::resetSuspension() +{ + + int i; + for (i=0;igetMotionState())) + { + getRigidBody()->getMotionState()->getWorldTransform(chassisTrans); + } + + wheel.m_raycastInfo.m_hardPointWS = chassisTrans( wheel.m_chassisConnectionPointCS ); + wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.getBasis() * wheel.m_wheelDirectionCS ; + wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.getBasis() * wheel.m_wheelAxleCS; +} + +btScalar btRaycastVehicle::rayCast(btWheelInfo& wheel) +{ + updateWheelTransformsWS( wheel,false); + + + btScalar depth = -1; + + btScalar raylen = wheel.getSuspensionRestLength()+wheel.m_wheelsRadius; + + btVector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen); + const btVector3& source = wheel.m_raycastInfo.m_hardPointWS; + wheel.m_raycastInfo.m_contactPointWS = source + rayvector; + const btVector3& target = wheel.m_raycastInfo.m_contactPointWS; + + btScalar param = btScalar(0.); + + btVehicleRaycaster::btVehicleRaycasterResult rayResults; + + assert(m_vehicleRaycaster); + + void* object = m_vehicleRaycaster->castRay(source,target,rayResults); + + wheel.m_raycastInfo.m_groundObject = 0; + + if (object) + { + param = rayResults.m_distFraction; + depth = raylen * rayResults.m_distFraction; + wheel.m_raycastInfo.m_contactNormalWS = rayResults.m_hitNormalInWorld; + wheel.m_raycastInfo.m_isInContact = true; + + wheel.m_raycastInfo.m_groundObject = &s_fixedObject;//todo for driving on dynamic/movable objects!; + //wheel.m_raycastInfo.m_groundObject = object; + + + btScalar hitDistance = param*raylen; + wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelsRadius; + //clamp on max suspension travel + + btScalar minSuspensionLength = wheel.getSuspensionRestLength() - wheel.m_maxSuspensionTravelCm*btScalar(0.01); + btScalar maxSuspensionLength = wheel.getSuspensionRestLength()+ wheel.m_maxSuspensionTravelCm*btScalar(0.01); + if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength) + { + wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength; + } + if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength) + { + wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength; + } + + wheel.m_raycastInfo.m_contactPointWS = rayResults.m_hitPointInWorld; + + btScalar denominator= wheel.m_raycastInfo.m_contactNormalWS.dot( wheel.m_raycastInfo.m_wheelDirectionWS ); + + btVector3 chassis_velocity_at_contactPoint; + btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition(); + + chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos); + + btScalar projVel = wheel.m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint ); + + if ( denominator >= btScalar(-0.1)) + { + wheel.m_suspensionRelativeVelocity = btScalar(0.0); + wheel.m_clippedInvContactDotSuspension = btScalar(1.0) / btScalar(0.1); + } + else + { + btScalar inv = btScalar(-1.) / denominator; + wheel.m_suspensionRelativeVelocity = projVel * inv; + wheel.m_clippedInvContactDotSuspension = inv; + } + + } else + { + //put wheel info as in rest position + wheel.m_raycastInfo.m_suspensionLength = wheel.getSuspensionRestLength(); + wheel.m_suspensionRelativeVelocity = btScalar(0.0); + wheel.m_raycastInfo.m_contactNormalWS = - wheel.m_raycastInfo.m_wheelDirectionWS; + wheel.m_clippedInvContactDotSuspension = btScalar(1.0); + } + + return depth; +} + + +const btTransform& btRaycastVehicle::getChassisWorldTransform() const +{ + /*if (getRigidBody()->getMotionState()) + { + btTransform chassisWorldTrans; + getRigidBody()->getMotionState()->getWorldTransform(chassisWorldTrans); + return chassisWorldTrans; + } + */ + + + return getRigidBody()->getCenterOfMassTransform(); +} + + +void btRaycastVehicle::updateVehicle( btScalar step ) +{ + { + for (int i=0;igetLinearVelocity().length(); + + const btTransform& chassisTrans = getChassisWorldTransform(); + + btVector3 forwardW ( + chassisTrans.getBasis()[0][m_indexForwardAxis], + chassisTrans.getBasis()[1][m_indexForwardAxis], + chassisTrans.getBasis()[2][m_indexForwardAxis]); + + if (forwardW.dot(getRigidBody()->getLinearVelocity()) < btScalar(0.)) + { + m_currentVehicleSpeedKmHour *= btScalar(-1.); + } + + // + // simulate suspension + // + + int i=0; + for (i=0;i gMaxSuspensionForce) + { + suspensionForce = gMaxSuspensionForce; + } + btVector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step; + btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition(); + + getRigidBody()->applyImpulse(impulse, relpos); + + } + + + + updateFriction( step); + + + for (i=0;igetCenterOfMassPosition(); + btVector3 vel = getRigidBody()->getVelocityInLocalPoint( relpos ); + + if (wheel.m_raycastInfo.m_isInContact) + { + const btTransform& chassisWorldTransform = getChassisWorldTransform(); + + btVector3 fwd ( + chassisWorldTransform.getBasis()[0][m_indexForwardAxis], + chassisWorldTransform.getBasis()[1][m_indexForwardAxis], + chassisWorldTransform.getBasis()[2][m_indexForwardAxis]); + + btScalar proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS); + fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj; + + btScalar proj2 = fwd.dot(vel); + + wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelsRadius); + wheel.m_rotation += wheel.m_deltaRotation; + + } else + { + wheel.m_rotation += wheel.m_deltaRotation; + } + + wheel.m_deltaRotation *= btScalar(0.99);//damping of rotation when not in contact + + } + + + +} + + +void btRaycastVehicle::setSteeringValue(btScalar steering,int wheel) +{ + assert(wheel>=0 && wheel < getNumWheels()); + + btWheelInfo& wheelInfo = getWheelInfo(wheel); + wheelInfo.m_steering = steering; +} + + + +btScalar btRaycastVehicle::getSteeringValue(int wheel) const +{ + return getWheelInfo(wheel).m_steering; +} + + +void btRaycastVehicle::applyEngineForce(btScalar force, int wheel) +{ + assert(wheel>=0 && wheel < getNumWheels()); + btWheelInfo& wheelInfo = getWheelInfo(wheel); + wheelInfo.m_engineForce = force; +} + + +const btWheelInfo& btRaycastVehicle::getWheelInfo(int index) const +{ + btAssert((index >= 0) && (index < getNumWheels())); + + return m_wheelInfo[index]; +} + +btWheelInfo& btRaycastVehicle::getWheelInfo(int index) +{ + btAssert((index >= 0) && (index < getNumWheels())); + + return m_wheelInfo[index]; +} + +void btRaycastVehicle::setBrake(btScalar brake,int wheelIndex) +{ + btAssert((wheelIndex >= 0) && (wheelIndex < getNumWheels())); + getWheelInfo(wheelIndex).m_brake = brake; +} + + +void btRaycastVehicle::updateSuspension(btScalar deltaTime) +{ + (void)deltaTime; + + btScalar chassisMass = btScalar(1.) / m_chassisBody->getInvMass(); + + for (int w_it=0; w_itcomputeImpulseDenominator(frictionPosWorld,frictionDirectionWorld); + btScalar denom1 = body1->computeImpulseDenominator(frictionPosWorld,frictionDirectionWorld); + btScalar relaxation = 1.f; + m_jacDiagABInv = relaxation/(denom0+denom1); + } + + + +}; + +btScalar calcRollingFriction(btWheelContactPoint& contactPoint) +{ + + btScalar j1=0.f; + + const btVector3& contactPosWorld = contactPoint.m_frictionPositionWorld; + + btVector3 rel_pos1 = contactPosWorld - contactPoint.m_body0->getCenterOfMassPosition(); + btVector3 rel_pos2 = contactPosWorld - contactPoint.m_body1->getCenterOfMassPosition(); + + btScalar maxImpulse = contactPoint.m_maxImpulse; + + btVector3 vel1 = contactPoint.m_body0->getVelocityInLocalPoint(rel_pos1); + btVector3 vel2 = contactPoint.m_body1->getVelocityInLocalPoint(rel_pos2); + btVector3 vel = vel1 - vel2; + + btScalar vrel = contactPoint.m_frictionDirectionWorld.dot(vel); + + // calculate j that moves us to zero relative velocity + j1 = -vrel * contactPoint.m_jacDiagABInv; + GEN_set_min(j1, maxImpulse); + GEN_set_max(j1, -maxImpulse); + + return j1; +} + + + + +btScalar sideFrictionStiffness2 = btScalar(1.0); +void btRaycastVehicle::updateFriction(btScalar timeStep) +{ + + //calculate the impulse, so that the wheels don't move sidewards + int numWheel = getNumWheels(); + if (!numWheel) + return; + + + btVector3* forwardWS = new btVector3[numWheel]; + btVector3* axle = new btVector3[numWheel]; + btScalar* forwardImpulse = new btScalar[numWheel]; + btScalar* sideImpulse = new btScalar[numWheel]; + + int numWheelsOnGround = 0; + + + //collapse all those loops into one! + for (int i=0;i maximpSquared) + { + sliding = true; + + btScalar factor = maximp / btSqrt(impulseSquared); + + m_wheelInfo[wheel].m_skidInfo *= factor; + } + } + + } + } + + + + + if (sliding) + { + for (int wheel = 0;wheel < getNumWheels(); wheel++) + { + if (sideImpulse[wheel] != btScalar(0.)) + { + if (m_wheelInfo[wheel].m_skidInfo< btScalar(1.)) + { + forwardImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo; + sideImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo; + } + } + } + } + + // apply the impulses + { + for (int wheel = 0;wheelgetCenterOfMassPosition(); + + if (forwardImpulse[wheel] != btScalar(0.)) + { + m_chassisBody->applyImpulse(forwardWS[wheel]*(forwardImpulse[wheel]),rel_pos); + } + if (sideImpulse[wheel] != btScalar(0.)) + { + class btRigidBody* groundObject = (class btRigidBody*) m_wheelInfo[wheel].m_raycastInfo.m_groundObject; + + btVector3 rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS - + groundObject->getCenterOfMassPosition(); + + + btVector3 sideImp = axle[wheel] * sideImpulse[wheel]; + + rel_pos[2] *= wheelInfo.m_rollInfluence; + m_chassisBody->applyImpulse(sideImp,rel_pos); + + //apply friction impulse on the ground + groundObject->applyImpulse(-sideImp,rel_pos2); + } + } + } + + delete []forwardWS; + delete [] axle; + delete[]forwardImpulse; + delete[] sideImpulse; +} + + +void* btDefaultVehicleRaycaster::castRay(const btVector3& from,const btVector3& to, btVehicleRaycasterResult& result) +{ +// RayResultCallback& resultCallback; + + btCollisionWorld::ClosestRayResultCallback rayCallback(from,to); + + m_dynamicsWorld->rayTest(from, to, rayCallback); + + if (rayCallback.HasHit()) + { + + btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject); + if (body) + { + result.m_hitPointInWorld = rayCallback.m_hitPointWorld; + result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld; + result.m_hitNormalInWorld.normalize(); + result.m_distFraction = rayCallback.m_closestHitFraction; + return body; + } + } + return 0; +} diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h b/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h new file mode 100644 index 00000000000..f4249599615 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. + * It is provided "as is" without express or implied warranty. +*/ +#ifndef RAYCASTVEHICLE_H +#define RAYCASTVEHICLE_H + +#include "../Dynamics/btRigidBody.h" +#include "../ConstraintSolver/btTypedConstraint.h" +#include "btVehicleRaycaster.h" +class btDynamicsWorld; +#include "../../LinearMath/btAlignedObjectArray.h" +#include "btWheelInfo.h" + +class btVehicleTuning; + +///rayCast vehicle, very special constraint that turn a rigidbody into a vehicle. +class btRaycastVehicle : public btTypedConstraint +{ +public: + class btVehicleTuning + { + public: + + btVehicleTuning() + :m_suspensionStiffness(btScalar(5.88)), + m_suspensionCompression(btScalar(0.83)), + m_suspensionDamping(btScalar(0.88)), + m_maxSuspensionTravelCm(btScalar(500.)), + m_frictionSlip(btScalar(10.5)) + { + } + btScalar m_suspensionStiffness; + btScalar m_suspensionCompression; + btScalar m_suspensionDamping; + btScalar m_maxSuspensionTravelCm; + btScalar m_frictionSlip; + + }; +private: + + btScalar m_tau; + btScalar m_damping; + btVehicleRaycaster* m_vehicleRaycaster; + btScalar m_pitchControl; + btScalar m_steeringValue; + btScalar m_currentVehicleSpeedKmHour; + + btRigidBody* m_chassisBody; + + int m_indexRightAxis; + int m_indexUpAxis; + int m_indexForwardAxis; + + void defaultInit(const btVehicleTuning& tuning); + +public: + + //constructor to create a car from an existing rigidbody + btRaycastVehicle(const btVehicleTuning& tuning,btRigidBody* chassis, btVehicleRaycaster* raycaster ); + + virtual ~btRaycastVehicle() ; + + + const btTransform& getChassisWorldTransform() const; + + btScalar rayCast(btWheelInfo& wheel); + + virtual void updateVehicle(btScalar step); + + void resetSuspension(); + + btScalar getSteeringValue(int wheel) const; + + void setSteeringValue(btScalar steering,int wheel); + + + void applyEngineForce(btScalar force, int wheel); + + const btTransform& getWheelTransformWS( int wheelIndex ) const; + + void updateWheelTransform( int wheelIndex, bool interpolatedTransform = true ); + + void setRaycastWheelInfo( int wheelIndex , bool isInContact, const btVector3& hitPoint, const btVector3& hitNormal,btScalar depth); + + btWheelInfo& addWheel( const btVector3& connectionPointCS0, const btVector3& wheelDirectionCS0,const btVector3& wheelAxleCS,btScalar suspensionRestLength,btScalar wheelRadius,const btVehicleTuning& tuning, bool isFrontWheel); + + inline int getNumWheels() const { + return int (m_wheelInfo.size()); + } + + btAlignedObjectArray m_wheelInfo; + + + const btWheelInfo& getWheelInfo(int index) const; + + btWheelInfo& getWheelInfo(int index); + + void updateWheelTransformsWS(btWheelInfo& wheel , bool interpolatedTransform = true); + + + void setBrake(btScalar brake,int wheelIndex); + + void setPitchControl(btScalar pitch) + { + m_pitchControl = pitch; + } + + void updateSuspension(btScalar deltaTime); + + void updateFriction(btScalar timeStep); + + + + inline btRigidBody* getRigidBody() + { + return m_chassisBody; + } + + const btRigidBody* getRigidBody() const + { + return m_chassisBody; + } + + inline int getRightAxis() const + { + return m_indexRightAxis; + } + inline int getUpAxis() const + { + return m_indexUpAxis; + } + + inline int getForwardAxis() const + { + return m_indexForwardAxis; + } + + + ///Worldspace forward vector + btVector3 getForwardVector() const + { + const btTransform& chassisTrans = getChassisWorldTransform(); + + btVector3 forwardW ( + chassisTrans.getBasis()[0][m_indexForwardAxis], + chassisTrans.getBasis()[1][m_indexForwardAxis], + chassisTrans.getBasis()[2][m_indexForwardAxis]); + + return forwardW; + } + + ///Velocity of vehicle (positive if velocity vector has same direction as foward vector) + btScalar getCurrentSpeedKmHour() const + { + return m_currentVehicleSpeedKmHour; + } + + virtual void setCoordinateSystem(int rightIndex,int upIndex,int forwardIndex) + { + m_indexRightAxis = rightIndex; + m_indexUpAxis = upIndex; + m_indexForwardAxis = forwardIndex; + } + + virtual void buildJacobian() + { + //not yet + } + + virtual void solveConstraint(btScalar timeStep) + { + (void)timeStep; + //not yet + } + + +}; + +class btDefaultVehicleRaycaster : public btVehicleRaycaster +{ + btDynamicsWorld* m_dynamicsWorld; +public: + btDefaultVehicleRaycaster(btDynamicsWorld* world) + :m_dynamicsWorld(world) + { + } + + virtual void* castRay(const btVector3& from,const btVector3& to, btVehicleRaycasterResult& result); + +}; + + +#endif //RAYCASTVEHICLE_H + diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btVehicleRaycaster.h b/extern/bullet2/src/BulletDynamics/Vehicle/btVehicleRaycaster.h new file mode 100644 index 00000000000..64a47fcaada --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Vehicle/btVehicleRaycaster.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. + * It is provided "as is" without express or implied warranty. +*/ +#ifndef VEHICLE_RAYCASTER_H +#define VEHICLE_RAYCASTER_H + +#include "../../LinearMath/btVector3.h" + +/// btVehicleRaycaster is provides interface for between vehicle simulation and raycasting +struct btVehicleRaycaster +{ +virtual ~btVehicleRaycaster() +{ +} + struct btVehicleRaycasterResult + { + btVehicleRaycasterResult() :m_distFraction(btScalar(-1.)){}; + btVector3 m_hitPointInWorld; + btVector3 m_hitNormalInWorld; + btScalar m_distFraction; + }; + + virtual void* castRay(const btVector3& from,const btVector3& to, btVehicleRaycasterResult& result) = 0; + +}; + +#endif //VEHICLE_RAYCASTER_H + diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.cpp b/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.cpp new file mode 100644 index 00000000000..ef93c16fffc --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. + * It is provided "as is" without express or implied warranty. +*/ +#include "btWheelInfo.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" // for pointvelocity + + +btScalar btWheelInfo::getSuspensionRestLength() const +{ + + return m_suspensionRestLength1; + +} + +void btWheelInfo::updateWheel(const btRigidBody& chassis,RaycastInfo& raycastInfo) +{ + (void)raycastInfo; + + + if (m_raycastInfo.m_isInContact) + + { + btScalar project= m_raycastInfo.m_contactNormalWS.dot( m_raycastInfo.m_wheelDirectionWS ); + btVector3 chassis_velocity_at_contactPoint; + btVector3 relpos = m_raycastInfo.m_contactPointWS - chassis.getCenterOfMassPosition(); + chassis_velocity_at_contactPoint = chassis.getVelocityInLocalPoint( relpos ); + btScalar projVel = m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint ); + if ( project >= btScalar(-0.1)) + { + m_suspensionRelativeVelocity = btScalar(0.0); + m_clippedInvContactDotSuspension = btScalar(1.0) / btScalar(0.1); + } + else + { + btScalar inv = btScalar(-1.) / project; + m_suspensionRelativeVelocity = projVel * inv; + m_clippedInvContactDotSuspension = inv; + } + + } + + else // Not in contact : position wheel in a nice (rest length) position + { + m_raycastInfo.m_suspensionLength = this->getSuspensionRestLength(); + m_suspensionRelativeVelocity = btScalar(0.0); + m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS; + m_clippedInvContactDotSuspension = btScalar(1.0); + } +} diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.h b/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.h new file mode 100644 index 00000000000..2e349b3fde4 --- /dev/null +++ b/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies. + * Erwin Coumans makes no representations about the suitability + * of this software for any purpose. + * It is provided "as is" without express or implied warranty. +*/ +#ifndef WHEEL_INFO_H +#define WHEEL_INFO_H + +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btTransform.h" + +class btRigidBody; + +struct btWheelInfoConstructionInfo +{ + btVector3 m_chassisConnectionCS; + btVector3 m_wheelDirectionCS; + btVector3 m_wheelAxleCS; + btScalar m_suspensionRestLength; + btScalar m_maxSuspensionTravelCm; + btScalar m_wheelRadius; + + btScalar m_suspensionStiffness; + btScalar m_wheelsDampingCompression; + btScalar m_wheelsDampingRelaxation; + btScalar m_frictionSlip; + bool m_bIsFrontWheel; + +}; + +/// btWheelInfo contains information per wheel about friction and suspension. +struct btWheelInfo +{ + struct RaycastInfo + { + //set by raycaster + btVector3 m_contactNormalWS;//contactnormal + btVector3 m_contactPointWS;//raycast hitpoint + btScalar m_suspensionLength; + btVector3 m_hardPointWS;//raycast starting point + btVector3 m_wheelDirectionWS; //direction in worldspace + btVector3 m_wheelAxleWS; // axle in worldspace + bool m_isInContact; + void* m_groundObject; //could be general void* ptr + }; + + RaycastInfo m_raycastInfo; + + btTransform m_worldTransform; + + btVector3 m_chassisConnectionPointCS; //const + btVector3 m_wheelDirectionCS;//const + btVector3 m_wheelAxleCS; // const or modified by steering + btScalar m_suspensionRestLength1;//const + btScalar m_maxSuspensionTravelCm; + btScalar getSuspensionRestLength() const; + btScalar m_wheelsRadius;//const + btScalar m_suspensionStiffness;//const + btScalar m_wheelsDampingCompression;//const + btScalar m_wheelsDampingRelaxation;//const + btScalar m_frictionSlip; + btScalar m_steering; + btScalar m_rotation; + btScalar m_deltaRotation; + btScalar m_rollInfluence; + + btScalar m_engineForce; + + btScalar m_brake; + + bool m_bIsFrontWheel; + + void* m_clientInfo;//can be used to store pointer to sync transforms... + + btWheelInfo(btWheelInfoConstructionInfo& ci) + + { + + m_suspensionRestLength1 = ci.m_suspensionRestLength; + m_maxSuspensionTravelCm = ci.m_maxSuspensionTravelCm; + + m_wheelsRadius = ci.m_wheelRadius; + m_suspensionStiffness = ci.m_suspensionStiffness; + m_wheelsDampingCompression = ci.m_wheelsDampingCompression; + m_wheelsDampingRelaxation = ci.m_wheelsDampingRelaxation; + m_chassisConnectionPointCS = ci.m_chassisConnectionCS; + m_wheelDirectionCS = ci.m_wheelDirectionCS; + m_wheelAxleCS = ci.m_wheelAxleCS; + m_frictionSlip = ci.m_frictionSlip; + m_steering = btScalar(0.); + m_engineForce = btScalar(0.); + m_rotation = btScalar(0.); + m_deltaRotation = btScalar(0.); + m_brake = btScalar(0.); + m_rollInfluence = btScalar(0.1); + m_bIsFrontWheel = ci.m_bIsFrontWheel; + + } + + void updateWheel(const btRigidBody& chassis,RaycastInfo& raycastInfo); + + btScalar m_clippedInvContactDotSuspension; + btScalar m_suspensionRelativeVelocity; + //calculated by suspension + btScalar m_wheelsSuspensionForce; + btScalar m_skidInfo; + +}; + +#endif //WHEEL_INFO_H + diff --git a/extern/bullet2/src/CMakeLists.txt b/extern/bullet2/src/CMakeLists.txt new file mode 100644 index 00000000000..0ae1a7ab6ab --- /dev/null +++ b/extern/bullet2/src/CMakeLists.txt @@ -0,0 +1 @@ +SUBDIRS( BulletCollision BulletDynamics LinearMath ) diff --git a/extern/bullet2/src/LinearMath/CMakeLists.txt b/extern/bullet2/src/LinearMath/CMakeLists.txt new file mode 100644 index 00000000000..207eed94a3e --- /dev/null +++ b/extern/bullet2/src/LinearMath/CMakeLists.txt @@ -0,0 +1,10 @@ + +INCLUDE_DIRECTORIES( +${BULLET_PHYSICS_SOURCE_DIR}/src } +) + +ADD_LIBRARY(LibLinearMath +btQuickprof.cpp +btGeometryUtil.cpp +) + diff --git a/extern/bullet2/src/LinearMath/btAabbUtil2.h b/extern/bullet2/src/LinearMath/btAabbUtil2.h new file mode 100644 index 00000000000..429163c8138 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btAabbUtil2.h @@ -0,0 +1,127 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef AABB_UTIL2 +#define AABB_UTIL2 + +#include "btVector3.h" +#include "btSimdMinMax.h" + + +#define btMin(a,b) ((a < b ? a : b)) +#define btMax(a,b) ((a > b ? a : b)) + + +/// conservative test for overlap between two aabbs +SIMD_FORCE_INLINE bool TestAabbAgainstAabb2(const btVector3 &aabbMin1, const btVector3 &aabbMax1, + const btVector3 &aabbMin2, const btVector3 &aabbMax2) +{ + bool overlap = true; + overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap; + overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap; + overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap; + return overlap; +} + +/// conservative test for overlap between triangle and aabb +SIMD_FORCE_INLINE bool TestTriangleAgainstAabb2(const btVector3 *vertices, + const btVector3 &aabbMin, const btVector3 &aabbMax) +{ + const btVector3 &p1 = vertices[0]; + const btVector3 &p2 = vertices[1]; + const btVector3 &p3 = vertices[2]; + + if (btMin(btMin(p1[0], p2[0]), p3[0]) > aabbMax[0]) return false; + if (btMax(btMax(p1[0], p2[0]), p3[0]) < aabbMin[0]) return false; + + if (btMin(btMin(p1[2], p2[2]), p3[2]) > aabbMax[2]) return false; + if (btMax(btMax(p1[2], p2[2]), p3[2]) < aabbMin[2]) return false; + + if (btMin(btMin(p1[1], p2[1]), p3[1]) > aabbMax[1]) return false; + if (btMax(btMax(p1[1], p2[1]), p3[1]) < aabbMin[1]) return false; + return true; +} + + +SIMD_FORCE_INLINE int btOutcode(const btVector3& p,const btVector3& halfExtent) +{ + return (p.getX() < -halfExtent.getX() ? 0x01 : 0x0) | + (p.getX() > halfExtent.getX() ? 0x08 : 0x0) | + (p.getY() < -halfExtent.getY() ? 0x02 : 0x0) | + (p.getY() > halfExtent.getY() ? 0x10 : 0x0) | + (p.getZ() < -halfExtent.getZ() ? 0x4 : 0x0) | + (p.getZ() > halfExtent.getZ() ? 0x20 : 0x0); +} + + +SIMD_FORCE_INLINE bool btRayAabb(const btVector3& rayFrom, + const btVector3& rayTo, + const btVector3& aabbMin, + const btVector3& aabbMax, + btScalar& param, btVector3& normal) +{ + btVector3 aabbHalfExtent = (aabbMax-aabbMin)* btScalar(0.5); + btVector3 aabbCenter = (aabbMax+aabbMin)* btScalar(0.5); + btVector3 source = rayFrom - aabbCenter; + btVector3 target = rayTo - aabbCenter; + int sourceOutcode = btOutcode(source,aabbHalfExtent); + int targetOutcode = btOutcode(target,aabbHalfExtent); + if ((sourceOutcode & targetOutcode) == 0x0) + { + btScalar lambda_enter = btScalar(0.0); + btScalar lambda_exit = param; + btVector3 r = target - source; + int i; + btScalar normSign = 1; + btVector3 hitNormal(0,0,0); + int bit=1; + + for (int j=0;j<2;j++) + { + for (i = 0; i != 3; ++i) + { + if (sourceOutcode & bit) + { + btScalar lambda = (-source[i] - aabbHalfExtent[i]*normSign) / r[i]; + if (lambda_enter <= lambda) + { + lambda_enter = lambda; + hitNormal.setValue(0,0,0); + hitNormal[i] = normSign; + } + } + else if (targetOutcode & bit) + { + btScalar lambda = (-source[i] - aabbHalfExtent[i]*normSign) / r[i]; + btSetMin(lambda_exit, lambda); + } + bit<<=1; + } + normSign = btScalar(-1.); + } + if (lambda_enter <= lambda_exit) + { + param = lambda_enter; + normal = hitNormal; + return true; + } + } + return false; +} + + +#endif + diff --git a/extern/bullet2/src/LinearMath/btAlignedAllocator.cpp b/extern/bullet2/src/LinearMath/btAlignedAllocator.cpp new file mode 100644 index 00000000000..1f5877fa37e --- /dev/null +++ b/extern/bullet2/src/LinearMath/btAlignedAllocator.cpp @@ -0,0 +1,70 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btAlignedAllocator.h" + + +#if defined (BT_HAS_ALIGNED_ALOCATOR) + +#include +void* btAlignedAlloc (int size, int alignment) +{ + return _aligned_malloc(size,alignment); +} + +void btAlignedFree (void* ptr) +{ + _aligned_free(ptr); +} + +#else + +#ifdef __CELLOS_LV2__ + +#include + +int numAllocs = 0; +int numFree = 0; + +void* btAlignedAlloc (int size, int alignment) +{ + numAllocs++; + return memalign(alignment, size); +} + +void btAlignedFree (void* ptr) +{ + numFree++; + free(ptr); +} + +#else +///todo +///will add some multi-platform version that works without _aligned_malloc/_aligned_free + +void* btAlignedAlloc (int size, int alignment) +{ + return new char[size]; +} + +void btAlignedFree (void* ptr) +{ + delete [] (char*) ptr; +} +#endif // + +#endif + + diff --git a/extern/bullet2/src/LinearMath/btAlignedAllocator.h b/extern/bullet2/src/LinearMath/btAlignedAllocator.h new file mode 100644 index 00000000000..07585717f45 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btAlignedAllocator.h @@ -0,0 +1,80 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_ALIGNED_ALLOCATOR +#define BT_ALIGNED_ALLOCATOR + +///we probably replace this with our own aligned memory allocator +///so we replace _aligned_malloc and _aligned_free with our own +///that is better portable and more predictable + +#include "btScalar.h" + +void* btAlignedAlloc (int size, int alignment); + +void btAlignedFree (void* ptr); + + +typedef int size_type; + + +template < typename T , unsigned Alignment > +class btAlignedAllocator { + + typedef btAlignedAllocator< T , Alignment > self_type; + +public: + + //just going down a list: + btAlignedAllocator() {} + /* + btAlignedAllocator( const self_type & ) {} + */ + + template < typename Other > + btAlignedAllocator( const btAlignedAllocator< Other , Alignment > & ) {} + + typedef const T* const_pointer; + typedef const T& const_reference; + typedef T* pointer; + typedef T& reference; + typedef T value_type; + + pointer address ( reference ref ) const { return &ref; } + const_pointer address ( const_reference ref ) const { return &ref; } + pointer allocate ( size_type n , const_pointer * hint = 0 ) { + (void)hint; + return reinterpret_cast< pointer >(btAlignedAlloc( sizeof(value_type) * n , Alignment )); + } + void construct ( pointer ptr , const value_type & value ) { new (ptr) value_type( value ); } + void deallocate( pointer ptr ) { + btAlignedFree( reinterpret_cast< void * >( ptr ) ); + } + void destroy ( pointer ptr ) { ptr->~value_type(); } + + + template < typename O > struct rebind { + typedef btAlignedAllocator< O , Alignment > other; + }; + template < typename O > + self_type & operator=( const btAlignedAllocator< O , Alignment > & ) { return *this; } + + friend bool operator==( const self_type & , const self_type & ) { return true; } +}; + + + +#endif //BT_ALIGNED_ALLOCATOR + diff --git a/extern/bullet2/src/LinearMath/btAlignedObjectArray.h b/extern/bullet2/src/LinearMath/btAlignedObjectArray.h new file mode 100644 index 00000000000..8bef5eb5d06 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btAlignedObjectArray.h @@ -0,0 +1,367 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef BT_OBJECT_ARRAY__ +#define BT_OBJECT_ARRAY__ + +#include "btScalar.h" // has definitions like SIMD_FORCE_INLINE +#include "btAlignedAllocator.h" + +///If the platform doesn't support placement new, you can disable BT_USE_PLACEMENT_NEW +///then the btAlignedObjectArray doesn't support objects with virtual methods, and non-trivial constructors/destructors +///You can enable BT_USE_MEMCPY, then swapping elements in the array will use memcpy instead of operator= +///see discussion here: http://continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1231 and +///http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1240 + +#define BT_USE_PLACEMENT_NEW 1 +//#define BT_USE_MEMCPY 1 //disable, because it is cumbersome to find out for each platform where memcpy is defined. It can be in or or otherwise... + +#ifdef BT_USE_MEMCPY +#include +#include +#endif //BT_USE_MEMCPY + +#ifdef BT_USE_PLACEMENT_NEW +#include //for placement new +#endif //BT_USE_PLACEMENT_NEW + + +///btAlignedObjectArray uses a subset of the stl::vector interface for its methods +///It is developed to replace stl::vector to avoid STL alignment issues to add SIMD/SSE data +template +//template +class btAlignedObjectArray +{ + btAlignedAllocator m_allocator; + + int m_size; + int m_capacity; + T* m_data; + + protected: + SIMD_FORCE_INLINE int allocSize(int size) + { + return (size ? size*2 : 1); + } + SIMD_FORCE_INLINE void copy(int start,int end, T* dest) + { + int i; + for (i=start;i size()) + { + reserve(newsize); + } +#ifdef BT_USE_PLACEMENT_NEW + for (int i=curSize;i + void downHeap(T *pArr, int k, int n,L CompareFunc) + { + /* PRE: a[k+1..N] is a heap */ + /* POST: a[k..N] is a heap */ + + T temp = pArr[k - 1]; + /* k has child(s) */ + while (k <= n/2) + { + int child = 2*k; + + if ((child < n) && CompareFunc(pArr[child - 1] , pArr[child])) + { + child++; + } + /* pick larger child */ + if (CompareFunc(temp , pArr[child - 1])) + { + /* move child up */ + pArr[k - 1] = pArr[child - 1]; + k = child; + } + else + { + break; + } + } + pArr[k - 1] = temp; + } /*downHeap*/ + + void swap(int index0,int index1) + { +#ifdef BT_USE_MEMCPY + char temp[sizeof(T)]; + memcpy(temp,&m_data[index0],sizeof(T)); + memcpy(&m_data[index0],&m_data[index1],sizeof(T)); + memcpy(&m_data[index1],temp,sizeof(T)); +#else + T temp = m_data[index0]; + m_data[index0] = m_data[index1]; + m_data[index1] = temp; +#endif //BT_USE_PLACEMENT_NEW + + } + + template + void heapSort(L CompareFunc) + { + /* sort a[0..N-1], N.B. 0 to N-1 */ + int k; + int n = m_size; + for (k = n/2; k > 0; k--) + { + downHeap(m_data, k, n, CompareFunc); + } + + /* a[1..N] is now a heap */ + while ( n>=1 ) + { + swap(0,n-1); /* largest of a[0..n-1] */ + + + n = n - 1; + /* restore a[1..i-1] heap */ + downHeap(m_data, 1, n, CompareFunc); + } + } + + ///non-recursive binary search, assumes sorted array + int findBinarySearch(const T& key) const + { + int first = 0; + int last = size(); + + //assume sorted array + while (first <= last) { + int mid = (first + last) / 2; // compute mid point. + if (key > m_data[mid]) + first = mid + 1; // repeat search in top half. + else if (key < m_data[mid]) + last = mid - 1; // repeat search in bottom half. + else + return mid; // found it. return position ///// + } + return size(); // failed to find key + } + + + int findLinearSearch(const T& key) const + { + int index=size(); + int i; + + for (i=0;i& planeEquations, const btVector3& point, btScalar margin) +{ + int numbrushes = planeEquations.size(); + for (int i=0;ibtScalar(0.)) + { + return false; + } + } + return true; + +} + + +bool btGeometryUtil::areVerticesBehindPlane(const btVector3& planeNormal, const btAlignedObjectArray& vertices, btScalar margin) +{ + int numvertices = vertices.size(); + for (int i=0;ibtScalar(0.)) + { + return false; + } + } + return true; +} + +bool notExist(const btVector3& planeEquation,const btAlignedObjectArray& planeEquations) +{ + int numbrushes = planeEquations.size(); + for (int i=0;i btScalar(0.999)) + { + return false; + } + } + return true; +} + +void btGeometryUtil::getPlaneEquationsFromVertices(btAlignedObjectArray& vertices, btAlignedObjectArray& planeEquationsOut ) +{ + const int numvertices = vertices.size(); + // brute force: + for (int i=0;i btScalar(0.0001)) + { + planeEquation.normalize(); + if (notExist(planeEquation,planeEquationsOut)) + { + planeEquation[3] = -planeEquation.dot(N1); + + //check if inside, and replace supportingVertexOut if needed + if (areVerticesBehindPlane(planeEquation,vertices,btScalar(0.01))) + { + planeEquationsOut.push_back(planeEquation); + } + } + } + normalSign = btScalar(-1.); + } + + } + } + } + +} + +void btGeometryUtil::getVerticesFromPlaneEquations(const btAlignedObjectArray& planeEquations , btAlignedObjectArray& verticesOut ) +{ + const int numbrushes = planeEquations.size(); + // brute force: + for (int i=0;i btScalar(0.0001) ) && + ( n3n1.length2() > btScalar(0.0001) ) && + ( n1n2.length2() > btScalar(0.0001) ) ) + { + //point P out of 3 plane equations: + + // d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 ) + //P = ------------------------------------------------------------------------- + // N1 . ( N2 * N3 ) + + + btScalar quotient = (N1.dot(n2n3)); + if (btFabs(quotient) > btScalar(0.000001)) + { + quotient = btScalar(-1.) / quotient; + n2n3 *= N1[3]; + n3n1 *= N2[3]; + n1n2 *= N3[3]; + btVector3 potentialVertex = n2n3; + potentialVertex += n3n1; + potentialVertex += n1n2; + potentialVertex *= quotient; + + //check if inside, and replace supportingVertexOut if needed + if (isPointInsidePlanes(planeEquations,potentialVertex,btScalar(0.01))) + { + verticesOut.push_back(potentialVertex); + } + } + } + } + } + } +} + diff --git a/extern/bullet2/src/LinearMath/btGeometryUtil.h b/extern/bullet2/src/LinearMath/btGeometryUtil.h new file mode 100644 index 00000000000..766cd75c383 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btGeometryUtil.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef BT_GEOMETRY_UTIL_H +#define BT_GEOMETRY_UTIL_H + +#include "btVector3.h" +#include "btAlignedObjectArray.h" + +class btGeometryUtil +{ + public: + + + static void getPlaneEquationsFromVertices(btAlignedObjectArray& vertices, btAlignedObjectArray& planeEquationsOut ); + + static void getVerticesFromPlaneEquations(const btAlignedObjectArray& planeEquations , btAlignedObjectArray& verticesOut ); + + static bool isInside(const btAlignedObjectArray& vertices, const btVector3& planeNormal, btScalar margin); + + static bool isPointInsidePlanes(const btAlignedObjectArray& planeEquations, const btVector3& point, btScalar margin); + + static bool areVerticesBehindPlane(const btVector3& planeNormal, const btAlignedObjectArray& vertices, btScalar margin); + +}; + + +#endif //BT_GEOMETRY_UTIL_H + diff --git a/extern/bullet2/src/LinearMath/btIDebugDraw.h b/extern/bullet2/src/LinearMath/btIDebugDraw.h new file mode 100644 index 00000000000..5f40ca39157 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btIDebugDraw.h @@ -0,0 +1,100 @@ +/* +Copyright (c) 2005 Gino van den Bergen / Erwin Coumans http://continuousphysics.com + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef IDEBUG_DRAW__H +#define IDEBUG_DRAW__H + +#include "btVector3.h" + + +class btIDebugDraw +{ + public: + + enum DebugDrawModes + { + DBG_NoDebug=0, + DBG_DrawWireframe = 1, + DBG_DrawAabb=2, + DBG_DrawFeaturesText=4, + DBG_DrawContactPoints=8, + DBG_NoDeactivation=16, + DBG_NoHelpText = 32, + DBG_DrawText=64, + DBG_ProfileTimings = 128, + DBG_EnableSatComparison = 256, + DBG_DisableBulletLCP = 512, + DBG_EnableCCD = 1024, + DBG_MAX_DEBUG_DRAW_MODE + }; + + virtual ~btIDebugDraw() {}; + + virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)=0; + + virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color)=0; + + virtual void reportErrorWarning(const char* warningString) = 0; + + virtual void setDebugMode(int debugMode) =0; + + virtual int getDebugMode() const = 0; + + inline void drawAabb(const btVector3& from,const btVector3& to,const btVector3& color) + { + + btVector3 halfExtents = (to-from)* 0.5f; + btVector3 center = (to+from) *0.5f; + int i,j; + + btVector3 edgecoord(1.f,1.f,1.f),pa,pb; + for (i=0;i<4;i++) + { + for (j=0;j<3;j++) + { + pa = btVector3(edgecoord[0]*halfExtents[0], edgecoord[1]*halfExtents[1], + edgecoord[2]*halfExtents[2]); + pa+=center; + + int othercoord = j%3; + edgecoord[othercoord]*=-1.f; + pb = btVector3(edgecoord[0]*halfExtents[0], edgecoord[1]*halfExtents[1], + edgecoord[2]*halfExtents[2]); + pb+=center; + + drawLine(pa,pb,color); + } + edgecoord = btVector3(-1.f,-1.f,-1.f); + if (i<3) + edgecoord[i]*=-1.f; + } + } +}; + + +#endif //IDEBUG_DRAW__H + diff --git a/extern/bullet2/src/LinearMath/btList.h b/extern/bullet2/src/LinearMath/btList.h new file mode 100644 index 00000000000..c87b47faf2b --- /dev/null +++ b/extern/bullet2/src/LinearMath/btList.h @@ -0,0 +1,73 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef GEN_LIST_H +#define GEN_LIST_H + +class btGEN_Link { +public: + btGEN_Link() : m_next(0), m_prev(0) {} + btGEN_Link(btGEN_Link *next, btGEN_Link *prev) : m_next(next), m_prev(prev) {} + + btGEN_Link *getNext() const { return m_next; } + btGEN_Link *getPrev() const { return m_prev; } + + bool isHead() const { return m_prev == 0; } + bool isTail() const { return m_next == 0; } + + void insertBefore(btGEN_Link *link) { + m_next = link; + m_prev = link->m_prev; + m_next->m_prev = this; + m_prev->m_next = this; + } + + void insertAfter(btGEN_Link *link) { + m_next = link->m_next; + m_prev = link; + m_next->m_prev = this; + m_prev->m_next = this; + } + + void remove() { + m_next->m_prev = m_prev; + m_prev->m_next = m_next; + } + +private: + btGEN_Link *m_next; + btGEN_Link *m_prev; +}; + +class btGEN_List { +public: + btGEN_List() : m_head(&m_tail, 0), m_tail(0, &m_head) {} + + btGEN_Link *getHead() const { return m_head.getNext(); } + btGEN_Link *getTail() const { return m_tail.getPrev(); } + + void addHead(btGEN_Link *link) { link->insertAfter(&m_head); } + void addTail(btGEN_Link *link) { link->insertBefore(&m_tail); } + +private: + btGEN_Link m_head; + btGEN_Link m_tail; +}; + +#endif + + + diff --git a/extern/bullet2/src/LinearMath/btMatrix3x3.h b/extern/bullet2/src/LinearMath/btMatrix3x3.h new file mode 100644 index 00000000000..94f53c3c0a5 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btMatrix3x3.h @@ -0,0 +1,410 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef btMatrix3x3_H +#define btMatrix3x3_H + +#include "btScalar.h" + +#include "btVector3.h" +#include "btQuaternion.h" + + +class btMatrix3x3 { + public: + btMatrix3x3 () {} + +// explicit btMatrix3x3(const btScalar *m) { setFromOpenGLSubMatrix(m); } + + explicit btMatrix3x3(const btQuaternion& q) { setRotation(q); } + /* + template + Matrix3x3(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) + { + setEulerYPR(yaw, pitch, roll); + } + */ + btMatrix3x3(const btScalar& xx, const btScalar& xy, const btScalar& xz, + const btScalar& yx, const btScalar& yy, const btScalar& yz, + const btScalar& zx, const btScalar& zy, const btScalar& zz) + { + setValue(xx, xy, xz, + yx, yy, yz, + zx, zy, zz); + } + + SIMD_FORCE_INLINE btMatrix3x3 (const btMatrix3x3& other) + { + m_el[0] = other.m_el[0]; + m_el[1] = other.m_el[1]; + m_el[2] = other.m_el[2]; + } + + SIMD_FORCE_INLINE btMatrix3x3& operator=(const btMatrix3x3& other) + { + m_el[0] = other.m_el[0]; + m_el[1] = other.m_el[1]; + m_el[2] = other.m_el[2]; + return *this; + } + + SIMD_FORCE_INLINE btVector3 getColumn(int i) const + { + return btVector3(m_el[0][i],m_el[1][i],m_el[2][i]); + } + + + + SIMD_FORCE_INLINE const btVector3& getRow(int i) const + { + return m_el[i]; + } + + + SIMD_FORCE_INLINE btVector3& operator[](int i) + { + btFullAssert(0 <= i && i < 3); + return m_el[i]; + } + + SIMD_FORCE_INLINE const btVector3& operator[](int i) const + { + btFullAssert(0 <= i && i < 3); + return m_el[i]; + } + + btMatrix3x3& operator*=(const btMatrix3x3& m); + + + void setFromOpenGLSubMatrix(const btScalar *m) + { + m_el[0].setValue(m[0],m[4],m[8]); + m_el[1].setValue(m[1],m[5],m[9]); + m_el[2].setValue(m[2],m[6],m[10]); + + } + + void setValue(const btScalar& xx, const btScalar& xy, const btScalar& xz, + const btScalar& yx, const btScalar& yy, const btScalar& yz, + const btScalar& zx, const btScalar& zy, const btScalar& zz) + { + m_el[0].setValue(xx,xy,xz); + m_el[1].setValue(yx,yy,yz); + m_el[2].setValue(zx,zy,zz); + } + + void setRotation(const btQuaternion& q) + { + btScalar d = q.length2(); + btFullAssert(d != btScalar(0.0)); + btScalar s = btScalar(2.0) / d; + btScalar xs = q.x() * s, ys = q.y() * s, zs = q.z() * s; + btScalar wx = q.w() * xs, wy = q.w() * ys, wz = q.w() * zs; + btScalar xx = q.x() * xs, xy = q.x() * ys, xz = q.x() * zs; + btScalar yy = q.y() * ys, yz = q.y() * zs, zz = q.z() * zs; + setValue(btScalar(1.0) - (yy + zz), xy - wz, xz + wy, + xy + wz, btScalar(1.0) - (xx + zz), yz - wx, + xz - wy, yz + wx, btScalar(1.0) - (xx + yy)); + } + + + + void setEulerYPR(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) + { + + btScalar cy(btCos(yaw)); + btScalar sy(btSin(yaw)); + btScalar cp(btCos(pitch)); + btScalar sp(btSin(pitch)); + btScalar cr(btCos(roll)); + btScalar sr(btSin(roll)); + btScalar cc = cy * cr; + btScalar cs = cy * sr; + btScalar sc = sy * cr; + btScalar ss = sy * sr; + setValue(cc - sp * ss, -cs - sp * sc, -sy * cp, + cp * sr, cp * cr, -sp, + sc + sp * cs, -ss + sp * cc, cy * cp); + + } + + /** + * setEulerZYX + * @param euler a const reference to a btVector3 of euler angles + * These angles are used to produce a rotation matrix. The euler + * angles are applied in ZYX order. I.e a vector is first rotated + * about X then Y and then Z + **/ + + void setEulerZYX(btScalar eulerX,btScalar eulerY,btScalar eulerZ) { + btScalar ci ( btCos(eulerX)); + btScalar cj ( btCos(eulerY)); + btScalar ch ( btCos(eulerZ)); + btScalar si ( btSin(eulerX)); + btScalar sj ( btSin(eulerY)); + btScalar sh ( btSin(eulerZ)); + btScalar cc = ci * ch; + btScalar cs = ci * sh; + btScalar sc = si * ch; + btScalar ss = si * sh; + + setValue(cj * ch, sj * sc - cs, sj * cc + ss, + cj * sh, sj * ss + cc, sj * cs - sc, + -sj, cj * si, cj * ci); + } + + void setIdentity() + { + setValue(btScalar(1.0), btScalar(0.0), btScalar(0.0), + btScalar(0.0), btScalar(1.0), btScalar(0.0), + btScalar(0.0), btScalar(0.0), btScalar(1.0)); + } + + void getOpenGLSubMatrix(btScalar *m) const + { + m[0] = btScalar(m_el[0].x()); + m[1] = btScalar(m_el[1].x()); + m[2] = btScalar(m_el[2].x()); + m[3] = btScalar(0.0); + m[4] = btScalar(m_el[0].y()); + m[5] = btScalar(m_el[1].y()); + m[6] = btScalar(m_el[2].y()); + m[7] = btScalar(0.0); + m[8] = btScalar(m_el[0].z()); + m[9] = btScalar(m_el[1].z()); + m[10] = btScalar(m_el[2].z()); + m[11] = btScalar(0.0); + } + + void getRotation(btQuaternion& q) const + { + btScalar trace = m_el[0].x() + m_el[1].y() + m_el[2].z(); + btScalar temp[4]; + + if (trace > btScalar(0.0)) + { + btScalar s = btSqrt(trace + btScalar(1.0)); + temp[3]=(s * btScalar(0.5)); + s = btScalar(0.5) / s; + + temp[0]=((m_el[2].y() - m_el[1].z()) * s); + temp[1]=((m_el[0].z() - m_el[2].x()) * s); + temp[2]=((m_el[1].x() - m_el[0].y()) * s); + } + else + { + int i = m_el[0].x() < m_el[1].y() ? + (m_el[1].y() < m_el[2].z() ? 2 : 1) : + (m_el[0].x() < m_el[2].z() ? 2 : 0); + int j = (i + 1) % 3; + int k = (i + 2) % 3; + + btScalar s = btSqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + btScalar(1.0)); + temp[i] = s * btScalar(0.5); + s = btScalar(0.5) / s; + + temp[3] = (m_el[k][j] - m_el[j][k]) * s; + temp[j] = (m_el[j][i] + m_el[i][j]) * s; + temp[k] = (m_el[k][i] + m_el[i][k]) * s; + } + q.setValue(temp[0],temp[1],temp[2],temp[3]); + } + + void getEuler(btScalar& yaw, btScalar& pitch, btScalar& roll) const + { + + if (btScalar(m_el[1].z()) < btScalar(1)) + { + if (btScalar(m_el[1].z()) > -btScalar(1)) + { + yaw = btScalar(btAtan2(m_el[1].x(), m_el[0].x())); + pitch = btScalar(btAsin(-m_el[1].y())); + roll = btScalar(btAtan2(m_el[2].y(), m_el[2].z())); + } + else + { + yaw = btScalar(-btAtan2(-m_el[0].y(), m_el[0].z())); + pitch = SIMD_HALF_PI; + roll = btScalar(0.0); + } + } + else + { + yaw = btScalar(btAtan2(-m_el[0].y(), m_el[0].z())); + pitch = -SIMD_HALF_PI; + roll = btScalar(0.0); + } + } + + + + + btMatrix3x3 scaled(const btVector3& s) const + { + return btMatrix3x3(m_el[0].x() * s.x(), m_el[0].y() * s.y(), m_el[0].z() * s.z(), + m_el[1].x() * s.x(), m_el[1].y() * s.y(), m_el[1].z() * s.z(), + m_el[2].x() * s.x(), m_el[2].y() * s.y(), m_el[2].z() * s.z()); + } + + btScalar determinant() const; + btMatrix3x3 adjoint() const; + btMatrix3x3 absolute() const; + btMatrix3x3 transpose() const; + btMatrix3x3 inverse() const; + + btMatrix3x3 transposeTimes(const btMatrix3x3& m) const; + btMatrix3x3 timesTranspose(const btMatrix3x3& m) const; + + SIMD_FORCE_INLINE btScalar tdotx(const btVector3& v) const + { + return m_el[0].x() * v.x() + m_el[1].x() * v.y() + m_el[2].x() * v.z(); + } + SIMD_FORCE_INLINE btScalar tdoty(const btVector3& v) const + { + return m_el[0].y() * v.x() + m_el[1].y() * v.y() + m_el[2].y() * v.z(); + } + SIMD_FORCE_INLINE btScalar tdotz(const btVector3& v) const + { + return m_el[0].z() * v.x() + m_el[1].z() * v.y() + m_el[2].z() * v.z(); + } + + + + protected: + btScalar cofac(int r1, int c1, int r2, int c2) const + { + return m_el[r1][c1] * m_el[r2][c2] - m_el[r1][c2] * m_el[r2][c1]; + } + + btVector3 m_el[3]; + }; + + SIMD_FORCE_INLINE btMatrix3x3& + btMatrix3x3::operator*=(const btMatrix3x3& m) + { + setValue(m.tdotx(m_el[0]), m.tdoty(m_el[0]), m.tdotz(m_el[0]), + m.tdotx(m_el[1]), m.tdoty(m_el[1]), m.tdotz(m_el[1]), + m.tdotx(m_el[2]), m.tdoty(m_el[2]), m.tdotz(m_el[2])); + return *this; + } + + SIMD_FORCE_INLINE btScalar + btMatrix3x3::determinant() const + { + return triple((*this)[0], (*this)[1], (*this)[2]); + } + + + SIMD_FORCE_INLINE btMatrix3x3 + btMatrix3x3::absolute() const + { + return btMatrix3x3( + btFabs(m_el[0].x()), btFabs(m_el[0].y()), btFabs(m_el[0].z()), + btFabs(m_el[1].x()), btFabs(m_el[1].y()), btFabs(m_el[1].z()), + btFabs(m_el[2].x()), btFabs(m_el[2].y()), btFabs(m_el[2].z())); + } + + SIMD_FORCE_INLINE btMatrix3x3 + btMatrix3x3::transpose() const + { + return btMatrix3x3(m_el[0].x(), m_el[1].x(), m_el[2].x(), + m_el[0].y(), m_el[1].y(), m_el[2].y(), + m_el[0].z(), m_el[1].z(), m_el[2].z()); + } + + SIMD_FORCE_INLINE btMatrix3x3 + btMatrix3x3::adjoint() const + { + return btMatrix3x3(cofac(1, 1, 2, 2), cofac(0, 2, 2, 1), cofac(0, 1, 1, 2), + cofac(1, 2, 2, 0), cofac(0, 0, 2, 2), cofac(0, 2, 1, 0), + cofac(1, 0, 2, 1), cofac(0, 1, 2, 0), cofac(0, 0, 1, 1)); + } + + SIMD_FORCE_INLINE btMatrix3x3 + btMatrix3x3::inverse() const + { + btVector3 co(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)); + btScalar det = (*this)[0].dot(co); + btFullAssert(det != btScalar(0.0)); + btScalar s = btScalar(1.0) / det; + return btMatrix3x3(co.x() * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, + co.y() * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s, + co.z() * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s); + } + + SIMD_FORCE_INLINE btMatrix3x3 + btMatrix3x3::transposeTimes(const btMatrix3x3& m) const + { + return btMatrix3x3( + m_el[0].x() * m[0].x() + m_el[1].x() * m[1].x() + m_el[2].x() * m[2].x(), + m_el[0].x() * m[0].y() + m_el[1].x() * m[1].y() + m_el[2].x() * m[2].y(), + m_el[0].x() * m[0].z() + m_el[1].x() * m[1].z() + m_el[2].x() * m[2].z(), + m_el[0].y() * m[0].x() + m_el[1].y() * m[1].x() + m_el[2].y() * m[2].x(), + m_el[0].y() * m[0].y() + m_el[1].y() * m[1].y() + m_el[2].y() * m[2].y(), + m_el[0].y() * m[0].z() + m_el[1].y() * m[1].z() + m_el[2].y() * m[2].z(), + m_el[0].z() * m[0].x() + m_el[1].z() * m[1].x() + m_el[2].z() * m[2].x(), + m_el[0].z() * m[0].y() + m_el[1].z() * m[1].y() + m_el[2].z() * m[2].y(), + m_el[0].z() * m[0].z() + m_el[1].z() * m[1].z() + m_el[2].z() * m[2].x()); + } + + SIMD_FORCE_INLINE btMatrix3x3 + btMatrix3x3::timesTranspose(const btMatrix3x3& m) const + { + return btMatrix3x3( + m_el[0].dot(m[0]), m_el[0].dot(m[1]), m_el[0].dot(m[2]), + m_el[1].dot(m[0]), m_el[1].dot(m[1]), m_el[1].dot(m[2]), + m_el[2].dot(m[0]), m_el[2].dot(m[1]), m_el[2].dot(m[2])); + + } + + SIMD_FORCE_INLINE btVector3 + operator*(const btMatrix3x3& m, const btVector3& v) + { + return btVector3(m[0].dot(v), m[1].dot(v), m[2].dot(v)); + } + + + SIMD_FORCE_INLINE btVector3 + operator*(const btVector3& v, const btMatrix3x3& m) + { + return btVector3(m.tdotx(v), m.tdoty(v), m.tdotz(v)); + } + + SIMD_FORCE_INLINE btMatrix3x3 + operator*(const btMatrix3x3& m1, const btMatrix3x3& m2) + { + return btMatrix3x3( + m2.tdotx( m1[0]), m2.tdoty( m1[0]), m2.tdotz( m1[0]), + m2.tdotx( m1[1]), m2.tdoty( m1[1]), m2.tdotz( m1[1]), + m2.tdotx( m1[2]), m2.tdoty( m1[2]), m2.tdotz( m1[2])); + } + +/* + SIMD_FORCE_INLINE btMatrix3x3 btMultTransposeLeft(const btMatrix3x3& m1, const btMatrix3x3& m2) { + return btMatrix3x3( + m1[0][0] * m2[0][0] + m1[1][0] * m2[1][0] + m1[2][0] * m2[2][0], + m1[0][0] * m2[0][1] + m1[1][0] * m2[1][1] + m1[2][0] * m2[2][1], + m1[0][0] * m2[0][2] + m1[1][0] * m2[1][2] + m1[2][0] * m2[2][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[1][0] + m1[2][1] * m2[2][0], + m1[0][1] * m2[0][1] + m1[1][1] * m2[1][1] + m1[2][1] * m2[2][1], + m1[0][1] * m2[0][2] + m1[1][1] * m2[1][2] + m1[2][1] * m2[2][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[1][0] + m1[2][2] * m2[2][0], + m1[0][2] * m2[0][1] + m1[1][2] * m2[1][1] + m1[2][2] * m2[2][1], + m1[0][2] * m2[0][2] + m1[1][2] * m2[1][2] + m1[2][2] * m2[2][2]); +} +*/ + + +#endif diff --git a/extern/bullet2/src/LinearMath/btMinMax.h b/extern/bullet2/src/LinearMath/btMinMax.h new file mode 100644 index 00000000000..1b8a3633f38 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btMinMax.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef GEN_MINMAX_H +#define GEN_MINMAX_H + +template +SIMD_FORCE_INLINE const T& GEN_min(const T& a, const T& b) +{ + return b < a ? b : a; +} + +template +SIMD_FORCE_INLINE const T& GEN_max(const T& a, const T& b) +{ + return a < b ? b : a; +} + +template +SIMD_FORCE_INLINE const T& GEN_clamped(const T& a, const T& lb, const T& ub) +{ + return a < lb ? lb : (ub < a ? ub : a); +} + +template +SIMD_FORCE_INLINE void GEN_set_min(T& a, const T& b) +{ + if (b < a) + { + a = b; + } +} + +template +SIMD_FORCE_INLINE void GEN_set_max(T& a, const T& b) +{ + if (a < b) + { + a = b; + } +} + +template +SIMD_FORCE_INLINE void GEN_clamp(T& a, const T& lb, const T& ub) +{ + if (a < lb) + { + a = lb; + } + else if (ub < a) + { + a = ub; + } +} + +#endif diff --git a/extern/bullet2/src/LinearMath/btMotionState.h b/extern/bullet2/src/LinearMath/btMotionState.h new file mode 100644 index 00000000000..1975e5ff900 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btMotionState.h @@ -0,0 +1,40 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_MOTIONSTATE_H +#define BT_MOTIONSTATE_H + +#include "btTransform.h" + +///btMotionState allows the dynamics world to synchronize the updated world transforms with graphics +///For optimizations, potentially only moving objects get synchronized (using setWorldPosition/setWorldOrientation) +class btMotionState +{ + public: + + virtual ~btMotionState() + { + + } + + virtual void getWorldTransform(btTransform& worldTrans ) const =0; + + //Bullet only calls the update of worldtransform for active objects + virtual void setWorldTransform(const btTransform& worldTrans)=0; + + +}; + +#endif //BT_MOTIONSTATE_H diff --git a/extern/bullet2/src/LinearMath/btPoint3.h b/extern/bullet2/src/LinearMath/btPoint3.h new file mode 100644 index 00000000000..a2020e26d12 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btPoint3.h @@ -0,0 +1,24 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef btPoint3_H +#define btPoint3_H + +#include "btVector3.h" + +typedef btVector3 btPoint3; + +#endif diff --git a/extern/bullet2/src/LinearMath/btQuadWord.h b/extern/bullet2/src/LinearMath/btQuadWord.h new file mode 100644 index 00000000000..961ac484d20 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btQuadWord.h @@ -0,0 +1,139 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef SIMD_QUADWORD_H +#define SIMD_QUADWORD_H + +#include "btScalar.h" + + + + +///btQuadWord is base-class for vectors, points +class btQuadWord +{ + protected: + btScalar m_x; + btScalar m_y; + btScalar m_z; + btScalar m_unusedW; + + public: + +// SIMD_FORCE_INLINE btScalar& operator[](int i) { return (&m_x)[i]; } +// SIMD_FORCE_INLINE const btScalar& operator[](int i) const { return (&m_x)[i]; } + + SIMD_FORCE_INLINE const btScalar& getX() const { return m_x; } + + SIMD_FORCE_INLINE const btScalar& getY() const { return m_y; } + + SIMD_FORCE_INLINE const btScalar& getZ() const { return m_z; } + + SIMD_FORCE_INLINE void setX(btScalar x) { m_x = x;}; + + SIMD_FORCE_INLINE void setY(btScalar y) { m_y = y;}; + + SIMD_FORCE_INLINE void setZ(btScalar z) { m_z = z;}; + + SIMD_FORCE_INLINE void setW(btScalar w) { m_unusedW = w;}; + + SIMD_FORCE_INLINE const btScalar& x() const { return m_x; } + + SIMD_FORCE_INLINE const btScalar& y() const { return m_y; } + + SIMD_FORCE_INLINE const btScalar& z() const { return m_z; } + + SIMD_FORCE_INLINE const btScalar& w() const { return m_unusedW; } + + + SIMD_FORCE_INLINE operator btScalar *() { return &m_x; } + SIMD_FORCE_INLINE operator const btScalar *() const { return &m_x; } + + SIMD_FORCE_INLINE void setValue(const btScalar& x, const btScalar& y, const btScalar& z) + { + m_x=x; + m_y=y; + m_z=z; + m_unusedW = 0.f; + } + +/* void getValue(btScalar *m) const + { + m[0] = m_x; + m[1] = m_y; + m[2] = m_z; + } +*/ + SIMD_FORCE_INLINE void setValue(const btScalar& x, const btScalar& y, const btScalar& z,const btScalar& w) + { + m_x=x; + m_y=y; + m_z=z; + m_unusedW=w; + } + + SIMD_FORCE_INLINE btQuadWord() + // :m_x(btScalar(0.)),m_y(btScalar(0.)),m_z(btScalar(0.)),m_unusedW(btScalar(0.)) + { + } + + SIMD_FORCE_INLINE btQuadWord(const btScalar& x, const btScalar& y, const btScalar& z) + :m_x(x),m_y(y),m_z(z) + //todo, remove this in release/simd ? + ,m_unusedW(btScalar(0.)) + { + } + + SIMD_FORCE_INLINE btQuadWord(const btScalar& x, const btScalar& y, const btScalar& z,const btScalar& w) + :m_x(x),m_y(y),m_z(z),m_unusedW(w) + { + } + + + SIMD_FORCE_INLINE void setMax(const btQuadWord& other) + { + if (other.m_x > m_x) + m_x = other.m_x; + + if (other.m_y > m_y) + m_y = other.m_y; + + if (other.m_z > m_z) + m_z = other.m_z; + + if (other.m_unusedW > m_unusedW) + m_unusedW = other.m_unusedW; + } + + SIMD_FORCE_INLINE void setMin(const btQuadWord& other) + { + if (other.m_x < m_x) + m_x = other.m_x; + + if (other.m_y < m_y) + m_y = other.m_y; + + if (other.m_z < m_z) + m_z = other.m_z; + + if (other.m_unusedW < m_unusedW) + m_unusedW = other.m_unusedW; + } + + + +}; + +#endif //SIMD_QUADWORD_H diff --git a/extern/bullet2/src/LinearMath/btQuaternion.h b/extern/bullet2/src/LinearMath/btQuaternion.h new file mode 100644 index 00000000000..50334970ba6 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btQuaternion.h @@ -0,0 +1,321 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef SIMD__QUATERNION_H_ +#define SIMD__QUATERNION_H_ + +#include "btVector3.h" + +class btQuaternion : public btQuadWord { +public: + btQuaternion() {} + + // template + // explicit Quaternion(const btScalar *v) : Tuple4(v) {} + + btQuaternion(const btScalar& x, const btScalar& y, const btScalar& z, const btScalar& w) + : btQuadWord(x, y, z, w) + {} + + btQuaternion(const btVector3& axis, const btScalar& angle) + { + setRotation(axis, angle); + } + + btQuaternion(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) + { + setEuler(yaw, pitch, roll); + } + + void setRotation(const btVector3& axis, const btScalar& angle) + { + btScalar d = axis.length(); + assert(d != btScalar(0.0)); + btScalar s = btSin(angle * btScalar(0.5)) / d; + setValue(axis.x() * s, axis.y() * s, axis.z() * s, + btCos(angle * btScalar(0.5))); + } + + void setEuler(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) + { + btScalar halfYaw = btScalar(yaw) * btScalar(0.5); + btScalar halfPitch = btScalar(pitch) * btScalar(0.5); + btScalar halfRoll = btScalar(roll) * btScalar(0.5); + btScalar cosYaw = btCos(halfYaw); + btScalar sinYaw = btSin(halfYaw); + btScalar cosPitch = btCos(halfPitch); + btScalar sinPitch = btSin(halfPitch); + btScalar cosRoll = btCos(halfRoll); + btScalar sinRoll = btSin(halfRoll); + setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, + cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, + sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, + cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); + } + + btQuaternion& operator+=(const btQuaternion& q) + { + m_x += q.x(); m_y += q.y(); m_z += q.z(); m_unusedW += q.m_unusedW; + return *this; + } + + btQuaternion& operator-=(const btQuaternion& q) + { + m_x -= q.x(); m_y -= q.y(); m_z -= q.z(); m_unusedW -= q.m_unusedW; + return *this; + } + + btQuaternion& operator*=(const btScalar& s) + { + m_x *= s; m_y *= s; m_z *= s; m_unusedW *= s; + return *this; + } + + + btQuaternion& operator*=(const btQuaternion& q) + { + setValue(m_unusedW * q.x() + m_x * q.m_unusedW + m_y * q.z() - m_z * q.y(), + m_unusedW * q.y() + m_y * q.m_unusedW + m_z * q.x() - m_x * q.z(), + m_unusedW * q.z() + m_z * q.m_unusedW + m_x * q.y() - m_y * q.x(), + m_unusedW * q.m_unusedW - m_x * q.x() - m_y * q.y() - m_z * q.z()); + return *this; + } + + btScalar dot(const btQuaternion& q) const + { + return m_x * q.x() + m_y * q.y() + m_z * q.z() + m_unusedW * q.m_unusedW; + } + + btScalar length2() const + { + return dot(*this); + } + + btScalar length() const + { + return btSqrt(length2()); + } + + btQuaternion& normalize() + { + return *this /= length(); + } + + SIMD_FORCE_INLINE btQuaternion + operator*(const btScalar& s) const + { + return btQuaternion(x() * s, y() * s, z() * s, m_unusedW * s); + } + + + + btQuaternion operator/(const btScalar& s) const + { + assert(s != btScalar(0.0)); + return *this * (btScalar(1.0) / s); + } + + + btQuaternion& operator/=(const btScalar& s) + { + assert(s != btScalar(0.0)); + return *this *= btScalar(1.0) / s; + } + + + btQuaternion normalized() const + { + return *this / length(); + } + + btScalar angle(const btQuaternion& q) const + { + btScalar s = btSqrt(length2() * q.length2()); + assert(s != btScalar(0.0)); + return btAcos(dot(q) / s); + } + + btScalar getAngle() const + { + btScalar s = btScalar(2.) * btAcos(m_unusedW); + return s; + } + + + + btQuaternion inverse() const + { + return btQuaternion(m_x, m_y, m_z, -m_unusedW); + } + + SIMD_FORCE_INLINE btQuaternion + operator+(const btQuaternion& q2) const + { + const btQuaternion& q1 = *this; + return btQuaternion(q1.x() + q2.x(), q1.y() + q2.y(), q1.z() + q2.z(), q1.m_unusedW + q2.m_unusedW); + } + + SIMD_FORCE_INLINE btQuaternion + operator-(const btQuaternion& q2) const + { + const btQuaternion& q1 = *this; + return btQuaternion(q1.x() - q2.x(), q1.y() - q2.y(), q1.z() - q2.z(), q1.m_unusedW - q2.m_unusedW); + } + + SIMD_FORCE_INLINE btQuaternion operator-() const + { + const btQuaternion& q2 = *this; + return btQuaternion( - q2.x(), - q2.y(), - q2.z(), - q2.m_unusedW); + } + + SIMD_FORCE_INLINE btQuaternion farthest( const btQuaternion& qd) const + { + btQuaternion diff,sum; + diff = *this - qd; + sum = *this + qd; + if( diff.dot(diff) > sum.dot(sum) ) + return qd; + return (-qd); + } + + btQuaternion slerp(const btQuaternion& q, const btScalar& t) const + { + btScalar theta = angle(q); + if (theta != btScalar(0.0)) + { + btScalar d = btScalar(1.0) / btSin(theta); + btScalar s0 = btSin((btScalar(1.0) - t) * theta); + btScalar s1 = btSin(t * theta); + return btQuaternion((m_x * s0 + q.x() * s1) * d, + (m_y * s0 + q.y() * s1) * d, + (m_z * s0 + q.z() * s1) * d, + (m_unusedW * s0 + q.m_unusedW * s1) * d); + } + else + { + return *this; + } + } + + SIMD_FORCE_INLINE const btScalar& getW() const { return m_unusedW; } + + +}; + + + +SIMD_FORCE_INLINE btQuaternion +operator-(const btQuaternion& q) +{ + return btQuaternion(-q.x(), -q.y(), -q.z(), -q.w()); +} + + + + +SIMD_FORCE_INLINE btQuaternion +operator*(const btQuaternion& q1, const btQuaternion& q2) { + return btQuaternion(q1.w() * q2.x() + q1.x() * q2.w() + q1.y() * q2.z() - q1.z() * q2.y(), + q1.w() * q2.y() + q1.y() * q2.w() + q1.z() * q2.x() - q1.x() * q2.z(), + q1.w() * q2.z() + q1.z() * q2.w() + q1.x() * q2.y() - q1.y() * q2.x(), + q1.w() * q2.w() - q1.x() * q2.x() - q1.y() * q2.y() - q1.z() * q2.z()); +} + +SIMD_FORCE_INLINE btQuaternion +operator*(const btQuaternion& q, const btVector3& w) +{ + return btQuaternion( q.w() * w.x() + q.y() * w.z() - q.z() * w.y(), + q.w() * w.y() + q.z() * w.x() - q.x() * w.z(), + q.w() * w.z() + q.x() * w.y() - q.y() * w.x(), + -q.x() * w.x() - q.y() * w.y() - q.z() * w.z()); +} + +SIMD_FORCE_INLINE btQuaternion +operator*(const btVector3& w, const btQuaternion& q) +{ + return btQuaternion( w.x() * q.w() + w.y() * q.z() - w.z() * q.y(), + w.y() * q.w() + w.z() * q.x() - w.x() * q.z(), + w.z() * q.w() + w.x() * q.y() - w.y() * q.x(), + -w.x() * q.x() - w.y() * q.y() - w.z() * q.z()); +} + +SIMD_FORCE_INLINE btScalar +dot(const btQuaternion& q1, const btQuaternion& q2) +{ + return q1.dot(q2); +} + + +SIMD_FORCE_INLINE btScalar +length(const btQuaternion& q) +{ + return q.length(); +} + +SIMD_FORCE_INLINE btScalar +angle(const btQuaternion& q1, const btQuaternion& q2) +{ + return q1.angle(q2); +} + + +SIMD_FORCE_INLINE btQuaternion +inverse(const btQuaternion& q) +{ + return q.inverse(); +} + +SIMD_FORCE_INLINE btQuaternion +slerp(const btQuaternion& q1, const btQuaternion& q2, const btScalar& t) +{ + return q1.slerp(q2, t); +} + +SIMD_FORCE_INLINE btVector3 +quatRotate(btQuaternion& rotation, btVector3& v) +{ + btQuaternion q = rotation * v; + q *= rotation.inverse(); + return btVector3(q.getX(),q.getY(),q.getZ()); +} + +SIMD_FORCE_INLINE btQuaternion +shortestArcQuat(btVector3& v0,btVector3& v1) // Game Programming Gems 2.10. make sure v0,v1 are normalized +{ + btVector3 c = v0.cross(v1); + btScalar d = v0.dot(v1); + + if (d < -1.0 + SIMD_EPSILON) + return btQuaternion(0.0f,1.0f,0.0f,0.0f); // just pick any vector + + btScalar s = btSqrt((1.0f + d) * 2.0f); + btScalar rs = 1.0f / s; + + return btQuaternion(c.getX()*rs,c.getY()*rs,c.getZ()*rs,s * 0.5f); +} + +SIMD_FORCE_INLINE btQuaternion +shortestArcQuatNormalize(btVector3& v0,btVector3& v1) +{ + v0.normalize(); + v1.normalize(); + return shortestArcQuat(v0,v1); +} + +#endif + + + diff --git a/extern/bullet2/src/LinearMath/btQuickprof.cpp b/extern/bullet2/src/LinearMath/btQuickprof.cpp new file mode 100644 index 00000000000..37a0c8c3be5 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btQuickprof.cpp @@ -0,0 +1,38 @@ +/* +Copyright (c) 2006 Tyler Streeter + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +*/ + + +// Please visit the project website (http://quickprof.sourceforge.net) +// for usage instructions. + +// Credits: The Clock class was inspired by the Timer classes in +// Ogre (www.ogre3d.org). + +#include "LinearMath/btQuickprof.h" + +#ifdef USE_QUICKPROF + +// Note: We must declare these private static variables again here to +// avoid link errors. +bool btProfiler::mEnabled = false; +btClock btProfiler::mClock; +unsigned long int btProfiler::mCurrentCycleStartMicroseconds = 0; +unsigned long int btProfiler::mLastCycleDurationMicroseconds = 0; +std::map btProfiler::mProfileBlocks; +std::ofstream btProfiler::mOutputFile; +bool btProfiler::mFirstFileOutput = true; +btProfiler::BlockTimingMethod btProfiler::mFileOutputMethod; +unsigned long int btProfiler::mCycleNumber = 0; +#endif //USE_QUICKPROF diff --git a/extern/bullet2/src/LinearMath/btQuickprof.h b/extern/bullet2/src/LinearMath/btQuickprof.h new file mode 100644 index 00000000000..a885967c5fa --- /dev/null +++ b/extern/bullet2/src/LinearMath/btQuickprof.h @@ -0,0 +1,712 @@ +/* +Copyright (c) 2006 Tyler Streeter + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +*/ + +// Please visit the project website (http://quickprof.sourceforge.net) +// for usage instructions. + +// Credits: The Clock class was inspired by the Timer classes in +// Ogre (www.ogre3d.org). + +#ifndef QUICK_PROF_H +#define QUICK_PROF_H + +#include "btScalar.h" + +//#define USE_QUICKPROF 1 +//Don't use quickprof for now, because it contains STL. TODO: replace STL by Bullet container classes. + + +//if you don't need btClock, you can comment next line +#define USE_BT_CLOCK 1 + +#ifdef USE_BT_CLOCK +#ifdef __CELLOS_LV2__ +#include +#include +typedef uint64_t __int64; +#endif + +#if defined (SUNOS) || defined (__SUNOS__) + #include +#endif + +#if defined(WIN32) || defined(_WIN32) + + #define USE_WINDOWS_TIMERS + #define WIN32_LEAN_AND_MEAN + #define NOWINRES + #define NOMCX + #define NOIME +#ifdef _XBOX + #include +#else + #include +#endif + #include + +#else + #include +#endif + +#define mymin(a,b) (a > b ? a : b) + +/// basic clock +class btClock + { + public: + btClock() + { +#ifdef USE_WINDOWS_TIMERS + QueryPerformanceFrequency(&mClockFrequency); +#endif + reset(); + } + + ~btClock() + { + } + + /// Resets the initial reference time. + void reset() + { +#ifdef USE_WINDOWS_TIMERS + QueryPerformanceCounter(&mStartTime); + mStartTick = GetTickCount(); + mPrevElapsedTime = 0; +#else +#ifdef __CELLOS_LV2__ + + typedef uint64_t __int64; + typedef __int64 ClockSize; + ClockSize newTime; + __asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); + mStartTime = newTime; +#else + gettimeofday(&mStartTime, 0); +#endif + +#endif + } + + /// Returns the time in ms since the last call to reset or since + /// the btClock was created. + unsigned long int getTimeMilliseconds() + { +#ifdef USE_WINDOWS_TIMERS + LARGE_INTEGER currentTime; + QueryPerformanceCounter(¤tTime); + LONGLONG elapsedTime = currentTime.QuadPart - + mStartTime.QuadPart; + + // Compute the number of millisecond ticks elapsed. + unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / + mClockFrequency.QuadPart); + + // Check for unexpected leaps in the Win32 performance counter. + // (This is caused by unexpected data across the PCI to ISA + // bridge, aka south bridge. See Microsoft KB274323.) + unsigned long elapsedTicks = GetTickCount() - mStartTick; + signed long msecOff = (signed long)(msecTicks - elapsedTicks); + if (msecOff < -100 || msecOff > 100) + { + // Adjust the starting time forwards. + LONGLONG msecAdjustment = mymin(msecOff * + mClockFrequency.QuadPart / 1000, elapsedTime - + mPrevElapsedTime); + mStartTime.QuadPart += msecAdjustment; + elapsedTime -= msecAdjustment; + + // Recompute the number of millisecond ticks elapsed. + msecTicks = (unsigned long)(1000 * elapsedTime / + mClockFrequency.QuadPart); + } + + // Store the current elapsed time for adjustments next time. + mPrevElapsedTime = elapsedTime; + + return msecTicks; +#else + +#ifdef __CELLOS_LV2__ + __int64 freq=sys_time_get_timebase_frequency(); + double dFreq=((double) freq) / 1000.0; + typedef uint64_t __int64; + typedef __int64 ClockSize; + ClockSize newTime; + __asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); + + return (newTime-mStartTime) / dFreq; +#else + + struct timeval currentTime; + gettimeofday(¤tTime, 0); + return (currentTime.tv_sec - mStartTime.tv_sec) * 1000 + + (currentTime.tv_usec - mStartTime.tv_usec) / 1000; +#endif //__CELLOS_LV2__ +#endif + } + + /// Returns the time in us since the last call to reset or since + /// the Clock was created. + unsigned long int getTimeMicroseconds() + { +#ifdef USE_WINDOWS_TIMERS + LARGE_INTEGER currentTime; + QueryPerformanceCounter(¤tTime); + LONGLONG elapsedTime = currentTime.QuadPart - + mStartTime.QuadPart; + + // Compute the number of millisecond ticks elapsed. + unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / + mClockFrequency.QuadPart); + + // Check for unexpected leaps in the Win32 performance counter. + // (This is caused by unexpected data across the PCI to ISA + // bridge, aka south bridge. See Microsoft KB274323.) + unsigned long elapsedTicks = GetTickCount() - mStartTick; + signed long msecOff = (signed long)(msecTicks - elapsedTicks); + if (msecOff < -100 || msecOff > 100) + { + // Adjust the starting time forwards. + LONGLONG msecAdjustment = mymin(msecOff * + mClockFrequency.QuadPart / 1000, elapsedTime - + mPrevElapsedTime); + mStartTime.QuadPart += msecAdjustment; + elapsedTime -= msecAdjustment; + } + + // Store the current elapsed time for adjustments next time. + mPrevElapsedTime = elapsedTime; + + // Convert to microseconds. + unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime / + mClockFrequency.QuadPart); + + return usecTicks; +#else + +#ifdef __CELLOS_LV2__ + __int64 freq=sys_time_get_timebase_frequency(); + double dFreq=((double) freq)/ 1000000.0; + typedef uint64_t __int64; + typedef __int64 ClockSize; + ClockSize newTime; + __asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); + + return (newTime-mStartTime) / dFreq; +#else + + struct timeval currentTime; + gettimeofday(¤tTime, 0); + return (currentTime.tv_sec - mStartTime.tv_sec) * 1000000 + + (currentTime.tv_usec - mStartTime.tv_usec); +#endif//__CELLOS_LV2__ +#endif + } + + private: +#ifdef USE_WINDOWS_TIMERS + LARGE_INTEGER mClockFrequency; + DWORD mStartTick; + LONGLONG mPrevElapsedTime; + LARGE_INTEGER mStartTime; +#else +#ifdef __CELLOS_LV2__ + uint64_t mStartTime; +#else + struct timeval mStartTime; +#endif +#endif //__CELLOS_LV2__ + + }; + +#endif //USE_BT_CLOCK + + +#ifdef USE_QUICKPROF + + +#include +#include +#include +#include + + + + +namespace hidden +{ + /// A simple data structure representing a single timed block + /// of code. + struct ProfileBlock + { + ProfileBlock() + { + currentBlockStartMicroseconds = 0; + currentCycleTotalMicroseconds = 0; + lastCycleTotalMicroseconds = 0; + totalMicroseconds = 0; + } + + /// The starting time (in us) of the current block update. + unsigned long int currentBlockStartMicroseconds; + + /// The accumulated time (in us) spent in this block during the + /// current profiling cycle. + unsigned long int currentCycleTotalMicroseconds; + + /// The accumulated time (in us) spent in this block during the + /// past profiling cycle. + unsigned long int lastCycleTotalMicroseconds; + + /// The total accumulated time (in us) spent in this block. + unsigned long int totalMicroseconds; + }; + +}; + +/// A static class that manages timing for a set of profiling blocks. +class btProfiler +{ +public: + /// A set of ways to retrieve block timing data. + enum BlockTimingMethod + { + /// The total time spent in the block (in seconds) since the + /// profiler was initialized. + BLOCK_TOTAL_SECONDS, + + /// The total time spent in the block (in ms) since the + /// profiler was initialized. + BLOCK_TOTAL_MILLISECONDS, + + /// The total time spent in the block (in us) since the + /// profiler was initialized. + BLOCK_TOTAL_MICROSECONDS, + + /// The total time spent in the block, as a % of the total + /// elapsed time since the profiler was initialized. + BLOCK_TOTAL_PERCENT, + + /// The time spent in the block (in seconds) in the most recent + /// profiling cycle. + BLOCK_CYCLE_SECONDS, + + /// The time spent in the block (in ms) in the most recent + /// profiling cycle. + BLOCK_CYCLE_MILLISECONDS, + + /// The time spent in the block (in us) in the most recent + /// profiling cycle. + BLOCK_CYCLE_MICROSECONDS, + + /// The time spent in the block (in seconds) in the most recent + /// profiling cycle, as a % of the total cycle time. + BLOCK_CYCLE_PERCENT + }; + + /// Initializes the profiler. This must be called first. If this is + /// never called, the profiler is effectively disabled; all other + /// functions will return immediately. The first parameter + /// is the name of an output data file; if this string is not empty, + /// data will be saved on every profiling cycle; if this string is + /// empty, no data will be saved to a file. The second parameter + /// determines which timing method is used when printing data to the + /// output file. + inline static void init(const std::string outputFilename="", + BlockTimingMethod outputMethod=BLOCK_CYCLE_MILLISECONDS); + + /// Cleans up allocated memory. + inline static void destroy(); + + /// Begins timing the named block of code. + inline static void beginBlock(const std::string& name); + + /// Updates the accumulated time spent in the named block by adding + /// the elapsed time since the last call to startBlock for this block + /// name. + inline static void endBlock(const std::string& name); + + /// Returns the time spent in the named block according to the + /// given timing method. See comments on BlockTimingMethod for details. + inline static double getBlockTime(const std::string& name, + BlockTimingMethod method=BLOCK_CYCLE_MILLISECONDS); + + /// Defines the end of a profiling cycle. Use this regularly if you + /// want to generate detailed timing information. This must not be + /// called within a timing block. + inline static void endProfilingCycle(); + + /// A helper function that creates a string of statistics for + /// each timing block. This is mainly for printing an overall + /// summary to the command line. + inline static std::string createStatsString( + BlockTimingMethod method=BLOCK_TOTAL_PERCENT); + +//private: + inline btProfiler(); + + inline ~btProfiler(); + + /// Prints an error message to standard output. + inline static void printError(const std::string& msg) + { + //btAssert(0); + std::cout << "[QuickProf error] " << msg << std::endl; + } + + /// Determines whether the profiler is enabled. + static bool mEnabled; + + /// The clock used to time profile blocks. + static btClock mClock; + + /// The starting time (in us) of the current profiling cycle. + static unsigned long int mCurrentCycleStartMicroseconds; + + /// The duration (in us) of the most recent profiling cycle. + static unsigned long int mLastCycleDurationMicroseconds; + + /// Internal map of named profile blocks. + static std::map mProfileBlocks; + + /// The data file used if this feature is enabled in 'init.' + static std::ofstream mOutputFile; + + /// Tracks whether we have begun print data to the output file. + static bool mFirstFileOutput; + + /// The method used when printing timing data to an output file. + static BlockTimingMethod mFileOutputMethod; + + /// The number of the current profiling cycle. + static unsigned long int mCycleNumber; +}; + + +btProfiler::btProfiler() +{ + // This never gets called because a btProfiler instance is never + // created. +} + +btProfiler::~btProfiler() +{ + // This never gets called because a btProfiler instance is never + // created. +} + +void btProfiler::init(const std::string outputFilename, + BlockTimingMethod outputMethod) +{ + mEnabled = true; + + if (!outputFilename.empty()) + { + mOutputFile.open(outputFilename.c_str()); + } + + mFileOutputMethod = outputMethod; + + mClock.reset(); + + // Set the start time for the first cycle. + mCurrentCycleStartMicroseconds = mClock.getTimeMicroseconds(); +} + +void btProfiler::destroy() +{ + if (!mEnabled) + { + return; + } + + if (mOutputFile.is_open()) + { + mOutputFile.close(); + } + + // Destroy all ProfileBlocks. + while (!mProfileBlocks.empty()) + { + delete (*mProfileBlocks.begin()).second; + mProfileBlocks.erase(mProfileBlocks.begin()); + } +} + +void btProfiler::beginBlock(const std::string& name) +{ + if (!mEnabled) + { + return; + } + + if (name.empty()) + { + printError("Cannot allow unnamed profile blocks."); + return; + } + + hidden::ProfileBlock* block = mProfileBlocks[name]; + + if (!block) + { + // Create a new ProfileBlock. + mProfileBlocks[name] = new hidden::ProfileBlock(); + block = mProfileBlocks[name]; + } + + // We do this at the end to get more accurate results. + block->currentBlockStartMicroseconds = mClock.getTimeMicroseconds(); +} + +void btProfiler::endBlock(const std::string& name) +{ + if (!mEnabled) + { + return; + } + + // We do this at the beginning to get more accurate results. + unsigned long int endTick = mClock.getTimeMicroseconds(); + + hidden::ProfileBlock* block = mProfileBlocks[name]; + + if (!block) + { + // The named block does not exist. Print an error. + printError("The profile block named '" + name + + "' does not exist."); + return; + } + + unsigned long int blockDuration = endTick - + block->currentBlockStartMicroseconds; + block->currentCycleTotalMicroseconds += blockDuration; + block->totalMicroseconds += blockDuration; +} + +double btProfiler::getBlockTime(const std::string& name, + BlockTimingMethod method) +{ + if (!mEnabled) + { + return 0; + } + + hidden::ProfileBlock* block = mProfileBlocks[name]; + + if (!block) + { + // The named block does not exist. Print an error. + printError("The profile block named '" + name + + "' does not exist."); + return 0; + } + + double result = 0; + + switch(method) + { + case BLOCK_TOTAL_SECONDS: + result = (double)block->totalMicroseconds * (double)0.000001; + break; + case BLOCK_TOTAL_MILLISECONDS: + result = (double)block->totalMicroseconds * (double)0.001; + break; + case BLOCK_TOTAL_MICROSECONDS: + result = (double)block->totalMicroseconds; + break; + case BLOCK_TOTAL_PERCENT: + { + double timeSinceInit = (double)mClock.getTimeMicroseconds(); + if (timeSinceInit <= 0) + { + result = 0; + } + else + { + result = 100.0 * (double)block->totalMicroseconds / + timeSinceInit; + } + break; + } + case BLOCK_CYCLE_SECONDS: + result = (double)block->lastCycleTotalMicroseconds * + (double)0.000001; + break; + case BLOCK_CYCLE_MILLISECONDS: + result = (double)block->lastCycleTotalMicroseconds * + (double)0.001; + break; + case BLOCK_CYCLE_MICROSECONDS: + result = (double)block->lastCycleTotalMicroseconds; + break; + case BLOCK_CYCLE_PERCENT: + { + if (0 == mLastCycleDurationMicroseconds) + { + // We have not yet finished a cycle, so just return zero + // percent to avoid a divide by zero error. + result = 0; + } + else + { + result = 100.0 * (double)block->lastCycleTotalMicroseconds / + mLastCycleDurationMicroseconds; + } + break; + } + default: + break; + } + + return result; +} + +void btProfiler::endProfilingCycle() +{ + if (!mEnabled) + { + return; + } + + // Store the duration of the cycle that just finished. + mLastCycleDurationMicroseconds = mClock.getTimeMicroseconds() - + mCurrentCycleStartMicroseconds; + + // For each block, update data for the cycle that just finished. + std::map::iterator iter; + for (iter = mProfileBlocks.begin(); iter != mProfileBlocks.end(); ++iter) + { + hidden::ProfileBlock* block = (*iter).second; + block->lastCycleTotalMicroseconds = + block->currentCycleTotalMicroseconds; + block->currentCycleTotalMicroseconds = 0; + } + + if (mOutputFile.is_open()) + { + // Print data to the output file. + if (mFirstFileOutput) + { + // On the first iteration, print a header line that shows the + // names of each profiling block. + mOutputFile << "#cycle, "; + + for (iter = mProfileBlocks.begin(); iter != mProfileBlocks.end(); + ++iter) + { + mOutputFile << (*iter).first << ", "; + } + + mOutputFile << std::endl; + mFirstFileOutput = false; + } + + mOutputFile << mCycleNumber << ", "; + + for (iter = mProfileBlocks.begin(); iter != mProfileBlocks.end(); + ++iter) + { + mOutputFile << getBlockTime((*iter).first, mFileOutputMethod) + << ", "; + } + + mOutputFile << std::endl; + } + + ++mCycleNumber; + mCurrentCycleStartMicroseconds = mClock.getTimeMicroseconds(); +} + +std::string btProfiler::createStatsString(BlockTimingMethod method) +{ + if (!mEnabled) + { + return ""; + } + + std::string s; + std::string suffix; + + switch(method) + { + case BLOCK_TOTAL_SECONDS: + suffix = "s"; + break; + case BLOCK_TOTAL_MILLISECONDS: + suffix = "ms"; + break; + case BLOCK_TOTAL_MICROSECONDS: + suffix = "us"; + break; + case BLOCK_TOTAL_PERCENT: + { + suffix = "%"; + break; + } + case BLOCK_CYCLE_SECONDS: + suffix = "s"; + break; + case BLOCK_CYCLE_MILLISECONDS: + suffix = "ms"; + break; + case BLOCK_CYCLE_MICROSECONDS: + suffix = "us"; + break; + case BLOCK_CYCLE_PERCENT: + { + suffix = "%"; + break; + } + default: + break; + } + + std::map::iterator iter; + for (iter = mProfileBlocks.begin(); iter != mProfileBlocks.end(); ++iter) + { + if (iter != mProfileBlocks.begin()) + { + s += "\n"; + } + + char blockTime[64]; + sprintf(blockTime, "%lf", getBlockTime((*iter).first, method)); + + s += (*iter).first; + s += ": "; + s += blockTime; + s += " "; + s += suffix; + } + + return s; +} + + +#define BEGIN_PROFILE(a) btProfiler::beginBlock(a) +#define END_PROFILE(a) btProfiler::endBlock(a) + +#else //USE_QUICKPROF +#define BEGIN_PROFILE(a) +#define END_PROFILE(a) + +#endif //USE_QUICKPROF + +#endif //QUICK_PROF_H + + diff --git a/extern/bullet2/src/LinearMath/btRandom.h b/extern/bullet2/src/LinearMath/btRandom.h new file mode 100644 index 00000000000..fdf65e01caf --- /dev/null +++ b/extern/bullet2/src/LinearMath/btRandom.h @@ -0,0 +1,42 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef GEN_RANDOM_H +#define GEN_RANDOM_H + +#ifdef MT19937 + +#include +#include + +#define GEN_RAND_MAX UINT_MAX + +SIMD_FORCE_INLINE void GEN_srand(unsigned int seed) { init_genrand(seed); } +SIMD_FORCE_INLINE unsigned int GEN_rand() { return genrand_int32(); } + +#else + +#include + +#define GEN_RAND_MAX RAND_MAX + +SIMD_FORCE_INLINE void GEN_srand(unsigned int seed) { srand(seed); } +SIMD_FORCE_INLINE unsigned int GEN_rand() { return rand(); } + +#endif + +#endif + diff --git a/extern/bullet2/src/LinearMath/btScalar.h b/extern/bullet2/src/LinearMath/btScalar.h new file mode 100644 index 00000000000..01ad93e786a --- /dev/null +++ b/extern/bullet2/src/LinearMath/btScalar.h @@ -0,0 +1,181 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef SIMD___SCALAR_H +#define SIMD___SCALAR_H + +#include + +#include +#include +#include + +#ifdef WIN32 + + #if defined(__MINGW32__) || defined(__CYGWIN__) || (defined (_MSC_VER) && _MSC_VER < 1300) + #define SIMD_FORCE_INLINE inline + #define ATTRIBUTE_ALIGNED16(a) a + #else + #define BT_HAS_ALIGNED_ALOCATOR + #pragma warning(disable:4530) + #pragma warning(disable:4996) + #pragma warning(disable:4786) + #define SIMD_FORCE_INLINE __forceinline + #define ATTRIBUTE_ALIGNED16(a) __declspec(align(16)) a + #ifdef _XBOX + #define BT_USE_VMX128 + #else + #define BT_USE_SSE + #endif + #endif //__MINGW32__ + + #include + #define btAssert assert + //btFullAssert is optional, slows down a lot + #define btFullAssert(x) +#else + +#if defined (__CELLOS_LV2__) + #define SIMD_FORCE_INLINE inline + #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + #ifndef assert + #include + #endif + #define btAssert assert + //btFullAssert is optional, slows down a lot + #define btFullAssert(x) +#else + + //non-windows systems + + #define SIMD_FORCE_INLINE inline + #define ATTRIBUTE_ALIGNED16(a) a + #ifndef assert + #include + #endif + #define btAssert assert + //btFullAssert is optional, slows down a lot + #define btFullAssert(x) +#endif //__CELLOS_LV2__ +#endif + +/// older compilers (gcc 3.x) and Sun needs double version of sqrt etc. +/// exclude Apple Intel (i's assumed to be a Macbook or new Intel Dual Core Processor) +#if defined (__sun) || defined (__sun__) || defined (__sparc) || (defined (__APPLE__) && ! defined (__i386__)) +//use slow double float precision operation on those platforms +#ifndef BT_USE_DOUBLE_PRECISION +#define BT_FORCE_DOUBLE_FUNCTIONS +#endif +#endif + +#if defined(BT_USE_DOUBLE_PRECISION) +typedef double btScalar; +#else +typedef float btScalar; +#endif + + +#if defined(BT_USE_DOUBLE_PRECISION) || defined(BT_FORCE_DOUBLE_FUNCTIONS) + +SIMD_FORCE_INLINE btScalar btSqrt(btScalar x) { return sqrt(x); } +SIMD_FORCE_INLINE btScalar btFabs(btScalar x) { return fabs(x); } +SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cos(x); } +SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sin(x); } +SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tan(x); } +SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { return acos(x); } +SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { return asin(x); } +SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atan(x); } +SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2(x, y); } +SIMD_FORCE_INLINE btScalar btExp(btScalar x) { return exp(x); } +SIMD_FORCE_INLINE btScalar btLog(btScalar x) { return log(x); } +SIMD_FORCE_INLINE btScalar btPow(btScalar x,btScalar y) { return pow(x,y); } + +#else + +SIMD_FORCE_INLINE btScalar btSqrt(btScalar x) { return sqrtf(x); } +SIMD_FORCE_INLINE btScalar btFabs(btScalar x) { return fabsf(x); } +SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cosf(x); } +SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sinf(x); } +SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tanf(x); } +SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { return acosf(x); } +SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { return asinf(x); } +SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atanf(x); } +SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2f(x, y); } +SIMD_FORCE_INLINE btScalar btExp(btScalar x) { return expf(x); } +SIMD_FORCE_INLINE btScalar btLog(btScalar x) { return logf(x); } +SIMD_FORCE_INLINE btScalar btPow(btScalar x,btScalar y) { return powf(x,y); } + +#endif + +#define SIMD_2_PI btScalar(6.283185307179586232) +#define SIMD_PI (SIMD_2_PI * btScalar(0.5)) +#define SIMD_HALF_PI (SIMD_2_PI * btScalar(0.25)) +#define SIMD_RADS_PER_DEG (SIMD_2_PI / btScalar(360.0)) +#define SIMD_DEGS_PER_RAD (btScalar(360.0) / SIMD_2_PI) + +#ifdef BT_USE_DOUBLE_PRECISION +#define SIMD_EPSILON DBL_EPSILON +#define SIMD_INFINITY DBL_MAX +#else +#define SIMD_EPSILON FLT_EPSILON +#define SIMD_INFINITY FLT_MAX +#endif + +SIMD_FORCE_INLINE btScalar btAtan2Fast(btScalar y, btScalar x) +{ + btScalar coeff_1 = SIMD_PI / 4.0f; + btScalar coeff_2 = 3.0f * coeff_1; + btScalar abs_y = btFabs(y); + btScalar angle; + if (x >= 0.0f) { + btScalar r = (x - abs_y) / (x + abs_y); + angle = coeff_1 - coeff_1 * r; + } else { + btScalar r = (x + abs_y) / (abs_y - x); + angle = coeff_2 - coeff_1 * r; + } + return (y < 0.0f) ? -angle : angle; +} + +SIMD_FORCE_INLINE bool btFuzzyZero(btScalar x) { return btFabs(x) < SIMD_EPSILON; } + +SIMD_FORCE_INLINE bool btEqual(btScalar a, btScalar eps) { + return (((a) <= eps) && !((a) < -eps)); +} +SIMD_FORCE_INLINE bool btGreaterEqual (btScalar a, btScalar eps) { + return (!((a) <= eps)); +} + +/*SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cosf(x); } +SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sinf(x); } +SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tanf(x); } +SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { return acosf(x); } +SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { return asinf(x); } +SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atanf(x); } +SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2f(x, y); } +*/ + +SIMD_FORCE_INLINE int btIsNegative(btScalar x) { + return x < btScalar(0.0) ? 1 : 0; +} + +SIMD_FORCE_INLINE btScalar btRadians(btScalar x) { return x * SIMD_RADS_PER_DEG; } +SIMD_FORCE_INLINE btScalar btDegrees(btScalar x) { return x * SIMD_DEGS_PER_RAD; } + +#define BT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + + +#endif //SIMD___SCALAR_H diff --git a/extern/bullet2/src/LinearMath/btSimdMinMax.h b/extern/bullet2/src/LinearMath/btSimdMinMax.h new file mode 100644 index 00000000000..75e83f3c53f --- /dev/null +++ b/extern/bullet2/src/LinearMath/btSimdMinMax.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef SIMD_MINMAX_H +#define SIMD_MINMAX_H +#include "btScalar.h" + +template +SIMD_FORCE_INLINE const T& btMin(const T& a, const T& b) { + return b < a ? b : a; +} + +template +SIMD_FORCE_INLINE const T& btMax(const T& a, const T& b) { + return a < b ? b : a; +} + +template +SIMD_FORCE_INLINE void btSetMin(T& a, const T& b) { + if (a > b) a = b; +} + +template +SIMD_FORCE_INLINE void btSetMax(T& a, const T& b) { + if (a < b) a = b; +} + +#endif diff --git a/extern/bullet2/src/LinearMath/btStackAlloc.h b/extern/bullet2/src/LinearMath/btStackAlloc.h new file mode 100644 index 00000000000..d219b453537 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btStackAlloc.h @@ -0,0 +1,106 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +/* +StackAlloc extracted from GJK-EPA collision solver by Nathanael Presson +Nov.2006 +*/ + +#ifndef BT_STACK_ALLOC +#define BT_STACK_ALLOC + +#include "btScalar.h" //for btAssert + +struct btBlock +{ + btBlock* previous; + unsigned char* address; +}; + +///StackAlloc provides some fast stack-based memory allocator (LIFO last-in first-out) +class btStackAlloc +{ +public: + + btStackAlloc(unsigned int size) { ctor();create(size); } + ~btStackAlloc() { destroy(); } + + inline void create(unsigned int size) + { + destroy(); + data = new unsigned char[size]; + totalsize = size; + } + inline void destroy() + { + btAssert(usedsize==0); + //Raise(L"StackAlloc is still in use"); + + if(usedsize==0) + { + if(!ischild) delete[] data; + data = 0; + usedsize = 0; + } + + } + unsigned char* allocate(unsigned int size) + { + const unsigned int nus(usedsize+size); + if(nusprevious = current; + pb->address = data+usedsize; + current = pb; + return(pb); + } + inline void endBlock(btBlock* block) + { + btAssert(block==current); + //Raise(L"Unmatched blocks"); + if(block==current) + { + current = block->previous; + usedsize = (unsigned int)((block->address-data)-sizeof(btBlock)); + } + } + +private: + void ctor() + { + data = 0; + totalsize = 0; + usedsize = 0; + current = 0; + ischild = false; + } + unsigned char* data; + unsigned int totalsize; + unsigned int usedsize; + btBlock* current; + bool ischild; +}; + +#endif //BT_STACK_ALLOC diff --git a/extern/bullet2/src/LinearMath/btTransform.h b/extern/bullet2/src/LinearMath/btTransform.h new file mode 100644 index 00000000000..2d55fec83a4 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btTransform.h @@ -0,0 +1,206 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef btTransform_H +#define btTransform_H + +#include "btVector3.h" +#include "btMatrix3x3.h" + + +///btTransform supports rigid transforms (only translation and rotation, no scaling/shear) +class btTransform { + + +public: + + + btTransform() {} + + explicit SIMD_FORCE_INLINE btTransform(const btQuaternion& q, + const btVector3& c = btVector3(btScalar(0), btScalar(0), btScalar(0))) + : m_basis(q), + m_origin(c) + {} + + explicit SIMD_FORCE_INLINE btTransform(const btMatrix3x3& b, + const btVector3& c = btVector3(btScalar(0), btScalar(0), btScalar(0))) + : m_basis(b), + m_origin(c) + {} + + SIMD_FORCE_INLINE btTransform (const btTransform& other) + : m_basis(other.m_basis), + m_origin(other.m_origin) + { + } + + SIMD_FORCE_INLINE btTransform& operator=(const btTransform& other) + { + m_basis = other.m_basis; + m_origin = other.m_origin; + return *this; + } + + + SIMD_FORCE_INLINE void mult(const btTransform& t1, const btTransform& t2) { + m_basis = t1.m_basis * t2.m_basis; + m_origin = t1(t2.m_origin); + } + +/* void multInverseLeft(const btTransform& t1, const btTransform& t2) { + btVector3 v = t2.m_origin - t1.m_origin; + m_basis = btMultTransposeLeft(t1.m_basis, t2.m_basis); + m_origin = v * t1.m_basis; + } + */ + + + SIMD_FORCE_INLINE btVector3 operator()(const btVector3& x) const + { + return btVector3(m_basis[0].dot(x) + m_origin.x(), + m_basis[1].dot(x) + m_origin.y(), + m_basis[2].dot(x) + m_origin.z()); + } + + SIMD_FORCE_INLINE btVector3 operator*(const btVector3& x) const + { + return (*this)(x); + } + + SIMD_FORCE_INLINE btMatrix3x3& getBasis() { return m_basis; } + SIMD_FORCE_INLINE const btMatrix3x3& getBasis() const { return m_basis; } + + SIMD_FORCE_INLINE btVector3& getOrigin() { return m_origin; } + SIMD_FORCE_INLINE const btVector3& getOrigin() const { return m_origin; } + + btQuaternion getRotation() const { + btQuaternion q; + m_basis.getRotation(q); + return q; + } + template + void setValue(const Scalar2 *m) + { + m_basis.setValue(m); + m_origin.setValue(&m[12]); + } + + + void setFromOpenGLMatrix(const btScalar *m) + { + m_basis.setFromOpenGLSubMatrix(m); + m_origin.setValue(m[12],m[13],m[14]); + } + + void getOpenGLMatrix(btScalar *m) const + { + m_basis.getOpenGLSubMatrix(m); + m[12] = m_origin.x(); + m[13] = m_origin.y(); + m[14] = m_origin.z(); + m[15] = btScalar(1.0); + } + + SIMD_FORCE_INLINE void setOrigin(const btVector3& origin) + { + m_origin = origin; + } + + SIMD_FORCE_INLINE btVector3 invXform(const btVector3& inVec) const; + + + + SIMD_FORCE_INLINE void setBasis(const btMatrix3x3& basis) + { + m_basis = basis; + } + + SIMD_FORCE_INLINE void setRotation(const btQuaternion& q) + { + m_basis.setRotation(q); + } + + + + void setIdentity() + { + m_basis.setIdentity(); + m_origin.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); + } + + + btTransform& operator*=(const btTransform& t) + { + m_origin += m_basis * t.m_origin; + m_basis *= t.m_basis; + return *this; + } + + btTransform inverse() const + { + btMatrix3x3 inv = m_basis.transpose(); + return btTransform(inv, inv * -m_origin); + } + + btTransform inverseTimes(const btTransform& t) const; + + btTransform operator*(const btTransform& t) const; + + static btTransform getIdentity() + { + btTransform tr; + tr.setIdentity(); + return tr; + } + +private: + + btMatrix3x3 m_basis; + btVector3 m_origin; +}; + + +SIMD_FORCE_INLINE btVector3 +btTransform::invXform(const btVector3& inVec) const +{ + btVector3 v = inVec - m_origin; + return (m_basis.transpose() * v); +} + +SIMD_FORCE_INLINE btTransform +btTransform::inverseTimes(const btTransform& t) const +{ + btVector3 v = t.getOrigin() - m_origin; + return btTransform(m_basis.transposeTimes(t.m_basis), + v * m_basis); +} + +SIMD_FORCE_INLINE btTransform +btTransform::operator*(const btTransform& t) const +{ + return btTransform(m_basis * t.m_basis, + (*this)(t.m_origin)); +} + + + +#endif + + + + + diff --git a/extern/bullet2/src/LinearMath/btTransformUtil.h b/extern/bullet2/src/LinearMath/btTransformUtil.h new file mode 100644 index 00000000000..bc42fd166b6 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btTransformUtil.h @@ -0,0 +1,138 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef SIMD_TRANSFORM_UTIL_H +#define SIMD_TRANSFORM_UTIL_H + +#include "btTransform.h" +#define ANGULAR_MOTION_THRESHOLD btScalar(0.5)*SIMD_HALF_PI + + + +#define SIMDSQRT12 btScalar(0.7071067811865475244008443621048490) + +#define btRecipSqrt(x) ((btScalar)(btScalar(1.0)/btSqrt(btScalar(x)))) /* reciprocal square root */ + +inline btVector3 btAabbSupport(const btVector3& halfExtents,const btVector3& supportDir) +{ + return btVector3(supportDir.x() < btScalar(0.0) ? -halfExtents.x() : halfExtents.x(), + supportDir.y() < btScalar(0.0) ? -halfExtents.y() : halfExtents.y(), + supportDir.z() < btScalar(0.0) ? -halfExtents.z() : halfExtents.z()); +} + + +inline void btPlaneSpace1 (const btVector3& n, btVector3& p, btVector3& q) +{ + if (btFabs(n.z()) > SIMDSQRT12) { + // choose p in y-z plane + btScalar a = n[1]*n[1] + n[2]*n[2]; + btScalar k = btRecipSqrt (a); + p.setValue(0,-n[2]*k,n[1]*k); + // set q = n x p + q.setValue(a*k,-n[0]*p[2],n[0]*p[1]); + } + else { + // choose p in x-y plane + btScalar a = n.x()*n.x() + n.y()*n.y(); + btScalar k = btRecipSqrt (a); + p.setValue(-n.y()*k,n.x()*k,0); + // set q = n x p + q.setValue(-n.z()*p.y(),n.z()*p.x(),a*k); + } +} + + + +/// Utils related to temporal transforms +class btTransformUtil +{ + +public: + + static void integrateTransform(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep,btTransform& predictedTransform) + { + predictedTransform.setOrigin(curTrans.getOrigin() + linvel * timeStep); +// #define QUATERNION_DERIVATIVE + #ifdef QUATERNION_DERIVATIVE + btQuaternion predictedOrn = curTrans.getRotation(); + predictedOrn += (angvel * predictedOrn) * (timeStep * btScalar(0.5)); + predictedOrn.normalize(); + #else + //exponential map + btVector3 axis; + btScalar fAngle = angvel.length(); + //limit the angular motion + if (fAngle*timeStep > ANGULAR_MOTION_THRESHOLD) + { + fAngle = ANGULAR_MOTION_THRESHOLD / timeStep; + } + + if ( fAngle < btScalar(0.001) ) + { + // use Taylor's expansions of sync function + axis = angvel*( btScalar(0.5)*timeStep-(timeStep*timeStep*timeStep)*(btScalar(0.020833333333))*fAngle*fAngle ); + } + else + { + // sync(fAngle) = sin(c*fAngle)/t + axis = angvel*( btSin(btScalar(0.5)*fAngle*timeStep)/fAngle ); + } + btQuaternion dorn (axis.x(),axis.y(),axis.z(),btCos( fAngle*timeStep*btScalar(0.5) )); + btQuaternion orn0 = curTrans.getRotation(); + + btQuaternion predictedOrn = dorn * orn0; + predictedOrn.normalize(); + #endif + predictedTransform.setRotation(predictedOrn); + } + + static void calculateVelocity(const btTransform& transform0,const btTransform& transform1,btScalar timeStep,btVector3& linVel,btVector3& angVel) + { + linVel = (transform1.getOrigin() - transform0.getOrigin()) / timeStep; + btVector3 axis; + btScalar angle; + calculateDiffAxisAngle(transform0,transform1,axis,angle); + angVel = axis * angle / timeStep; + } + + static void calculateDiffAxisAngle(const btTransform& transform0,const btTransform& transform1,btVector3& axis,btScalar& angle) + { + + #ifdef USE_QUATERNION_DIFF + btQuaternion orn0 = transform0.getRotation(); + btQuaternion orn1a = transform1.getRotation(); + btQuaternion orn1 = orn0.farthest(orn1a); + btQuaternion dorn = orn1 * orn0.inverse(); +#else + btMatrix3x3 dmat = transform1.getBasis() * transform0.getBasis().inverse(); + btQuaternion dorn; + dmat.getRotation(dorn); +#endif//USE_QUATERNION_DIFF + + angle = dorn.getAngle(); + axis = btVector3(dorn.x(),dorn.y(),dorn.z()); + axis[3] = btScalar(0.); + //check for axis length + btScalar len = axis.length2(); + if (len < SIMD_EPSILON*SIMD_EPSILON) + axis = btVector3(btScalar(1.),btScalar(0.),btScalar(0.)); + else + axis /= btSqrt(len); + } + +}; + +#endif //SIMD_TRANSFORM_UTIL_H + diff --git a/extern/bullet2/src/LinearMath/btVector3.h b/extern/bullet2/src/LinearMath/btVector3.h new file mode 100644 index 00000000000..74d41ad2a19 --- /dev/null +++ b/extern/bullet2/src/LinearMath/btVector3.h @@ -0,0 +1,402 @@ +/* +Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + + +#ifndef SIMD__VECTOR3_H +#define SIMD__VECTOR3_H + +#include "btQuadWord.h" + +///btVector3 can be used to represent 3D points and vectors. +///It has an un-used w component to suit 16-byte alignment when btVector3 is stored in containers. This extra component can be used by derived classes (Quaternion?) or by user +///Ideally, this class should be replaced by a platform optimized SIMD version that keeps the data in registers +class btVector3 : public btQuadWord { + +public: + SIMD_FORCE_INLINE btVector3() {} + + + + SIMD_FORCE_INLINE btVector3(const btScalar& x, const btScalar& y, const btScalar& z) + :btQuadWord(x,y,z,btScalar(0.)) + { + } + +// SIMD_FORCE_INLINE btVector3(const btScalar& x, const btScalar& y, const btScalar& z,const btScalar& w) +// : btQuadWord(x,y,z,w) +// { +// } + + + + SIMD_FORCE_INLINE btVector3& operator+=(const btVector3& v) + { + m_x += v.x(); m_y += v.y(); m_z += v.z(); + return *this; + } + + + + SIMD_FORCE_INLINE btVector3& operator-=(const btVector3& v) + { + m_x -= v.x(); m_y -= v.y(); m_z -= v.z(); + return *this; + } + + SIMD_FORCE_INLINE btVector3& operator*=(const btScalar& s) + { + m_x *= s; m_y *= s; m_z *= s; + return *this; + } + + SIMD_FORCE_INLINE btVector3& operator/=(const btScalar& s) + { + btFullAssert(s != btScalar(0.0)); + return *this *= btScalar(1.0) / s; + } + + SIMD_FORCE_INLINE btScalar dot(const btVector3& v) const + { + return m_x * v.x() + m_y * v.y() + m_z * v.z(); + } + + SIMD_FORCE_INLINE btScalar length2() const + { + return dot(*this); + } + + SIMD_FORCE_INLINE btScalar length() const + { + return btSqrt(length2()); + } + + SIMD_FORCE_INLINE btScalar distance2(const btVector3& v) const; + + SIMD_FORCE_INLINE btScalar distance(const btVector3& v) const; + + SIMD_FORCE_INLINE btVector3& normalize() + { + return *this /= length(); + } + + SIMD_FORCE_INLINE btVector3 normalized() const; + + SIMD_FORCE_INLINE btVector3 rotate( const btVector3& wAxis, const btScalar angle ); + + SIMD_FORCE_INLINE btScalar angle(const btVector3& v) const + { + btScalar s = btSqrt(length2() * v.length2()); + btFullAssert(s != btScalar(0.0)); + return btAcos(dot(v) / s); + } + + SIMD_FORCE_INLINE btVector3 absolute() const + { + return btVector3( + btFabs(m_x), + btFabs(m_y), + btFabs(m_z)); + } + + SIMD_FORCE_INLINE btVector3 cross(const btVector3& v) const + { + return btVector3( + m_y * v.z() - m_z * v.y(), + m_z * v.x() - m_x * v.z(), + m_x * v.y() - m_y * v.x()); + } + + SIMD_FORCE_INLINE btScalar triple(const btVector3& v1, const btVector3& v2) const + { + return m_x * (v1.y() * v2.z() - v1.z() * v2.y()) + + m_y * (v1.z() * v2.x() - v1.x() * v2.z()) + + m_z * (v1.x() * v2.y() - v1.y() * v2.x()); + } + + SIMD_FORCE_INLINE int minAxis() const + { + return m_x < m_y ? (m_x < m_z ? 0 : 2) : (m_y < m_z ? 1 : 2); + } + + SIMD_FORCE_INLINE int maxAxis() const + { + return m_x < m_y ? (m_y < m_z ? 2 : 1) : (m_x < m_z ? 2 : 0); + } + + SIMD_FORCE_INLINE int furthestAxis() const + { + return absolute().minAxis(); + } + + SIMD_FORCE_INLINE int closestAxis() const + { + return absolute().maxAxis(); + } + + SIMD_FORCE_INLINE void setInterpolate3(const btVector3& v0, const btVector3& v1, btScalar rt) + { + btScalar s = btScalar(1.0) - rt; + m_x = s * v0.x() + rt * v1.x(); + m_y = s * v0.y() + rt * v1.y(); + m_z = s * v0.z() + rt * v1.z(); + //don't do the unused w component + // m_co[3] = s * v0[3] + rt * v1[3]; + } + + SIMD_FORCE_INLINE btVector3 lerp(const btVector3& v, const btScalar& t) const + { + return btVector3(m_x + (v.x() - m_x) * t, + m_y + (v.y() - m_y) * t, + m_z + (v.z() - m_z) * t); + } + + + SIMD_FORCE_INLINE btVector3& operator*=(const btVector3& v) + { + m_x *= v.x(); m_y *= v.y(); m_z *= v.z(); + return *this; + } + + + +}; + +SIMD_FORCE_INLINE btVector3 +operator+(const btVector3& v1, const btVector3& v2) +{ + return btVector3(v1.x() + v2.x(), v1.y() + v2.y(), v1.z() + v2.z()); +} + +SIMD_FORCE_INLINE btVector3 +operator*(const btVector3& v1, const btVector3& v2) +{ + return btVector3(v1.x() * v2.x(), v1.y() * v2.y(), v1.z() * v2.z()); +} + +SIMD_FORCE_INLINE btVector3 +operator-(const btVector3& v1, const btVector3& v2) +{ + return btVector3(v1.x() - v2.x(), v1.y() - v2.y(), v1.z() - v2.z()); +} + +SIMD_FORCE_INLINE btVector3 +operator-(const btVector3& v) +{ + return btVector3(-v.x(), -v.y(), -v.z()); +} + +SIMD_FORCE_INLINE btVector3 +operator*(const btVector3& v, const btScalar& s) +{ + return btVector3(v.x() * s, v.y() * s, v.z() * s); +} + +SIMD_FORCE_INLINE btVector3 +operator*(const btScalar& s, const btVector3& v) +{ + return v * s; +} + +SIMD_FORCE_INLINE btVector3 +operator/(const btVector3& v, const btScalar& s) +{ + btFullAssert(s != btScalar(0.0)); + return v * (btScalar(1.0) / s); +} + +SIMD_FORCE_INLINE btVector3 +operator/(const btVector3& v1, const btVector3& v2) +{ + return btVector3(v1.x() / v2.x(),v1.y() / v2.y(),v1.z() / v2.z()); +} + +SIMD_FORCE_INLINE btScalar +dot(const btVector3& v1, const btVector3& v2) +{ + return v1.dot(v2); +} + + + +SIMD_FORCE_INLINE btScalar +distance2(const btVector3& v1, const btVector3& v2) +{ + return v1.distance2(v2); +} + + +SIMD_FORCE_INLINE btScalar +distance(const btVector3& v1, const btVector3& v2) +{ + return v1.distance(v2); +} + +SIMD_FORCE_INLINE btScalar +angle(const btVector3& v1, const btVector3& v2) +{ + return v1.angle(v2); +} + +SIMD_FORCE_INLINE btVector3 +cross(const btVector3& v1, const btVector3& v2) +{ + return v1.cross(v2); +} + +SIMD_FORCE_INLINE btScalar +triple(const btVector3& v1, const btVector3& v2, const btVector3& v3) +{ + return v1.triple(v2, v3); +} + +SIMD_FORCE_INLINE btVector3 +lerp(const btVector3& v1, const btVector3& v2, const btScalar& t) +{ + return v1.lerp(v2, t); +} + + +SIMD_FORCE_INLINE bool operator==(const btVector3& p1, const btVector3& p2) +{ + return p1.x() == p2.x() && p1.y() == p2.y() && p1.z() == p2.z(); +} + +SIMD_FORCE_INLINE btScalar btVector3::distance2(const btVector3& v) const +{ + return (v - *this).length2(); +} + +SIMD_FORCE_INLINE btScalar btVector3::distance(const btVector3& v) const +{ + return (v - *this).length(); +} + +SIMD_FORCE_INLINE btVector3 btVector3::normalized() const +{ + return *this / length(); +} + +SIMD_FORCE_INLINE btVector3 btVector3::rotate( const btVector3& wAxis, const btScalar angle ) +{ + // wAxis must be a unit lenght vector + + btVector3 o = wAxis * wAxis.dot( *this ); + btVector3 x = *this - o; + btVector3 y; + + y = wAxis.cross( *this ); + + return ( o + x * btCos( angle ) + y * btSin( angle ) ); +} + +class btVector4 : public btVector3 +{ +public: + + SIMD_FORCE_INLINE btVector4() {} + + + SIMD_FORCE_INLINE btVector4(const btScalar& x, const btScalar& y, const btScalar& z,const btScalar& w) + : btVector3(x,y,z) + { + m_unusedW = w; + } + + + SIMD_FORCE_INLINE btVector4 absolute4() const + { + return btVector4( + btFabs(m_x), + btFabs(m_y), + btFabs(m_z), + btFabs(m_unusedW)); + } + + + + btScalar getW() const { return m_unusedW;} + + + SIMD_FORCE_INLINE int maxAxis4() const + { + int maxIndex = -1; + btScalar maxVal = btScalar(-1e30); + if (m_x > maxVal) + { + maxIndex = 0; + maxVal = m_x; + } + if (m_y > maxVal) + { + maxIndex = 1; + maxVal = m_y; + } + if (m_z > maxVal) + { + maxIndex = 2; + maxVal = m_z; + } + if (m_unusedW > maxVal) + { + maxIndex = 3; + maxVal = m_unusedW; + } + + + + + return maxIndex; + + } + + + SIMD_FORCE_INLINE int minAxis4() const + { + int minIndex = -1; + btScalar minVal = btScalar(1e30); + if (m_x < minVal) + { + minIndex = 0; + minVal = m_x; + } + if (m_y < minVal) + { + minIndex = 1; + minVal = m_y; + } + if (m_z < minVal) + { + minIndex = 2; + minVal = m_z; + } + if (m_unusedW < minVal) + { + minIndex = 3; + minVal = m_unusedW; + } + + return minIndex; + + } + + + SIMD_FORCE_INLINE int closestAxis4() const + { + return absolute4().maxAxis4(); + } + +}; + +#endif //SIMD__VECTOR3_H diff --git a/extern/bullet2/src/Makefile b/extern/bullet2/src/Makefile new file mode 100644 index 00000000000..567811bae28 --- /dev/null +++ b/extern/bullet2/src/Makefile @@ -0,0 +1,71 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# + +LIBNAME = bullet2 +DIR = $(OCGDIR)/extern/$(LIBNAME) + +BULLETDIRS = \ +LinearMath \ +BulletCollision/BroadphaseCollision \ +BulletCollision/CollisionShapes \ +BulletCollision/NarrowPhaseCollision \ +BulletCollision/CollisionDispatch \ +BulletDynamics/ConstraintSolver \ +BulletDynamics/Vehicle \ +BulletDynamics/Dynamics + +CCSRCS = $(wildcard \ +LinearMath/*.cpp \ +BulletCollision/BroadphaseCollision/*.cpp \ +BulletCollision/CollisionShapes/*.cpp \ +BulletCollision/NarrowPhaseCollision/*.cpp \ +BulletCollision/CollisionDispatch/*.cpp \ +BulletDynamics/ConstraintSolver/*.cpp \ +BulletDynamics/Vehicle/*.cpp \ +BulletDynamics/Dynamics/*.cpp) + +CPPFLAGS += -D_LIB -I. -IBulletCollision -IBulletDynamics -ILinearMath + +all debug:: objdirs + +include nan_compile.mk + +.PHONY: objdirs clean +objdirs: + @for i in $(BULLETDIRS); do \ + [ -d $(DIR)/$(DEBUG_DIR)$$i ] || mkdir -p $(DIR)/$(DEBUG_DIR)$$i; \ + done + +clean:: + rm -rf $(DIR) + rm -rf $(NAN_BULLET2)/lib/libbullet2.a + rm -rf $(NAN_BULLET2)/include diff --git a/extern/bullet2/src/SConscript b/extern/bullet2/src/SConscript new file mode 100644 index 00000000000..6280c49066d --- /dev/null +++ b/extern/bullet2/src/SConscript @@ -0,0 +1,97 @@ +#!/usr/bin/python +import sys +import os + +Import('env') + +defs = 'USE_DOUBLES QHULL _LIB' +cflags = [] + +if env['OURPLATFORM']=='win32-vc': + defs += ' WIN32 NDEBUG _WINDOWS _LIB' + #cflags += ['/MT', '/W3', '/GX', '/O2', '/Op'] + cflags += ['/MT', '/W3', '/GX', '/Og', '/Ot', '/Ob1', '/Op', '/G6'] +elif env['OURPLATFORM']=='win32-mingw': + defs += ' NDEBUG' + cflags += ['-O2'] +elif sys.platform=='linux2' or sys.platform=='linux-i386' or sys.platform=='freebsd4' or sys.platform=='freebsd5': + defs += ' NDEBUG' + cflags += ['-O2'] +elif sys.platform=='darwin': + defs += ' NDEBUG' + cflags += ['-O2','-pipe', '-fPIC', '-funsigned-char', '-ffast-math'] + +linearmath_src = env.Glob("LinearMath/*.cpp") +bulletdyn_src = ["BulletDynamics/ConstraintSolver/btContactConstraint.cpp", + "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp", + "BulletDynamics/ConstraintSolver/btHingeConstraint.cpp", + "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp", + "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp", + "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp", + "BulletDynamics/ConstraintSolver/btTypedConstraint.cpp", + "BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp", + "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp", + "BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp", + "BulletDynamics/Dynamics/btRigidBody.cpp", + "BulletDynamics/Vehicle/btRaycastVehicle.cpp", + "BulletDynamics/Vehicle/btWheelInfo.cpp"] +collision_src = ["BulletCollision/BroadphaseCollision/btAxisSweep3.cpp", + "BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp", + "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp", + "BulletCollision/BroadphaseCollision/btDispatcher.cpp", + "BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp", + "BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp", + "BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp", + "BulletCollision/CollisionDispatch/btCollisionObject.cpp", + "BulletCollision/CollisionDispatch/btCollisionWorld.cpp", + "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp", + "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp", + "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp", + "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp", + "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp", + "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp", + "BulletCollision/CollisionDispatch/btManifoldResult.cpp", + "BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp", + "BulletCollision/CollisionDispatch/btUnionFind.cpp", + "BulletCollision/CollisionShapes/btBoxShape.cpp", + "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp", + "BulletCollision/CollisionShapes/btCollisionShape.cpp", + "BulletCollision/CollisionShapes/btCompoundShape.cpp", + "BulletCollision/CollisionShapes/btConcaveShape.cpp", + "BulletCollision/CollisionShapes/btConeShape.cpp", + "BulletCollision/CollisionShapes/btConvexHullShape.cpp", + "BulletCollision/CollisionShapes/btConvexShape.cpp", + "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp", + "BulletCollision/CollisionShapes/btCylinderShape.cpp", + "BulletCollision/CollisionShapes/btEmptyShape.cpp", + "BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp", + "BulletCollision/CollisionShapes/btMultiSphereShape.cpp", + "BulletCollision/CollisionShapes/btOptimizedBvh.cpp", + "BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp", + "BulletCollision/CollisionShapes/btTetrahedronShape.cpp", + "BulletCollision/CollisionShapes/btSphereShape.cpp", + "BulletCollision/CollisionShapes/btStaticPlaneShape.cpp", + "BulletCollision/CollisionShapes/btStridingMeshInterface.cpp", + "BulletCollision/CollisionShapes/btTriangleCallback.cpp", + "BulletCollision/CollisionShapes/btTriangleBuffer.cpp", + "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp", + "BulletCollision/CollisionShapes/btTriangleMesh.cpp", + "BulletCollision/CollisionShapes/btTriangleMeshShape.cpp", + "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp", + "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp", + "BulletCollision/NarrowPhaseCollision/btGjkEpa.cpp", + "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp", + "BulletCollision/NarrowPhaseCollision/btConvexCast.cpp", + "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp", + "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp", + "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp", + "BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp", + "BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp", + "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp", + "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp"] + +incs = '. BulletCollision BulletDynamics LinearMath' + +env.BlenderLib ( libname = 'extern_bullet2linmath', sources=linearmath_src, includes=Split(incs), defines=Split(defs), libtype=['game2', 'player'], priority=[20, 170], compileflags=cflags ) +env.BlenderLib ( libname = 'extern_bullet2dynamics', sources=bulletdyn_src, includes=Split(incs), defines=Split(defs), libtype=['game2', 'player'], priority=[19, 169], compileflags=cflags ) +env.BlenderLib ( libname = 'extern_bullet2collision', sources=collision_src, includes=Split(incs), defines=Split(defs), libtype=['game2', 'player'], priority=[20, 170], compileflags=cflags ) diff --git a/extern/bullet2/src/btBulletCollisionCommon.h b/extern/bullet2/src/btBulletCollisionCommon.h new file mode 100644 index 00000000000..8417ccc671f --- /dev/null +++ b/extern/bullet2/src/btBulletCollisionCommon.h @@ -0,0 +1,61 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BULLET_COLLISION_COMMON_H +#define BULLET_COLLISION_COMMON_H + +///Common headerfile includes for Bullet Collision Detection + +///Bullet's btCollisionWorld and btCollisionObject definitions +#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" + +///Collision Shapes +#include "BulletCollision/CollisionShapes/btBoxShape.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" +#include "BulletCollision/CollisionShapes/btCapsuleShape.h" +#include "BulletCollision/CollisionShapes/btCylinderShape.h" +#include "BulletCollision/CollisionShapes/btConeShape.h" +#include "BulletCollision/CollisionShapes/btStaticPlaneShape.h" +#include "BulletCollision/CollisionShapes/btConvexHullShape.h" +#include "BulletCollision/CollisionShapes/btTriangleMesh.h" +#include "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h" +#include "BulletCollision/CollisionShapes/btTriangleMeshShape.h" +#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h" +#include "BulletCollision/CollisionShapes/btCompoundShape.h" +#include "BulletCollision/CollisionShapes/btTetrahedronShape.h" +#include "BulletCollision/CollisionShapes/btEmptyShape.h" +#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" +#include "BulletCollision/CollisionShapes/btMultiSphereShape.h" + +///Narrowphase Collision Detector +#include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h" +#include "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h" + +///Dispatching and generation of collision pairs (broadphase) +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" +#include "BulletCollision/BroadphaseCollision/btAxisSweep3.h" + + +///Math library & Utils +#include "LinearMath/btQuaternion.h" +#include "LinearMath/btTransform.h" +#include "LinearMath/btDefaultMotionState.h" +#include "LinearMath/btQuickprof.h" +#include "LinearMath/btIDebugDraw.h" + +#endif //BULLET_COLLISION_COMMON_H + diff --git a/extern/bullet2/src/btBulletDynamicsCommon.h b/extern/bullet2/src/btBulletDynamicsCommon.h new file mode 100644 index 00000000000..25f016cba8a --- /dev/null +++ b/extern/bullet2/src/btBulletDynamicsCommon.h @@ -0,0 +1,42 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BULLET_DYNAMICS_COMMON_H +#define BULLET_DYNAMICS_COMMON_H + +///Common headerfile includes for Bullet Dynamics, including Collision Detection +#include "btBulletCollisionCommon.h" + +#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" +#include "BulletDynamics/Dynamics/btSimpleDynamicsWorld.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" + +#include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h" +#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h" +#include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h" + + +#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" +///Vehicle simulation, with wheel contact simulated by raycasts +#include "BulletDynamics/Vehicle/btRaycastVehicle.h" + + + + + + +#endif //BULLET_DYNAMICS_COMMON_H + diff --git a/extern/make/msvc_7_0/build_install_all.vcproj b/extern/make/msvc_7_0/build_install_all.vcproj new file mode 100644 index 00000000000..3396ecbb799 --- /dev/null +++ b/extern/make/msvc_7_0/build_install_all.vcproj @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/make/msvc_7_0/extern.sln b/extern/make/msvc_7_0/extern.sln new file mode 100644 index 00000000000..afc88ddda8e --- /dev/null +++ b/extern/make/msvc_7_0/extern.sln @@ -0,0 +1,180 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "build_install_all", "build_install_all.vcproj", "{9C71A793-C177-4CAB-8EC5-923D500B39F8}" + ProjectSection(ProjectDependencies) = postProject + {F9850C15-FF0A-429E-9D47-89FB433C9BD8} = {F9850C15-FF0A-429E-9D47-89FB433C9BD8} + {D696C86B-0B53-4471-A50D-5B983A6FA4AD} = {D696C86B-0B53-4471-A50D-5B983A6FA4AD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "solid", "..\..\solid\make\msvc_7_0\solid.vcproj", "{D696C86B-0B53-4471-A50D-5B983A6FA4AD}" + ProjectSection(ProjectDependencies) = postProject + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B} = {6461F05D-4698-47AB-A8E8-1CA2ACC9948B} + {0112CAD5-3584-412A-A2E5-1315A00437B4} = {0112CAD5-3584-412A-A2E5-1315A00437B4} + {B83C6BED-11EC-46C8-AFFA-121EEDE94373} = {B83C6BED-11EC-46C8-AFFA-121EEDE94373} + {524264F4-DF21-4B79-847F-E7CA643ECD0B} = {524264F4-DF21-4B79-847F-E7CA643ECD0B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qhull", "..\..\qhull\make\msvc_7_0\qhull.vcproj", "{6461F05D-4698-47AB-A8E8-1CA2ACC9948B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "convex", "..\..\solid\make\msvc_7_0\convex\convex.vcproj", "{524264F4-DF21-4B79-847F-E7CA643ECD0B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "complex", "..\..\solid\make\msvc_7_0\complex\complex.vcproj", "{B83C6BED-11EC-46C8-AFFA-121EEDE94373}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "broad", "..\..\solid\make\msvc_7_0\broad\broad.vcproj", "{0112CAD5-3584-412A-A2E5-1315A00437B4}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftgl_static_lib", "..\..\bFTGL\make\msvc_7_0\ftgl_static_lib.vcproj", "{F9850C15-FF0A-429E-9D47-89FB433C9BD8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "verse", "..\..\verse\make\msvc_7_0\libverse.vcproj", "{F9850C15-FF0A-429E-9D47-89FB433C9BD8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "verse_server", "..\..\verse\make\msvc_7_0\verse.vcproj", "{FC752464-F413-4D4F-842D-A5D3AA0E6A3D}" + ProjectSection(ProjectDependencies) = postProject + {F9850C15-FF0A-429E-9D47-89FB433C9BD8} = {F9850C15-FF0A-429E-9D47-89FB433C9BD8} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bullet2", "..\..\bullet2\make\msvc_7_0\Bullet_vc7.vcproj", "{FFD3C64A-30E2-4BC7-BC8F-51818C320400}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + 3D Plugin Debug = 3D Plugin Debug + 3D Plugin Release = 3D Plugin Release + Blender Debug = Blender Debug + Blender Release = Blender Release + BlenderPlayer Debug = BlenderPlayer Debug + BlenderPlayer Release = BlenderPlayer Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.Blender Debug.Build.0 = Blender Debug|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.Blender Release.ActiveCfg = Blender Release|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.Blender Release.Build.0 = Blender Release|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.BlenderPlayer Debug.ActiveCfg = Blender Release|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.BlenderPlayer Debug.Build.0 = Blender Release|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {9C71A793-C177-4CAB-8EC5-923D500B39F8}.BlenderPlayer Release.Build.0 = Blender Release|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.Blender Debug.Build.0 = Blender Debug|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.Blender Release.ActiveCfg = Blender Release|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.Blender Release.Build.0 = Blender Release|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.BlenderPlayer Debug.ActiveCfg = Blender Release|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.BlenderPlayer Debug.Build.0 = Blender Release|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {D696C86B-0B53-4471-A50D-5B983A6FA4AD}.BlenderPlayer Release.Build.0 = Blender Release|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.Blender Debug.Build.0 = Blender Debug|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.Blender Release.ActiveCfg = Blender Release|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.Blender Release.Build.0 = Blender Release|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.BlenderPlayer Debug.Build.0 = Blender Debug|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.BlenderPlayer Release.ActiveCfg = Blender Debug|Win32 + {6461F05D-4698-47AB-A8E8-1CA2ACC9948B}.BlenderPlayer Release.Build.0 = Blender Debug|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.Blender Debug.Build.0 = Blender Debug|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.Blender Release.ActiveCfg = Blender Release|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.Blender Release.Build.0 = Blender Release|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.BlenderPlayer Debug.ActiveCfg = Blender Release|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.BlenderPlayer Debug.Build.0 = Blender Release|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {524264F4-DF21-4B79-847F-E7CA643ECD0B}.BlenderPlayer Release.Build.0 = Blender Release|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.Blender Debug.Build.0 = Blender Debug|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.Blender Release.ActiveCfg = Blender Release|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.Blender Release.Build.0 = Blender Release|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.BlenderPlayer Debug.Build.0 = Blender Debug|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.BlenderPlayer Release.ActiveCfg = Blender Debug|Win32 + {B83C6BED-11EC-46C8-AFFA-121EEDE94373}.BlenderPlayer Release.Build.0 = Blender Debug|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.Blender Debug.Build.0 = Blender Debug|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.Blender Release.ActiveCfg = Blender Release|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.Blender Release.Build.0 = Blender Release|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.BlenderPlayer Debug.Build.0 = Blender Debug|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.BlenderPlayer Release.ActiveCfg = Blender Debug|Win32 + {0112CAD5-3584-412A-A2E5-1315A00437B4}.BlenderPlayer Release.Build.0 = Blender Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.Blender Debug.Build.0 = Blender Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.Blender Release.ActiveCfg = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.Blender Release.Build.0 = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.BlenderPlayer Debug.ActiveCfg = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.BlenderPlayer Debug.Build.0 = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.BlenderPlayer Release.Build.0 = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.Blender Debug.Build.0 = Blender Debug|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.Blender Release.ActiveCfg = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.Blender Release.Build.0 = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.BlenderPlayer Debug.ActiveCfg = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.BlenderPlayer Debug.Build.0 = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {F9850C15-FF0A-429E-9D47-89FB433C9BD8}.BlenderPlayer Release.Build.0 = Blender Release|Win32 + {FC752464-F413-4D4F-842D-A5D3AA0E6A3D}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {FC752464-F413-4D4F-842D-A5D3AA0E6A3D}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {FC752464-F413-4D4F-842D-A5D3AA0E6A3D}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {FC752464-F413-4D4F-842D-A5D3AA0E6A3D}.Blender Debug.Build.0 = Blender Debug|Win32 + {FC752464-F413-4D4F-842D-A5D3AA0E6A3D}.Blender Release.ActiveCfg = Blender Release|Win32 + {FC752464-F413-4D4F-842D-A5D3AA0E6A3D}.Blender Release.Build.0 = Blender Release|Win32 + {FC752464-F413-4D4F-842D-A5D3AA0E6A3D}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {FC752464-F413-4D4F-842D-A5D3AA0E6A3D}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.Blender Debug.Build.0 = Blender Debug|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.Blender Release.ActiveCfg = Blender Release|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.Blender Release.Build.0 = Blender Release|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.BlenderPlayer Debug.ActiveCfg = Blender Release|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.BlenderPlayer Debug.Build.0 = Blender Release|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {FFD3C64A-30E2-4BC7-BC8F-51818C320400}.BlenderPlayer Release.Build.0 = Blender Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/extern/ode/Makefile b/extern/ode/Makefile new file mode 100644 index 00000000000..f1d2c98fe23 --- /dev/null +++ b/extern/ode/Makefile @@ -0,0 +1,113 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2002 by Hans Lambermont +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +include nan_definitions.mk + +DISTDIR = dist +CP = ../../intern/tools/cpifdiff.sh +USERSETTINGS = ./dist/config/user-settings +TEMPSETTINGS = ./user-settings + +all: + [ -d $(DISTDIR)/lib ] || mkdir $(DISTDIR)/lib + # prepare settings for patching, clean in case of interruption + ifeq ($(OS),$(findstring $(OS), "darwin windows")) + [ ! -f $(TEMPSETTINGS) ] || mv $(TEMPSETTINGS) $(USERSETTINGS) + cp $(USERSETTINGS) $(TEMPSETTINGS) + endif + ifeq ($(OS),freebsd) + (grep FreeBSD $(DISTDIR)/Makefile >/dev/null ; \ + [ $$? -eq 0 ] || patch < patchfile.FreeBSD ) + endif + ifeq ($(OS),darwin) + cat $(TEMPSETTINGS) | sed s/unix-gcc/osx/ > $(USERSETTINGS) + endif + ifeq ($(OS),windows) + # compile with MSVC + cat $(TEMPSETTINGS) | sed s/unix-gcc/msvc/ > $(USERSETTINGS) + env PATH=".:$(PATH)" $(MAKE) -C $(DISTDIR) + endif + ifeq ($(OS),$(findstring $(OS), "freebsd linux darwin")) + $(MAKE) -C $(DISTDIR) + endif + # restore settings + ifeq ($(OS),$(findstring $(OS), "darwin windows")) + mv $(TEMPSETTINGS) $(USERSETTINGS) + endif + +# fake debug target +debug: + +install: all + ifeq ($(OS),$(findstring $(OS), "freebsd linux darwin")) + [ -d $(LCGDIR) ] || mkdir $(LCGDIR) + [ -d $(NAN_ODE) ] || mkdir $(NAN_ODE) + [ -d $(NAN_ODE)/include ] || mkdir $(NAN_ODE)/include + [ -d $(NAN_ODE)/include/ode ] || mkdir $(NAN_ODE)/include/ode + [ -d $(NAN_ODE)/lib ] || mkdir $(NAN_ODE)/lib + [ -d $(NAN_ODE)/ode ] || mkdir $(NAN_ODE)/ode + [ -d $(NAN_ODE)/ode/src ] || mkdir $(NAN_ODE)/ode/src + @$(CP) $(DISTDIR)/lib/libode.a $(NAN_ODE)/lib/ + @$(CP) $(DISTDIR)/include/ode/*.h $(NAN_ODE)/include/ode/ + @$(CP) $(DISTDIR)/ode/src/array.h $(NAN_ODE)/ode/src/ + @$(CP) $(DISTDIR)/ode/src/joint.h $(NAN_ODE)/ode/src/ + @$(CP) $(DISTDIR)/ode/src/objects.h $(NAN_ODE)/ode/src/ + @$(CP) $(DISTDIR)/ode/src/obstack.h $(NAN_ODE)/ode/src/ + ifeq ($(OS),darwin) + ranlib $(NAN_ODE)/lib/libode.a + endif + endif + ifeq ($(OS),windows) + @echo "====> $(MAKE) $@ in $(SOURCEDIR)" + [ -d $(LCGDIR) ] || mkdir $(LCGDIR) + [ -d $(NAN_ODE) ] || mkdir $(NAN_ODE) + [ -d $(NAN_ODE)/include ] || mkdir $(NAN_ODE)/include + [ -d $(NAN_ODE)/include/ode ] || mkdir $(NAN_ODE)/include/ode + [ -d $(NAN_ODE)/lib ] || mkdir $(NAN_ODE)/lib + [ -d $(NAN_ODE)/ode ] || mkdir $(NAN_ODE)/ode + [ -d $(NAN_ODE)/ode/src ] || mkdir $(NAN_ODE)/ode/src + cp $(DISTDIR)/lib/ode.lib $(NAN_ODE)/lib/libode.a + cp $(DISTDIR)/include/ode/*.h $(NAN_ODE)/include/ode/ + cp $(DISTDIR)/ode/src/array.h $(NAN_ODE)/ode/src/ + cp $(DISTDIR)/ode/src/joint.h $(NAN_ODE)/ode/src/ + cp $(DISTDIR)/ode/src/objects.h $(NAN_ODE)/ode/src/ + cp $(DISTDIR)/ode/src/obstack.h $(NAN_ODE)/ode/src/ + endif + +clean: + ifeq ($(OS),$(findstring $(OS), "freebsd linux darwin")) + [ ! -f dist/Makefile ] || $(MAKE) -C dist clean + endif + ifeq ($(OS),freebsd) + (grep FreeBSD $(DISTDIR)/Makefile >/dev/null ; \ + [ $$? -ne 0 ] || patch -R < patchfile.FreeBSD ) + endif + diff --git a/extern/ode/dist/INSTALL b/extern/ode/dist/INSTALL new file mode 100644 index 00000000000..f82285db1b2 --- /dev/null +++ b/extern/ode/dist/INSTALL @@ -0,0 +1,44 @@ + +here are the steps to buid ODE: + +(1) get the GNU 'make' tool. many unix platforms come with this, although + sometimes it is called 'gmake'. i have provided a version of GNU make + for windows at: http://q12.org/ode/bin/make.exe + +(2) edit the settings in the file config/user-settings. the list of supported + platforms is given in that file. + +(3) run 'make' to configure and build ODE and the graphical test programs. + to build parts of ODE the make targets are: + + make configure create configuration file include/ode/config.h + make ode-lib build the core ODE library + make drawstuff-lib build the OpenGL-based graphics library + make ode-test build some ODE tests (they need drawstuff) + make drawstuff-test build a test app for the drawstuff library + + all of these targets will do an implicit 'make configure'. if the + configurator screws up then you can edit the settings directly in + include/ode/config.h. + +(4) to install the ODE library onto your system you should copy the 'lib' and + 'include' directories to a suitable place, e.g. on unix: + + include/ode --> /usr/local/include/ode + lib/libode.a --> /usr/local/lib/libode.a + +ODE has been verified to build on the following platforms: + + config ode-lib ode-test + ------ ------- -------- + windows + MSVC msvc * * + MinGW mingw * * + CygWin cygwin * * + linux (x86, mandrake 8.1) unix-gcc * * + linux (alpha, debian 2.2) unix-gcc * ? + linux (RS/6000, debian 2.2) unix-gcc * ? + linux (Sparc U60, debian 2.2) unix-gcc * ? + freebsd 4.3 unix-gcc * ? + Mac OS-X osx * ? + Solaris 8 (Sparc R220) unix-gcc * ? diff --git a/extern/ode/dist/LICENSE-BSD.TXT b/extern/ode/dist/LICENSE-BSD.TXT new file mode 100644 index 00000000000..05929239487 --- /dev/null +++ b/extern/ode/dist/LICENSE-BSD.TXT @@ -0,0 +1,34 @@ + +This is the BSD-style license for the Open Dynamics Engine +---------------------------------------------------------- + +Open Dynamics Engine +Copyright (c) 2001,2002, Russell L. Smith. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the names of ODE's copyright owner nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/extern/ode/dist/LICENSE.TXT b/extern/ode/dist/LICENSE.TXT new file mode 100644 index 00000000000..cfe59bcadb8 --- /dev/null +++ b/extern/ode/dist/LICENSE.TXT @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/extern/ode/dist/Makefile b/extern/ode/dist/Makefile new file mode 100644 index 00000000000..34fbd53f792 --- /dev/null +++ b/extern/ode/dist/Makefile @@ -0,0 +1,280 @@ +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +USER_SETTINGS=config/user-settings +include $(USER_SETTINGS) +PLATFORM_MAKEFILE=config/makefile.$(PLATFORM) +include $(PLATFORM_MAKEFILE) + +############################################################################## +# check some variables that were supposed to be defined + +ifneq ($(BUILD),debug) +ifneq ($(BUILD),release) +$(error the BUILD variable is not set properly) +endif +endif + +ifneq ($(PRECISION),SINGLE) +ifneq ($(PRECISION),DOUBLE) +$(error the PRECISION variable is not set properly) +endif +endif + +############################################################################## +# package settings + +ODE_SRC = \ + ode/src/array.cpp \ + ode/src/error.cpp \ + ode/src/memory.cpp \ + ode/src/obstack.cpp \ + ode/src/odemath.cpp \ + ode/src/matrix.cpp \ + ode/src/misc.cpp \ + ode/src/rotation.cpp \ + ode/src/mass.cpp \ + ode/src/ode.cpp \ + ode/src/step.cpp \ + ode/src/lcp.cpp \ + ode/src/joint.cpp \ + ode/src/space.cpp \ + ode/src/geom.cpp \ + ode/src/timer.cpp \ + ode/src/mat.cpp \ + ode/src/testing.cpp +ODE_PREGEN_SRC = \ + ode/src/fastldlt.c \ + ode/src/fastlsolve.c \ + ode/src/fastltsolve.c \ + ode/src/fastdot.c + +ifeq ($(WINDOWS),1) +DRAWSTUFF_SRC = drawstuff/src/drawstuff.cpp drawstuff/src/windows.cpp +RESOURCE_FILE=lib/resources.RES +else +DRAWSTUFF_SRC = drawstuff/src/drawstuff.cpp drawstuff/src/x11.cpp +endif + +ODE_LIB_NAME=ode +DRAWSTUFF_LIB_NAME=drawstuff + +INCPATH=include +LIBPATH=lib + +ODE_TEST_SRC_CPP = \ + ode/test/test_ode.cpp \ + ode/test/test_chain2.cpp \ + ode/test/test_hinge.cpp \ + ode/test/test_slider.cpp \ + ode/test/test_collision.cpp \ + ode/test/test_boxstack.cpp \ + ode/test/test_buggy.cpp \ + ode/test/test_joints.cpp \ + ode/test/test_space.cpp \ + ode/test/test_I.cpp \ + ode/test/test_step.cpp \ + ode/test/test_friction.cpp +ODE_TEST_SRC_C = \ + ode/test/test_chain1.c +DRAWSTUFF_TEST_SRC_CPP = \ + drawstuff/dstest/dstest.cpp + +CONFIGURATOR_SRC=configurator.c +CONFIG_H=include/ode/config.h + +############################################################################## +# derived things + +DEFINES= + +# add some defines depending on the build mode +ifeq ($(BUILD),release) +DEFINES+=$(C_DEF)dNODEBUG +endif +ifeq ($(BUILD),debug) +DEFINES+=$(C_DEF)dDEBUG_ALLOC +endif + +# object file names +ODE_PREGEN_OBJECTS=$(ODE_PREGEN_SRC:%.c=%$(OBJ)) +ODE_OBJECTS=$(ODE_SRC:%.cpp=%$(OBJ)) $(ODE_PREGEN_OBJECTS) +DRAWSTUFF_OBJECTS=$(DRAWSTUFF_SRC:%.cpp=%$(OBJ)) $(RESOURCE_FILE) + +# side-effect variables causing creation of files containing lists of +# filenames to be linked, to work around command-line-length limitations +# on outdated 16-bit operating systems. because of command-line length +# limitations we cannot issue a link command with all object filenames +# specified (because this command is too long and overflows the command +# buffer), but instead must create a file containing all object filenames +# to be linked, and specify this list-file with @listfile on the command-line. +# +# the difficult part is doing this in a flexible way; we don't want to +# hard-code the to-be-linked object filenames in a file, but instead +# want to dynamically create a file containing a list of all object filenames +# within the $XXX_OBJECTS makefile variables. to do this, we use side-effect +# variables. +# +# idea: when these variables are EVALUATED (i.e. later during rule execution, +# not now during variable definition), they cause a SIDE EFFECT which creates +# a file with the list of all ODE object files. why the chicanery??? because +# if we have a command-line length limitation, no SINGLE command we issue will +# be able to create a file containing all object files to be linked +# (because that command itself would need to include all filenames, making +# it too long to be executed). instead, we must use the gnu-make "foreach" +# function, combined - probably in an unintended way - with the "shell" +# function. this is probably unintended because we are not using the "shell" +# function to return a string value for variable evaluation, but are instead +# using the "shell" function to cause a side effect (appending of each filename +# to the filename-list-file). +# +# one possible snag is that, forbidding use of any external EXE utilities and +# relying only on the facilities provided by the outdated 16-bit operating +# system, there is no way to issue a SERIES of commands which append text to +# the end of a file WITHOUT adding newlines. therefore, the list of to-be- +# linked object files is separated by newlines in the list file. fortunately, +# the linker utility for this outdated 16-bit operating system accepts +# filenames on separate lines in the list file. + +# remember: when we evaluate these variables later, this causes the creation +# of the appropriate list file. +ifeq ($(WINDOWS16),1) +SIDE_EFFECT_ODE_OBJLIST = $(foreach o,$(ODE_OBJECTS),$(shell echo $(o) >> odeobj.txt )) +SIDE_EFFECT_DRAWSTUFF_OBJLIST = $(foreach o,$(DRAWSTUFF_OBJECTS),$(shell echo $(o) >> dsobj.txt )) +endif + +# library file names +ODE_LIB=$(LIBPATH)/$(LIB_PREFIX)$(ODE_LIB_NAME)$(LIB_SUFFIX) +DRAWSTUFF_LIB=$(LIBPATH)/$(LIB_PREFIX)$(DRAWSTUFF_LIB_NAME)$(LIB_SUFFIX) + +# executable file names +ODE_TEST_EXE=$(ODE_TEST_SRC_CPP:%.cpp=%.exe) $(ODE_TEST_SRC_C:%.c=%.exe) +DRAWSTUFF_TEST_EXE=$(DRAWSTUFF_TEST_SRC_CPP:%.cpp=%.exe) +CONFIGURATOR_EXE=$(CONFIGURATOR_SRC:%.c=%.exe) + +############################################################################## +# rules +# +# NOTE: the '.c' files are pregenerated sources, and must be compiled with +# -O1 optimization. that is why the rule for .c files is a bit different. +# why should it be compiled with O1? it is numerical code that is generated +# by fbuild. O1 optimization is used to preserve the operation orders that +# were discovered by fbuild to be the fastest on that platform. believe it or +# not, O2 makes this code run much slower for most compilers. + +debug: all +all: ode-lib drawstuff-lib ode-test drawstuff-test + @echo SUCCESS + +ode-lib: configure $(ODE_LIB) +drawstuff-lib: configure $(DRAWSTUFF_LIB) +ode-test: ode-lib drawstuff-lib $(ODE_TEST_EXE) +drawstuff-test: drawstuff-lib $(DRAWSTUFF_TEST_EXE) + +ifndef ODE_LIB_AR_RULE +ODE_LIB_AR_RULE=$(AR)$@ +endif + +$(ODE_LIB): pre_ode_lib $(ODE_OBJECTS) +ifeq ($(WINDOWS16),1) +# if we have a command-line-length limitation, then dynamically create +# a file containing all object filenames, and pass this file to the linker +# instead of directly specifying the object filenames on the command line. +# the very evaluation of the following variable causes creation of file +# odeobj.txt + $(SIDE_EFFECT_ODE_OBJLIST) + $(ODE_LIB_AR_RULE) @odeobj.txt +else +# if we have no command-line-length limitation, directly specify all +# object files to be linked. + $(ODE_LIB_AR_RULE) $(ODE_OBJECTS) +endif + +ifdef RANLIB + $(RANLIB) $@ +endif + +$(DRAWSTUFF_LIB): pre_drawstuff_lib $(DRAWSTUFF_OBJECTS) +ifeq ($WINDOWS16),1) +# if we have a command-line-length limitation, then do the same as above. + $(SIDE_EFFECT_DRAWSTUFF_OBJLIST) + $(AR)$@ @dsobj.txt +else +# if we have no command-line-length limitation, directly specify all object +# files to be linked. + $(AR)$@ $(DRAWSTUFF_OBJECTS) +endif +ifdef RANLIB + $(RANLIB) $@ +endif + +# rules to be executed before library linking starts: delete list file (if one is used) + +pre_ode_lib: +ifeq ($WINDOWS16),1) + $(DEL_CMD) odeobj.txt +endif + +pre_drawstuff_lib: +ifeq ($WINDOWS16),1) + $(DEL_CMD) dsobj.txt +endif + +clean: + -$(DEL_CMD) $(ODE_OBJECTS) $(ODE_TEST_EXE) $(ODE_LIB) $(DRAWSTUFF_OBJECTS) $(DRAWSTUFF_TEST_EXE) $(DRAWSTUFF_LIB) ode/test/*$(OBJ) drawstuff/dstest/*$(OBJ) $(CONFIGURATOR_EXE) $(CONFIG_H) + +%$(OBJ): %.c + $(CC) $(C_FLAGS) $(C_INC)$(INCPATH) $(DEFINES) $(C_OPT)1 $(C_OUT)$@ $< + +%$(OBJ): %.cpp + $(CC) $(C_FLAGS) $(C_INC)$(INCPATH) $(DEFINES) $(C_OPT)$(OPT) $(C_OUT)$@ $< + +%.exe: %$(OBJ) + $(CC) $(C_EXEOUT)$@ $< $(ODE_LIB) $(DRAWSTUFF_LIB) $(RESOURCE_FILE) $(LINK_OPENGL) $(LINK_MATH) + +# windows specific rules + +lib/resources.RES: drawstuff/src/resources.rc + $(RC_RULE) + + +# configurator rules + +configure: $(CONFIG_H) + +$(CONFIG_H): $(CONFIGURATOR_EXE) $(USER_SETTINGS) $(PLATFORM_MAKEFILE) + $(THIS_DIR)$(CONFIGURATOR_EXE) $(CONFIG_H) "$(CC) $(DEFINES) $(C_EXEOUT)" "$(DEL_CMD)" $(THIS_DIR) + +$(CONFIGURATOR_EXE): $(CONFIGURATOR_SRC) $(USER_SETTINGS) $(PLATFORM_MAKEFILE) + $(CC) $(C_DEF)d$(PRECISION) $(DEFINES) $(C_EXEOUT)$@ $< + + +# unix-gcc specific dependency making + +DEP_RULE=gcc -M $(C_INC)$(INCPATH) $(DEFINES) +depend: $(ODE_SRC) $(ODE_PREGEN_SRC) $(DRAWSTUFF_SRC) $(ODE_TEST_SRC_CPP) $(ODE_TEST_SRC_C) $(DRAWSTUFF_TEST_SRC_CPP) + $(DEP_RULE) $(ODE_SRC) $(ODE_PREGEN_SRC) | tools/process_deps ode/src/ > Makefile.deps + $(DEP_RULE) $(DRAWSTUFF_SRC) | tools/process_deps drawstuff/src/ >> Makefile.deps + $(DEP_RULE) $(ODE_TEST_SRC_CPP) | tools/process_deps ode/test/ >> Makefile.deps + $(DEP_RULE) $(DRAWSTUFF_TEST_SRC_CPP) | tools/process_deps drawstuff/dstest/ >> Makefile.deps + +include Makefile.deps diff --git a/extern/ode/dist/Makefile.deps b/extern/ode/dist/Makefile.deps new file mode 100644 index 00000000000..ad11f01353f --- /dev/null +++ b/extern/ode/dist/Makefile.deps @@ -0,0 +1,456 @@ +ode/src/array.o: \ + ode/src/array.cpp \ + include/ode/config.h \ + include/ode/memory.h \ + include/ode/error.h \ + ode/src/array.h +ode/src/error.o: \ + ode/src/error.cpp \ + include/ode/config.h \ + include/ode/error.h +ode/src/memory.o: \ + ode/src/memory.cpp \ + include/ode/config.h \ + include/ode/memory.h \ + include/ode/error.h +ode/src/obstack.o: \ + ode/src/obstack.cpp \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/memory.h \ + ode/src/obstack.h \ + ode/src/objects.h \ + include/ode/mass.h \ + ode/src/array.h +ode/src/odemath.o: \ + ode/src/odemath.cpp \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/odemath.h +ode/src/matrix.o: \ + ode/src/matrix.cpp \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/matrix.h +ode/src/misc.o: \ + ode/src/misc.cpp \ + include/ode/config.h \ + include/ode/misc.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/matrix.h +ode/src/rotation.o: \ + ode/src/rotation.cpp \ + include/ode/rotation.h \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h +ode/src/mass.o: \ + ode/src/mass.cpp \ + include/ode/config.h \ + include/ode/mass.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/odemath.h \ + include/ode/matrix.h +ode/src/ode.o: \ + ode/src/ode.cpp \ + ode/src/objects.h \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/mass.h \ + ode/src/array.h \ + include/ode/ode.h \ + include/ode/contact.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + ode/src/joint.h \ + ode/src/obstack.h \ + ode/src/step.h +ode/src/step.o: \ + ode/src/step.cpp \ + ode/src/objects.h \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/mass.h \ + ode/src/array.h \ + ode/src/joint.h \ + include/ode/contact.h \ + ode/src/obstack.h \ + include/ode/odemath.h \ + include/ode/rotation.h \ + include/ode/timer.h \ + include/ode/matrix.h \ + ode/src/lcp.h +ode/src/lcp.o: \ + ode/src/lcp.cpp \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + ode/src/lcp.h \ + include/ode/matrix.h \ + include/ode/misc.h \ + ode/src/mat.h \ + include/ode/timer.h +ode/src/joint.o: \ + ode/src/joint.cpp \ + include/ode/odemath.h \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/rotation.h \ + include/ode/matrix.h \ + ode/src/joint.h \ + ode/src/objects.h \ + include/ode/memory.h \ + include/ode/mass.h \ + ode/src/array.h \ + include/ode/contact.h \ + ode/src/obstack.h +ode/src/space.o: \ + ode/src/space.cpp \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/contact.h \ + include/ode/memory.h \ + ode/src/objects.h \ + include/ode/mass.h \ + ode/src/array.h \ + ode/src/geom_internal.h +ode/src/geom.o: \ + ode/src/geom.cpp \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/geom.h \ + include/ode/space.h \ + include/ode/contact.h \ + include/ode/rotation.h \ + include/ode/odemath.h \ + include/ode/memory.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/mass.h \ + include/ode/matrix.h \ + ode/src/objects.h \ + ode/src/array.h \ + ode/src/geom_internal.h +ode/src/timer.o: \ + ode/src/timer.cpp \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h \ + include/ode/timer.h +ode/src/mat.o: \ + ode/src/mat.cpp \ + include/ode/config.h \ + include/ode/misc.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/matrix.h \ + include/ode/memory.h \ + ode/src/mat.h +ode/src/testing.o: \ + ode/src/testing.cpp \ + include/ode/config.h \ + include/ode/misc.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + ode/src/testing.h \ + ode/src/array.h +ode/src/fastldlt.o: \ + ode/src/fastldlt.c \ + include/ode/matrix.h \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h +ode/src/fastlsolve.o: \ + ode/src/fastlsolve.c \ + include/ode/matrix.h \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h +ode/src/fastltsolve.o: \ + ode/src/fastltsolve.c \ + include/ode/matrix.h \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h +ode/src/fastdot.o: \ + ode/src/fastdot.c \ + include/ode/matrix.h \ + include/ode/common.h \ + include/ode/config.h \ + include/ode/error.h +drawstuff/src/drawstuff.o: \ + drawstuff/src/drawstuff.cpp \ + include/ode/config.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h \ + drawstuff/src/internal.h +drawstuff/src/x11.o: \ + drawstuff/src/x11.cpp \ + include/ode/config.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h \ + drawstuff/src/internal.h +ode/test/test_ode.o: \ + ode/test/test_ode.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h +ode/test/test_chain2.o: \ + ode/test/test_chain2.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_hinge.o: \ + ode/test/test_hinge.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_slider.o: \ + ode/test/test_slider.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_collision.o: \ + ode/test/test_collision.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_boxstack.o: \ + ode/test/test_boxstack.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_buggy.o: \ + ode/test/test_buggy.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_joints.o: \ + ode/test/test_joints.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_space.o: \ + ode/test/test_space.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_I.o: \ + ode/test/test_I.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_step.o: \ + ode/test/test_step.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +ode/test/test_friction.o: \ + ode/test/test_friction.cpp \ + include/ode/ode.h \ + include/ode/config.h \ + include/ode/contact.h \ + include/ode/common.h \ + include/ode/error.h \ + include/ode/memory.h \ + include/ode/odemath.h \ + include/ode/matrix.h \ + include/ode/timer.h \ + include/ode/rotation.h \ + include/ode/mass.h \ + include/ode/space.h \ + include/ode/geom.h \ + include/ode/misc.h \ + include/ode/objects.h \ + include/ode/odecpp.h \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h +drawstuff/dstest/dstest.o: \ + drawstuff/dstest/dstest.cpp \ + include/drawstuff/drawstuff.h \ + include/drawstuff/version.h diff --git a/extern/ode/dist/README b/extern/ode/dist/README new file mode 100644 index 00000000000..6b151d1a27b --- /dev/null +++ b/extern/ode/dist/README @@ -0,0 +1,30 @@ +The Open Dynamics Engine (ODE), Copyright (C) 2001,2002 Russell L. Smith. +------------------------------------------------------------------------- + +ODE is a free, industrial quality library for simulating articulated +rigid body dynamics - for example ground vehicles, legged creatures, +and moving objects in VR environments. It is fast, flexible, robust +and platform independent, with advanced joints, contact with friction, +and built-in collision detection. + +This library is free software; you can redistribute it and/or +modify it under the terms of EITHER: + (1) The GNU Lesser General Public License as published by the Free + Software Foundation; either version 2.1 of the License, or (at + your option) any later version. The text of the GNU Lesser + General Public License is included with this library in the + file LICENSE.TXT. + (2) The BSD-style license that is included with this library in + the file LICENSE-BSD.TXT. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files +LICENSE.TXT and LICENSE-BSD.TXT for more details. + + * Installation instructions are in the INSTALL file + + * The ODE web pages are at http://q12.org/ode/ + + * The ODE documentation is in the file ode/doc/ode.html, or you + can view it on the web at http://q12.org/ode/ode-docs.html diff --git a/extern/ode/dist/README_BLENDER b/extern/ode/dist/README_BLENDER new file mode 100644 index 00000000000..64d97624a55 --- /dev/null +++ b/extern/ode/dist/README_BLENDER @@ -0,0 +1,18 @@ +Checked out from ODE cvs (http://q12.org) on or around +Fri Oct 18 14:24:11 GMT 2002 + +Note that ODE has its own build system. The source/ode/ +directory is traversed by Blender's source/Makefile. However +source/ode/config/user-settings has to be set correctly +depending on the target platform. This needs to be done in the +source/Makefile which determines the proper platform, then copies +the appropriate platform-specific user-settings.platform file to +source/ode/config/user-settings. Currently source/ode/user-settings is +for Linux. + +Don't change the source in this directory. This source code is +maintained on the CVS server at http://q12.org and is provided here +so that Blender developers can compile ODE without having to separately +download and install it. This source code can and should periodically +be synchronized (manually) with the source code at http://q12.org. + diff --git a/extern/ode/dist/config/README b/extern/ode/dist/config/README new file mode 100644 index 00000000000..0fa18062a4e --- /dev/null +++ b/extern/ode/dist/config/README @@ -0,0 +1,41 @@ + +variable names used in the per-platform makefile configuration files: + +platform stuff +-------------- + +WINDOWS set to 1 if this is a microsoft windows based platform + +filesystem stuff and commands +----------------------------- + +THIS_DIR prefix to run a command from the current directory +DEL_CMD the name of the delete command + +compiler stuff +-------------- + +CC the C/C++ compiler to use +OBJ the object file extension +C_FLAGS the standard set of compiler flags +C_INC flag to add an include path +C_OUT flag to specify the object file output +C_EXEOUT flag to specify the executable file output +C_DEF flag to add a define +C_OPT flag to set the optimization level +OPT the optimization level to use + +library archiver +---------------- + +AR library archiver command +RANLIB ranlib command, if necessary +LIB_PREFIX library file prefix +LIB_SUFFIX library file suffix +LINK_OPENGL link flags to link in windowing stuff and opengl +LINK_MATH link flags to link in the system math library + +windows specific stuff +---------------------- + +RC_RULE makefile rule to use for the resource compiler diff --git a/extern/ode/dist/config/makefile.cygwin b/extern/ode/dist/config/makefile.cygwin new file mode 100644 index 00000000000..de23b71a29f --- /dev/null +++ b/extern/ode/dist/config/makefile.cygwin @@ -0,0 +1,28 @@ +WINDOWS=1 +THIS_DIR=./ +DEL_CMD=rm -f +CC=gcc +OBJ=.o +C_FLAGS=-c -Wall -fno-exceptions -fno-rtti -DWIN32 -DCYGWIN +C_INC=-I +C_OUT=-o +C_EXEOUT=-o +C_DEF=-D +C_OPT=-O +AR=ar rc +RANLIB= +LIB_PREFIX=lib +LIB_SUFFIX=.a +LINK_OPENGL=-lComctl32 -lkernel32 -luser32 -lgdi32 -lOpenGL32 -lGlu32 +LINK_MATH=-lm +RC_RULE=windres -I rc -O coff $< $@ + +ifeq ($(BUILD),release) +OPT=2 +C_FLAGS+=-fomit-frame-pointer -ffast-math +endif + +ifeq ($(BUILD),debug) +OPT=0 +C_FLAGS+=-g +endif diff --git a/extern/ode/dist/config/makefile.mingw b/extern/ode/dist/config/makefile.mingw new file mode 100644 index 00000000000..4b18fb6bcdc --- /dev/null +++ b/extern/ode/dist/config/makefile.mingw @@ -0,0 +1,28 @@ +WINDOWS=1 +THIS_DIR= +DEL_CMD=tools\rm +CC=gcc +OBJ=.o +C_FLAGS=-c -Wall -fno-exceptions -fno-rtti -DWIN32 +C_INC=-I +C_OUT=-o +C_EXEOUT=-o +C_DEF=-D +C_OPT=-O +AR=ar rc +RANLIB= +LIB_PREFIX=lib +LIB_SUFFIX=.a +LINK_OPENGL=-lComctl32 -lkernel32 -luser32 -lgdi32 -lOpenGL32 -lGlu32 +LINK_MATH=-lm +RC_RULE=windres -I rc -O coff $< $@ + +ifeq ($(BUILD),release) +OPT=2 +C_FLAGS+=-fomit-frame-pointer -ffast-math +endif + +ifeq ($(BUILD),debug) +OPT=0 +C_FLAGS+=-g +endif diff --git a/extern/ode/dist/config/makefile.msvc b/extern/ode/dist/config/makefile.msvc new file mode 100644 index 00000000000..9d4da0bf912 --- /dev/null +++ b/extern/ode/dist/config/makefile.msvc @@ -0,0 +1,27 @@ +WINDOWS=1 +THIS_DIR= +DEL_CMD=tools\rm +CC=cl /nologo /DWIN32 /DMSVC /DSHAREDLIBEXPORT= /DSHAREDLIBIMPORT= +OBJ=.obj +C_FLAGS=/c /GR- /GX- /W3 /GF +C_INC=/I +C_OUT=/Fo +C_EXEOUT=/Fe +C_DEF=/D +C_OPT=/O +AR=lib /nologo /OUT: +RANLIB= +LIB_PREFIX= +LIB_SUFFIX=.lib +LINK_OPENGL=Comctl32.lib kernel32.lib user32.lib gdi32.lib OpenGL32.lib Glu32.lib +LINK_MATH= +RC_RULE=rc /r /fo$@ $< + +ifeq ($(BUILD),release) +OPT=2 +C_FLAGS+=/Oy +endif + +ifeq ($(BUILD),debug) +OPT=d +endif diff --git a/extern/ode/dist/config/makefile.msvc-dll b/extern/ode/dist/config/makefile.msvc-dll new file mode 100644 index 00000000000..fe495893616 --- /dev/null +++ b/extern/ode/dist/config/makefile.msvc-dll @@ -0,0 +1,29 @@ +WINDOWS=1 +THIS_DIR= +DEL_CMD=tools\rm +CC=cl /nologo /DWIN32 /DMSVC /DSHAREDLIBIMPORT=__declspec(dllimport) /DSHAREDLIBEXPORT=__declspec(dllexport) +OBJ=.obj +C_FLAGS=/c /GR- /GX- /W3 /GF +C_INC=/I +C_OUT=/Fo +C_EXEOUT=/Fe +C_DEF=/D +C_OPT=/O +AR=lib /nologo /OUT: +RANLIB= +LIB_PREFIX= +LIB_SUFFIX=.lib +LINK_OPENGL=Comctl32.lib kernel32.lib user32.lib gdi32.lib OpenGL32.lib Glu32.lib +LINK_MATH= +RC_RULE=rc /r /fo$@ $< + +ifeq ($(BUILD),release) +OPT=2 +C_FLAGS+=/Oy +endif + +ifeq ($(BUILD),debug) +OPT=d +endif + +ODE_LIB_AR_RULE=link /dll /nologo /SUBSYSTEM:WINDOWS /LIBPATH:"C:\Programme\Micros~2\VC98\Lib" /def:config/msvcdefs.def $(LINK_OPENGL) /OUT:$(patsubst %.lib,%.dll,$@) diff --git a/extern/ode/dist/config/makefile.osx b/extern/ode/dist/config/makefile.osx new file mode 100644 index 00000000000..1d5e0f42252 --- /dev/null +++ b/extern/ode/dist/config/makefile.osx @@ -0,0 +1,26 @@ +THIS_DIR=./ +DEL_CMD=rm -f +CC=cc +OBJ=.o +C_FLAGS=-c -Wall -fno-rtti -fno-exceptions -Wall -I/usr/X11R6/include +C_INC=-I +C_OUT=-o +C_EXEOUT=-o +C_DEF=-D +C_OPT=-O +AR=ar rc +RANLIB=ranlib +LIB_PREFIX=lib +LIB_SUFFIX=.a +LINK_OPENGL=-L/usr/X11R6/lib -L/usr/X11/lib -L/usr/lib/X11R6 -L/usr/lib/X11 -lX11 -lGL -lGLU -lstdc++ +LINK_MATH=-lm + +ifeq ($(BUILD),release) +OPT=2 +C_FLAGS+=-fomit-frame-pointer -ffast-math +endif + +ifeq ($(BUILD),debug) +OPT=0 +C_FLAGS+=-g +endif diff --git a/extern/ode/dist/config/makefile.unix-gcc b/extern/ode/dist/config/makefile.unix-gcc new file mode 100644 index 00000000000..b9d07632353 --- /dev/null +++ b/extern/ode/dist/config/makefile.unix-gcc @@ -0,0 +1,29 @@ +THIS_DIR=./ +DEL_CMD=rm -f +CC=gcc +OBJ=.o +C_FLAGS=-c -Wall -fno-rtti -fno-exceptions -Wall +C_INC=-I +C_OUT=-o +C_EXEOUT=-o +C_DEF=-D +C_OPT=-O +AR=ar rc +RANLIB= +LIB_PREFIX=lib +LIB_SUFFIX=.a +LINK_OPENGL=-L/usr/X11R6/lib -L/usr/X11/lib -L/usr/lib/X11R6 -L/usr/lib/X11 -lX11 -lGL -lGLU +LINK_MATH=-lm + +ifeq ($(BUILD),release) +OPT=2 +C_FLAGS+=-fomit-frame-pointer -ffast-math +endif + +ifeq ($(BUILD),debug) +OPT=0 +C_FLAGS+=-g +endif + +# some other possible flags: +# -malign-double -mpentiumpro -march=pentiumpro diff --git a/extern/ode/dist/config/makefile.unix-generic b/extern/ode/dist/config/makefile.unix-generic new file mode 100644 index 00000000000..f435e1a0db8 --- /dev/null +++ b/extern/ode/dist/config/makefile.unix-generic @@ -0,0 +1,24 @@ +THIS_DIR=./ +DEL_CMD=rm -f +CC=CC +OBJ=.o +C_FLAGS=-c +C_INC=-I +C_OUT=-o +C_EXEOUT=-o +C_DEF=-D +C_OPT=-O +AR=ar rc +RANLIB= +LIB_PREFIX=lib +LIB_SUFFIX=.a +LINK_OPENGL=-L/usr/X11R6/lib -L/usr/X11/lib -L/usr/lib/X11R6 -L/usr/lib/X11 -lX11 -lGL -lGLU +LINK_MATH=-lm + +ifeq ($(BUILD),release) +OPT=2 +endif + +ifeq ($(BUILD),debug) +OPT=0 +endif diff --git a/extern/ode/dist/config/msvcdefs.def b/extern/ode/dist/config/msvcdefs.def new file mode 100644 index 00000000000..11258ab9aa8 --- /dev/null +++ b/extern/ode/dist/config/msvcdefs.def @@ -0,0 +1,228 @@ +LIBRARY ODE +EXPORTS +dAreConnected +dBodyAddForce +dBodyAddForceAtPos +dBodyAddForceAtRelPos +dBodyAddRelForce +dBodyAddRelForceAtPos +dBodyAddRelForceAtRelPos +dBodyAddRelTorque +dBodyAddTorque +dBodyCreate +dBodyDestroy +dBodyDisable +dBodyEnable +dBodyGetAngularVel +dBodyGetData +dBodyGetFiniteRotationAxis +dBodyGetFiniteRotationMode +dBodyGetForce +dBodyGetGravityMode +dBodyGetJoint +dBodyGetLinearVel +dBodyGetMass +dBodyGetNumJoints +dBodyGetPointVel +dBodyGetPosRelPoint +dBodyGetPosition +dBodyGetQuaternion +dBodyGetRelPointPos +dBodyGetRelPointVel +dBodyGetRotation +dBodyGetTorque +dBodyIsEnabled +dBodySetAngularVel +dBodySetData +dBodySetFiniteRotationAxis +dBodySetFiniteRotationMode +dBodySetForce +dBodySetGravityMode +dBodySetLinearVel +dBodySetMass +dBodySetPosition +dBodySetQuaternion +dBodySetRotation +dBodySetTorque +dBodyVectorFromWorld +dBodyVectorToWorld +dBoxBox +dBoxClass +dBoxTouchesBox +dCCylinderClass +dClearUpperTriangle +dCloseODE +dClosestLineSegmentPoints +dCollide +dCreateBox +dCreateCCylinder +dCreateGeom +dCreateGeomClass +dCreateGeomGroup +dCreateGeomTransform +dCreatePlane +dCreateSphere +dError +dFactorCholesky +dFactorLDLT +dGeomBoxGetLengths +dGeomBoxSetLengths +dGeomCCylinderGetParams +dGeomCCylinderSetParams +dGeomDestroy +dGeomGetAABB +dGeomGetBody +dGeomGetClass +dGeomGetClassData +dGeomGetData +dGeomGetPosition +dGeomGetRotation +dGeomGetSpaceAABB +dGeomGroupAdd +dGeomGroupGetGeom +dGeomGroupGetNumGeoms +dGeomGroupRemove +dGeomPlaneGetParams +dGeomPlaneSetParams +dGeomSetBody +dGeomSetData +dGeomSetPosition +dGeomSetRotation +dGeomSphereGetRadius +dGeomSphereSetRadius +dGeomTransformClass +dGeomTransformGetCleanup +dGeomTransformGetGeom +dGeomTransformSetCleanup +dGeomTransformSetGeom +dHashSpaceCreate +dHashSpaceSetLevels +dInfiniteAABB +dInfinityValue +dInvertPDMatrix +dIsPositiveDefinite +dJointAttach +dJointCreateAMotor +dJointCreateBall +dJointCreateContact +dJointCreateFixed +dJointCreateHinge +dJointCreateHinge2 +dJointCreateSlider +dJointCreateUniversal +dJointDestroy +dJointGetAMotorAngle +dJointGetAMotorAngleRate +dJointGetAMotorAxis +dJointGetAMotorAxisRel +dJointGetAMotorMode +dJointGetAMotorNumAxes +dJointGetAMotorParam +dJointGetBallAnchor +dJointGetBody +dJointGetData +dJointGetHinge2Anchor +dJointGetHinge2Angle1 +dJointGetHinge2Angle1Rate +dJointGetHinge2Angle2Rate +dJointGetHinge2Axis1 +dJointGetHinge2Axis2 +dJointGetHinge2Param +dJointGetHingeAnchor +dJointGetHingeAngle +dJointGetHingeAngleRate +dJointGetHingeAxis +dJointGetHingeParam +dJointGetSliderAxis +dJointGetSliderParam +dJointGetSliderPosition +dJointGetSliderPositionRate +dJointGetType +dJointGetUniversalAnchor +dJointGetUniversalAxis1 +dJointGetUniversalAxis2 +dJointGroupCreate +dJointGroupDestroy +dJointGroupEmpty +dJointSetAMotorAngle +dJointSetAMotorAxis +dJointSetAMotorMode +dJointSetAMotorNumAxes +dJointSetAMotorParam +dJointSetBallAnchor +dJointSetData +dJointSetFixed +dJointSetHinge2Anchor +dJointSetHinge2Axis1 +dJointSetHinge2Axis2 +dJointSetHinge2Param +dJointSetHingeAnchor +dJointSetHingeAxis +dJointSetHingeParam +dJointSetSliderAxis +dJointSetSliderParam +dJointSetUniversalAnchor +dJointSetUniversalAxis1 +dJointSetUniversalAxis2 +dLDLTAddTL +dLDLTRemove +dMakeRandomMatrix +dMakeRandomVector +dMassAdd +dMassAdjust +dMassRotate +dMassSetBox +dMassSetCappedCylinder +dMassSetParameters +dMassSetSphere +dMassSetZero +dMassTranslate +dMaxDifference +dMultiply0 +dMultiply1 +dMultiply2 +dNormalize3 +dNormalize4 +dPlaneSpace +dQFromAxisAndAngle +dQMultiply0 +dQMultiply1 +dQMultiply2 +dQMultiply3 +dQSetIdentity +dQtoR +dRFrom2Axes +dRFromAxisAndAngle +dRFromEulerAngles +dRSetIdentity +dRandInt +dRandReal +dRandSetSeed +dRemoveRowCol +dRtoQ +dSetMessageHandler +dSetZero +dSimpleSpaceCreate +dSolveCholesky +dSolveLDLT +dSpaceAdd +dSpaceCollide +dSpaceDestroy +dSpaceQuery +dSpaceRemove +dSphereClass +dTestMatrixComparison +dTestRand +dTestSolveLCP +dWorldCreate +dWorldDestroy +dWorldGetCFM +dWorldGetERP +dWorldGetGravity +dWorldImpulseToForce +dWorldSetCFM +dWorldSetERP +dWorldSetGravity +dWorldStep +dWorldStep +dWtoDQ diff --git a/extern/ode/dist/config/user-settings b/extern/ode/dist/config/user-settings new file mode 100644 index 00000000000..d632eba9678 --- /dev/null +++ b/extern/ode/dist/config/user-settings @@ -0,0 +1,31 @@ +# ODE user settings: the following variables must be set by the user + +# (1) the platform to use. this name should have a corresponding +# makefile.PLATFORM file. currently supported platforms are: +# msvc microsoft visual C/C++ +# msvc-dll microsoft visual C/C++, create a DLL +# mingw minimalist GNU for windows +# cygwin cygnus GNU for windows +# unix-gcc GNU gcc on unix +# unix-generic generic unix compiler. you may need to edit the CC +# variable in makefile.unix-generic +# osx Mac OS-X, with the gnu compiler. + +PLATFORM=unix-gcc + +# (2) the floating point precision to use (either "SINGLE" or "DOUBLE") + +PRECISION=SINGLE +#PRECISION=DOUBLE + +# (3) the library type to build (either "debug" if you are doing development, +# or "release" for the optimized library) + +#BUILD=debug +BUILD=release + +# (4) if you are using an old version of MS-Windows that has command line +# length limitations then you will need to set this to "1". otherwise, +# leave it at "0". + +WINDOWS16=0 diff --git a/extern/ode/dist/config/user-settings.example b/extern/ode/dist/config/user-settings.example new file mode 100644 index 00000000000..0b0d480a25a --- /dev/null +++ b/extern/ode/dist/config/user-settings.example @@ -0,0 +1,31 @@ +# ODE user settings: the following variables must be set by the user + +# (1) the platform to use. this name should have a corresponding +# makefile.PLATFORM file. currently supported platforms are: +# msvc microsoft visual C/C++ +# msvc-dll microsoft visual C/C++, create a DLL +# mingw minimalist GNU for windows +# cygwin cygnus GNU for windows +# unix-gcc GNU gcc on unix +# unix-generic generic unix compiler. you may need to edit the CC +# variable in makefile.unix-generic +# osx Mac OS-X, with the gnu compiler. + +PLATFORM=unix-gcc + +# (2) the floating point precision to use (either "SINGLE" or "DOUBLE") + +#PRECISION=SINGLE +PRECISION=DOUBLE + +# (3) the library type to build (either "debug" if you are doing development, +# or "release" for the optimized library) + +#BUILD=debug +BUILD=release + +# (4) if you are using an old version of MS-Windows that has command line +# length limitations then you will need to set this to "1". otherwise, +# leave it at "0". + +WINDOWS16=0 diff --git a/extern/ode/dist/configurator.c b/extern/ode/dist/configurator.c new file mode 100644 index 00000000000..8129716881d --- /dev/null +++ b/extern/ode/dist/configurator.c @@ -0,0 +1,437 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +this program discovers some system configuration stuff, prior to compiling +ODE. the usage is: + + configurator + + +this program looks long, but it really has an extremely simple structure and +should be very easy for anyone to modify. it should be very portable as it +is written in straight ANSI C and only uses the following library functions: + * printf + * fopen (assumes 0 returned on failure) + * fclose + * fprintf + * system + * exit +except where stated, we do not assume anything about the return codes from +these functions. + +why didn't i just use GNU autoconf? : + * autoconf needs a bourne shell and a bunch of other tools that windows + users may not have. + * i like reinventing the wheel. + +*/ + +#include + +/****************************************************************************/ +/* project constants */ + +#define SETUP_SHLIB_DEFS \ + "#ifndef SHAREDLIBIMPORT\n" \ + "#define SHAREDLIBIMPORT\n" \ + "#endif\n" \ + "#ifndef SHAREDLIBEXPORT\n" \ + "#define SHAREDLIBEXPORT\n" \ + "#endif\n" + +/* the config.h header */ +char *config_h_part1 = +"/* per-machine configuration. this file is automatically generated. */\n" +"\n" +"#ifndef _ODE_CONFIG_H_\n" +"#define _ODE_CONFIG_H_\n" +"\n" +"/* shared lib definitions */\n" +SETUP_SHLIB_DEFS +"\n" +"/* standard system headers */\n"; + + +char *config_h_part2 = +"\n" +"#ifdef __cplusplus\n" +"extern \"C\" {\n" +"#endif\n" +"\n"; + +/* the config.h footer */ +char *config_h_footer = +"#ifdef __cplusplus\n" +"}\n" +"#endif\n" +"#endif\n"; + +/****************************************************************************/ +/* implementations of some string functions. these are prefixed with 'x' + * to prevent any conflicts with built-in functions. + */ + +#define strcpy xstrcpy +void xstrcpy (char *dest, char *src) +{ + while (*src) *dest++ = *src++; + *dest = 0; +} + + +#define strcat xstrcat +void xstrcat (char *dest, char *src) +{ + while (*dest) dest++; + while (*src) *dest++ = *src++; + *dest = 0; +} + +/****************************************************************************/ +/* utility functions */ + +/* print an error message and exit */ + +void fatal_error (char *message) +{ + printf ("\n*** configurator failed: %s.\n\n" + "please fix your configuration and try again.\n" + "if you have to fix the configurator program or the makefiles, " + "please email\n" + "your changes to the ODE mailing list (ode@q12.org).\n\n", message); + exit (0); +} + + +/* open a file, generate an error if it can't be done */ + +FILE * xfopen (char *filename, char *mode) +{ + FILE *f; + f = fopen (filename,mode); + if (!f) fatal_error ("can not open a file"); + return f; +} + + +/* return 1 if the file exists or 0 if not */ + +int file_exists (char *filename) +{ + FILE *f; + f = fopen (filename,"rb"); + if (f) fclose (f); + return (f != 0); +} + + +/* write a string to a new file */ + +void write_to_file (char *filename, char *s) +{ + FILE *f = xfopen (filename,"wt"); + fprintf (f,"%s",s); + fclose (f); +} + + +/* write a comment to a header file */ + +void write_header_comment (FILE *file, char *description) +{ + fprintf (file,"/* %s */\n",description); + printf ("%s ...\n",description); +} + + +/* delete a file */ + +char *delete_cmd_line = 0; +void delete_file (char *filename) +{ + char cmd[1000]; + strcpy (cmd,delete_cmd_line); + strcat (cmd," "); + strcat (cmd,filename); + printf ("%s\n",cmd); + system (cmd); +} + + +/* run a compile command */ + +char *compile_cmd_line = 0; +void compile (char *output, char *input) +{ + char cmd[1000]; + strcpy (cmd,compile_cmd_line); + strcat (cmd,output); + strcat (cmd," "); + strcat (cmd,input); + printf ("%s\n",cmd); + system (cmd); +} + + +/* run a program we've just compiled */ + +char *run_prefix = ""; +void run (char *filename) +{ + char cmd[1000]; + strcpy (cmd,run_prefix); + strcat (cmd,filename); + printf ("%s\n",cmd); + system (cmd); +} + +/****************************************************************************/ +/* system tests */ + +void check_if_this_is_a_pentium (FILE *file) +{ + write_header_comment (file,"is this a pentium on a gcc-based platform?"); + write_to_file ("ctest.c", + "int main() {\n" + " asm (\"mov $0,%%eax\\n cpuid\\n\" : : : \"%eax\");\n" + " return 0;\n" + "}\n"); + delete_file ("ctest.exe"); + compile ("ctest.exe","ctest.c"); + if (file_exists ("ctest.exe")) { + fprintf (file,"#define PENTIUM 1\n\n"); + } + else { + fprintf (file,"/* #define PENTIUM 1 -- not a pentium */\n\n"); + } + + delete_file ("ctest.c"); + delete_file ("ctest.exe"); +} + +/****************************************************************************/ +/* tests: standard headers */ + +void get_all_standard_headers (FILE *file) +{ + int i; + FILE *f; + char *header[7] = {"stdio.h", "stdlib.h", "math.h", "string.h", + "stdarg.h", "malloc.h", "alloca.h"}; + + for (i=0; i < sizeof(header)/sizeof(char*); i++) { + FILE *f = xfopen ("ctest.c","wt"); + fprintf (f,"#include <%s>\nint main() { return 0; }\n",header[i]); + fclose (f); + delete_file ("ctest.exe"); + compile ("ctest.exe","ctest.c"); + if (file_exists ("ctest.exe")) { + fprintf (file,"#include <%s>\n",header[i]); + } + } + + delete_file ("ctest.c"); + delete_file ("ctest.exe"); +} + +/****************************************************************************/ +/* tests: typedefs and constants for ODE */ + +void get_ODE_integer_typedefs (FILE *file) +{ + write_header_comment (file,"integer types (we assume int >= 32 bits)"); + if (sizeof(char) != 1) fatal_error ("expecting sizeof(char) == 1"); + if (sizeof(int) < 4) fatal_error ("expecting sizeof(int) >= 4"); + fprintf (file,"typedef char int8;\ntypedef unsigned char uint8;\n"); + if (sizeof(short) == 4) { + fprintf (file,"typedef short int32;\ntypedef unsigned short uint32;\n"); + } + else if (sizeof(int) == 4) { + fprintf (file,"typedef int int32;\ntypedef unsigned int uint32;\n"); + } + else { + fatal_error ("can not find 4 byte integer type"); + } + fprintf (file,"\n" + "/* an integer type that we can safely cast a pointer to and\n" + " * from without loss of bits.\n" + " */\n"); + if (sizeof(short) == sizeof(void*)) { + fprintf (file,"typedef unsigned short intP;\n"); + } + else if (sizeof(int) == sizeof(void*)) { + fprintf (file,"typedef unsigned int intP;\n"); + } + else if (sizeof(long int) == sizeof(void*)) { + fprintf (file,"typedef unsigned long int intP;\n"); + } + fprintf (file,"\n"); +} + + +void get_ODE_float_stuff (FILE *file) +{ + char *suffix,*type; + int i; + FILE *f; + +#define SHARED_LIB_SPEC_DECISION \ + "#if defined SHARED_CONFIG_H_INCLUDED_FROM_DEFINING_FILE\n" \ + " #define GLOBAL_SHAREDLIB_SPEC SHAREDLIBEXPORT\n" \ + "#else \n" \ + " #define GLOBAL_SHAREDLIB_SPEC SHAREDLIBIMPORT\n" \ + "#endif\n" + +#define UNDEF_SHAREDLIB_SPEC "\n#undef GLOBAL_SHAREDLIB_SPEC\n" + +#ifdef dSINGLE + +#define INFBYTES SHARED_LIB_SPEC_DECISION "union dInfBytes { unsigned char c[4]; float f; };\nextern GLOBAL_SHAREDLIB_SPEC union dInfBytes dInfinityValue;\n#define dInfinity (dInfinityValue.f)" + + char *inc[6] = {"#include ", + "#include ", + "", + "", + "", + ""}; + char *decl[6] = { + "SHAREDLIBEXPORT double dInfinityValue = HUGE_VALF;", + "SHAREDLIBEXPORT double dInfinityValue = HUGE_VAL;", + "SHAREDLIBEXPORT union dInfBytes dInfinityValue = {{0x7f,0x80,0,0}};", + "SHAREDLIBEXPORT union dInfBytes dInfinityValue = {{0,0,0x80,0x7f}};", + "SHAREDLIBEXPORT double dInfinityValue = 1.0f/0.0f;", + "SHAREDLIBEXPORT double dInfinityValue = 1e20f;"}; + char *inf[6] = { + SHARED_LIB_SPEC_DECISION "extern GLOBAL_SHAREDLIB_SPEC double dInfinityValue;\n#define dInfinity dInfinityValue" UNDEF_SHAREDLIB_SPEC, + SHARED_LIB_SPEC_DECISION "extern GLOBAL_SHAREDLIB_SPEC double dInfinityValue;\n#define dInfinity dInfinityValue" UNDEF_SHAREDLIB_SPEC, + INFBYTES UNDEF_SHAREDLIB_SPEC, + INFBYTES UNDEF_SHAREDLIB_SPEC, + SHARED_LIB_SPEC_DECISION "extern GLOBAL_SHAREDLIB_SPEC double dInfinityValue;\n#define dInfinity dInfinityValue" UNDEF_SHAREDLIB_SPEC, + SHARED_LIB_SPEC_DECISION "extern GLOBAL_SHAREDLIB_SPEC double dInfinityValue;\n#define dInfinity dInfinityValue" UNDEF_SHAREDLIB_SPEC}; + +#else /* not dSINGLE, must be dDOUBLE */ + +#define INFBYTES SHARED_LIB_SPEC_DECISION "union dInfBytes { unsigned char c[8]; double d; };\nextern GLOBAL_SHAREDLIB_SPEC union dInfBytes dInfinityValue;\n#define dInfinity (dInfinityValue.d)" + + char *inc[5] = { + "#include ", + "", + "", + "", + ""}; + char *decl[5] = { + "SHAREDLIBEXPORT double dInfinityValue = HUGE_VAL;", + "SHAREDLIBEXPORT union dInfBytes dInfinityValue = {{0x7f,0xf0,0,0,0,0,0,0}};", + "SHAREDLIBEXPORT union dInfBytes dInfinityValue = {{0,0,0,0,0,0,0xf0,0x7f}};", + "SHAREDLIBEXPORT double dInfinityValue = 1.0/0.0;", + "SHAREDLIBEXPORT double dInfinityValue = 1e20;"}; + char *inf[5] = { + SHARED_LIB_SPEC_DECISION "extern GLOBAL_SHAREDLIB_SPEC double dInfinityValue;\n#define dInfinity dInfinityValue" UNDEF_SHAREDLIB_SPEC, + INFBYTES UNDEF_SHAREDLIB_SPEC, + INFBYTES UNDEF_SHAREDLIB_SPEC, + SHARED_LIB_SPEC_DECISION "extern GLOBAL_SHAREDLIB_SPEC double dInfinityValue;\n#define dInfinity dInfinityValue" UNDEF_SHAREDLIB_SPEC, + SHARED_LIB_SPEC_DECISION "extern GLOBAL_SHAREDLIB_SPEC double dInfinityValue;\n#define dInfinity dInfinityValue" UNDEF_SHAREDLIB_SPEC}; +#endif + + write_header_comment (file,"select the base floating point type"); +#ifdef dSINGLE + fprintf (file,"#define dSINGLE 1\n\n"); + type = "float"; + suffix = "f"; +#else + fprintf (file,"#define dDOUBLE 1\n\n"); + type = "double"; + suffix = ""; +#endif + + /* infinity */ + write_header_comment (file,"the floating point infinity"); + + /* try the different infinity constants until one works */ + for (i=0; i < sizeof(inf)/sizeof(char*); i++) { + f = xfopen ("ctest.c","wt"); + fprintf (f, + "#include \n" + "#define SHARED_CONFIG_H_INCLUDED_FROM_DEFINING_FILE 1\n" + SETUP_SHLIB_DEFS + "%s\n" + "%s\n" + "%s\n" + "int main() {\n" + " if (dInfinity > 1e10%s && -dInfinity < -1e10%s &&\n" + " -dInfinity < dInfinity) {\n" + " FILE *f = fopen (\"data\",\"wt\");\n" + " fprintf (f,\"foo\\n\");\n" + " fclose (f);\n" + " }\n" + " return 0;\n" + "}\n" + ,inc[i],inf[i],decl[i],suffix,suffix); + fclose (f); + delete_file ("data"); + compile ("ctest.exe","ctest.c"); + run ("ctest.exe"); + if (file_exists ("data")) { + fprintf (file,"#define DINFINITY_DECL %s\n",decl[i]); + fprintf (file,"%s\n\n",inf[i]); + delete_file ("ctest.c"); + delete_file ("ctest.exe"); + delete_file ("data"); + return; + } + } + + fatal_error ("can't determine dInfinity constant"); +} + +/****************************************************************************/ + +int main (int argc, char **argv) +{ + FILE *file; + + if (argc < 4 || argc > 5) + fatal_error ("configurator expects 3 or 4 arguments"); + compile_cmd_line = argv[2]; + delete_cmd_line = argv[3]; + if (argc >= 5) run_prefix = argv[4]; + + /* check some defines we should have been compiled with */ +#if !defined(dSINGLE) && !defined(dDOUBLE) + fatal_error ("you must set PRECISION to either SINGLE or DOUBLE"); +#endif + + file = xfopen (argv[1],"wt"); + fprintf (file,config_h_part1); + get_all_standard_headers (file); + fprintf (file,config_h_part2); + check_if_this_is_a_pentium (file); + get_ODE_integer_typedefs (file); + get_ODE_float_stuff (file); + fprintf (file,config_h_footer); + fclose (file); + + printf ("\n*** configurator succeeded ***\n\n"); + return 0; +} diff --git a/extern/ode/dist/include/ode/README b/extern/ode/dist/include/ode/README new file mode 100644 index 00000000000..aaedfcc38fe --- /dev/null +++ b/extern/ode/dist/include/ode/README @@ -0,0 +1,18 @@ + +this is the public C interface to the ODE library. + +all these files should be includable from C, i.e. they should not use any +C++ features. everything should be protected with + + #ifdef __cplusplus + extern "C" { + #endif + + ... + + #ifdef __cplusplus + } + #endif + +the only exception is the odecpp.h file, which defines a C++ wrapper for +the C interface. remember to keep this in sync! diff --git a/extern/ode/dist/include/ode/common.h b/extern/ode/dist/include/ode/common.h new file mode 100644 index 00000000000..bd29d904028 --- /dev/null +++ b/extern/ode/dist/include/ode/common.h @@ -0,0 +1,307 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_COMMON_H_ +#define _ODE_COMMON_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* configuration stuff */ + +/* the efficient alignment. most platforms align data structures to some + * number of bytes, but this is not always the most efficient alignment. + * for example, many x86 compilers align to 4 bytes, but on a pentium it + * is important to align doubles to 8 byte boundaries (for speed), and + * the 4 floats in a SIMD register to 16 byte boundaries. many other + * platforms have similar behavior. setting a larger alignment can waste + * a (very) small amount of memory. NOTE: this number must be a power of + * two. this is set to 16 by default. + */ +#define EFFICIENT_ALIGNMENT 16 + + +/* constants */ + +/* pi and 1/sqrt(2) are defined here if necessary because they don't get + * defined in on some platforms (like MS-Windows) + */ + +#ifndef M_PI +#define M_PI REAL(3.1415926535897932384626433832795029) +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 REAL(0.7071067811865475244008443621048490) +#endif + + +/* debugging: + * IASSERT is an internal assertion, i.e. a consistency check. if it fails + * we want to know where. + * UASSERT is a user assertion, i.e. if it fails a nice error message + * should be printed for the user. + * AASSERT is an arguments assertion, i.e. if it fails "bad argument(s)" + * is printed. + * DEBUGMSG just prints out a message + */ + +#ifndef dNODEBUG +#ifdef __GNUC__ +#define dIASSERT(a) if (!(a)) dDebug (d_ERR_IASSERT, \ + "assertion \"" #a "\" failed in %s() [%s]",__FUNCTION__,__FILE__); +#define dUASSERT(a,msg) if (!(a)) dDebug (d_ERR_UASSERT, \ + msg " in %s()", __FUNCTION__); +#define dDEBUGMSG(msg) dMessage (d_ERR_UASSERT, \ + msg " in %s()", __FUNCTION__); +#else +#define dIASSERT(a) if (!(a)) dDebug (d_ERR_IASSERT, \ + "assertion \"" #a "\" failed in %s:%d",__FILE__,__LINE__); +#define dUASSERT(a,msg) if (!(a)) dDebug (d_ERR_UASSERT, \ + msg " (%s:%d)", __FILE__,__LINE__); +#define dDEBUGMSG(msg) dMessage (d_ERR_UASSERT, \ + msg " (%s:%d)", __FILE__,__LINE__); +#endif +#else +#define dIASSERT(a) ; +#define dUASSERT(a,msg) ; +#define dDEBUGMSG(msg) ; +#endif +#define dAASSERT(a) dUASSERT(a,"Bad argument(s)") + +/* floating point data type, vector, matrix and quaternion types */ + +#if defined(dSINGLE) +typedef float dReal; +#elif defined(dDOUBLE) +typedef double dReal; +#else +#error You must #define dSINGLE or dDOUBLE +#endif + + +/* round an integer up to a multiple of 4, except that 0 and 1 are unmodified + * (used to compute matrix leading dimensions) + */ +#define dPAD(a) (((a) > 1) ? ((((a)-1)|3)+1) : (a)) + +/* these types are mainly just used in headers */ +typedef dReal dVector3[4]; +typedef dReal dVector4[4]; +typedef dReal dMatrix3[4*3]; +typedef dReal dMatrix4[4*4]; +typedef dReal dMatrix6[8*6]; +typedef dReal dQuaternion[4]; + + +/* precision dependent scalar math functions */ + +#if defined(dSINGLE) + +#define REAL(x) (x ## f) /* form a constant */ +#define dRecip(x) ((float)(1.0f/(x))) /* reciprocal */ +#define dSqrt(x) ((float)sqrt(x)) /* square root */ +#define dRecipSqrt(x) ((float)(1.0f/sqrt(x))) /* reciprocal square root */ +#define dSin(x) ((float)sin(x)) /* sine */ +#define dCos(x) ((float)cos(x)) /* cosine */ +#define dFabs(x) ((float)fabs(x)) /* absolute value */ +#define dAtan2(y,x) ((float)atan2((y),(x))) /* arc tangent with 2 args */ + +#elif defined(dDOUBLE) + +#define REAL(x) (x) +#define dRecip(x) (1.0/(x)) +#define dSqrt(x) sqrt(x) +#define dRecipSqrt(x) (1.0/sqrt(x)) +#define dSin(x) sin(x) +#define dCos(x) cos(x) +#define dFabs(x) fabs(x) +#define dAtan2(y,x) atan2((y),(x)) + +#else +#error You must #define dSINGLE or dDOUBLE +#endif + + +/* utility */ + + +/* round something up to be a multiple of the EFFICIENT_ALIGNMENT */ + +#define dEFFICIENT_SIZE(x) ((((x)-1)|(EFFICIENT_ALIGNMENT-1))+1) + + +/* alloca aligned to the EFFICIENT_ALIGNMENT. note that this can waste + * up to 15 bytes per allocation, depending on what alloca() returns. + */ + +#define dALLOCA16(n) \ + ((char*)dEFFICIENT_SIZE(((int)(alloca((n)+(EFFICIENT_ALIGNMENT-1)))))) + + +/* internal object types (all prefixed with `dx') */ + +struct dxWorld; /* dynamics world */ +struct dxSpace; /* collision space */ +struct dxBody; /* rigid body (dynamics object) */ +struct dxGeom; /* geometry (collision object) */ +struct dxJoint; +struct dxJointNode; +struct dxJointGroup; + +typedef struct dxWorld *dWorldID; +typedef struct dxSpace *dSpaceID; +typedef struct dxBody *dBodyID; +typedef struct dxGeom *dGeomID; +typedef struct dxJoint *dJointID; +typedef struct dxJointGroup *dJointGroupID; + + +/* error numbers */ + +enum { + d_ERR_UNKNOWN = 0, /* unknown error */ + d_ERR_IASSERT, /* internal assertion failed */ + d_ERR_UASSERT, /* user assertion failed */ + d_ERR_LCP /* user assertion failed */ +}; + + +/* joint type numbers */ + +enum { + dJointTypeNone = 0, /* or "unknown" */ + dJointTypeBall, + dJointTypeHinge, + dJointTypeSlider, + dJointTypeContact, + dJointTypeUniversal, + dJointTypeHinge2, + dJointTypeFixed, + dJointTypeNull, + dJointTypeAMotor +}; + + +/* an alternative way of setting joint parameters, using joint parameter + * structures and member constants. we don't actually do this yet. + */ + +/* +typedef struct dLimot { + int mode; + dReal lostop, histop; + dReal vel, fmax; + dReal fudge_factor; + dReal bounce, soft; + dReal suspension_erp, suspension_cfm; +} dLimot; + +enum { + dLimotLoStop = 0x0001, + dLimotHiStop = 0x0002, + dLimotVel = 0x0004, + dLimotFMax = 0x0008, + dLimotFudgeFactor = 0x0010, + dLimotBounce = 0x0020, + dLimotSoft = 0x0040 +}; +*/ + + +/* standard joint parameter names. why are these here? - because we don't want + * to include all the joint function definitions in joint.cpp. hmmmm. + * MSVC complains if we call D_ALL_PARAM_NAMES_X with a blank second argument, + * which is why we have the D_ALL_PARAM_NAMES macro as well. please copy and + * paste between these two. + */ + +#define D_ALL_PARAM_NAMES(start) \ + /* parameters for limits and motors */ \ + dParamLoStop = start, \ + dParamHiStop, \ + dParamVel, \ + dParamFMax, \ + dParamFudgeFactor, \ + dParamBounce, \ + dParamCFM, \ + dParamStopERP, \ + dParamStopCFM, \ + /* parameters for suspension */ \ + dParamSuspensionERP, \ + dParamSuspensionCFM, + +#define D_ALL_PARAM_NAMES_X(start,x) \ + /* parameters for limits and motors */ \ + dParamLoStop ## x = start, \ + dParamHiStop ## x, \ + dParamVel ## x, \ + dParamFMax ## x, \ + dParamFudgeFactor ## x, \ + dParamBounce ## x, \ + dParamCFM ## x, \ + dParamStopERP ## x, \ + dParamStopCFM ## x, \ + /* parameters for suspension */ \ + dParamSuspensionERP ## x, \ + dParamSuspensionCFM ## x, + +enum { + D_ALL_PARAM_NAMES(0) + D_ALL_PARAM_NAMES_X(0x100,2) + D_ALL_PARAM_NAMES_X(0x200,3) + + /* add a multiple of this constant to the basic parameter numbers to get + * the parameters for the second, third etc axes. + */ + dParamGroup=0x100 +}; + + +/* angular motor mode numbers */ + +enum{ + dAMotorUser = 0, + dAMotorEuler = 1 +}; + + +/* joint force feedback information */ + +typedef struct dJointFeedback { + dVector3 f1; // force applied to body 1 + dVector3 t1; // torque applied to body 1 + dVector3 f2; // force applied to body 2 + dVector3 t2; // torque applied to body 2 +} dJointFeedback; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/contact.h b/extern/ode/dist/include/ode/contact.h new file mode 100644 index 00000000000..6fc66a179c0 --- /dev/null +++ b/extern/ode/dist/include/ode/contact.h @@ -0,0 +1,91 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_CONTACT_H_ +#define _ODE_CONTACT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +enum { + dContactMu2 = 0x001, + dContactFDir1 = 0x002, + dContactBounce = 0x004, + dContactSoftERP = 0x008, + dContactSoftCFM = 0x010, + dContactMotion1 = 0x020, + dContactMotion2 = 0x040, + dContactSlip1 = 0x080, + dContactSlip2 = 0x100, + + dContactApprox0 = 0x0000, + dContactApprox1_1 = 0x1000, + dContactApprox1_2 = 0x2000, + dContactApprox1 = 0x3000 +}; + + +typedef struct dSurfaceParameters { + /* must always be defined */ + int mode; + dReal mu; + + /* only defined if the corresponding flag is set in mode */ + dReal mu2; + dReal bounce; + dReal bounce_vel; + dReal soft_erp; + dReal soft_cfm; + dReal motion1,motion2; + dReal slip1,slip2; +} dSurfaceParameters; + + +/* contact info set by collision functions */ + +typedef struct dContactGeom { + dVector3 pos; + dVector3 normal; + dReal depth; + dGeomID g1,g2; +} dContactGeom; + + +/* contact info used by contact joint */ + +typedef struct dContact { + dSurfaceParameters surface; + dContactGeom geom; + dVector3 fdir1; +} dContact; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/error.h b/extern/ode/dist/include/ode/error.h new file mode 100644 index 00000000000..1350bbc8427 --- /dev/null +++ b/extern/ode/dist/include/ode/error.h @@ -0,0 +1,64 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* this comes from the `reuse' library. copy any changes back to the source */ + +#ifndef _ODE_ERROR_H_ +#define _ODE_ERROR_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* all user defined error functions have this type. error and debug functions + * should not return. + */ +typedef void dMessageFunction (int errnum, const char *msg, va_list ap); + +/* set a new error, debug or warning handler. if fn is 0, the default handlers + * are used. + */ +void dSetErrorHandler (dMessageFunction *fn); +void dSetDebugHandler (dMessageFunction *fn); +void dSetMessageHandler (dMessageFunction *fn); + +/* return the current error, debug or warning handler. if the return value is + * 0, the default handlers are in place. + */ +dMessageFunction *dGetErrorHandler(); +dMessageFunction *dGetDebugHandler(); +dMessageFunction *dGetMessageHandler(); + +/* generate a fatal error, debug trap or a message. */ +void dError (int num, const char *msg, ...); +void dDebug (int num, const char *msg, ...); +void dMessage (int num, const char *msg, ...); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/geom.h b/extern/ode/dist/include/ode/geom.h new file mode 100644 index 00000000000..20fc8998ded --- /dev/null +++ b/extern/ode/dist/include/ode/geom.h @@ -0,0 +1,153 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_GEOM_H_ +#define _ODE_GEOM_H_ + +#include +#include +#include + +#if defined SHARED_GEOM_H_INCLUDED_FROM_DEFINING_FILE +#define GLOBAL_SHAREDLIB_SPEC SHAREDLIBEXPORT +#else +#define GLOBAL_SHAREDLIB_SPEC SHAREDLIBIMPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ************************************************************************ */ +/* utility functions */ + +void dClosestLineSegmentPoints (const dVector3 a1, const dVector3 a2, + const dVector3 b1, const dVector3 b2, + dVector3 cp1, dVector3 cp2); + +int dBoxTouchesBox (const dVector3 _p1, const dMatrix3 R1, + const dVector3 side1, const dVector3 _p2, + const dMatrix3 R2, const dVector3 side2); + +void dInfiniteAABB (dGeomID geom, dReal aabb[6]); +void dCloseODE(); + +/* ************************************************************************ */ +/* standard classes */ + +/* class numbers */ +extern GLOBAL_SHAREDLIB_SPEC int dSphereClass; +extern GLOBAL_SHAREDLIB_SPEC int dBoxClass; +extern GLOBAL_SHAREDLIB_SPEC int dCCylinderClass; +extern GLOBAL_SHAREDLIB_SPEC int dPlaneClass; +extern GLOBAL_SHAREDLIB_SPEC int dGeomGroupClass; +extern GLOBAL_SHAREDLIB_SPEC int dGeomTransformClass; + +/* constructors */ +dGeomID dCreateSphere (dSpaceID space, dReal radius); +dGeomID dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz); +dGeomID dCreatePlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d); +dGeomID dCreateCCylinder (dSpaceID space, dReal radius, dReal length); +dGeomID dCreateGeomGroup (dSpaceID space); + +/* set geometry parameters */ +void dGeomSphereSetRadius (dGeomID sphere, dReal radius); +void dGeomBoxSetLengths (dGeomID box, dReal lx, dReal ly, dReal lz); +void dGeomPlaneSetParams (dGeomID plane, dReal a, dReal b, dReal c, dReal d); +void dGeomCCylinderSetParams (dGeomID ccylinder, dReal radius, dReal length); + +/* get geometry parameters */ +int dGeomGetClass (dGeomID); +dReal dGeomSphereGetRadius (dGeomID sphere); +void dGeomBoxGetLengths (dGeomID box, dVector3 result); +void dGeomPlaneGetParams (dGeomID plane, dVector4 result); +void dGeomCCylinderGetParams (dGeomID ccylinder, + dReal *radius, dReal *length); + +/* general functions */ +void dGeomSetData (dGeomID, void *); +void *dGeomGetData (dGeomID); +void dGeomSetBody (dGeomID, dBodyID); +dBodyID dGeomGetBody (dGeomID); +void dGeomSetPosition (dGeomID, dReal x, dReal y, dReal z); +void dGeomSetRotation (dGeomID, const dMatrix3 R); +const dReal * dGeomGetPosition (dGeomID); +const dReal * dGeomGetRotation (dGeomID); +void dGeomDestroy (dGeomID); +void dGeomGetAABB (dGeomID, dReal aabb[6]); +dReal *dGeomGetSpaceAABB (dGeomID); + +/* ************************************************************************ */ +/* geometry group functions */ + +void dGeomGroupAdd (dGeomID group, dGeomID x); +void dGeomGroupRemove (dGeomID group, dGeomID x); +int dGeomGroupGetNumGeoms (dGeomID group); +dGeomID dGeomGroupGetGeom (dGeomID group, int i); + +/* ************************************************************************ */ +/* transformed geometry functions */ + +dGeomID dCreateGeomTransform (dSpaceID space); +void dGeomTransformSetGeom (dGeomID g, dGeomID obj); +dGeomID dGeomTransformGetGeom (dGeomID g); +void dGeomTransformSetCleanup (dGeomID g, int mode); +int dGeomTransformGetCleanup (dGeomID g); +void dGeomTransformSetInfo (dGeomID g, int mode); +int dGeomTransformGetInfo (dGeomID g); + +/* ************************************************************************ */ +/* general collision */ + +int dCollide (dGeomID o1, dGeomID o2, int flags, dContactGeom *contact, + int skip); + +/* ************************************************************************ */ +/* custom classes */ + +typedef void dGetAABBFn (dGeomID, dReal aabb[6]); +typedef int dColliderFn (dGeomID o1, dGeomID o2, + int flags, dContactGeom *contact, int skip); +typedef dColliderFn * dGetColliderFnFn (int num); +typedef void dGeomDtorFn (dGeomID o); +typedef int dAABBTestFn (dGeomID o1, dGeomID o2, dReal aabb[6]); + +typedef struct dGeomClass { + int bytes; + dGetColliderFnFn *collider; + dGetAABBFn *aabb; + dAABBTestFn *aabb_test; + dGeomDtorFn *dtor; +} dGeomClass; + +int dCreateGeomClass (const dGeomClass *classptr); +void * dGeomGetClassData (dGeomID); +dGeomID dCreateGeom (int classnum); + +/* ************************************************************************ */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/mass.h b/extern/ode/dist/include/ode/mass.h new file mode 100644 index 00000000000..8e75da0c1eb --- /dev/null +++ b/extern/ode/dist/include/ode/mass.h @@ -0,0 +1,98 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_MASS_H_ +#define _ODE_MASS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct dMass; +typedef struct dMass dMass; + + +void dMassSetZero (dMass *); + +void dMassSetParameters (dMass *, dReal themass, + dReal cgx, dReal cgy, dReal cgz, + dReal I11, dReal I22, dReal I33, + dReal I12, dReal I13, dReal I23); + +void dMassSetSphere (dMass *, dReal density, dReal radius); + +void dMassSetCappedCylinder (dMass *, dReal density, int direction, + dReal a, dReal b); + +void dMassSetBox (dMass *, dReal density, + dReal lx, dReal ly, dReal lz); + +void dMassAdjust (dMass *, dReal newmass); + +void dMassTranslate (dMass *, dReal x, dReal y, dReal z); + +void dMassRotate (dMass *, const dMatrix3 R); + +void dMassAdd (dMass *a, const dMass *b); + + + +struct dMass { + dReal mass; + dVector4 c; + dMatrix3 I; + +#ifdef __cplusplus + dMass() + { dMassSetZero (this); } + void setZero() + { dMassSetZero (this); } + void setParameters (dReal themass, dReal cgx, dReal cgy, dReal cgz, + dReal I11, dReal I22, dReal I33, + dReal I12, dReal I13, dReal I23) + { dMassSetParameters (this,themass,cgx,cgy,cgz,I11,I22,I33,I12,I13,I23); } + void setSphere (dReal density, dReal radius) + { dMassSetSphere (this,density,radius); } + void setCappedCylinder (dReal density, int direction, dReal a, dReal b) + { dMassSetCappedCylinder (this,density,direction,a,b); } + void setBox (dReal density, dReal lx, dReal ly, dReal lz) + { dMassSetBox (this,density,lx,ly,lz); } + void adjust (dReal newmass) + { dMassAdjust (this,newmass); } + void translate (dReal x, dReal y, dReal z) + { dMassTranslate (this,x,y,z); } + void rotate (const dMatrix3 R) + { dMassRotate (this,R); } + void add (const dMass *b) + { dMassAdd (this,b); } +#endif +}; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/matrix.h b/extern/ode/dist/include/ode/matrix.h new file mode 100644 index 00000000000..94d830095cd --- /dev/null +++ b/extern/ode/dist/include/ode/matrix.h @@ -0,0 +1,195 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* optimized and unoptimized vector and matrix functions */ + +#ifndef _ODE_MATRIX_H_ +#define _ODE_MATRIX_H_ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* set a vector/matrix of size n to all zeros, or to a specific value. */ + +void dSetZero (dReal *a, int n); +void dSetValue (dReal *a, int n, dReal value); + + +/* get the dot product of two n*1 vectors. if n <= 0 then + * zero will be returned (in which case a and b need not be valid). + */ + +dReal dDot (const dReal *a, const dReal *b, int n); + + +/* get the dot products of (a0,b), (a1,b), etc and return them in outsum. + * all vectors are n*1. if n <= 0 then zeroes will be returned (in which case + * the input vectors need not be valid). this function is somewhat faster + * than calling dDot() for all of the combinations separately. + */ + +/* NOT INCLUDED in the library for now. +void dMultidot2 (const dReal *a0, const dReal *a1, + const dReal *b, dReal *outsum, int n); +*/ + + +/* matrix multiplication. all matrices are stored in standard row format. + * the digit refers to the argument that is transposed: + * 0: A = B * C (sizes: A:p*r B:p*q C:q*r) + * 1: A = B' * C (sizes: A:p*r B:q*p C:q*r) + * 2: A = B * C' (sizes: A:p*r B:p*q C:r*q) + * case 1,2 are equivalent to saying that the operation is A=B*C but + * B or C are stored in standard column format. + */ + +void dMultiply0 (dReal *A, const dReal *B, const dReal *C, int p,int q,int r); +void dMultiply1 (dReal *A, const dReal *B, const dReal *C, int p,int q,int r); +void dMultiply2 (dReal *A, const dReal *B, const dReal *C, int p,int q,int r); + + +/* do an in-place cholesky decomposition on the lower triangle of the n*n + * symmetric matrix A (which is stored by rows). the resulting lower triangle + * will be such that L*L'=A. return 1 on success and 0 on failure (on failure + * the matrix is not positive definite). + */ + +int dFactorCholesky (dReal *A, int n); + + +/* solve for x: L*L'*x = b, and put the result back into x. + * L is size n*n, b is size n*1. only the lower triangle of L is considered. + */ + +void dSolveCholesky (const dReal *L, dReal *b, int n); + + +/* compute the inverse of the n*n positive definite matrix A and put it in + * Ainv. this is not especially fast. this returns 1 on success (A was + * positive definite) or 0 on failure (not PD). + */ + +int dInvertPDMatrix (const dReal *A, dReal *Ainv, int n); + + +/* check whether an n*n matrix A is positive definite, return 1/0 (yes/no). + * positive definite means that x'*A*x > 0 for any x. this performs a + * cholesky decomposition of A. if the decomposition fails then the matrix + * is not positive definite. A is stored by rows. A is not altered. + */ + +int dIsPositiveDefinite (const dReal *A, int n); + + +/* factorize a matrix A into L*D*L', where L is lower triangular with ones on + * the diagonal, and D is diagonal. + * A is an n*n matrix stored by rows, with a leading dimension of n rounded + * up to 4. L is written into the strict lower triangle of A (the ones are not + * written) and the reciprocal of the diagonal elements of D are written into + * d. + */ +void dFactorLDLT (dReal *A, dReal *d, int n, int nskip); + + +/* solve L*x=b, where L is n*n lower triangular with ones on the diagonal, + * and x,b are n*1. b is overwritten with x. + * the leading dimension of L is `nskip'. + */ +void dSolveL1 (const dReal *L, dReal *b, int n, int nskip); + + +/* solve L'*x=b, where L is n*n lower triangular with ones on the diagonal, + * and x,b are n*1. b is overwritten with x. + * the leading dimension of L is `nskip'. + */ +void dSolveL1T (const dReal *L, dReal *b, int n, int nskip); + + +/* in matlab syntax: a(1:n) = a(1:n) .* d(1:n) */ + +void dVectorScale (dReal *a, const dReal *d, int n); + + +/* given `L', a n*n lower triangular matrix with ones on the diagonal, + * and `d', a n*1 vector of the reciprocal diagonal elements of an n*n matrix + * D, solve L*D*L'*x=b where x,b are n*1. x overwrites b. + * the leading dimension of L is `nskip'. + */ + +void dSolveLDLT (const dReal *L, const dReal *d, dReal *b, int n, int nskip); + + +/* given an L*D*L' factorization of an n*n matrix A, return the updated + * factorization L2*D2*L2' of A plus the following "top left" matrix: + * + * [ b a' ] <-- b is a[0] + * [ a 0 ] <-- a is a[1..n-1] + * + * - L has size n*n, its leading dimension is nskip. L is lower triangular + * with ones on the diagonal. only the lower triangle of L is referenced. + * - d has size n. d contains the reciprocal diagonal elements of D. + * - a has size n. + * the result is written into L, except that the left column of L and d[0] + * are not actually modified. see ldltaddTL.m for further comments. + */ +void dLDLTAddTL (dReal *L, dReal *d, const dReal *a, int n, int nskip); + + +/* given an L*D*L' factorization of a permuted matrix A, produce a new + * factorization for row and column `r' removed. + * - A has size n1*n1, its leading dimension in nskip. A is symmetric and + * positive definite. only the lower triangle of A is referenced. + * A itself may actually be an array of row pointers. + * - L has size n2*n2, its leading dimension in nskip. L is lower triangular + * with ones on the diagonal. only the lower triangle of L is referenced. + * - d has size n2. d contains the reciprocal diagonal elements of D. + * - p is a permutation vector. it contains n2 indexes into A. each index + * must be in the range 0..n1-1. + * - r is the row/column of L to remove. + * the new L will be written within the old L, i.e. will have the same leading + * dimension. the last row and column of L, and the last element of d, are + * undefined on exit. + * + * a fast O(n^2) algorithm is used. see ldltremove.m for further comments. + */ +void dLDLTRemove (dReal **A, const int *p, dReal *L, dReal *d, + int n1, int n2, int r, int nskip); + + +/* given an n*n matrix A (with leading dimension nskip), remove the r'th row + * and column by moving elements. the new matrix will have the same leading + * dimension. the last row and column of A are untouched on exit. + */ +void dRemoveRowCol (dReal *A, int n, int nskip, int r); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/memory.h b/extern/ode/dist/include/ode/memory.h new file mode 100644 index 00000000000..7ea668e4d39 --- /dev/null +++ b/extern/ode/dist/include/ode/memory.h @@ -0,0 +1,64 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* this comes from the `reuse' library. copy any changes back to the source */ + +#ifndef _ODE_MEMORY_H_ +#define _ODE_MEMORY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* function types to allocate and free memory */ +typedef void * dAllocFunction (int size); +typedef void * dReallocFunction (void *ptr, int oldsize, int newsize); +typedef void dFreeFunction (void *ptr, int size); + +/* set new memory management functions. if fn is 0, the default handlers are + * used. */ +void dSetAllocHandler (dAllocFunction *fn); +void dSetReallocHandler (dReallocFunction *fn); +void dSetFreeHandler (dFreeFunction *fn); + +/* get current memory management functions */ +dAllocFunction *dGetAllocHandler (); +dReallocFunction *dGetReallocHandler (); +dFreeFunction *dGetFreeHandler (); + +/* allocate and free memory. */ +void * dAlloc (int size); +void * dRealloc (void *ptr, int oldsize, int newsize); +void dFree (void *ptr, int size); + +/* when alloc debugging is turned on, this indicates that the given block of + * alloc()ed memory should not be reported as "still in use" when the program + * exits. + */ +void dAllocDontReport (void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/misc.h b/extern/ode/dist/include/ode/misc.h new file mode 100644 index 00000000000..241ad71ed9e --- /dev/null +++ b/extern/ode/dist/include/ode/misc.h @@ -0,0 +1,86 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* miscellaneous math functions. these are mostly useful for testing */ + +#ifndef _ODE_MISC_H_ +#define _ODE_MISC_H_ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* return 1 if the random number generator is working. */ +int dTestRand(); + +/* return next 32 bit random number. this uses a not-very-random linear + * congruential method. + */ +unsigned long dRand(); + +/* get and set the current random number seed. */ +unsigned long dRandGetSeed(); +void dRandSetSeed (unsigned long s); + +/* return a random integer between 0..n-1. the distribution will get worse + * as n approaches 2^32. + */ +int dRandInt (int n); + +/* return a random real number between 0..1 */ +dReal dRandReal(); + +/* print out a matrix */ +#ifdef __cplusplus +void dPrintMatrix (dReal *A, int n, int m, char *fmt = "%10.4f ", + FILE *f=stdout); +#else +void dPrintMatrix (dReal *A, int n, int m, char *fmt, FILE *f); +#endif + +/* make a random vector with entries between +/- range. A has n elements. */ +void dMakeRandomVector (dReal *A, int n, dReal range); + +/* make a random matrix with entries between +/- range. A has size n*m. */ +void dMakeRandomMatrix (dReal *A, int n, int m, dReal range); + +/* clear the upper triangle of a square matrix */ +void dClearUpperTriangle (dReal *A, int n); + +/* return the maximum element difference between the two n*m matrices */ +dReal dMaxDifference (const dReal *A, const dReal *B, int n, int m); + +/* return the maximum element difference between the lower triangle of two + * n*n matrices */ +dReal dMaxDifferenceLowerTriangle (const dReal *A, const dReal *B, int n); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/objects.h b/extern/ode/dist/include/ode/objects.h new file mode 100644 index 00000000000..606051ead34 --- /dev/null +++ b/extern/ode/dist/include/ode/objects.h @@ -0,0 +1,202 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_OBJECTS_H_ +#define _ODE_OBJECTS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* world */ + +dWorldID dWorldCreate(); +void dWorldDestroy (dWorldID); + +void dWorldSetGravity (dWorldID, dReal x, dReal y, dReal z); +void dWorldGetGravity (dWorldID, dVector3 gravity); +void dWorldSetERP (dWorldID, dReal erp); +dReal dWorldGetERP (dWorldID); +void dWorldSetCFM (dWorldID, dReal cfm); +dReal dWorldGetCFM (dWorldID); +void dWorldStep (dWorldID, dReal stepsize); +void dWorldImpulseToForce (dWorldID, dReal stepsize, + dReal ix, dReal iy, dReal iz, dVector3 force); + +/* bodies */ + +dBodyID dBodyCreate (dWorldID); +void dBodyDestroy (dBodyID); + +void dBodySetData (dBodyID, void *data); +void *dBodyGetData (dBodyID); + +void dBodySetPosition (dBodyID, dReal x, dReal y, dReal z); +void dBodySetRotation (dBodyID, const dMatrix3 R); +void dBodySetQuaternion (dBodyID, const dQuaternion q); +void dBodySetLinearVel (dBodyID, dReal x, dReal y, dReal z); +void dBodySetAngularVel (dBodyID, dReal x, dReal y, dReal z); +const dReal * dBodyGetPosition (dBodyID); +const dReal * dBodyGetRotation (dBodyID); /* ptr to 4x3 rot matrix */ +const dReal * dBodyGetQuaternion (dBodyID); +const dReal * dBodyGetLinearVel (dBodyID); +const dReal * dBodyGetAngularVel (dBodyID); + +void dBodySetMass (dBodyID, const dMass *mass); +void dBodyGetMass (dBodyID, dMass *mass); + +void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); +void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); +void dBodyAddRelForce (dBodyID, dReal fx, dReal fy, dReal fz); +void dBodyAddRelTorque (dBodyID, dReal fx, dReal fy, dReal fz); +void dBodyAddForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz); +void dBodyAddForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz); +void dBodyAddRelForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz); +void dBodyAddRelForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz); + +const dReal * dBodyGetForce (dBodyID); +const dReal * dBodyGetTorque (dBodyID); +void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z); +void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z); + +void dBodyGetRelPointPos (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyGetRelPointVel (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyGetPointVel (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyGetPosRelPoint (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyVectorToWorld (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyVectorFromWorld (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); + +void dBodySetFiniteRotationMode (dBodyID, int mode); +void dBodySetFiniteRotationAxis (dBodyID, dReal x, dReal y, dReal z); + +int dBodyGetFiniteRotationMode (dBodyID); +void dBodyGetFiniteRotationAxis (dBodyID, dVector3 result); + +int dBodyGetNumJoints (dBodyID b); +dJointID dBodyGetJoint (dBodyID, int index); + +void dBodyEnable (dBodyID); +void dBodyDisable (dBodyID); +int dBodyIsEnabled (dBodyID); + +void dBodySetGravityMode (dBodyID b, int mode); +int dBodyGetGravityMode (dBodyID b); + + +/* joints */ + +dJointID dJointCreateBall (dWorldID, dJointGroupID); +dJointID dJointCreateHinge (dWorldID, dJointGroupID); +dJointID dJointCreateSlider (dWorldID, dJointGroupID); +dJointID dJointCreateContact (dWorldID, dJointGroupID, const dContact *); +dJointID dJointCreateHinge2 (dWorldID, dJointGroupID); +dJointID dJointCreateUniversal (dWorldID, dJointGroupID); +dJointID dJointCreateFixed (dWorldID, dJointGroupID); +dJointID dJointCreateNull (dWorldID, dJointGroupID); +dJointID dJointCreateAMotor (dWorldID, dJointGroupID); + +void dJointDestroy (dJointID); + +dJointGroupID dJointGroupCreate (int max_size); +void dJointGroupDestroy (dJointGroupID); +void dJointGroupEmpty (dJointGroupID); + +void dJointAttach (dJointID, dBodyID body1, dBodyID body2); +void dJointSetData (dJointID, void *data); +void *dJointGetData (dJointID); +int dJointGetType (dJointID); +dBodyID dJointGetBody (dJointID, int index); + +void dJointSetFeedback (dJointID, dJointFeedback *); +dJointFeedback *dJointGetFeedback (dJointID); + +void dJointSetBallAnchor (dJointID, dReal x, dReal y, dReal z); +void dJointSetHingeAnchor (dJointID, dReal x, dReal y, dReal z); +void dJointSetHingeAxis (dJointID, dReal x, dReal y, dReal z); +void dJointSetHingeParam (dJointID, int parameter, dReal value); +void dJointSetSliderAxis (dJointID, dReal x, dReal y, dReal z); +void dJointSetSliderParam (dJointID, int parameter, dReal value); +void dJointSetHinge2Anchor (dJointID, dReal x, dReal y, dReal z); +void dJointSetHinge2Axis1 (dJointID, dReal x, dReal y, dReal z); +void dJointSetHinge2Axis2 (dJointID, dReal x, dReal y, dReal z); +void dJointSetHinge2Param (dJointID, int parameter, dReal value); +void dJointSetUniversalAnchor (dJointID, dReal x, dReal y, dReal z); +void dJointSetUniversalAxis1 (dJointID, dReal x, dReal y, dReal z); +void dJointSetUniversalAxis2 (dJointID, dReal x, dReal y, dReal z); +void dJointSetFixed (dJointID); +void dJointSetAMotorNumAxes (dJointID, int num); +void dJointSetAMotorAxis (dJointID, int anum, int rel, + dReal x, dReal y, dReal z); +void dJointSetAMotorAngle (dJointID, int anum, dReal angle); +void dJointSetAMotorParam (dJointID, int parameter, dReal value); +void dJointSetAMotorMode (dJointID, int mode); + +void dJointGetBallAnchor (dJointID, dVector3 result); +void dJointGetHingeAnchor (dJointID, dVector3 result); +void dJointGetHingeAxis (dJointID, dVector3 result); +dReal dJointGetHingeParam (dJointID, int parameter); +dReal dJointGetHingeAngle (dJointID); +dReal dJointGetHingeAngleRate (dJointID); +dReal dJointGetSliderPosition (dJointID); +dReal dJointGetSliderPositionRate (dJointID); +void dJointGetSliderAxis (dJointID, dVector3 result); +dReal dJointGetSliderParam (dJointID, int parameter); +void dJointGetHinge2Anchor (dJointID, dVector3 result); +void dJointGetHinge2Axis1 (dJointID, dVector3 result); +void dJointGetHinge2Axis2 (dJointID, dVector3 result); +dReal dJointGetHinge2Param (dJointID, int parameter); +dReal dJointGetHinge2Angle1 (dJointID); +dReal dJointGetHinge2Angle1Rate (dJointID); +dReal dJointGetHinge2Angle2Rate (dJointID); +void dJointGetUniversalAnchor (dJointID, dVector3 result); +void dJointGetUniversalAxis1 (dJointID, dVector3 result); +void dJointGetUniversalAxis2 (dJointID, dVector3 result); +int dJointGetAMotorNumAxes (dJointID); +void dJointGetAMotorAxis (dJointID, int anum, dVector3 result); +int dJointGetAMotorAxisRel (dJointID, int anum); +dReal dJointGetAMotorAngle (dJointID, int anum); +dReal dJointGetAMotorAngleRate (dJointID, int anum); +dReal dJointGetAMotorParam (dJointID, int parameter); +int dJointGetAMotorMode (dJointID); + +int dAreConnected (dBodyID, dBodyID); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/ode.h b/extern/ode/dist/include/ode/ode.h new file mode 100644 index 00000000000..da7f2e1a0e7 --- /dev/null +++ b/extern/ode/dist/include/ode/ode.h @@ -0,0 +1,45 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_ODE_H_ +#define _ODE_ODE_H_ + +/* include *everything* here */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + diff --git a/extern/ode/dist/include/ode/odecpp.h b/extern/ode/dist/include/ode/odecpp.h new file mode 100644 index 00000000000..35712236d1d --- /dev/null +++ b/extern/ode/dist/include/ode/odecpp.h @@ -0,0 +1,797 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// C++ interface for everything + + +#ifndef _ODE_ODECPP_H_ +#define _ODE_ODECPP_H_ +#ifdef __cplusplus + +#include + + +class dWorld { + dWorldID _id; + + // intentionally undefined, don't use these + dWorld (const dWorld &); + void operator= (const dWorld &); + +public: + dWorld() + { _id = dWorldCreate(); } + ~dWorld() + { dWorldDestroy (_id); } + + dWorldID id() const + { return _id; } + operator dWorldID() const + { return _id; } + + void setGravity (dReal x, dReal y, dReal z) + { dWorldSetGravity (_id,x,y,z); } + void getGravity (dVector3 g) const + { dWorldGetGravity (_id,g); } + + void setERP (dReal erp) + { dWorldSetERP(_id, erp); } + dReal getERP() const + { return dWorldGetERP(_id); } + + void setCFM (dReal cfm) + { dWorldSetCFM(_id, cfm); } + dReal getCFM() const + { return dWorldGetCFM(_id); } + + void step (dReal stepsize) + { dWorldStep (_id,stepsize); } + + void impulseToForce (dReal stepsize, dReal ix, dReal iy, dReal iz, + dVector3 force) + { dWorldImpulseToForce (_id,stepsize,ix,iy,iz,force); } +}; + + +class dBody { + dBodyID _id; + + // intentionally undefined, don't use these + dBody (const dBody &); + void operator= (const dBody &); + +public: + dBody() + { _id = 0; } + dBody (dWorldID world) + { _id = dBodyCreate (world); } + ~dBody() + { if (_id) dBodyDestroy (_id); } + + void create (dWorldID world) { + if (_id) dBodyDestroy (_id); + _id = dBodyCreate (world); + } + + dBodyID id() const + { return _id; } + operator dBodyID() const + { return _id; } + + void setData (void *data) + { dBodySetData (_id,data); } + void *getData() const + { return dBodyGetData (_id); } + + void setPosition (dReal x, dReal y, dReal z) + { dBodySetPosition (_id,x,y,z); } + void setRotation (const dMatrix3 R) + { dBodySetRotation (_id,R); } + void setQuaternion (const dQuaternion q) + { dBodySetQuaternion (_id,q); } + void setLinearVel (dReal x, dReal y, dReal z) + { dBodySetLinearVel (_id,x,y,z); } + void setAngularVel (dReal x, dReal y, dReal z) + { dBodySetAngularVel (_id,x,y,z); } + + const dReal * getPosition() const + { return dBodyGetPosition (_id); } + const dReal * getRotation() const + { return dBodyGetRotation (_id); } + const dReal * getQuaternion() const + { return dBodyGetQuaternion (_id); } + const dReal * getLinearVel() const + { return dBodyGetLinearVel (_id); } + const dReal * getAngularVel() const + { return dBodyGetAngularVel (_id); } + + void setMass (const dMass *mass) + { dBodySetMass (_id,mass); } + void getMass (dMass *mass) const + { dBodyGetMass (_id,mass); } + + void addForce (dReal fx, dReal fy, dReal fz) + { dBodyAddForce (_id, fx, fy, fz); } + void addTorque (dReal fx, dReal fy, dReal fz) + { dBodyAddTorque (_id, fx, fy, fz); } + void addRelForce (dReal fx, dReal fy, dReal fz) + { dBodyAddRelForce (_id, fx, fy, fz); } + void addRelTorque (dReal fx, dReal fy, dReal fz) + { dBodyAddRelTorque (_id, fx, fy, fz); } + void addForceAtPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddForceAtPos (_id, fx, fy, fz, px, py, pz); } + void addForceAtRelPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddForceAtRelPos (_id, fx, fy, fz, px, py, pz); } + void addRelForceAtPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddRelForceAtPos (_id, fx, fy, fz, px, py, pz); } + void addRelForceAtRelPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddRelForceAtRelPos (_id, fx, fy, fz, px, py, pz); } + + const dReal * getForce() const + { return dBodyGetForce(_id); } + const dReal * getTorque() const + { return dBodyGetTorque(_id); } + void setForce (dReal x, dReal y, dReal z) + { dBodySetForce (_id,x,y,z); } + void setTorque (dReal x, dReal y, dReal z) + { dBodySetTorque (_id,x,y,z); } + + void enable() + { dBodyEnable (_id); } + void disable() + { dBodyDisable (_id); } + int isEnabled() const + { return dBodyIsEnabled (_id); } + + void getRelPointPos (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyGetRelPointPos (_id, px, py, pz, result); } + void getRelPointVel (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyGetRelPointVel (_id, px, py, pz, result); } + void getPointVel (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyGetPointVel (_id,px,py,pz,result); } + void getPosRelPoint (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyGetPosRelPoint (_id,px,py,pz,result); } + void vectorToWorld (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyVectorToWorld (_id,px,py,pz,result); } + void vectorFromWorld (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyVectorFromWorld (_id,px,py,pz,result); } + + void setFiniteRotationMode (int mode) + { dBodySetFiniteRotationMode (_id, mode); } + void setFiniteRotationAxis (dReal x, dReal y, dReal z) + { dBodySetFiniteRotationAxis (_id, x, y, z); } + + int getFiniteRotationMode() const + { return dBodyGetFiniteRotationMode (_id); } + void getFiniteRotationAxis (dVector3 result) const + { dBodyGetFiniteRotationAxis (_id, result); } + + int getNumJoints() const + { return dBodyGetNumJoints (_id); } + dJointID getJoint (int index) const + { return dBodyGetJoint (_id, index); } + + void setGravityMode (int mode) + { dBodySetGravityMode (_id,mode); } + int getGravityMode() const + { return dBodyGetGravityMode (_id); } + + int isConnectedTo (dBodyID body) const + { return dAreConnected (_id, body); } +}; + + +class dJointGroup { + dJointGroupID _id; + + // intentionally undefined, don't use these + dJointGroup (const dJointGroup &); + void operator= (const dJointGroup &); + +public: + dJointGroup (int dummy_arg=0) + { _id = dJointGroupCreate (0); } + ~dJointGroup() + { dJointGroupDestroy (_id); } + void create (int dummy_arg=0) { + if (_id) dJointGroupDestroy (_id); + _id = dJointGroupCreate (0); + } + + dJointGroupID id() const + { return _id; } + operator dJointGroupID() const + { return _id; } + + void empty() + { dJointGroupEmpty (_id); } +}; + + +class dJoint { +private: + // intentionally undefined, don't use these + dJoint (const dJoint &) ; + void operator= (const dJoint &); + +protected: + dJointID _id; + +public: + dJoint() + { _id = 0; } + ~dJoint() + { if (_id) dJointDestroy (_id); } + + dJointID id() const + { return _id; } + operator dJointID() const + { return _id; } + + void attach (dBodyID body1, dBodyID body2) + { dJointAttach (_id, body1, body2); } + + void setData (void *data) + { dJointSetData (_id, data); } + void *getData (void *data) const + { return dJointGetData (_id); } + + int getType() const + { return dJointGetType (_id); } + + dBodyID getBody (int index) const + { return dJointGetBody (_id, index); } +}; + + +class dBallJoint : public dJoint { +private: + // intentionally undefined, don't use these + dBallJoint (const dBallJoint &); + void operator= (const dBallJoint &); + +public: + dBallJoint() { } + dBallJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateBall (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateBall (world, group); + } + + void setAnchor (dReal x, dReal y, dReal z) + { dJointSetBallAnchor (_id, x, y, z); } + void getAnchor (dVector3 result) const + { dJointGetBallAnchor (_id, result); } +} ; + + +class dHingeJoint : public dJoint { + // intentionally undefined, don't use these + dHingeJoint (const dHingeJoint &); + void operator = (const dHingeJoint &); + +public: + dHingeJoint() { } + dHingeJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateHinge (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateHinge (world, group); + } + + void setAnchor (dReal x, dReal y, dReal z) + { dJointSetHingeAnchor (_id, x, y, z); } + void getAnchor (dVector3 result) const + { dJointGetHingeAnchor (_id, result); } + + void setAxis (dReal x, dReal y, dReal z) + { dJointSetHingeAxis (_id, x, y, z); } + void getAxis (dVector3 result) const + { dJointGetHingeAxis (_id, result); } + + dReal getAngle() const + { return dJointGetHingeAngle (_id); } + dReal getAngleRate() const + { return dJointGetHingeAngleRate (_id); } + + void setParam (int parameter, dReal value) + { dJointSetHingeParam (_id, parameter, value); } + dReal getParam (int parameter) const + { return dJointGetHingeParam (_id, parameter); } +}; + + +class dSliderJoint : public dJoint { + // intentionally undefined, don't use these + dSliderJoint (const dSliderJoint &); + void operator = (const dSliderJoint &); + +public: + dSliderJoint() { } + dSliderJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateSlider (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateSlider (world, group); + } + + void setAxis (dReal x, dReal y, dReal z) + { dJointSetSliderAxis (_id, x, y, z); } + void getAxis (dVector3 result) const + { dJointGetSliderAxis (_id, result); } + + dReal getPosition() const + { return dJointGetSliderPosition (_id); } + dReal getPositionRate() const + { return dJointGetSliderPositionRate (_id); } + + void setParam (int parameter, dReal value) + { dJointSetSliderParam (_id, parameter, value); } + dReal getParam (int parameter) const + { return dJointGetSliderParam (_id, parameter); } +}; + + +class dUniversalJoint : public dJoint { + // intentionally undefined, don't use these + dUniversalJoint (const dUniversalJoint &); + void operator = (const dUniversalJoint &); + +public: + dUniversalJoint() { } + dUniversalJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateUniversal (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateUniversal (world, group); + } + + void setAnchor (dReal x, dReal y, dReal z) + { dJointSetUniversalAnchor (_id, x, y, z); } + void setAxis1 (dReal x, dReal y, dReal z) + { dJointSetUniversalAxis1 (_id, x, y, z); } + void setAxis2 (dReal x, dReal y, dReal z) + { dJointSetUniversalAxis2 (_id, x, y, z); } + + void getAnchor (dVector3 result) const + { dJointGetUniversalAnchor (_id, result); } + void getAxis1 (dVector3 result) const + { dJointGetUniversalAxis1 (_id, result); } + void getAxis2 (dVector3 result) const + { dJointGetUniversalAxis2 (_id, result); } +}; + + +class dHinge2Joint : public dJoint { + // intentionally undefined, don't use these + dHinge2Joint (const dHinge2Joint &); + void operator = (const dHinge2Joint &); + +public: + dHinge2Joint() { } + dHinge2Joint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateHinge2 (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateHinge2 (world, group); + } + + void setAnchor (dReal x, dReal y, dReal z) + { dJointSetHinge2Anchor (_id, x, y, z); } + void setAxis1 (dReal x, dReal y, dReal z) + { dJointSetHinge2Axis1 (_id, x, y, z); } + void setAxis2 (dReal x, dReal y, dReal z) + { dJointSetHinge2Axis2 (_id, x, y, z); } + + void getAnchor (dVector3 result) const + { dJointGetHinge2Anchor (_id, result); } + void getAxis1 (dVector3 result) const + { dJointGetHinge2Axis1 (_id, result); } + void getAxis2 (dVector3 result) const + { dJointGetHinge2Axis2 (_id, result); } + + dReal getAngle1() const + { return dJointGetHinge2Angle1 (_id); } + dReal getAngle1Rate() const + { return dJointGetHinge2Angle1Rate (_id); } + dReal getAngle2Rate() const + { return dJointGetHinge2Angle2Rate (_id); } + + void setParam (int parameter, dReal value) + { dJointSetHinge2Param (_id, parameter, value); } + dReal getParam (int parameter) const + { return dJointGetHinge2Param (_id, parameter); } +}; + + +class dFixedJoint : public dJoint { + // intentionally undefined, don't use these + dFixedJoint (const dFixedJoint &); + void operator = (const dFixedJoint &); + +public: + dFixedJoint() { } + dFixedJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateFixed (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateFixed (world, group); + } + + void set() + { dJointSetFixed (_id); } +}; + + +class dContactJoint : public dJoint { + // intentionally undefined, don't use these + dContactJoint (const dContactJoint &); + void operator = (const dContactJoint &); + +public: + dContactJoint() { } + dContactJoint (dWorldID world, dJointGroupID group, dContact *contact) + { _id = dJointCreateContact (world, group, contact); } + + void create (dWorldID world, dJointGroupID group, dContact *contact) { + if (_id) dJointDestroy (_id); + _id = dJointCreateContact (world, group, contact); + } +}; + + +class dNullJoint : public dJoint { + // intentionally undefined, don't use these + dNullJoint (const dNullJoint &); + void operator = (const dNullJoint &); + +public: + dNullJoint() { } + dNullJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateNull (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateNull (world, group); + } +}; + + +class dAMotorJoint : public dJoint { + // intentionally undefined, don't use these + dAMotorJoint (const dAMotorJoint &); + void operator = (const dAMotorJoint &); + +public: + dAMotorJoint() { } + dAMotorJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateAMotor (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateAMotor (world, group); + } + + void setMode (int mode) + { dJointSetAMotorMode (_id, mode); } + int getMode() const + { return dJointGetAMotorMode (_id); } + + void setNumAxes (int num) + { dJointSetAMotorNumAxes (_id, num); } + int getNumAxes() const + { return dJointGetAMotorNumAxes (_id); } + + void setAxis (int anum, int rel, dReal x, dReal y, dReal z) + { dJointSetAMotorAxis (_id, anum, rel, x, y, z); } + void getAxis (int anum, dVector3 result) const + { dJointGetAMotorAxis (_id, anum, result); } + int getAxisRel (int anum) const + { return dJointGetAMotorAxisRel (_id, anum); } + + void setAngle (int anum, dReal angle) + { dJointSetAMotorAngle (_id, anum, angle); } + dReal getAngle (int anum) const + { return dJointGetAMotorAngle (_id, anum); } + dReal getAngleRate (int anum) + { return dJointGetAMotorAngleRate (_id,anum); } + + void setParam (int parameter, dReal value) + { dJointSetAMotorParam (_id, parameter, value); } + dReal getParam (int parameter) const + { return dJointGetAMotorParam (_id, parameter); } +}; + + +class dGeom { + // intentionally undefined, don't use these + dGeom (dGeom &); + void operator= (dGeom &); + +protected: + dGeomID _id; + +public: + dGeom() + { _id = 0; } + ~dGeom() + { if (_id) dGeomDestroy (_id); } + + dGeomID id() const + { return _id; } + operator dGeomID() const + { return _id; } + + void destroy() { + if (_id) dGeomDestroy (_id); + _id = 0; + } + + int getClass() const + { return dGeomGetClass (_id); } + + void setData (void *data) + { dGeomSetData (_id,data); } + void *getData() const + { return dGeomGetData (_id); } + + void setBody (dBodyID b) + { dGeomSetBody (_id,b); } + dBodyID getBody() const + { return dGeomGetBody (_id); } + + void setPosition (dReal x, dReal y, dReal z) + { dGeomSetPosition (_id,x,y,z); } + const dReal * getPosition() const + { return dGeomGetPosition (_id); } + + void setRotation (const dMatrix3 R) + { dGeomSetRotation (_id,R); } + const dReal * getRotation() const + { return dGeomGetRotation (_id); } + + void getAABB (dReal aabb[6]) const + { dGeomGetAABB (_id, aabb); } + const dReal *getSpaceAABB() const + { return dGeomGetSpaceAABB (_id); } +}; + + +class dSpace { + // intentionally undefined, don't use these + dSpace (dSpace &); + void operator= (dSpace &); + +protected: + dSpaceID _id; + + // the default constructor is protected so that you + // can't instance this class. you must instance one + // of its subclasses instead. + dSpace () { _id = 0; } + +public: + ~dSpace() + { dSpaceDestroy (_id); } + + dSpaceID id() const + { return _id; } + operator dSpaceID() const + { return _id; } + + void add (dGeomID x) + { dSpaceAdd (_id, x); } + void remove (dGeomID x) + { dSpaceRemove (_id, x); } + int query (dGeomID x) + { return dSpaceQuery (_id,x); } + + void collide (void *data, dNearCallback *callback) + { dSpaceCollide (_id,data,callback); } +}; + + +class dSimpleSpace : public dSpace { + // intentionally undefined, don't use these + dSimpleSpace (dSimpleSpace &); + void operator= (dSimpleSpace &); + +public: + dSimpleSpace () + { _id = dSimpleSpaceCreate(); } +}; + + +class dHashSpace : public dSpace { + // intentionally undefined, don't use these + dHashSpace (dHashSpace &); + void operator= (dHashSpace &); + +public: + dHashSpace () + { _id = dHashSpaceCreate(); } + void setLevels (int minlevel, int maxlevel) + { dHashSpaceSetLevels (_id,minlevel,maxlevel); } +}; + + +class dSphere : public dGeom { + // intentionally undefined, don't use these + dSphere (dSphere &); + void operator= (dSphere &); + +public: + dSphere () { } + dSphere (dSpaceID space, dReal radius) + { _id = dCreateSphere (space, radius); } + + void create (dSpaceID space, dReal radius) { + if (_id) dGeomDestroy (_id); + _id = dCreateSphere (space, radius); + } + + void setRadius (dReal radius) + { dGeomSphereSetRadius (_id, radius); } + dReal getRadius() const + { return dGeomSphereGetRadius (_id); } +}; + + +class dBox : public dGeom { + // intentionally undefined, don't use these + dBox (dBox &); + void operator= (dBox &); + +public: + dBox () { } + dBox (dSpaceID space, dReal lx, dReal ly, dReal lz) + { _id = dCreateBox (space,lx,ly,lz); } + + void create (dSpaceID space, dReal lx, dReal ly, dReal lz) { + if (_id) dGeomDestroy (_id); + _id = dCreateBox (space,lx,ly,lz); + } + + void setLengths (dReal lx, dReal ly, dReal lz) + { dGeomBoxSetLengths (_id, lx, ly, lz); } + void getLengths (dVector3 result) const + { dGeomBoxGetLengths (_id,result); } +}; + + +class dPlane : public dGeom { + // intentionally undefined, don't use these + dPlane (dPlane &); + void operator= (dPlane &); + +public: + dPlane() { } + dPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d) + { _id = dCreatePlane (space,a,b,c,d); } + + void create (dSpaceID space, dReal a, dReal b, dReal c, dReal d) { + if (_id) dGeomDestroy (_id); + _id = dCreatePlane (space,a,b,c,d); + } + + void setParams (dReal a, dReal b, dReal c, dReal d) + { dGeomPlaneSetParams (_id, a, b, c, d); } + void getParams (dVector4 result) const + { dGeomPlaneGetParams (_id,result); } +}; + + +class dCCylinder : public dGeom { + // intentionally undefined, don't use these + dCCylinder (dCCylinder &); + void operator= (dCCylinder &); + +public: + dCCylinder() { } + dCCylinder (dSpaceID space, dReal radius, dReal length) + { _id = dCreateCCylinder (space,radius,length); } + + void create (dSpaceID space, dReal radius, dReal length) { + if (_id) dGeomDestroy (_id); + _id = dCreateCCylinder (space,radius,length); + } + + void setParams (dReal radius, dReal length) + { dGeomCCylinderSetParams (_id, radius, length); } + void getParams (dReal *radius, dReal *length) const + { dGeomCCylinderGetParams (_id,radius,length); } +}; + + +class dGeomGroup : public dGeom { + // intentionally undefined, don't use these + dGeomGroup (dGeomGroup &); + void operator= (dGeomGroup &); + +public: + dGeomGroup() { } + dGeomGroup (dSpaceID space) + { _id = dCreateGeomGroup (space); } + + void create (dSpaceID space=0) { + if (_id) dGeomDestroy (_id); + _id = dCreateGeomGroup (space); + } + + void add (dGeomID x) + { dGeomGroupAdd (_id, x); } + void remove (dGeomID x) + { dGeomGroupRemove (_id, x); } + + int getNumGeoms() const + { return dGeomGroupGetNumGeoms (_id); } + dGeomID getGeom (int i) const + { return dGeomGroupGetGeom (_id, i); } +}; + + +class dGeomTransform : public dGeom { + // intentionally undefined, don't use these + dGeomTransform (dGeomTransform &); + void operator= (dGeomTransform &); + +public: + dGeomTransform() { } + dGeomTransform (dSpaceID space) + { _id = dCreateGeomTransform (space); } + + void create (dSpaceID space=0) { + if (_id) dGeomDestroy (_id); + _id = dCreateGeomTransform (space); + } + + void setGeom (dGeomID geom) + { dGeomTransformSetGeom (_id, geom); } + dGeomID getGeom() const + { return dGeomTransformGetGeom (_id); } + + void setCleanup (int mode) + { dGeomTransformSetCleanup (_id,mode); } + int getCleanup (dGeomID g) + { return dGeomTransformGetCleanup (_id); } + + void setInfo (int mode) + { dGeomTransformSetInfo (_id,mode); } + int getInfo() + { return dGeomTransformGetInfo (_id); } +}; + +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/odecpp_old.h b/extern/ode/dist/include/ode/odecpp_old.h new file mode 100644 index 00000000000..b7b55232f89 --- /dev/null +++ b/extern/ode/dist/include/ode/odecpp_old.h @@ -0,0 +1,317 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* this is the old C++ interface, the new C++ interface is not quite + * compatible with this. but this file is kept around in case you were + * using the old interface. + */ + +#ifndef _ODE_ODECPP_H_ +#define _ODE_ODECPP_H_ +#ifdef __cplusplus + +#include + + +class dWorld { + dWorldID _id; + + dWorld (dWorld &) { dDebug (0,"bad"); } + void operator= (dWorld &) { dDebug (0,"bad"); } + +public: + dWorld() + { _id = dWorldCreate(); } + ~dWorld() + { dWorldDestroy (_id); } + dWorldID id() + { return _id; } + + void setGravity (dReal x, dReal y, dReal z) + { dWorldSetGravity (_id,x,y,z); } + void getGravity (dVector3 g) + { dWorldGetGravity (_id,g); } + void step (dReal stepsize) + { dWorldStep (_id,stepsize); } +}; + + +class dBody { + dBodyID _id; + + dBody (dBody &) { dDebug (0,"bad"); } + void operator= (dBody &) { dDebug (0,"bad"); } + +public: + dBody() + { _id = 0; } + dBody (dWorld &world) + { _id = dBodyCreate (world.id()); } + ~dBody() + { dBodyDestroy (_id); } + void create (dWorld &world) + { if (_id) dBodyDestroy (_id); _id = dBodyCreate (world.id()); } + dBodyID id() + { return _id; } + + void setData (void *data) + { dBodySetData (_id,data); } + void *getData() + { return dBodyGetData (_id); } + + void setPosition (dReal x, dReal y, dReal z) + { dBodySetPosition (_id,x,y,z); } + void setRotation (const dMatrix3 R) + { dBodySetRotation (_id,R); } + void setQuaternion (const dQuaternion q) + { dBodySetQuaternion (_id,q); } + void setLinearVel (dReal x, dReal y, dReal z) + { dBodySetLinearVel (_id,x,y,z); } + void setAngularVel (dReal x, dReal y, dReal z) + { dBodySetAngularVel (_id,x,y,z); } + + const dReal * getPosition() + { return dBodyGetPosition (_id); } + const dReal * getRotation() + { return dBodyGetRotation (_id); } + const dReal * getQuaternion() + { return dBodyGetQuaternion (_id); } + const dReal * getLinearVel() + { return dBodyGetLinearVel (_id); } + const dReal * getAngularVel() + { return dBodyGetAngularVel (_id); } + + void setMass (const dMass *mass) + { dBodySetMass (_id,mass); } + void getMass (dMass *mass) + { dBodyGetMass (_id,mass); } + + void addForce (dReal fx, dReal fy, dReal fz) + { dBodyAddForce (_id, fx, fy, fz); } + void addTorque (dReal fx, dReal fy, dReal fz) + { dBodyAddTorque (_id, fx, fy, fz); } + void addRelForce (dReal fx, dReal fy, dReal fz) + { dBodyAddRelForce (_id, fx, fy, fz); } + void addRelTorque (dReal fx, dReal fy, dReal fz) + { dBodyAddRelTorque (_id, fx, fy, fz); } + void addForceAtPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddForceAtPos (_id, fx, fy, fz, px, py, pz); } + void addRelForceAtPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddRelForceAtPos (_id, fx, fy, fz, px, py, pz); } + void addRelForceAtRelPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddRelForceAtRelPos (_id, fx, fy, fz, px, py, pz); } + + void getRelPointPos (dReal px, dReal py, dReal pz, dVector3 result) + { dBodyGetRelPointPos (_id, px, py, pz, result); } + void getRelPointVel (dReal px, dReal py, dReal pz, dVector3 result) + { dBodyGetRelPointVel (_id, px, py, pz, result); } + + int isConnectedTo (const dBody &b) + { return dAreConnected (_id,b._id); } +}; + + +class dJointGroup { + dJointGroupID _id; + + dJointGroup (dJointGroup &) { dDebug (0,"bad"); } + void operator= (dJointGroup &) { dDebug (0,"bad"); } + +public: + dJointGroup() + { _id = 0; } + dJointGroup (int max_size) + { _id = dJointGroupCreate (max_size); } + ~dJointGroup() + { dJointGroupDestroy (_id); } + void create (int max_size) + { if (_id) dJointGroupDestroy (_id); _id = dJointGroupCreate (max_size); } + dJointGroupID id() + { return _id; } + + void empty() + { dJointGroupEmpty (_id); } +}; + + +class dJoint { + dJointID _id; + + dJoint (dJoint &) { dDebug (0,"bad"); } + void operator= (dJoint &) { dDebug (0,"bad"); } + +public: + dJoint() + { _id = 0; } + ~dJoint() + { dJointDestroy (_id); } + dJointID id() + { return _id; } + + void createBall (dWorld &world, dJointGroup *group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateBall (world.id(), group ? group->id() : 0); + } + void createHinge (dWorld &world, dJointGroup *group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateHinge (world.id(), group ? group->id() : 0); + } + void createSlider (dWorld &world, dJointGroup *group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateSlider (world.id(), group ? group->id() : 0); + } + void createContact (dWorld &world, dJointGroup *group, dContact *contact) { + if (_id) dJointDestroy (_id); + _id = dJointCreateContact (world.id(), group ? group->id() : 0, contact); + } + + void attach (dBody &body1, dBody &body2) + { dJointAttach (_id, body1.id(), body2.id()); } + + void setBallAnchor (dReal x, dReal y, dReal z) + { dJointSetBallAnchor (_id, x, y, z); } + void setHingeAnchor (dReal x, dReal y, dReal z) + { dJointSetHingeAnchor (_id, x, y, z); } + + void setHingeAxis (dReal x, dReal y, dReal z) + { dJointSetHingeAxis (_id, x, y, z); } + void setSliderAxis (dReal x, dReal y, dReal z) + { dJointSetSliderAxis (_id, x, y, z); } + + void getBallAnchor (dVector3 result) + { dJointGetBallAnchor (_id, result); } + void getHingeAnchor (dVector3 result) + { dJointGetHingeAnchor (_id, result); } + + void getHingeAxis (dVector3 result) + { dJointGetHingeAxis (_id, result); } + void getSliderAxis (dVector3 result) + { dJointGetSliderAxis (_id, result); } +}; + + +class dSpace { + dSpaceID _id; + + dSpace (dSpace &) { dDebug (0,"bad"); } + void operator= (dSpace &) { dDebug (0,"bad"); } + +public: + dSpace () + { _id = dHashSpaceCreate(); } + ~dSpace() + { dSpaceDestroy (_id); } + dSpaceID id() + { return _id; } + void collide (void *data, dNearCallback *callback) + { dSpaceCollide (_id,data,callback); } +}; + + +class dGeom { + dGeomID _id; + + dGeom (dGeom &) { dDebug (0,"bad"); } + void operator= (dGeom &) { dDebug (0,"bad"); } + +public: + dGeom() + { _id = 0; } + ~dGeom() + { dGeomDestroy (_id); } + dGeomID id() + { return _id; } + + void createSphere (dSpace &space, dReal radius) { + if (_id) dGeomDestroy (_id); + _id = dCreateSphere (space.id(),radius); + } + + void createBox (dSpace &space, dReal lx, dReal ly, dReal lz) { + if (_id) dGeomDestroy (_id); + _id = dCreateBox (space.id(),lx,ly,lz); + } + + void createPlane (dSpace &space, dReal a, dReal b, dReal c, dReal d) { + if (_id) dGeomDestroy (_id); + _id = dCreatePlane (space.id(),a,b,c,d); + } + + void createCCylinder (dSpace &space, dReal radius, dReal length) { + if (_id) dGeomDestroy (_id); + _id = dCreateCCylinder (space.id(),radius,length); + } + + void destroy() { + if (_id) dGeomDestroy (_id); + _id = 0; + } + + int getClass() + { return dGeomGetClass (_id); } + + dReal sphereGetRadius() + { return dGeomSphereGetRadius (_id); } + + void boxGetLengths (dVector3 result) + { dGeomBoxGetLengths (_id,result); } + + void planeGetParams (dVector4 result) + { dGeomPlaneGetParams (_id,result); } + + void CCylinderGetParams (dReal *radius, dReal *length) + { dGeomCCylinderGetParams (_id,radius,length); } + + void setData (void *data) + { dGeomSetData (_id,data); } + + void *getData() + { return dGeomGetData (_id); } + + void setBody (dBody &b) + { dGeomSetBody (_id,b.id()); } + void setBody (dBodyID b) + { dGeomSetBody (_id,b); } + + dBodyID getBody() + { return dGeomGetBody (_id); } + + void setPosition (dReal x, dReal y, dReal z) + { dGeomSetPosition (_id,x,y,z); } + + void setRotation (const dMatrix3 R) + { dGeomSetRotation (_id,R); } + + const dReal * getPosition() + { return dGeomGetPosition (_id); } + + const dReal * getRotation() + { return dGeomGetRotation (_id); } +}; + +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/odemath.h b/extern/ode/dist/include/ode/odemath.h new file mode 100644 index 00000000000..5f41a27b5a1 --- /dev/null +++ b/extern/ode/dist/include/ode/odemath.h @@ -0,0 +1,217 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_ODEMATH_H_ +#define _ODE_ODEMATH_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* 3-way dot product. dDOTpq means that elements of `a' and `b' are spaced + * p and q indexes apart respectively. dDOT() means dDOT11. + */ + +#ifdef __cplusplus +inline dReal dDOT (const dReal *a, const dReal *b) + { return ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2]); } +inline dReal dDOT14(const dReal *a, const dReal *b) + { return ((a)[0]*(b)[0] + (a)[1]*(b)[4] + (a)[2]*(b)[8]); } +inline dReal dDOT41(const dReal *a, const dReal *b) + { return ((a)[0]*(b)[0] + (a)[4]*(b)[1] + (a)[8]*(b)[2]); } +inline dReal dDOT44(const dReal *a, const dReal *b) + { return ((a)[0]*(b)[0] + (a)[4]*(b)[4] + (a)[8]*(b)[8]); } +#else +#define dDOT(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2]) +#define dDOT14(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[4] + (a)[2]*(b)[8]) +#define dDOT41(a,b) ((a)[0]*(b)[0] + (a)[4]*(b)[1] + (a)[8]*(b)[2]) +#define dDOT44(a,b) ((a)[0]*(b)[0] + (a)[4]*(b)[4] + (a)[8]*(b)[8]) +#endif + + +/* cross product, set a = b x c. dCROSSpqr means that elements of `a', `b' + * and `c' are spaced p, q and r indexes apart respectively. + * dCROSS() means dCROSS111. `op' is normally `=', but you can set it to + * +=, -= etc to get other effects. + */ + +#define dCROSS(a,op,b,c) \ + (a)[0] op ((b)[1]*(c)[2] - (b)[2]*(c)[1]); \ + (a)[1] op ((b)[2]*(c)[0] - (b)[0]*(c)[2]); \ + (a)[2] op ((b)[0]*(c)[1] - (b)[1]*(c)[0]); +#define dCROSSpqr(a,op,b,c,p,q,r) \ + (a)[ 0] op ((b)[ q]*(c)[2*r] - (b)[2*q]*(c)[ r]); \ + (a)[ p] op ((b)[2*q]*(c)[ 0] - (b)[ 0]*(c)[2*r]); \ + (a)[2*p] op ((b)[ 0]*(c)[ r] - (b)[ q]*(c)[ 0]); +#define dCROSS114(a,op,b,c) dCROSSpqr(a,op,b,c,1,1,4) +#define dCROSS141(a,op,b,c) dCROSSpqr(a,op,b,c,1,4,1) +#define dCROSS144(a,op,b,c) dCROSSpqr(a,op,b,c,1,4,4) +#define dCROSS411(a,op,b,c) dCROSSpqr(a,op,b,c,4,1,1) +#define dCROSS414(a,op,b,c) dCROSSpqr(a,op,b,c,4,1,4) +#define dCROSS441(a,op,b,c) dCROSSpqr(a,op,b,c,4,4,1) +#define dCROSS444(a,op,b,c) dCROSSpqr(a,op,b,c,4,4,4) + + +/* set a 3x3 submatrix of A to a matrix such that submatrix(A)*b = a x b. + * A is stored by rows, and has `skip' elements per row. the matrix is + * assumed to be already zero, so this does not write zero elements! + * if (plus,minus) is (+,-) then a positive version will be written. + * if (plus,minus) is (-,+) then a negative version will be written. + */ + +#define dCROSSMAT(A,a,skip,plus,minus) \ + (A)[1] = minus (a)[2]; \ + (A)[2] = plus (a)[1]; \ + (A)[(skip)+0] = plus (a)[2]; \ + (A)[(skip)+2] = minus (a)[0]; \ + (A)[2*(skip)+0] = minus (a)[1]; \ + (A)[2*(skip)+1] = plus (a)[0]; + + +/* compute the distance between two 3-vectors (oops, C++!) */ +#ifdef __cplusplus +inline dReal dDISTANCE (const dVector3 a, const dVector3 b) + { return dSqrt( (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + + (a[2]-b[2])*(a[2]-b[2]) ); } +#else +#define dDISTANCE(a,b) \ + (dSqrt( ((a)[0]-(b)[0])*((a)[0]-(b)[0]) + ((a)[1]-(b)[1])*((a)[1]-(b)[1]) + \ + ((a)[2]-(b)[2])*((a)[2]-(b)[2]) )) +#endif + + +/* normalize 3x1 and 4x1 vectors (i.e. scale them to unit length) */ +void dNormalize3 (dVector3 a); +void dNormalize4 (dVector4 a); + + +/* given a unit length "normal" vector n, generate vectors p and q vectors + * that are an orthonormal basis for the plane space perpendicular to n. + * i.e. this makes p,q such that n,p,q are all perpendicular to each other. + * q will equal n x p. if n is not unit length then p will be unit length but + * q wont be. + */ + +void dPlaneSpace (const dVector3 n, dVector3 p, dVector3 q); + + +/* special case matrix multipication, with operator selection */ + +#define dMULTIPLYOP0_331(A,op,B,C) \ + (A)[0] op dDOT((B),(C)); \ + (A)[1] op dDOT((B+4),(C)); \ + (A)[2] op dDOT((B+8),(C)); +#define dMULTIPLYOP1_331(A,op,B,C) \ + (A)[0] op dDOT41((B),(C)); \ + (A)[1] op dDOT41((B+1),(C)); \ + (A)[2] op dDOT41((B+2),(C)); +#define dMULTIPLYOP0_133(A,op,B,C) \ + (A)[0] op dDOT14((B),(C)); \ + (A)[1] op dDOT14((B),(C+1)); \ + (A)[2] op dDOT14((B),(C+2)); +#define dMULTIPLYOP0_333(A,op,B,C) \ + (A)[0] op dDOT14((B),(C)); \ + (A)[1] op dDOT14((B),(C+1)); \ + (A)[2] op dDOT14((B),(C+2)); \ + (A)[4] op dDOT14((B+4),(C)); \ + (A)[5] op dDOT14((B+4),(C+1)); \ + (A)[6] op dDOT14((B+4),(C+2)); \ + (A)[8] op dDOT14((B+8),(C)); \ + (A)[9] op dDOT14((B+8),(C+1)); \ + (A)[10] op dDOT14((B+8),(C+2)); +#define dMULTIPLYOP1_333(A,op,B,C) \ + (A)[0] op dDOT44((B),(C)); \ + (A)[1] op dDOT44((B),(C+1)); \ + (A)[2] op dDOT44((B),(C+2)); \ + (A)[4] op dDOT44((B+1),(C)); \ + (A)[5] op dDOT44((B+1),(C+1)); \ + (A)[6] op dDOT44((B+1),(C+2)); \ + (A)[8] op dDOT44((B+2),(C)); \ + (A)[9] op dDOT44((B+2),(C+1)); \ + (A)[10] op dDOT44((B+2),(C+2)); +#define dMULTIPLYOP2_333(A,op,B,C) \ + (A)[0] op dDOT((B),(C)); \ + (A)[1] op dDOT((B),(C+4)); \ + (A)[2] op dDOT((B),(C+8)); \ + (A)[4] op dDOT((B+4),(C)); \ + (A)[5] op dDOT((B+4),(C+4)); \ + (A)[6] op dDOT((B+4),(C+8)); \ + (A)[8] op dDOT((B+8),(C)); \ + (A)[9] op dDOT((B+8),(C+4)); \ + (A)[10] op dDOT((B+8),(C+8)); + +#ifdef __cplusplus + +inline void dMULTIPLY0_331(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP0_331(A,=,B,C) } +inline void dMULTIPLY1_331(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP1_331(A,=,B,C) } +inline void dMULTIPLY0_133(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP0_133(A,=,B,C) } +inline void dMULTIPLY0_333(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP0_333(A,=,B,C) } +inline void dMULTIPLY1_333(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP1_333(A,=,B,C) } +inline void dMULTIPLY2_333(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP2_333(A,=,B,C) } + +inline void dMULTIPLYADD0_331(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP0_331(A,+=,B,C) } +inline void dMULTIPLYADD1_331(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP1_331(A,+=,B,C) } +inline void dMULTIPLYADD0_133(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP0_133(A,+=,B,C) } +inline void dMULTIPLYADD0_333(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP0_333(A,+=,B,C) } +inline void dMULTIPLYADD1_333(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP1_333(A,+=,B,C) } +inline void dMULTIPLYADD2_333(dReal *A, const dReal *B, const dReal *C) + { dMULTIPLYOP2_333(A,+=,B,C) } + +#else + +#define dMULTIPLY0_331(A,B,C) dMULTIPLYOP0_331(A,=,B,C) +#define dMULTIPLY1_331(A,B,C) dMULTIPLYOP1_331(A,=,B,C) +#define dMULTIPLY0_133(A,B,C) dMULTIPLYOP0_133(A,=,B,C) +#define dMULTIPLY0_333(A,B,C) dMULTIPLYOP0_333(A,=,B,C) +#define dMULTIPLY1_333(A,B,C) dMULTIPLYOP1_333(A,=,B,C) +#define dMULTIPLY2_333(A,B,C) dMULTIPLYOP2_333(A,=,B,C) + +#define dMULTIPLYADD0_331(A,B,C) dMULTIPLYOP0_331(A,+=,B,C) +#define dMULTIPLYADD1_331(A,B,C) dMULTIPLYOP1_331(A,+=,B,C) +#define dMULTIPLYADD0_133(A,B,C) dMULTIPLYOP0_133(A,+=,B,C) +#define dMULTIPLYADD0_333(A,B,C) dMULTIPLYOP0_333(A,+=,B,C) +#define dMULTIPLYADD1_333(A,B,C) dMULTIPLYOP1_333(A,+=,B,C) +#define dMULTIPLYADD2_333(A,B,C) dMULTIPLYOP2_333(A,+=,B,C) + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/rotation.h b/extern/ode/dist/include/ode/rotation.h new file mode 100644 index 00000000000..19204c651f3 --- /dev/null +++ b/extern/ode/dist/include/ode/rotation.h @@ -0,0 +1,65 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_ROTATION_H_ +#define _ODE_ROTATION_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +void dRSetIdentity (dMatrix3 R); + +void dRFromAxisAndAngle (dMatrix3 R, dReal ax, dReal ay, dReal az, + dReal angle); + +void dRFromEulerAngles (dMatrix3 R, dReal phi, dReal theta, dReal psi); + +void dRFrom2Axes (dMatrix3 R, dReal ax, dReal ay, dReal az, + dReal bx, dReal by, dReal bz); + +void dQSetIdentity (dQuaternion q); + +void dQFromAxisAndAngle (dQuaternion q, dReal ax, dReal ay, dReal az, + dReal angle); + +void dQMultiply0 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); +void dQMultiply1 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); +void dQMultiply2 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); +void dQMultiply3 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); + +void dQtoR (const dQuaternion q, dMatrix3 R); + +void dRtoQ (const dMatrix3 R, dQuaternion q); + +void dWtoDQ (const dVector3 w, const dQuaternion q, dVector4 dq); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/space.h b/extern/ode/dist/include/ode/space.h new file mode 100644 index 00000000000..c540cd69d6e --- /dev/null +++ b/extern/ode/dist/include/ode/space.h @@ -0,0 +1,78 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_SPACE_H_ +#define _ODE_SPACE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct dContactGeom; + +typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); + + +/* extra information the space needs in every geometry object */ + +typedef struct dGeomSpaceData { + dGeomID next; +} dGeomSpaceData; + + +dSpaceID dSimpleSpaceCreate(); +dSpaceID dHashSpaceCreate(); + +void dSpaceDestroy (dSpaceID); +void dSpaceAdd (dSpaceID, dGeomID); +void dSpaceRemove (dSpaceID, dGeomID); +void dSpaceCollide (dSpaceID space, void *data, dNearCallback *callback); +int dSpaceQuery (dSpaceID, dGeomID); + +void dHashSpaceSetLevels (dSpaceID space, int minlevel, int maxlevel); + + +/* @@@ NOT FLEXIBLE ENOUGH + * + * generate contacts for those objects in the space that touch each other. + * an array of contacts is created on the alternative stack using + * StackAlloc(), and a pointer to the array is returned. the size of the + * array is returned by the function. + */ +/* int dSpaceCollide (dSpaceID space, dContactGeom **contact_array); */ + + +/* HMMMMM... i dont think so. + * tell the space that an object has moved, so its representation in the + * space should be changed. + */ +/* void dSpaceObjectMoved (dSpaceID, dGeomID); */ + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/include/ode/timer.h b/extern/ode/dist/include/ode/timer.h new file mode 100644 index 00000000000..fe2574feb3c --- /dev/null +++ b/extern/ode/dist/include/ode/timer.h @@ -0,0 +1,77 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_TIMER_H_ +#define _ODE_TIMER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* stop watch objects */ + +typedef struct dStopwatch { + double time; /* total clock count */ + unsigned long cc[2]; /* clock count since last `start' */ +} dStopwatch; + +void dStopwatchReset (dStopwatch *); +void dStopwatchStart (dStopwatch *); +void dStopwatchStop (dStopwatch *); +double dStopwatchTime (dStopwatch *); /* returns total time in secs */ + + +/* code timers */ + +void dTimerStart (const char *description); /* pass a static string here */ +void dTimerNow (const char *description); /* pass a static string here */ +void dTimerEnd(); + +/* print out a timer report. if `average' is nonzero, print out the average + * time for each slot (this is only meaningful if the same start-now-end + * calls are being made repeatedly. + */ +void dTimerReport (FILE *fout, int average); + + +/* resolution */ + +/* returns the timer ticks per second implied by the timing hardware or API. + * the actual timer resolution may not be this great. + */ +double dTimerTicksPerSecond(); + +/* returns an estimate of the actual timer resolution, in seconds. this may + * be greater than 1/ticks_per_second. + */ +double dTimerResolution(); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/extern/ode/dist/ode/README b/extern/ode/dist/ode/README new file mode 100644 index 00000000000..dd4596f9935 --- /dev/null +++ b/extern/ode/dist/ode/README @@ -0,0 +1,158 @@ +Dynamics Library. +================= + +CONVENTIONS +----------- + +matrix storage +-------------- + +matrix operations like factorization are expensive, so we must store the data +in a way that is most useful to the matrix code. we want the ability to update +the dynamics library without recompiling applications, e.g. so users can take +advantage of new floating point hardware. so we must settle on a single +format. because of the prevalence of 4-way SIMD, the format is this: store +the matrix by rows or columns, and each column is rounded up to a multiple of +4 elements. the extra "padding" elements at the end of each row/column are set +to 0. this is called the "standard format". to indicate if the data is stored +by rows or columns, we will say "standard row format" or "standard column +format". hopefully this decision will remain good in the future, as more and +more processors have 4-way SIMD, and 3D graphics always needs fast 4x4 +matrices. + +exception: matrices that have only one column or row (vectors), are always +stored as consecutive elements in standard row format, i.e. there is no +interior padding, only padding at the end. + +thus: all 3x1 floating point vectors are stored as 4x1 vectors: (x,x,x,0). +also: all 6x1 spatial velocities and accelerations are split into 3x1 position + and angular components, which are stored as contiguous 4x1 vectors. + +ALL matrices are stored by in standard row format. + + +arguments +--------- + +3x1 vector arguments to set() functions are supplied as x,y,z. +3x1 vector result arguments to get() function are pointers to arrays. +larger vectors are always supplied and returned as pointers. +all coordinates are in the global frame except where otherwise specified. +output-only arguments are usually supplied at the end. + + +memory allocation +----------------- + +with many C/C++ libraries memory allocation is a difficult problem to solve. +who allocates the memory? who frees it? must objects go on the heap or can +they go on the stack or in static storage? to provide the maximum flexibility, +the dynamics and collision libraries do not do their own memory allocation. +you must pass in pointers to externally allocated chunks of the right sizes. +the body, joint and colllision object structures are all exported, so you +can make instances of those structure and pass pointers to them. + +there are helper functions which allocate objects out of areans, in case you +need loots of dynamic creation and deletion. + +BUT!!! this ties us down to the body/joint/collision representation. + +a better approach is to supply custom memory allocation functions +(e.g. dlAlloc() etc). + + +C versus C++ ... ? +------------------ + +everything should be C linkable, and there should be C header files for +everything. but we want to develop in C++. so do this: + * all comments are "//". automatically convert to /**/ for distribution. + * structures derived from other structures --> automatically convert? + + +WORLDS +------ + +might want better terminology here. + +the dynamics world (DWorld) is a list of systems. each system corresponds to +one or more bodies, or perhaps some other kinds of physical object. +each system corresponds to one or more objects in the collision world +(there does not have to be a one-to-one correspondence between bodies and +collision objects). + +systems are simulated separately, perhaps using completely different +techniques. we must do something special when systems collide. +systems collide when collision objects belonging to system A touch +collision objects belonging to system B. + +for each collision point, the system must provide matrix equation data +that is used to compute collision forces. once those forces are computed, +the system must incorporate the forces into its timestep. +PROBLEM: what if we intertwine the LCP problems of the two systems - then +this simple approach wont work. + +the dynamics world contains two kinds of objects: bodies and joints. +joints connect two bodies together. + +the world contains one of more partitions. each partition is a collection of +bodies and joints such that each body is attached (through one or more joints) +to every other body. + +Joints +------ + +a joint can be connected to one or two bodies. +if the joint is only connected to one body, joint.node[1].body == 0. +joint.node[0].body is always valid. + + +Linkage +------- + +this library will always be statically linked with the app, for these reasons: + * collision space is selected at compile time, it adds data to the geom + objects. + + +Optimization +------------ + +doubles must be aligned on 8 byte boundaries! + + +MinGW on Windows issues +----------------------- + +* the .rc file for drawstuff needs a different include, try winresrc.h. + +* it seems we can't have both main() and WinMain() without the entry point + defaulting to main() and having resource loading problems. this screws up + what i was trying to do in the drawstuff library. perhaps main2() ? + +* remember to compile resources to COFF format RES files. + + + +Collision +--------- + +to plug in your own collision handling, replace (some of?) these functions +with your own. collision should be a separate library that you can link in +or not. your own library can call components in this collision library, e.g. +if you want polymorphic spaces instead of a single statically called space. + +creating an object will automatically register the appropriate +class (if necessary). how can we ensure that the minimum amount of code is +linked in? e.g. only one space handler, and sphere-sphere and sphere-box and +box-box collision code (if spheres and boxes instanced). + +the user creates a collision space, and for each dynamics object that is +created a collision object is inserted into the space. the collision +object's pos and R pointers are set to the corresponding dynamics +variables. + +there should be utility functions which create the dynamics and collision +objects at the same time, e.g. dMakeSphere(). + +collision objects and dynamics objects keep pointers to each other. diff --git a/extern/ode/dist/ode/fbuild/BuildDot b/extern/ode/dist/ode/fbuild/BuildDot new file mode 100644 index 00000000000..09b49274da8 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/BuildDot @@ -0,0 +1,148 @@ +#!/usr/bin/perl +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# dot product code generator. +# +# code generation parameters, set in a parameters file: +# FNAME : name of source file to generate - a .c file will be made +# UNROLL1 : inner loop unrolling factor (1..) +# FETCH : max num of a[i]'s and b[i]'s to load ahead of muls +# LAT1 : load -> mul latency (>=1) +# LAT2 : mul -> add latency (>=1). if this is 1, use fused mul-add +# +############################################################################# + +require ("BuildUtil"); + +# get and check code generation parameters +error ("Usage: BuildDot ") if $#ARGV != 0; +do $ARGV[0]; + +if (!defined($FNAME) || !defined($UNROLL1) || !defined($FETCH) || + !defined($LAT1) || !defined($LAT2)) { + error ("code generation parameters not defined"); +} + +# check parameters +error ("bad UNROLL1") if $UNROLL1 < 1; +error ("bad FETCH") if $FETCH < 1; +error ("bad LAT1") if $LAT1 < 1; +error ("bad LAT2") if $LAT2 < 1; + +############################################################################# + +open (FOUT,">$FNAME.c") or die "can't open $FNAME.c for writing"; + +# file and function header +output (<= 0) { +END + +@load = (); # slot where a[i]'s and b[i]'s loaded +@mul = (); # slot where multiply i happened +@add = (); # slow where add i happened + +# in the future we may want to reduce the number of variables declared, +# so these arrays will be useful. +@pqused = (); # 1 if p/q[i] loaded with data, 0 once that data's used +@mused = (); # 1 if m[i] loaded with data, 0 once that data's used +@pqmap = (); # map virtual p/q variables to actual p/q variables +@mmap = (); # map virtual m variables to actual m variables + +output ("p0 = a[0]; q0 = b[0];\n"); +push (@load,0); + +$slot=0; # one slot for every load/mul/add/nop issued +for (;;) { + $startslot = $slot; + + # do next load + if (($#load - $#mul) < $FETCH && ($#load+1) < $UNROLL1) { + push (@load,$slot); + output ("p$#load = a[$#load]; q$#load = b[$#load];\n"); + $slot++; + } + # do next multiply + if ($#load > $#mul && $slot >= ($load[$#mul+1] + $LAT1) && + ($#mul+1) < $UNROLL1) { + push (@mul,$slot); + if ($LAT2 > 1) { + output ("m$#mul = p$#mul * q$#mul;\n"); + } + else { + output ("sum += p$#mul * q$#mul;\n"); + last if ($#mul+1) >= $UNROLL1; + } + $slot++; + } + # do next add + if ($LAT2 > 1) { + if ($#mul > $#add && $slot >= ($mul[$#add+1] + $LAT2)) { + push (@add,$slot); + output ("sum += m$#add;\n"); + $slot++; + last if ($#add+1) >= $UNROLL1; + } + } + + if ($slot == $startslot) { + # comment ("nop"); + $slot++; + } +} + +output ("a += $UNROLL1;\n"); +output ("b += $UNROLL1;\n"); +output ("n -= $UNROLL1;\n"); +output ("}\n"); + +output (< 0) { +sum += (*a) * (*b); +a++; +b++; +n--; +} +return sum; +} +END diff --git a/extern/ode/dist/ode/fbuild/BuildLDLT b/extern/ode/dist/ode/fbuild/BuildLDLT new file mode 100644 index 00000000000..fd74faf18df --- /dev/null +++ b/extern/ode/dist/ode/fbuild/BuildLDLT @@ -0,0 +1,654 @@ +#!/usr/bin/perl +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# +# triangular matrix solver and factorizer code generator. +# +# SOLVER +# ------ +# +# if L is an n x n lower triangular matrix (with ones on the diagonal), the +# solver solves L*X=B where X and B are n x m matrices. this is the core +# step in L*D*L' factorization. the algorithm is (in matlab): +# +# for i=1:n +# for j=1:m +# X(i,j) = B(i,j) - L(i,1:i-1)*X(1:i-1,j); +# end +# end +# +# note that the ordering of the (i,j) loop is somewhat arbitrary. the only +# prerequisite to calculating element (i,j) of X is that all X(1:i-1,j) have +# have already been calcuated. this gives us some flexibility. +# +# the code generated below calculates X in N1 x N1 blocks. to speed up the +# innermost dot product loop, the outer product trick is used. for instance, +# to calculate the value of the 2x2 matrix ABCD below we first iterate over +# the vectors (a,b,c,d) and (e,f,g,h), computing ABCD = a*e+b*f+c*g+d*h. +# then A and B contain the dot product values needed in the algorithm, and +# C and D have almost all of it. the outer product trick reduces the number +# of memory loads required. in this example 16 loads are required, but if +# the simple dot product in the above algorithm is used then 32 loads are +# required. increasing N1 decreases the total number of loads, but only as long +# as we have enough temporary registers to keep the matrix blocks and vectors. +# +# L * X = B +# +# [ . ] [ e e ] [ . . ] +# [ . . ] [ f f ] [ . . ] +# [ . . . ] [ g g ] [ . . ] +# [ . . . . ] [ h h ] [ . . ] +# [ a b c d . ] [ A B ] = [ . . ] +# [ a b c d . . ] [ C D ] [ . . ] +# [ . . . . . . . ] [ . . ] [ . . ] +# [ . . . . . . . . ] [ . . ] [ . . ] +# [ . . . . . . . . . ] [ . . ] [ . . ] +# +# note that L is stored by rows but X and B are stored by columns. +# the outer product loops are unrolled for extra speed. +# +# LDLT FACTORIZATION +# ------------------ +# +# the factorization algorithm builds L incrementally by repeatedly solving +# the following equation: +# +# [ L 0 ] [ D 0 ] [ L' l ] = [ A a ] <-- n rows +# [ l' e ] [ 0 d ] [ 0 e' ] [ a' b ] <-- m rows +# +# [ L*D*L' L*D*l ] = [ A a ] +# [ l'*D*L' l'*D*l+e*d*e' ] [ a' b ] +# +# L*D*L'=A is an existing solution, and a,b are new rows/columns to add to A. +# we compute: +# +# L * (Dl) = a +# l = inv(D) * Dl +# e*d*e' = b - l'*Dl (m*m LDLT factorization) +# +# +# L-transpose solver +# ------------------ +# +# the LT (L-transpose) solver uses the same logic as the standard L-solver, +# with a few tricks to make it work. to solve L^T*X=B we first remap: +# L to Lhat : Lhat(i,j) = L(n-j,n-i) +# X to Xhat : Xhat(i) = X(n-i) +# B to Bhat : Bhat(i) = B(n-i) +# and then solve Lhat*Xhat = Bhat. the current LT solver only supports one +# right hand side, but that's okay as it is not used in the factorizer. +# +############################################################################# +# +# code generation parameters, set in a parameters file: +# FNAME : name of source file to generate - a .c file will be made +# TYPE : 'f' to build factorizer, 's' to build solver, 't' to build the +# transpose solver. +# N1 : block size (size of outer product matrix) (1..9) +# UNROLL1 : solver inner loop unrolling factor (1..) +# UNROLL2 : factorizer inner loop unrolling factor (1..) +# MADD : if nonzero, generate code for fused multiply-add (0,1) +# FETCH : how to fetch data in the inner loop: +# 0 - load in a batch (the `normal way') +# 1 - delay inner loop loads until just before they're needed +# +############################################################################# +# +# TODO +# ---- +# +# * dFactorLDLT() is not so efficient for matrix sizes < block size, e.g. +# redundant calls, zero loads, adds etc +# +############################################################################# +# +# NOTES: +# +# * on the pentium we can prefetch like this: +# asm ("prefetcht0 %0" : : "m" (*Ai) ); +# but it doesn't seem to help much + +require ("BuildUtil"); + +# get and check code generation parameters +error ("Usage: BuildLDLT ") if $#ARGV != 0; +do $ARGV[0]; + +if (!defined($FNAME) || !defined($TYPE) || !defined($N1) || + !defined($UNROLL1) || !defined($UNROLL2) || !defined($MADD) || + !defined($FETCH)) { + error ("code generation parameters not defined"); +} + +# check parameters +error ("bad TYPE") if $TYPE ne 'f' && $TYPE ne 's' && $TYPE ne 't'; +error ("bad N1") if $N1 < 1 || $N1 > 9; +error ("bad UNROLL1") if $UNROLL1 < 1; +error ("bad UNROLL2") if $UNROLL2 < 1; +error ("bad MADD") if $MADD != 0 && $MADD != 1; +error ("bad FETCH") if $FETCH < 0 && $FETCH > 1; + +############################################################################# +# utility + +# functions to handle delayed loading of p and q values. +# bit in the the `ploaded' and `qloaded' numbers record what has been loaded, +# so we dont load it again. + +sub newLoads +{ + # bits in these numbers say what registers p and q have been loaded so far + $ploaded = 0; + $qloaded = 0; +} + +sub loadedEverything +{ + $ploaded = 0xffffffff; + $qloaded = 0xffffffff; +} + +sub loadP # (i,loadcmd) +{ + my $i = $_[0]; + my $loadcmd = $_[1]; + return if ($ploaded & (1 << $i)); + output ($loadcmd); + $ploaded |= (1 << $i); +} + +sub loadQ # (i,loadcmd) +{ + my $i = $_[0]; + my $loadcmd = $_[1]; + return if ($qloaded & (1 << $i)); + output ($loadcmd); + $qloaded |= (1 << $i); +} + +############################################################################# +# make a fast L solve function. +# this function has a restriction that the leading dimension of X and B must +# be a multiple of the block size. + +sub innerOuterProductLoop # (M,k,nrhs,increment) +{ + my $M=$_[0]; + my $k=$_[1]; + my $nrhs=$_[2]; + my $increment=$_[3]; + my ($i,$j); + newLoads; + if ($FETCH==0) { + comment ("load p and q values"); + for ($i=1; $i<=$M; $i++) { + if ($TYPE eq 't') { + output ("p$i=ell[".ofs2(-($i-1),0,'lskip')."];\n"); + output ("q$i=ex[".ofs2(-($k),$i-1,'lskip')."];\n") if $i <= $nrhs; + } + else { + output ("p$i=ell[".ofs2($k,$i-1,'lskip')."];\n"); + output ("q$i=ex[".ofs2($k,$i-1,'lskip')."];\n") if $i <= $nrhs; + } + } + loadedEverything; + } + + comment ("compute outer product and add it to the Z matrix"); + for ($i=1; $i<=$M; $i++) { + for ($j=1; $j<=$nrhs; $j++) { + if ($TYPE eq 't') { + loadP ($i,"p$i=ell[".ofs2(-($i-1),0,'lskip')."];\n"); + loadQ ($j,"q$j=ex[".ofs2(-($k),$j-1,'lskip')."];\n"); + } + else { + loadP ($i,"p$i=ell[".ofs2($k,$i-1,'lskip')."];\n"); + loadQ ($j,"q$j=ex[".ofs2($k,$j-1,'lskip')."];\n"); + } + my $var = $MADD ? "Z$i$j +=" : "m$i$j ="; + output ("$var p$i * q$j;\n"); + } + } + + if ($TYPE eq 't') { + if ($increment > 0) { + output ("ell += lskip1;\n"); + output ("ex -= $increment;\n"); + } + else { + output ("ell += lskip1;\n"); + } + } + else { + if ($increment > 0) { + comment ("advance pointers"); + output ("ell += $increment;\n"); + output ("ex += $increment;\n"); + } + } + + if ($MADD==0) { + for ($i=1; $i<=$M; $i++) { + for ($j=1; $j<=$nrhs; $j++) { + output ("Z$i$j += m$i$j;\n"); + } + } + } +} + + +sub computeRows # (nrhs,rows) +{ + my $nrhs = $_[0]; + my $rows = $_[1]; + my ($i,$j,$k); + + comment ("compute all $rows x $nrhs block of X, from rows i..i+$rows-1"); + + comment ("set the Z matrix to 0"); + for ($i=1; $i<=$rows; $i++) { + for ($j=1; $j<=$nrhs; $j++) { + output ("Z$i$j=0;\n"); + } + } + if ($TYPE eq 't') { + output ("ell = L - i;\n"); + } + else { + output ("ell = L + i*lskip1;\n"); + } + output ("ex = B;\n"); + + comment ("the inner loop that computes outer products and adds them to Z"); + output ("for (j=i-$UNROLL1; j >= 0; j -= $UNROLL1) {\n"); + for ($k=0; $k < $UNROLL1; $k++) { + innerOuterProductLoop ($rows,$k,$nrhs,($k==$UNROLL1-1) ? $UNROLL1 : 0); + } + + comment ("end of inner loop"); + output ("}\n"); + + if ($UNROLL1 > 1) { + comment ("compute left-over iterations"); + output ("j += $UNROLL1;\n"); + output ("for (; j > 0; j--) {\n"); + innerOuterProductLoop ($rows,'0',$nrhs,1); + output ("}\n"); + } + + comment ("finish computing the X(i) block"); + + for ($j=1; $j<=$nrhs; $j++) { + if ($TYPE eq 't') { + output ("Z1$j = ex[".ofs1(-($j-1),'lskip')."] - Z1$j;\n"); + output ("ex[".ofs1(-($j-1),'lskip')."] = Z1$j;\n"); + } + else { + output ("Z1$j = ex[".ofs1($j-1,'lskip')."] - Z1$j;\n"); + output ("ex[".ofs1($j-1,'lskip')."] = Z1$j;\n"); + } + } + + for ($i=2; $i<=$rows; $i++) { + for ($j=1; $j<$i; $j++) { + if ($TYPE eq 't') { + output ("p$j = ell[".ofs2(-($i-1),$j-1,'lskip')."];\n"); + } + else { + output ("p$j = ell[".ofs2($j-1,$i-1,'lskip')."];\n"); + } + } + for ($j=1; $j<=$nrhs; $j++) { + if ($TYPE eq 't') { + output ("Z$i$j = ex[".ofs2(-($i-1),$j-1,'lskip')."] - Z$i$j"); + } + else { + output ("Z$i$j = ex[".ofs2($i-1,$j-1,'lskip')."] - Z$i$j"); + } + for ($k=1; $k < $i; $k++) { + output (" - p$k*Z$k$j"); + } + output (";\n"); + if ($TYPE eq 't') { + output ("ex[".ofs2(-($i-1),$j-1,'lskip')."] = Z$i$j;\n"); + } + else { + output ("ex[".ofs2($i-1,$j-1,'lskip')."] = Z$i$j;\n"); + } + } + } +} + + +sub makeFastL1Solve # ( number-of-right-hand-sides ) +{ + my $nrhs = $_[0]; + my ($i,$j,$k); + my $funcsuffix = ($TYPE eq 'f') ? "_$nrhs" : ''; + my $staticvoid = ($TYPE eq 'f') ? 'static void' : 'void'; + + # function header + if ($TYPE eq 't') { + output (< 2) { + comment ("compute lskip values"); + for ($i=2; $i<$N1; $i++) { + output ("lskip$i = $i*lskip1;\n"); + } + } + + comment ("compute all $N1 x $nrhs blocks of X"); + if ($TYPE eq 's' or $TYPE eq 't') { + output ("for (i=0; i <= n-$N1; i+=$N1) {\n"); + } + else { + output ("for (i=0; i < n; i+=$N1) {\n"); + } + computeRows ($nrhs,$N1); + comment ("end of outer loop"); + output ("}\n"); + + if ($TYPE eq 's' or $TYPE eq 't') { + comment ("compute rows at end that are not a multiple of block size"); + output ("for (; i < n; i++) {\n"); + computeRows ($nrhs,1); + output ("}\n"); + } + + output ("}\n"); +} + +############################################################################# +# make a fast L*D*L' factorizer + +# code fragment: this factors an M x M block. if A_or_Z is 0 then it works +# on the $A matrix otherwise it works on the Z matrix. in either case it +# writes the diagonal entries into the `dee' vector. +# it is a simple implementation of the LDLT algorithm, with no tricks. + +sub getA # (i,j,A,A_or_Z) +{ + my $i = $_[0]; + my $j = $_[1]; + my $A = $_[2]; + return $_[3] ? ('Z'.($i+1).($j+1)) : ($A.'['.ofs2($j,$i,'nskip').']'); +} + +sub miniLDLT # (A,A_or_Z,M) +{ + my ($i,$j,$k); + my $A = $_[0]; + my $AZ = $_[1]; + my $M = $_[2]; + comment ("factorize $M x $M block " . ($AZ ? "Z,dee" : "$A,dee")); + comment ("factorize row 1"); + output ("dee[0] = dRecip(".getA(0,0,$A,$AZ).");\n"); + for ($i=1; $i<$M; $i++) { + comment ("factorize row ".($i+1)); + for ($j=1; $j<$i; $j++) { + output (getA($i,$j,$A,$AZ)." -= "); + for ($k=0; $k<$j; $k++) { + output (" + ") if $k > 0; + output (getA($i,$k,$A,$AZ)."*".getA($j,$k,$A,$AZ)); + } + output (";\n"); + } + output ("sum = 0;\n"); + for ($j=0; $j<$i; $j++) { + output ("q1 = ".getA($i,$j,$A,$AZ).";\n"); + output ("q2 = q1 * dee[$j];\n"); + output (getA($i,$j,$A,$AZ)." = q2;\n"); + output ("sum += q1*q2;\n"); + } + output ("dee[$i] = dRecip(".getA($i,$i,$A,$AZ)." - sum);\n"); + } + comment ("done factorizing $M x $M block"); +} + + +sub innerScaleAndOuterProductLoop # (M,k) +{ + my $M = $_[0]; + my $k = $_[1]; + my ($i,$j); + for ($i=1; $i<=$M; $i++) { + output ("p$i = ell[".ofs2($k,$i-1,'nskip')."];\n"); + } + output ("dd = dee[$k];\n"); + for ($i=1; $i<=$M; $i++) { + output ("q$i = p$i*dd;\n"); + } + for ($i=1; $i<=$M; $i++) { + output ("ell[".ofs2($k,$i-1,'nskip')."] = q$i;\n"); + } + for ($i=1; $i<=$M; $i++) { + for ($j=1; $j<=$i; $j++) { + my $var = $MADD ? "Z$i$j +=" : "m$i$j ="; + output ("$var p$i*q$j;\n"); + } + } + if ($MADD==0) { + for ($i=1; $i<=$M; $i++) { + for ($j=1; $j<=$i; $j++) { + output ("Z$i$j += m$i$j;\n"); + } + } + } +} + + +sub diagRows # (M) +{ + my $M=$_[0]; + comment ("scale the elements in a $M x i block at A(i,0), and also"); + comment ("compute Z = the outer product matrix that we'll need."); + for ($i=1; $i<=$M; $i++) { + for ($j=1; $j<=$i; $j++) { + output ("Z$i$j = 0;\n"); + } + } + output ("ell = A+i*nskip1;\n"); + output ("dee = d;\n"); + output ("for (j=i-$UNROLL2; j >= 0; j -= $UNROLL2) {\n"); + for ($i=0; $i < $UNROLL2; $i++) { + innerScaleAndOuterProductLoop ($M,$i); + } + output ("ell += $UNROLL2;\n"); + output ("dee += $UNROLL2;\n"); + output ("}\n"); + + if ($UNROLL2 > 1) { + comment ("compute left-over iterations"); + output ("j += $UNROLL2;\n"); + output ("for (; j > 0; j--) {\n"); + innerScaleAndOuterProductLoop ($M,0); + output ("ell++;\n"); + output ("dee++;\n"); + output ("}\n"); + } +} + + +sub diagBlock # (M) +{ + my $M = $_[0]; + comment ("solve for diagonal $M x $M block at A(i,i)"); + for ($i=1; $i<=$M; $i++) { + for ($j=1; $j<=$i; $j++) { + output ("Z$i$j = ell[".ofs2($j-1,$i-1,'nskip')."] - Z$i$j;\n"); + } + } + output ("dee = d + i;\n"); + miniLDLT ('',1,$M); + for ($i=2; $i<=$M; $i++) { + for ($j=1; $j<$i; $j++) { + output ("ell[".ofs2($j-1,$i-1,'nskip')."] = Z$i$j;\n"); + } + } +} + + +sub makeFastLDLT +{ + my ($i,$j,$k); + + # function header + output (<$FNAME.c") or die "can't open $FNAME.c for writing"; + +# file and function header +output (< mul latency (>=1) +# LAT2 : mul -> add latency (>=1). if this is 1, use fused mul-add +# +############################################################################# + +require ("BuildUtil"); + +# get and check code generation parameters +error ("Usage: BuildMultidot ") if $#ARGV != 0; +do $ARGV[0]; + +if (!defined($FNAME) || !defined($N1) || !defined($UNROLL1) || + !defined($FETCH) || !defined($LAT1) || !defined($LAT2)) { + error ("code generation parameters not defined"); +} + +# check parameters +error ("bad N1") if $N1 < 2; +error ("bad UNROLL1") if $UNROLL1 < 1; +error ("bad FETCH") if $FETCH < 1; +error ("bad LAT1") if $LAT1 < 1; +error ("bad LAT2") if $LAT2 < 1; + +############################################################################# + +open (FOUT,">$FNAME.c") or die "can't open $FNAME.c for writing"; + +# file and function header +output (< 1; + } + output ("q$i,"); +} +for ($i=0; $i<$N1; $i++) { + output ("sum$i"); + output (",") if $i < ($N1-1); +} +output (";\n"); +for ($i=0; $i<$N1; $i++) { + output ("sum$i = 0;\n"); +} +output (<= 0) { +END + +@load = (); # slot where a[i]'s and b[i]'s loaded +@mul = (); # slot where multiply i happened +@add = (); # slow where add i happened + +for ($i=0; $i<$N1; $i++) { + output ("p0$i = a$i [0];\n"); +} +output ("q0 = b[0];\n"); +push (@load,0); + +$slot=0; # one slot for every load/mul/add/nop issued +for (;;) { + $startslot = $slot; + + # do next load + if (($#load - $#mul) < $FETCH && ($#load+1) < $UNROLL1) { + push (@load,$slot); + for ($j=0; $j<$N1; $j++) { + output ("p$#load$j = a$j [$#load];\n"); + } + output ("q$#load = b[$#load];\n"); + $slot++; + } + + # do next multiply + if ($#load > $#mul && $slot >= ($load[$#mul+1] + $LAT1) && + ($#mul+1) < $UNROLL1) { + push (@mul,$slot); + if ($LAT2 > 1) { + for ($j=0; $j<$N1; $j++) { + output ("m$#mul$j = p$#mul$j * q$#mul;\n"); + } + } + else { + for ($j=0; $j<$N1; $j++) { + output ("sum$j += p$#mul$j * q$#mul;\n"); + } + last if ($#mul+1) >= $UNROLL1; + } + $slot++; + } + # do next add + if ($LAT2 > 1) { + if ($#mul > $#add && $slot >= ($mul[$#add+1] + $LAT2)) { + push (@add,$slot); + for ($j=0; $j<$N1; $j++) { + output ("sum$j += m$#add$j;\n"); + } + $slot++; + last if ($#add+1) >= $UNROLL1; + } + } + + if ($slot == $startslot) { + # comment ("nop"); + $slot++; + } +} + +for ($j=0; $j<$N1; $j++) { + output ("a$j += $UNROLL1;\n"); +} +output ("b += $UNROLL1;\n"); +output ("n -= $UNROLL1;\n"); +output ("}\n"); + +output ("n += $UNROLL1;\n"); +output ("while (n > 0) {\n"); +output ("q0 = *b;\n"); +for ($j=0; $j<$N1; $j++) { + output ("sum$j += (*a$j) * q0;\n"); + output ("a$j++;\n"); +} +output ("b++;\n"); +output ("n--;\n"); +output ("}\n"); +for ($j=0; $j<$N1; $j++) { + output ("outsum[$j] = sum$j;\n"); +} +output ("}\n"); diff --git a/extern/ode/dist/ode/fbuild/BuildUtil b/extern/ode/dist/ode/fbuild/BuildUtil new file mode 100644 index 00000000000..b0828ff5ec1 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/BuildUtil @@ -0,0 +1,99 @@ +#!/usr/bin/perl -w +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +package BuildUtil; + + +# print out code. after newlines, indent according to the number of curly +# brackets we've seen + +my $indent = 0; +my $startofline = 1; + + +sub main::output +{ + my $line = $_[0]; + my ($i,$j,$c); + for ($i=0; $i < length ($line); $i++) { + $c = substr ($line,$i,1); + print main::FOUT $c if $c eq '{'; + $indent++ if $c eq '{'; + $indent-- if $c eq '}'; + if ($startofline) { + for ($j=0; $j < $indent; $j++) { + print main::FOUT " "; + } + $startofline = 0; + } + print main::FOUT $c if $c ne '{'; + $startofline = 1 if $c eq "\n"; + } +} + + +# write a C comment with the correct indenting + +sub main::comment +{ + main::output ("/* $_[0] */\n"); +} + + +# return an offset: N*skip = skipN where N=0,1,2,... + +sub main::ofs1 # (N,skip) +{ + my $N = $_[0]; + my $skip = $_[1]; + return '0' if $N==0; + return $skip . $N; +} + + +# return an offset: M+N*skip = M+skipN where N=0,1,2,... + +sub main::ofs2 # (M,N,skip) +{ + my $M = $_[0]; + my $N = $_[1]; + my $skip = $_[2]; + $M = '0' if $M eq '-0'; + my $a = $M; + $a .= '+' . $skip . $N if ($N > 0); + substr ($a,0,2)='' if substr ($a,0,2) eq '0+'; + return $a; +} + + +# print an error message and exit + +sub main::error +{ + print "ERROR: $_[0]\n"; + exit 1; +} + + +1; diff --git a/extern/ode/dist/ode/fbuild/Dependencies b/extern/ode/dist/ode/fbuild/Dependencies new file mode 100644 index 00000000000..86f5cd4417b --- /dev/null +++ b/extern/ode/dist/ode/fbuild/Dependencies @@ -0,0 +1,16 @@ +test_dot.o: test_dot.cpp ../../include/ode/ode.h \ + ../../include/ode/config.h ../../include/ode/contact.h \ + ../../include/ode/common.h ../../include/ode/error.h \ + ../../include/ode/memory.h ../../include/ode/odemath.h \ + ../../include/ode/matrix.h ../../include/ode/timer.h \ + ../../include/ode/rotation.h ../../include/ode/mass.h \ + ../../include/ode/space.h ../../include/ode/geom.h \ + ../../include/ode/misc.h +test_ldlt.o: test_ldlt.cpp ../../include/ode/ode.h \ + ../../include/ode/config.h ../../include/ode/contact.h \ + ../../include/ode/common.h ../../include/ode/error.h \ + ../../include/ode/memory.h ../../include/ode/odemath.h \ + ../../include/ode/matrix.h ../../include/ode/timer.h \ + ../../include/ode/rotation.h ../../include/ode/mass.h \ + ../../include/ode/space.h ../../include/ode/geom.h \ + ../../include/ode/misc.h diff --git a/extern/ode/dist/ode/fbuild/Makefile b/extern/ode/dist/ode/fbuild/Makefile new file mode 100644 index 00000000000..f988c3739af --- /dev/null +++ b/extern/ode/dist/ode/fbuild/Makefile @@ -0,0 +1,77 @@ +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# currently this only works under linux, and it's a bit of a mess! + +MAKEFILE_INC=../../build/Makefile.inc +include $(MAKEFILE_INC) + +INCLUDE_PATHS=../../include +LIB_PATHS = ../../lib +DEFINES=dDOUBLE + +SOURCES_CPP=test_ldlt.cpp +SOURCES_C=fastldlt.c fastlsolve.c fastltsolve.c +APPS=$(call fEXENAME,test_ldlt) $(call fEXENAME,test_dot) $(call fEXENAME,test_multidot) +EXTRA_CLEAN=test_ldlt test_dot test_multidot fastldlt.c fastlsolve.c fastltsolve.c fastdot.c fastmultidot.c + + +all: $(APPS) + +$(call fEXENAME,test_ldlt): $(call fTARGETS,$(SOURCES_CPP) $(SOURCES_C)) + gcc -o $@ $^ -L $(LIB_PATHS) $(call fLIB,ode) -lm + +$(call fEXENAME,test_dot): test_dot.o fastdot.o + gcc -o $@ test_dot.o fastdot.o -L $(LIB_PATHS) $(call fLIB,ode) -lm + +$(call fEXENAME,test_multidot): test_multidot.o fastmultidot.o + gcc -o $@ test_multidot.o fastmultidot.o -L $(LIB_PATHS) $(call fLIB,ode) -lm + +fastldlt.o: fastldlt.c + gcc -O1 -I$(INCLUDE_PATHS) -ffast-math -fomit-frame-pointer -c -D$(DEFINES) $< + +fastlsolve.o: fastlsolve.c + gcc -O1 -I$(INCLUDE_PATHS) -ffast-math -fomit-frame-pointer -c -D$(DEFINES) $< + +fastltsolve.o: fastltsolve.c + gcc -O1 -I$(INCLUDE_PATHS) -ffast-math -fomit-frame-pointer -c -D$(DEFINES) $< + +fastdot.o: fastdot.c + gcc -O1 -I$(INCLUDE_PATHS) -ffast-math -fomit-frame-pointer -c -D$(DEFINES) $< + +fastmultidot.o: fastmultidot.c + gcc -O1 -I$(INCLUDE_PATHS) -ffast-math -fomit-frame-pointer -c -D$(DEFINES) $< + +fastldlt.c: BuildLDLT BuildUtil ParametersF + ./BuildLDLT ParametersF + +fastlsolve.c: BuildLDLT BuildUtil ParametersS + ./BuildLDLT ParametersS + +fastltsolve.c: BuildLDLT BuildUtil ParametersT + ./BuildLDLT ParametersT + +fastdot.c: BuildDot BuildUtil ParametersD + ./BuildDot ParametersD + +fastmultidot.c: BuildMultidot BuildUtil ParametersM + ./BuildMultidot ParametersM diff --git a/extern/ode/dist/ode/fbuild/OptimizeDot b/extern/ode/dist/ode/fbuild/OptimizeDot new file mode 100644 index 00000000000..1dc178262aa --- /dev/null +++ b/extern/ode/dist/ode/fbuild/OptimizeDot @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# optimize the dot product built by BuildDot + +############################################################################## + +require ("OptimizeUtil"); + +# unused standard parameters +$TYPE='unused'; +$N1=0; # unused +$UNROLL2=0; # unused +$MADD=0; # unused + +############################################################################## + +sub testDot # (filename) +{ + my $filename = $_[0]; + createParametersFile ('ParametersD'); + $params = "$N1 $UNROLL1 $UNROLL2 $MADD $FETCH $LAT1 $LAT2"; + print "***** TESTING $params\n"; + doit ("rm -f fastdot.c fastdot.o test_dot"); + doit ("make test_dot"); + doit ("./test_dot >> $filename"); + open (FILE,">>$filename"); + print FILE " $params\n"; + close FILE; +} + +# find optimal parameters. write results to data4.txt + +open (FILE,">data4.txt"); +print FILE "# dot product data from OptimizeDot\n"; +close FILE; +$FNAME='fastdot'; + +for ($UNROLL1=1; $UNROLL1 <= 10; $UNROLL1++) { + for ($LAT1=1; $LAT1 <= 5; $LAT1++) { + for ($LAT2=1; $LAT2 <= 5; $LAT2++) { + for ($FETCH=1; $FETCH<=5; $FETCH++) { + testDot ('data4.txt'); + } + } + } +} + +readBackDataFile ('data4.txt'); +createParametersFile ('ParametersD'); diff --git a/extern/ode/dist/ode/fbuild/OptimizeLDLT b/extern/ode/dist/ode/fbuild/OptimizeLDLT new file mode 100644 index 00000000000..612633e00c2 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/OptimizeLDLT @@ -0,0 +1,91 @@ +#!/usr/bin/perl +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# optimize the factorizer built by BuildLDLT +# +# FNAME : name of source file to generate - .h and .c files will be made +# N1 : block size (size of outer product matrix) (1..9) +# UNROLL1 : solver inner loop unrolling factor (1..) +# UNROLL2 : factorizer inner loop unrolling factor (1..) +# MADD : if nonzero, generate code for fused multiply-add (0,1) +# FETCH : how to fetch data in the inner loop: +# 0 - load in a batch (the `normal way') +# 1 - delay inner loop loads until just before they're needed + +############################################################################## + +require ("OptimizeUtil"); + +############################################################################## +# optimize factorizer + +sub testFactorizer # (filename) +{ + my $filename = $_[0]; + createParametersFile ('ParametersF'); + $params = "$N1 $UNROLL1 $UNROLL2 $MADD $FETCH"; + print "***** TESTING $params\n"; + doit ("rm -f fastldlt.c fastldlt.o test_ldlt"); + doit ("make test_ldlt"); + doit ("./test_ldlt f >> $filename"); + open (FILE,">>$filename"); + print FILE " $params\n"; + close FILE; +} + + +# first find optimal parameters ignoring UNROLL1 and UNROLL2, write results +# to data1.txt + +open (FILE,">data1.txt"); +print FILE "# factorizer data from OptimizeLDLT\n"; +close FILE; +$FNAME='fastldlt'; +$TYPE='f'; +$UNROLL1=4; +$UNROLL2=4; +for ($N1=1; $N1 <= 4; $N1++) { + for ($MADD=0; $MADD<=1; $MADD++) { + for ($FETCH=0; $FETCH<=1; $FETCH++) { + testFactorizer ('data1.txt'); + } + } +} + +readBackDataFile ('data1.txt'); +createParametersFile ('ParametersF'); + +# now find optimal UNROLL1 and UNROLL2 values, write results to data2.txt + +open (FILE,">data2.txt"); +print FILE "# factorizer data from OptimizeLDLT\n"; +close FILE; +for ($UNROLL1=1; $UNROLL1 <= 10; $UNROLL1++) { + for ($UNROLL2=1; $UNROLL2 <= 10; $UNROLL2++) { + testFactorizer ('data2.txt'); + } +} + +readBackDataFile ('data2.txt'); +createParametersFile ('ParametersF'); diff --git a/extern/ode/dist/ode/fbuild/OptimizeLSolve b/extern/ode/dist/ode/fbuild/OptimizeLSolve new file mode 100644 index 00000000000..bba6b495f2c --- /dev/null +++ b/extern/ode/dist/ode/fbuild/OptimizeLSolve @@ -0,0 +1,76 @@ +#!/usr/bin/perl +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# optimize the solver built by BuildLDLT +# +# FNAME : name of source file to generate - .h and .c files will be made +# N1 : block size (size of outer product matrix) (1..9) +# UNROLL1 : solver inner loop unrolling factor (1..) +# UNROLL2 : factorizer inner loop unrolling factor (1..) +# MADD : if nonzero, generate code for fused multiply-add (0,1) +# FETCH : how to fetch data in the inner loop: +# 0 - load in a batch (the `normal way') +# 1 - delay inner loop loads until just before they're needed + +############################################################################## + +require ("OptimizeUtil"); + +############################################################################## +# optimize solver + +sub testSolver # (filename) +{ + my $filename = $_[0]; + createParametersFile ('ParametersS'); + $params = "$N1 $UNROLL1 $UNROLL2 $MADD $FETCH"; + print "***** TESTING $params\n"; + doit ("rm -f fastlsolve.c fastlsolve.o test_ldlt"); + doit ("make test_ldlt"); + doit ("./test_ldlt s >> $filename"); + open (FILE,">>$filename"); + print FILE " $params\n"; + close FILE; +} + +# find optimal parameters. UNROLL2 has no effect. write results to data3.txt + +open (FILE,">data3.txt"); +print FILE "# solver data from OptimizeLDLT\n"; +close FILE; +$FNAME='fastlsolve'; +$TYPE='s'; +$UNROLL2=1; +for ($N1=1; $N1 <= 5; $N1++) { + for ($UNROLL1=1; $UNROLL1 <= 15; $UNROLL1++) { + for ($MADD=0; $MADD<=1; $MADD++) { + for ($FETCH=0; $FETCH<=1; $FETCH++) { + testSolver ('data3.txt'); + } + } + } +} + +readBackDataFile ('data3.txt'); +createParametersFile ('ParametersS'); diff --git a/extern/ode/dist/ode/fbuild/OptimizeLTSolve b/extern/ode/dist/ode/fbuild/OptimizeLTSolve new file mode 100644 index 00000000000..a10109e2d2c --- /dev/null +++ b/extern/ode/dist/ode/fbuild/OptimizeLTSolve @@ -0,0 +1,76 @@ +#!/usr/bin/perl +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# optimize the transpose solver built by BuildLDLT +# +# FNAME : name of source file to generate - .h and .c files will be made +# N1 : block size (size of outer product matrix) (1..9) +# UNROLL1 : solver inner loop unrolling factor (1..) +# UNROLL2 : factorizer inner loop unrolling factor (1..) +# MADD : if nonzero, generate code for fused multiply-add (0,1) +# FETCH : how to fetch data in the inner loop: +# 0 - load in a batch (the `normal way') +# 1 - delay inner loop loads until just before they're needed + +############################################################################## + +require ("OptimizeUtil"); + +############################################################################## +# optimize solver + +sub testSolver # (filename) +{ + my $filename = $_[0]; + createParametersFile ('ParametersT'); + $params = "$N1 $UNROLL1 $UNROLL2 $MADD $FETCH"; + print "***** TESTING $params\n"; + doit ("rm -f fastltsolve.c fastltsolve.o test_ldlt"); + doit ("make test_ldlt"); + doit ("./test_ldlt t >> $filename"); + open (FILE,">>$filename"); + print FILE " $params\n"; + close FILE; +} + +# find optimal parameters. UNROLL2 has no effect. write results to data5.txt + +open (FILE,">data5.txt"); +print FILE "# solver data from OptimizeLDLT\n"; +close FILE; +$FNAME='fastltsolve'; +$TYPE='t'; +$UNROLL2=1; +for ($N1=1; $N1 <= 5; $N1++) { + for ($UNROLL1=1; $UNROLL1 <= 15; $UNROLL1++) { + for ($MADD=0; $MADD<=1; $MADD++) { + for ($FETCH=0; $FETCH<=1; $FETCH++) { + testSolver ('data5.txt'); + } + } + } +} + +readBackDataFile ('data5.txt'); +createParametersFile ('ParametersT'); diff --git a/extern/ode/dist/ode/fbuild/OptimizeMultidot b/extern/ode/dist/ode/fbuild/OptimizeMultidot new file mode 100644 index 00000000000..f2b54383312 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/OptimizeMultidot @@ -0,0 +1,73 @@ +#!/usr/bin/perl +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# optimize the dot product built by BuildMultidot + +############################################################################## + +require ("OptimizeUtil"); + +# multiple +$N1=2; + +# unused standard parameters +$TYPE='unused'; +$UNROLL2=0; # unused +$MADD=0; # unused + +############################################################################## + +sub testMultidot # (filename) +{ + my $filename = $_[0]; + createParametersFile ('ParametersM'); + $params = "$N1 $UNROLL1 $UNROLL2 $MADD $FETCH $LAT1 $LAT2"; + print "***** TESTING $params\n"; + doit ("rm -f fastmultidot.c fastmultidot.o test_multidot"); + doit ("make test_multidot"); + doit ("./test_multidot >> $filename"); + open (FILE,">>$filename"); + print FILE " $params\n"; + close FILE; +} + +# find optimal parameters. write results to data6.txt + +open (FILE,">data6.txt"); +print FILE "# multi-dot product data from OptimizeMultidot\n"; +close FILE; +$FNAME='fastmultidot'; + +for ($UNROLL1=1; $UNROLL1 <= 10; $UNROLL1++) { + for ($LAT1=1; $LAT1 <= 5; $LAT1++) { + for ($LAT2=1; $LAT2 <= 5; $LAT2++) { + for ($FETCH=1; $FETCH<=5; $FETCH++) { + testMultidot ('data6.txt'); + } + } + } +} + +readBackDataFile ('data6.txt'); +createParametersFile ('ParametersM'); diff --git a/extern/ode/dist/ode/fbuild/OptimizeUtil b/extern/ode/dist/ode/fbuild/OptimizeUtil new file mode 100644 index 00000000000..2b882fcba65 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/OptimizeUtil @@ -0,0 +1,86 @@ +#!/usr/bin/perl -w +# +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +package BuildUtil; + + +sub main::doit +{ + my $cmd = $_[0]; + print "$cmd\n"; + system ($cmd)==0 or die "FAILED"; +} + + +sub main::createParametersFile # (filename) +{ + open (PARAM,">$_[0]"); + print PARAM "# perl script to set parameters required by the code generator\n"; + print PARAM "\$FNAME=\"$main::FNAME\";\n" if defined($main::FNAME); + print PARAM "\$TYPE=\"$main::TYPE\";\n" if defined($main::TYPE); + print PARAM "\$N1=$main::N1;\n" if defined($main::N1); + print PARAM "\$UNROLL1=$main::UNROLL1;\n" if defined($main::UNROLL1); + print PARAM "\$UNROLL2=$main::UNROLL2;\n" if defined($main::UNROLL2); + print PARAM "\$MADD=$main::MADD;\n" if defined($main::MADD); + print PARAM "\$FETCH=$main::FETCH;\n" if defined($main::FETCH); + print PARAM "\$LAT1=$main::LAT1;\n" if defined($main::LAT1); + print PARAM "\$LAT2=$main::LAT2;\n" if defined($main::LAT2); + close PARAM; +} + + +# read back a data file and find best parameters + +sub main::readBackDataFile # (filename) +{ + my $filename = $_[0]; + my $maxtime = 1e10; + open (FILE,$filename); + while () { + next if /^\#/; + my $line = lc $_; + if ($line =~ /error/) { + print "ERRORS FOUND IN $filename\n"; + exit 1; + } + $line =~ s/^\s*//; + $line =~ s/\s*$//; + my @nums = split (/\s+/,$line); + $time = $nums[0]; + if ($time < $maxtime) { + $main::N1 = $nums[1]; + $main::UNROLL1 = $nums[2]; + $main::UNROLL2 = $nums[3]; + $main::MADD = $nums[4]; + $main::FETCH = $nums[5]; + $main::LAT1 = $nums[6]; + $main::LAT2 = $nums[7]; + $maxtime = $time; + } + } + close FILE; +} + + +1; diff --git a/extern/ode/dist/ode/fbuild/ParametersD.example b/extern/ode/dist/ode/fbuild/ParametersD.example new file mode 100644 index 00000000000..e58f279f7d7 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/ParametersD.example @@ -0,0 +1,32 @@ +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# perl script to set parameters required by the code generator +$FNAME="fastdot"; +$TYPE="unused"; +$N1=0; +$UNROLL1=2; +$UNROLL2=0; +$MADD=0; +$FETCH=1; +$LAT1=1; +$LAT2=2; diff --git a/extern/ode/dist/ode/fbuild/ParametersF.example b/extern/ode/dist/ode/fbuild/ParametersF.example new file mode 100644 index 00000000000..9881b09ad81 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/ParametersF.example @@ -0,0 +1,30 @@ +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# perl script to set parameters required by the code generator +$FNAME="fastldlt"; +$TYPE="f"; +$N1=2; +$UNROLL1=2; +$UNROLL2=6; +$MADD=0; +$FETCH=1; diff --git a/extern/ode/dist/ode/fbuild/ParametersM.example b/extern/ode/dist/ode/fbuild/ParametersM.example new file mode 100644 index 00000000000..bb81d6b83f1 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/ParametersM.example @@ -0,0 +1,32 @@ +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# perl script to set parameters required by the code generator +$FNAME="fastmultidot"; +$TYPE="unused"; +$N1=2; +$UNROLL1=1; +$UNROLL2=0; +$MADD=0; +$FETCH=5; +$LAT1=1; +$LAT2=1; diff --git a/extern/ode/dist/ode/fbuild/ParametersS.example b/extern/ode/dist/ode/fbuild/ParametersS.example new file mode 100644 index 00000000000..29c9a91fc16 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/ParametersS.example @@ -0,0 +1,30 @@ +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# perl script to set parameters required by the code generator +$FNAME="fastlsolve"; +$TYPE="s"; +$N1=4; +$UNROLL1=12; +$UNROLL2=1; +$MADD=1; +$FETCH=0; diff --git a/extern/ode/dist/ode/fbuild/ParametersT.example b/extern/ode/dist/ode/fbuild/ParametersT.example new file mode 100644 index 00000000000..3aa92a31dd2 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/ParametersT.example @@ -0,0 +1,30 @@ +######################################################################### +# # +# Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. # +# All rights reserved. Email: russ@q12.org Web: www.q12.org # +# # +# This library is free software; you can redistribute it and/or # +# modify it under the terms of EITHER: # +# (1) The GNU Lesser General Public License as published by the Free # +# Software Foundation; either version 2.1 of the License, or (at # +# your option) any later version. The text of the GNU Lesser # +# General Public License is included with this library in the # +# file LICENSE.TXT. # +# (2) The BSD-style license that is included with this library in # +# the file LICENSE-BSD.TXT. # +# # +# This library is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # +# LICENSE.TXT and LICENSE-BSD.TXT for more details. # +# # +######################################################################### + +# perl script to set parameters required by the code generator +$FNAME="fastltsolve"; +$TYPE="t"; +$N1=4; +$UNROLL1=12; +$UNROLL2=1; +$MADD=1; +$FETCH=0; diff --git a/extern/ode/dist/ode/fbuild/README b/extern/ode/dist/ode/fbuild/README new file mode 100644 index 00000000000..bcf7f5aa8b5 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/README @@ -0,0 +1,41 @@ + +factorizer/solver builder + +before running `make', copy the following files: + ParametersD.example --> ParametersD + ParametersF.example --> ParametersF + ParametersS.example --> ParametersS + +the files Parameters[D|F|S] don't exist in the CVS archive because +they are changable. + + + +STATS - for chol +----- + +* all with -O1 + +128x128 matrix +atlas = 1724779 clocks +my chol = 1164629 clocks (parameters: 2 2 2 1) with Ai++, Aj++ +my chol = 1140786 clocks (parameters: 2 6 8 0) with Ai++, Aj++ +my chol = 1118968 clocks (parameters: 2 6 8 0) with +ofs + +64x64 matrix +atlas = 374020 clocks +my chol = 157076 clocks (parameters = 2 2 2 1) + +32x32 matrix (12961 flops) +atlas = 83827 clocks +my chol = 25945 clocks (parameters: 2 2 2 1) + + + + +TODO +---- + +* doc! + +* iterate blocks by partial rows to try and keep more data in cache diff --git a/extern/ode/dist/ode/fbuild/ldlt.m b/extern/ode/dist/ode/fbuild/ldlt.m new file mode 100644 index 00000000000..19ae2d1c94e --- /dev/null +++ b/extern/ode/dist/ode/fbuild/ldlt.m @@ -0,0 +1,26 @@ +function [L,d] = ldlt(A) + +n=length(A); +d=zeros(n,1); + +d(1) = 1/A(1,1); +for i=2:n + for j=2:i-1 + A(i,j) = A(i,j) - A(j,1:j-1) * A(i,1:j-1)'; + end + sum = 0; + for j=1:i-1 + q1 = A(i,j); + q2 = q1 * d(j); + A(i,j) = q2; + sum = sum + q1*q2; + end + d(i) = 1/(A(i,i) - sum); +end + +L=A; +for i=1:n + L(i,i:n)=zeros(1,n+1-i); + L(i,i)=1; +end +d = d .\ 1; diff --git a/extern/ode/dist/ode/fbuild/test_dot.cpp b/extern/ode/dist/ode/fbuild/test_dot.cpp new file mode 100644 index 00000000000..62aec32e509 --- /dev/null +++ b/extern/ode/dist/ode/fbuild/test_dot.cpp @@ -0,0 +1,124 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include "ode/ode.h" + +#define ALLOCA dALLOCA16 +#define SIZE 1000 + + +// correct dot product, for accuracy testing + +dReal goodDot (dReal *a, dReal *b, int n) +{ + dReal sum=0; + while (n > 0) { + sum += (*a) * (*b); + a++; + b++; + n--; + } + return sum; +} + + +// test dot product accuracy + +void testAccuracy() +{ + // allocate vectors a and b and fill them with random data + dReal *a = (dReal*) ALLOCA (SIZE*sizeof(dReal)); + dReal *b = (dReal*) ALLOCA (SIZE*sizeof(dReal)); + dMakeRandomMatrix (a,1,SIZE,1.0); + dMakeRandomMatrix (b,1,SIZE,1.0); + + for (int n=1; n<100; n++) { + dReal good = goodDot (a,b,n); + dReal test = dDot (a,b,n); + dReal diff = fabs(good-test); + //printf ("diff = %e\n",diff); + if (diff > 1e-10) printf ("ERROR: accuracy test failed\n"); + } +} + + +// test dot product factorizer speed. + +void testSpeed() +{ + // allocate vectors a and b and fill them with random data + dReal *a = (dReal*) ALLOCA (SIZE*sizeof(dReal)); + dReal *b = (dReal*) ALLOCA (SIZE*sizeof(dReal)); + dMakeRandomMatrix (a,1,SIZE,1.0); + dMakeRandomMatrix (b,1,SIZE,1.0); + + // time several dot products, return the minimum timing + double mintime = 1e100; + dStopwatch sw; + for (int i=0; i<1000; i++) { + dStopwatchReset (&sw); + dStopwatchStart (&sw); + + // try a bunch of prime sizes up to 101 + dDot (a,b,2); + dDot (a,b,3); + dDot (a,b,5); + dDot (a,b,7); + dDot (a,b,11); + dDot (a,b,13); + dDot (a,b,17); + dDot (a,b,19); + dDot (a,b,23); + dDot (a,b,29); + dDot (a,b,31); + dDot (a,b,37); + dDot (a,b,41); + dDot (a,b,43); + dDot (a,b,47); + dDot (a,b,53); + dDot (a,b,59); + dDot (a,b,61); + dDot (a,b,67); + dDot (a,b,71); + dDot (a,b,73); + dDot (a,b,79); + dDot (a,b,83); + dDot (a,b,89); + dDot (a,b,97); + dDot (a,b,101); + + dStopwatchStop (&sw); + double time = dStopwatchTime (&sw); + if (time < mintime) mintime = time; + } + + printf ("%.0f",mintime * dTimerTicksPerSecond()); +} + + +int main() +{ + testAccuracy(); + testSpeed(); + return 0; +} diff --git a/extern/ode/dist/ode/fbuild/test_ldlt.cpp b/extern/ode/dist/ode/fbuild/test_ldlt.cpp new file mode 100644 index 00000000000..3b795b9ee7f --- /dev/null +++ b/extern/ode/dist/ode/fbuild/test_ldlt.cpp @@ -0,0 +1,299 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include +#include "ode/ode.h" + +#define ALLOCA dALLOCA16 + +//**************************************************************************** +// constants + +#ifdef dSINGLE +#define TOL (1e-4) +#else +#define TOL (1e-10) +#endif + +//**************************************************************************** +// test L*X=B solver accuracy. + +void testSolverAccuracy (int n) +{ + int i; + int npad = dPAD(n); + dReal *L = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + dReal *B = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *B2 = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *X = (dReal*) ALLOCA (n*sizeof(dReal)); + + // L is a random lower triangular matrix with 1's on the diagonal + dMakeRandomMatrix (L,n,n,1.0); + dClearUpperTriangle (L,n); + for (i=0; i TOL) { + printf ("error = %e, size = %d\n",error,n); + } +} + +//**************************************************************************** +// test L^T*X=B solver accuracy. + +void testTransposeSolverAccuracy (int n) +{ + int i; + int npad = dPAD(n); + dReal *L = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + dReal *B = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *B2 = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *X = (dReal*) ALLOCA (n*sizeof(dReal)); + + // L is a random lower triangular matrix with 1's on the diagonal + dMakeRandomMatrix (L,n,n,1.0); + dClearUpperTriangle (L,n); + for (i=0; i TOL) { + printf ("error = %e, size = %d\n",error,n); + } +} + +//**************************************************************************** +// test L*D*L' factorizer accuracy. + +void testLDLTAccuracy (int n) +{ + int i,j; + int npad = dPAD(n); + dReal *A = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + dReal *L = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + dReal *d = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *Atest = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + dReal *DL = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + + dMakeRandomMatrix (A,n,n,1.0); + dMultiply2 (L,A,A,n,n,n); + memcpy (A,L,n*npad*sizeof(dReal)); + dSetZero (d,n); + + dFactorLDLT (L,d,n,npad); + + // make L lower triangular, and convert d into diagonal of D + dClearUpperTriangle (L,n); + for (i=0; i TOL) { + printf ("error = %e, size = %d\n",error,n); + } + + /* + printf ("\n"); + dPrintMatrix (A,n,n); + printf ("\n"); + dPrintMatrix (L,n,n); + printf ("\n"); + dPrintMatrix (d,1,n); + */ +} + +//**************************************************************************** +// test L*D*L' factorizer speed. + +void testLDLTSpeed (int n) +{ + int npad = dPAD(n); + + // allocate A + dReal *A = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + + // make B a symmetric positive definite matrix + dMakeRandomMatrix (A,n,n,1.0); + dReal *B = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + dSetZero (B,n*npad); + dMultiply2 (B,A,A,n,n,n); + + // make d + dReal *d = (dReal*) ALLOCA (n*sizeof(dReal)); + dSetZero (d,n); + + // time several factorizations, return the minimum timing + double mintime = 1e100; + dStopwatch sw; + for (int i=0; i<100; i++) { + memcpy (A,B,n*npad*sizeof(dReal)); + dStopwatchReset (&sw); + dStopwatchStart (&sw); + + dFactorLDLT (A,d,n,npad); + + dStopwatchStop (&sw); + double time = dStopwatchTime (&sw); + if (time < mintime) mintime = time; + } + + printf ("%.0f",mintime * dTimerTicksPerSecond()); +} + +//**************************************************************************** +// test solver speed. + +void testSolverSpeed (int n, int transpose) +{ + int i; + int npad = dPAD(n); + + // allocate L,B,X + dReal *L = (dReal*) ALLOCA (n*npad*sizeof(dReal)); + dReal *B = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *X = (dReal*) ALLOCA (n*sizeof(dReal)); + + // L is a random lower triangular matrix with 1's on the diagonal + dMakeRandomMatrix (L,n,n,1.0); + dClearUpperTriangle (L,n); + for (i=0; i +#include "ode/ode.h" + +#define NUM_A 2 +#define ALLOCA dALLOCA16 +#define SIZE 1000 + + +extern "C" void dMultidot2 (const dReal *a0, const dReal *a1, + const dReal *b, dReal *outsum, int n); +/* +extern "C" void dMultidot4 (const dReal *a0, const dReal *a1, + const dReal *a2, const dReal *a3, + const dReal *b, dReal *outsum, int n); +*/ + + +// correct dot product, for accuracy testing + +dReal goodDot (dReal *a, dReal *b, int n) +{ + dReal sum=0; + while (n > 0) { + sum += (*a) * (*b); + a++; + b++; + n--; + } + return sum; +} + + +// test multi-dot product accuracy + +void testAccuracy() +{ + int j; + + // allocate vectors a and b and fill them with random data + dReal *a[NUM_A]; + for (j=0; j 1e-10) printf ("ERROR: accuracy test failed\n"); + } +} + + +// test multi-dot product factorizer speed. + +void testSpeed() +{ + int j; + dReal sum[NUM_A]; + + // allocate vectors a and b and fill them with random data + dReal *a[NUM_A]; + for (j=0; j +#include +#include +#include "array.h" + + +static inline int roundUpToPowerOfTwo (int x) +{ + int i = 1; + while (i < x) i <<= 1; + return i; +} + + +void dArrayBase::_freeAll (int sizeofT) +{ + if (_data) { + if (_data == this+1) return; // if constructLocalArray() was called + dFree (_data,_anum * sizeofT); + } +} + + +void dArrayBase::_setSize (int newsize, int sizeofT) +{ + if (newsize < 0) return; + if (newsize > _anum) { + if (_data == this+1) { + // this is a no-no, because constructLocalArray() was called + dDebug (0,"setSize() out of space in LOCAL array"); + } + int newanum = roundUpToPowerOfTwo (newsize); + if (_data) _data = dRealloc (_data, _anum*sizeofT, newanum*sizeofT); + else _data = dAlloc (newanum*sizeofT); + _anum = newanum; + } + _size = newsize; +} + + +void * dArrayBase::operator new (size_t size) +{ + return dAlloc (size); +} + + +void dArrayBase::operator delete (void *ptr, size_t size) +{ + dFree (ptr,size); +} + + +void dArrayBase::constructLocalArray (int __anum) +{ + _size = 0; + _anum = __anum; + _data = this+1; +} diff --git a/extern/ode/dist/ode/src/array.h b/extern/ode/dist/ode/src/array.h new file mode 100644 index 00000000000..97c2cebc2f4 --- /dev/null +++ b/extern/ode/dist/ode/src/array.h @@ -0,0 +1,135 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* this comes from the `reuse' library. copy any changes back to the source. + * + * Variable sized array template. The array is always stored in a contiguous + * chunk. The array can be resized. A size increase will cause more memory + * to be allocated, and may result in relocation of the array memory. + * A size decrease has no effect on the memory allocation. + * + * Array elements with constructors or destructors are not supported! + * But if you must have such elements, here's what to know/do: + * - Bitwise copy is used when copying whole arrays. + * - When copying individual items (via push(), insert() etc) the `=' + * (equals) operator is used. Thus you should define this operator to do + * a bitwise copy. You should probably also define the copy constructor. + */ + + +#ifndef _ODE_ARRAY_H_ +#define _ODE_ARRAY_H_ + +#include + + +// this base class has no constructors or destructor, for your convenience. + +class dArrayBase { +protected: + int _size; // number of elements in `data' + int _anum; // allocated number of elements in `data' + void *_data; // array data + + void _freeAll (int sizeofT); + void _setSize (int newsize, int sizeofT); + // set the array size to `newsize', allocating more memory if necessary. + // if newsize>_anum and is a power of two then this is guaranteed to + // set _size and _anum to newsize. + +public: + // not: dArrayBase () { _size=0; _anum=0; _data=0; } + + int size() const { return _size; } + int allocatedSize() const { return _anum; } + void * operator new (size_t size); + void operator delete (void *ptr, size_t size); + + void constructor() { _size=0; _anum=0; _data=0; } + // if this structure is allocated with malloc() instead of new, you can + // call this to set it up. + + void constructLocalArray (int __anum); + // this helper function allows non-reallocating arrays to be constructed + // on the stack (or in the heap if necessary). this is something of a + // kludge and should be used with extreme care. this function acts like + // a constructor - it is called on uninitialized memory that will hold the + // Array structure and the data. __anum is the number of elements that + // are allocated. the memory MUST be allocated with size: + // sizeof(ArrayBase) + __anum*sizeof(T) + // arrays allocated this way will never try to reallocate or free the + // memory - that's your job. +}; + + +template class dArray : public dArrayBase { +public: + void equals (const dArray &x) { + setSize (x.size()); + memcpy (_data,x._data,x._size * sizeof(T)); + } + + dArray () { constructor(); } + dArray (const dArray &x) { constructor(); equals (x); } + ~dArray () { _freeAll(sizeof(T)); } + void setSize (int newsize) { _setSize (newsize,sizeof(T)); } + T *data() const { return (T*) _data; } + T & operator[] (int i) const { return ((T*)_data)[i]; } + void operator = (const dArray &x) { equals (x); } + + void push (const T item) { + if (_size < _anum) _size++; else _setSize (_size+1,sizeof(T)); + ((T*)_data)[_size-1] = item; + } + + void swap (dArray &x) { + int tmp1; + void *tmp2; + tmp1=_size; _size=x._size; x._size=tmp1; + tmp1=_anum; _anum=x._anum; x._anum=tmp1; + tmp2=_data; _data=x._data; x._data=tmp2; + } + + // insert the item at the position `i'. if i<0 then add the item to the + // start, if i >= size then add the item to the end of the array. + void insert (int i, const T item) { + if (_size < _anum) _size++; else _setSize (_size+1,sizeof(T)); + if (i >= (_size-1)) i = _size-1; // add to end + else { + if (i < 0) i=0; // add to start + int n = _size-1-i; + if (n>0) memmove (((T*)_data) + i+1, ((T*)_data) + i, n*sizeof(T)); + } + ((T*)_data)[i] = item; + } + + void remove (int i) { + if (i >= 0 && i < _size) { // passing this test guarantees size>0 + int n = _size-1-i; + if (n>0) memmove (((T*)_data) + i, ((T*)_data) + i+1, n*sizeof(T)); + _size--; + } + } +}; + +#endif + diff --git a/extern/ode/dist/ode/src/error.cpp b/extern/ode/dist/ode/src/error.cpp new file mode 100644 index 00000000000..9b33db55f0c --- /dev/null +++ b/extern/ode/dist/ode/src/error.cpp @@ -0,0 +1,172 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include + + +static dMessageFunction *error_function = 0; +static dMessageFunction *debug_function = 0; +static dMessageFunction *message_function = 0; + + +extern "C" void dSetErrorHandler (dMessageFunction *fn) +{ + error_function = fn; +} + + +extern "C" void dSetDebugHandler (dMessageFunction *fn) +{ + debug_function = fn; +} + + +extern "C" void dSetMessageHandler (dMessageFunction *fn) +{ + message_function = fn; +} + + +extern "C" dMessageFunction *dGetErrorHandler() +{ + return error_function; +} + + +extern "C" dMessageFunction *dGetDebugHandler() +{ + return debug_function; +} + + +extern "C" dMessageFunction *dGetMessageHandler() +{ + return message_function; +} + + +static void printMessage (int num, const char *msg1, const char *msg2, + va_list ap) +{ + fflush (stderr); + fflush (stdout); + if (num) fprintf (stderr,"\n%s %d: ",msg1,num); + else fprintf (stderr,"\n%s: ",msg1); + vfprintf (stderr,msg2,ap); + fprintf (stderr,"\n"); + fflush (stderr); +} + +//**************************************************************************** +// unix + +#ifndef WIN32 + +extern "C" void dError (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (error_function) error_function (num,msg,ap); + else printMessage (num,"ODE Error",msg,ap); + exit (1); +} + + +extern "C" void dDebug (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (debug_function) debug_function (num,msg,ap); + else printMessage (num,"ODE INTERNAL ERROR",msg,ap); + // *((char *)0) = 0; ... commit SEGVicide + abort(); +} + + +extern "C" void dMessage (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (message_function) message_function (num,msg,ap); + else printMessage (num,"ODE Message",msg,ap); +} + +#endif + +//**************************************************************************** +// windows + +#ifdef WIN32 + +// isn't cygwin annoying! +#ifdef CYGWIN +#define _snprintf snprintf +#define _vsnprintf vsnprintf +#endif + + +#include "windows.h" + + +extern "C" void dError (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (error_function) error_function (num,msg,ap); + else { + char s[1000],title[100]; + _snprintf (title,sizeof(title),"ODE Error %d",num); + _vsnprintf (s,sizeof(s),msg,ap); + s[sizeof(s)-1] = 0; + MessageBox(0,s,title,MB_OK | MB_ICONWARNING); + } + exit (1); +} + + +extern "C" void dDebug (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (debug_function) debug_function (num,msg,ap); + else { + char s[1000],title[100]; + _snprintf (title,sizeof(title),"ODE INTERNAL ERROR %d",num); + _vsnprintf (s,sizeof(s),msg,ap); + s[sizeof(s)-1] = 0; + MessageBox(0,s,title,MB_OK | MB_ICONSTOP); + } + abort(); +} + + +extern "C" void dMessage (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (message_function) message_function (num,msg,ap); + else printMessage (num,"ODE Message",msg,ap); +} + + +#endif diff --git a/extern/ode/dist/ode/src/fastdot.c b/extern/ode/dist/ode/src/fastdot.c new file mode 100644 index 00000000000..148d2dd9e17 --- /dev/null +++ b/extern/ode/dist/ode/src/fastdot.c @@ -0,0 +1,30 @@ +/* generated code, do not edit. */ + +#include "ode/matrix.h" + + +dReal dDot (const dReal *a, const dReal *b, int n) +{ + dReal p0,q0,m0,p1,q1,m1,sum; + sum = 0; + n -= 2; + while (n >= 0) { + p0 = a[0]; q0 = b[0]; + m0 = p0 * q0; + p1 = a[1]; q1 = b[1]; + m1 = p1 * q1; + sum += m0; + sum += m1; + a += 2; + b += 2; + n -= 2; + } + n += 2; + while (n > 0) { + sum += (*a) * (*b); + a++; + b++; + n--; + } + return sum; +} diff --git a/extern/ode/dist/ode/src/fastldlt.c b/extern/ode/dist/ode/src/fastldlt.c new file mode 100644 index 00000000000..df2ea6ec229 --- /dev/null +++ b/extern/ode/dist/ode/src/fastldlt.c @@ -0,0 +1,381 @@ +/* generated code, do not edit. */ + +#include "ode/matrix.h" + +/* solve L*X=B, with B containing 1 right hand sides. + * L is an n*n lower triangular matrix with ones on the diagonal. + * L is stored by rows and its leading dimension is lskip. + * B is an n*1 matrix that contains the right hand sides. + * B is stored by columns and its leading dimension is also lskip. + * B is overwritten with X. + * this processes blocks of 2*2. + * if this is in the factorizer source file, n must be a multiple of 2. + */ + +static void dSolveL1_1 (const dReal *L, dReal *B, int n, int lskip1) +{ + /* declare variables - Z matrix, p and q vectors, etc */ + dReal Z11,m11,Z21,m21,p1,q1,p2,*ex; + const dReal *ell; + int i,j; + /* compute all 2 x 1 blocks of X */ + for (i=0; i < n; i+=2) { + /* compute all 2 x 1 block of X, from rows i..i+2-1 */ + /* set the Z matrix to 0 */ + Z11=0; + Z21=0; + ell = L + i*lskip1; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-2; j >= 0; j -= 2) { + /* compute outer product and add it to the Z matrix */ + p1=ell[0]; + q1=ex[0]; + m11 = p1 * q1; + p2=ell[lskip1]; + m21 = p2 * q1; + Z11 += m11; + Z21 += m21; + /* compute outer product and add it to the Z matrix */ + p1=ell[1]; + q1=ex[1]; + m11 = p1 * q1; + p2=ell[1+lskip1]; + m21 = p2 * q1; + /* advance pointers */ + ell += 2; + ex += 2; + Z11 += m11; + Z21 += m21; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 2; + for (; j > 0; j--) { + /* compute outer product and add it to the Z matrix */ + p1=ell[0]; + q1=ex[0]; + m11 = p1 * q1; + p2=ell[lskip1]; + m21 = p2 * q1; + /* advance pointers */ + ell += 1; + ex += 1; + Z11 += m11; + Z21 += m21; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + p1 = ell[lskip1]; + Z21 = ex[1] - Z21 - p1*Z11; + ex[1] = Z21; + /* end of outer loop */ + } +} + +/* solve L*X=B, with B containing 2 right hand sides. + * L is an n*n lower triangular matrix with ones on the diagonal. + * L is stored by rows and its leading dimension is lskip. + * B is an n*2 matrix that contains the right hand sides. + * B is stored by columns and its leading dimension is also lskip. + * B is overwritten with X. + * this processes blocks of 2*2. + * if this is in the factorizer source file, n must be a multiple of 2. + */ + +static void dSolveL1_2 (const dReal *L, dReal *B, int n, int lskip1) +{ + /* declare variables - Z matrix, p and q vectors, etc */ + dReal Z11,m11,Z12,m12,Z21,m21,Z22,m22,p1,q1,p2,q2,*ex; + const dReal *ell; + int i,j; + /* compute all 2 x 2 blocks of X */ + for (i=0; i < n; i+=2) { + /* compute all 2 x 2 block of X, from rows i..i+2-1 */ + /* set the Z matrix to 0 */ + Z11=0; + Z12=0; + Z21=0; + Z22=0; + ell = L + i*lskip1; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-2; j >= 0; j -= 2) { + /* compute outer product and add it to the Z matrix */ + p1=ell[0]; + q1=ex[0]; + m11 = p1 * q1; + q2=ex[lskip1]; + m12 = p1 * q2; + p2=ell[lskip1]; + m21 = p2 * q1; + m22 = p2 * q2; + Z11 += m11; + Z12 += m12; + Z21 += m21; + Z22 += m22; + /* compute outer product and add it to the Z matrix */ + p1=ell[1]; + q1=ex[1]; + m11 = p1 * q1; + q2=ex[1+lskip1]; + m12 = p1 * q2; + p2=ell[1+lskip1]; + m21 = p2 * q1; + m22 = p2 * q2; + /* advance pointers */ + ell += 2; + ex += 2; + Z11 += m11; + Z12 += m12; + Z21 += m21; + Z22 += m22; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 2; + for (; j > 0; j--) { + /* compute outer product and add it to the Z matrix */ + p1=ell[0]; + q1=ex[0]; + m11 = p1 * q1; + q2=ex[lskip1]; + m12 = p1 * q2; + p2=ell[lskip1]; + m21 = p2 * q1; + m22 = p2 * q2; + /* advance pointers */ + ell += 1; + ex += 1; + Z11 += m11; + Z12 += m12; + Z21 += m21; + Z22 += m22; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + Z12 = ex[lskip1] - Z12; + ex[lskip1] = Z12; + p1 = ell[lskip1]; + Z21 = ex[1] - Z21 - p1*Z11; + ex[1] = Z21; + Z22 = ex[1+lskip1] - Z22 - p1*Z12; + ex[1+lskip1] = Z22; + /* end of outer loop */ + } +} + + +void dFactorLDLT (dReal *A, dReal *d, int n, int nskip1) +{ + int i,j; + dReal sum,*ell,*dee,dd,p1,p2,q1,q2,Z11,m11,Z21,m21,Z22,m22; + if (n < 1) return; + + for (i=0; i<=n-2; i += 2) { + /* solve L*(D*l)=a, l is scaled elements in 2 x i block at A(i,0) */ + dSolveL1_2 (A,A+i*nskip1,i,nskip1); + /* scale the elements in a 2 x i block at A(i,0), and also */ + /* compute Z = the outer product matrix that we'll need. */ + Z11 = 0; + Z21 = 0; + Z22 = 0; + ell = A+i*nskip1; + dee = d; + for (j=i-6; j >= 0; j -= 6) { + p1 = ell[0]; + p2 = ell[nskip1]; + dd = dee[0]; + q1 = p1*dd; + q2 = p2*dd; + ell[0] = q1; + ell[nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[1]; + p2 = ell[1+nskip1]; + dd = dee[1]; + q1 = p1*dd; + q2 = p2*dd; + ell[1] = q1; + ell[1+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[2]; + p2 = ell[2+nskip1]; + dd = dee[2]; + q1 = p1*dd; + q2 = p2*dd; + ell[2] = q1; + ell[2+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[3]; + p2 = ell[3+nskip1]; + dd = dee[3]; + q1 = p1*dd; + q2 = p2*dd; + ell[3] = q1; + ell[3+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[4]; + p2 = ell[4+nskip1]; + dd = dee[4]; + q1 = p1*dd; + q2 = p2*dd; + ell[4] = q1; + ell[4+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[5]; + p2 = ell[5+nskip1]; + dd = dee[5]; + q1 = p1*dd; + q2 = p2*dd; + ell[5] = q1; + ell[5+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + ell += 6; + dee += 6; + } + /* compute left-over iterations */ + j += 6; + for (; j > 0; j--) { + p1 = ell[0]; + p2 = ell[nskip1]; + dd = dee[0]; + q1 = p1*dd; + q2 = p2*dd; + ell[0] = q1; + ell[nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + ell++; + dee++; + } + /* solve for diagonal 2 x 2 block at A(i,i) */ + Z11 = ell[0] - Z11; + Z21 = ell[nskip1] - Z21; + Z22 = ell[1+nskip1] - Z22; + dee = d + i; + /* factorize 2 x 2 block Z,dee */ + /* factorize row 1 */ + dee[0] = dRecip(Z11); + /* factorize row 2 */ + sum = 0; + q1 = Z21; + q2 = q1 * dee[0]; + Z21 = q2; + sum += q1*q2; + dee[1] = dRecip(Z22 - sum); + /* done factorizing 2 x 2 block */ + ell[nskip1] = Z21; + } + /* compute the (less than 2) rows at the bottom */ + switch (n-i) { + case 0: + break; + + case 1: + dSolveL1_1 (A,A+i*nskip1,i,nskip1); + /* scale the elements in a 1 x i block at A(i,0), and also */ + /* compute Z = the outer product matrix that we'll need. */ + Z11 = 0; + ell = A+i*nskip1; + dee = d; + for (j=i-6; j >= 0; j -= 6) { + p1 = ell[0]; + dd = dee[0]; + q1 = p1*dd; + ell[0] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[1]; + dd = dee[1]; + q1 = p1*dd; + ell[1] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[2]; + dd = dee[2]; + q1 = p1*dd; + ell[2] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[3]; + dd = dee[3]; + q1 = p1*dd; + ell[3] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[4]; + dd = dee[4]; + q1 = p1*dd; + ell[4] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[5]; + dd = dee[5]; + q1 = p1*dd; + ell[5] = q1; + m11 = p1*q1; + Z11 += m11; + ell += 6; + dee += 6; + } + /* compute left-over iterations */ + j += 6; + for (; j > 0; j--) { + p1 = ell[0]; + dd = dee[0]; + q1 = p1*dd; + ell[0] = q1; + m11 = p1*q1; + Z11 += m11; + ell++; + dee++; + } + /* solve for diagonal 1 x 1 block at A(i,i) */ + Z11 = ell[0] - Z11; + dee = d + i; + /* factorize 1 x 1 block Z,dee */ + /* factorize row 1 */ + dee[0] = dRecip(Z11); + /* done factorizing 1 x 1 block */ + break; + + default: *((char*)0)=0; /* this should never happen! */ + } +} diff --git a/extern/ode/dist/ode/src/fastlsolve.c b/extern/ode/dist/ode/src/fastlsolve.c new file mode 100644 index 00000000000..0ae99d62d0b --- /dev/null +++ b/extern/ode/dist/ode/src/fastlsolve.c @@ -0,0 +1,298 @@ +/* generated code, do not edit. */ + +#include "ode/matrix.h" + +/* solve L*X=B, with B containing 1 right hand sides. + * L is an n*n lower triangular matrix with ones on the diagonal. + * L is stored by rows and its leading dimension is lskip. + * B is an n*1 matrix that contains the right hand sides. + * B is stored by columns and its leading dimension is also lskip. + * B is overwritten with X. + * this processes blocks of 4*4. + * if this is in the factorizer source file, n must be a multiple of 4. + */ + +void dSolveL1 (const dReal *L, dReal *B, int n, int lskip1) +{ + /* declare variables - Z matrix, p and q vectors, etc */ + dReal Z11,Z21,Z31,Z41,p1,q1,p2,p3,p4,*ex; + const dReal *ell; + int lskip2,lskip3,i,j; + /* compute lskip values */ + lskip2 = 2*lskip1; + lskip3 = 3*lskip1; + /* compute all 4 x 1 blocks of X */ + for (i=0; i <= n-4; i+=4) { + /* compute all 4 x 1 block of X, from rows i..i+4-1 */ + /* set the Z matrix to 0 */ + Z11=0; + Z21=0; + Z31=0; + Z41=0; + ell = L + i*lskip1; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-12; j >= 0; j -= 12) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + p2=ell[lskip1]; + p3=ell[lskip2]; + p4=ell[lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[1]; + q1=ex[1]; + p2=ell[1+lskip1]; + p3=ell[1+lskip2]; + p4=ell[1+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[2]; + q1=ex[2]; + p2=ell[2+lskip1]; + p3=ell[2+lskip2]; + p4=ell[2+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[3]; + q1=ex[3]; + p2=ell[3+lskip1]; + p3=ell[3+lskip2]; + p4=ell[3+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[4]; + q1=ex[4]; + p2=ell[4+lskip1]; + p3=ell[4+lskip2]; + p4=ell[4+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[5]; + q1=ex[5]; + p2=ell[5+lskip1]; + p3=ell[5+lskip2]; + p4=ell[5+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[6]; + q1=ex[6]; + p2=ell[6+lskip1]; + p3=ell[6+lskip2]; + p4=ell[6+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[7]; + q1=ex[7]; + p2=ell[7+lskip1]; + p3=ell[7+lskip2]; + p4=ell[7+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[8]; + q1=ex[8]; + p2=ell[8+lskip1]; + p3=ell[8+lskip2]; + p4=ell[8+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[9]; + q1=ex[9]; + p2=ell[9+lskip1]; + p3=ell[9+lskip2]; + p4=ell[9+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[10]; + q1=ex[10]; + p2=ell[10+lskip1]; + p3=ell[10+lskip2]; + p4=ell[10+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[11]; + q1=ex[11]; + p2=ell[11+lskip1]; + p3=ell[11+lskip2]; + p4=ell[11+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* advance pointers */ + ell += 12; + ex += 12; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 12; + for (; j > 0; j--) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + p2=ell[lskip1]; + p3=ell[lskip2]; + p4=ell[lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* advance pointers */ + ell += 1; + ex += 1; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + p1 = ell[lskip1]; + Z21 = ex[1] - Z21 - p1*Z11; + ex[1] = Z21; + p1 = ell[lskip2]; + p2 = ell[1+lskip2]; + Z31 = ex[2] - Z31 - p1*Z11 - p2*Z21; + ex[2] = Z31; + p1 = ell[lskip3]; + p2 = ell[1+lskip3]; + p3 = ell[2+lskip3]; + Z41 = ex[3] - Z41 - p1*Z11 - p2*Z21 - p3*Z31; + ex[3] = Z41; + /* end of outer loop */ + } + /* compute rows at end that are not a multiple of block size */ + for (; i < n; i++) { + /* compute all 1 x 1 block of X, from rows i..i+1-1 */ + /* set the Z matrix to 0 */ + Z11=0; + ell = L + i*lskip1; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-12; j >= 0; j -= 12) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[1]; + q1=ex[1]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[2]; + q1=ex[2]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[3]; + q1=ex[3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[4]; + q1=ex[4]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[5]; + q1=ex[5]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[6]; + q1=ex[6]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[7]; + q1=ex[7]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[8]; + q1=ex[8]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[9]; + q1=ex[9]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[10]; + q1=ex[10]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[11]; + q1=ex[11]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* advance pointers */ + ell += 12; + ex += 12; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 12; + for (; j > 0; j--) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* advance pointers */ + ell += 1; + ex += 1; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + } +} diff --git a/extern/ode/dist/ode/src/fastltsolve.c b/extern/ode/dist/ode/src/fastltsolve.c new file mode 100644 index 00000000000..eb950f6076a --- /dev/null +++ b/extern/ode/dist/ode/src/fastltsolve.c @@ -0,0 +1,199 @@ +/* generated code, do not edit. */ + +#include "ode/matrix.h" + +/* solve L^T * x=b, with b containing 1 right hand side. + * L is an n*n lower triangular matrix with ones on the diagonal. + * L is stored by rows and its leading dimension is lskip. + * b is an n*1 matrix that contains the right hand side. + * b is overwritten with x. + * this processes blocks of 4. + */ + +void dSolveL1T (const dReal *L, dReal *B, int n, int lskip1) +{ + /* declare variables - Z matrix, p and q vectors, etc */ + dReal Z11,m11,Z21,m21,Z31,m31,Z41,m41,p1,q1,p2,p3,p4,*ex; + const dReal *ell; + int lskip2,lskip3,i,j; + /* special handling for L and B because we're solving L1 *transpose* */ + L = L + (n-1)*(lskip1+1); + B = B + n-1; + lskip1 = -lskip1; + /* compute lskip values */ + lskip2 = 2*lskip1; + lskip3 = 3*lskip1; + /* compute all 4 x 1 blocks of X */ + for (i=0; i <= n-4; i+=4) { + /* compute all 4 x 1 block of X, from rows i..i+4-1 */ + /* set the Z matrix to 0 */ + Z11=0; + Z21=0; + Z31=0; + Z41=0; + ell = L - i; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-4; j >= 0; j -= 4) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + /* load p and q values */ + p1=ell[0]; + q1=ex[-1]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + /* load p and q values */ + p1=ell[0]; + q1=ex[-2]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + /* load p and q values */ + p1=ell[0]; + q1=ex[-3]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + ex -= 4; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 4; + for (; j > 0; j--) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + ex -= 1; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + p1 = ell[-1]; + Z21 = ex[-1] - Z21 - p1*Z11; + ex[-1] = Z21; + p1 = ell[-2]; + p2 = ell[-2+lskip1]; + Z31 = ex[-2] - Z31 - p1*Z11 - p2*Z21; + ex[-2] = Z31; + p1 = ell[-3]; + p2 = ell[-3+lskip1]; + p3 = ell[-3+lskip2]; + Z41 = ex[-3] - Z41 - p1*Z11 - p2*Z21 - p3*Z31; + ex[-3] = Z41; + /* end of outer loop */ + } + /* compute rows at end that are not a multiple of block size */ + for (; i < n; i++) { + /* compute all 1 x 1 block of X, from rows i..i+1-1 */ + /* set the Z matrix to 0 */ + Z11=0; + ell = L - i; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-4; j >= 0; j -= 4) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + Z11 += m11; + /* load p and q values */ + p1=ell[0]; + q1=ex[-1]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + Z11 += m11; + /* load p and q values */ + p1=ell[0]; + q1=ex[-2]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + Z11 += m11; + /* load p and q values */ + p1=ell[0]; + q1=ex[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + ex -= 4; + Z11 += m11; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 4; + for (; j > 0; j--) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + ex -= 1; + Z11 += m11; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + } +} diff --git a/extern/ode/dist/ode/src/geom.cpp b/extern/ode/dist/ode/src/geom.cpp new file mode 100644 index 00000000000..1818814a791 --- /dev/null +++ b/extern/ode/dist/ode/src/geom.cpp @@ -0,0 +1,2207 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +the rule is that only the low level primitive collision functions should set +dContactGeom::g1 and dContactGeom::g2. + +*/ + +#define SHARED_GEOM_H_INCLUDED_FROM_DEFINING_FILE 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include "objects.h" +#include "array.h" +#include "geom_internal.h" + +//**************************************************************************** +// collision utilities. + +// given a pointer `p' to a dContactGeom, return the dContactGeom at +// p + skip bytes. + +#define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) + + +// if the spheres (p1,r1) and (p2,r2) collide, set the contact `c' and +// return 1, else return 0. + +static int dCollideSpheres (dVector3 p1, dReal r1, + dVector3 p2, dReal r2, dContactGeom *c) +{ + // printf ("d=%.2f (%.2f %.2f %.2f) (%.2f %.2f %.2f) r1=%.2f r2=%.2f\n", + // d,p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],r1,r2); + + dReal d = dDISTANCE (p1,p2); + if (d > (r1 + r2)) return 0; + if (d <= 0) { + c->pos[0] = p1[0]; + c->pos[1] = p1[1]; + c->pos[2] = p1[2]; + c->normal[0] = 1; + c->normal[1] = 0; + c->normal[2] = 0; + c->depth = r1 + r2; + } + else { + dReal d1 = dRecip (d); + c->normal[0] = (p1[0]-p2[0])*d1; + c->normal[1] = (p1[1]-p2[1])*d1; + c->normal[2] = (p1[2]-p2[2])*d1; + dReal k = REAL(0.5) * (r2 - r1 - d); + c->pos[0] = p1[0] + c->normal[0]*k; + c->pos[1] = p1[1] + c->normal[1]*k; + c->pos[2] = p1[2] + c->normal[2]*k; + c->depth = r1 + r2 - d; + } + return 1; +} + + +// given two lines +// qa = pa + alpha* ua +// qb = pb + beta * ub +// where pa,pb are two points, ua,ub are two unit length vectors, and alpha, +// beta go from [-inf,inf], return alpha and beta such that qa and qb are +// as close as possible + +static void lineClosestApproach (const dVector3 pa, const dVector3 ua, + const dVector3 pb, const dVector3 ub, + dReal *alpha, dReal *beta) +{ + dVector3 p; + p[0] = pb[0] - pa[0]; + p[1] = pb[1] - pa[1]; + p[2] = pb[2] - pa[2]; + dReal uaub = dDOT(ua,ub); + dReal q1 = dDOT(ua,p); + dReal q2 = -dDOT(ub,p); + dReal d = 1-uaub*uaub; + if (d <= 0) { + // @@@ this needs to be made more robust + *alpha = 0; + *beta = 0; + } + else { + d = dRecip(d); + *alpha = (q1 + uaub*q2)*d; + *beta = (uaub*q1 + q2)*d; + } +} + + +// given two line segments A and B with endpoints a1-a2 and b1-b2, return the +// points on A and B that are closest to each other (in cp1 and cp2). +// in the case of parallel lines where there are multiple solutions, a +// solution involving the endpoint of at least one line will be returned. +// this will work correctly for zero length lines, e.g. if a1==a2 and/or +// b1==b2. +// +// the algorithm works by applying the voronoi clipping rule to the features +// of the line segments. the three features of each line segment are the two +// endpoints and the line between them. the voronoi clipping rule states that, +// for feature X on line A and feature Y on line B, the closest points PA and +// PB between X and Y are globally the closest points if PA is in V(Y) and +// PB is in V(X), where V(X) is the voronoi region of X. + + +void dClosestLineSegmentPoints (dVector3 const a1, dVector3 const a2, + dVector3 const b1, dVector3 const b2, + dVector3 cp1, dVector3 cp2) +{ + dVector3 a1a2,b1b2,a1b1,a1b2,a2b1,a2b2,n; + dReal la,lb,k,da1,da2,da3,da4,db1,db2,db3,db4,det; + +#define SET2(a,b) a[0]=b[0]; a[1]=b[1]; a[2]=b[2]; +#define SET3(a,b,op,c) a[0]=b[0] op c[0]; a[1]=b[1] op c[1]; a[2]=b[2] op c[2]; + + // check vertex-vertex features + + SET3 (a1a2,a2,-,a1); + SET3 (b1b2,b2,-,b1); + SET3 (a1b1,b1,-,a1); + da1 = dDOT(a1a2,a1b1); + db1 = dDOT(b1b2,a1b1); + if (da1 <= 0 && db1 >= 0) { + SET2 (cp1,a1); + SET2 (cp2,b1); + return; + } + + SET3 (a1b2,b2,-,a1); + da2 = dDOT(a1a2,a1b2); + db2 = dDOT(b1b2,a1b2); + if (da2 <= 0 && db2 <= 0) { + SET2 (cp1,a1); + SET2 (cp2,b2); + return; + } + + SET3 (a2b1,b1,-,a2); + da3 = dDOT(a1a2,a2b1); + db3 = dDOT(b1b2,a2b1); + if (da3 >= 0 && db3 >= 0) { + SET2 (cp1,a2); + SET2 (cp2,b1); + return; + } + + SET3 (a2b2,b2,-,a2); + da4 = dDOT(a1a2,a2b2); + db4 = dDOT(b1b2,a2b2); + if (da4 >= 0 && db4 <= 0) { + SET2 (cp1,a2); + SET2 (cp2,b2); + return; + } + + // check edge-vertex features. + // if one or both of the lines has zero length, we will never get to here, + // so we do not have to worry about the following divisions by zero. + + la = dDOT(a1a2,a1a2); + if (da1 >= 0 && da3 <= 0) { + k = da1 / la; + SET3 (n,a1b1,-,k*a1a2); + if (dDOT(b1b2,n) >= 0) { + SET3 (cp1,a1,+,k*a1a2); + SET2 (cp2,b1); + return; + } + } + + if (da2 >= 0 && da4 <= 0) { + k = da2 / la; + SET3 (n,a1b2,-,k*a1a2); + if (dDOT(b1b2,n) <= 0) { + SET3 (cp1,a1,+,k*a1a2); + SET2 (cp2,b2); + return; + } + } + + lb = dDOT(b1b2,b1b2); + if (db1 <= 0 && db2 >= 0) { + k = -db1 / lb; + SET3 (n,-a1b1,-,k*b1b2); + if (dDOT(a1a2,n) >= 0) { + SET2 (cp1,a1); + SET3 (cp2,b1,+,k*b1b2); + return; + } + } + + if (db3 <= 0 && db4 >= 0) { + k = -db3 / lb; + SET3 (n,-a2b1,-,k*b1b2); + if (dDOT(a1a2,n) <= 0) { + SET2 (cp1,a2); + SET3 (cp2,b1,+,k*b1b2); + return; + } + } + + // it must be edge-edge + + k = dDOT(a1a2,b1b2); + det = la*lb - k*k; + if (det <= 0) { + // this should never happen, but just in case... + SET2(cp1,a1); + SET2(cp2,b1); + return; + } + det = dRecip (det); + dReal alpha = (lb*da1 - k*db1) * det; + dReal beta = ( k*da1 - la*db1) * det; + SET3 (cp1,a1,+,alpha*a1a2); + SET3 (cp2,b1,+,beta*b1b2); + +# undef SET2 +# undef SET3 +} + + +// given a line segment p1-p2 and a box (center 'c', rotation 'R', side length +// vector 'side'), compute the points of closest approach between the box +// and the line. return these points in 'lret' (the point on the line) and +// 'bret' (the point on the box). if the line actually penetrates the box +// then the solution is not unique, but only one solution will be returned. +// in this case the solution points will coincide. +// +// a simple root finding algorithm is used to find the value of 't' that +// satisfies: +// d|D(t)|^2/dt = 0 +// where: +// |D(t)| = |p(t)-b(t)| +// where p(t) is a point on the line parameterized by t: +// p(t) = p1 + t*(p2-p1) +// and b(t) is that same point clipped to the boundary of the box. in box- +// relative coordinates d|D(t)|^2/dt is the sum of three x,y,z components +// each of which looks like this: +// +// t_lo / +// ______/ -->t +// / t_hi +// / +// +// t_lo and t_hi are the t values where the line passes through the planes +// corresponding to the sides of the box. the algorithm computes d|D(t)|^2/dt +// in a piecewise fashion from t=0 to t=1, stopping at the point where +// d|D(t)|^2/dt crosses from negative to positive. + +static void dClosestLineBoxPoints (const dVector3 p1, const dVector3 p2, + const dVector3 c, const dMatrix3 R, + const dVector3 side, + dVector3 lret, dVector3 bret) +{ + int i; + + // compute the start and delta of the line p1-p2 relative to the box. + // we will do all subsequent computations in this box-relative coordinate + // system. we have to do a translation and rotation for each point. + dVector3 tmp,s,v; + tmp[0] = p1[0] - c[0]; + tmp[1] = p1[1] - c[1]; + tmp[2] = p1[2] - c[2]; + dMULTIPLY1_331 (s,R,tmp); + tmp[0] = p2[0] - p1[0]; + tmp[1] = p2[1] - p1[1]; + tmp[2] = p2[2] - p1[2]; + dMULTIPLY1_331 (v,R,tmp); + + // mirror the line so that v has all components >= 0 + dVector3 sign; + for (i=0; i<3; i++) { + if (v[i] < 0) { + s[i] = -s[i]; + v[i] = -v[i]; + sign[i] = -1; + } + else sign[i] = 1; + } + + // compute v^2 + dVector3 v2; + v2[0] = v[0]*v[0]; + v2[1] = v[1]*v[1]; + v2[2] = v[2]*v[2]; + + // compute the half-sides of the box + dReal h[3]; + h[0] = REAL(0.5) * side[0]; + h[1] = REAL(0.5) * side[1]; + h[2] = REAL(0.5) * side[2]; + + // region is -1,0,+1 depending on which side of the box planes each + // coordinate is on. tanchor in the next t value at which there is a + // transition, or the last one if there are no more. + int region[3]; + dReal tanchor[3]; + + // find the region and tanchor values for p1 + for (i=0; i<3; i++) { + if (v[i] > 0) { + if (s[i] < -h[i]) { + region[i] = -1; + tanchor[i] = (-h[i]-s[i])/v[i]; + } + else { + region[i] = (s[i] > h[i]); + tanchor[i] = (h[i]-s[i])/v[i]; + } + } + else { + region[i] = 0; + tanchor[i] = 2; // this will never be a valid tanchor + } + } + + // compute d|d|^2/dt for t=0. if it's >= 0 then p1 is the closest point + dReal t=0; + dReal dd2dt = 0; + for (i=0; i<3; i++) dd2dt -= (region[i] ? v2[i] : 0) * tanchor[i]; + if (dd2dt >= 0) goto got_answer; + + do { + // find the point on the line that is at the next clip plane boundary + dReal next_t = 1; + for (i=0; i<3; i++) { + if (tanchor[i] > t && tanchor[i] < 1 && tanchor[i] < next_t) + next_t = tanchor[i]; + } + + // compute d|d|^2/dt for the next t + dReal next_dd2dt = 0; + for (i=0; i<3; i++) { + next_dd2dt += (region[i] ? v2[i] : 0) * (next_t - tanchor[i]); + } + + // if the sign of d|d|^2/dt has changed, solution = the crossover point + if (next_dd2dt >= 0) { + dReal m = (next_dd2dt-dd2dt)/(next_t - t); + t -= dd2dt/m; + goto got_answer; + } + + // advance to the next anchor point / region + for (i=0; i<3; i++) { + if (tanchor[i] == next_t) { + tanchor[i] = (h[i]-s[i])/v[i]; + region[i]++; + } + } + t = next_t; + dd2dt = next_dd2dt; + } + while (t < 1); + t = 1; + + got_answer: + + // compute closest point on the line + for (i=0; i<3; i++) lret[i] = p1[i] + t*tmp[i]; // note: tmp=p2-p1 + + // compute closest point on the box + for (i=0; i<3; i++) { + tmp[i] = sign[i] * (s[i] + t*v[i]); + if (tmp[i] < -h[i]) tmp[i] = -h[i]; + else if (tmp[i] > h[i]) tmp[i] = h[i]; + } + dMULTIPLY0_331 (s,R,tmp); + for (i=0; i<3; i++) bret[i] = s[i] + c[i]; +} + + +// given a box (R,side), `R' is the rotation matrix for the box, and `side' +// is a vector of x/y/z side lengths, return the size of the interval of the +// box projected along the given axis. if the axis has unit length then the +// return value will be the actual diameter, otherwise the result will be +// scaled by the axis length. + +static inline dReal boxDiameter (const dMatrix3 R, const dVector3 side, + const dVector3 axis) +{ + dVector3 q; + dMULTIPLY1_331 (q,R,axis); // transform axis to body-relative + return dFabs(q[0])*side[0] + dFabs(q[1])*side[1] + dFabs(q[2])*side[2]; +} + + +// given boxes (p1,R1,side1) and (p1,R1,side1), return 1 if they intersect +// or 0 if not. + +int dBoxTouchesBox (const dVector3 p1, const dMatrix3 R1, + const dVector3 side1, const dVector3 p2, + const dMatrix3 R2, const dVector3 side2) +{ + // two boxes are disjoint if (and only if) there is a separating axis + // perpendicular to a face from one box or perpendicular to an edge from + // either box. the following tests are derived from: + // "OBB Tree: A Hierarchical Structure for Rapid Interference Detection", + // S.Gottschalk, M.C.Lin, D.Manocha., Proc of ACM Siggraph 1996. + + // Rij is R1'*R2, i.e. the relative rotation between R1 and R2. + // Qij is abs(Rij) + dVector3 p,pp; + dReal A1,A2,A3,B1,B2,B3,R11,R12,R13,R21,R22,R23,R31,R32,R33, + Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33; + + // get vector from centers of box 1 to box 2, relative to box 1 + p[0] = p2[0] - p1[0]; + p[1] = p2[1] - p1[1]; + p[2] = p2[2] - p1[2]; + dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 + + // get side lengths / 2 + A1 = side1[0]*REAL(0.5); A2 = side1[1]*REAL(0.5); A3 = side1[2]*REAL(0.5); + B1 = side2[0]*REAL(0.5); B2 = side2[1]*REAL(0.5); B3 = side2[2]*REAL(0.5); + + // for the following tests, excluding computation of Rij, in the worst case, + // 15 compares, 60 adds, 81 multiplies, and 24 absolutes. + // notation: R1=[u1 u2 u3], R2=[v1 v2 v3] + + // separating axis = u1,u2,u3 + R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); + Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13); + if (dFabs(pp[0]) > (A1 + B1*Q11 + B2*Q12 + B3*Q13)) return 0; + R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); + Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23); + if (dFabs(pp[1]) > (A2 + B1*Q21 + B2*Q22 + B3*Q23)) return 0; + R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); + Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33); + if (dFabs(pp[2]) > (A3 + B1*Q31 + B2*Q32 + B3*Q33)) return 0; + + // separating axis = v1,v2,v3 + if (dFabs(dDOT41(R2+0,p)) > (A1*Q11 + A2*Q21 + A3*Q31 + B1)) return 0; + if (dFabs(dDOT41(R2+1,p)) > (A1*Q12 + A2*Q22 + A3*Q32 + B2)) return 0; + if (dFabs(dDOT41(R2+2,p)) > (A1*Q13 + A2*Q23 + A3*Q33 + B3)) return 0; + + // separating axis = u1 x (v1,v2,v3) + if (dFabs(pp[2]*R21-pp[1]*R31) > A2*Q31 + A3*Q21 + B2*Q13 + B3*Q12) return 0; + if (dFabs(pp[2]*R22-pp[1]*R32) > A2*Q32 + A3*Q22 + B1*Q13 + B3*Q11) return 0; + if (dFabs(pp[2]*R23-pp[1]*R33) > A2*Q33 + A3*Q23 + B1*Q12 + B2*Q11) return 0; + + // separating axis = u2 x (v1,v2,v3) + if (dFabs(pp[0]*R31-pp[2]*R11) > A1*Q31 + A3*Q11 + B2*Q23 + B3*Q22) return 0; + if (dFabs(pp[0]*R32-pp[2]*R12) > A1*Q32 + A3*Q12 + B1*Q23 + B3*Q21) return 0; + if (dFabs(pp[0]*R33-pp[2]*R13) > A1*Q33 + A3*Q13 + B1*Q22 + B2*Q21) return 0; + + // separating axis = u3 x (v1,v2,v3) + if (dFabs(pp[1]*R11-pp[0]*R21) > A1*Q21 + A2*Q11 + B2*Q33 + B3*Q32) return 0; + if (dFabs(pp[1]*R12-pp[0]*R22) > A1*Q22 + A2*Q12 + B1*Q33 + B3*Q31) return 0; + if (dFabs(pp[1]*R13-pp[0]*R23) > A1*Q23 + A2*Q13 + B1*Q32 + B2*Q31) return 0; + + return 1; +} + + +// given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and +// generate contact points. this returns 0 if there is no contact otherwise +// it returns the number of contacts generated. +// `normal' returns the contact normal. +// `depth' returns the maximum penetration depth along that normal. +// `code' returns a number indicating the type of contact that was detected: +// 1,2,3 = box 2 intersects with a face of box 1 +// 4,5,6 = box 1 intersects with a face of box 2 +// 7..15 = edge-edge contact +// `maxc' is the maximum number of contacts allowed to be generated, i.e. +// the size of the `contact' array. +// `contact' and `skip' are the contact array information provided to the +// collision functions. this function only fills in the position and depth +// fields. +// +// @@@ some stuff to optimize here, reuse code in contact point calculations. + +extern "C" int dBoxBox (const dVector3 p1, const dMatrix3 R1, + const dVector3 side1, const dVector3 p2, + const dMatrix3 R2, const dVector3 side2, + dVector3 normal, dReal *depth, int *code, + int maxc, dContactGeom *contact, int skip) +{ + dVector3 p,pp,normalC; + const dReal *normalR = 0; + dReal A1,A2,A3,B1,B2,B3,R11,R12,R13,R21,R22,R23,R31,R32,R33, + Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l; + int i,invert_normal; + + // get vector from centers of box 1 to box 2, relative to box 1 + p[0] = p2[0] - p1[0]; + p[1] = p2[1] - p1[1]; + p[2] = p2[2] - p1[2]; + dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 + + // get side lengths / 2 + A1 = side1[0]*REAL(0.5); A2 = side1[1]*REAL(0.5); A3 = side1[2]*REAL(0.5); + B1 = side2[0]*REAL(0.5); B2 = side2[1]*REAL(0.5); B3 = side2[2]*REAL(0.5); + + // Rij is R1'*R2, i.e. the relative rotation between R1 and R2 + R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); + R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); + R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); + + Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13); + Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23); + Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33); + + // for all 15 possible separating axes: + // * see if the axis separates the boxes. if so, return 0. + // * find the depth of the penetration along the separating axis (s2) + // * if this is the largest depth so far, record it. + // the normal vector will be set to the separating axis with the smallest + // depth. note: normalR is set to point to a column of R1 or R2 if that is + // the smallest depth normal so far. otherwise normalR is 0 and normalC is + // set to a vector relative to body 1. invert_normal is 1 if the sign of + // the normal should be flipped. + +#define TEST(expr1,expr2,norm,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + if (s2 > s) { \ + s = s2; \ + normalR = norm; \ + invert_normal = ((expr1) < 0); \ + *code = (cc); \ + } + + s = -dInfinity; + invert_normal = 0; + *code = 0; + + // separating axis = u1,u2,u3 + TEST (pp[0],(A1 + B1*Q11 + B2*Q12 + B3*Q13),R1+0,1); + TEST (pp[1],(A2 + B1*Q21 + B2*Q22 + B3*Q23),R1+1,2); + TEST (pp[2],(A3 + B1*Q31 + B2*Q32 + B3*Q33),R1+2,3); + + // separating axis = v1,v2,v3 + TEST (dDOT41(R2+0,p),(A1*Q11 + A2*Q21 + A3*Q31 + B1),R2+0,4); + TEST (dDOT41(R2+1,p),(A1*Q12 + A2*Q22 + A3*Q32 + B2),R2+1,5); + TEST (dDOT41(R2+2,p),(A1*Q13 + A2*Q23 + A3*Q33 + B3),R2+2,6); + + // note: cross product axes need to be scaled when s is computed. + // normal (n1,n2,n3) is relative to box 1. +#undef TEST +#define TEST(expr1,expr2,n1,n2,n3,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + l = dSqrt ((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ + if (l > 0) { \ + s2 /= l; \ + if (s2 > s) { \ + s = s2; \ + normalR = 0; \ + normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ + invert_normal = ((expr1) < 0); \ + *code = (cc); \ + } \ + } + + // separating axis = u1 x (v1,v2,v3) + TEST(pp[2]*R21-pp[1]*R31,(A2*Q31+A3*Q21+B2*Q13+B3*Q12),0,-R31,R21,7); + TEST(pp[2]*R22-pp[1]*R32,(A2*Q32+A3*Q22+B1*Q13+B3*Q11),0,-R32,R22,8); + TEST(pp[2]*R23-pp[1]*R33,(A2*Q33+A3*Q23+B1*Q12+B2*Q11),0,-R33,R23,9); + + // separating axis = u2 x (v1,v2,v3) + TEST(pp[0]*R31-pp[2]*R11,(A1*Q31+A3*Q11+B2*Q23+B3*Q22),R31,0,-R11,10); + TEST(pp[0]*R32-pp[2]*R12,(A1*Q32+A3*Q12+B1*Q23+B3*Q21),R32,0,-R12,11); + TEST(pp[0]*R33-pp[2]*R13,(A1*Q33+A3*Q13+B1*Q22+B2*Q21),R33,0,-R13,12); + + // separating axis = u3 x (v1,v2,v3) + TEST(pp[1]*R11-pp[0]*R21,(A1*Q21+A2*Q11+B2*Q33+B3*Q32),-R21,R11,0,13); + TEST(pp[1]*R12-pp[0]*R22,(A1*Q22+A2*Q12+B1*Q33+B3*Q31),-R22,R12,0,14); + TEST(pp[1]*R13-pp[0]*R23,(A1*Q23+A2*Q13+B1*Q32+B2*Q31),-R23,R13,0,15); + +#undef TEST + + // if we get to this point, the boxes interpenetrate. compute the normal + // in global coordinates. + if (normalR) { + normal[0] = normalR[0]; + normal[1] = normalR[4]; + normal[2] = normalR[8]; + } + else { + dMULTIPLY0_331 (normal,R1,normalC); + } + if (invert_normal) { + normal[0] = -normal[0]; + normal[1] = -normal[1]; + normal[2] = -normal[2]; + } + *depth = -s; + + // compute contact point(s) + + if (*code > 6) { + // an edge from box 1 touches an edge from box 2. + // find a point pa on the intersecting edge of box 1 + dVector3 pa; + dReal sign; + for (i=0; i<3; i++) pa[i] = p1[i]; + sign = (dDOT14(normal,R1+0) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) pa[i] += sign * A1 * R1[i*4]; + sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) pa[i] += sign * A2 * R1[i*4+1]; + sign = (dDOT14(normal,R1+2) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) pa[i] += sign * A3 * R1[i*4+2]; + + // find a point pb on the intersecting edge of box 2 + dVector3 pb; + for (i=0; i<3; i++) pb[i] = p2[i]; + sign = (dDOT14(normal,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; i++) pb[i] += sign * B1 * R2[i*4]; + sign = (dDOT14(normal,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; i++) pb[i] += sign * B2 * R2[i*4+1]; + sign = (dDOT14(normal,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; i++) pb[i] += sign * B3 * R2[i*4+2]; + + dReal alpha,beta; + dVector3 ua,ub; + for (i=0; i<3; i++) ua[i] = R1[((*code)-7)/3 + i*4]; + for (i=0; i<3; i++) ub[i] = R2[((*code)-7)%3 + i*4]; + + lineClosestApproach (pa,ua,pb,ub,&alpha,&beta); + for (i=0; i<3; i++) pa[i] += ua[i]*alpha; + for (i=0; i<3; i++) pb[i] += ub[i]*beta; + + for (i=0; i<3; i++) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); + contact[0].depth = *depth; + return 1; + } + + // okay, we have a face-something intersection (because the separating + // axis is perpendicular to a face). + + // @@@ temporary: make deepest vertex on the "other" box the contact point. + // @@@ this kind of works, but we need multiple contact points for stability, + // @@@ especially for face-face contact. + + dVector3 vertex; + if (*code <= 3) { + // face from box 1 touches a vertex/edge/face from box 2. + dReal sign; + for (i=0; i<3; i++) vertex[i] = p2[i]; + sign = (dDOT14(normal,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; i++) vertex[i] += sign * B1 * R2[i*4]; + sign = (dDOT14(normal,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; i++) vertex[i] += sign * B2 * R2[i*4+1]; + sign = (dDOT14(normal,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; i++) vertex[i] += sign * B3 * R2[i*4+2]; + } + else { + // face from box 2 touches a vertex/edge/face from box 1. + dReal sign; + for (i=0; i<3; i++) vertex[i] = p1[i]; + sign = (dDOT14(normal,R1+0) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) vertex[i] += sign * A1 * R1[i*4]; + sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) vertex[i] += sign * A2 * R1[i*4+1]; + sign = (dDOT14(normal,R1+2) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) vertex[i] += sign * A3 * R1[i*4+2]; + } + for (i=0; i<3; i++) contact[0].pos[i] = vertex[i]; + contact[0].depth = *depth; + return 1; +} + +//**************************************************************************** +// general support for geometry objects and classes + +struct dColliderEntry { + dColliderFn *fn; // collider function + int mode; // 1 = reverse o1 and o2, 2 = no function available +}; + +static dArray *classes=0; + +// function pointers and modes for n^2 class collider functions. this is an +// n*n matrix stored by row. the functions pointers are extracted from the +// class get-collider-function function. +static dArray *colliders=0; + + +static inline void initCollisionArrays() +{ + if (classes==0) { + // old way: + // classes = (dArray *) dAllocNoFree (sizeof(dArrayBase)); + // classes->constructor(); + classes = new dArray; + classes->setSize (1); // force allocation of array data memory + dAllocDontReport (classes); + dAllocDontReport (classes->data()); + classes->setSize (0); + } + if (colliders==0) { + // old way: + // colliders=(dArray *)dAllocNoFree (sizeof(dArrayBase)); + // colliders->constructor(); + colliders = new dArray; + colliders->setSize (1); // force allocation of array data memory + dAllocDontReport (colliders); + dAllocDontReport (colliders->data()); + colliders->setSize (0); + } +} + + +int dCreateGeomClass (const dGeomClass *c) +{ + dUASSERT(c && c->bytes >= 0 && c->collider && c->aabb,"bad geom class"); + initCollisionArrays(); + + int n = classes->size(); + dxGeomClass *gc = (dxGeomClass*) dAlloc (sizeof(dxGeomClass)); + dAllocDontReport (gc); + gc->collider = c->collider; + gc->aabb = c->aabb; + gc->aabb_test = c->aabb_test; + gc->dtor = c->dtor; + gc->num = n; + gc->size = SIZEOF_DXGEOM + c->bytes; + classes->push (gc); + + // make room for n^2 class collider function pointers - these entries will + // be filled as dCollide() is called. + colliders->setSize ((n+1)*(n+1)); + memset (colliders->data(),0,(n+1)*(n+1)*sizeof(dColliderEntry)); + + return n; +} + + +int dCollide (dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, + int skip) +{ + int i,c1,c2,a1,a2,count,swap; + dColliderFn *fn; + dAASSERT(o1 && o2 && contact); + dUASSERT(classes && colliders,"no registered geometry classes"); + + // no contacts if both geoms on the same body, and the body is not 0 + if (o1->body == o2->body && o1->body) return 0; + + dColliderEntry *colliders2 = colliders->data(); + c1 = o1->_class->num; + c2 = o2->_class->num; + a1 = c1 * classes->size() + c2; // address 1 in collider array + a2 = c2 * classes->size() + c1; // address 2 in collider array + swap = 0; // set to 1 to swap normals before returning + + // return if there are no collider functions available + if ((colliders2[a1].mode==2) || (colliders2[a2].mode==2)) return 0; + + if ((fn = colliders2[a1].fn)) { + swap = colliders2[a1].mode; + if (swap) count = (*fn) (o2,o1,flags,contact,skip); + else count = (*fn) (o1,o2,flags,contact,skip); + } + else if ((fn = (*classes)[c1]->collider (c2))) { + colliders2 [a2].fn = fn; + colliders2 [a2].mode = 1; + colliders2 [a1].fn = fn; // do mode=0 assignment second so that + colliders2 [a1].mode = 0; // diagonal entries will have mode 0 + count = (*fn) (o1,o2,flags,contact,skip); + swap = 0; + } + else if ((fn = (*classes)[c2]->collider (c1))) { + colliders2 [a1].fn = fn; + colliders2 [a1].mode = 1; + colliders2 [a2].fn = fn; // do mode=0 assignment second so that + colliders2 [a2].mode = 0; // diagonal entries will have mode 0 + count = (*fn) (o2,o1,flags,contact,skip); + swap = 1; + } + else { + colliders2[a1].mode = 2; + colliders2[a2].mode = 2; + return 0; + } + + if (swap) { + for (i=0; inormal[0] = -c->normal[0]; + c->normal[1] = -c->normal[1]; + c->normal[2] = -c->normal[2]; + dxGeom *tmp = c->g1; + c->g1 = c->g2; + c->g2 = tmp; + } + } + + return count; +} + + +int dGeomGetClass (dxGeom *g) +{ + dAASSERT (g); + return g->_class->num; +} + + +void dGeomSetData (dxGeom *g, void *data) +{ + dAASSERT (g); + g->data = data; +} + + +void *dGeomGetData (dxGeom *g) +{ + dAASSERT (g); + return g->data; +} + + +void dGeomSetBody (dxGeom *g, dBodyID b) +{ + dAASSERT (g); + if (b) { + if (!g->body) dFree (g->pos,sizeof(dxPosR)); + g->body = b; + g->pos = b->pos; + g->R = b->R; + } + else { + if (g->body) { + dxPosR *pr = (dxPosR*) dAlloc (sizeof(dxPosR)); + g->pos = pr->pos; + g->R = pr->R; + memcpy (g->pos,g->body->pos,sizeof(g->pos)); + memcpy (g->R,g->body->R,sizeof(g->R)); + g->body = 0; + } + } +} + + +dBodyID dGeomGetBody (dxGeom *g) +{ + dAASSERT (g); + return g->body; +} + + +void dGeomSetPosition (dxGeom *g, dReal x, dReal y, dReal z) +{ + dAASSERT (g); + if (g->body) dBodySetPosition (g->body,x,y,z); + else { + g->pos[0] = x; + g->pos[1] = y; + g->pos[2] = z; + } +} + + +void dGeomSetRotation (dxGeom *g, const dMatrix3 R) +{ + dAASSERT (g); + if (g->body) dBodySetRotation (g->body,R); + else memcpy (g->R,R,sizeof(dMatrix3)); +} + + +const dReal * dGeomGetPosition (dxGeom *g) +{ + dAASSERT (g); + return g->pos; +} + + +const dReal * dGeomGetRotation (dxGeom *g) +{ + dAASSERT (g); + return g->R; +} + + +// for external use only. use the CLASSDATA macro inside ODE. + +void * dGeomGetClassData (dxGeom *g) +{ + dAASSERT (g); + return (void*) CLASSDATA(g); +} + + +dxGeom * dCreateGeom (int classnum) +{ + dUASSERT (classes && colliders && classnum >= 0 && + classnum < classes->size(),"bad class number"); + int size = (*classes)[classnum]->size; + dxGeom *geom = (dxGeom*) dAlloc (size); + memset (geom,0,size); // everything is initially zeroed + + geom->_class = (*classes)[classnum]; + geom->data = 0; + geom->body = 0; + + dxPosR *pr = (dxPosR*) dAlloc (sizeof(dxPosR)); + geom->pos = pr->pos; + geom->R = pr->R; + dSetZero (geom->pos,4); + dRSetIdentity (geom->R); + + return geom; +} + + +void dGeomDestroy (dxGeom *g) +{ + dAASSERT (g); + if (g->spaceid) dSpaceRemove (g->spaceid,g); + if (g->_class->dtor) g->_class->dtor (g); + if (!g->body) dFree (g->pos,sizeof(dxPosR)); + dFree (g,g->_class->size); +} + + +void dGeomGetAABB (dxGeom *g, dReal aabb[6]) +{ + dAASSERT (g); + g->_class->aabb (g,aabb); +} + + +dReal *dGeomGetSpaceAABB (dxGeom *g) +{ + dAASSERT (g); + return g->space_aabb; +} + +//**************************************************************************** +// data for the standard classes + +struct dxSphere { + dReal radius; // sphere radius +}; + +struct dxBox { + dVector3 side; // side lengths (x,y,z) +}; + +struct dxCCylinder { // capped cylinder + dReal radius,lz; // radius, length along z axis */ +}; + +struct dxPlane { + dReal p[4]; +}; + +struct dxGeomGroup { + dArray parts; // all the geoms that make up the group +}; + +//**************************************************************************** +// primitive collision functions +// same interface as dCollide(). +// S=sphere, B=box, C=capped cylinder, P=plane, G=group, T=transform + +int dCollideSS (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dSphereClass); + dIASSERT (o2->_class->num == dSphereClass); + dxSphere *s1 = (dxSphere*) CLASSDATA(o1); + dxSphere *s2 = (dxSphere*) CLASSDATA(o2); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + return dCollideSpheres (o1->pos,s1->radius, + o2->pos,s2->radius,contact); +} + + +int dCollideSB (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + // this is easy. get the sphere center `p' relative to the box, and then clip + // that to the boundary of the box (call that point `q'). if q is on the + // boundary of the box and |p-q| is <= sphere radius, they touch. + // if q is inside the box, the sphere is inside the box, so set a contact + // normal to push the sphere to the closest box edge. + + dVector3 l,t,p,q,r; + dReal depth; + int onborder = 0; + + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dSphereClass); + dIASSERT (o2->_class->num == dBoxClass); + dxSphere *sphere = (dxSphere*) CLASSDATA(o1); + dxBox *box = (dxBox*) CLASSDATA(o2); + + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + + p[0] = o1->pos[0] - o2->pos[0]; + p[1] = o1->pos[1] - o2->pos[1]; + p[2] = o1->pos[2] - o2->pos[2]; + + l[0] = box->side[0]*REAL(0.5); + t[0] = dDOT14(p,o2->R); + if (t[0] < -l[0]) { t[0] = -l[0]; onborder = 1; } + if (t[0] > l[0]) { t[0] = l[0]; onborder = 1; } + + l[1] = box->side[1]*REAL(0.5); + t[1] = dDOT14(p,o2->R+1); + if (t[1] < -l[1]) { t[1] = -l[1]; onborder = 1; } + if (t[1] > l[1]) { t[1] = l[1]; onborder = 1; } + + t[2] = dDOT14(p,o2->R+2); + l[2] = box->side[2]*REAL(0.5); + if (t[2] < -l[2]) { t[2] = -l[2]; onborder = 1; } + if (t[2] > l[2]) { t[2] = l[2]; onborder = 1; } + + if (!onborder) { + // sphere center inside box. find largest `t' value + dReal max = dFabs(t[0]); + int maxi = 0; + for (int i=1; i<3; i++) { + dReal tt = dFabs(t[i]); + if (tt > max) { + max = tt; + maxi = i; + } + } + // contact position = sphere center + contact->pos[0] = o1->pos[0]; + contact->pos[1] = o1->pos[1]; + contact->pos[2] = o1->pos[2]; + // contact normal aligned with box edge along largest `t' value + dVector3 tmp; + tmp[0] = 0; + tmp[1] = 0; + tmp[2] = 0; + tmp[maxi] = (t[maxi] > 0) ? REAL(1.0) : REAL(-1.0); + dMULTIPLY0_331 (contact->normal,o2->R,tmp); + // contact depth = distance to wall along normal plus radius + contact->depth = l[maxi] - max + sphere->radius; + return 1; + } + + t[3] = 0; //@@@ hmmm + dMULTIPLY0_331 (q,o2->R,t); + r[0] = p[0] - q[0]; + r[1] = p[1] - q[1]; + r[2] = p[2] - q[2]; + depth = sphere->radius - dSqrt(dDOT(r,r)); + if (depth < 0) return 0; + contact->pos[0] = q[0] + o2->pos[0]; + contact->pos[1] = q[1] + o2->pos[1]; + contact->pos[2] = q[2] + o2->pos[2]; + contact->normal[0] = r[0]; + contact->normal[1] = r[1]; + contact->normal[2] = r[2]; + dNormalize3 (contact->normal); + contact->depth = depth; + return 1; +} + + +int dCollideSP (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dSphereClass); + dIASSERT (o2->_class->num == dPlaneClass); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + dxSphere *sphere = (dxSphere*) CLASSDATA(o1); + dxPlane *plane = (dxPlane*) CLASSDATA(o2); + dReal k = dDOT (o1->pos,plane->p); + dReal depth = plane->p[3] - k + sphere->radius; + if (depth >= 0) { + contact->normal[0] = plane->p[0]; + contact->normal[1] = plane->p[1]; + contact->normal[2] = plane->p[2]; + contact->pos[0] = o1->pos[0] - plane->p[0] * sphere->radius; + contact->pos[1] = o1->pos[1] - plane->p[1] * sphere->radius; + contact->pos[2] = o1->pos[2] - plane->p[2] * sphere->radius; + contact->depth = depth; + return 1; + } + else return 0; +} + + +int dCollideBB (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dVector3 normal; + dReal depth; + int code; + dxBox *b1 = (dxBox*) CLASSDATA(o1); + dxBox *b2 = (dxBox*) CLASSDATA(o2); + int num = dBoxBox (o1->pos,o1->R,b1->side, o2->pos,o2->R,b2->side, + normal,&depth,&code,flags & NUMC_MASK,contact,skip); + for (int i=0; inormal[0] = -normal[0]; + CONTACT(contact,i*skip)->normal[1] = -normal[1]; + CONTACT(contact,i*skip)->normal[2] = -normal[2]; + CONTACT(contact,i*skip)->g1 = const_cast (o1); + CONTACT(contact,i*skip)->g2 = const_cast (o2); + } + return num; +} + + +int dCollideBP (const dxGeom *o1, const dxGeom *o2, + int flags, dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dBoxClass); + dIASSERT (o2->_class->num == dPlaneClass); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + dxBox *box = (dxBox*) CLASSDATA(o1); + dxPlane *plane = (dxPlane*) CLASSDATA(o2); + int ret = 0; + + //@@@ problem: using 4-vector (plane->p) as 3-vector (normal). + const dReal *R = o1->R; // rotation of box + const dReal *n = plane->p; // normal vector + + // project sides lengths along normal vector, get absolute values + dReal Q1 = dDOT14(n,R+0); + dReal Q2 = dDOT14(n,R+1); + dReal Q3 = dDOT14(n,R+2); + dReal A1 = box->side[0] * Q1; + dReal A2 = box->side[1] * Q2; + dReal A3 = box->side[2] * Q3; + dReal B1 = dFabs(A1); + dReal B2 = dFabs(A2); + dReal B3 = dFabs(A3); + + // early exit test + dReal depth = plane->p[3] + REAL(0.5)*(B1+B2+B3) - dDOT(n,o1->pos); + if (depth < 0) return 0; + + // find number of contacts requested + int maxc = flags & NUMC_MASK; + if (maxc < 1) maxc = 1; + if (maxc > 3) maxc = 3; // no more than 3 contacts per box allowed + + // find deepest point + dVector3 p; + p[0] = o1->pos[0]; + p[1] = o1->pos[1]; + p[2] = o1->pos[2]; +#define FOO(i,op) \ + p[0] op REAL(0.5)*box->side[i] * R[0+i]; \ + p[1] op REAL(0.5)*box->side[i] * R[4+i]; \ + p[2] op REAL(0.5)*box->side[i] * R[8+i]; +#define BAR(i,iinc) if (A ## iinc > 0) { FOO(i,-=) } else { FOO(i,+=) } + BAR(0,1); + BAR(1,2); + BAR(2,3); +#undef FOO +#undef BAR + + // the deepest point is the first contact point + contact->pos[0] = p[0]; + contact->pos[1] = p[1]; + contact->pos[2] = p[2]; + contact->normal[0] = n[0]; + contact->normal[1] = n[1]; + contact->normal[2] = n[2]; + contact->depth = depth; + ret = 1; // ret is number of contact points found so far + if (maxc == 1) goto done; + + // get the second and third contact points by starting from `p' and going + // along the two sides with the smallest projected length. + +#define FOO(i,j,op) \ + CONTACT(contact,i*skip)->pos[0] = p[0] op box->side[j] * R[0+j]; \ + CONTACT(contact,i*skip)->pos[1] = p[1] op box->side[j] * R[4+j]; \ + CONTACT(contact,i*skip)->pos[2] = p[2] op box->side[j] * R[8+j]; +#define BAR(ctact,side,sideinc) \ + depth -= B ## sideinc; \ + if (depth < 0) goto done; \ + if (A ## sideinc > 0) { FOO(ctact,side,+) } else { FOO(ctact,side,-) } \ + CONTACT(contact,ctact*skip)->depth = depth; \ + ret++; + + CONTACT(contact,skip)->normal[0] = n[0]; + CONTACT(contact,skip)->normal[1] = n[1]; + CONTACT(contact,skip)->normal[2] = n[2]; + if (maxc == 3) { + CONTACT(contact,2*skip)->normal[0] = n[0]; + CONTACT(contact,2*skip)->normal[1] = n[1]; + CONTACT(contact,2*skip)->normal[2] = n[2]; + } + + if (B1 < B2) { + if (B3 < B1) goto use_side_3; else { + BAR(1,0,1); // use side 1 + if (maxc == 2) goto done; + if (B2 < B3) goto contact2_2; else goto contact2_3; + } + } + else { + if (B3 < B2) { + use_side_3: // use side 3 + BAR(1,2,3); + if (maxc == 2) goto done; + if (B1 < B2) goto contact2_1; else goto contact2_2; + } + else { + BAR(1,1,2); // use side 2 + if (maxc == 2) goto done; + if (B1 < B3) goto contact2_1; else goto contact2_3; + } + } + + contact2_1: BAR(2,0,1); goto done; + contact2_2: BAR(2,1,2); goto done; + contact2_3: BAR(2,2,3); goto done; +#undef FOO +#undef BAR + + done: + for (int i=0; ig1 = const_cast (o1); + CONTACT(contact,i*skip)->g2 = const_cast (o2); + } + return ret; +} + + +int dCollideCS (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dCCylinderClass); + dIASSERT (o2->_class->num == dSphereClass); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + dxCCylinder *ccyl = (dxCCylinder*) CLASSDATA(o1); + dxSphere *sphere = (dxSphere*) CLASSDATA(o2); + + // find the point on the cylinder axis that is closest to the sphere + dReal alpha = + o1->R[2] * (o2->pos[0] - o1->pos[0]) + + o1->R[6] * (o2->pos[1] - o1->pos[1]) + + o1->R[10] * (o2->pos[2] - o1->pos[2]); + dReal lz2 = ccyl->lz * REAL(0.5); + if (alpha > lz2) alpha = lz2; + if (alpha < -lz2) alpha = -lz2; + + // collide the spheres + dVector3 p; + p[0] = o1->pos[0] + alpha * o1->R[2]; + p[1] = o1->pos[1] + alpha * o1->R[6]; + p[2] = o1->pos[2] + alpha * o1->R[10]; + return dCollideSpheres (p,ccyl->radius,o2->pos,sphere->radius,contact); +} + + +int dCollideCB (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dCCylinderClass); + dIASSERT (o2->_class->num == dBoxClass); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + dxCCylinder *cyl = (dxCCylinder*) CLASSDATA(o1); + dxBox *box = (dxBox*) CLASSDATA(o2); + + // get p1,p2 = cylinder axis endpoints, get radius + dVector3 p1,p2; + dReal clen = cyl->lz * REAL(0.5); + p1[0] = o1->pos[0] + clen * o1->R[2]; + p1[1] = o1->pos[1] + clen * o1->R[6]; + p1[2] = o1->pos[2] + clen * o1->R[10]; + p2[0] = o1->pos[0] - clen * o1->R[2]; + p2[1] = o1->pos[1] - clen * o1->R[6]; + p2[2] = o1->pos[2] - clen * o1->R[10]; + dReal radius = cyl->radius; + + // copy out box center, rotation matrix, and side array + dReal *c = o2->pos; + dReal *R = o2->R; + dReal *side = box->side; + + // get the closest point between the cylinder axis and the box + dVector3 pl,pb; + dClosestLineBoxPoints (p1,p2,c,R,side,pl,pb); + + // generate contact point + return dCollideSpheres (pl,radius,pb,0,contact); +} + + +// this returns at most one contact point when the two cylinder's axes are not +// aligned, and at most two (for stability) when they are aligned. +// the algorithm minimizes the distance between two "sample spheres" that are +// positioned along the cylinder axes according to: +// sphere1 = pos1 + alpha1 * axis1 +// sphere2 = pos2 + alpha2 * axis2 +// alpha1 and alpha2 are limited to +/- half the length of the cylinders. +// the algorithm works by finding a solution that has both alphas free, or +// a solution that has one or both alphas fixed to the ends of the cylinder. + +int dCollideCC (const dxGeom *o1, const dxGeom *o2, + int flags, dContactGeom *contact, int skip) +{ + int i; + const dReal tolerance = REAL(1e-5); + + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dCCylinderClass); + dIASSERT (o2->_class->num == dCCylinderClass); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + dxCCylinder *cyl1 = (dxCCylinder*) CLASSDATA(o1); + dxCCylinder *cyl2 = (dxCCylinder*) CLASSDATA(o2); + + // copy out some variables, for convenience + dReal lz1 = cyl1->lz * REAL(0.5); + dReal lz2 = cyl2->lz * REAL(0.5); + dReal *pos1 = o1->pos; + dReal *pos2 = o2->pos; + dReal axis1[3],axis2[3]; + axis1[0] = o1->R[2]; + axis1[1] = o1->R[6]; + axis1[2] = o1->R[10]; + axis2[0] = o2->R[2]; + axis2[1] = o2->R[6]; + axis2[2] = o2->R[10]; + + dReal alpha1,alpha2,sphere1[3],sphere2[3]; + int fix1 = 0; // 0 if alpha1 is free, +/-1 to fix at +/- lz1 + int fix2 = 0; // 0 if alpha2 is free, +/-1 to fix at +/- lz2 + + for (int count=0; count<9; count++) { + // find a trial solution by fixing or not fixing the alphas + if (fix1) { + if (fix2) { + // alpha1 and alpha2 are fixed, so the solution is easy + if (fix1 > 0) alpha1 = lz1; else alpha1 = -lz1; + if (fix2 > 0) alpha2 = lz2; else alpha2 = -lz2; + for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; + } + else { + // fix alpha1 but let alpha2 be free + if (fix1 > 0) alpha1 = lz1; else alpha1 = -lz1; + for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; + alpha2 = (axis2[0]*(sphere1[0]-pos2[0]) + + axis2[1]*(sphere1[1]-pos2[1]) + + axis2[2]*(sphere1[2]-pos2[2])); + for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; + } + } + else { + if (fix2) { + // fix alpha2 but let alpha1 be free + if (fix2 > 0) alpha2 = lz2; else alpha2 = -lz2; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; + alpha1 = (axis1[0]*(sphere2[0]-pos1[0]) + + axis1[1]*(sphere2[1]-pos1[1]) + + axis1[2]*(sphere2[2]-pos1[2])); + for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; + } + else { + // let alpha1 and alpha2 be free + // compute determinant of d(d^2)\d(alpha) jacobian + dReal a1a2 = dDOT (axis1,axis2); + dReal det = REAL(1.0)-a1a2*a1a2; + if (det < tolerance) { + // the cylinder axes (almost) parallel, so we will generate up to two + // contacts. the solution matrix is rank deficient so alpha1 and + // alpha2 are related by: + // alpha2 = alpha1 + (pos1-pos2)'*axis1 (if axis1==axis2) + // or alpha2 = -(alpha1 + (pos1-pos2)'*axis1) (if axis1==-axis2) + // first compute where the two cylinders overlap in alpha1 space: + if (a1a2 < 0) { + axis2[0] = -axis2[0]; + axis2[1] = -axis2[1]; + axis2[2] = -axis2[2]; + } + dReal q[3]; + for (i=0; i<3; i++) q[i] = pos1[i]-pos2[i]; + dReal k = dDOT (axis1,q); + dReal a1lo = -lz1; + dReal a1hi = lz1; + dReal a2lo = -lz2 - k; + dReal a2hi = lz2 - k; + dReal lo = (a1lo > a2lo) ? a1lo : a2lo; + dReal hi = (a1hi < a2hi) ? a1hi : a2hi; + if (lo <= hi) { + int num_contacts = flags & NUMC_MASK; + if (num_contacts >= 2 && lo < hi) { + // generate up to two contacts. if one of those contacts is + // not made, fall back on the one-contact strategy. + for (i=0; i<3; i++) sphere1[i] = pos1[i] + lo*axis1[i]; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + (lo+k)*axis2[i]; + int n1 = dCollideSpheres (sphere1,cyl1->radius, + sphere2,cyl2->radius,contact); + if (n1) { + for (i=0; i<3; i++) sphere1[i] = pos1[i] + hi*axis1[i]; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + (hi+k)*axis2[i]; + dContactGeom *c2 = CONTACT(contact,skip); + int n2 = dCollideSpheres (sphere1,cyl1->radius, + sphere2,cyl2->radius, c2); + if (n2) { + c2->g1 = const_cast (o1); + c2->g2 = const_cast (o2); + return 2; + } + } + } + + // just one contact to generate, so put it in the middle of + // the range + alpha1 = (lo + hi) * REAL(0.5); + alpha2 = alpha1 + k; + for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; + return dCollideSpheres (sphere1,cyl1->radius, + sphere2,cyl2->radius,contact); + } + else return 0; + } + det = REAL(1.0)/det; + dReal delta[3]; + for (i=0; i<3; i++) delta[i] = pos1[i] - pos2[i]; + dReal q1 = dDOT (delta,axis1); + dReal q2 = dDOT (delta,axis2); + alpha1 = det*(a1a2*q2-q1); + alpha2 = det*(q2-a1a2*q1); + for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; + } + } + + // if the alphas are outside their allowed ranges then fix them and + // try again + if (fix1==0) { + if (alpha1 < -lz1) { + fix1 = -1; + continue; + } + if (alpha1 > lz1) { + fix1 = 1; + continue; + } + } + if (fix2==0) { + if (alpha2 < -lz2) { + fix2 = -1; + continue; + } + if (alpha2 > lz2) { + fix2 = 1; + continue; + } + } + + // unfix the alpha variables if the local distance gradient indicates + // that we are not yet at the minimum + dReal tmp[3]; + for (i=0; i<3; i++) tmp[i] = sphere1[i] - sphere2[i]; + if (fix1) { + dReal gradient = dDOT (tmp,axis1); + if ((fix1 > 0 && gradient > 0) || (fix1 < 0 && gradient < 0)) { + fix1 = 0; + continue; + } + } + if (fix2) { + dReal gradient = -dDOT (tmp,axis2); + if ((fix2 > 0 && gradient > 0) || (fix2 < 0 && gradient < 0)) { + fix2 = 0; + continue; + } + } + return dCollideSpheres (sphere1,cyl1->radius,sphere2,cyl2->radius,contact); + } + // if we go through the loop too much, then give up. we should NEVER get to + // this point (i hope). + dMessage (0,"dCollideCC(): too many iterations"); + return 0; +} + + +int dCollideCP (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dCCylinderClass); + dIASSERT (o2->_class->num == dPlaneClass); + dxCCylinder *ccyl = (dxCCylinder*) CLASSDATA(o1); + dxPlane *plane = (dxPlane*) CLASSDATA(o2); + + // collide the deepest capping sphere with the plane + dReal sign = (dDOT14 (plane->p,o1->R+2) > 0) ? REAL(-1.0) : REAL(1.0); + dVector3 p; + p[0] = o1->pos[0] + o1->R[2] * ccyl->lz * REAL(0.5) * sign; + p[1] = o1->pos[1] + o1->R[6] * ccyl->lz * REAL(0.5) * sign; + p[2] = o1->pos[2] + o1->R[10] * ccyl->lz * REAL(0.5) * sign; + + dReal k = dDOT (p,plane->p); + dReal depth = plane->p[3] - k + ccyl->radius; + if (depth < 0) return 0; + contact->normal[0] = plane->p[0]; + contact->normal[1] = plane->p[1]; + contact->normal[2] = plane->p[2]; + contact->pos[0] = p[0] - plane->p[0] * ccyl->radius; + contact->pos[1] = p[1] - plane->p[1] * ccyl->radius; + contact->pos[2] = p[2] - plane->p[2] * ccyl->radius; + contact->depth = depth; + + int ncontacts = 1; + if ((flags & NUMC_MASK) >= 2) { + // collide the other capping sphere with the plane + p[0] = o1->pos[0] - o1->R[2] * ccyl->lz * REAL(0.5) * sign; + p[1] = o1->pos[1] - o1->R[6] * ccyl->lz * REAL(0.5) * sign; + p[2] = o1->pos[2] - o1->R[10] * ccyl->lz * REAL(0.5) * sign; + + k = dDOT (p,plane->p); + depth = plane->p[3] - k + ccyl->radius; + if (depth >= 0) { + dContactGeom *c2 = CONTACT(contact,skip); + c2->normal[0] = plane->p[0]; + c2->normal[1] = plane->p[1]; + c2->normal[2] = plane->p[2]; + c2->pos[0] = p[0] - plane->p[0] * ccyl->radius; + c2->pos[1] = p[1] - plane->p[1] * ccyl->radius; + c2->pos[2] = p[2] - plane->p[2] * ccyl->radius; + c2->depth = depth; + ncontacts = 2; + } + } + + for (int i=0; i < ncontacts; i++) { + CONTACT(contact,i*skip)->g1 = const_cast (o1); + CONTACT(contact,i*skip)->g2 = const_cast (o2); + } + return ncontacts; +} + + +// this collides a group with another geom. the other geom can also be a +// group, but this case is not handled specially. + +int dCollideG (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dxGeomGroup *gr = (dxGeomGroup*) CLASSDATA(o1); + int numleft = flags & NUMC_MASK; + if (numleft == 0) numleft = 1; + flags &= ~NUMC_MASK; + int num=0,i=0; + while (i < gr->parts.size() && numleft > 0) { + int n = dCollide (gr->parts[i],const_cast(o2), + flags | numleft,contact,skip); + contact = CONTACT (contact,skip*n); + numleft -= n; + num += n; + i++; + } + return num; +} + +//**************************************************************************** +// standard classes + +SHAREDLIBEXPORT int dSphereClass = -1; +SHAREDLIBEXPORT int dBoxClass = -1; +SHAREDLIBEXPORT int dCCylinderClass = -1; +SHAREDLIBEXPORT int dPlaneClass = -1; + + +static dColliderFn * dSphereColliderFn (int num) +{ + if (num == dSphereClass) return (dColliderFn *) &dCollideSS; + if (num == dBoxClass) return (dColliderFn *) &dCollideSB; + if (num == dPlaneClass) return (dColliderFn *) &dCollideSP; + return 0; +} + + +static void dSphereAABB (dxGeom *geom, dReal aabb[6]) +{ + dxSphere *s = (dxSphere*) CLASSDATA(geom); + aabb[0] = geom->pos[0] - s->radius; + aabb[1] = geom->pos[0] + s->radius; + aabb[2] = geom->pos[1] - s->radius; + aabb[3] = geom->pos[1] + s->radius; + aabb[4] = geom->pos[2] - s->radius; + aabb[5] = geom->pos[2] + s->radius; +} + + +static dColliderFn * dBoxColliderFn (int num) +{ + if (num == dBoxClass) return (dColliderFn *) &dCollideBB; + if (num == dPlaneClass) return (dColliderFn *) &dCollideBP; + return 0; +} + + +static void dBoxAABB (dxGeom *geom, dReal aabb[6]) +{ + dxBox *b = (dxBox*) CLASSDATA(geom); + dReal xrange = REAL(0.5) * (dFabs (geom->R[0] * b->side[0]) + + dFabs (geom->R[1] * b->side[1]) + dFabs (geom->R[2] * b->side[2])); + dReal yrange = REAL(0.5) * (dFabs (geom->R[4] * b->side[0]) + + dFabs (geom->R[5] * b->side[1]) + dFabs (geom->R[6] * b->side[2])); + dReal zrange = REAL(0.5) * (dFabs (geom->R[8] * b->side[0]) + + dFabs (geom->R[9] * b->side[1]) + dFabs (geom->R[10] * b->side[2])); + aabb[0] = geom->pos[0] - xrange; + aabb[1] = geom->pos[0] + xrange; + aabb[2] = geom->pos[1] - yrange; + aabb[3] = geom->pos[1] + yrange; + aabb[4] = geom->pos[2] - zrange; + aabb[5] = geom->pos[2] + zrange; +} + + +static dColliderFn * dCCylinderColliderFn (int num) +{ + if (num == dSphereClass) return (dColliderFn *) &dCollideCS; + if (num == dPlaneClass) return (dColliderFn *) &dCollideCP; + if (num == dCCylinderClass) return (dColliderFn *) &dCollideCC; + if (num == dBoxClass) return (dColliderFn *) &dCollideCB; + return 0; +} + + +static void dCCylinderAABB (dxGeom *geom, dReal aabb[6]) +{ + dxCCylinder *c = (dxCCylinder*) CLASSDATA(geom); + dReal xrange = dFabs(geom->R[2] * c->lz) * REAL(0.5) + c->radius; + dReal yrange = dFabs(geom->R[6] * c->lz) * REAL(0.5) + c->radius; + dReal zrange = dFabs(geom->R[10] * c->lz) * REAL(0.5) + c->radius; + aabb[0] = geom->pos[0] - xrange; + aabb[1] = geom->pos[0] + xrange; + aabb[2] = geom->pos[1] - yrange; + aabb[3] = geom->pos[1] + yrange; + aabb[4] = geom->pos[2] - zrange; + aabb[5] = geom->pos[2] + zrange; +} + + +dColliderFn * dPlaneColliderFn (int num) +{ + return 0; +} + + +static void dPlaneAABB (dxGeom *geom, dReal aabb[6]) +{ + // @@@ planes that have normal vectors aligned along an axis can use a + // @@@ less comprehensive bounding box. + aabb[0] = -dInfinity; + aabb[1] = dInfinity; + aabb[2] = -dInfinity; + aabb[3] = dInfinity; + aabb[4] = -dInfinity; + aabb[5] = dInfinity; +} + + +dxGeom *dCreateSphere (dSpaceID space, dReal radius) +{ + dAASSERT (radius > 0); + if (dSphereClass == -1) { + dGeomClass c; + c.bytes = sizeof (dxSphere); + c.collider = &dSphereColliderFn; + c.aabb = &dSphereAABB; + c.aabb_test = 0; + c.dtor = 0; + dSphereClass = dCreateGeomClass (&c); + } + + dxGeom *g = dCreateGeom (dSphereClass); + if (space) dSpaceAdd (space,g); + dxSphere *s = (dxSphere*) CLASSDATA(g); + s->radius = radius; + return g; +} + + +dxGeom *dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz) +{ + dAASSERT (lx > 0 && ly > 0 && lz > 0); + if (dBoxClass == -1) { + dGeomClass c; + c.bytes = sizeof (dxBox); + c.collider = &dBoxColliderFn; + c.aabb = &dBoxAABB; + c.aabb_test = 0; + c.dtor = 0; + dBoxClass = dCreateGeomClass (&c); + } + + dxGeom *g = dCreateGeom (dBoxClass); + if (space) dSpaceAdd (space,g); + dxBox *b = (dxBox*) CLASSDATA(g); + b->side[0] = lx; + b->side[1] = ly; + b->side[2] = lz; + return g; +} + + +dxGeom * dCreateCCylinder (dSpaceID space, dReal radius, dReal length) +{ + dAASSERT (radius > 0 && length > 0); + if (dCCylinderClass == -1) { + dGeomClass c; + c.bytes = sizeof (dxCCylinder); + c.collider = &dCCylinderColliderFn; + c.aabb = &dCCylinderAABB; + c.aabb_test = 0; + c.dtor = 0; + dCCylinderClass = dCreateGeomClass (&c); + } + + dxGeom *g = dCreateGeom (dCCylinderClass); + if (space) dSpaceAdd (space,g); + dxCCylinder *c = (dxCCylinder*) CLASSDATA(g); + c->radius = radius; + c->lz = length; + return g; +} + + +dxGeom *dCreatePlane (dSpaceID space, + dReal a, dReal b, dReal c, dReal d) +{ + if (dPlaneClass == -1) { + dGeomClass c; + c.bytes = sizeof (dxPlane); + c.collider = &dPlaneColliderFn; + c.aabb = &dPlaneAABB; + c.aabb_test = 0; + c.dtor = 0; + dPlaneClass = dCreateGeomClass (&c); + } + + dxGeom *g = dCreateGeom (dPlaneClass); + if (space) dSpaceAdd (space,g); + dxPlane *p = (dxPlane*) CLASSDATA(g); + + // make sure plane normal has unit length + dReal l = a*a + b*b + c*c; + if (l > 0) { + l = dRecipSqrt(l); + p->p[0] = a*l; + p->p[1] = b*l; + p->p[2] = c*l; + p->p[3] = d*l; + } + else { + p->p[0] = 1; + p->p[1] = 0; + p->p[2] = 0; + p->p[3] = 0; + } + return g; +} + + +void dGeomSphereSetRadius (dGeomID g, dReal radius) +{ + dUASSERT (g && g->_class->num == dSphereClass,"argument not a sphere"); + dAASSERT (radius > 0); + dxSphere *s = (dxSphere*) CLASSDATA(g); + s->radius = radius; +} + + +void dGeomBoxSetLengths (dGeomID g, dReal lx, dReal ly, dReal lz) +{ + dUASSERT (g && g->_class->num == dBoxClass,"argument not a box"); + dAASSERT (lx > 0 && ly > 0 && lz > 0); + dxBox *b = (dxBox*) CLASSDATA(g); + b->side[0] = lx; + b->side[1] = ly; + b->side[2] = lz; +} + + +void dGeomPlaneSetParams (dGeomID g, dReal a, dReal b, dReal c, dReal d) +{ + dUASSERT (g && g->_class->num == dPlaneClass,"argument not a plane"); + dxPlane *p = (dxPlane*) CLASSDATA(g); + p->p[0] = a; + p->p[1] = b; + p->p[2] = c; + p->p[3] = d; +} + + +void dGeomCCylinderSetParams (dGeomID g, dReal radius, dReal length) +{ + dUASSERT (g && g->_class->num == dCCylinderClass,"argument not a ccylinder"); + dAASSERT (radius > 0 && length > 0); + dxCCylinder *c = (dxCCylinder*) CLASSDATA(g); + c->radius = radius; + c->lz = length; +} + + +dReal dGeomSphereGetRadius (dGeomID g) +{ + dUASSERT (g && g->_class->num == dSphereClass,"argument not a sphere"); + dxSphere *s = (dxSphere*) CLASSDATA(g); + return s->radius; +} + + +void dGeomBoxGetLengths (dGeomID g, dVector3 result) +{ + dUASSERT (g && g->_class->num == dBoxClass,"argument not a box"); + dxBox *b = (dxBox*) CLASSDATA(g); + result[0] = b->side[0]; + result[1] = b->side[1]; + result[2] = b->side[2]; +} + + +void dGeomPlaneGetParams (dGeomID g, dVector4 result) +{ + dUASSERT (g && g->_class->num == dPlaneClass,"argument not a plane"); + dxPlane *p = (dxPlane*) CLASSDATA(g); + result[0] = p->p[0]; + result[1] = p->p[1]; + result[2] = p->p[2]; + result[3] = p->p[3]; +} + + +void dGeomCCylinderGetParams (dGeomID g, dReal *radius, dReal *length) +{ + dUASSERT (g && g->_class->num == dCCylinderClass,"argument not a ccylinder"); + dxCCylinder *c = (dxCCylinder*) CLASSDATA(g); + *radius = c->radius; + *length = c->lz; +} + +//**************************************************************************** +// geom group + +int dGeomGroupClass = -1; + +static dColliderFn * dGeomGroupColliderFn (int num) +{ + return (dColliderFn *) &dCollideG; +} + + +static void dGeomGroupAABB (dxGeom *geom, dReal aabb[6]) +{ + dxGeomGroup *gr = (dxGeomGroup*) CLASSDATA(geom); + aabb[0] = dInfinity; + aabb[1] = -dInfinity; + aabb[2] = dInfinity; + aabb[3] = -dInfinity; + aabb[4] = dInfinity; + aabb[5] = -dInfinity; + int i,j; + for (i=0; i < gr->parts.size(); i++) { + dReal aabb2[6]; + gr->parts[i]->_class->aabb (gr->parts[i],aabb2); + for (j=0; j<6; j += 2) if (aabb2[j] < aabb[j]) aabb[j] = aabb2[j]; + for (j=1; j<6; j += 2) if (aabb2[j] > aabb[j]) aabb[j] = aabb2[j]; + } +} + + +static void dGeomGroupDtor (dxGeom *geom) +{ + dxGeomGroup *gr = (dxGeomGroup*) CLASSDATA(geom); + gr->parts.~dArray(); +} + + +dxGeom *dCreateGeomGroup (dSpaceID space) +{ + if (dGeomGroupClass == -1) { + dGeomClass c; + c.bytes = sizeof (dxGeomGroup); + c.collider = &dGeomGroupColliderFn; + c.aabb = &dGeomGroupAABB; + c.aabb_test = 0; + c.dtor = &dGeomGroupDtor; + dGeomGroupClass = dCreateGeomClass (&c); + } + + dxGeom *g = dCreateGeom (dGeomGroupClass); + if (space) dSpaceAdd (space,g); + dxGeomGroup *gr = (dxGeomGroup*) CLASSDATA(g); + gr->parts.constructor(); + return g; +} + + +void dGeomGroupAdd (dxGeom *g, dxGeom *x) +{ + dUASSERT (g && g->_class->num == dGeomGroupClass,"argument not a geomgroup"); + dxGeomGroup *gr = (dxGeomGroup*) CLASSDATA(g); + gr->parts.push (x); +} + + +void dGeomGroupRemove (dxGeom *g, dxGeom *x) +{ + dUASSERT (g && g->_class->num == dGeomGroupClass,"argument not a geomgroup"); + dxGeomGroup *gr = (dxGeomGroup*) CLASSDATA(g); + for (int i=0; i < gr->parts.size(); i++) { + if (gr->parts[i] == x) { + gr->parts.remove (i); + return; + } + } +} + + +int dGeomGroupGetNumGeoms (dxGeom *g) +{ + dUASSERT (g && g->_class->num == dGeomGroupClass,"argument not a geomgroup"); + dxGeomGroup *gr = (dxGeomGroup*) CLASSDATA(g); + return gr->parts.size(); +} + + +dxGeom * dGeomGroupGetGeom (dxGeom *g, int i) +{ + dUASSERT (g && g->_class->num == dGeomGroupClass,"argument not a geomgroup"); + dxGeomGroup *gr = (dxGeomGroup*) CLASSDATA(g); + dAASSERT (i >= 0 && i < gr->parts.size()); + return gr->parts[i]; +} + +//**************************************************************************** +// transformed geom + +int dGeomTransformClass = -1; + +struct dxGeomTransform { + dxGeom *obj; // object that is being transformed + int cleanup; // 1 to destroy obj when destroyed + int infomode; // 1 to put Tx geom in dContactGeom g1 + dVector3 final_pos; // final tx (body tx + relative tx) of the object. + dMatrix3 final_R; // this is only set if the AABB function is called +}; // by space collision before the collide fn is called + + +// compute final pos and R for the encapsulated geom object + +static void compute_final_tx (const dxGeom *g) +{ + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(g); + dMULTIPLY0_331 (tr->final_pos,g->R,tr->obj->pos); + tr->final_pos[0] += g->pos[0]; + tr->final_pos[1] += g->pos[1]; + tr->final_pos[2] += g->pos[2]; + dMULTIPLY0_333 (tr->final_R,g->R,tr->obj->R); +} + + + +// this collides a transformed geom with another geom. the other geom can +// also be a transformed geom, but this case is not handled specially. + +int dCollideT (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(o1); + if (!tr->obj) return 0; + dUASSERT (tr->obj->spaceid==0, + "GeomTransform encapsulated object must not be in a space"); + dUASSERT (tr->obj->body==0, + "GeomTransform encapsulated object must not be attach to a body"); + + // backup the relative pos and R pointers of the encapsulated geom object, + // and the body pointer + dReal *posbak = tr->obj->pos; + dReal *Rbak = tr->obj->R; + dxBody *bodybak = tr->obj->body; + + // compute temporary pos and R for the encapsulated geom object + if (!o1->space_aabb) compute_final_tx (o1); + tr->obj->pos = tr->final_pos; + tr->obj->R = tr->final_R; + tr->obj->body = o1->body; + + // do the collision + int n = dCollide (tr->obj,const_cast(o2),flags,contact,skip); + + // if required, adjust the 'g1' values in the generated contacts so that + // thay indicated the GeomTransform object instead of the encapsulated + // object. + if (tr->infomode) { + for (int i=0; ig1 = const_cast (o1); + } + } + + // restore the pos, R and body + tr->obj->pos = posbak; + tr->obj->R = Rbak; + tr->obj->body = bodybak; + return n; +} + + +static dColliderFn * dGeomTransformColliderFn (int num) +{ + return (dColliderFn *) &dCollideT; +} + + +static void dGeomTransformAABB (dxGeom *geom, dReal aabb[6]) +{ + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(geom); + if (!tr->obj) { + dSetZero (aabb,6); + return; + } + + // backup the relative pos and R pointers of the encapsulated geom object + dReal *posbak = tr->obj->pos; + dReal *Rbak = tr->obj->R; + + // compute temporary pos and R for the encapsulated geom object + compute_final_tx (geom); + tr->obj->pos = tr->final_pos; + tr->obj->R = tr->final_R; + + // compute the AABB + tr->obj->_class->aabb (tr->obj,aabb); + + // restore the pos and R + tr->obj->pos = posbak; + tr->obj->R = Rbak; +} + + +static void dGeomTransformDtor (dxGeom *geom) +{ + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(geom); + if (tr->obj && tr->cleanup) { + dGeomDestroy (tr->obj); + } +} + + +dxGeom *dCreateGeomTransform (dSpaceID space) +{ + if (dGeomTransformClass == -1) { + dGeomClass c; + c.bytes = sizeof (dxGeomTransform); + c.collider = &dGeomTransformColliderFn; + c.aabb = &dGeomTransformAABB; + c.aabb_test = 0; + c.dtor = dGeomTransformDtor; + dGeomTransformClass = dCreateGeomClass (&c); + } + + dxGeom *g = dCreateGeom (dGeomTransformClass); + if (space) dSpaceAdd (space,g); + + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(g); + tr->obj = 0; + tr->cleanup = 0; + tr->infomode = 0; + dSetZero (tr->final_pos,4); + dRSetIdentity (tr->final_R); + + return g; +} + + +void dGeomTransformSetGeom (dxGeom *g, dxGeom *obj) +{ + dUASSERT (g && g->_class->num == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(g); + if (tr->obj && tr->cleanup) { + dGeomDestroy (tr->obj); + } + tr->obj = obj; +} + + +dxGeom * dGeomTransformGetGeom (dxGeom *g) +{ + dUASSERT (g && g->_class->num == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(g); + return tr->obj; +} + + +void dGeomTransformSetCleanup (dGeomID g, int mode) +{ + dUASSERT (g && g->_class->num == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(g); + tr->cleanup = mode; +} + + +int dGeomTransformGetCleanup (dGeomID g) +{ + dUASSERT (g && g->_class->num == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(g); + return tr->cleanup; +} + + +void dGeomTransformSetInfo (dGeomID g, int mode) +{ + dUASSERT (g && g->_class->num == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(g); + tr->infomode = mode; +} + + +int dGeomTransformGetInfo (dGeomID g) +{ + dUASSERT (g && g->_class->num == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) CLASSDATA(g); + return tr->infomode; +} + +//**************************************************************************** +// other utility functions + +void dInfiniteAABB (dxGeom *geom, dReal aabb[6]) +{ + aabb[0] = -dInfinity; + aabb[1] = dInfinity; + aabb[2] = -dInfinity; + aabb[3] = dInfinity; + aabb[4] = -dInfinity; + aabb[5] = dInfinity; +} + + +void dCloseODE() +{ + if (colliders) { + delete colliders; + colliders = 0; + } + if (classes) { + for (int i=0; i < classes->size(); i++) { + dFree ((*classes)[i], sizeof (dxGeomClass)); + } + delete classes; + classes = 0; + } + + // reset geom class vars + dSphereClass = -1; + dBoxClass = -1; + dCCylinderClass = -1; + dPlaneClass = -1; + dGeomGroupClass = -1; + dGeomTransformClass = -1; + + // if you're using contrib code you may want to uncomment the following: + // dTriListClass = -1; + // dRayClass = -1; +} diff --git a/extern/ode/dist/ode/src/geom_internal.h b/extern/ode/dist/ode/src/geom_internal.h new file mode 100644 index 00000000000..63be589ffe0 --- /dev/null +++ b/extern/ode/dist/ode/src/geom_internal.h @@ -0,0 +1,83 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_GEOM_INTERNAL_H_ +#define _ODE_GEOM_INTERNAL_H_ + + +// mask for the number-of-contacts field in the dCollide() flags parameter +#define NUMC_MASK (0xffff) + + +// internal info for geometry class + +struct dxGeomClass { + dGetColliderFnFn *collider; + dGetAABBFn *aabb; + dAABBTestFn *aabb_test; + dGeomDtorFn *dtor; + int num; // class number + int size; // total size of object, including extra data area +}; + + +// position vector and rotation matrix for geometry objects that are not +// connected to bodies. + +struct dxPosR { + dVector3 pos; + dMatrix3 R; +}; + + +// common data for all geometry objects. the class-specific data area follows +// this structure. pos and R will either point to a separately allocated +// buffer (if body is 0 - pos points to the dxPosR object) or to the pos and +// R of the body (if body nonzero). + +struct dxGeom { // a dGeomID is a pointer to this + dxGeomClass *_class; // class of this object + void *data; // user data pointer + dBodyID body; // dynamics body associated with this object (if any) + dReal *pos; // pointer to object's position vector + dReal *R; // pointer to object's rotation matrix + dSpaceID spaceid; // the space this object is in + dGeomSpaceData space; // reserved for use by space this object is in + dReal *space_aabb; // ptr to aabb array held by dSpaceCollide() fn + // class-specific data follows here, with proper alignment. +}; + + +// this is the size of the dxGeom structure rounded up to a multiple of 16 +// bytes. any class specific data that comes after this will have the correct +// alignment. + +#define SIZEOF_DXGEOM dEFFICIENT_SIZE(sizeof(dxGeom)) + + +// given a pointer to a dxGeom, return a pointer to the class data that +// follows it. + +#define CLASSDATA(geomptr) (((char*)geomptr) + SIZEOF_DXGEOM) + +#endif + diff --git a/extern/ode/dist/ode/src/joint.cpp b/extern/ode/dist/ode/src/joint.cpp new file mode 100644 index 00000000000..74e4c34cc71 --- /dev/null +++ b/extern/ode/dist/ode/src/joint.cpp @@ -0,0 +1,2160 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +design note: the general principle for giving a joint the option of connecting +to the static environment (i.e. the absolute frame) is to check the second +body (joint->node[1].body), and if it is zero then behave as if its body +transform is the identity. + +*/ + +#include +#include +#include +#include "joint.h" + +//**************************************************************************** +// externs + +extern "C" void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); +extern "C" void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); + +//**************************************************************************** +// utility + +// set three "ball-and-socket" rows in the constraint equation, and the +// corresponding right hand side. + +static inline void setBall (dxJoint *joint, dxJoint::Info2 *info, + dVector3 anchor1, dVector3 anchor2) +{ + // anchor points in global coordinates with respect to body PORs. + dVector3 a1,a2; + + int s = info->rowskip; + + // set jacobian + info->J1l[0] = 1; + info->J1l[s+1] = 1; + info->J1l[2*s+2] = 1; + dMULTIPLY0_331 (a1,joint->node[0].body->R,anchor1); + dCROSSMAT (info->J1a,a1,s,-,+); + if (joint->node[1].body) { + info->J2l[0] = -1; + info->J2l[s+1] = -1; + info->J2l[2*s+2] = -1; + dMULTIPLY0_331 (a2,joint->node[1].body->R,anchor2); + dCROSSMAT (info->J2a,a2,s,+,-); + } + + // set right hand side + dReal k = info->fps * info->erp; + if (joint->node[1].body) { + for (int j=0; j<3; j++) { + info->c[j] = k * (a2[j] + joint->node[1].body->pos[j] - + a1[j] - joint->node[0].body->pos[j]); + } + } + else { + for (int j=0; j<3; j++) { + info->c[j] = k * (anchor2[j] - a1[j] - + joint->node[0].body->pos[j]); + } + } +} + + +// this is like setBall(), except that `axis' is a unit length vector +// (in global coordinates) that should be used for the first jacobian +// position row (the other two row vectors will be derived from this). +// `erp1' is the erp value to use along the axis. + +static inline void setBall2 (dxJoint *joint, dxJoint::Info2 *info, + dVector3 anchor1, dVector3 anchor2, + dVector3 axis, dReal erp1) +{ + // anchor points in global coordinates with respect to body PORs. + dVector3 a1,a2; + + int i,s = info->rowskip; + + // get vectors normal to the axis. in setBall() axis,q1,q2 is [1 0 0], + // [0 1 0] and [0 0 1], which makes everything much easier. + dVector3 q1,q2; + dPlaneSpace (axis,q1,q2); + + // set jacobian + for (i=0; i<3; i++) info->J1l[i] = axis[i]; + for (i=0; i<3; i++) info->J1l[s+i] = q1[i]; + for (i=0; i<3; i++) info->J1l[2*s+i] = q2[i]; + dMULTIPLY0_331 (a1,joint->node[0].body->R,anchor1); + dCROSS (info->J1a,=,a1,axis); + dCROSS (info->J1a+s,=,a1,q1); + dCROSS (info->J1a+2*s,=,a1,q2); + if (joint->node[1].body) { + for (i=0; i<3; i++) info->J2l[i] = -axis[i]; + for (i=0; i<3; i++) info->J2l[s+i] = -q1[i]; + for (i=0; i<3; i++) info->J2l[2*s+i] = -q2[i]; + dMULTIPLY0_331 (a2,joint->node[1].body->R,anchor2); + dCROSS (info->J2a,= -,a2,axis); + dCROSS (info->J2a+s,= -,a2,q1); + dCROSS (info->J2a+2*s,= -,a2,q2); + } + + // set right hand side - measure error along (axis,q1,q2) + dReal k1 = info->fps * erp1; + dReal k = info->fps * info->erp; + + for (i=0; i<3; i++) a1[i] += joint->node[0].body->pos[i]; + if (joint->node[1].body) { + for (i=0; i<3; i++) a2[i] += joint->node[1].body->pos[i]; + info->c[0] = k1 * (dDOT(axis,a2) - dDOT(axis,a1)); + info->c[1] = k * (dDOT(q1,a2) - dDOT(q1,a1)); + info->c[2] = k * (dDOT(q2,a2) - dDOT(q2,a1)); + } + else { + info->c[0] = k1 * (dDOT(axis,anchor2) - dDOT(axis,a1)); + info->c[1] = k * (dDOT(q1,anchor2) - dDOT(q1,a1)); + info->c[2] = k * (dDOT(q2,anchor2) - dDOT(q2,a1)); + } +} + + +// compute anchor points relative to bodies + +static void setAnchors (dxJoint *j, dReal x, dReal y, dReal z, + dVector3 anchor1, dVector3 anchor2) +{ + if (j->node[0].body) { + dReal q[4]; + q[0] = x - j->node[0].body->pos[0]; + q[1] = y - j->node[0].body->pos[1]; + q[2] = z - j->node[0].body->pos[2]; + q[3] = 0; + dMULTIPLY1_331 (anchor1,j->node[0].body->R,q); + if (j->node[1].body) { + q[0] = x - j->node[1].body->pos[0]; + q[1] = y - j->node[1].body->pos[1]; + q[2] = z - j->node[1].body->pos[2]; + q[3] = 0; + dMULTIPLY1_331 (anchor2,j->node[1].body->R,q); + } + else { + anchor2[0] = x; + anchor2[1] = y; + anchor2[2] = z; + } + } + anchor1[3] = 0; + anchor2[3] = 0; +} + + +// compute axes relative to bodies. axis2 can be 0 + +static void setAxes (dxJoint *j, dReal x, dReal y, dReal z, + dVector3 axis1, dVector3 axis2) +{ + if (j->node[0].body) { + dReal q[4]; + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = 0; + dNormalize3 (q); + dMULTIPLY1_331 (axis1,j->node[0].body->R,q); + if (axis2) { + if (j->node[1].body) { + dMULTIPLY1_331 (axis2,j->node[1].body->R,q); + } + else { + axis2[0] = x; + axis2[1] = y; + axis2[2] = z; + } + axis2[3] = 0; + } + } + axis1[3] = 0; +} + + +static void getAnchor (dxJoint *j, dVector3 result, dVector3 anchor1) +{ + if (j->node[0].body) { + dMULTIPLY0_331 (result,j->node[0].body->R,anchor1); + result[0] += j->node[0].body->pos[0]; + result[1] += j->node[0].body->pos[1]; + result[2] += j->node[0].body->pos[2]; + } +} + + +static void getAxis (dxJoint *j, dVector3 result, dVector3 axis1) +{ + if (j->node[0].body) { + dMULTIPLY0_331 (result,j->node[0].body->R,axis1); + } +} + + +// given two bodies (body1,body2), the hinge axis that they are connected by +// w.r.t. body1 (axis), and the initial relative orientation between them +// (q_initial), return the relative rotation angle. the initial relative +// orientation corresponds to an angle of zero. if body2 is 0 then measure the +// angle between body1 and the static frame. +// +// this will not return the correct angle if the bodies rotate along any axis +// other than the given hinge axis. + +static dReal getHingeAngle (dxBody *body1, dxBody *body2, dVector3 axis, + dQuaternion q_initial) +{ + // the angle between the two bodies is extracted from the quaternion that + // represents the relative rotation between them. recall that a quaternion + // q is: + // [s,v] = [ cos(theta/2) , sin(theta/2) * u ] + // where s is a scalar and v is a 3-vector. u is a unit length axis and + // theta is a rotation along that axis. we can get theta/2 by: + // theta/2 = atan2 ( sin(theta/2) , cos(theta/2) ) + // but we can't get sin(theta/2) directly, only its absolute value, i.e.: + // |v| = |sin(theta/2)| * |u| + // = |sin(theta/2)| + // using this value will have a strange effect. recall that there are two + // quaternion representations of a given rotation, q and -q. typically as + // a body rotates along the axis it will go through a complete cycle using + // one representation and then the next cycle will use the other + // representation. this corresponds to u pointing in the direction of the + // hinge axis and then in the opposite direction. the result is that theta + // will appear to go "backwards" every other cycle. here is a fix: if u + // points "away" from the direction of the hinge (motor) axis (i.e. more + // than 90 degrees) then use -q instead of q. this represents the same + // rotation, but results in the cos(theta/2) value being sign inverted. + + // get qrel = relative rotation between the two bodies + dQuaternion qrel; + if (body2) { + dQuaternion qq; + dQMultiply1 (qq,body1->q,body2->q); + dQMultiply2 (qrel,qq,q_initial); + } + else { + // pretend body2->q is the identity + dQMultiply3 (qrel,body1->q,q_initial); + } + + // extract the angle from the quaternion. cost2 = cos(theta/2), + // sint2 = |sin(theta/2)| + dReal cost2 = qrel[0]; + dReal sint2 = dSqrt (qrel[1]*qrel[1]+qrel[2]*qrel[2]+qrel[3]*qrel[3]); + dReal theta = (dDOT(qrel+1,axis) >= 0) ? // @@@ padding assumptions + (2 * dAtan2(sint2,cost2)) : // if u points in direction of axis + (2 * dAtan2(sint2,-cost2)); // if u points in opposite direction + + // the angle we get will be between 0..2*pi, but we want to return angles + // between -pi..pi + if (theta > M_PI) theta -= 2*M_PI; + + // the angle we've just extracted has the wrong sign + theta = -theta; + + return theta; +} + +//**************************************************************************** +// dxJointLimitMotor + +void dxJointLimitMotor::init (dxWorld *world) +{ + vel = 0; + fmax = 0; + lostop = -dInfinity; + histop = dInfinity; + fudge_factor = 1; + normal_cfm = world->global_cfm; + stop_erp = world->global_erp; + stop_cfm = world->global_cfm; + bounce = 0; + limit = 0; + limit_err = 0; +} + + +void dxJointLimitMotor::set (int num, dReal value) +{ + switch (num) { + case dParamLoStop: + if (value <= histop) lostop = value; + break; + case dParamHiStop: + if (value >= lostop) histop = value; + break; + case dParamVel: + vel = value; + break; + case dParamFMax: + if (value >= 0) fmax = value; + break; + case dParamFudgeFactor: + if (value >= 0 && value <= 1) fudge_factor = value; + break; + case dParamBounce: + bounce = value; + break; + case dParamCFM: + normal_cfm = value; + break; + case dParamStopERP: + stop_erp = value; + break; + case dParamStopCFM: + stop_cfm = value; + break; + } +} + + +dReal dxJointLimitMotor::get (int num) +{ + switch (num) { + case dParamLoStop: return lostop; + case dParamHiStop: return histop; + case dParamVel: return vel; + case dParamFMax: return fmax; + case dParamFudgeFactor: return fudge_factor; + case dParamBounce: return bounce; + case dParamCFM: return normal_cfm; + case dParamStopERP: return stop_erp; + case dParamStopCFM: return stop_cfm; + default: return 0; + } +} + + +int dxJointLimitMotor::testRotationalLimit (dReal angle) +{ + if (angle <= lostop) { + limit = 1; + limit_err = angle - lostop; + return 1; + } + else if (angle >= histop) { + limit = 2; + limit_err = angle - histop; + return 1; + } + else { + limit = 0; + return 0; + } +} + + +int dxJointLimitMotor::addLimot (dxJoint *joint, + dxJoint::Info2 *info, int row, + dVector3 ax1, int rotational) +{ + int srow = row * info->rowskip; + + // if the joint is powered, or has joint limits, add in the extra row + int powered = fmax > 0; + if (powered || limit) { + dReal *J1 = rotational ? info->J1a : info->J1l; + dReal *J2 = rotational ? info->J2a : info->J2l; + + J1[srow+0] = ax1[0]; + J1[srow+1] = ax1[1]; + J1[srow+2] = ax1[2]; + if (joint->node[1].body) { + J2[srow+0] = -ax1[0]; + J2[srow+1] = -ax1[1]; + J2[srow+2] = -ax1[2]; + } + + // if we're limited low and high simultaneously, the joint motor is + // ineffective + if (limit && (lostop == histop)) powered = 0; + + if (powered) { + info->cfm[row] = normal_cfm; + if (! limit) { + info->c[row] = vel; + info->lo[row] = -fmax; + info->hi[row] = fmax; + } + else { + // the joint is at a limit, AND is being powered. if the joint is + // being powered into the limit then we apply the maximum motor force + // in that direction, because the motor is working against the + // immovable limit. if the joint is being powered away from the limit + // then we have problems because actually we need *two* lcp + // constraints to handle this case. so we fake it and apply some + // fraction of the maximum force. the fraction to use can be set as + // a fudge factor. + + dReal fm = fmax; + if (vel > 0) fm = -fm; + + // if we're powering away from the limit, apply the fudge factor + if ((limit==1 && vel > 0) || (limit==2 && vel < 0)) fm *= fudge_factor; + + if (rotational) { + dBodyAddTorque (joint->node[0].body,-fm*ax1[0],-fm*ax1[1], + -fm*ax1[2]); + if (joint->node[1].body) + dBodyAddTorque (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]); + } + else { + dBodyAddForce (joint->node[0].body,-fm*ax1[0],-fm*ax1[1],-fm*ax1[2]); + if (joint->node[1].body) + dBodyAddForce (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]); + } + } + } + + if (limit) { + dReal k = info->fps * stop_erp; + info->c[row] = -k * limit_err; + info->cfm[row] = stop_cfm; + + if (lostop == histop) { + // limited low and high simultaneously + info->lo[row] = -dInfinity; + info->hi[row] = dInfinity; + } + else { + if (limit == 1) { + // low limit + info->lo[row] = 0; + info->hi[row] = dInfinity; + } + else { + // high limit + info->lo[row] = -dInfinity; + info->hi[row] = 0; + } + + // deal with bounce + if (bounce > 0) { + // calculate joint velocity + dReal vel; + if (rotational) { + vel = dDOT(joint->node[0].body->avel,ax1); + if (joint->node[1].body) + vel -= dDOT(joint->node[1].body->avel,ax1); + } + else { + vel = dDOT(joint->node[0].body->lvel,ax1); + if (joint->node[1].body) + vel -= dDOT(joint->node[1].body->lvel,ax1); + } + + // only apply bounce if the velocity is incoming, and if the + // resulting c[] exceeds what we already have. + if (limit == 1) { + // low limit + if (vel < 0) { + dReal newc = -bounce * vel; + if (newc > info->c[row]) info->c[row] = newc; + } + } + else { + // high limit - all those computations are reversed + if (vel > 0) { + dReal newc = -bounce * vel; + if (newc < info->c[row]) info->c[row] = newc; + } + } + } + } + } + return 1; + } + else return 0; +} + +//**************************************************************************** +// ball and socket + +static void ballInit (dxJointBall *j) +{ + dSetZero (j->anchor1,4); + dSetZero (j->anchor2,4); +} + + +static void ballGetInfo1 (dxJointBall *j, dxJoint::Info1 *info) +{ + info->m = 3; + info->nub = 3; +} + + +static void ballGetInfo2 (dxJointBall *joint, dxJoint::Info2 *info) +{ + setBall (joint,info,joint->anchor1,joint->anchor2); +} + + +extern "C" void dJointSetBallAnchor (dxJointBall *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); +} + + +extern "C" void dJointGetBallAnchor (dxJointBall *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); + getAnchor (joint,result,joint->anchor1); +} + + +dxJoint::Vtable __dball_vtable = { + sizeof(dxJointBall), + (dxJoint::init_fn*) ballInit, + (dxJoint::getInfo1_fn*) ballGetInfo1, + (dxJoint::getInfo2_fn*) ballGetInfo2, + dJointTypeBall}; + +//**************************************************************************** +// hinge + +static void hingeInit (dxJointHinge *j) +{ + dSetZero (j->anchor1,4); + dSetZero (j->anchor2,4); + dSetZero (j->axis1,4); + j->axis1[0] = 1; + dSetZero (j->axis2,4); + j->axis2[0] = 1; + dSetZero (j->qrel,4); + j->limot.init (j->world); +} + + +static void hingeGetInfo1 (dxJointHinge *j, dxJoint::Info1 *info) +{ + info->nub = 5; + + // see if joint is powered + if (j->limot.fmax > 0) + info->m = 6; // powered hinge needs an extra constraint row + else info->m = 5; + + // see if we're at a joint limit. + if ((j->limot.lostop >= -M_PI || j->limot.histop <= M_PI) && + j->limot.lostop <= j->limot.histop) { + dReal angle = getHingeAngle (j->node[0].body,j->node[1].body,j->axis1, + j->qrel); + if (j->limot.testRotationalLimit (angle)) info->m = 6; + } +} + + +static void hingeGetInfo2 (dxJointHinge *joint, dxJoint::Info2 *info) +{ + // set the three ball-and-socket rows + setBall (joint,info,joint->anchor1,joint->anchor2); + + // set the two hinge rows. the hinge axis should be the only unconstrained + // rotational axis, the angular velocity of the two bodies perpendicular to + // the hinge axis should be equal. thus the constraint equations are + // p*w1 - p*w2 = 0 + // q*w1 - q*w2 = 0 + // where p and q are unit vectors normal to the hinge axis, and w1 and w2 + // are the angular velocity vectors of the two bodies. + + dVector3 ax1; // length 1 joint axis in global coordinates, from 1st body + dVector3 p,q; // plane space vectors for ax1 + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + dPlaneSpace (ax1,p,q); + + int s3=3*info->rowskip; + int s4=4*info->rowskip; + + info->J1a[s3+0] = p[0]; + info->J1a[s3+1] = p[1]; + info->J1a[s3+2] = p[2]; + info->J1a[s4+0] = q[0]; + info->J1a[s4+1] = q[1]; + info->J1a[s4+2] = q[2]; + + if (joint->node[1].body) { + info->J2a[s3+0] = -p[0]; + info->J2a[s3+1] = -p[1]; + info->J2a[s3+2] = -p[2]; + info->J2a[s4+0] = -q[0]; + info->J2a[s4+1] = -q[1]; + info->J2a[s4+2] = -q[2]; + } + + // compute the right hand side of the constraint equation. set relative + // body velocities along p and q to bring the hinge back into alignment. + // if ax1,ax2 are the unit length hinge axes as computed from body1 and + // body2, we need to rotate both bodies along the axis u = (ax1 x ax2). + // if `theta' is the angle between ax1 and ax2, we need an angular velocity + // along u to cover angle erp*theta in one step : + // |angular_velocity| = angle/time = erp*theta / stepsize + // = (erp*fps) * theta + // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| + // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) + // ...as ax1 and ax2 are unit length. if theta is smallish, + // theta ~= sin(theta), so + // angular_velocity = (erp*fps) * (ax1 x ax2) + // ax1 x ax2 is in the plane space of ax1, so we project the angular + // velocity to p and q to find the right hand side. + + dVector3 ax2,b; + if (joint->node[1].body) { + dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); + } + else { + ax2[0] = joint->axis2[0]; + ax2[1] = joint->axis2[1]; + ax2[2] = joint->axis2[2]; + } + dCROSS (b,=,ax1,ax2); + dReal k = info->fps * info->erp; + info->c[3] = k * dDOT(b,p); + info->c[4] = k * dDOT(b,q); + + // if the hinge is powered, or has joint limits, add in the stuff + joint->limot.addLimot (joint,info,5,ax1,1); +} + + +// compute initial relative rotation body1 -> body2, or env -> body1 + +static void hingeComputeInitialRelativeRotation (dxJointHinge *joint) +{ + if (joint->node[0].body) { + if (joint->node[1].body) { + dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); + } + else { + // set joint->qrel to the transpose of the first body q + joint->qrel[0] = joint->node[0].body->q[0]; + for (int i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; + } + } +} + + +extern "C" void dJointSetHingeAnchor (dxJointHinge *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); + hingeComputeInitialRelativeRotation (joint); +} + + +extern "C" void dJointSetHingeAxis (dxJointHinge *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + setAxes (joint,x,y,z,joint->axis1,joint->axis2); + hingeComputeInitialRelativeRotation (joint); +} + + +extern "C" void dJointGetHingeAnchor (dxJointHinge *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + getAnchor (joint,result,joint->anchor1); +} + + +extern "C" void dJointGetHingeAxis (dxJointHinge *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + getAxis (joint,result,joint->axis1); +} + + +extern "C" void dJointSetHingeParam (dxJointHinge *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + joint->limot.set (parameter,value); +} + + +extern "C" dReal dJointGetHingeParam (dxJointHinge *joint, int parameter) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + return joint->limot.get (parameter); +} + + +extern "C" dReal dJointGetHingeAngle (dxJointHinge *joint) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + if (joint->node[0].body) { + return getHingeAngle (joint->node[0].body,joint->node[1].body,joint->axis1, + joint->qrel); + } + else return 0; +} + + +extern "C" dReal dJointGetHingeAngleRate (dxJointHinge *joint) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge"); + if (joint->node[0].body) { + dVector3 axis; + dMULTIPLY0_331 (axis,joint->node[0].body->R,joint->axis1); + dReal rate = dDOT(axis,joint->node[0].body->avel); + if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); + return rate; + } + else return 0; +} + + +dxJoint::Vtable __dhinge_vtable = { + sizeof(dxJointHinge), + (dxJoint::init_fn*) hingeInit, + (dxJoint::getInfo1_fn*) hingeGetInfo1, + (dxJoint::getInfo2_fn*) hingeGetInfo2, + dJointTypeHinge}; + +//**************************************************************************** +// slider + +static void sliderInit (dxJointSlider *j) +{ + dSetZero (j->axis1,4); + j->axis1[0] = 1; + dSetZero (j->qrel,4); + dSetZero (j->offset,4); + j->limot.init (j->world); +} + + +extern "C" dReal dJointGetSliderPosition (dxJointSlider *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + + // get axis1 in global coordinates + dVector3 ax1,q; + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + + if (joint->node[1].body) { + // get body2 + offset point in global coordinates + dMULTIPLY0_331 (q,joint->node[1].body->R,joint->offset); + for (int i=0; i<3; i++) q[i] = joint->node[0].body->pos[i] - q[i] - + joint->node[1].body->pos[i]; + } + else { + for (int i=0; i<3; i++) q[i] = joint->node[0].body->pos[i] - + joint->offset[i]; + + } + return dDOT(ax1,q); +} + + +extern "C" dReal dJointGetSliderPositionRate (dxJointSlider *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + + // get axis1 in global coordinates + dVector3 ax1; + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + + if (joint->node[1].body) { + return dDOT(ax1,joint->node[0].body->lvel) - + dDOT(ax1,joint->node[1].body->lvel); + } + else { + return dDOT(ax1,joint->node[0].body->lvel); + } +} + + +static void sliderGetInfo1 (dxJointSlider *j, dxJoint::Info1 *info) +{ + info->nub = 5; + + // see if joint is powered + if (j->limot.fmax > 0) + info->m = 6; // powered slider needs an extra constraint row + else info->m = 5; + + // see if we're at a joint limit. + j->limot.limit = 0; + if ((j->limot.lostop > -dInfinity || j->limot.histop < dInfinity) && + j->limot.lostop <= j->limot.histop) { + // measure joint position + dReal pos = dJointGetSliderPosition (j); + if (pos <= j->limot.lostop) { + j->limot.limit = 1; + j->limot.limit_err = pos - j->limot.lostop; + info->m = 6; + } + else if (pos >= j->limot.histop) { + j->limot.limit = 2; + j->limot.limit_err = pos - j->limot.histop; + info->m = 6; + } + } +} + + +static void sliderGetInfo2 (dxJointSlider *joint, dxJoint::Info2 *info) +{ + int i,s = info->rowskip; + int s2=2*s,s3=3*s,s4=4*s; + + // pull out pos and R for both bodies. also get the `connection' + // vector pos2-pos1. + + dReal *pos1,*pos2,*R1,*R2; + dVector3 c; + pos1 = joint->node[0].body->pos; + R1 = joint->node[0].body->R; + if (joint->node[1].body) { + pos2 = joint->node[1].body->pos; + R2 = joint->node[1].body->R; + for (i=0; i<3; i++) c[i] = pos2[i] - pos1[i]; + } + else { + pos2 = 0; + R2 = 0; + } + + // 3 rows to make body rotations equal + info->J1a[0] = 1; + info->J1a[s+1] = 1; + info->J1a[s2+2] = 1; + if (joint->node[1].body) { + info->J2a[0] = -1; + info->J2a[s+1] = -1; + info->J2a[s2+2] = -1; + } + + // remaining two rows. we want: vel2 = vel1 + w1 x c ... but this would + // result in three equations, so we project along the planespace vectors + // so that sliding along the slider axis is disregarded. for symmetry we + // also substitute (w1+w2)/2 for w1, as w1 is supposed to equal w2. + + dVector3 ax1; // joint axis in global coordinates (unit length) + dVector3 p,q; // plane space of ax1 + dMULTIPLY0_331 (ax1,R1,joint->axis1); + dPlaneSpace (ax1,p,q); + if (joint->node[1].body) { + dVector3 tmp; + dCROSS (tmp, = REAL(0.5) * ,c,p); + for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i]; + for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i]; + dCROSS (tmp, = REAL(0.5) * ,c,q); + for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i]; + for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i]; + for (i=0; i<3; i++) info->J2l[s3+i] = -p[i]; + for (i=0; i<3; i++) info->J2l[s4+i] = -q[i]; + } + for (i=0; i<3; i++) info->J1l[s3+i] = p[i]; + for (i=0; i<3; i++) info->J1l[s4+i] = q[i]; + + // compute the right hand side. the first three elements will result in + // relative angular velocity of the two bodies - this is set to bring them + // back into alignment. the correcting angular velocity is + // |angular_velocity| = angle/time = erp*theta / stepsize + // = (erp*fps) * theta + // angular_velocity = |angular_velocity| * u + // = (erp*fps) * theta * u + // where rotation along unit length axis u by theta brings body 2's frame + // to qrel with respect to body 1's frame. using a small angle approximation + // for sin(), this gives + // angular_velocity = (erp*fps) * 2 * v + // where the quaternion of the relative rotation between the two bodies is + // q = [cos(theta/2) sin(theta/2)*u] = [s v] + + // get qerr = relative rotation (rotation error) between two bodies + dQuaternion qerr,e; + if (joint->node[1].body) { + dQuaternion qq; + dQMultiply1 (qq,joint->node[0].body->q,joint->node[1].body->q); + dQMultiply2 (qerr,qq,joint->qrel); + } + else { + dQMultiply3 (qerr,joint->node[0].body->q,joint->qrel); + } + if (qerr[0] < 0) { + qerr[1] = -qerr[1]; // adjust sign of qerr to make theta small + qerr[2] = -qerr[2]; + qerr[3] = -qerr[3]; + } + dMULTIPLY0_331 (e,joint->node[0].body->R,qerr+1); // @@@ bad SIMD padding! + dReal k = info->fps * info->erp; + info->c[0] = 2*k * e[0]; + info->c[1] = 2*k * e[1]; + info->c[2] = 2*k * e[2]; + + // compute last two elements of right hand side. we want to align the offset + // point (in body 2's frame) with the center of body 1. + if (joint->node[1].body) { + dVector3 ofs; // offset point in global coordinates + dMULTIPLY0_331 (ofs,R2,joint->offset); + for (i=0; i<3; i++) c[i] += ofs[i]; + info->c[3] = k * dDOT(p,c); + info->c[4] = k * dDOT(q,c); + } + else { + dVector3 ofs; // offset point in global coordinates + for (i=0; i<3; i++) ofs[i] = joint->offset[i] - pos1[i]; + info->c[3] = k * dDOT(p,ofs); + info->c[4] = k * dDOT(q,ofs); + } + + // if the slider is powered, or has joint limits, add in the extra row + joint->limot.addLimot (joint,info,5,ax1,0); +} + + +extern "C" void dJointSetSliderAxis (dxJointSlider *joint, + dReal x, dReal y, dReal z) +{ + int i; + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + setAxes (joint,x,y,z,joint->axis1,0); + + // compute initial relative rotation body1 -> body2, or env -> body1 + // also compute center of body1 w.r.t body 2 + if (joint->node[1].body) { + dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); + dVector3 c; + for (i=0; i<3; i++) + c[i] = joint->node[0].body->pos[i] - joint->node[1].body->pos[i]; + dMULTIPLY1_331 (joint->offset,joint->node[1].body->R,c); + } + else { + // set joint->qrel to the transpose of the first body's q + joint->qrel[0] = joint->node[0].body->q[0]; + for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; + for (i=0; i<3; i++) joint->offset[i] = joint->node[0].body->pos[i]; + } +} + + +extern "C" void dJointGetSliderAxis (dxJointSlider *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + getAxis (joint,result,joint->axis1); +} + + +extern "C" void dJointSetSliderParam (dxJointSlider *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + joint->limot.set (parameter,value); +} + + +extern "C" dReal dJointGetSliderParam (dxJointSlider *joint, int parameter) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + return joint->limot.get (parameter); +} + + +dxJoint::Vtable __dslider_vtable = { + sizeof(dxJointSlider), + (dxJoint::init_fn*) sliderInit, + (dxJoint::getInfo1_fn*) sliderGetInfo1, + (dxJoint::getInfo2_fn*) sliderGetInfo2, + dJointTypeSlider}; + +//**************************************************************************** +// contact + +static void contactInit (dxJointContact *j) +{ + // default frictionless contact. hmmm, this info gets overwritten straight + // away anyway, so why bother? + j->contact.surface.mode = 0; + j->contact.surface.mu = 0; + dSetZero (j->contact.geom.pos,4); + dSetZero (j->contact.geom.normal,4); + j->contact.geom.depth = 0; +} + + +static void contactGetInfo1 (dxJointContact *j, dxJoint::Info1 *info) +{ + // make sure mu's >= 0, then calculate number of constraint rows and number + // of unbounded rows. + int m = 1, nub=0; + if (j->contact.surface.mu < 0) j->contact.surface.mu = 0; + if (j->contact.surface.mode & dContactMu2) { + if (j->contact.surface.mu > 0) m++; + if (j->contact.surface.mu2 < 0) j->contact.surface.mu2 = 0; + if (j->contact.surface.mu2 > 0) m++; + if (j->contact.surface.mu == dInfinity) nub ++; + if (j->contact.surface.mu2 == dInfinity) nub ++; + } + else { + if (j->contact.surface.mu > 0) m += 2; + if (j->contact.surface.mu == dInfinity) nub += 2; + } + + j->the_m = m; + info->m = m; + info->nub = nub; +} + + +static void contactGetInfo2 (dxJointContact *j, dxJoint::Info2 *info) +{ + int i,s = info->rowskip; + int s2 = 2*s; + + // get normal, with sign adjusted for body1/body2 polarity + dVector3 normal; + if (j->flags & dJOINT_REVERSE) { + normal[0] = j->contact.geom.normal[0]; + normal[1] = j->contact.geom.normal[1]; + normal[2] = j->contact.geom.normal[2]; + } + else { + normal[0] = - j->contact.geom.normal[0]; + normal[1] = - j->contact.geom.normal[1]; + normal[2] = - j->contact.geom.normal[2]; + } + normal[3] = 0; // @@@ hmmm + + // c1,c2 = contact points with respect to body PORs + dVector3 c1,c2; + for (i=0; i<3; i++) c1[i] = j->contact.geom.pos[i] - j->node[0].body->pos[i]; + + // set jacobian for normal + info->J1l[0] = normal[0]; + info->J1l[1] = normal[1]; + info->J1l[2] = normal[2]; + dCROSS (info->J1a,=,c1,normal); + if (j->node[1].body) { + for (i=0; i<3; i++) c2[i] = j->contact.geom.pos[i] - + j->node[1].body->pos[i]; + info->J2l[0] = -normal[0]; + info->J2l[1] = -normal[1]; + info->J2l[2] = -normal[2]; + dCROSS (info->J2a,= -,c2,normal); + } + + // set right hand side and cfm value for normal + dReal erp = info->erp; + if (j->contact.surface.mode & dContactSoftERP) + erp = j->contact.surface.soft_erp; + dReal k = info->fps * erp; + info->c[0] = k*j->contact.geom.depth; + if (j->contact.surface.mode & dContactSoftCFM) + info->cfm[0] = j->contact.surface.soft_cfm; + + // deal with bounce + if (j->contact.surface.mode & dContactBounce) { + // calculate outgoing velocity (-ve for incoming contact) + dReal outgoing = dDOT(info->J1l,j->node[0].body->lvel) + + dDOT(info->J1a,j->node[0].body->avel); + if (j->node[1].body) { + outgoing += dDOT(info->J2l,j->node[1].body->lvel) + + dDOT(info->J2a,j->node[1].body->avel); + } + // only apply bounce if the outgoing velocity is greater than the + // threshold, and if the resulting c[0] exceeds what we already have. + if (j->contact.surface.bounce_vel >= 0 && + (-outgoing) > j->contact.surface.bounce_vel) { + dReal newc = - j->contact.surface.bounce * outgoing; + if (newc > info->c[0]) info->c[0] = newc; + } + } + + // set LCP limits for normal + info->lo[0] = 0; + info->hi[0] = dInfinity; + + // now do jacobian for tangential forces + dVector3 t1,t2; // two vectors tangential to normal + + // first friction direction + if (j->the_m >= 2) { + if (j->contact.surface.mode & dContactFDir1) { // use fdir1 ? + t1[0] = j->contact.fdir1[0]; + t1[1] = j->contact.fdir1[1]; + t1[2] = j->contact.fdir1[2]; + dCROSS (t2,=,normal,t1); + } + else { + dPlaneSpace (normal,t1,t2); + } + info->J1l[s+0] = t1[0]; + info->J1l[s+1] = t1[1]; + info->J1l[s+2] = t1[2]; + dCROSS (info->J1a+s,=,c1,t1); + if (j->node[1].body) { + info->J2l[s+0] = -t1[0]; + info->J2l[s+1] = -t1[1]; + info->J2l[s+2] = -t1[2]; + dCROSS (info->J2a+s,= -,c2,t1); + } + // set right hand side + if (j->contact.surface.mode & dContactMotion1) { + info->c[1] = j->contact.surface.motion1; + } + // set LCP bounds and friction index. this depends on the approximation + // mode + info->lo[1] = -j->contact.surface.mu; + info->hi[1] = j->contact.surface.mu; + if (j->contact.surface.mode & dContactApprox1_1) info->findex[1] = 0; + + // set slip (constraint force mixing) + if (j->contact.surface.mode & dContactSlip1) + info->cfm[1] = j->contact.surface.slip1; + } + + // second friction direction + if (j->the_m >= 3) { + info->J1l[s2+0] = t2[0]; + info->J1l[s2+1] = t2[1]; + info->J1l[s2+2] = t2[2]; + dCROSS (info->J1a+s2,=,c1,t2); + if (j->node[1].body) { + info->J2l[s2+0] = -t2[0]; + info->J2l[s2+1] = -t2[1]; + info->J2l[s2+2] = -t2[2]; + dCROSS (info->J2a+s2,= -,c2,t2); + } + // set right hand side + if (j->contact.surface.mode & dContactMotion2) { + info->c[2] = j->contact.surface.motion2; + } + // set LCP bounds and friction index. this depends on the approximation + // mode + if (j->contact.surface.mode & dContactMu2) { + info->lo[2] = -j->contact.surface.mu2; + info->hi[2] = j->contact.surface.mu2; + } + else { + info->lo[2] = -j->contact.surface.mu; + info->hi[2] = j->contact.surface.mu; + } + if (j->contact.surface.mode & dContactApprox1_2) info->findex[2] = 0; + + // set slip (constraint force mixing) + if (j->contact.surface.mode & dContactSlip2) + info->cfm[2] = j->contact.surface.slip2; + } +} + + +dxJoint::Vtable __dcontact_vtable = { + sizeof(dxJointContact), + (dxJoint::init_fn*) contactInit, + (dxJoint::getInfo1_fn*) contactGetInfo1, + (dxJoint::getInfo2_fn*) contactGetInfo2, + dJointTypeContact}; + +//**************************************************************************** +// hinge 2. note that this joint must be attached to two bodies for it to work + +static dReal measureHinge2Angle (dxJointHinge2 *joint) +{ + dVector3 a1,a2; + dMULTIPLY0_331 (a1,joint->node[1].body->R,joint->axis2); + dMULTIPLY1_331 (a2,joint->node[0].body->R,a1); + dReal x = dDOT(joint->v1,a2); + dReal y = dDOT(joint->v2,a2); + return -dAtan2 (y,x); +} + + +static void hinge2Init (dxJointHinge2 *j) +{ + dSetZero (j->anchor1,4); + dSetZero (j->anchor2,4); + dSetZero (j->axis1,4); + j->axis1[0] = 1; + dSetZero (j->axis2,4); + j->axis2[1] = 1; + j->c0 = 0; + j->s0 = 0; + + dSetZero (j->v1,4); + j->v1[0] = 1; + dSetZero (j->v2,4); + j->v2[1] = 1; + + j->limot1.init (j->world); + j->limot2.init (j->world); + + j->susp_erp = j->world->global_erp; + j->susp_cfm = j->world->global_cfm; + + j->flags |= dJOINT_TWOBODIES; +} + + +static void hinge2GetInfo1 (dxJointHinge2 *j, dxJoint::Info1 *info) +{ + info->m = 4; + info->nub = 4; + + // see if we're powered or at a joint limit for axis 1 + int atlimit=0; + if ((j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) && + j->limot1.lostop <= j->limot1.histop) { + dReal angle = measureHinge2Angle (j); + if (j->limot1.testRotationalLimit (angle)) atlimit = 1; + } + if (atlimit || j->limot1.fmax > 0) info->m++; + + // see if we're powering axis 2 (we currently never limit this axis) + j->limot2.limit = 0; + if (j->limot2.fmax > 0) info->m++; +} + + +// macro that computes ax1,ax2 = axis 1 and 2 in global coordinates (they are +// relative to body 1 and 2 initially) and then computes the constrained +// rotational axis as the cross product of ax1 and ax2. +// the sin and cos of the angle between axis 1 and 2 is computed, this comes +// from dot and cross product rules. + +#define HINGE2_GET_AXIS_INFO(axis,sin_angle,cos_angle) \ + dVector3 ax1,ax2; \ + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); \ + dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); \ + dCROSS (axis,=,ax1,ax2); \ + sin_angle = dSqrt (axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]); \ + cos_angle = dDOT (ax1,ax2); + + +static void hinge2GetInfo2 (dxJointHinge2 *joint, dxJoint::Info2 *info) +{ + // get information we need to set the hinge row + dReal s,c; + dVector3 q; + HINGE2_GET_AXIS_INFO (q,s,c); + dNormalize3 (q); // @@@ quicker: divide q by s ? + + // set the three ball-and-socket rows (aligned to the suspension axis ax1) + setBall2 (joint,info,joint->anchor1,joint->anchor2,ax1,joint->susp_erp); + + // set the hinge row + int s3=3*info->rowskip; + info->J1a[s3+0] = q[0]; + info->J1a[s3+1] = q[1]; + info->J1a[s3+2] = q[2]; + if (joint->node[1].body) { + info->J2a[s3+0] = -q[0]; + info->J2a[s3+1] = -q[1]; + info->J2a[s3+2] = -q[2]; + } + + // compute the right hand side for the constrained rotational DOF. + // axis 1 and axis 2 are separated by an angle `theta'. the desired + // separation angle is theta0. sin(theta0) and cos(theta0) are recorded + // in the joint structure. the correcting angular velocity is: + // |angular_velocity| = angle/time = erp*(theta0-theta) / stepsize + // = (erp*fps) * (theta0-theta) + // (theta0-theta) can be computed using the following small-angle-difference + // approximation: + // theta0-theta ~= tan(theta0-theta) + // = sin(theta0-theta)/cos(theta0-theta) + // = (c*s0 - s*c0) / (c*c0 + s*s0) + // = c*s0 - s*c0 assuming c*c0 + s*s0 ~= 1 + // where c = cos(theta), s = sin(theta) + // c0 = cos(theta0), s0 = sin(theta0) + + dReal k = info->fps * info->erp; + info->c[3] = k * (joint->c0 * s - joint->s0 * c); + + // if the axis1 hinge is powered, or has joint limits, add in more stuff + int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1); + + // if the axis2 hinge is powered, add in more stuff + joint->limot2.addLimot (joint,info,row,ax2,1); + + // set parameter for the suspension + info->cfm[0] = joint->susp_cfm; +} + + +// compute vectors v1 and v2 (embedded in body1), used to measure angle +// between body 1 and body 2 + +static void makeHinge2V1andV2 (dxJointHinge2 *joint) +{ + if (joint->node[0].body) { + // get axis 1 and 2 in global coords + dVector3 ax1,ax2,v; + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); + + // don't do anything if the axis1 or axis2 vectors are zero or the same + if ((ax1[0]==0 && ax1[1]==0 && ax1[2]==0) || + (ax2[0]==0 && ax2[1]==0 && ax2[2]==0) || + (ax1[0]==ax2[0] && ax1[1]==ax2[1] && ax1[2]==ax2[2])) return; + + // modify axis 2 so it's perpendicular to axis 1 + dReal k = dDOT(ax1,ax2); + for (int i=0; i<3; i++) ax2[i] -= k*ax1[i]; + dNormalize3 (ax2); + + // make v1 = modified axis2, v2 = axis1 x (modified axis2) + dCROSS (v,=,ax1,ax2); + dMULTIPLY1_331 (joint->v1,joint->node[0].body->R,ax2); + dMULTIPLY1_331 (joint->v2,joint->node[0].body->R,v); + } +} + + +extern "C" void dJointSetHinge2Anchor (dxJointHinge2 *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); + makeHinge2V1andV2 (joint); +} + + +extern "C" void dJointSetHinge2Axis1 (dxJointHinge2 *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body) { + dReal q[4]; + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = 0; + dNormalize3 (q); + dMULTIPLY1_331 (joint->axis1,joint->node[0].body->R,q); + joint->axis1[3] = 0; + + // compute the sin and cos of the angle between axis 1 and axis 2 + dVector3 ax; + HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0); + } + makeHinge2V1andV2 (joint); +} + + +extern "C" void dJointSetHinge2Axis2 (dxJointHinge2 *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[1].body) { + dReal q[4]; + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = 0; + dNormalize3 (q); + dMULTIPLY1_331 (joint->axis2,joint->node[1].body->R,q); + joint->axis1[3] = 0; + + // compute the sin and cos of the angle between axis 1 and axis 2 + dVector3 ax; + HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0); + } + makeHinge2V1andV2 (joint); +} + + +extern "C" void dJointSetHinge2Param (dxJointHinge2 *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if ((parameter & 0xff00) == 0x100) { + joint->limot2.set (parameter & 0xff,value); + } + else { + if (parameter == dParamSuspensionERP) joint->susp_erp = value; + else if (parameter == dParamSuspensionCFM) joint->susp_cfm = value; + else joint->limot1.set (parameter,value); + } +} + + +extern "C" void dJointGetHinge2Anchor (dxJointHinge2 *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + getAnchor (joint,result,joint->anchor1); +} + + +extern "C" void dJointGetHinge2Axis1 (dxJointHinge2 *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body) { + dMULTIPLY0_331 (result,joint->node[0].body->R,joint->axis1); + } +} + + +extern "C" void dJointGetHinge2Axis2 (dxJointHinge2 *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[1].body) { + dMULTIPLY0_331 (result,joint->node[1].body->R,joint->axis2); + } +} + + +extern "C" dReal dJointGetHinge2Param (dxJointHinge2 *joint, int parameter) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if ((parameter & 0xff00) == 0x100) { + return joint->limot2.get (parameter & 0xff); + } + else { + if (parameter == dParamSuspensionERP) return joint->susp_erp; + else if (parameter == dParamSuspensionCFM) return joint->susp_cfm; + else return joint->limot1.get (parameter); + } +} + + +extern "C" dReal dJointGetHinge2Angle1 (dxJointHinge2 *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body) return measureHinge2Angle (joint); + else return 0; +} + + +extern "C" dReal dJointGetHinge2Angle1Rate (dxJointHinge2 *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body) { + dVector3 axis; + dMULTIPLY0_331 (axis,joint->node[0].body->R,joint->axis1); + dReal rate = dDOT(axis,joint->node[0].body->avel); + if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); + return rate; + } + else return 0; +} + + +extern "C" dReal dJointGetHinge2Angle2Rate (dxJointHinge2 *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body && joint->node[1].body) { + dVector3 axis; + dMULTIPLY0_331 (axis,joint->node[1].body->R,joint->axis2); + dReal rate = dDOT(axis,joint->node[0].body->avel); + if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); + return rate; + } + else return 0; +} + + +dxJoint::Vtable __dhinge2_vtable = { + sizeof(dxJointHinge2), + (dxJoint::init_fn*) hinge2Init, + (dxJoint::getInfo1_fn*) hinge2GetInfo1, + (dxJoint::getInfo2_fn*) hinge2GetInfo2, + dJointTypeHinge2}; + +//**************************************************************************** +// universal + +static void universalInit (dxJointUniversal *j) +{ + dSetZero (j->anchor1,4); + dSetZero (j->anchor2,4); + dSetZero (j->axis1,4); + j->axis1[0] = 1; + dSetZero (j->axis2,4); + j->axis2[1] = 1; +} + + +static void universalGetInfo1 (dxJointUniversal *j, dxJoint::Info1 *info) +{ + info->nub = 4; + info->m = 4; +} + + +static void universalGetInfo2 (dxJointUniversal *joint, dxJoint::Info2 *info) +{ + // set the three ball-and-socket rows + setBall (joint,info,joint->anchor1,joint->anchor2); + + // set the universal joint row. the angular velocity about an axis + // perpendicular to both joint axes should be equal. thus the constraint + // equation is + // p*w1 - p*w2 = 0 + // where p is a vector normal to both joint axes, and w1 and w2 + // are the angular velocity vectors of the two bodies. + + // length 1 joint axis in global coordinates, from each body + dVector3 ax1, ax2; + // length 1 vector perpendicular to ax1 and ax2. Neither body can rotate + // about this. + dVector3 p; + + // This says "ax1 = joint->node[0].body->R * joint->axis1" + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + if (joint->node[1].body) { + dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); + } + else { + ax2[0] = joint->axis2[0]; + ax2[1] = joint->axis2[1]; + ax2[2] = joint->axis2[2]; + } + + // if ax1 and ax2 are almost parallel, p won't be perpendicular to them. + // Is there some more robust way to do this? + dCROSS(p, =, ax1, ax2); + dNormalize3(p); + + int s3=3*info->rowskip; + + info->J1a[s3+0] = p[0]; + info->J1a[s3+1] = p[1]; + info->J1a[s3+2] = p[2]; + + if (joint->node[1].body) { + info->J2a[s3+0] = -p[0]; + info->J2a[s3+1] = -p[1]; + info->J2a[s3+2] = -p[2]; + } + + // compute the right hand side of the constraint equation. set relative + // body velocities along p to bring the axes back to perpendicular. + // If ax1, ax2 are unit length joint axes as computed from body1 and + // body2, we need to rotate both bodies along the axis p. If theta + // is the angle between ax1 and ax2, we need an angular velocity + // along p to cover the angle erp * (theta - Pi/2) in one step: + // + // |angular_velocity| = angle/time = erp*(theta - Pi/2) / stepsize + // = (erp*fps) * (theta - Pi/2) + // + // if theta is close to Pi/2, + // theta - Pi/2 ~= cos(theta), so + // |angular_velocity| = (erp*fps) * (ax1 dot ax2) + + info->c[3] = info->fps * info->erp * - dDOT(ax1, ax2); +} + + +extern "C" void dJointSetUniversalAnchor (dxJointUniversal *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); +} + + +extern "C" void dJointSetUniversalAxis1 (dxJointUniversal *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->node[0].body) { + dReal q[4]; + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = 0; + dNormalize3 (q); + dMULTIPLY1_331 (joint->axis1,joint->node[0].body->R,q); + } + joint->axis1[3] = 0; +} + + +extern "C" void dJointSetUniversalAxis2 (dxJointUniversal *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->node[1].body) { + dReal q[4]; + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = 0; + dNormalize3 (q); + dMULTIPLY1_331 (joint->axis2,joint->node[1].body->R,q); + } + joint->axis2[3] = 0; +} + + +extern "C" void dJointGetUniversalAnchor (dxJointUniversal *joint, + dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + getAnchor (joint,result,joint->anchor1); +} + + +extern "C" void dJointGetUniversalAxis1 (dxJointUniversal *joint, + dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->node[0].body) { + dMULTIPLY0_331 (result, joint->node[0].body->R, joint->axis1); + } +} + + +extern "C" void dJointGetUniversalAxis2 (dxJointUniversal *joint, + dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->node[1].body) { + dMULTIPLY0_331 (result, joint->node[1].body->R, joint->axis2); + } +} + + +dxJoint::Vtable __duniversal_vtable = { + sizeof(dxJointUniversal), + (dxJoint::init_fn*) universalInit, + (dxJoint::getInfo1_fn*) universalGetInfo1, + (dxJoint::getInfo2_fn*) universalGetInfo2, + dJointTypeUniversal}; + +//**************************************************************************** +// angular motor + +static void amotorInit (dxJointAMotor *j) +{ + int i; + j->num = 0; + j->mode = dAMotorUser; + for (i=0; i<3; i++) { + j->rel[i] = 0; + dSetZero (j->axis[i],4); + j->limot[i].init (j->world); + j->angle[i] = 0; + } + dSetZero (j->reference1,4); + dSetZero (j->reference2,4); + + j->flags |= dJOINT_TWOBODIES; +} + + +// compute the 3 axes in global coordinates + +static void amotorComputeGlobalAxes (dxJointAMotor *joint, dVector3 ax[3]) +{ + if (joint->mode == dAMotorEuler) { + // special handling for euler mode + dMULTIPLY0_331 (ax[0],joint->node[0].body->R,joint->axis[0]); + dMULTIPLY0_331 (ax[2],joint->node[1].body->R,joint->axis[2]); + dCROSS (ax[1],=,ax[2],ax[0]); + dNormalize3 (ax[1]); + } + else { + for (int i=0; i < joint->num; i++) { + if (joint->rel[i] == 1) { + // relative to b1 + dMULTIPLY0_331 (ax[i],joint->node[0].body->R,joint->axis[i]); + } + if (joint->rel[i] == 2) { + // relative to b2 + dMULTIPLY0_331 (ax[i],joint->node[1].body->R,joint->axis[i]); + } + else { + // global - just copy it + ax[i][0] = joint->axis[i][0]; + ax[i][1] = joint->axis[i][1]; + ax[i][2] = joint->axis[i][2]; + } + } + } +} + + +static void amotorComputeEulerAngles (dxJointAMotor *joint, dVector3 ax[3]) +{ + // assumptions: + // global axes already calculated --> ax + // axis[0] is relative to body 1 --> global ax[0] + // axis[2] is relative to body 2 --> global ax[2] + // ax[1] = ax[2] x ax[0] + // original ax[0] and ax[2] are perpendicular + // reference1 is perpendicular to ax[0] (in body 1 frame) + // reference2 is perpendicular to ax[2] (in body 2 frame) + // all ax[] and reference vectors are unit length + + // calculate references in global frame + dVector3 ref1,ref2; + dMULTIPLY0_331 (ref1,joint->node[0].body->R,joint->reference1); + dMULTIPLY0_331 (ref2,joint->node[1].body->R,joint->reference2); + + // get q perpendicular to both ax[0] and ref1, get first euler angle + dVector3 q; + dCROSS (q,=,ax[0],ref1); + joint->angle[0] = -dAtan2 (dDOT(ax[2],q),dDOT(ax[2],ref1)); + + // get q perpendicular to both ax[0] and ax[1], get second euler angle + dCROSS (q,=,ax[0],ax[1]); + joint->angle[1] = -dAtan2 (dDOT(ax[2],ax[0]),dDOT(ax[2],q)); + + // get q perpendicular to both ax[1] and ax[2], get third euler angle + dCROSS (q,=,ax[1],ax[2]); + joint->angle[2] = -dAtan2 (dDOT(ref2,ax[1]), dDOT(ref2,q)); +} + + +// set the reference vectors as follows: +// * reference1 = current axis[2] relative to body 1 +// * reference2 = current axis[0] relative to body 2 +// this assumes that: +// * axis[0] is relative to body 1 +// * axis[2] is relative to body 2 + +static void amotorSetEulerReferenceVectors (dxJointAMotor *j) +{ + if (j->node[0].body && j->node[1].body) { + dVector3 r; // axis[2] and axis[0] in global coordinates + dMULTIPLY0_331 (r,j->node[1].body->R,j->axis[2]); + dMULTIPLY1_331 (j->reference1,j->node[0].body->R,r); + dMULTIPLY0_331 (r,j->node[0].body->R,j->axis[0]); + dMULTIPLY1_331 (j->reference2,j->node[1].body->R,r); + } +} + + +static void amotorGetInfo1 (dxJointAMotor *j, dxJoint::Info1 *info) +{ + info->m = 0; + info->nub = 0; + + // compute the axes and angles, if in euler mode + if (j->mode == dAMotorEuler) { + dVector3 ax[3]; + amotorComputeGlobalAxes (j,ax); + amotorComputeEulerAngles (j,ax); + } + + // see if we're powered or at a joint limit for each axis + for (int i=0; i < j->num; i++) { + if (j->limot[i].testRotationalLimit (j->angle[i]) || + j->limot[i].fmax > 0) { + info->m++; + } + } +} + + +static void amotorGetInfo2 (dxJointAMotor *joint, dxJoint::Info2 *info) +{ + int i; + + // compute the axes (if not global) + dVector3 ax[3]; + amotorComputeGlobalAxes (joint,ax); + + // in euler angle mode we do not actually constrain the angular velocity + // along the axes axis[0] and axis[2] (although we do use axis[1]) : + // + // to get constrain w2-w1 along ...not + // ------ --------------------- ------ + // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0] + // d(angle[1])/dt = 0 ax[1] + // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2] + // + // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0. + // to prove the result for angle[0], write the expression for angle[0] from + // GetInfo1 then take the derivative. to prove this for angle[2] it is + // easier to take the euler rate expression for d(angle[2])/dt with respect + // to the components of w and set that to 0. + + dVector3 *axptr[3]; + axptr[0] = &ax[0]; + axptr[1] = &ax[1]; + axptr[2] = &ax[2]; + + dVector3 ax0_cross_ax1; + dVector3 ax1_cross_ax2; + if (joint->mode == dAMotorEuler) { + dCROSS (ax0_cross_ax1,=,ax[0],ax[1]); + axptr[2] = &ax0_cross_ax1; + dCROSS (ax1_cross_ax2,=,ax[1],ax[2]); + axptr[0] = &ax1_cross_ax2; + } + + int row=0; + for (i=0; i < joint->num; i++) { + row += joint->limot[i].addLimot (joint,info,row,*(axptr[i]),1); + } +} + + +extern "C" void dJointSetAMotorNumAxes (dxJointAMotor *joint, int num) +{ + dAASSERT(joint && num >= 0 && num <= 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (joint->mode == dAMotorEuler) { + joint->num = 3; + } + else { + if (num < 0) num = 0; + if (num > 3) num = 3; + joint->num = num; + } +} + + +extern "C" void dJointSetAMotorAxis (dxJointAMotor *joint, int anum, int rel, + dReal x, dReal y, dReal z) +{ + dAASSERT(joint && anum >= 0 && anum <= 2 && rel >= 0 && rel <= 2); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + joint->rel[anum] = rel; + + // x,y,z is always in global coordinates regardless of rel, so we may have + // to convert it to be relative to a body + dVector3 r; + r[0] = x; + r[1] = y; + r[2] = z; + r[3] = 0; + if (rel > 0) { + if (rel==1) { + dMULTIPLY1_331 (joint->axis[anum],joint->node[0].body->R,r); + } + else { + dMULTIPLY1_331 (joint->axis[anum],joint->node[1].body->R,r); + } + } + else { + joint->axis[anum][0] = r[0]; + joint->axis[anum][1] = r[1]; + joint->axis[anum][2] = r[2]; + } + dNormalize3 (joint->axis[anum]); + if (joint->mode == dAMotorEuler) amotorSetEulerReferenceVectors (joint); +} + + +extern "C" void dJointSetAMotorAngle (dxJointAMotor *joint, int anum, + dReal angle) +{ + dAASSERT(joint && anum >= 0 && anum < 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (joint->mode == dAMotorUser) { + if (anum < 0) anum = 0; + if (anum > 3) anum = 3; + joint->angle[anum] = angle; + } +} + + +extern "C" void dJointSetAMotorParam (dxJointAMotor *joint, int parameter, + dReal value) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + int anum = parameter >> 8; + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + parameter &= 0xff; + joint->limot[anum].set (parameter, value); +} + + +extern "C" void dJointSetAMotorMode (dxJointAMotor *joint, int mode) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + joint->mode = mode; + if (joint->mode == dAMotorEuler) { + joint->num = 3; + amotorSetEulerReferenceVectors (joint); + } +} + + +extern "C" int dJointGetAMotorNumAxes (dxJointAMotor *joint) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + return joint->num; +} + + +extern "C" void dJointGetAMotorAxis (dxJointAMotor *joint, int anum, + dVector3 result) +{ + dAASSERT(joint && anum >= 0 && anum < 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + if (joint->rel[anum] > 0) { + if (joint->rel[anum]==1) { + dMULTIPLY0_331 (result,joint->node[0].body->R,joint->axis[anum]); + } + else { + dMULTIPLY0_331 (result,joint->node[1].body->R,joint->axis[anum]); + } + } + else { + result[0] = joint->axis[anum][0]; + result[1] = joint->axis[anum][1]; + result[2] = joint->axis[anum][2]; + } +} + + +extern "C" int dJointGetAMotorAxisRel (dxJointAMotor *joint, int anum) +{ + dAASSERT(joint && anum >= 0 && anum < 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + return joint->rel[anum]; +} + + +extern "C" dReal dJointGetAMotorAngle (dxJointAMotor *joint, int anum) +{ + dAASSERT(joint && anum >= 0 && anum < 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (anum < 0) anum = 0; + if (anum > 3) anum = 3; + return joint->angle[anum]; +} + + +extern "C" dReal dJointGetAMotorAngleRate (dxJointAMotor *joint, int anum) +{ + // @@@ + dDebug (0,"not yet implemented"); + return 0; +} + + +extern "C" dReal dJointGetAMotorParam (dxJointAMotor *joint, int parameter) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + int anum = parameter >> 8; + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + parameter &= 0xff; + return joint->limot[anum].get (parameter); +} + + +extern "C" int dJointGetAMotorMode (dxJointAMotor *joint) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + return joint->mode; +} + + +dxJoint::Vtable __damotor_vtable = { + sizeof(dxJointAMotor), + (dxJoint::init_fn*) amotorInit, + (dxJoint::getInfo1_fn*) amotorGetInfo1, + (dxJoint::getInfo2_fn*) amotorGetInfo2, + dJointTypeAMotor}; + +//**************************************************************************** +// fixed joint + +static void fixedInit (dxJointFixed *j) +{ + dSetZero (j->offset,4); +} + + +static void fixedGetInfo1 (dxJointFixed *j, dxJoint::Info1 *info) +{ + info->m = 6; + info->nub = 6; +} + + +static void fixedGetInfo2 (dxJointFixed *joint, dxJoint::Info2 *info) +{ + int s = info->rowskip; + + // set jacobian + info->J1l[0] = 1; + info->J1l[s+1] = 1; + info->J1l[2*s+2] = 1; + info->J1a[3*s] = 1; + info->J1a[4*s+1] = 1; + info->J1a[5*s+2] = 1; + + dVector3 ofs; + if (joint->node[1].body) { + dMULTIPLY0_331 (ofs,joint->node[0].body->R,joint->offset); + dCROSSMAT (info->J1a,ofs,s,+,-); + info->J2l[0] = -1; + info->J2l[s+1] = -1; + info->J2l[2*s+2] = -1; + info->J2a[3*s] = -1; + info->J2a[4*s+1] = -1; + info->J2a[5*s+2] = -1; + } + + // set right hand side for the first three rows (linear) + dReal k = info->fps * info->erp; + if (joint->node[1].body) { + for (int j=0; j<3; j++) + info->c[j] = k * (joint->node[1].body->pos[j] - + joint->node[0].body->pos[j] + ofs[j]); + } + else { + for (int j=0; j<3; j++) + info->c[j] = k * (joint->offset[j] - joint->node[0].body->pos[j]); + } + + // set right hand side for the next three rows (angular). this code is + // borrowed from the slider, so look at the comments there. + // @@@ make a function common to both the slider and this joint !!! + + // get qerr = relative rotation (rotation error) between two bodies + dQuaternion qerr,e; + if (joint->node[1].body) { + dQMultiply1 (qerr,joint->node[0].body->q,joint->node[1].body->q); + } + else { + qerr[0] = joint->node[0].body->q[0]; + for (int i=1; i<4; i++) qerr[i] = -joint->node[0].body->q[i]; + } + if (qerr[0] < 0) { + qerr[1] = -qerr[1]; // adjust sign of qerr to make theta small + qerr[2] = -qerr[2]; + qerr[3] = -qerr[3]; + } + dMULTIPLY0_331 (e,joint->node[0].body->R,qerr+1); // @@@ bad SIMD padding! + info->c[3] = 2*k * e[0]; + info->c[4] = 2*k * e[1]; + info->c[5] = 2*k * e[2]; +} + + +extern "C" void dJointSetFixed (dxJointFixed *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not fixed"); + int i; + + // compute the offset between the bodies + if (joint->node[0].body) { + if (joint->node[1].body) { + dReal ofs[4]; + for (i=0; i<4; i++) ofs[i] = joint->node[0].body->pos[i]; + for (i=0; i<4; i++) ofs[i] -= joint->node[1].body->pos[i]; + dMULTIPLY1_331 (joint->offset,joint->node[0].body->R,ofs); + } + else { + for (i=0; i<4; i++) joint->offset[i] = joint->node[0].body->pos[i]; + } + } +} + + +dxJoint::Vtable __dfixed_vtable = { + sizeof(dxJointFixed), + (dxJoint::init_fn*) fixedInit, + (dxJoint::getInfo1_fn*) fixedGetInfo1, + (dxJoint::getInfo2_fn*) fixedGetInfo2, + dJointTypeFixed}; + +//**************************************************************************** +// null joint + +static void nullGetInfo1 (dxJointNull *j, dxJoint::Info1 *info) +{ + info->m = 0; + info->nub = 0; +} + + +static void nullGetInfo2 (dxJointNull *joint, dxJoint::Info2 *info) +{ + dDebug (0,"this should never get called"); +} + + +dxJoint::Vtable __dnull_vtable = { + sizeof(dxJointNull), + (dxJoint::init_fn*) 0, + (dxJoint::getInfo1_fn*) nullGetInfo1, + (dxJoint::getInfo2_fn*) nullGetInfo2, + dJointTypeNull}; diff --git a/extern/ode/dist/ode/src/joint.h b/extern/ode/dist/ode/src/joint.h new file mode 100644 index 00000000000..e0362ffa829 --- /dev/null +++ b/extern/ode/dist/ode/src/joint.h @@ -0,0 +1,260 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_JOINT_H_ +#define _ODE_JOINT_H_ + + +#include "objects.h" +#include +#include "obstack.h" + + +// joint flags +enum { + // if this flag is set, the joint was allocated in a joint group + dJOINT_INGROUP = 1, + + // if this flag is set, the joint was attached with arguments (0,body). + // our convention is to treat all attaches as (body,0), i.e. so node[0].body + // is always nonzero, so this flag records the fact that the arguments were + // swapped. + dJOINT_REVERSE = 2, + + // if this flag is set, the joint can not have just one body attached to it, + // it must have either zero or two bodies attached. + dJOINT_TWOBODIES = 4 +}; + + +// there are two of these nodes in the joint, one for each connection to a +// body. these are node of a linked list kept by each body of it's connecting +// joints. but note that the body pointer in each node points to the body that +// makes use of the *other* node, not this node. this trick makes it a bit +// easier to traverse the body/joint graph. + +struct dxJointNode { + dxJoint *joint; // pointer to enclosing dxJoint object + dxBody *body; // *other* body this joint is connected to + dxJointNode *next; // next node in body's list of connected joints +}; + + +struct dxJoint : public dObject { + // naming convention: the "first" body this is connected to is node[0].body, + // and the "second" body is node[1].body. if this joint is only connected + // to one body then the second body is 0. + + // info returned by getInfo1 function. the constraint dimension is m (<=6). + // i.e. that is the total number of rows in the jacobian. `nub' is the + // number of unbounded variables (which have lo,hi = -/+ infinity). + + struct Info1 { + int m,nub; + }; + + // info returned by getInfo2 function + + struct Info2 { + // integrator parameters: frames per second (1/stepsize), default error + // reduction parameter (0..1). + dReal fps,erp; + + // for the first and second body, pointers to two (linear and angular) + // n*3 jacobian sub matrices, stored by rows. these matrices will have + // been initialized to 0 on entry. if the second body is zero then the + // J2xx pointers may be 0. + dReal *J1l,*J1a,*J2l,*J2a; + + // elements to jump from one row to the next in J's + int rowskip; + + // right hand sides of the equation J*v = c + cfm * lambda. cfm is the + // "constraint force mixing" vector. c is set to zero on entry, cfm is + // set to a constant value (typically very small or zero) value on entry. + dReal *c,*cfm; + + // lo and hi limits for variables (set to -/+ infinity on entry). + dReal *lo,*hi; + + // findex vector for variables. see the LCP solver interface for a + // description of what this does. this is set to -1 on entry. + // note that the returned indexes are relative to the first index of + // the constraint. + int *findex; + }; + + // virtual function table: size of the joint structure, function pointers. + // we do it this way instead of using C++ virtual functions because + // sometimes we need to allocate joints ourself within a memory pool. + + typedef void init_fn (dxJoint *joint); + typedef void getInfo1_fn (dxJoint *joint, Info1 *info); + typedef void getInfo2_fn (dxJoint *joint, Info2 *info); + struct Vtable { + int size; + init_fn *init; + getInfo1_fn *getInfo1; + getInfo2_fn *getInfo2; + int typenum; // a dJointTypeXXX type number + }; + + Vtable *vtable; // virtual function table + int flags; // dJOINT_xxx flags + dxJointNode node[2]; // connections to bodies. node[1].body can be 0 + dJointFeedback *feedback; // optional feedback structure +}; + + +// joint group. NOTE: any joints in the group that have their world destroyed +// will have their world pointer set to 0. + +struct dxJointGroup : public dBase { + int num; // number of joints on the stack + dObStack stack; // a stack of (possibly differently sized) dxJoint +}; // objects. + + +// common limit and motor information for a single joint axis of movement +struct dxJointLimitMotor { + dReal vel,fmax; // powered joint: velocity, max force + dReal lostop,histop; // joint limits, relative to initial position + dReal fudge_factor; // when powering away from joint limits + dReal normal_cfm; // cfm to use when not at a stop + dReal stop_erp,stop_cfm; // erp and cfm for when at joint limit + dReal bounce; // restitution factor + // variables used between getInfo1() and getInfo2() + int limit; // 0=free, 1=at lo limit, 2=at hi limit + dReal limit_err; // if at limit, amount over limit + + void init (dxWorld *); + void set (int num, dReal value); + dReal get (int num); + int testRotationalLimit (dReal angle); + int addLimot (dxJoint *joint, dxJoint::Info2 *info, int row, + dVector3 ax1, int rotational); +}; + + +// ball and socket + +struct dxJointBall : public dxJoint { + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body +}; +extern struct dxJoint::Vtable __dball_vtable; + + +// hinge + +struct dxJointHinge : public dxJoint { + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + dVector3 axis1; // axis w.r.t first body + dVector3 axis2; // axis w.r.t second body + dQuaternion qrel; // initial relative rotation body1 -> body2 + dxJointLimitMotor limot; // limit and motor information +}; +extern struct dxJoint::Vtable __dhinge_vtable; + + +// universal + +struct dxJointUniversal : public dxJoint { + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + dVector3 axis1; // axis w.r.t first body + dVector3 axis2; // axis w.r.t second body +}; +extern struct dxJoint::Vtable __duniversal_vtable; + + +// slider. if body2 is 0 then qrel is the absolute rotation of body1 and +// offset is the position of body1 center along axis1. + +struct dxJointSlider : public dxJoint { + dVector3 axis1; // axis w.r.t first body + dQuaternion qrel; // initial relative rotation body1 -> body2 + dVector3 offset; // point relative to body2 that should be + // aligned with body1 center along axis1 + dxJointLimitMotor limot; // limit and motor information +}; +extern struct dxJoint::Vtable __dslider_vtable; + + +// contact + +struct dxJointContact : public dxJoint { + int the_m; // number of rows computed by getInfo1 + dContact contact; +}; +extern struct dxJoint::Vtable __dcontact_vtable; + + +// hinge 2 + +struct dxJointHinge2 : public dxJoint { + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + dVector3 axis1; // axis 1 w.r.t first body + dVector3 axis2; // axis 2 w.r.t second body + dReal c0,s0; // cos,sin of desired angle between axis 1,2 + dVector3 v1,v2; // angle ref vectors embedded in first body + dxJointLimitMotor limot1; // limit+motor info for axis 1 + dxJointLimitMotor limot2; // limit+motor info for axis 2 + dReal susp_erp,susp_cfm; // suspension parameters (erp,cfm) +}; +extern struct dxJoint::Vtable __dhinge2_vtable; + + +// angular motor + +struct dxJointAMotor : public dxJoint { + int num; // number of axes (0..3) + int mode; // a dAMotorXXX constant + int rel[3]; // what the axes are relative to (global,b1,b2) + dVector3 axis[3]; // three axes + dxJointLimitMotor limot[3]; // limit+motor info for axes + dReal angle[3]; // user-supplied angles for axes + // these vectors are used for calculating euler angles + dVector3 reference1; // original axis[2], relative to body 1 + dVector3 reference2; // original axis[0], relative to body 2 +}; +extern struct dxJoint::Vtable __damotor_vtable; + + +// fixed + +struct dxJointFixed : public dxJoint { + dVector3 offset; // relative offset between the bodies +}; +extern struct dxJoint::Vtable __dfixed_vtable; + + +// null joint, for testing only + +struct dxJointNull : public dxJoint { +}; +extern struct dxJoint::Vtable __dnull_vtable; + +#endif + diff --git a/extern/ode/dist/ode/src/lcp.cpp b/extern/ode/dist/ode/src/lcp.cpp new file mode 100644 index 00000000000..dba2d3b949b --- /dev/null +++ b/extern/ode/dist/ode/src/lcp.cpp @@ -0,0 +1,1455 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + + +THE ALGORITHM +------------- + +solve A*x = b+w, with x and w subject to certain LCP conditions. +each x(i),w(i) must lie on one of the three line segments in the following +diagram. each line segment corresponds to one index set : + + w(i) + /|\ | : + | | : + | |i in N : + w>0 | |state[i]=0 : + | | : + | | : i in C + w=0 + +-----------------------+ + | : | + | : | + w<0 | : |i in N + | : |state[i]=1 + | : | + | : | + +-------|-----------|-----------|----------> x(i) + lo 0 hi + +the Dantzig algorithm proceeds as follows: + for i=1:n + * if (x(i),w(i)) is not on the line, push x(i) and w(i) positive or + negative towards the line. as this is done, the other (x(j),w(j)) + for j= 0. this makes the algorithm a bit +simpler, because the starting point for x(i),w(i) is always on the dotted +line x=0 and x will only ever increase in one direction, so it can only hit +two out of the three line segments. + + +NOTES +----- + +this is an implementation of "lcp_dantzig2_ldlt.m" and "lcp_dantzig_lohi.m". +the implementation is split into an LCP problem object (dLCP) and an LCP +driver function. most optimization occurs in the dLCP object. + +a naive implementation of the algorithm requires either a lot of data motion +or a lot of permutation-array lookup, because we are constantly re-ordering +rows and columns. to avoid this and make a more optimized algorithm, a +non-trivial data structure is used to represent the matrix A (this is +implemented in the fast version of the dLCP object). + +during execution of this algorithm, some indexes in A are clamped (set C), +some are non-clamped (set N), and some are "don't care" (where x=0). +A,x,b,w (and other problem vectors) are permuted such that the clamped +indexes are first, the unclamped indexes are next, and the don't-care +indexes are last. this permutation is recorded in the array `p'. +initially p = 0..n-1, and as the rows and columns of A,x,b,w are swapped, +the corresponding elements of p are swapped. + +because the C and N elements are grouped together in the rows of A, we can do +lots of work with a fast dot product function. if A,x,etc were not permuted +and we only had a permutation array, then those dot products would be much +slower as we would have a permutation array lookup in some inner loops. + +A is accessed through an array of row pointers, so that element (i,j) of the +permuted matrix is A[i][j]. this makes row swapping fast. for column swapping +we still have to actually move the data. + +during execution of this algorithm we maintain an L*D*L' factorization of +the clamped submatrix of A (call it `AC') which is the top left nC*nC +submatrix of A. there are two ways we could arrange the rows/columns in AC. + +(1) AC is always permuted such that L*D*L' = AC. this causes a problem + when a row/column is removed from C, because then all the rows/columns of A + between the deleted index and the end of C need to be rotated downward. + this results in a lot of data motion and slows things down. +(2) L*D*L' is actually a factorization of a *permutation* of AC (which is + itself a permutation of the underlying A). this is what we do - the + permutation is recorded in the vector C. call this permutation A[C,C]. + when a row/column is removed from C, all we have to do is swap two + rows/columns and manipulate C. + +*/ + +#include +#include "lcp.h" +#include +#include +#include "mat.h" // for testing +#include // for testing + +//*************************************************************************** +// code generation parameters + +// LCP debugging (mosty for fast dLCP) - this slows things down a lot +//#define DEBUG_LCP + +//#define dLCP_SLOW // use slow dLCP object +#define dLCP_FAST // use fast dLCP object + +// option 1 : matrix row pointers (less data copying) +#define ROWPTRS +#define ATYPE dReal ** +#define AROW(i) (A[i]) + +// option 2 : no matrix row pointers (slightly faster inner loops) +//#define NOROWPTRS +//#define ATYPE dReal * +//#define AROW(i) (A+(i)*nskip) + +// misc defines +#define ALLOCA dALLOCA16 +//#define dDot myDot +#define NUB_OPTIMIZATIONS + +//*************************************************************************** + +// an alternative inline dot product, for speed comparisons + +static inline dReal myDot (dReal *a, dReal *b, int n) +{ + dReal sum=0; + while (n > 0) { + sum += (*a) * (*b); + a++; + b++; + n--; + } + return sum; +} + + +// swap row/column i1 with i2 in the n*n matrix A. the leading dimension of +// A is nskip. this only references and swaps the lower triangle. +// if `do_fast_row_swaps' is nonzero and row pointers are being used, then +// rows will be swapped by exchanging row pointers. otherwise the data will +// be copied. + +static void swapRowsAndCols (ATYPE A, int n, int i1, int i2, int nskip, + int do_fast_row_swaps) +{ + int i; + dIASSERT (A && n > 0 && i1 >= 0 && i2 >= 0 && i1 < n && i2 < n && + nskip >= n && i1 < i2); + +# ifdef ROWPTRS + for (i=i1+1; i 0) { + memcpy (tmprow,A+i1*nskip,i1*sizeof(dReal)); + memcpy (A+i1*nskip,A+i2*nskip,i1*sizeof(dReal)); + memcpy (A+i2*nskip,tmprow,i1*sizeof(dReal)); + } + for (i=i1+1; i0 && i1 >=0 && i2 >= 0 && i1 < n && i2 < n && nskip >= n && + i1 <= i2); + if (i1==i2) return; + swapRowsAndCols (A,n,i1,i2,nskip,do_fast_row_swaps); + tmp = x[i1]; + x[i1] = x[i2]; + x[i2] = tmp; + tmp = b[i1]; + b[i1] = b[i2]; + b[i2] = tmp; + tmp = w[i1]; + w[i1] = w[i2]; + w[i2] = tmp; + tmp = lo[i1]; + lo[i1] = lo[i2]; + lo[i2] = tmp; + tmp = hi[i1]; + hi[i1] = hi[i2]; + hi[i2] = tmp; + tmpi = p[i1]; + p[i1] = p[i2]; + p[i2] = tmpi; + tmpi = state[i1]; + state[i1] = state[i2]; + state[i2] = tmpi; + if (findex) { + tmpi = findex[i1]; + findex[i1] = findex[i2]; + findex[i2] = tmpi; + } +} + + +// for debugging - check that L,d is the factorization of A[C,C]. +// A[C,C] has size nC*nC and leading dimension nskip. +// L has size nC*nC and leading dimension nskip. +// d has size nC. + +#ifdef DEBUG_LCP + +static void checkFactorization (ATYPE A, dReal *_L, dReal *_d, + int nC, int *C, int nskip) +{ + int i,j; + if (nC==0) return; + + // get A1=A, copy the lower triangle to the upper triangle, get A2=A[C,C] + dMatrix A1 (nC,nC); + for (i=0; i 1e-8) + dDebug (0,"L*D*L' check, maximum difference = %.6e\n",diff); +} + +#endif + + +// for debugging + +#ifdef DEBUG_LCP + +static void checkPermutations (int i, int n, int nC, int nN, int *p, int *C) +{ + int j,k; + dIASSERT (nC>=0 && nN>=0 && (nC+nN)==i && i < n); + for (k=0; k= 0 && p[k] < i); + for (k=i; k C,N; // index sets + int last_i_for_solve1; // last i value given to solve1 + + dLCP (int _n, int _nub, dReal *_Adata, dReal *_x, dReal *_b, dReal *_w, + dReal *_lo, dReal *_hi, dReal *_L, dReal *_d, + dReal *_Dell, dReal *_ell, dReal *_tmp, + int *_state, int *_findex, int *_p, int *_C, dReal **Arows); + // the constructor is given an initial problem description (A,x,b,w) and + // space for other working data (which the caller may allocate on the stack). + // some of this data is specific to the fast dLCP implementation. + // the matrices A and L have size n*n, vectors have size n*1. + // A represents a symmetric matrix but only the lower triangle is valid. + // `nub' is the number of unbounded indexes at the start. all the indexes + // 0..nub-1 will be put into C. + + ~dLCP(); + + int getNub() { return nub; } + // return the value of `nub'. the constructor may want to change it, + // so the caller should find out its new value. + + // transfer functions: transfer index i to the given set (C or N). indexes + // less than `nub' can never be given. A,x,b,w,etc may be permuted by these + // functions, the caller must be robust to this. + + void transfer_i_to_C (int i); + // this assumes C and N span 1:i-1. this also assumes that solve1() has + // been recently called for the same i without any other transfer + // functions in between (thereby allowing some data reuse for the fast + // implementation). + void transfer_i_to_N (int i); + // this assumes C and N span 1:i-1. + void transfer_i_from_N_to_C (int i); + void transfer_i_from_C_to_N (int i); + + int numC(); + int numN(); + // return the number of indexes in set C/N + + int indexC (int i); + int indexN (int i); + // return index i in set C/N. + + // accessor and arithmetic functions. Aij translates as A(i,j), etc. + // make sure that only the lower triangle of A is ever referenced. + + dReal Aii (int i); + dReal AiC_times_qC (int i, dReal *q); + dReal AiN_times_qN (int i, dReal *q); // for all Nj + void pN_equals_ANC_times_qC (dReal *p, dReal *q); // for all Nj + void pN_plusequals_ANi (dReal *p, int i, int sign=1); + // for all Nj. sign = +1,-1. assumes i > maximum index in N. + void pC_plusequals_s_times_qC (dReal *p, dReal s, dReal *q); + void pN_plusequals_s_times_qN (dReal *p, dReal s, dReal *q); // for all Nj + void solve1 (dReal *a, int i, int dir=1, int only_transfer=0); + // get a(C) = - dir * A(C,C) \ A(C,i). dir must be +/- 1. + // the fast version of this function computes some data that is needed by + // transfer_i_to_C(). if only_transfer is nonzero then this function + // *only* computes that data, it does not set a(C). + + void unpermute(); + // call this at the end of the LCP function. if the x/w values have been + // permuted then this will unscramble them. +}; + + +dLCP::dLCP (int _n, int _nub, dReal *_Adata, dReal *_x, dReal *_b, dReal *_w, + dReal *_lo, dReal *_hi, dReal *_L, dReal *_d, + dReal *_Dell, dReal *_ell, dReal *_tmp, + int *_state, int *_findex, int *_p, int *_C, dReal **Arows) +{ + dUASSERT (_findex==0,"slow dLCP object does not support findex array"); + + n = _n; + nub = _nub; + Adata = _Adata; + A = 0; + x = _x; + b = _b; + w = _w; + lo = _lo; + hi = _hi; + nskip = dPAD(n); + dSetZero (x,n); + last_i_for_solve1 = -1; + + int i,j; + C.setSize (n); + N.setSize (n); + for (int i=0; i0, put all indexes 0..nub-1 into C and solve for x + if (nub > 0) { + for (i=0; i= i) dDebug (0,"N assumption violated"); + if (sign > 0) { + for (k=0; k 0) { + for (ii=0; ii nub + if (nub < n) { + for (k=0; k<100; k++) { + int i1,i2; + do { + i1 = dRandInt(n-nub)+nub; + i2 = dRandInt(n-nub)+nub; + } + while (i1 > i2); + //printf ("--> %d %d\n",i1,i2); + swapProblem (A,x,b,w,lo,hi,p,state,findex,n,i1,i2,nskip,0); + } + } + */ + + // permute the problem so that *all* the unbounded variables are at the + // start, i.e. look for unbounded variables not included in `nub'. we can + // potentially push up `nub' this way and get a bigger initial factorization. + // note that when we swap rows/cols here we must not just swap row pointers, + // as the initial factorization relies on the data being all in one chunk. + for (k=nub; k 0) { + for (k=0; k nub such that all findex variables are at the end + if (findex) { + int num_at_end = 0; + for (k=n-1; k >= nub; k--) { + if (findex[k] >= 0) { + swapProblem (A,x,b,w,lo,hi,p,state,findex,n,k,n-1-num_at_end,nskip,1); + num_at_end++; + } + } + } + + // print info about indexes + /* + for (k=0; k 0) { + // ell,Dell were computed by solve1(). note, ell = D \ L1solve (L,A(i,C)) + for (j=0; j 0) { + dReal *aptr = AROW(i); +# ifdef NUB_OPTIMIZATIONS + // if nub>0, initial part of aptr unpermuted + for (j=0; j 0) { + for (int i=0; i 0) { + dReal *aptr = AROW(i); +# ifdef NUB_OPTIMIZATIONS + // if nub>0, initial part of aptr[] is guaranteed unpermuted + for (j=0; j 0) { + for (j=0; j0 && A && x && b && w && nub == 0); + + int i,k; + int nskip = dPAD(n); + dReal *L = (dReal*) ALLOCA (n*nskip*sizeof(dReal)); + dReal *d = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *delta_x = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *delta_w = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *Dell = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *ell = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *tmp = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal **Arows = (dReal**) ALLOCA (n*sizeof(dReal*)); + int *p = (int*) ALLOCA (n*sizeof(int)); + int *C = (int*) ALLOCA (n*sizeof(int)); + int *dummy = (int*) ALLOCA (n*sizeof(int)); + + dLCP lcp (n,0,A,x,b,w,tmp,tmp,L,d,Dell,ell,tmp,dummy,dummy,p,C,Arows); + nub = lcp.getNub(); + + for (i=0; i= 0) { + lcp.transfer_i_to_N (i); + } + else { + for (;;) { + // compute: delta_x(C) = -A(C,C)\A(C,i) + dSetZero (delta_x,n); + lcp.solve1 (delta_x,i); + delta_x[i] = 1; + + // compute: delta_w = A*delta_x + dSetZero (delta_w,n); + lcp.pN_equals_ANC_times_qC (delta_w,delta_x); + lcp.pN_plusequals_ANi (delta_w,i); + delta_w[i] = lcp.AiC_times_qC (i,delta_x) + lcp.Aii(i); + + // find index to switch + int si = i; // si = switch index + int si_in_N = 0; // set to 1 if si in N + dReal s = -w[i]/delta_w[i]; + + if (s <= 0) { + dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s); + if (i < (n-1)) { + dSetZero (x+i,n-i); + dSetZero (w+i,n-i); + } + goto done; + } + + for (k=0; k < lcp.numN(); k++) { + if (delta_w[lcp.indexN(k)] < 0) { + dReal s2 = -w[lcp.indexN(k)] / delta_w[lcp.indexN(k)]; + if (s2 < s) { + s = s2; + si = lcp.indexN(k); + si_in_N = 1; + } + } + } + for (k=0; k < lcp.numC(); k++) { + if (delta_x[lcp.indexC(k)] < 0) { + dReal s2 = -x[lcp.indexC(k)] / delta_x[lcp.indexC(k)]; + if (s2 < s) { + s = s2; + si = lcp.indexC(k); + si_in_N = 0; + } + } + } + + // apply x = x + s * delta_x + lcp.pC_plusequals_s_times_qC (x,s,delta_x); + x[i] += s; + lcp.pN_plusequals_s_times_qN (w,s,delta_w); + w[i] += s * delta_w[i]; + + // switch indexes between sets if necessary + if (si==i) { + w[i] = 0; + lcp.transfer_i_to_C (i); + break; + } + if (si_in_N) { + w[si] = 0; + lcp.transfer_i_from_N_to_C (si); + } + else { + x[si] = 0; + lcp.transfer_i_from_C_to_N (si); + } + } + } + } + + done: + lcp.unpermute(); +} + +//*************************************************************************** +// an optimized Dantzig LCP driver routine for the lo-hi LCP problem. + +void dSolveLCP (int n, dReal *A, dReal *x, dReal *b, + dReal *w, int nub, dReal *lo, dReal *hi, int *findex) +{ + dAASSERT (n>0 && A && x && b && w && lo && hi && nub >= 0 && nub <= n); + int i,k,hit_first_friction_index = 0; + int nskip = dPAD(n); + + // if all the variables are unbounded then we can just factor, solve, + // and return + if (nub >= n) { + dFactorLDLT (A,w,n,nskip); // use w for d + dSolveLDLT (A,w,b,n,nskip); + memcpy (x,b,n*sizeof(dReal)); + dSetZero (w,n); + return; + } + +# ifndef dNODEBUG + // check restrictions on lo and hi + for (k=0; k= 0); +# endif + + dReal *L = (dReal*) ALLOCA (n*nskip*sizeof(dReal)); + dReal *d = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *delta_x = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *delta_w = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *Dell = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *ell = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal **Arows = (dReal**) ALLOCA (n*sizeof(dReal*)); + int *p = (int*) ALLOCA (n*sizeof(int)); + int *C = (int*) ALLOCA (n*sizeof(int)); + int dir; + dReal dirf; + + // for i in N, state[i] is 0 if x(i)==lo(i) or 1 if x(i)==hi(i) + int *state = (int*) ALLOCA (n*sizeof(int)); + + // create LCP object. note that tmp is set to delta_w to save space, this + // optimization relies on knowledge of how tmp is used, so be careful! + dLCP lcp (n,nub,A,x,b,w,lo,hi,L,d,Dell,ell,delta_w,state,findex,p,C,Arows); + nub = lcp.getNub(); + + // loop over all indexes nub..n-1. for index i, if x(i),w(i) satisfy the + // LCP conditions then i is added to the appropriate index set. otherwise + // x(i),w(i) is driven either +ve or -ve to force it to the valid region. + // as we drive x(i), x(C) is also adjusted to keep w(C) at zero. + // while driving x(i) we maintain the LCP conditions on the other variables + // 0..i-1. we do this by watching out for other x(i),w(i) values going + // outside the valid region, and then switching them between index sets + // when that happens. + + for (i=nub; i= 0) { + // un-permute x into delta_w, which is not being used at the moment + for (k=0; k= 0) { + lcp.transfer_i_to_N (i); + state[i] = 0; + } + else if (hi[i]==0 && w[i] <= 0) { + lcp.transfer_i_to_N (i); + state[i] = 1; + } + else if (w[i]==0) { + // this is a degenerate case. by the time we get to this test we know + // that lo != 0, which means that lo < 0 as lo is not allowed to be +ve, + // and similarly that hi > 0. this means that the line segment + // corresponding to set C is at least finite in extent, and we are on it. + // NOTE: we must call lcp.solve1() before lcp.transfer_i_to_C() + lcp.solve1 (delta_x,i,0,1); + lcp.transfer_i_to_C (i); + } + else { + // we must push x(i) and w(i) + for (;;) { + // find direction to push on x(i) + if (w[i] <= 0) { + dir = 1; + dirf = REAL(1.0); + } + else { + dir = -1; + dirf = REAL(-1.0); + } + + // compute: delta_x(C) = -dir*A(C,C)\A(C,i) + lcp.solve1 (delta_x,i,dir); + // note that delta_x[i] = dirf, but we wont bother to set it + + // compute: delta_w = A*delta_x ... note we only care about + // delta_w(N) and delta_w(i), the rest is ignored + lcp.pN_equals_ANC_times_qC (delta_w,delta_x); + lcp.pN_plusequals_ANi (delta_w,i,dir); + delta_w[i] = lcp.AiC_times_qC (i,delta_x) + lcp.Aii(i)*dirf; + + // find largest step we can take (size=s), either to drive x(i),w(i) + // to the valid LCP region or to drive an already-valid variable + // outside the valid region. + + int cmd = 1; // index switching command + int si = 0; // si = index to switch if cmd>3 + dReal s = -w[i]/delta_w[i]; + if (dir > 0) { + if (hi[i] < dInfinity) { + dReal s2 = (hi[i]-x[i])/dirf; // step to x(i)=hi(i) + if (s2 < s) { + s = s2; + cmd = 3; + } + } + } + else { + if (lo[i] > -dInfinity) { + dReal s2 = (lo[i]-x[i])/dirf; // step to x(i)=lo(i) + if (s2 < s) { + s = s2; + cmd = 2; + } + } + } + + for (k=0; k < lcp.numN(); k++) { + if ((state[lcp.indexN(k)]==0 && delta_w[lcp.indexN(k)] < 0) || + (state[lcp.indexN(k)]!=0 && delta_w[lcp.indexN(k)] > 0)) { + // don't bother checking if lo=hi=0 + if (lo[lcp.indexN(k)] == 0 && hi[lcp.indexN(k)] == 0) continue; + dReal s2 = -w[lcp.indexN(k)] / delta_w[lcp.indexN(k)]; + if (s2 < s) { + s = s2; + cmd = 4; + si = lcp.indexN(k); + } + } + } + + for (k=nub; k < lcp.numC(); k++) { + if (delta_x[lcp.indexC(k)] < 0 && lo[lcp.indexC(k)] > -dInfinity) { + dReal s2 = (lo[lcp.indexC(k)]-x[lcp.indexC(k)]) / + delta_x[lcp.indexC(k)]; + if (s2 < s) { + s = s2; + cmd = 5; + si = lcp.indexC(k); + } + } + if (delta_x[lcp.indexC(k)] > 0 && hi[lcp.indexC(k)] < dInfinity) { + dReal s2 = (hi[lcp.indexC(k)]-x[lcp.indexC(k)]) / + delta_x[lcp.indexC(k)]; + if (s2 < s) { + s = s2; + cmd = 6; + si = lcp.indexC(k); + } + } + } + + //static char* cmdstring[8] = {0,"->C","->NL","->NH","N->C", + // "C->NL","C->NH"}; + //printf ("cmd=%d (%s), si=%d\n",cmd,cmdstring[cmd],(cmd>3) ? si : i); + + // if s <= 0 then we've got a problem. if we just keep going then + // we're going to get stuck in an infinite loop. instead, just cross + // our fingers and exit with the current solution. + if (s <= 0) { + dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s); + if (i < (n-1)) { + dSetZero (x+i,n-i); + dSetZero (w+i,n-i); + } + goto done; + } + + // apply x = x + s * delta_x + lcp.pC_plusequals_s_times_qC (x,s,delta_x); + x[i] += s * dirf; + + // apply w = w + s * delta_w + lcp.pN_plusequals_s_times_qN (w,s,delta_w); + w[i] += s * delta_w[i]; + + // switch indexes between sets if necessary + switch (cmd) { + case 1: // done + w[i] = 0; + lcp.transfer_i_to_C (i); + break; + case 2: // done + x[i] = lo[i]; + state[i] = 0; + lcp.transfer_i_to_N (i); + break; + case 3: // done + x[i] = hi[i]; + state[i] = 1; + lcp.transfer_i_to_N (i); + break; + case 4: // keep going + w[si] = 0; + lcp.transfer_i_from_N_to_C (si); + break; + case 5: // keep going + x[si] = lo[si]; + state[si] = 0; + lcp.transfer_i_from_C_to_N (si); + break; + case 6: // keep going + x[si] = hi[si]; + state[si] = 1; + lcp.transfer_i_from_C_to_N (si); + break; + } + + if (cmd <= 3) break; + } + } + } + + done: + lcp.unpermute(); +} + +//*************************************************************************** +// accuracy and timing test + +extern "C" void dTestSolveLCP() +{ + int n = 100; + int i,nskip = dPAD(n); + const dReal tol = REAL(1e-9); + printf ("dTestSolveLCP()\n"); + + dReal *A = (dReal*) ALLOCA (n*nskip*sizeof(dReal)); + dReal *x = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *b = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *w = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *lo = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *hi = (dReal*) ALLOCA (n*sizeof(dReal)); + + dReal *A2 = (dReal*) ALLOCA (n*nskip*sizeof(dReal)); + dReal *b2 = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *lo2 = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *hi2 = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *tmp1 = (dReal*) ALLOCA (n*sizeof(dReal)); + dReal *tmp2 = (dReal*) ALLOCA (n*sizeof(dReal)); + + double total_time = 0; + for (int count=0; count < 1000; count++) { + + // form (A,b) = a random positive definite LCP problem + dMakeRandomMatrix (A2,n,n,1.0); + dMultiply2 (A,A2,A2,n,n,n); + dMakeRandomMatrix (x,n,1,1.0); + dMultiply0 (b,A,x,n,n,1); + for (i=0; i tol ? "FAILED" : "passed"); + if (diff > tol) dDebug (0,"A*x = b+w, maximum difference = %.6e",diff); + int n1=0,n2=0,n3=0; + for (i=0; i= 0) { + n1++; // ok + } + else if (x[i]==hi[i] && w[i] <= 0) { + n2++; // ok + } + else if (x[i] >= lo[i] && x[i] <= hi[i] && w[i] == 0) { + n3++; // ok + } + else { + dDebug (0,"FAILED: i=%d x=%.4e w=%.4e lo=%.4e hi=%.4e",i, + x[i],w[i],lo[i],hi[i]); + } + } + + // pacifier + printf ("passed: NL=%3d NH=%3d C=%3d ",n1,n2,n3); + printf ("time=%10.3f ms avg=%10.4f\n",time * 1000.0,average); + } +} diff --git a/extern/ode/dist/ode/src/lcp.h b/extern/ode/dist/ode/src/lcp.h new file mode 100644 index 00000000000..86cbd6319eb --- /dev/null +++ b/extern/ode/dist/ode/src/lcp.h @@ -0,0 +1,59 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +given (A,b,lo,hi), solve the LCP problem: A*x = b+w, where each x(i),w(i) +satisfies one of + (1) x = lo, w >= 0 + (2) x = hi, w <= 0 + (3) lo < x < hi, w = 0 +A is a matrix of dimension n*n, everything else is a vector of size n*1. +lo and hi can be +/- dInfinity as needed. the first `nub' variables are +unbounded, i.e. hi and lo are assumed to be +/- dInfinity. + +we restrict lo(i) <= 0 and hi(i) >= 0. + +the original data (A,b) may be modified by this function. + +if the `findex' (friction index) parameter is nonzero, it points to an array +of index values. in this case constraints that have findex[i] >= 0 are +special. all non-special constraints are solved for, then the lo and hi values +for the special constraints are set: + hi[i] = abs( hi[i] * x[findex[i]] ) + lo[i] = -hi[i] +and the solution continues. this mechanism allows a friction approximation +to be implemented. + +*/ + + +#ifndef _ODE_LCP_H_ +#define _ODE_LCP_H_ + + +void dSolveLCP (int n, dReal *A, dReal *x, dReal *b, dReal *w, + int nub, dReal *lo, dReal *hi, int *findex); + + +#endif + diff --git a/extern/ode/dist/ode/src/mass.cpp b/extern/ode/dist/ode/src/mass.cpp new file mode 100644 index 00000000000..9c1aae2033f --- /dev/null +++ b/extern/ode/dist/ode/src/mass.cpp @@ -0,0 +1,261 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include +#include +#include + + +#define _I(i,j) I[(i)*4+(j)] + + +// return 1 if ok, 0 if bad + +static int checkMass (dMass *m) +{ + if (m->mass <= 0) { + dDEBUGMSG ("mass must be > 0"); + return 0; + } + if (!dIsPositiveDefinite (m->I,3)) { + dDEBUGMSG ("inertia must be positive definite"); + return 0; + } + + // verify that the center of mass position is consistent with the mass + // and inertia matrix. this is done by checking that the inertia around + // the center of mass is also positive definite. from the comment in + // dMassTranslate(), if the body is translated so that its center of mass + // is at the point of reference, then the new inertia is: + // I + mass*crossmat(c)^2 + // note that requiring this to be positive definite is exactly equivalent + // to requiring that the spatial inertia matrix + // [ mass*eye(3,3) M*crossmat(c)^T ] + // [ M*crossmat(c) I ] + // is positive definite, given that I is PD and mass>0. see the theorem + // about partitioned PD matrices for proof. + + dMatrix3 I2,chat; + dSetZero (chat,12); + dCROSSMAT (chat,m->c,4,+,-); + dMULTIPLY0_333 (I2,chat,chat); + for (int i=0; i<12; i++) I2[i] = m->I[i] + m->mass*I2[i]; + if (!dIsPositiveDefinite (I2,3)) { + dDEBUGMSG ("center of mass inconsistent with mass parameters"); + return 0; + } + return 1; +} + + +void dMassSetZero (dMass *m) +{ + dAASSERT (m); + m->mass = REAL(0.0); + dSetZero (m->c,sizeof(m->c) / sizeof(dReal)); + dSetZero (m->I,sizeof(m->I) / sizeof(dReal)); +} + + +void dMassSetParameters (dMass *m, dReal themass, + dReal cgx, dReal cgy, dReal cgz, + dReal I11, dReal I22, dReal I33, + dReal I12, dReal I13, dReal I23) +{ + dAASSERT (m); + dMassSetZero (m); + m->mass = themass; + m->c[0] = cgx; + m->c[1] = cgy; + m->c[2] = cgz; + m->_I(0,0) = I11; + m->_I(1,1) = I22; + m->_I(2,2) = I33; + m->_I(0,1) = I12; + m->_I(0,2) = I13; + m->_I(1,2) = I23; + m->_I(1,0) = I12; + m->_I(2,0) = I13; + m->_I(2,1) = I23; + checkMass (m); +} + + +void dMassSetSphere (dMass *m, dReal density, dReal radius) +{ + dAASSERT (m); + dMassSetZero (m); + m->mass = (REAL(4.0)/REAL(3.0)) * M_PI * radius*radius*radius * density; + dReal II = REAL(0.4) * m->mass * radius*radius; + m->_I(0,0) = II; + m->_I(1,1) = II; + m->_I(2,2) = II; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassSetCappedCylinder (dMass *m, dReal density, int direction, + dReal a, dReal b) +{ + dReal M1,M2,Ia,Ib; + dAASSERT (m); + dUASSERT (direction >= 1 && direction <= 3,"bad direction number"); + dMassSetZero (m); + M1 = M_PI*a*a*b*density; // cylinder mass + M2 = (REAL(4.0)/REAL(3.0))*M_PI*a*a*a*density; // total cap mass + m->mass = M1+M2; + Ia = M1*(REAL(0.25)*a*a + (REAL(1.0)/REAL(12.0))*b*b) + + M2*(REAL(0.4)*a*a + REAL(0.5)*b*b); + Ib = (M1*REAL(0.5) + M2*REAL(0.4))*a*a; + m->_I(0,0) = Ia; + m->_I(1,1) = Ia; + m->_I(2,2) = Ia; + m->_I(direction-1,direction-1) = Ib; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassSetBox (dMass *m, dReal density, + dReal lx, dReal ly, dReal lz) +{ + dAASSERT (m); + dMassSetZero (m); + dReal M = lx*ly*lz*density; + m->mass = M; + m->_I(0,0) = M/REAL(12.0) * (ly*ly + lz*lz); + m->_I(1,1) = M/REAL(12.0) * (lx*lx + lz*lz); + m->_I(2,2) = M/REAL(12.0) * (lx*lx + ly*ly); + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassAdjust (dMass *m, dReal newmass) +{ + dAASSERT (m); + dReal scale = newmass / m->mass; + m->mass = newmass; + for (int i=0; i<3; i++) for (int j=0; j<3; j++) m->_I(i,j) *= scale; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassTranslate (dMass *m, dReal x, dReal y, dReal z) +{ + // if the body is translated by `a' relative to its point of reference, + // the new inertia about the point of reference is: + // + // I + mass*(crossmat(c)^2 - crossmat(c+a)^2) + // + // where c is the existing center of mass and I is the old inertia. + + int i,j; + dMatrix3 ahat,chat,t1,t2; + dReal a[3]; + + dAASSERT (m); + + // adjust inertia matrix + dSetZero (chat,12); + dCROSSMAT (chat,m->c,4,+,-); + a[0] = x + m->c[0]; + a[1] = y + m->c[1]; + a[2] = z + m->c[2]; + dSetZero (ahat,12); + dCROSSMAT (ahat,a,4,+,-); + dMULTIPLY0_333 (t1,ahat,ahat); + dMULTIPLY0_333 (t2,chat,chat); + for (i=0; i<3; i++) for (j=0; j<3; j++) + m->_I(i,j) += m->mass * (t2[i*4+j]-t1[i*4+j]); + + // ensure perfect symmetry + m->_I(1,0) = m->_I(0,1); + m->_I(2,0) = m->_I(0,2); + m->_I(2,1) = m->_I(1,2); + + // adjust center of mass + m->c[0] += x; + m->c[1] += y; + m->c[2] += z; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassRotate (dMass *m, const dMatrix3 R) +{ + // if the body is rotated by `R' relative to its point of reference, + // the new inertia about the point of reference is: + // + // R * I * R' + // + // where I is the old inertia. + + dMatrix3 t1; + dReal t2[3]; + + dAASSERT (m); + + // rotate inertia matrix + dMULTIPLY2_333 (t1,m->I,R); + dMULTIPLY0_333 (m->I,R,t1); + + // ensure perfect symmetry + m->_I(1,0) = m->_I(0,1); + m->_I(2,0) = m->_I(0,2); + m->_I(2,1) = m->_I(1,2); + + // rotate center of mass + dMULTIPLY0_331 (t2,R,m->c); + m->c[0] = t2[0]; + m->c[1] = t2[1]; + m->c[2] = t2[2]; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassAdd (dMass *a, const dMass *b) +{ + int i; + dAASSERT (a && b); + dReal denom = dRecip (a->mass + b->mass); + for (i=0; i<3; i++) a->c[i] = (a->c[i]*a->mass + b->c[i]*b->mass)*denom; + a->mass += b->mass; + for (i=0; i<12; i++) a->I[i] += b->I[i]; +} diff --git a/extern/ode/dist/ode/src/mat.cpp b/extern/ode/dist/ode/src/mat.cpp new file mode 100644 index 00000000000..6e635dcc994 --- /dev/null +++ b/extern/ode/dist/ode/src/mat.cpp @@ -0,0 +1,230 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include +#include +#include +#include +#include "mat.h" + + +dMatrix::dMatrix() +{ + n = 0; + m = 0; + data = 0; +} + + +dMatrix::dMatrix (int rows, int cols) +{ + if (rows < 1 || cols < 1) dDebug (0,"bad matrix size"); + n = rows; + m = cols; + data = (dReal*) dAlloc (n*m*sizeof(dReal)); + dSetZero (data,n*m); +} + + +dMatrix::dMatrix (const dMatrix &a) +{ + n = a.n; + m = a.m; + data = (dReal*) dAlloc (n*m*sizeof(dReal)); + memcpy (data,a.data,n*m*sizeof(dReal)); +} + + +dMatrix::dMatrix (int rows, int cols, + dReal *_data, int rowskip, int colskip) +{ + if (rows < 1 || cols < 1) dDebug (0,"bad matrix size"); + n = rows; + m = cols; + data = (dReal*) dAlloc (n*m*sizeof(dReal)); + for (int i=0; i= n || j < 0 || j >= m) dDebug (0,"bad matrix (i,j)"); + return data [i*m+j]; +} + + +void dMatrix::operator= (const dMatrix &a) +{ + if (data) dFree (data,n*m*sizeof(dReal)); + n = a.n; + m = a.m; + if (n > 0 && m > 0) { + data = (dReal*) dAlloc (n*m*sizeof(dReal)); + memcpy (data,a.data,n*m*sizeof(dReal)); + } + else data = 0; +} + + +void dMatrix::operator= (dReal a) +{ + for (int i=0; i= n || q[i] < 0 || q[i] >= m) + dDebug (0,"Matrix select, bad index arrays"); + r.data[i*nq+j] = data[p[i]*m+q[j]]; + } + } + return r; +} + + +dMatrix dMatrix::operator + (const dMatrix &a) +{ + if (n != a.n || m != a.m) dDebug (0,"matrix +, mismatched sizes"); + dMatrix r (n,m); + for (int i=0; i max) max = diff; + } + } + return max; +} diff --git a/extern/ode/dist/ode/src/mat.h b/extern/ode/dist/ode/src/mat.h new file mode 100644 index 00000000000..26f6bd1093a --- /dev/null +++ b/extern/ode/dist/ode/src/mat.h @@ -0,0 +1,72 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// matrix class. this is mostly for convenience in the testing code, it is +// not optimized at all. correctness is much more importance here. + +#ifndef _ODE_MAT_H_ +#define _ODE_MAT_H_ + +#include + + +class dMatrix { + int n,m; // matrix dimension, n,m >= 0 + dReal *data; // if nonzero, n*m elements allocated on the heap + +public: + // constructors, destructors + dMatrix(); // make default 0x0 matrix + dMatrix (int rows, int cols); // construct zero matrix of given size + dMatrix (const dMatrix &); // construct copy of given matrix + // create copy of given data - element (i,j) is data[i*rowskip+j*colskip] + dMatrix (int rows, int cols, dReal *_data, int rowskip, int colskip); + ~dMatrix(); // destructor + + // data movement + dReal & operator () (int i, int j); // reference an element + void operator= (const dMatrix &); // matrix = matrix + void operator= (dReal); // matrix = scalar + dMatrix transpose(); // return transposed matrix + // return a permuted submatrix of this matrix, made up of the rows in p + // and the columns in q. p has np elements, q has nq elements. + dMatrix select (int np, int *p, int nq, int *q); + + // operators + dMatrix operator + (const dMatrix &); + dMatrix operator - (const dMatrix &); + dMatrix operator - (); + dMatrix operator * (const dMatrix &); + void operator += (const dMatrix &); + void operator -= (const dMatrix &); + + // utility + void clearUpperTriangle(); + void clearLowerTriangle(); + void makeRandom (dReal range); + void print (char *fmt = "%10.4f ", FILE *f=stdout); + dReal maxDifference (const dMatrix &); +}; + + +#endif + diff --git a/extern/ode/dist/ode/src/matrix.cpp b/extern/ode/dist/ode/src/matrix.cpp new file mode 100644 index 00000000000..16afe915dd6 --- /dev/null +++ b/extern/ode/dist/ode/src/matrix.cpp @@ -0,0 +1,358 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include + +// misc defines +#define ALLOCA dALLOCA16 + + +void dSetZero (dReal *a, int n) +{ + dAASSERT (a && n >= 0); + while (n > 0) { + *(a++) = 0; + n--; + } +} + + +void dSetValue (dReal *a, int n, dReal value) +{ + dAASSERT (a && n >= 0); + while (n > 0) { + *(a++) = value; + n--; + } +} + + +void dMultiply0 (dReal *A, const dReal *B, const dReal *C, int p, int q, int r) +{ + int i,j,k,qskip,rskip,rpad; + dAASSERT (A && B && C && p>0 && q>0 && r>0); + qskip = dPAD(q); + rskip = dPAD(r); + rpad = rskip - r; + dReal sum; + const dReal *b,*c,*bb; + bb = B; + for (i=p; i; i--) { + for (j=0 ; j0 && q>0 && r>0); + pskip = dPAD(p); + rskip = dPAD(r); + for (i=0; i0 && q>0 && r>0); + rpad = dPAD(r) - r; + qskip = dPAD(q); + bb = B; + for (i=p; i; i--) { + cc = C; + for (j=r; j; j--) { + z = 0; + sum = 0; + for (k=q; k; k--,z++) sum += bb[z] * cc[z]; + *(A++) = sum; + cc += qskip; + } + A += rpad; + bb += qskip; + } +} + + +int dFactorCholesky (dReal *A, int n) +{ + int i,j,k,nskip; + dReal sum,*a,*b,*aa,*bb,*cc,*recip; + dAASSERT (n > 0 && A); + nskip = dPAD (n); + recip = (dReal*) ALLOCA (n * sizeof(dReal)); + aa = A; + for (i=0; i 0 && L && b); + nskip = dPAD (n); + y = (dReal*) ALLOCA (n*sizeof(dReal)); + for (i=0; i= 0; i--) { + sum = 0; + for (k=i+1; k < n; k++) sum += L[k*nskip+i]*b[k]; + b[i] = (y[i]-sum)/L[i*nskip+i]; + } +} + + +int dInvertPDMatrix (const dReal *A, dReal *Ainv, int n) +{ + int i,j,nskip; + dReal *L,*x; + dAASSERT (n > 0 && A && Ainv); + nskip = dPAD (n); + L = (dReal*) ALLOCA (nskip*n*sizeof(dReal)); + memcpy (L,A,nskip*n*sizeof(dReal)); + x = (dReal*) ALLOCA (n*sizeof(dReal)); + if (dFactorCholesky (L,n)==0) return 0; + dSetZero (Ainv,n*nskip); // make sure all padding elements set to 0 + for (i=0; i 0 && A); + int nskip = dPAD (n); + Acopy = (dReal*) ALLOCA (nskip*n * sizeof(dReal)); + memcpy (Acopy,A,nskip*n * sizeof(dReal)); + return dFactorCholesky (Acopy,n); +} + + +/***** this has been replaced by a faster version +void dSolveL1T (const dReal *L, dReal *b, int n, int nskip) +{ + int i,j; + dAASSERT (L && b && n >= 0 && nskip >= n); + dReal sum; + for (i=n-2; i>=0; i--) { + sum = 0; + for (j=i+1; j= 0); + for (int i=0; i 0 && nskip >= n); + dSolveL1 (L,b,n,nskip); + dVectorScale (b,d,n); + dSolveL1T (L,b,n,nskip); +} + + +void dLDLTAddTL (dReal *L, dReal *d, const dReal *a, int n, int nskip) +{ + int j,p; + dReal *W1,*W2,W11,W21,alpha1,alpha2,alphanew,gamma1,gamma2,k1,k2,Wp,ell,dee; + dAASSERT (L && d && a && n > 0 && nskip >= n); + + if (n < 2) return; + W1 = (dReal*) ALLOCA (n*sizeof(dReal)); + W2 = (dReal*) ALLOCA (n*sizeof(dReal)); + + W1[0] = 0; + W2[0] = 0; + for (j=1; j j) ? _GETA(i,j) : _GETA(j,i)) + + +void dLDLTRemove (dReal **A, const int *p, dReal *L, dReal *d, + int n1, int n2, int r, int nskip) +{ + int i; + dAASSERT(A && p && L && d && n1 > 0 && n2 > 0 && r >= 0 && r < n2 && + n1 >= n2 && nskip >= n1); + #ifndef dNODEBUG + for (i=0; i= 0 && p[i] < n1); + #endif + + if (r==n2-1) { + return; // deleting last row/col is easy + } + else if (r==0) { + dReal *a = (dReal*) ALLOCA (n2 * sizeof(dReal)); + for (i=0; i 0 && nskip >= n && r >= 0 && r < n); + if (r >= n-1) return; + if (r > 0) { + for (i=0; i 0 for alloc and realloc +// - realloc and free operate on uncorrupted blocks +// - realloc and free with the correct sizes +// - on exit, report of block allocation statistics +// - on exit, report of unfreed blocks and if they are corrupted +// the allocator will also call Debug() when it allocates a block with +// sequence number `_d_seqstop' or pointer value `_d_ptrstop'. these variables +// are global and can be set in the debugger. + +#include +#include +#include + +#ifdef dDEBUG_ALLOC + +// when debugging, this is a header that it put at start of all blocks. +// it contains `padding', which are PADSIZE elements of known value just +// before the user memory starts. another PADSIZE padding elements are put +// at the end of the user memory. the idea is that if the user accidentally +// steps outside the allocated memory, it can hopefully be detected by +// examining the padding elements. + +#define PADSIZE 10 +struct blockHeader { + long pad1; // protective padding + long seq; // sequence number + long size; // data size + long flags; // bit 0 = ignore this block in final report + blockHeader *next,*prev; // next & previous blocks + long pad[PADSIZE]; // protective padding +}; + +// compute the memory block size, including padding. the user memory block is +// rounded up to a multiple of 4 bytes, to get alignment for the padding at +// the end of the block. + +#define BSIZE(size) (((((size)-1) | 3)+1) + sizeof(blockHeader) + \ + PADSIZE * sizeof(long)) + +static blockHeader dummyblock = {0,0,0,0,&dummyblock,&dummyblock, + {0,0,0,0,0,0,0,0,0,0}}; +static blockHeader *firstblock = &dummyblock; +static long num_blocks_alloced = 0; +static long num_bytes_alloced = 0; +static long total_num_blocks_alloced = 0; +static long total_num_bytes_alloced = 0; +static long max_blocks_alloced = 0; +static long max_bytes_alloced = 0; + +long _d_seqstop = 0; +void *_d_ptrstop = 0; + +static int checkBlockOk (void *ptr, int fatal) +{ + if (ptr==0) dDebug (0,"0 passed to checkBlockOk()"); + blockHeader *b = ((blockHeader*) ptr) - 1; + int i,ok = 1; + if (b->pad1 != (long)0xdeadbeef || b->seq < 0 || b->size < 0) ok = 0; + if (ok) { + for (i=0; ipad[i] != (long)0xdeadbeef) ok = 0; + } + if (ok) { + long *endpad = (long*) (((char*)ptr) + (((b->size-1) | 3)+1)); + for (i=0; isize,b->seq); + return ok; +} + +#endif + + +static dAllocFunction *allocfn = 0; +static dReallocFunction *reallocfn = 0; +static dFreeFunction *freefn = 0; + + + +void dSetAllocHandler (dAllocFunction *fn) +{ + allocfn = fn; +} + + +void dSetReallocHandler (dReallocFunction *fn) +{ + reallocfn = fn; +} + + +void dSetFreeHandler (dFreeFunction *fn) +{ + freefn = fn; +} + + +dAllocFunction *dGetAllocHandler() +{ + return allocfn; +} + + +dReallocFunction *dGetReallocHandler() +{ + return reallocfn; +} + + +dFreeFunction *dGetFreeHandler() +{ + return freefn; +} + + +void * dAlloc (int size) +{ +#ifdef dDEBUG_ALLOC + if (size < 1) dDebug (0,"bad block size to Alloc()"); + + num_blocks_alloced++; + num_bytes_alloced += size; + total_num_blocks_alloced++; + total_num_bytes_alloced += size; + if (num_blocks_alloced > max_blocks_alloced) + max_blocks_alloced = num_blocks_alloced; + if (num_bytes_alloced > max_bytes_alloced) + max_bytes_alloced = num_bytes_alloced; + + if (total_num_blocks_alloced == _d_seqstop) + dDebug (0,"ALLOCATOR TRAP ON SEQUENCE NUMBER %d",_d_seqstop); + long size2 = BSIZE(size); + blockHeader *b = (blockHeader*) malloc (size2); + if (b+1 == _d_ptrstop) + dDebug (0,"ALLOCATOR TRAP ON BLOCK POINTER %p",_d_ptrstop); + for (unsigned int i=0; i < (size2/sizeof(long)); i++) + ((long*)b)[i] = 0xdeadbeef; + b->seq = total_num_blocks_alloced; + b->size = size; + b->flags = 0; + b->next = firstblock->next; + b->prev = firstblock; + firstblock->next->prev = b; + firstblock->next = b; + return b + 1; +#else + if (allocfn) return allocfn (size); else return malloc (size); +#endif +} + + +void * dRealloc (void *ptr, int oldsize, int newsize) +{ +#ifdef dDEBUG_ALLOC + if (ptr==0) dDebug (0,"Realloc() called with ptr==0"); + checkBlockOk (ptr,1); + blockHeader *b = ((blockHeader*) ptr) - 1; + if (b->size != oldsize) + dDebug (0,"Realloc(%p,%d,%d) has bad old size, good size " + "is %ld, seq=%ld",ptr,oldsize,newsize,b->size,b->seq); + void *p = dAlloc (newsize); + blockHeader *newb = ((blockHeader*) p) - 1; + newb->flags = b->flags; + if (oldsize>=1) memcpy (p,ptr,oldsize); + dFree (ptr,oldsize); + return p; +#else + if (reallocfn) return reallocfn (ptr,oldsize,newsize); + else return realloc (ptr,newsize); +#endif +} + + +void dFree (void *ptr, int size) +{ + if (!ptr) return; +#ifdef dDEBUG_ALLOC + checkBlockOk (ptr,1); + blockHeader *b = ((blockHeader*) ptr) - 1; + if (b->size != size) + dDebug (0,"Free(%p,%d) has bad size, good size " + "is %ld, seq=%ld",ptr,size,b->size,b->seq); + num_blocks_alloced--; + num_bytes_alloced -= b->size; + if (num_blocks_alloced < 0 || num_bytes_alloced < 0) + dDebug (0,"Free called too many times"); + + b->next->prev = b->prev; + b->prev->next = b->next; + memset (b,0,BSIZE(b->size)); + + free (b); +#else + if (freefn) freefn (ptr,size); else free (ptr); +#endif +} + + +void dAllocDontReport (void *ptr) +{ +#ifdef dDEBUG_ALLOC + checkBlockOk (ptr,1); + blockHeader *b = ((blockHeader*) ptr) - 1; + b->flags |= 1; +#endif +} + + +#ifdef dDEBUG_ALLOC + +static void printReport() +{ + // subtract the "dont report" blocks from the totals + blockHeader *b = firstblock; + do { + if (b != &dummyblock && (b->flags & 1)) { + num_blocks_alloced--; + num_bytes_alloced -= b->size; + if (!checkBlockOk (b+1,0)) + fprintf (stderr,"\tCORRUPTED: %p, size=%ld, seq=%ld\n",b+1, + b->size,b->seq); + } + b = b->prev; + } + while (b != firstblock); + + fprintf (stderr,"\nALLOCATOR REPORT\n"); + fprintf (stderr,"\tblocks still allocated: %ld\n",num_blocks_alloced); + fprintf (stderr,"\tbytes still allocated: %ld\n",num_bytes_alloced); + fprintf (stderr,"\ttotal blocks allocated: %ld\n",total_num_blocks_alloced); + fprintf (stderr,"\ttotal bytes allocated: %ld\n",total_num_bytes_alloced); + fprintf (stderr,"\tmax blocks allocated: %ld\n",max_blocks_alloced); + fprintf (stderr,"\tmax bytes allocated: %ld\n",max_bytes_alloced); + + b = firstblock; + do { + if (b != &dummyblock && (b->flags & 1)==0) { + int ok = checkBlockOk (b+1,0); + fprintf (stderr,"\tUNFREED: %p, size=%ld, seq=%ld (%s)\n",b+1, + b->size,b->seq, ok ? "ok" : "CORUPTED"); + } + b = b->prev; + } + while (b != firstblock); + fprintf (stderr,"\n"); +} + + +struct dMemoryReportPrinter { + ~dMemoryReportPrinter() { printReport(); } +} _dReportPrinter; + +#endif diff --git a/extern/ode/dist/ode/src/misc.cpp b/extern/ode/dist/ode/src/misc.cpp new file mode 100644 index 00000000000..bdc1579d5aa --- /dev/null +++ b/extern/ode/dist/ode/src/misc.cpp @@ -0,0 +1,147 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include +#include + +//**************************************************************************** +// random numbers + +static unsigned long seed = 0; + +unsigned long dRand() +{ + seed = (1664525L*seed + 1013904223L) & 0xffffffff; + return seed; +} + + +unsigned long dRandGetSeed() +{ + return seed; +} + + +void dRandSetSeed (unsigned long s) +{ + seed = s; +} + + +int dTestRand() +{ + unsigned long oldseed = seed; + int ret = 1; + seed = 0; + if (dRand() != 0x3c6ef35f || dRand() != 0x47502932 || + dRand() != 0xd1ccf6e9 || dRand() != 0xaaf95334 || + dRand() != 0x6252e503) ret = 0; + seed = oldseed; + return ret; +} + + +int dRandInt (int n) +{ + double a = double(n) / 4294967296.0; + return (int) (double(dRand()) * a); +} + + +dReal dRandReal() +{ + return ((dReal) dRand()) / ((dReal) 0xffffffff); +} + +//**************************************************************************** +// matrix utility stuff + +void dPrintMatrix (dReal *A, int n, int m, char *fmt, FILE *f) +{ + int i,j; + int skip = dPAD(m); + for (i=0; i max) max = diff; + } + } + return max; +} + + +dReal dMaxDifferenceLowerTriangle (const dReal *A, const dReal *B, int n) +{ + int i,j; + int skip = dPAD(n); + dReal diff,max; + max = 0; + for (i=0; i max) max = diff; + } + } + return max; +} diff --git a/extern/ode/dist/ode/src/objects.h b/extern/ode/dist/ode/src/objects.h new file mode 100644 index 00000000000..4d2c4ca6af7 --- /dev/null +++ b/extern/ode/dist/ode/src/objects.h @@ -0,0 +1,91 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// object, body, and world structs. + + +#ifndef _ODE_OBJECT_H_ +#define _ODE_OBJECT_H_ + +#include +#include +#include +#include "array.h" + + +// some body flags + +enum { + dxBodyFlagFiniteRotation = 1, // use finite rotations + dxBodyFlagFiniteRotationAxis = 2, // use finite rotations only along axis + dxBodyDisabled = 4, // body is disabled + dxBodyNoGravity = 8 // body is not influenced by gravity +}; + + +// base class that does correct object allocation / deallocation + +struct dBase { + void *operator new (size_t size) { return dAlloc (size); } + void operator delete (void *ptr, size_t size) { dFree (ptr,size); } + void *operator new[] (size_t size) { return dAlloc (size); } + void operator delete[] (void *ptr, size_t size) { dFree (ptr,size); } +}; + + +// base class for bodies and joints + +struct dObject : public dBase { + dxWorld *world; // world this object is in + dObject *next; // next object of this type in list + dObject **tome; // pointer to previous object's next ptr + void *userdata; // user settable data + int tag; // used by dynamics algorithms +}; + + +struct dxBody : public dObject { + dxJointNode *firstjoint; // list of attached joints + int flags; // some dxBodyFlagXXX flags + dMass mass; // mass parameters about POR + dMatrix3 invI; // inverse of mass.I + dReal invMass; // 1 / mass.mass + dVector3 pos; // position of POR (point of reference) + dQuaternion q; // orientation quaternion + dMatrix3 R; // rotation matrix, always corresponds to q + dVector3 lvel,avel; // linear and angular velocity of POR + dVector3 facc,tacc; // force and torque accululators + dVector3 finite_rot_axis; // finite rotation axis, unit length or 0=none +}; + + +struct dxWorld : public dBase { + dxBody *firstbody; // body linked list + dxJoint *firstjoint; // joint linked list + int nb,nj; // number of bodies and joints in lists + dVector3 gravity; // gravity vector (m/s/s) + dReal global_erp; // global error reduction parameter + dReal global_cfm; // global costraint force mixing parameter +}; + +#endif + diff --git a/extern/ode/dist/ode/src/obstack.cpp b/extern/ode/dist/ode/src/obstack.cpp new file mode 100644 index 00000000000..a6b9d36fbb4 --- /dev/null +++ b/extern/ode/dist/ode/src/obstack.cpp @@ -0,0 +1,130 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include +#include +#include "obstack.h" + +//**************************************************************************** +// macros and constants + +#define ROUND_UP_OFFSET_TO_EFFICIENT_SIZE(arena,ofs) \ + ofs = (int) (dEFFICIENT_SIZE( ((intP)(arena)) + ofs ) - ((intP)(arena)) ); + +#define MAX_ALLOC_SIZE \ + ((int)(dOBSTACK_ARENA_SIZE - sizeof (Arena) - EFFICIENT_ALIGNMENT + 1)) + +//**************************************************************************** +// dObStack + +dObStack::dObStack() +{ + first = 0; + last = 0; + current_arena = 0; + current_ofs = 0; +} + + +dObStack::~dObStack() +{ + // free all arenas + Arena *a,*nexta; + a = first; + while (a) { + nexta = a->next; + dFree (a,dOBSTACK_ARENA_SIZE); + a = nexta; + } +} + + +void *dObStack::alloc (int num_bytes) +{ + if (num_bytes > MAX_ALLOC_SIZE) dDebug (0,"num_bytes too large"); + + // allocate or move to a new arena if necessary + if (!first) { + // allocate the first arena if necessary + first = last = (Arena *) dAlloc (dOBSTACK_ARENA_SIZE); + first->next = 0; + first->used = sizeof (Arena); + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (first,first->used); + } + else { + // we already have one or more arenas, see if a new arena must be used + if ((last->used + num_bytes) > dOBSTACK_ARENA_SIZE) { + if (!last->next) { + last->next = (Arena *) dAlloc (dOBSTACK_ARENA_SIZE); + last->next->next = 0; + } + last = last->next; + last->used = sizeof (Arena); + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (last,last->used); + } + } + + // allocate an area in the arena + char *c = ((char*) last) + last->used; + last->used += num_bytes; + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (last,last->used); + return c; +} + + +void dObStack::freeAll() +{ + last = first; + if (first) { + first->used = sizeof(Arena); + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (first,first->used); + } +} + + +void *dObStack::rewind() +{ + current_arena = first; + current_ofs = sizeof (Arena); + if (current_arena) { + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs) + return ((char*) current_arena) + current_ofs; + } + else return 0; +} + + +void *dObStack::next (int num_bytes) +{ + // this functions like alloc, except that no new storage is ever allocated + if (!current_arena) return 0; + current_ofs += num_bytes; + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs); + if (current_ofs >= current_arena->used) { + current_arena = current_arena->next; + if (!current_arena) return 0; + current_ofs = sizeof (Arena); + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs); + } + return ((char*) current_arena) + current_ofs; +} diff --git a/extern/ode/dist/ode/src/obstack.h b/extern/ode/dist/ode/src/obstack.h new file mode 100644 index 00000000000..fa7155dd966 --- /dev/null +++ b/extern/ode/dist/ode/src/obstack.h @@ -0,0 +1,69 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_OBSTACK_H_ +#define _ODE_OBSTACK_H_ + +#include "objects.h" + +// each obstack Arena pointer points to a block of this many bytes +#define dOBSTACK_ARENA_SIZE 16384 + + +struct dObStack : public dBase { + struct Arena { + Arena *next; // next arena in linked list + int used; // total number of bytes used in this arena, counting + }; // this header + + Arena *first; // head of the arena linked list. 0 if no arenas yet + Arena *last; // arena where blocks are currently being allocated + + // used for iterator + Arena *current_arena; + int current_ofs; + + dObStack(); + ~dObStack(); + + void *alloc (int num_bytes); + // allocate a block in the last arena, allocating a new arena if necessary. + // it is a runtime error if num_bytes is larger than the arena size. + + void freeAll(); + // free all blocks in all arenas. this does not deallocate the arenas + // themselves, so future alloc()s will reuse them. + + void *rewind(); + // rewind the obstack iterator, and return the address of the first + // allocated block. return 0 if there are no allocated blocks. + + void *next (int num_bytes); + // return the address of the next allocated block. 'num_bytes' is the size + // of the previous block. this returns null if there are no more arenas. + // the sequence of 'num_bytes' parameters passed to next() during a + // traversal of the list must exactly match the parameters passed to alloc(). +}; + + +#endif + diff --git a/extern/ode/dist/ode/src/ode.cpp b/extern/ode/dist/ode/src/ode.cpp new file mode 100644 index 00000000000..1a14e3292a0 --- /dev/null +++ b/extern/ode/dist/ode/src/ode.cpp @@ -0,0 +1,1341 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// this source file is mostly concerned with the data structures, not the +// numerics. + +#include "objects.h" +#include +#include "joint.h" +#include +#include +#include "step.h" +#include +#include + +// misc defines +#define ALLOCA dALLOCA16 + +//**************************************************************************** +// utility + +static inline void initObject (dObject *obj, dxWorld *w) +{ + obj->world = w; + obj->next = 0; + obj->tome = 0; + obj->userdata = 0; + obj->tag = 0; +} + + +// add an object `obj' to the list who's head pointer is pointed to by `first'. + +static inline void addObjectToList (dObject *obj, dObject **first) +{ + obj->next = *first; + obj->tome = first; + if (*first) (*first)->tome = &obj->next; + (*first) = obj; +} + + +// remove the object from the linked list + +static inline void removeObjectFromList (dObject *obj) +{ + if (obj->next) obj->next->tome = obj->tome; + *(obj->tome) = obj->next; + // safeguard + obj->next = 0; + obj->tome = 0; +} + + +// remove the joint from neighbour lists of all connected bodies + +static void removeJointReferencesFromAttachedBodies (dxJoint *j) +{ + for (int i=0; i<2; i++) { + dxBody *body = j->node[i].body; + if (body) { + dxJointNode *n = body->firstjoint; + dxJointNode *last = 0; + while (n) { + if (n->joint == j) { + if (last) last->next = n->next; + else body->firstjoint = n->next; + break; + } + last = n; + n = n->next; + } + } + } + j->node[0].body = 0; + j->node[0].next = 0; + j->node[1].body = 0; + j->node[1].next = 0; +} + +//**************************************************************************** +// island processing + +// this groups all joints and bodies in a world into islands. all objects +// in an island are reachable by going through connected bodies and joints. +// each island can be simulated separately. +// note that joints that are not attached to anything will not be included +// in any island, an so they do not affect the simulation. +// +// this function starts new island from unvisited bodies. however, it will +// never start a new islands from a disabled body. thus islands of disabled +// bodies will not be included in the simulation. disabled bodies are +// re-enabled if they are found to be part of an active island. + +static void processIslands (dxWorld *world, dReal stepsize) +{ + dxBody *b,*bb,**body; + dxJoint *j,**joint; + + // nothing to do if no bodies + if (world->nb <= 0) return; + + // make arrays for body and joint lists (for a single island) to go into + body = (dxBody**) ALLOCA (world->nb * sizeof(dxBody*)); + joint = (dxJoint**) ALLOCA (world->nj * sizeof(dxJoint*)); + int bcount = 0; // number of bodies in `body' + int jcount = 0; // number of joints in `joint' + + // set all body/joint tags to 0 + for (b=world->firstbody; b; b=(dxBody*)b->next) b->tag = 0; + for (j=world->firstjoint; j; j=(dxJoint*)j->next) j->tag = 0; + + // allocate a stack of unvisited bodies in the island. the maximum size of + // the stack can be the lesser of the number of bodies or joints, because + // new bodies are only ever added to the stack by going through untagged + // joints. all the bodies in the stack must be tagged! + int stackalloc = (world->nj < world->nb) ? world->nj : world->nb; + dxBody **stack = (dxBody**) ALLOCA (stackalloc * sizeof(dxBody*)); + + for (bb=world->firstbody; bb; bb=(dxBody*)bb->next) { + // get bb = the next enabled, untagged body, and tag it + if (bb->tag || (bb->flags & dxBodyDisabled)) continue; + bb->tag = 1; + + // tag all bodies and joints starting from bb. + int stacksize = 0; + b = bb; + body[0] = bb; + bcount = 1; + jcount = 0; + goto quickstart; + while (stacksize > 0) { + b = stack[--stacksize]; // pop body off stack + body[bcount++] = b; // put body on body list + quickstart: + + // traverse and tag all body's joints, add untagged connected bodies + // to stack + for (dxJointNode *n=b->firstjoint; n; n=n->next) { + if (!n->joint->tag) { + n->joint->tag = 1; + joint[jcount++] = n->joint; + if (n->body && !n->body->tag) { + n->body->tag = 1; + stack[stacksize++] = n->body; + } + } + } + dIASSERT(stacksize <= world->nb); + dIASSERT(stacksize <= world->nj); + } + + // now do something with body and joint lists + dInternalStepIsland (world,body,bcount,joint,jcount,stepsize); + + // what we've just done may have altered the body/joint tag values. + // we must make sure that these tags are nonzero. + // also make sure all bodies are in the enabled state. + int i; + for (i=0; itag = 1; + body[i]->flags &= ~dxBodyDisabled; + } + for (i=0; itag = 1; + } + + // if debugging, check that all objects (except for disabled bodies, + // unconnected joints, and joints that are connected to disabled bodies) + // were tagged. +# ifndef dNODEBUG + for (b=world->firstbody; b; b=(dxBody*)b->next) { + if (b->flags & dxBodyDisabled) { + if (b->tag) dDebug (0,"disabled body tagged"); + } + else { + if (!b->tag) dDebug (0,"enabled body not tagged"); + } + } + for (j=world->firstjoint; j; j=(dxJoint*)j->next) { + if ((j->node[0].body && (j->node[0].body->flags & dxBodyDisabled)==0) || + (j->node[1].body && (j->node[1].body->flags & dxBodyDisabled)==0)) { + if (!j->tag) dDebug (0,"attached enabled joint not tagged"); + } + else { + if (j->tag) dDebug (0,"unattached or disabled joint tagged"); + } + } +# endif +} + +//**************************************************************************** +// debugging + +// see if an object list loops on itself (if so, it's bad). + +static int listHasLoops (dObject *first) +{ + if (first==0 || first->next==0) return 0; + dObject *a=first,*b=first->next; + int skip=0; + while (b) { + if (a==b) return 1; + b = b->next; + if (skip) a = a->next; + skip ^= 1; + } + return 0; +} + + +// check the validity of the world data structures + +static void checkWorld (dxWorld *w) +{ + dxBody *b; + dxJoint *j; + + // check there are no loops + if (listHasLoops (w->firstbody)) dDebug (0,"body list has loops"); + if (listHasLoops (w->firstjoint)) dDebug (0,"joint list has loops"); + + // check lists are well formed (check `tome' pointers) + for (b=w->firstbody; b; b=(dxBody*)b->next) { + if (b->next && b->next->tome != &b->next) + dDebug (0,"bad tome pointer in body list"); + } + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->next && j->next->tome != &j->next) + dDebug (0,"bad tome pointer in joint list"); + } + + // check counts + int n = 0; + for (b=w->firstbody; b; b=(dxBody*)b->next) n++; + if (w->nb != n) dDebug (0,"body count incorrect"); + n = 0; + for (j=w->firstjoint; j; j=(dxJoint*)j->next) n++; + if (w->nj != n) dDebug (0,"joint count incorrect"); + + // set all tag values to a known value + static int count = 0; + count++; + for (b=w->firstbody; b; b=(dxBody*)b->next) b->tag = count; + for (j=w->firstjoint; j; j=(dxJoint*)j->next) j->tag = count; + + // check all body/joint world pointers are ok + for (b=w->firstbody; b; b=(dxBody*)b->next) if (b->world != w) + dDebug (0,"bad world pointer in body list"); + for (j=w->firstjoint; j; j=(dxJoint*)j->next) if (j->world != w) + dDebug (0,"bad world pointer in joint list"); + + /* + // check for half-connected joints - actually now these are valid + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->node[0].body || j->node[1].body) { + if (!(j->node[0].body && j->node[1].body)) + dDebug (0,"half connected joint found"); + } + } + */ + + // check that every joint node appears in the joint lists of both bodies it + // attaches + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + for (int i=0; i<2; i++) { + if (j->node[i].body) { + int ok = 0; + for (dxJointNode *n=j->node[i].body->firstjoint; n; n=n->next) { + if (n->joint == j) ok = 1; + } + if (ok==0) dDebug (0,"joint not in joint list of attached body"); + } + } + } + + // check all body joint lists (correct body ptrs) + for (b=w->firstbody; b; b=(dxBody*)b->next) { + for (dxJointNode *n=b->firstjoint; n; n=n->next) { + if (&n->joint->node[0] == n) { + if (n->joint->node[1].body != b) + dDebug (0,"bad body pointer in joint node of body list (1)"); + } + else { + if (n->joint->node[0].body != b) + dDebug (0,"bad body pointer in joint node of body list (2)"); + } + if (n->joint->tag != count) dDebug (0,"bad joint node pointer in body"); + } + } + + // check all body pointers in joints, check they are distinct + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->node[0].body && (j->node[0].body == j->node[1].body)) + dDebug (0,"non-distinct body pointers in joint"); + if ((j->node[0].body && j->node[0].body->tag != count) || + (j->node[1].body && j->node[1].body->tag != count)) + dDebug (0,"bad body pointer in joint"); + } +} + + +void dWorldCheck (dxWorld *w) +{ + checkWorld (w); +} + +//**************************************************************************** +// body + +dxBody *dBodyCreate (dxWorld *w) +{ + dAASSERT (w); + dxBody *b = new dxBody; + initObject (b,w); + b->firstjoint = 0; + b->flags = 0; + dMassSetParameters (&b->mass,1,0,0,0,1,1,1,0,0,0); + dSetZero (b->invI,4*3); + b->invI[0] = 1; + b->invI[5] = 1; + b->invI[10] = 1; + b->invMass = 1; + dSetZero (b->pos,4); + dSetZero (b->q,4); + b->q[0] = 1; + dRSetIdentity (b->R); + dSetZero (b->lvel,4); + dSetZero (b->avel,4); + dSetZero (b->facc,4); + dSetZero (b->tacc,4); + dSetZero (b->finite_rot_axis,4); + addObjectToList (b,(dObject **) &w->firstbody); + w->nb++; + return b; +} + + +void dBodyDestroy (dxBody *b) +{ + dAASSERT (b); + + // detach all neighbouring joints, then delete this body. + dxJointNode *n = b->firstjoint; + while (n) { + // sneaky trick to speed up removal of joint references (black magic) + n->joint->node[(n == n->joint->node)].body = 0; + + dxJointNode *next = n->next; + n->next = 0; + removeJointReferencesFromAttachedBodies (n->joint); + n = next; + } + removeObjectFromList (b); + b->world->nb--; + delete b; +} + + +void dBodySetData (dBodyID b, void *data) +{ + dAASSERT (b); + b->userdata = data; +} + + +void *dBodyGetData (dBodyID b) +{ + dAASSERT (b); + return b->userdata; +} + + +void dBodySetPosition (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->pos[0] = x; + b->pos[1] = y; + b->pos[2] = z; +} + + +void dBodySetRotation (dBodyID b, const dMatrix3 R) +{ + dAASSERT (b && R); + dQuaternion q; + dRtoQ (R,q); + dNormalize4 (q); + b->q[0] = q[0]; + b->q[1] = q[1]; + b->q[2] = q[2]; + b->q[3] = q[3]; + dQtoR (b->q,b->R); +} + + +void dBodySetQuaternion (dBodyID b, const dQuaternion q) +{ + dAASSERT (b && q); + b->q[0] = q[0]; + b->q[1] = q[1]; + b->q[2] = q[2]; + b->q[3] = q[3]; + dNormalize4 (b->q); + dQtoR (b->q,b->R); +} + + +void dBodySetLinearVel (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->lvel[0] = x; + b->lvel[1] = y; + b->lvel[2] = z; +} + + +void dBodySetAngularVel (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->avel[0] = x; + b->avel[1] = y; + b->avel[2] = z; +} + + +const dReal * dBodyGetPosition (dBodyID b) +{ + dAASSERT (b); + return b->pos; +} + + +const dReal * dBodyGetRotation (dBodyID b) +{ + dAASSERT (b); + return b->R; +} + + +const dReal * dBodyGetQuaternion (dBodyID b) +{ + dAASSERT (b); + return b->q; +} + + +const dReal * dBodyGetLinearVel (dBodyID b) +{ + dAASSERT (b); + return b->lvel; +} + + +const dReal * dBodyGetAngularVel (dBodyID b) +{ + dAASSERT (b); + return b->avel; +} + + +void dBodySetMass (dBodyID b, const dMass *mass) +{ + dAASSERT (b && mass); + memcpy (&b->mass,mass,sizeof(dMass)); + if (dInvertPDMatrix (b->mass.I,b->invI,3)==0) { + dDEBUGMSG ("inertia must be positive definite"); + dRSetIdentity (b->invI); + } + b->invMass = dRecip(b->mass.mass); +} + + +void dBodyGetMass (dBodyID b, dMass *mass) +{ + dAASSERT (b && mass); + memcpy (mass,&b->mass,sizeof(dMass)); +} + + +void dBodyAddForce (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + dAASSERT (b); + b->facc[0] += fx; + b->facc[1] += fy; + b->facc[2] += fz; +} + + +void dBodyAddTorque (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + dAASSERT (b); + b->tacc[0] += fx; + b->tacc[1] += fy; + b->tacc[2] += fz; +} + + +void dBodyAddRelForce (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + dAASSERT (b); + dVector3 t1,t2; + t1[0] = fx; + t1[1] = fy; + t1[2] = fz; + t1[3] = 0; + dMULTIPLY0_331 (t2,b->R,t1); + b->facc[0] += t2[0]; + b->facc[1] += t2[1]; + b->facc[2] += t2[2]; +} + + +void dBodyAddRelTorque (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + dAASSERT (b); + dVector3 t1,t2; + t1[0] = fx; + t1[1] = fy; + t1[2] = fz; + t1[3] = 0; + dMULTIPLY0_331 (t2,b->R,t1); + b->tacc[0] += t2[0]; + b->tacc[1] += t2[1]; + b->tacc[2] += t2[2]; +} + + +void dBodyAddForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + dAASSERT (b); + b->facc[0] += fx; + b->facc[1] += fy; + b->facc[2] += fz; + dVector3 f,q; + f[0] = fx; + f[1] = fy; + f[2] = fz; + q[0] = px - b->pos[0]; + q[1] = py - b->pos[1]; + q[2] = pz - b->pos[2]; + dCROSS (b->tacc,+=,q,f); +} + + +void dBodyAddForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + dAASSERT (b); + dVector3 prel,f,p; + f[0] = fx; + f[1] = fy; + f[2] = fz; + f[3] = 0; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (p,b->R,prel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dCROSS (b->tacc,+=,p,f); +} + + +void dBodyAddRelForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + dAASSERT (b); + dVector3 frel,f; + frel[0] = fx; + frel[1] = fy; + frel[2] = fz; + frel[3] = 0; + dMULTIPLY0_331 (f,b->R,frel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dVector3 q; + q[0] = px - b->pos[0]; + q[1] = py - b->pos[1]; + q[2] = pz - b->pos[2]; + dCROSS (b->tacc,+=,q,f); +} + + +void dBodyAddRelForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + dAASSERT (b); + dVector3 frel,prel,f,p; + frel[0] = fx; + frel[1] = fy; + frel[2] = fz; + frel[3] = 0; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (f,b->R,frel); + dMULTIPLY0_331 (p,b->R,prel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dCROSS (b->tacc,+=,p,f); +} + + +const dReal * dBodyGetForce (dBodyID b) +{ + dAASSERT (b); + return b->facc; +} + + +const dReal * dBodyGetTorque (dBodyID b) +{ + dAASSERT (b); + return b->tacc; +} + + +void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->facc[0] = x; + b->facc[1] = y; + b->facc[2] = z; +} + + +void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->tacc[0] = x; + b->tacc[1] = y; + b->tacc[2] = z; +} + + +void dBodyGetRelPointPos (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel,p; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (p,b->R,prel); + result[0] = p[0] + b->pos[0]; + result[1] = p[1] + b->pos[1]; + result[2] = p[2] + b->pos[2]; +} + + +void dBodyGetRelPointVel (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel,p; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (p,b->R,prel); + result[0] = b->lvel[0]; + result[1] = b->lvel[1]; + result[2] = b->lvel[2]; + dCROSS (result,+=,b->avel,p); +} + + +void dBodyGetPointVel (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px - b->pos[0]; + p[1] = py - b->pos[1]; + p[2] = pz - b->pos[2]; + p[3] = 0; + result[0] = b->lvel[0]; + result[1] = b->lvel[1]; + result[2] = b->lvel[2]; + dCROSS (result,+=,b->avel,p); +} + + +void dBodyGetPosRelPoint (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel; + prel[0] = px - b->pos[0]; + prel[1] = py - b->pos[1]; + prel[2] = pz - b->pos[2]; + prel[3] = 0; + dMULTIPLY1_331 (result,b->R,prel); +} + + +void dBodyVectorToWorld (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px; + p[1] = py; + p[2] = pz; + p[3] = 0; + dMULTIPLY0_331 (result,b->R,p); +} + + +void dBodyVectorFromWorld (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px; + p[1] = py; + p[2] = pz; + p[3] = 0; + dMULTIPLY1_331 (result,b->R,p); +} + + +void dBodySetFiniteRotationMode (dBodyID b, int mode) +{ + dAASSERT (b); + b->flags &= ~(dxBodyFlagFiniteRotation | dxBodyFlagFiniteRotationAxis); + if (mode) { + b->flags |= dxBodyFlagFiniteRotation; + if (b->finite_rot_axis[0] != 0 || b->finite_rot_axis[1] != 0 || + b->finite_rot_axis[2] != 0) { + b->flags |= dxBodyFlagFiniteRotationAxis; + } + } +} + + +void dBodySetFiniteRotationAxis (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->finite_rot_axis[0] = x; + b->finite_rot_axis[1] = y; + b->finite_rot_axis[2] = z; + if (x != 0 || y != 0 || z != 0) { + dNormalize3 (b->finite_rot_axis); + b->flags |= dxBodyFlagFiniteRotationAxis; + } + else { + b->flags &= ~dxBodyFlagFiniteRotationAxis; + } +} + + +int dBodyGetFiniteRotationMode (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyFlagFiniteRotation) != 0); +} + + +void dBodyGetFiniteRotationAxis (dBodyID b, dVector3 result) +{ + dAASSERT (b); + result[0] = b->finite_rot_axis[0]; + result[1] = b->finite_rot_axis[1]; + result[2] = b->finite_rot_axis[2]; +} + + +int dBodyGetNumJoints (dBodyID b) +{ + dAASSERT (b); + int count=0; + for (dxJointNode *n=b->firstjoint; n; n=n->next, count++); + return count; +} + + +dJointID dBodyGetJoint (dBodyID b, int index) +{ + dAASSERT (b); + int i=0; + for (dxJointNode *n=b->firstjoint; n; n=n->next, i++) { + if (i == index) return n->joint; + } + return 0; +} + + +void dBodyEnable (dBodyID b) +{ + dAASSERT (b); + b->flags &= ~dxBodyDisabled; +} + + +void dBodyDisable (dBodyID b) +{ + dAASSERT (b); + b->flags |= dxBodyDisabled; +} + + +int dBodyIsEnabled (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyDisabled) == 0); +} + + +void dBodySetGravityMode (dBodyID b, int mode) +{ + dAASSERT (b); + if (mode) b->flags &= ~dxBodyNoGravity; + else b->flags |= dxBodyNoGravity; +} + + +int dBodyGetGravityMode (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyNoGravity) == 0); +} + +//**************************************************************************** +// joints + +static void dJointInit (dxWorld *w, dxJoint *j) +{ + dIASSERT (w && j); + initObject (j,w); + j->vtable = 0; + j->flags = 0; + j->node[0].joint = j; + j->node[0].body = 0; + j->node[0].next = 0; + j->node[1].joint = j; + j->node[1].body = 0; + j->node[1].next = 0; + addObjectToList (j,(dObject **) &w->firstjoint); + w->nj++; +} + + +static dxJoint *createJoint (dWorldID w, dJointGroupID group, + dxJoint::Vtable *vtable) +{ + dIASSERT (w && vtable); + dxJoint *j; + if (group) { + j = (dxJoint*) group->stack.alloc (vtable->size); + group->num++; + } + else j = (dxJoint*) dAlloc (vtable->size); + dJointInit (w,j); + j->vtable = vtable; + if (group) j->flags |= dJOINT_INGROUP; + if (vtable->init) vtable->init (j); + j->feedback = 0; + return j; +} + + +dxJoint * dJointCreateBall (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dball_vtable); +} + + +dxJoint * dJointCreateHinge (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dhinge_vtable); +} + + +dxJoint * dJointCreateSlider (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dslider_vtable); +} + + +dxJoint * dJointCreateContact (dWorldID w, dJointGroupID group, + const dContact *c) +{ + dAASSERT (w && c); + dxJointContact *j = (dxJointContact *) + createJoint (w,group,&__dcontact_vtable); + j->contact = *c; + return j; +} + + +dxJoint * dJointCreateHinge2 (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dhinge2_vtable); +} + + +dxJoint * dJointCreateUniversal (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__duniversal_vtable); +} + + +dxJoint * dJointCreateFixed (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dfixed_vtable); +} + + +dxJoint * dJointCreateNull (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dnull_vtable); +} + + +dxJoint * dJointCreateAMotor (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__damotor_vtable); +} + + +void dJointDestroy (dxJoint *j) +{ + dAASSERT (j); + if (j->flags & dJOINT_INGROUP) return; + removeJointReferencesFromAttachedBodies (j); + removeObjectFromList (j); + j->world->nj--; + dFree (j,j->vtable->size); +} + + +dJointGroupID dJointGroupCreate (int max_size) +{ + // not any more ... dUASSERT (max_size > 0,"max size must be > 0"); + dxJointGroup *group = new dxJointGroup; + group->num = 0; + return group; +} + + +void dJointGroupDestroy (dJointGroupID group) +{ + dAASSERT (group); + dJointGroupEmpty (group); + delete group; +} + + +void dJointGroupEmpty (dJointGroupID group) +{ + // the joints in this group are detached starting from the most recently + // added (at the top of the stack). this helps ensure that the various + // linked lists are not traversed too much, as the joints will hopefully + // be at the start of those lists. + // if any group joints have their world pointer set to 0, their world was + // previously destroyed. no special handling is required for these joints. + + dAASSERT (group); + int i; + dxJoint **jlist = (dxJoint**) ALLOCA (group->num * sizeof(dxJoint*)); + dxJoint *j = (dxJoint*) group->stack.rewind(); + for (i=0; i < group->num; i++) { + jlist[i] = j; + j = (dxJoint*) (group->stack.next (j->vtable->size)); + } + for (i=group->num-1; i >= 0; i--) { + if (jlist[i]->world) { + removeJointReferencesFromAttachedBodies (jlist[i]); + removeObjectFromList (jlist[i]); + jlist[i]->world->nj--; + } + } + group->num = 0; + group->stack.freeAll(); +} + + +void dJointAttach (dxJoint *joint, dxBody *body1, dxBody *body2) +{ + // check arguments + dUASSERT (joint,"bad joint argument"); + dUASSERT (body1 == 0 || body1 != body2,"can't have body1==body2"); + dxWorld *world = joint->world; + dUASSERT ( (!body1 || body1->world == world) && + (!body2 || body2->world == world), + "joint and bodies must be in same world"); + + // check if the joint can not be attached to just one body + dUASSERT (!((joint->flags & dJOINT_TWOBODIES) && + ((body1 != 0) ^ (body2 != 0))), + "joint can not be attached to just one body"); + + // remove any existing body attachments + if (joint->node[0].body || joint->node[1].body) { + removeJointReferencesFromAttachedBodies (joint); + } + + // if a body is zero, make sure that it is body2, so 0 --> node[1].body + if (body1==0) { + body1 = body2; + body2 = 0; + joint->flags &= (~dJOINT_REVERSE); + } + else { + joint->flags |= dJOINT_REVERSE; + } + + // attach to new bodies + joint->node[0].body = body1; + joint->node[1].body = body2; + if (body1) { + joint->node[1].next = body1->firstjoint; + body1->firstjoint = &joint->node[1]; + } + else joint->node[1].next = 0; + if (body2) { + joint->node[0].next = body2->firstjoint; + body2->firstjoint = &joint->node[0]; + } + else { + joint->node[0].next = 0; + } +} + + +void dJointSetData (dxJoint *joint, void *data) +{ + dAASSERT (joint); + joint->userdata = data; +} + + +void *dJointGetData (dxJoint *joint) +{ + dAASSERT (joint); + return joint->userdata; +} + + +int dJointGetType (dxJoint *joint) +{ + dAASSERT (joint); + return joint->vtable->typenum; +} + + +dBodyID dJointGetBody (dxJoint *joint, int index) +{ + dAASSERT (joint); + if (index >= 0 && index < 2) return joint->node[index].body; + else return 0; +} + + +void dJointSetFeedback (dxJoint *joint, dJointFeedback *f) +{ + dAASSERT (joint); + joint->feedback = f; +} + + +dJointFeedback *dJointGetFeedback (dxJoint *joint) +{ + dAASSERT (joint); + return joint->feedback; +} + + +int dAreConnected (dBodyID b1, dBodyID b2) +{ + dAASSERT (b1 && b2); + // look through b1's neighbour list for b2 + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (n->body == b2) return 1; + } + return 0; +} + +//**************************************************************************** +// world + +dxWorld * dWorldCreate() +{ + dxWorld *w = new dxWorld; + w->firstbody = 0; + w->firstjoint = 0; + w->nb = 0; + w->nj = 0; + dSetZero (w->gravity,4); + w->global_erp = REAL(0.2); +#if defined(dSINGLE) + w->global_cfm = 1e-5f; +#elif defined(dDOUBLE) + w->global_cfm = 1e-10; +#else + #error dSINGLE or dDOUBLE must be defined +#endif + return w; +} + + +void dWorldDestroy (dxWorld *w) +{ + // delete all bodies and joints + dAASSERT (w); + dxBody *nextb, *b = w->firstbody; + while (b) { + nextb = (dxBody*) b->next; + delete b; + b = nextb; + } + dxJoint *nextj, *j = w->firstjoint; + while (j) { + nextj = (dxJoint*)j->next; + if (j->flags & dJOINT_INGROUP) { + // the joint is part of a group, so "deactivate" it instead + j->world = 0; + j->node[0].body = 0; + j->node[0].next = 0; + j->node[1].body = 0; + j->node[1].next = 0; + dMessage (0,"warning: destroying world containing grouped joints"); + } + else { + dFree (j,j->vtable->size); + } + j = nextj; + } + delete w; +} + + +void dWorldSetGravity (dWorldID w, dReal x, dReal y, dReal z) +{ + dAASSERT (w); + w->gravity[0] = x; + w->gravity[1] = y; + w->gravity[2] = z; +} + + +void dWorldGetGravity (dWorldID w, dVector3 g) +{ + dAASSERT (w); + g[0] = w->gravity[0]; + g[1] = w->gravity[1]; + g[2] = w->gravity[2]; +} + + +void dWorldSetERP (dWorldID w, dReal erp) +{ + dAASSERT (w); + w->global_erp = erp; +} + + +dReal dWorldGetERP (dWorldID w) +{ + dAASSERT (w); + return w->global_erp; +} + + +void dWorldSetCFM (dWorldID w, dReal cfm) +{ + dAASSERT (w); + w->global_cfm = cfm; +} + + +dReal dWorldGetCFM (dWorldID w) +{ + dAASSERT (w); + return w->global_cfm; +} + + +void dWorldStep (dWorldID w, dReal stepsize) +{ + dUASSERT (w,"bad world argument"); + dUASSERT (stepsize > 0,"stepsize must be > 0"); + processIslands (w,stepsize); +} + + +void dWorldImpulseToForce (dWorldID w, dReal stepsize, + dReal ix, dReal iy, dReal iz, + dVector3 force) +{ + dAASSERT (w); + stepsize = dRecip(stepsize); + force[0] = stepsize * ix; + force[1] = stepsize * iy; + force[2] = stepsize * iz; + // @@@ force[3] = 0; +} + +//**************************************************************************** +// testing + +#define NUM 100 + +#define DO(x) + + +extern "C" void dTestDataStructures() +{ + int i; + DO(printf ("testDynamicsStuff()\n")); + + dBodyID body [NUM]; + int nb = 0; + dJointID joint [NUM]; + int nj = 0; + + for (i=0; i 0.5) { + DO(printf ("creating body\n")); + body[nb] = dBodyCreate (w); + DO(printf ("\t--> %p\n",body[nb])); + nb++; + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + if (nj < NUM && nb > 2 && dRandReal() > 0.5) { + dBodyID b1 = body [dRand() % nb]; + dBodyID b2 = body [dRand() % nb]; + if (b1 != b2) { + DO(printf ("creating joint, attaching to %p,%p\n",b1,b2)); + joint[nj] = dJointCreateBall (w,0); + DO(printf ("\t-->%p\n",joint[nj])); + checkWorld (w); + dJointAttach (joint[nj],b1,b2); + nj++; + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + if (nj > 0 && nb > 2 && dRandReal() > 0.5) { + dBodyID b1 = body [dRand() % nb]; + dBodyID b2 = body [dRand() % nb]; + if (b1 != b2) { + int k = dRand() % nj; + DO(printf ("reattaching joint %p\n",joint[k])); + dJointAttach (joint[k],b1,b2); + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + if (nb > 0 && dRandReal() > 0.5) { + int k = dRand() % nb; + DO(printf ("destroying body %p\n",body[k])); + dBodyDestroy (body[k]); + checkWorld (w); + for (; k < (NUM-1); k++) body[k] = body[k+1]; + nb--; + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + if (nj > 0 && dRandReal() > 0.5) { + int k = dRand() % nj; + DO(printf ("destroying joint %p\n",joint[k])); + dJointDestroy (joint[k]); + checkWorld (w); + for (; k < (NUM-1); k++) joint[k] = joint[k+1]; + nj--; + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + + /* + printf ("creating world\n"); + dWorldID w = dWorldCreate(); + checkWorld (w); + printf ("creating body\n"); + dBodyID b1 = dBodyCreate (w); + checkWorld (w); + printf ("creating body\n"); + dBodyID b2 = dBodyCreate (w); + checkWorld (w); + printf ("creating joint\n"); + dJointID j = dJointCreateBall (w); + checkWorld (w); + printf ("attaching joint\n"); + dJointAttach (j,b1,b2); + checkWorld (w); + printf ("destroying joint\n"); + dJointDestroy (j); + checkWorld (w); + printf ("destroying body\n"); + dBodyDestroy (b1); + checkWorld (w); + printf ("destroying body\n"); + dBodyDestroy (b2); + checkWorld (w); + printf ("destroying world\n"); + dWorldDestroy (w); + */ +} diff --git a/extern/ode/dist/ode/src/odemath.cpp b/extern/ode/dist/ode/src/odemath.cpp new file mode 100644 index 00000000000..cd6dbc855fe --- /dev/null +++ b/extern/ode/dist/ode/src/odemath.cpp @@ -0,0 +1,173 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#define SHARED_CONFIG_H_INCLUDED_FROM_DEFINING_FILE 1 +#include +#include + + +// get some math functions under windows +#ifdef WIN32 +#include +#ifndef CYGWIN // added by andy for cygwin +#define copysign(a,b) ((dReal)_copysign(a,b)) +#endif // added by andy for cygwin +#endif + + +// infinity declaration + +#ifdef DINFINITY_DECL +DINFINITY_DECL +#endif + + +// this may be called for vectors `a' with extremely small magnitude, for +// example the result of a cross product on two nearly perpendicular vectors. +// we must be robust to these small vectors. to prevent numerical error, +// first find the component a[i] with the largest magnitude and then scale +// all the components by 1/a[i]. then we can compute the length of `a' and +// scale the components by 1/l. this has been verified to work with vectors +// containing the smallest representable numbers. + +void dNormalize3 (dVector3 a) +{ + dReal a0,a1,a2,aa0,aa1,aa2,l; + dAASSERT (a); + a0 = a[0]; + a1 = a[1]; + a2 = a[2]; + aa0 = dFabs(a0); + aa1 = dFabs(a1); + aa2 = dFabs(a2); + if (aa1 > aa0) { + if (aa2 > aa1) { + goto aa2_largest; + } + else { // aa1 is largest + a0 /= aa1; + a2 /= aa1; + l = dRecipSqrt (a0*a0 + a2*a2 + 1); + a[0] = a0*l; + a[1] = copysign(l,a1); + a[2] = a2*l; + } + } + else { + if (aa2 > aa0) { + aa2_largest: // aa2 is largest + a0 /= aa2; + a1 /= aa2; + l = dRecipSqrt (a0*a0 + a1*a1 + 1); + a[0] = a0*l; + a[1] = a1*l; + a[2] = copysign(l,a2); + } + else { // aa0 is largest + if (aa0 <= 0) { + dDEBUGMSG ("vector has zero size"); + a[0] = 1; // if all a's are zero, this is where we'll end up. + a[1] = 0; // return a default unit length vector. + a[2] = 0; + return; + } + a1 /= aa0; + a2 /= aa0; + l = dRecipSqrt (a1*a1 + a2*a2 + 1); + a[0] = copysign(l,a0); + a[1] = a1*l; + a[2] = a2*l; + } + } +} + + +/* OLD VERSION */ +/* +void dNormalize3 (dVector3 a) +{ + dASSERT (a); + dReal l = dDOT(a,a); + if (l > 0) { + l = dRecipSqrt(l); + a[0] *= l; + a[1] *= l; + a[2] *= l; + } + else { + a[0] = 1; + a[1] = 0; + a[2] = 0; + } +} +*/ + + +void dNormalize4 (dVector4 a) +{ + dAASSERT (a); + dReal l = dDOT(a,a)+a[3]*a[3]; + if (l > 0) { + l = dRecipSqrt(l); + a[0] *= l; + a[1] *= l; + a[2] *= l; + a[3] *= l; + } + else { + dDEBUGMSG ("vector has zero size"); + a[0] = 1; + a[1] = 0; + a[2] = 0; + a[3] = 0; + } +} + + +void dPlaneSpace (const dVector3 n, dVector3 p, dVector3 q) +{ + dAASSERT (n && p && q); + if (dFabs(n[2]) > M_SQRT1_2) { + // choose p in y-z plane + dReal a = n[1]*n[1] + n[2]*n[2]; + dReal k = dRecipSqrt (a); + p[0] = 0; + p[1] = -n[2]*k; + p[2] = n[1]*k; + // set q = n x p + q[0] = a*k; + q[1] = -n[0]*p[2]; + q[2] = n[0]*p[1]; + } + else { + // choose p in x-y plane + dReal a = n[0]*n[0] + n[1]*n[1]; + dReal k = dRecipSqrt (a); + p[0] = -n[1]*k; + p[1] = n[0]*k; + p[2] = 0; + // set q = n x p + q[0] = -n[2]*p[1]; + q[1] = n[2]*p[0]; + q[2] = a*k; + } +} diff --git a/extern/ode/dist/ode/src/rotation.cpp b/extern/ode/dist/ode/src/rotation.cpp new file mode 100644 index 00000000000..22b9fb13820 --- /dev/null +++ b/extern/ode/dist/ode/src/rotation.cpp @@ -0,0 +1,283 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +quaternions have the format: (s,vx,vy,vz) where (vx,vy,vz) is the +"rotation axis" and s is the "rotation angle". + +*/ + +#include + + +#define _R(i,j) R[(i)*4+(j)] + +#define SET_3x3_IDENTITY \ + _R(0,0) = REAL(1.0); \ + _R(0,1) = REAL(0.0); \ + _R(0,2) = REAL(0.0); \ + _R(0,3) = REAL(0.0); \ + _R(1,0) = REAL(0.0); \ + _R(1,1) = REAL(1.0); \ + _R(1,2) = REAL(0.0); \ + _R(1,3) = REAL(0.0); \ + _R(2,0) = REAL(0.0); \ + _R(2,1) = REAL(0.0); \ + _R(2,2) = REAL(1.0); \ + _R(2,3) = REAL(0.0); + + +void dRSetIdentity (dMatrix3 R) +{ + dAASSERT (R); + SET_3x3_IDENTITY; +} + + +void dRFromAxisAndAngle (dMatrix3 R, dReal ax, dReal ay, dReal az, + dReal angle) +{ + dAASSERT (R); + dQuaternion q; + dQFromAxisAndAngle (q,ax,ay,az,angle); + dQtoR (q,R); +} + + +void dRFromEulerAngles (dMatrix3 R, dReal phi, dReal theta, dReal psi) +{ + dReal sphi,cphi,stheta,ctheta,spsi,cpsi; + dAASSERT (R); + sphi = dSin(phi); + cphi = dCos(phi); + stheta = dSin(theta); + ctheta = dCos(theta); + spsi = dSin(psi); + cpsi = dCos(psi); + _R(0,0) = cpsi*ctheta; + _R(0,1) = spsi*ctheta; + _R(0,2) =-stheta; + _R(1,0) = cpsi*stheta*sphi - spsi*cphi; + _R(1,1) = spsi*stheta*sphi + cpsi*cphi; + _R(1,2) = ctheta*sphi; + _R(2,0) = cpsi*stheta*cphi + spsi*sphi; + _R(2,1) = spsi*stheta*cphi - cpsi*sphi; + _R(2,2) = ctheta*cphi; +} + + +void dRFrom2Axes (dMatrix3 R, dReal ax, dReal ay, dReal az, + dReal bx, dReal by, dReal bz) +{ + dReal l,k; + dAASSERT (R); + l = dSqrt (ax*ax + ay*ay + az*az); + if (l <= REAL(0.0)) { + dDEBUGMSG ("zero length vector"); + return; + } + l = dRecip(l); + ax *= l; + ay *= l; + az *= l; + k = ax*bx + ay*by + az*bz; + bx -= k*ax; + by -= k*ay; + bz -= k*az; + l = dSqrt (bx*bx + by*by + bz*bz); + if (l <= REAL(0.0)) { + dDEBUGMSG ("zero length vector"); + return; + } + l = dRecip(l); + bx *= l; + by *= l; + bz *= l; + _R(0,0) = ax; + _R(1,0) = ay; + _R(2,0) = az; + _R(0,1) = bx; + _R(1,1) = by; + _R(2,1) = bz; + _R(0,2) = - by*az + ay*bz; + _R(1,2) = - bz*ax + az*bx; + _R(2,2) = - bx*ay + ax*by; +} + + +void dQSetIdentity (dQuaternion q) +{ + dAASSERT (q); + q[0] = 1; + q[1] = 0; + q[2] = 0; + q[3] = 0; +} + + +void dQFromAxisAndAngle (dQuaternion q, dReal ax, dReal ay, dReal az, + dReal angle) +{ + dAASSERT (q); + dReal l = ax*ax + ay*ay + az*az; + if (l > REAL(0.0)) { + angle *= REAL(0.5); + q[0] = dCos (angle); + l = dSin(angle) * dRecipSqrt(l); + q[1] = ax*l; + q[2] = ay*l; + q[3] = az*l; + } + else { + q[0] = 1; + q[1] = 0; + q[2] = 0; + q[3] = 0; + } +} + + +void dQMultiply0 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) +{ + dAASSERT (qa && qb && qc); + qa[0] = qb[0]*qc[0] - qb[1]*qc[1] - qb[2]*qc[2] - qb[3]*qc[3]; + qa[1] = qb[0]*qc[1] + qb[1]*qc[0] + qb[2]*qc[3] - qb[3]*qc[2]; + qa[2] = qb[0]*qc[2] + qb[2]*qc[0] + qb[3]*qc[1] - qb[1]*qc[3]; + qa[3] = qb[0]*qc[3] + qb[3]*qc[0] + qb[1]*qc[2] - qb[2]*qc[1]; +} + + +void dQMultiply1 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) +{ + dAASSERT (qa && qb && qc); + qa[0] = qb[0]*qc[0] + qb[1]*qc[1] + qb[2]*qc[2] + qb[3]*qc[3]; + qa[1] = qb[0]*qc[1] - qb[1]*qc[0] - qb[2]*qc[3] + qb[3]*qc[2]; + qa[2] = qb[0]*qc[2] - qb[2]*qc[0] - qb[3]*qc[1] + qb[1]*qc[3]; + qa[3] = qb[0]*qc[3] - qb[3]*qc[0] - qb[1]*qc[2] + qb[2]*qc[1]; +} + + +void dQMultiply2 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) +{ + dAASSERT (qa && qb && qc); + qa[0] = qb[0]*qc[0] + qb[1]*qc[1] + qb[2]*qc[2] + qb[3]*qc[3]; + qa[1] = -qb[0]*qc[1] + qb[1]*qc[0] - qb[2]*qc[3] + qb[3]*qc[2]; + qa[2] = -qb[0]*qc[2] + qb[2]*qc[0] - qb[3]*qc[1] + qb[1]*qc[3]; + qa[3] = -qb[0]*qc[3] + qb[3]*qc[0] - qb[1]*qc[2] + qb[2]*qc[1]; +} + + +void dQMultiply3 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) +{ + dAASSERT (qa && qb && qc); + qa[0] = qb[0]*qc[0] - qb[1]*qc[1] - qb[2]*qc[2] - qb[3]*qc[3]; + qa[1] = -qb[0]*qc[1] - qb[1]*qc[0] + qb[2]*qc[3] - qb[3]*qc[2]; + qa[2] = -qb[0]*qc[2] - qb[2]*qc[0] + qb[3]*qc[1] - qb[1]*qc[3]; + qa[3] = -qb[0]*qc[3] - qb[3]*qc[0] + qb[1]*qc[2] - qb[2]*qc[1]; +} + + +// QtoR(), RtoQ() and WtoDQ() are derived from equations in "An Introduction +// to Physically Based Modeling: Rigid Body Simulation - 1: Unconstrained +// Rigid Body Dynamics" by David Baraff, Robotics Institute, Carnegie Mellon +// University, 1997. + +void dQtoR (const dQuaternion q, dMatrix3 R) +{ + dAASSERT (q && R); + // q = (s,vx,vy,vz) + dReal qq1 = 2*q[1]*q[1]; + dReal qq2 = 2*q[2]*q[2]; + dReal qq3 = 2*q[3]*q[3]; + _R(0,0) = 1 - qq2 - qq3; + _R(0,1) = 2*(q[1]*q[2] - q[0]*q[3]); + _R(0,2) = 2*(q[1]*q[3] + q[0]*q[2]); + _R(1,0) = 2*(q[1]*q[2] + q[0]*q[3]); + _R(1,1) = 1 - qq1 - qq3; + _R(1,2) = 2*(q[2]*q[3] - q[0]*q[1]); + _R(2,0) = 2*(q[1]*q[3] - q[0]*q[2]); + _R(2,1) = 2*(q[2]*q[3] + q[0]*q[1]); + _R(2,2) = 1 - qq1 - qq2; +} + + +void dRtoQ (const dMatrix3 R, dQuaternion q) +{ + dAASSERT (q && R); + dReal tr,s; + tr = _R(0,0) + _R(1,1) + _R(2,2); + if (tr >= 0) { + s = dSqrt (tr + 1); + q[0] = REAL(0.5) * s; + s = REAL(0.5) * dRecip(s); + q[1] = (_R(2,1) - _R(1,2)) * s; + q[2] = (_R(0,2) - _R(2,0)) * s; + q[3] = (_R(1,0) - _R(0,1)) * s; + } + else { + // find the largest diagonal element and jump to the appropriate case + if (_R(1,1) > _R(0,0)) { + if (_R(2,2) > _R(1,1)) goto case_2; + goto case_1; + } + if (_R(2,2) > _R(0,0)) goto case_2; + goto case_0; + + case_0: + s = dSqrt((_R(0,0) - (_R(1,1) + _R(2,2))) + 1); + q[1] = REAL(0.5) * s; + s = REAL(0.5) * dRecip(s); + q[2] = (_R(0,1) + _R(1,0)) * s; + q[3] = (_R(2,0) + _R(0,2)) * s; + q[0] = (_R(2,1) - _R(1,2)) * s; + return; + + case_1: + s = dSqrt((_R(1,1) - (_R(2,2) + _R(0,0))) + 1); + q[2] = REAL(0.5) * s; + s = REAL(0.5) * dRecip(s); + q[3] = (_R(1,2) + _R(2,1)) * s; + q[1] = (_R(0,1) + _R(1,0)) * s; + q[0] = (_R(0,2) - _R(2,0)) * s; + return; + + case_2: + s = dSqrt((_R(2,2) - (_R(0,0) + _R(1,1))) + 1); + q[3] = REAL(0.5) * s; + s = REAL(0.5) * dRecip(s); + q[1] = (_R(2,0) + _R(0,2)) * s; + q[2] = (_R(1,2) + _R(2,1)) * s; + q[0] = (_R(1,0) - _R(0,1)) * s; + return; + } +} + + +void dWtoDQ (const dVector3 w, const dQuaternion q, dVector4 dq) +{ + dAASSERT (w && q && dq); + dq[0] = REAL(0.5)*(- w[0]*q[1] - w[1]*q[2] - w[2]*q[3]); + dq[1] = REAL(0.5)*( w[0]*q[0] + w[1]*q[3] - w[2]*q[2]); + dq[2] = REAL(0.5)*(- w[0]*q[3] + w[1]*q[0] + w[2]*q[1]); + dq[3] = REAL(0.5)*( w[0]*q[2] - w[1]*q[1] + w[2]*q[0]); +} diff --git a/extern/ode/dist/ode/src/scrapbook.cpp b/extern/ode/dist/ode/src/scrapbook.cpp new file mode 100644 index 00000000000..ca8c11f1f1b --- /dev/null +++ b/extern/ode/dist/ode/src/scrapbook.cpp @@ -0,0 +1,270 @@ + +/* + +this is code that was once useful but has now been obseleted. + +this file should not be compiled as part of ODE! + +*/ + +//*************************************************************************** +// intersect a line segment with a plane + +extern "C" int dClipLineToBox (const dVector3 p1, const dVector3 p2, + const dVector3 p, const dMatrix3 R, + const dVector3 side) +{ + // compute the start and end of the line (p1 and p2) relative to the box. + // we will do all subsequent computations in this box-relative coordinate + // system. we have to do a translation and rotation for each point. + dVector3 tmp,s,e; + tmp[0] = p1[0] - p[0]; + tmp[1] = p1[1] - p[1]; + tmp[2] = p1[2] - p[2]; + dMULTIPLY1_331 (s,R,tmp); + tmp[0] = p2[0] - p[0]; + tmp[1] = p2[1] - p[1]; + tmp[2] = p2[2] - p[2]; + dMULTIPLY1_331 (e,R,tmp); + + // compute the vector 'v' from the start point to the end point + dVector3 v; + v[0] = e[0] - s[0]; + v[1] = e[1] - s[1]; + v[2] = e[2] - s[2]; + + // a point on the line is defined by the parameter 't'. t=0 corresponds + // to the start of the line, t=1 corresponds to the end of the line. + // we will clip the line to the box by finding the range of t where a + // point on the line is inside the box. the currently known bounds for + // t and tlo..thi. + dReal tlo=0,thi=1; + + // clip in the X/Y/Z direction + for (int i=0; i<3; i++) { + // first adjust s,e for the current t range. this is redundant for the + // first iteration, but never mind. + e[i] = s[i] + thi*v[i]; + s[i] = s[i] + tlo*v[i]; + // compute where t intersects the positive and negative sides. + dReal tp = ( side[i] - s[i])/v[i]; // @@@ handle case where denom=0 + dReal tm = (-side[i] - s[i])/v[i]; + // handle 9 intersection cases + if (s[i] <= -side[i]) { + tlo = tm; + if (e[i] <= -side[i]) return 0; + else if (e[i] >= side[i]) thi = tp; + } + else if (s[i] <= side[i]) { + if (e[i] <= -side[i]) thi = tm; + else if (e[i] >= side[i]) thi = tp; + } + else { + tlo = tp; + if (e[i] <= -side[i]) thi = tm; + else if (e[i] >= side[i]) return 0; + } + } + + //... @@@ AT HERE @@@ + + return 1; +} + + +//*************************************************************************** +// a nice try at C-B collision. unfortunately it doesn't work. the logic +// for testing for line-box intersection is correct, but unfortunately the +// closest-point distance estimates are often too large. as a result contact +// points are placed incorrectly. + + +int dCollideCB (const dxGeom *o1, const dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + int i; + + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->_class->num == dCCylinderClass); + dIASSERT (o2->_class->num == dBoxClass); + contact->g1 = const_cast (o1); + contact->g2 = const_cast (o2); + dxCCylinder *cyl = (dxCCylinder*) CLASSDATA(o1); + dxBox *box = (dxBox*) CLASSDATA(o2); + + // get p1,p2 = cylinder axis endpoints, get radius + dVector3 p1,p2; + dReal clen = cyl->lz * REAL(0.5); + p1[0] = o1->pos[0] + clen * o1->R[2]; + p1[1] = o1->pos[1] + clen * o1->R[6]; + p1[2] = o1->pos[2] + clen * o1->R[10]; + p2[0] = o1->pos[0] - clen * o1->R[2]; + p2[1] = o1->pos[1] - clen * o1->R[6]; + p2[2] = o1->pos[2] - clen * o1->R[10]; + dReal radius = cyl->radius; + + // copy out box center, rotation matrix, and side array + dReal *c = o2->pos; + dReal *R = o2->R; + dReal *side = box->side; + + // compute the start and end of the line (p1 and p2) relative to the box. + // we will do all subsequent computations in this box-relative coordinate + // system. we have to do a translation and rotation for each point. + dVector3 tmp3,s,e; + tmp3[0] = p1[0] - c[0]; + tmp3[1] = p1[1] - c[1]; + tmp3[2] = p1[2] - c[2]; + dMULTIPLY1_331 (s,R,tmp3); + tmp3[0] = p2[0] - c[0]; + tmp3[1] = p2[1] - c[1]; + tmp3[2] = p2[2] - c[2]; + dMULTIPLY1_331 (e,R,tmp3); + + // compute the vector 'v' from the start point to the end point + dVector3 v; + v[0] = e[0] - s[0]; + v[1] = e[1] - s[1]; + v[2] = e[2] - s[2]; + + // compute the half-sides of the box + dReal S0 = side[0] * REAL(0.5); + dReal S1 = side[1] * REAL(0.5); + dReal S2 = side[2] * REAL(0.5); + + // compute the size of the bounding box around the line segment + dReal B0 = dFabs (v[0]); + dReal B1 = dFabs (v[1]); + dReal B2 = dFabs (v[2]); + + // for all 6 separation axes, measure the penetration depth. if any depth is + // less than 0 then the objects don't penetrate at all so we can just + // return 0. find the axis with the smallest depth, and record its normal. + + // note: normalR is set to point to a column of R if that is the smallest + // depth normal so far. otherwise normalR is 0 and normalC is set to a + // vector relative to the box. invert_normal is 1 if the sign of the normal + // should be flipped. + + dReal depth,trial_depth,tmp,length; + const dReal *normalR=0; + dVector3 normalC; + int invert_normal = 0; + int code = 0; // 0=no contact, 1-3=face contact, 4-6=edge contact + + depth = dInfinity; + + // look at face-normal axes + +#undef TEST +#define TEST(center,depth_expr,norm,contact_code) \ + tmp = (center); \ + trial_depth = radius + REAL(0.5) * ((depth_expr) - dFabs(tmp)); \ + if (trial_depth < 0) return 0; \ + if (trial_depth < depth) { \ + depth = trial_depth; \ + normalR = (norm); \ + invert_normal = (tmp < 0); \ + code = contact_code; \ + } + + TEST (s[0]+e[0], side[0] + B0, R+0, 1); + TEST (s[1]+e[1], side[1] + B1, R+1, 2); + TEST (s[2]+e[2], side[2] + B2, R+2, 3); + + // look at v x box-edge axes + +#undef TEST +#define TEST(box_radius,line_offset,nx,ny,nz,contact_code) \ + tmp = (line_offset); \ + trial_depth = (box_radius) - dFabs(tmp); \ + length = dSqrt ((nx)*(nx) + (ny)*(ny) + (nz)*(nz)); \ + if (length > 0) { \ + length = dRecip(length); \ + trial_depth = trial_depth * length + radius; \ + if (trial_depth < 0) return 0; \ + if (trial_depth < depth) { \ + depth = trial_depth; \ + normalR = 0; \ + normalC[0] = (nx)*length; \ + normalC[1] = (ny)*length; \ + normalC[2] = (nz)*length; \ + invert_normal = (tmp < 0); \ + code = contact_code; \ + } \ + } + + TEST (B2*S1+B1*S2,v[1]*s[2]-v[2]*s[1], 0,-v[2],v[1], 4); + TEST (B2*S0+B0*S2,v[2]*s[0]-v[0]*s[2], v[2],0,-v[0], 5); + TEST (B1*S0+B0*S1,v[0]*s[1]-v[1]*s[0], -v[1],v[0],0, 6); + +#undef TEST + + // if we get to this point, the box and ccylinder interpenetrate. + // compute the normal in global coordinates. + dReal *normal = contact[0].normal; + if (normalR) { + normal[0] = normalR[0]; + normal[1] = normalR[4]; + normal[2] = normalR[8]; + } + else { + dMULTIPLY0_331 (normal,R,normalC); + } + if (invert_normal) { + normal[0] = -normal[0]; + normal[1] = -normal[1]; + normal[2] = -normal[2]; + } + + // set the depth + contact[0].depth = depth; + + if (code == 0) { + return 0; // should never get here + } + else if (code >= 4) { + // handle edge contacts + // find an endpoint q1 on the intersecting edge of the box + dVector3 q1; + dReal sign[3]; + for (i=0; i<3; i++) q1[i] = c[i]; + sign[0] = (dDOT14(normal,R+0) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) q1[i] += sign[0] * S0 * R[i*4]; + sign[1] = (dDOT14(normal,R+1) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) q1[i] += sign[1] * S1 * R[i*4+1]; + sign[2] = (dDOT14(normal,R+2) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) q1[i] += sign[2] * S2 * R[i*4+2]; + + // find the other endpoint q2 of the intersecting edge + dVector3 q2; + for (i=0; i<3; i++) + q2[i] = q1[i] - R[code-4 + i*4] * (sign[code-4] * side[code-4]); + + // determine the closest point between the box edge and the line segment + dVector3 cp1,cp2; + dClosestLineSegmentPoints (q1,q2, p1,p2, cp1,cp2); + for (i=0; i<3; i++) contact[0].pos[i] = cp1[i] - REAL(0.5)*normal[i]*depth; + return 1; + } + else { + // handle face contacts. + // @@@ temporary: make deepest vertex on the line the contact point. + // @@@ this kind of works, but we sometimes need two contact points for + // @@@ stability. + + // compute 'v' in global coordinates + dVector3 gv; + for (i=0; i<3; i++) gv[i] = p2[i] - p1[i]; + + if (dDOT (normal,gv) > 0) { + for (i=0; i<3; i++) + contact[0].pos[i] = p1[i] + (depth*REAL(0.5)-radius)*normal[i]; + } + else { + for (i=0; i<3; i++) + contact[0].pos[i] = p2[i] + (depth*REAL(0.5)-radius)*normal[i]; + } + return 1; + } +} diff --git a/extern/ode/dist/ode/src/space.cpp b/extern/ode/dist/ode/src/space.cpp new file mode 100644 index 00000000000..0c656573918 --- /dev/null +++ b/extern/ode/dist/ode/src/space.cpp @@ -0,0 +1,621 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +simple space +------------ + +reports all n^2 object intersections + + +multi-resolution hash table +--------------------------- + +the current implementation rebuilds a new hash table each time collide() +is called. we don't keep any state between calls. this is wasteful if there +are unmoving objects in the space. + + +TODO +---- + +less memory wasting may to prevent multiple collision callbacks for the +same pair? + +better virtual address function. + +the collision search can perhaps be optimized - as we search chains we can +come across other candidate intersections at other levels, perhaps we should +do the intersection check straight away? --> save on list searching time only, +which is not too significant. + +*/ + +//**************************************************************************** + +#include +#include +#include +#include +#include +#include "objects.h" +#include "geom_internal.h" + +//**************************************************************************** +// space base class + +struct dxSpace : public dBase { + int type; // don't want to use RTTI + virtual void destroy()=0; + virtual void add (dGeomID)=0; + virtual void remove (dGeomID)=0; + virtual void collide (void *data, dNearCallback *callback)=0; + virtual int query (dGeomID)=0; +}; + +#define TYPE_SIMPLE 0xbad +#define TYPE_HASH 0xbabe + +//**************************************************************************** +// stuff common to all spaces + +#define ALLOCA(x) dALLOCA16(x) + + +// collide two AABBs together. for the hash table space, this is called if +// the two AABBs inhabit the same hash table cells. this only calls the +// callback function if the boxes actually intersect. if a geom has an +// AABB test function, that is called to provide a further refinement of +// the intersection. + +static inline void collideAABBs (dReal bounds1[6], dReal bounds2[6], + dxGeom *g1, dxGeom *g2, + void *data, dNearCallback *callback) +{ + // no contacts if both geoms on the same body, and the body is not 0 + if (g1->body == g2->body && g1->body) return; + + if (bounds1[0] > bounds2[1] || + bounds1[1] < bounds2[0] || + bounds1[2] > bounds2[3] || + bounds1[3] < bounds2[2] || + bounds1[4] > bounds2[5] || + bounds1[5] < bounds2[4]) return; + if (g1->_class->aabb_test) { + if (g1->_class->aabb_test (g1,g2,bounds2) == 0) return; + } + if (g2->_class->aabb_test) { + if (g2->_class->aabb_test (g2,g1,bounds1) == 0) return; + } + callback (data,g1,g2); +} + +//**************************************************************************** +// simple space - reports all n^2 object intersections + +struct dxSimpleSpace : public dxSpace { + dGeomID first; + void destroy(); + void add (dGeomID); + void remove (dGeomID); + void collide (void *data, dNearCallback *callback); + int query (dGeomID); +}; + + +dSpaceID dSimpleSpaceCreate() +{ + dxSimpleSpace *w = new dxSimpleSpace; + w->type = TYPE_SIMPLE; + w->first = 0; + return w; +} + + +void dxSimpleSpace::destroy() +{ + // destroying each geom will call remove(). this will be efficient if + // we destroy geoms in list order. + dAASSERT (this); + dGeomID g,n; + g = first; + while (g) { + n = g->space.next; + dGeomDestroy (g); + g = n; + } + delete this; +} + + +void dxSimpleSpace::add (dGeomID obj) +{ + dAASSERT (this && obj); + dUASSERT (obj->spaceid == 0 && obj->space.next == 0, + "object is already in a space"); + obj->space.next = first; + first = obj; + obj->spaceid = this; +} + + +void dxSimpleSpace::remove (dGeomID geom_to_remove) +{ + dAASSERT (this && geom_to_remove); + dUASSERT (geom_to_remove->spaceid,"object is not in a space"); + dGeomID last=0,g=first; + while (g) { + if (g==geom_to_remove) { + if (last) last->space.next = g->space.next; + else first = g->space.next; + geom_to_remove->space.next = 0; + geom_to_remove->spaceid = 0; + return; + } + last = g; + g = g->space.next; + } +} + + +void dxSimpleSpace::collide (void *data, dNearCallback *callback) +{ + dAASSERT (this && callback); + dxGeom *g1,*g2; + int i,j,n; + + // count the number of objects + n=0; + for (g1=first; g1; g1=g1->space.next) n++; + + // allocate and fill bounds array + dReal *bounds = (dReal*) ALLOCA (6 * n * sizeof(dReal)); + i=0; + for (g1=first; g1; g1=g1->space.next) { + g1->_class->aabb (g1,bounds + i); + g1->space_aabb = bounds + i; + i += 6; + } + + // intersect all bounding boxes + i=0; + for (g1=first; g1; g1=g1->space.next) { + j=i+6; + for (g2=g1->space.next; g2; g2=g2->space.next) { + collideAABBs (bounds+i,bounds+j,g1,g2,data,callback); + j += 6; + } + i += 6; + } + + // reset the aabb fields of the geoms back to 0 + for (g1=first; g1; g1=g1->space.next) g1->space_aabb = 0; +} + + +// @@@ NOT FLEXIBLE ENOUGH +// +//int dSpaceCollide (dSpaceID space, dContactGeom **contact_array) +//{ +// int n = 0; +// dContactGeom *base = (dContact*) dStackAlloc (sizeof(dContact)); +// dContactGeom *c = base; +// for (dxGeom *g1=space->first; g1; g1=g1->space.next) { +// for (dxGeom *g2=g1->space.next; g2; g2=g2->space.next) { +// // generate at most 1 contact for this pair +// c->o1 = g1; +// c->o2 = g2; +// if (dCollide (0,c)) { +// c = (dContactGeom*) dStackAlloc (sizeof(dContactGeom)); +// n++; +// } +// } +// } +// *contact_array = base; +// return n; +//} + + +int dxSimpleSpace::query (dGeomID obj) +{ + dAASSERT (this && obj); + if (obj->spaceid != this) return 0; + dGeomID compare = first; + while (compare) { + if (compare == obj) return 1; + compare = compare->space.next; + } + dDebug (0,"object is not in the space it thinks it is in"); + return 0; +} + +//**************************************************************************** +// hash table space + +// kind of silly, but oh well... +#define MAXINT ((int)((((unsigned int)(-1)) << 1) >> 1)) + + +// prime[i] is the largest prime smaller than 2^i +#define NUM_PRIMES 31 +static long int prime[NUM_PRIMES] = {1L,2L,3L,7L,13L,31L,61L,127L,251L,509L, + 1021L,2039L,4093L,8191L,16381L,32749L,65521L,131071L,262139L, + 524287L,1048573L,2097143L,4194301L,8388593L,16777213L,33554393L, + 67108859L,134217689L,268435399L,536870909L,1073741789L}; + + +// currently the space 'container' is just a list of the geoms in the space. + +struct dxHashSpace : public dxSpace { + dxGeom *first; + int global_minlevel; // smallest hash table level to put AABBs in + int global_maxlevel; // objects that need a level larger than this will be + // put in a "big objects" list instead of a hash table + void destroy(); + void add (dGeomID); + void remove (dGeomID); + void collide (void *data, dNearCallback *callback); + int query (dGeomID); +}; + + +// an axis aligned bounding box +struct dxAABB { + dxAABB *next; // next in the list of all AABBs + dReal bounds[6]; // minx, maxx, miny, maxy, minz, maxz + int level; // the level this is stored in (cell size = 2^level) + int dbounds[6]; // AABB bounds, discretized to cell size + dxGeom *geom; // corresponding geometry object + int index; // index of this AABB, starting from 0 +}; + + +// a hash table node that represents an AABB that intersects a particular cell +// at a particular level +struct Node { + Node *next; // next node in hash table collision list, 0 if none + int x,y,z; // cell position in space, discretized to cell size + dxAABB *aabb; // axis aligned bounding box that intersects this cell +}; + + +// return the `level' of an AABB. the AABB will be put into cells at this +// level - the cell size will be 2^level. the level is chosen to be the +// smallest value such that the AABB occupies no more than 8 cells, regardless +// of its placement. this means that: +// size/2 < q <= size +// where q is the maximum AABB dimension. + +static int findLevel (dReal bounds[6]) +{ + // compute q + dReal q,q2; + q = bounds[1] - bounds[0]; // x bounds + q2 = bounds[3] - bounds[2]; // y bounds + if (q2 > q) q = q2; + q2 = bounds[5] - bounds[4]; // z bounds + if (q2 > q) q = q2; + + if (q == dInfinity) return MAXINT; + + // find level such that 0.5 * 2^level < q <= 2^level + int level; + frexp (q,&level); // q = (0.5 .. 1.0) * 2^level (definition of frexp) + return level; +} + + +// find a virtual memory address for a cell at the given level and x,y,z +// position. +// @@@ currently this is not very sophisticated, e.g. the scaling +// factors could be better designed to avoid collisions, and they should +// probably depend on the hash table physical size. + +static unsigned long getVirtualAddress (int level, int x, int y, int z) +{ + return level*1000 + x*100 + y*10 + z; +} + +//**************************************************************************** +// hash space public functions + +dSpaceID dHashSpaceCreate() +{ + dxHashSpace *w = new dxHashSpace; + w->type = TYPE_HASH; + w->first = 0; + w->global_minlevel = -3; + w->global_maxlevel = 10; + return w; +} + + +void dxHashSpace::destroy() +{ + // destroying each geom will call remove(). this will be efficient if + // we destroy geoms in list order. + dAASSERT (this); + dGeomID g,n; + g = first; + while (g) { + n = g->space.next; + dGeomDestroy (g); + g = n; + } + delete this; +} + + +void dHashSpaceSetLevels (dxSpace *space, int minlevel, int maxlevel) +{ + dUASSERT (minlevel <= maxlevel,"must have minlevel <= maxlevel"); + dUASSERT (space->type == TYPE_HASH,"must be a hash space"); + dxHashSpace *hspace = (dxHashSpace*) space; + hspace->global_minlevel = minlevel; + hspace->global_maxlevel = maxlevel; +} + + +void dxHashSpace::add (dGeomID obj) +{ + dAASSERT (this && obj); + dUASSERT (obj->spaceid == 0 && obj->space.next == 0, + "object is already in a space"); + obj->space.next = first; + first = obj; + obj->spaceid = this; +} + + +void dxHashSpace::remove (dGeomID geom_to_remove) +{ + dAASSERT (this && geom_to_remove); + dUASSERT (geom_to_remove->spaceid,"object is not in a space"); + dGeomID last=0,g=first; + while (g) { + if (g==geom_to_remove) { + if (last) last->space.next = g->space.next; + else first = g->space.next; + geom_to_remove->space.next = 0; + geom_to_remove->spaceid = 0; + return; + } + last = g; + g = g->space.next; + } +} + + +void dxHashSpace::collide (void *data, dNearCallback *callback) +{ + dAASSERT(this && callback); + dxGeom *geom; + dxAABB *aabb; + int i,maxlevel; + + // create a list of axis aligned bounding boxes for all geoms. count the + // number of AABBs as we go. set the level for all AABBs. put AABBs larger + // than the space's global_maxlevel in the big_boxes list, check everything + // else against that list at the end. for AABBs that are not too big, + // record the maximum level that we need. + + int n = 0; // number of AABBs in main list + int ntotal = 0; // total number of AABBs + dxAABB *first_aabb = 0; // list of AABBs in hash table + dxAABB *big_boxes = 0; // list of AABBs too big for hash table + maxlevel = global_minlevel - 1; + for (geom = first; geom; geom=geom->space.next) { + ntotal++; + dxAABB *aabb = (dxAABB*) ALLOCA (sizeof(dxAABB)); + geom->_class->aabb (geom,aabb->bounds); + geom->space_aabb = aabb->bounds; + aabb->geom = geom; + // compute level, but prevent cells from getting too small + int level = findLevel (aabb->bounds); + if (level < global_minlevel) level = global_minlevel; + if (level <= global_maxlevel) { + // aabb goes in main list + aabb->next = first_aabb; + first_aabb = aabb; + aabb->level = level; + if (level > maxlevel) maxlevel = level; + // cellsize = 2^level + dReal cellsize = (dReal) ldexp (1.0,level); + // discretize AABB position to cell size + for (i=0; i < 6; i++) aabb->dbounds[i] = (int) + floor (aabb->bounds[i]/cellsize); + // set AABB index + aabb->index = n; + n++; + } + else { + // aabb is too big, put it in the big_boxes list. we don't care about + // setting level, dbounds, index, or the maxlevel + aabb->next = big_boxes; + big_boxes = aabb; + } + } + + // 0 or 1 boxes can't collide with anything + if (ntotal < 2) return; + + // for `n' objects, an n*n array of bits is used to record if those objects + // have been intersection-tested against each other yet. this array can + // grow large with high n, but oh well... + int tested_rowsize = (n+7) >> 3; // number of bytes needed for n bits + unsigned char *tested = (unsigned char *) alloca (n * tested_rowsize); + memset (tested,0,n * tested_rowsize); + + // create a hash table to store all AABBs. each AABB may take up to 8 cells. + // we use chaining to resolve collisions, but we use a relatively large table + // to reduce the chance of collisions. + + // compute hash table size sz to be a prime > 8*n + for (i=0; i= (8*n)) break; + } + if (i >= NUM_PRIMES) i = NUM_PRIMES-1; // probably pointless + int sz = prime[i]; + + // allocate and initialize hash table node pointers + Node **table = (Node **) ALLOCA (sizeof(Node*) * sz); + for (i=0; inext) { + int *dbounds = aabb->dbounds; + for (int xi = dbounds[0]; xi <= dbounds[1]; xi++) { + for (int yi = dbounds[2]; yi <= dbounds[3]; yi++) { + for (int zi = dbounds[4]; zi <= dbounds[5]; zi++) { + // get the hash index + unsigned long hi = getVirtualAddress (aabb->level,xi,yi,zi) % sz; + // add a new node to the hash table + Node *node = (Node*) alloca (sizeof (Node)); + node->x = xi; + node->y = yi; + node->z = zi; + node->aabb = aabb; + node->next = table[hi]; + table[hi] = node; + } + } + } + } + + // now that all AABBs are loaded into the hash table, we do the actual + // collision detection. for all AABBs, check for other AABBs in the + // same cells for collisions, and then check for other AABBs in all + // intersecting higher level cells. + + int db[6]; // discrete bounds at current level + for (aabb=first_aabb; aabb; aabb=aabb->next) { + // we are searching for collisions with aabb + for (i=0; i<6; i++) db[i] = aabb->dbounds[i]; + for (int level = aabb->level; level <= maxlevel; level++) { + for (int xi = db[0]; xi <= db[1]; xi++) { + for (int yi = db[2]; yi <= db[3]; yi++) { + for (int zi = db[4]; zi <= db[5]; zi++) { + // get the hash index + unsigned long hi = getVirtualAddress (level,xi,yi,zi) % sz; + // search all nodes at this index + Node *node; + for (node = table[hi]; node; node=node->next) { + // node points to an AABB that may intersect aabb + if (node->aabb == aabb) continue; + if (node->aabb->level == level && + node->x == xi && node->y == yi && node->z == zi) { + // see if aabb and node->aabb have already been tested + // against each other + unsigned char mask; + if (aabb->index <= node->aabb->index) { + i = (aabb->index * tested_rowsize)+(node->aabb->index >> 3); + mask = 1 << (node->aabb->index & 7); + } + else { + i = (node->aabb->index * tested_rowsize)+(aabb->index >> 3); + mask = 1 << (aabb->index & 7); + } + dIASSERT (i >= 0 && i < (tested_rowsize*n)); + if ((tested[i] & mask)==0) { + collideAABBs (aabb->bounds,node->aabb->bounds, + aabb->geom,node->aabb->geom, + data,callback); + } + tested[i] |= mask; + } + } + } + } + } + // get the discrete bounds for the next level up + for (i=0; i<6; i++) db[i] >>= 1; + } + } + + // every AABB in the normal list must now be intersected against every + // AABB in the big_boxes list. so let's hope there are not too many objects + // in the big_boxes list. + for (aabb=first_aabb; aabb; aabb=aabb->next) { + for (dxAABB *aabb2=big_boxes; aabb2; aabb2=aabb2->next) { + collideAABBs (aabb->bounds,aabb2->bounds,aabb->geom,aabb2->geom, + data,callback); + } + } + + // intersected all AABBs in the big_boxes list together + for (aabb=big_boxes; aabb; aabb=aabb->next) { + for (dxAABB *aabb2=aabb->next; aabb2; aabb2=aabb2->next) { + collideAABBs (aabb->bounds,aabb2->bounds,aabb->geom,aabb2->geom, + data,callback); + } + } + + // reset the aabb fields of the geoms back to 0 + for (geom=first; geom; geom=geom->space.next) geom->space_aabb = 0; +} + + +int dxHashSpace::query (dGeomID obj) +{ + dAASSERT (this && obj); + if (obj->spaceid != this) return 0; + dGeomID compare = first; + while (compare) { + if (compare == obj) return 1; + compare = compare->space.next; + } + dDebug (0,"object is not in the space it thinks it is in"); + return 0; +} + +//**************************************************************************** +// space functions + +void dSpaceDestroy (dxSpace * space) +{ + space->destroy(); +} + + +void dSpaceAdd (dxSpace * space, dxGeom *g) +{ + space->add (g); +} + + +void dSpaceRemove (dxSpace * space, dxGeom *g) +{ + space->remove (g); +} + + +int dSpaceQuery (dxSpace * space, dxGeom *g) +{ + return space->query (g); +} + + +void dSpaceCollide (dxSpace * space, void *data, dNearCallback *callback) +{ + space->collide (data,callback); +} diff --git a/extern/ode/dist/ode/src/stack.cpp b/extern/ode/dist/ode/src/stack.cpp new file mode 100644 index 00000000000..e062f92b54f --- /dev/null +++ b/extern/ode/dist/ode/src/stack.cpp @@ -0,0 +1,114 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +@@@ this file should not be compiled any more @@@ + +#include +#include +#include "stack.h" +#include "ode/error.h" +#include "ode/config.h" + +//**************************************************************************** +// unix version that uses mmap(). some systems have anonymous mmaps and some +// need to mmap /dev/zero. + +#ifndef WIN32 + +#include +#include +#include +#include +#include + + +void dStack::init (int max_size) +{ + if (sizeof(long int) != sizeof(char*)) dDebug (0,"internal"); + if (max_size <= 0) dDebug (0,"Stack::init() given size <= 0"); + +#ifndef MMAP_ANONYMOUS + static int dev_zero_fd = -1; // cached file descriptor for /dev/zero + if (dev_zero_fd < 0) dev_zero_fd = open ("/dev/zero", O_RDWR); + if (dev_zero_fd < 0) dError (0,"can't open /dev/zero (%s)",strerror(errno)); + base = (char*) mmap (0,max_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, + dev_zero_fd,0); +#else + base = (char*) mmap (0,max_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON,0,0); +#endif + + if (int(base) == -1) dError (0,"Stack::init(), mmap() failed, " + "max_size=%d (%s)",max_size,strerror(errno)); + size = max_size; + pointer = base; + frame = 0; +} + + +void dStack::destroy() +{ + munmap (base,size); + base = 0; + size = 0; + pointer = 0; + frame = 0; +} + +#endif + +//**************************************************************************** + +#ifdef WIN32 + +#include "windows.h" + + +void dStack::init (int max_size) +{ + if (sizeof(LPVOID) != sizeof(char*)) dDebug (0,"internal"); + if (max_size <= 0) dDebug (0,"Stack::init() given size <= 0"); + base = (char*) VirtualAlloc (NULL,max_size,MEM_RESERVE,PAGE_READWRITE); + if (base == 0) dError (0,"Stack::init(), VirtualAlloc() failed, " + "max_size=%d",max_size); + size = max_size; + pointer = base; + frame = 0; + committed = 0; + + // get page size + SYSTEM_INFO info; + GetSystemInfo (&info); + pagesize = info.dwPageSize; +} + + +void dStack::destroy() +{ + VirtualFree (base,0,MEM_RELEASE); + base = 0; + size = 0; + pointer = 0; + frame = 0; +} + +#endif diff --git a/extern/ode/dist/ode/src/stack.h b/extern/ode/dist/ode/src/stack.h new file mode 100644 index 00000000000..3b98202b042 --- /dev/null +++ b/extern/ode/dist/ode/src/stack.h @@ -0,0 +1,139 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* this comes from the `reuse' library. copy any changes back to the source. + +these stack allocation functions are a replacement for alloca(), except that +they allocate memory from a separate pool. + +advantages over alloca(): + - consecutive allocations are guaranteed to be contiguous with increasing + address. + - functions can allocate stack memory that is returned to the caller, + in other words pushing and popping stack frames is optional. + +disadvantages compared to alloca(): + - less portable + - slightly slower, although still orders of magnitude faster than malloc(). + - longjmp() and exceptions do not deallocate stack memory (but who cares?). + +just like alloca(): + - using too much stack memory does not fail gracefully, it fails with a + segfault. + +*/ + + +#ifndef _ODE_STACK_H_ +#define _ODE_STACK_H_ + + +#ifdef WIN32 +#include "windows.h" +#endif + + +struct dStack { + char *base; // bottom of the stack + int size; // maximum size of the stack + char *pointer; // current top of the stack + char *frame; // linked list of stack frame ptrs +# ifdef WIN32 // stuff for windows: + int pagesize; // - page size - this is ASSUMED to be a power of 2 + int committed; // - bytes committed in allocated region +#endif + + // initialize the stack. `max_size' is the maximum size that the stack can + // reach. on unix and windows a `virtual' memory block of this size is + // mapped into the address space but does not actually consume physical + // memory until it is referenced - so it is safe to set this to a high value. + + void init (int max_size); + + + // destroy the stack. this unmaps any virtual memory that was allocated. + + void destroy(); + + + // allocate `size' bytes from the stack and return a pointer to the allocated + // memory. `size' must be >= 0. the returned pointer will be aligned to the + // size of a long int. + + char * alloc (int size) + { + char *ret = pointer; + pointer += ((size-1) | (sizeof(long int)-1) )+1; +# ifdef WIN32 + // for windows we need to commit pages as they are required + if ((pointer-base) > committed) { + committed = ((pointer-base-1) | (pagesize-1))+1; // round up to pgsize + VirtualAlloc (base,committed,MEM_COMMIT,PAGE_READWRITE); + } +# endif + return ret; + } + + + // return the address that will be returned by the next call to alloc() + + char *nextAlloc() + { + return pointer; + } + + + // push and pop the current size of the stack. pushFrame() saves the current + // frame pointer on the stack, and popFrame() retrieves it. a typical + // stack-using function will bracket alloc() calls with pushFrame() and + // popFrame(). both functions return the current stack pointer - this should + // be the same value for the two bracketing calls. calling popFrame() too + // many times will result in a segfault. + + char * pushFrame() + { + char *newframe = pointer; + char **addr = (char**) alloc (sizeof(char*)); + *addr = frame; + frame = newframe; + return newframe; + + /* OLD CODE + *((char**)pointer) = frame; + frame = pointer; + char *ret = pointer; + pointer += sizeof(char*); + return ret; + */ + } + + char * popFrame() + { + pointer = frame; + frame = *((char**)pointer); + return pointer; + } +}; + + +#endif + diff --git a/extern/ode/dist/ode/src/step.cpp b/extern/ode/dist/ode/src/step.cpp new file mode 100644 index 00000000000..16f77112ad2 --- /dev/null +++ b/extern/ode/dist/ode/src/step.cpp @@ -0,0 +1,1085 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "objects.h" +#include "joint.h" +#include +#include +#include +#include +#include +#include +#include "lcp.h" + +//**************************************************************************** +// misc defines + +#define FAST_FACTOR +//#define TIMING + +#define ALLOCA dALLOCA16 + +//**************************************************************************** +// debugging - comparison of various vectors and matrices produced by the +// slow and fast versions of the stepper. + +//#define COMPARE_METHODS + +#ifdef COMPARE_METHODS +#include "testing.h" +dMatrixComparison comparator; +#endif + +//**************************************************************************** +// special matrix multipliers + +// this assumes the 4th and 8th rows of B and C are zero. + +static void Multiply2_p8r (dReal *A, dReal *B, dReal *C, + int p, int r, int Askip) +{ + int i,j; + dReal sum,*bb,*cc; + dIASSERT (p>0 && r>0 && A && B && C); + bb = B; + for (i=p; i; i--) { + cc = C; + for (j=r; j; j--) { + sum = bb[0]*cc[0]; + sum += bb[1]*cc[1]; + sum += bb[2]*cc[2]; + sum += bb[4]*cc[4]; + sum += bb[5]*cc[5]; + sum += bb[6]*cc[6]; + *(A++) = sum; + cc += 8; + } + A += Askip - r; + bb += 8; + } +} + + +// this assumes the 4th and 8th rows of B and C are zero. + +static void MultiplyAdd2_p8r (dReal *A, dReal *B, dReal *C, + int p, int r, int Askip) +{ + int i,j; + dReal sum,*bb,*cc; + dIASSERT (p>0 && r>0 && A && B && C); + bb = B; + for (i=p; i; i--) { + cc = C; + for (j=r; j; j--) { + sum = bb[0]*cc[0]; + sum += bb[1]*cc[1]; + sum += bb[2]*cc[2]; + sum += bb[4]*cc[4]; + sum += bb[5]*cc[5]; + sum += bb[6]*cc[6]; + *(A++) += sum; + cc += 8; + } + A += Askip - r; + bb += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void Multiply0_p81 (dReal *A, dReal *B, dReal *C, int p) +{ + int i; + dIASSERT (p>0 && A && B && C); + dReal sum; + for (i=p; i; i--) { + sum = B[0]*C[0]; + sum += B[1]*C[1]; + sum += B[2]*C[2]; + sum += B[4]*C[4]; + sum += B[5]*C[5]; + sum += B[6]*C[6]; + *(A++) = sum; + B += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void MultiplyAdd0_p81 (dReal *A, dReal *B, dReal *C, int p) +{ + int i; + dIASSERT (p>0 && A && B && C); + dReal sum; + for (i=p; i; i--) { + sum = B[0]*C[0]; + sum += B[1]*C[1]; + sum += B[2]*C[2]; + sum += B[4]*C[4]; + sum += B[5]*C[5]; + sum += B[6]*C[6]; + *(A++) += sum; + B += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void MultiplyAdd1_8q1 (dReal *A, dReal *B, dReal *C, int q) +{ + int k; + dReal sum; + dIASSERT (q>0 && A && B && C); + sum = 0; + for (k=0; k0 && A && B && C); + sum = 0; + for (k=0; kpos[j] += h * b->lvel[j]; + + if (b->flags & dxBodyFlagFiniteRotation) { + dVector3 irv; // infitesimal rotation vector + dQuaternion q; // quaternion for finite rotation + + if (b->flags & dxBodyFlagFiniteRotationAxis) { + // split the angular velocity vector into a component along the finite + // rotation axis, and a component orthogonal to it. + dVector3 frv,irv; // finite rotation vector + dReal k = dDOT (b->finite_rot_axis,b->avel); + frv[0] = b->finite_rot_axis[0] * k; + frv[1] = b->finite_rot_axis[1] * k; + frv[2] = b->finite_rot_axis[2] * k; + irv[0] = b->avel[0] - frv[0]; + irv[1] = b->avel[1] - frv[1]; + irv[2] = b->avel[2] - frv[2]; + + // make a rotation quaternion q that corresponds to frv * h. + // compare this with the full-finite-rotation case below. + h *= REAL(0.5); + dReal theta = k * h; + q[0] = dCos(theta); + dReal s = sinc(theta) * h; + q[1] = frv[0] * s; + q[2] = frv[1] * s; + q[3] = frv[2] * s; + } + else { + // make a rotation quaternion q that corresponds to w * h + dReal wlen = dSqrt (b->avel[0]*b->avel[0] + b->avel[1]*b->avel[1] + + b->avel[2]*b->avel[2]); + h *= REAL(0.5); + dReal theta = wlen * h; + q[0] = dCos(theta); + dReal s = sinc(theta) * h; + q[1] = b->avel[0] * s; + q[2] = b->avel[1] * s; + q[3] = b->avel[2] * s; + } + + // do the finite rotation + dQuaternion q2; + dQMultiply0 (q2,q,b->q); + for (j=0; j<4; j++) b->q[j] = q2[j]; + + // do the infitesimal rotation if required + if (b->flags & dxBodyFlagFiniteRotationAxis) { + dReal dq[4]; + dWtoDQ (irv,b->q,dq); + for (j=0; j<4; j++) b->q[j] += h * dq[j]; + } + } + else { + // the normal way - do an infitesimal rotation + dReal dq[4]; + dWtoDQ (b->avel,b->q,dq); + for (j=0; j<4; j++) b->q[j] += h * dq[j]; + } + + // normalize the quaternion and convert it to a rotation matrix + dNormalize4 (b->q); + dQtoR (b->q,b->R); +} + +//**************************************************************************** +// the slow, but sure way +// note that this does not do any joint feedback! + +// given lists of bodies and joints that form an island, perform a first +// order timestep. +// +// `body' is the body array, `nb' is the size of the array. +// `_joint' is the body array, `nj' is the size of the array. + +void dInternalStepIsland_x1 (dxWorld *world, dxBody * const *body, int nb, + dxJoint * const *_joint, int nj, dReal stepsize) +{ + int i,j,k; + int n6 = 6*nb; + +# ifdef TIMING + dTimerStart("preprocessing"); +# endif + + // number all bodies in the body list - set their tag values + for (i=0; itag = i; + + // make a local copy of the joint array, because we might want to modify it. + // (the "dxJoint *const*" declaration says we're allowed to modify the joints + // but not the joint array, because the caller might need it unchanged). + dxJoint **joint = (dxJoint**) ALLOCA (nj * sizeof(dxJoint*)); + memcpy (joint,_joint,nj * sizeof(dxJoint*)); + + // for all bodies, compute the inertia tensor and its inverse in the global + // frame, and compute the rotational force and add it to the torque + // accumulator. + // @@@ check computation of rotational force. + dReal *I = (dReal*) ALLOCA (3*nb*4 * sizeof(dReal)); + dReal *invI = (dReal*) ALLOCA (3*nb*4 * sizeof(dReal)); + dSetZero (I,3*nb*4); + dSetZero (invI,3*nb*4); + for (i=0; imass.I,body[i]->R); + dMULTIPLY0_333 (I+i*12,body[i]->R,tmp); + // compute inverse inertia tensor in global frame + dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->R); + dMULTIPLY0_333 (invI+i*12,body[i]->R,tmp); + // compute rotational force + dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); + dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); + } + + // add the gravity force to all bodies + for (i=0; iflags & dxBodyNoGravity)==0) { + body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; + body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; + body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; + } + } + + // get m = total constraint dimension, nub = number of unbounded variables. + // create constraint offset array and number-of-rows array for all joints. + // the constraints are re-ordered as follows: the purely unbounded + // constraints, the mixed unbounded + LCP constraints, and last the purely + // LCP constraints. + // + // joints with m=0 are inactive and are removed from the joints array + // entirely, so that the code that follows does not consider them. + int m = 0; + dxJoint::Info1 *info = (dxJoint::Info1*) ALLOCA (nj*sizeof(dxJoint::Info1)); + int *ofs = (int*) ALLOCA (nj*sizeof(int)); + for (i=0, j=0; jvtable->getInfo1 (joint[j],info+i); + dIASSERT (info[i].m >= 0 && info[i].m <= 6 && + info[i].nub >= 0 && info[i].nub <= info[i].m); + if (info[i].m > 0) { + joint[i] = joint[j]; + i++; + } + } + nj = i; + + // the purely unbounded constraints + for (i=0; i 0 && info[i].nub < info[i].m) { + ofs[i] = m; + m += info[i].m; + } + // the purely LCP constraints + for (i=0; iinvMass; + MM[nskip+1] = body[i]->invMass; + MM[2*nskip+2] = body[i]->invMass; + MM += 3*nskip+3; + for (j=0; j<3; j++) for (k=0; k<3; k++) { + MM[j*nskip+k] = invI[i*12+j*4+k]; + } + } + + // assemble some body vectors: fe = external forces, v = velocities + dReal *fe = (dReal*) ALLOCA (n6 * sizeof(dReal)); + dReal *v = (dReal*) ALLOCA (n6 * sizeof(dReal)); + dSetZero (fe,n6); + dSetZero (v,n6); + for (i=0; ifacc[j]; + for (j=0; j<3; j++) fe[i*6+3+j] = body[i]->tacc[j]; + for (j=0; j<3; j++) v[i*6+j] = body[i]->lvel[j]; + for (j=0; j<3; j++) v[i*6+3+j] = body[i]->avel[j]; + } + + // this will be set to the velocity update + dReal *vnew = (dReal*) ALLOCA (n6 * sizeof(dReal)); + dSetZero (vnew,n6); + + // if there are constraints, compute cforce + if (m > 0) { + // create a constraint equation right hand side vector `c', a constraint + // force mixing vector `cfm', and LCP low and high bound vectors, and an + // 'findex' vector. + dReal *c = (dReal*) ALLOCA (m*sizeof(dReal)); + dReal *cfm = (dReal*) ALLOCA (m*sizeof(dReal)); + dReal *lo = (dReal*) ALLOCA (m*sizeof(dReal)); + dReal *hi = (dReal*) ALLOCA (m*sizeof(dReal)); + int *findex = (int*) alloca (m*sizeof(int)); + dSetZero (c,m); + dSetValue (cfm,m,world->global_cfm); + dSetValue (lo,m,-dInfinity); + dSetValue (hi,m, dInfinity); + for (i=0; iglobal_erp; + for (i=0; inode[0].body->tag; + Jinfo.J1a = Jinfo.J1l + 3; + if (joint[i]->node[1].body) { + Jinfo.J2l = J + nskip*ofs[i] + 6*joint[i]->node[1].body->tag; + Jinfo.J2a = Jinfo.J2l + 3; + } + else { + Jinfo.J2l = 0; + Jinfo.J2a = 0; + } + Jinfo.c = c + ofs[i]; + Jinfo.cfm = cfm + ofs[i]; + Jinfo.lo = lo + ofs[i]; + Jinfo.hi = hi + ofs[i]; + Jinfo.findex = findex + ofs[i]; + joint[i]->vtable->getInfo2 (joint[i],&Jinfo); + // adjust returned findex values for global index numbering + for (j=0; j= 0) findex[ofs[i] + j] += ofs[i]; + } + } + + // compute A = J*invM*J' +# ifdef TIMING + dTimerNow ("compute A"); +# endif + dReal *JinvM = (dReal*) ALLOCA (m*nskip*sizeof(dReal)); + dSetZero (JinvM,m*nskip); + dMultiply0 (JinvM,J,invM,m,n6,n6); + int mskip = dPAD(m); + dReal *A = (dReal*) ALLOCA (m*mskip*sizeof(dReal)); + dSetZero (A,m*mskip); + dMultiply2 (A,JinvM,J,m,n6,m); + + // add cfm to the diagonal of A + for (i=0; ilvel[j] = vnew[i*6+j]; + for (j=0; j<3; j++) body[i]->avel[j] = vnew[i*6+3+j]; + } + + // update the position and orientation from the new linear/angular velocity + // (over the given timestep) +# ifdef TIMING + dTimerNow ("update position"); +# endif + for (i=0; ifacc[0] = 0; + body[i]->facc[1] = 0; + body[i]->facc[2] = 0; + body[i]->facc[3] = 0; + body[i]->tacc[0] = 0; + body[i]->tacc[1] = 0; + body[i]->tacc[2] = 0; + body[i]->tacc[3] = 0; + } + +# ifdef TIMING + dTimerEnd(); + if (m > 0) dTimerReport (stdout,1); +# endif +} + +//**************************************************************************** +// an optimized version of dInternalStepIsland1() + +void dInternalStepIsland_x2 (dxWorld *world, dxBody * const *body, int nb, + dxJoint * const *_joint, int nj, dReal stepsize) +{ + int i,j,k; +# ifdef TIMING + dTimerStart("preprocessing"); +# endif + + dReal stepsize1 = dRecip(stepsize); + + // number all bodies in the body list - set their tag values + for (i=0; itag = i; + + // make a local copy of the joint array, because we might want to modify it. + // (the "dxJoint *const*" declaration says we're allowed to modify the joints + // but not the joint array, because the caller might need it unchanged). + dxJoint **joint = (dxJoint**) ALLOCA (nj * sizeof(dxJoint*)); + memcpy (joint,_joint,nj * sizeof(dxJoint*)); + + // for all bodies, compute the inertia tensor and its inverse in the global + // frame, and compute the rotational force and add it to the torque + // accumulator. I and invI are vertically stacked 3x4 matrices, one per body. + // @@@ check computation of rotational force. + dReal *I = (dReal*) ALLOCA (3*nb*4 * sizeof(dReal)); + dReal *invI = (dReal*) ALLOCA (3*nb*4 * sizeof(dReal)); + dSetZero (I,3*nb*4); + dSetZero (invI,3*nb*4); + for (i=0; imass.I,body[i]->R); + dMULTIPLY0_333 (I+i*12,body[i]->R,tmp); + // compute inverse inertia tensor in global frame + dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->R); + dMULTIPLY0_333 (invI+i*12,body[i]->R,tmp); + // compute rotational force + dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); + dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); + } + + // add the gravity force to all bodies + for (i=0; iflags & dxBodyNoGravity)==0) { + body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; + body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; + body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; + } + } + + // get m = total constraint dimension, nub = number of unbounded variables. + // create constraint offset array and number-of-rows array for all joints. + // the constraints are re-ordered as follows: the purely unbounded + // constraints, the mixed unbounded + LCP constraints, and last the purely + // LCP constraints. this assists the LCP solver to put all unbounded + // variables at the start for a quick factorization. + // + // joints with m=0 are inactive and are removed from the joints array + // entirely, so that the code that follows does not consider them. + // also number all active joints in the joint list (set their tag values). + // inactive joints receive a tag value of -1. + + int m = 0; + dxJoint::Info1 *info = (dxJoint::Info1*) ALLOCA (nj*sizeof(dxJoint::Info1)); + int *ofs = (int*) ALLOCA (nj*sizeof(int)); + for (i=0, j=0; jvtable->getInfo1 (joint[j],info+i); + dIASSERT (info[i].m >= 0 && info[i].m <= 6 && + info[i].nub >= 0 && info[i].nub <= info[i].m); + if (info[i].m > 0) { + joint[i] = joint[j]; + joint[i]->tag = i; + i++; + } + else { + joint[j]->tag = -1; + } + } + nj = i; + + // the purely unbounded constraints + for (i=0; i 0 && info[i].nub < info[i].m) { + ofs[i] = m; + m += info[i].m; + } + // the purely LCP constraints + for (i=0; i 0) { + // create a constraint equation right hand side vector `c', a constraint + // force mixing vector `cfm', and LCP low and high bound vectors, and an + // 'findex' vector. + dReal *c = (dReal*) ALLOCA (m*sizeof(dReal)); + dReal *cfm = (dReal*) ALLOCA (m*sizeof(dReal)); + dReal *lo = (dReal*) ALLOCA (m*sizeof(dReal)); + dReal *hi = (dReal*) ALLOCA (m*sizeof(dReal)); + int *findex = (int*) alloca (m*sizeof(int)); + dSetZero (c,m); + dSetValue (cfm,m,world->global_cfm); + dSetValue (lo,m,-dInfinity); + dSetValue (hi,m, dInfinity); + for (i=0; iglobal_erp; + for (i=0; ivtable->getInfo2 (joint[i],&Jinfo); + // adjust returned findex values for global index numbering + for (j=0; j= 0) findex[ofs[i] + j] += ofs[i]; + } + } + + // compute A = J*invM*J'. first compute JinvM = J*invM. this has the same + // format as J so we just go through the constraints in J multiplying by + // the appropriate scalars and matrices. +# ifdef TIMING + dTimerNow ("compute A"); +# endif + dReal *JinvM = (dReal*) ALLOCA (2*m*8*sizeof(dReal)); + dSetZero (JinvM,2*m*8); + for (i=0; inode[0].body->tag; + dReal body_invMass = body[b]->invMass; + dReal *body_invI = invI + b*12; + dReal *Jsrc = J + 2*8*ofs[i]; + dReal *Jdst = JinvM + 2*8*ofs[i]; + for (j=info[i].m-1; j>=0; j--) { + for (k=0; k<3; k++) Jdst[k] = Jsrc[k] * body_invMass; + dMULTIPLY0_133 (Jdst+4,Jsrc+4,body_invI); + Jsrc += 8; + Jdst += 8; + } + if (joint[i]->node[1].body) { + b = joint[i]->node[1].body->tag; + body_invMass = body[b]->invMass; + body_invI = invI + b*12; + for (j=info[i].m-1; j>=0; j--) { + for (k=0; k<3; k++) Jdst[k] = Jsrc[k] * body_invMass; + dMULTIPLY0_133 (Jdst+4,Jsrc+4,body_invI); + Jsrc += 8; + Jdst += 8; + } + } + } + + // now compute A = JinvM * J'. A's rows and columns are grouped by joint, + // i.e. in the same way as the rows of J. block (i,j) of A is only nonzero + // if joints i and j have at least one body in common. this fact suggests + // the algorithm used to fill A: + // + // for b = all bodies + // n = number of joints attached to body b + // for i = 1..n + // for j = i+1..n + // ii = actual joint number for i + // jj = actual joint number for j + // // (ii,jj) will be set to all pairs of joints around body b + // compute blockwise: A(ii,jj) += JinvM(ii) * J(jj)' + // + // this algorithm catches all pairs of joints that have at least one body + // in common. it does not compute the diagonal blocks of A however - + // another similar algorithm does that. + + int mskip = dPAD(m); + dReal *A = (dReal*) ALLOCA (m*mskip*sizeof(dReal)); + dSetZero (A,m*mskip); + for (i=0; ifirstjoint; n1; n1=n1->next) { + for (dxJointNode *n2=n1->next; n2; n2=n2->next) { + // get joint numbers and ensure ofs[j1] >= ofs[j2] + int j1 = n1->joint->tag; + int j2 = n2->joint->tag; + if (ofs[j1] < ofs[j2]) { + int tmp = j1; + j1 = j2; + j2 = tmp; + } + + // if either joint was tagged as -1 then it is an inactive (m=0) + // joint that should not be considered + if (j1==-1 || j2==-1) continue; + + // determine if body i is the 1st or 2nd body of joints j1 and j2 + int jb1 = (joint[j1]->node[1].body == body[i]); + int jb2 = (joint[j2]->node[1].body == body[i]); + // jb1/jb2 must be 0 for joints with only one body + dIASSERT(joint[j1]->node[1].body || jb1==0); + dIASSERT(joint[j2]->node[1].body || jb2==0); + + // set block of A + MultiplyAdd2_p8r (A + ofs[j1]*mskip + ofs[j2], + JinvM + 2*8*ofs[j1] + jb1*8*info[j1].m, + J + 2*8*ofs[j2] + jb2*8*info[j2].m, + info[j1].m,info[j2].m, mskip); + } + } + } + // compute diagonal blocks of A + for (i=0; inode[1].body) { + MultiplyAdd2_p8r (A + ofs[i]*(mskip+1), + JinvM + 2*8*ofs[i] + 8*info[i].m, + J + 2*8*ofs[i] + 8*info[i].m, + info[i].m,info[i].m, mskip); + } + } + + // add cfm to the diagonal of A + for (i=0; iinvMass; + dReal *body_invI = invI + i*12; + for (j=0; j<3; j++) tmp1[i*8+j] = body[i]->facc[j] * body_invMass + + body[i]->lvel[j] * stepsize1; + dMULTIPLY0_331 (tmp1 + i*8 + 4,body_invI,body[i]->tacc); + for (j=0; j<3; j++) tmp1[i*8+4+j] += body[i]->avel[j] * stepsize1; + } + // put J*tmp1 into rhs + dReal *rhs = (dReal*) ALLOCA (m * sizeof(dReal)); + dSetZero (rhs,m); + for (i=0; inode[0].body->tag, info[i].m); + if (joint[i]->node[1].body) { + MultiplyAdd0_p81 (rhs+ofs[i],JJ + 8*info[i].m, + tmp1 + 8*joint[i]->node[1].body->tag, info[i].m); + } + } + // complete rhs + for (i=0; inode[0].body; + dxBody* b2 = joint[i]->node[1].body; + dJointFeedback *fb = joint[i]->feedback; + + if (fb) { + // the user has requested feedback on the amount of force that this + // joint is applying to the bodies. we use a slightly slower + // computation that splits out the force components and puts them + // in the feedback structure. + dReal data1[8],data2[8]; + Multiply1_8q1 (data1, JJ, lambda+ofs[i], info[i].m); + dReal *cf1 = cforce + 8*b1->tag; + cf1[0] += (fb->f1[0] = data1[0]); + cf1[1] += (fb->f1[1] = data1[1]); + cf1[2] += (fb->f1[2] = data1[2]); + cf1[4] += (fb->t1[0] = data1[4]); + cf1[5] += (fb->t1[1] = data1[5]); + cf1[6] += (fb->t1[2] = data1[6]); + if (b2){ + Multiply1_8q1 (data2, JJ + 8*info[i].m, lambda+ofs[i], info[i].m); + dReal *cf2 = cforce + 8*b2->tag; + cf2[0] += (fb->f2[0] = data2[0]); + cf2[1] += (fb->f2[1] = data2[1]); + cf2[2] += (fb->f2[2] = data2[2]); + cf2[4] += (fb->t2[0] = data2[4]); + cf2[5] += (fb->t2[1] = data2[5]); + cf2[6] += (fb->t2[2] = data2[6]); + } + } + else { + // no feedback is required, let's compute cforce the faster way + MultiplyAdd1_8q1 (cforce + 8*b1->tag,JJ, lambda+ofs[i], info[i].m); + if (b2) { + MultiplyAdd1_8q1 (cforce + 8*b2->tag, + JJ + 8*info[i].m, lambda+ofs[i], info[i].m); + } + } + } + } + + // compute the velocity update +# ifdef TIMING + dTimerNow ("compute velocity update"); +# endif + + // add fe to cforce + for (i=0; ifacc[j]; + for (j=0; j<3; j++) cforce[i*8+4+j] += body[i]->tacc[j]; + } + // multiply cforce by stepsize + for (i=0; i < nb*8; i++) cforce[i] *= stepsize; + // add invM * cforce to the body velocity + for (i=0; iinvMass; + dReal *body_invI = invI + i*12; + for (j=0; j<3; j++) body[i]->lvel[j] += body_invMass * cforce[i*8+j]; + dMULTIPLYADD0_331 (body[i]->avel,body_invI,cforce+i*8+4); + } + + // update the position and orientation from the new linear/angular velocity + // (over the given timestep) +# ifdef TIMING + dTimerNow ("update position"); +# endif + for (i=0; ilvel[j]; + for (j=0; j<3; j++) tmp_vnew[i*6+3+j] = body[i]->avel[j]; + } + comparator.nextMatrix (tmp_vnew,nb*6,1,0,"vnew"); +# endif + +# ifdef TIMING + dTimerNow ("tidy up"); +# endif + + // zero all force accumulators + for (i=0; ifacc[0] = 0; + body[i]->facc[1] = 0; + body[i]->facc[2] = 0; + body[i]->facc[3] = 0; + body[i]->tacc[0] = 0; + body[i]->tacc[1] = 0; + body[i]->tacc[2] = 0; + body[i]->tacc[3] = 0; + } + +# ifdef TIMING + dTimerEnd(); + if (m > 0) dTimerReport (stdout,1); +# endif +} + +//**************************************************************************** + +void dInternalStepIsland (dxWorld *world, dxBody * const *body, int nb, + dxJoint * const *joint, int nj, dReal stepsize) +{ +# ifndef COMPARE_METHODS + dInternalStepIsland_x2 (world,body,nb,joint,nj,stepsize); +# endif + +# ifdef COMPARE_METHODS + int i; + + // save body state + dxBody *state = (dxBody*) ALLOCA (nb*sizeof(dxBody)); + for (i=0; i + + +void dInternalStepIsland (dxWorld *world, + dxBody * const *body, int nb, + dxJoint * const *joint, int nj, + dReal stepsize); + + + +#endif + diff --git a/extern/ode/dist/ode/src/testing.cpp b/extern/ode/dist/ode/src/testing.cpp new file mode 100644 index 00000000000..d55afc25257 --- /dev/null +++ b/extern/ode/dist/ode/src/testing.cpp @@ -0,0 +1,243 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include +#include +#include +#include "testing.h" + +#ifdef dDOUBLE +static const dReal tol = 1.0e-9; +#else +static const dReal tol = 1.0e-5f; +#endif + + +// matrix header on the stack + +struct dMatrixComparison::dMatInfo { + int n,m; // size of matrix + char name[128]; // name of the matrix + dReal *data; // matrix data + int size; // size of `data' +}; + + + +dMatrixComparison::dMatrixComparison() +{ + afterfirst = 0; + index = 0; +} + + +dMatrixComparison::~dMatrixComparison() +{ + reset(); +} + + +dReal dMatrixComparison::nextMatrix (dReal *A, int n, int m, int lower_tri, + char *name, ...) +{ + if (A==0 || n < 1 || m < 1 || name==0) dDebug (0,"bad args to nextMatrix"); + int num = n*dPAD(m); + + if (afterfirst==0) { + dMatInfo *mi = (dMatInfo*) dAlloc (sizeof(dMatInfo)); + mi->n = n; + mi->m = m; + mi->size = num * sizeof(dReal); + mi->data = (dReal*) dAlloc (mi->size); + memcpy (mi->data,A,mi->size); + + va_list ap; + va_start (ap,name); + vsprintf (mi->name,name,ap); + if (strlen(mi->name) >= sizeof (mi->name)) dDebug (0,"name too long"); + + mat.push (mi); + return 0; + } + else { + if (lower_tri && n != m) + dDebug (0,"dMatrixComparison, lower triangular matrix must be square"); + if (index >= mat.size()) dDebug (0,"dMatrixComparison, too many matrices"); + dMatInfo *mp = mat[index]; + index++; + + dMatInfo mi; + va_list ap; + va_start (ap,name); + vsprintf (mi.name,name,ap); + if (strlen(mi.name) >= sizeof (mi.name)) dDebug (0,"name too long"); + + if (strcmp(mp->name,mi.name) != 0) + dDebug (0,"dMatrixComparison, name mismatch (\"%s\" and \"%s\")", + mp->name,mi.name); + if (mp->n != n || mp->m != m) + dDebug (0,"dMatrixComparison, size mismatch (%dx%d and %dx%d)", + mp->n,mp->m,n,m); + + dReal maxdiff; + if (lower_tri) { + maxdiff = dMaxDifferenceLowerTriangle (A,mp->data,n); + } + else { + maxdiff = dMaxDifference (A,mp->data,n,m); + } + if (maxdiff > tol) + dDebug (0,"dMatrixComparison, matrix error (size=%dx%d, name=\"%s\", " + "error=%.4e)",n,m,mi.name,maxdiff); + return maxdiff; + } +} + + +void dMatrixComparison::end() +{ + if (mat.size() <= 0) dDebug (0,"no matrices in sequence"); + afterfirst = 1; + index = 0; +} + + +void dMatrixComparison::reset() +{ + for (int i=0; idata,mat[i]->size); + dFree (mat[i],sizeof(dMatInfo)); + } + mat.setSize (0); + afterfirst = 0; + index = 0; +} + + +void dMatrixComparison::dump() +{ + for (int i=0; iname,mat[i]->n,mat[i]->m); +} + +//**************************************************************************** +// unit test + +#include + +static jmp_buf jump_buffer; + +static void myDebug (int num, const char *msg, va_list ap) +{ + // printf ("(Error %d: ",num); + // vprintf (msg,ap); + // printf (")\n"); + longjmp (jump_buffer,1); +} + + +extern "C" void dTestMatrixComparison() +{ + volatile int i; + printf ("dTestMatrixComparison()\n"); + dMessageFunction *orig_debug = dGetDebugHandler(); + + dMatrixComparison mc; + dReal A[50*50]; + + // make first sequence + unsigned long seed = dRandGetSeed(); + for (i=1; i<49; i++) { + dMakeRandomMatrix (A,i,i+1,1.0); + mc.nextMatrix (A,i,i+1,0,"A%d",i); + } + mc.end(); + + //mc.dump(); + + // test identical sequence + dSetDebugHandler (&myDebug); + dRandSetSeed (seed); + if (setjmp (jump_buffer)) { + printf ("\tFAILED (1)\n"); + } + else { + for (i=1; i<49; i++) { + dMakeRandomMatrix (A,i,i+1,1.0); + mc.nextMatrix (A,i,i+1,0,"A%d",i); + } + mc.end(); + printf ("\tpassed (1)\n"); + } + dSetDebugHandler (orig_debug); + + // test broken sequences (with matrix error) + dRandSetSeed (seed); + volatile int passcount = 0; + for (i=1; i<49; i++) { + if (setjmp (jump_buffer)) { + passcount++; + } + else { + dSetDebugHandler (&myDebug); + dMakeRandomMatrix (A,i,i+1,1.0); + A[(i-1)*dPAD(i+1)+i] += REAL(0.01); + mc.nextMatrix (A,i,i+1,0,"A%d",i); + dSetDebugHandler (orig_debug); + } + } + mc.end(); + printf ("\t%s (2)\n",(passcount == 48) ? "passed" : "FAILED"); + + // test broken sequences (with name error) + dRandSetSeed (seed); + passcount = 0; + for (i=1; i<49; i++) { + if (setjmp (jump_buffer)) { + passcount++; + } + else { + dSetDebugHandler (&myDebug); + dMakeRandomMatrix (A,i,i+1,1.0); + mc.nextMatrix (A,i,i+1,0,"B%d",i); + dSetDebugHandler (orig_debug); + } + } + mc.end(); + printf ("\t%s (3)\n",(passcount == 48) ? "passed" : "FAILED"); + + // test identical sequence again + dSetDebugHandler (&myDebug); + dRandSetSeed (seed); + if (setjmp (jump_buffer)) { + printf ("\tFAILED (4)\n"); + } + else { + for (i=1; i<49; i++) { + dMakeRandomMatrix (A,i,i+1,1.0); + mc.nextMatrix (A,i,i+1,0,"A%d",i); + } + mc.end(); + printf ("\tpassed (4)\n"); + } + dSetDebugHandler (orig_debug); +} diff --git a/extern/ode/dist/ode/src/testing.h b/extern/ode/dist/ode/src/testing.h new file mode 100644 index 00000000000..aa4acf119db --- /dev/null +++ b/extern/ode/dist/ode/src/testing.h @@ -0,0 +1,66 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* stuff used for testing */ + +#ifndef _ODE_TESTING_H_ +#define _ODE_TESTING_H_ + +#include +#include "array.h" + + +// compare a sequence of named matrices/vectors, i.e. to make sure that two +// different pieces of code are giving the same results. + +class dMatrixComparison { + struct dMatInfo; + dArray mat; + int afterfirst,index; + +public: + dMatrixComparison(); + ~dMatrixComparison(); + + dReal nextMatrix (dReal *A, int n, int m, int lower_tri, char *name, ...); + // add a new n*m matrix A to the sequence. the name of the matrix is given + // by the printf-style arguments (name,...). if this is the first sequence + // then this object will simply record the matrices and return 0. + // if this the second or subsequent sequence then this object will compare + // the matrices with the first sequence, and report any differences. + // the matrix error will be returned. if `lower_tri' is 1 then only the + // lower triangle of the matrix (including the diagonal) will be compared + // (the matrix must be square). + + void end(); + // end a sequence. + + void reset(); + // restarts the object, so the next sequence will be the first sequence. + + void dump(); + // print out info about all the matrices in the sequence +}; + + +#endif + diff --git a/extern/ode/dist/ode/src/timer.cpp b/extern/ode/dist/ode/src/timer.cpp new file mode 100644 index 00000000000..87cb9f6f2fe --- /dev/null +++ b/extern/ode/dist/ode/src/timer.cpp @@ -0,0 +1,397 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +TODO +---- + +* gettimeofday() and the pentium time stamp counter return the real time, + not the process time. fix this somehow! + +*/ + +#include +#include + +// misc defines +#define ALLOCA dALLOCA16 + +//**************************************************************************** +// implementation for windows based on the multimedia performance counter. + +#ifdef WIN32 + +#include "windows.h" + +static inline void getClockCount (unsigned long cc[2]) +{ + LARGE_INTEGER a; + QueryPerformanceCounter (&a); + cc[0] = a.LowPart; + cc[1] = a.HighPart; +} + + +static inline void serialize() +{ +} + + +static inline double loadClockCount (unsigned long cc[2]) +{ + LARGE_INTEGER a; + a.LowPart = cc[0]; + a.HighPart = cc[1]; + return double(a.QuadPart); +} + + +double dTimerResolution() +{ + return 1.0/dTimerTicksPerSecond(); +} + + +double dTimerTicksPerSecond() +{ + static int query=0; + static double hz=0.0; + if (!query) { + LARGE_INTEGER a; + QueryPerformanceFrequency (&a); + hz = double(a.QuadPart); + query = 1; + } + return hz; +} + +#endif + +//**************************************************************************** +// implementation based on the pentium time stamp counter. the timer functions +// can be serializing or non-serializing. serializing will ensure that all +// instructions have executed and data has been written back before the cpu +// time stamp counter is read. the CPUID instruction is used to serialize. + +#if defined(PENTIUM) && !defined(WIN32) + +// we need to know the clock rate so that the timing function can report +// accurate times. this number only needs to be set accurately if we're +// doing performance tests and care about real-world time numbers - otherwise, +// just ignore this. i have not worked out how to determine this number +// automatically yet. + +#define PENTIUM_HZ (500e6) + + +static inline void getClockCount (unsigned long cc[2]) +{ + asm volatile ("\n\ + rdtsc\n\ + movl %%eax,(%%esi)\n\ + movl %%edx,4(%%esi)" + : : "S" (cc) : "%eax","%edx","cc","memory"); +} + + +static inline void serialize() +{ + asm volatile ("\n\ + mov $0,%%eax\n\ + cpuid" + : : : "%eax","%ebx","%ecx","%edx","cc","memory"); +} + + +static inline double loadClockCount (unsigned long a[2]) +{ + double ret; + asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) : + "cc","memory"); + return ret; +} + + +double dTimerResolution() +{ + return 1.0/PENTIUM_HZ; +} + + +double dTimerTicksPerSecond() +{ + return PENTIUM_HZ; +} + +#endif + +//**************************************************************************** +// otherwise, do the implementation based on gettimeofday(). + +#if !defined(PENTIUM) && !defined(WIN32) + +#ifndef macintosh + +#include +#include + + +static inline void getClockCount (unsigned long cc[2]) +{ + struct timeval tv; + gettimeofday (&tv,0); + cc[0] = tv.tv_usec; + cc[1] = tv.tv_sec; +} + +#else // macintosh + +#include +#include + +static inline void getClockCount (unsigned long cc[2]) +{ + UnsignedWide ms; + Microseconds (&ms); + cc[1] = ms.lo / 1000000; + cc[0] = ms.lo - ( cc[1] * 1000000 ); +} + +#endif + + +static inline void serialize() +{ +} + + +static inline double loadClockCount (unsigned long a[2]) +{ + return a[1]*1.0e6 + a[0]; +} + + +double dTimerResolution() +{ + unsigned long cc1[2],cc2[2]; + getClockCount (cc1); + do { + getClockCount (cc2); + } + while (cc1[0]==cc2[0] && cc1[1]==cc2[1]); + do { + getClockCount (cc1); + } + while (cc1[0]==cc2[0] && cc1[1]==cc2[1]); + double t1 = loadClockCount (cc1); + double t2 = loadClockCount (cc2); + return (t1-t2) / dTimerTicksPerSecond(); +} + + +double dTimerTicksPerSecond() +{ + return 1000000; +} + +#endif + +//**************************************************************************** +// stop watches + +void dStopwatchReset (dStopwatch *s) +{ + s->time = 0; + s->cc[0] = 0; + s->cc[1] = 0; +} + + +void dStopwatchStart (dStopwatch *s) +{ + serialize(); + getClockCount (s->cc); +} + + +void dStopwatchStop (dStopwatch *s) +{ + unsigned long cc[2]; + serialize(); + getClockCount (cc); + double t1 = loadClockCount (s->cc); + double t2 = loadClockCount (cc); + s->time += t2-t1; +} + + +double dStopwatchTime (dStopwatch *s) +{ + return s->time / dTimerTicksPerSecond(); +} + +//**************************************************************************** +// code timers + +// maximum number of events to record +#define MAXNUM 100 + +static int num = 0; // number of entries used in event array +static struct { + unsigned long cc[2]; // clock counts + double total_t; // total clocks used in this slot. + double total_p; // total percentage points used in this slot. + int count; // number of times this slot has been updated. + char *description; // pointer to static string +} event[MAXNUM]; + + +// make sure all slot totals and counts reset to 0 at start + +static void initSlots() +{ + static int initialized=0; + if (!initialized) { + for (int i=0; i (description); + num = 1; + serialize(); + getClockCount (event[0].cc); +} + + +void dTimerNow (const char *description) +{ + if (num < MAXNUM) { + // do not serialize + getClockCount (event[num].cc); + event[num].description = const_cast (description); + num++; + } +} + + +void dTimerEnd() +{ + if (num < MAXNUM) { + serialize(); + getClockCount (event[num].cc); + event[num].description = "TOTAL"; + num++; + } +} + +//**************************************************************************** +// print report + +static void fprintDoubleWithPrefix (FILE *f, double a, char *fmt) +{ + if (a >= 0.999999) { + fprintf (f,fmt,a); + return; + } + a *= 1000.0; + if (a >= 0.999999) { + fprintf (f,fmt,a); + fprintf (f,"m"); + return; + } + a *= 1000.0; + if (a >= 0.999999) { + fprintf (f,fmt,a); + fprintf (f,"u"); + return; + } + a *= 1000.0; + fprintf (f,fmt,a); + fprintf (f,"n"); +} + + +void dTimerReport (FILE *fout, int average) +{ + int i,maxl; + double ccunit = 1.0/dTimerTicksPerSecond(); + fprintf (fout,"\nTimer Report ("); + fprintDoubleWithPrefix (fout,ccunit,"%.2f "); + fprintf (fout,"s resolution)\n------------\n"); + if (num < 1) return; + + // get maximum description length + maxl = 0; + for (i=0; i maxl) maxl = l; + } + + // calculate total time + double t1 = loadClockCount (event[0].cc); + double t2 = loadClockCount (event[num-1].cc); + double total = t2 - t1; + if (total <= 0) total = 1; + + // compute time difference for all slots except the last one. update totals + double *times = (double*) ALLOCA (num * sizeof(double)); + for (i=0; i < (num-1); i++) { + double t1 = loadClockCount (event[i].cc); + double t2 = loadClockCount (event[i+1].cc); + times[i] = t2 - t1; + event[i].count++; + event[i].total_t += times[i]; + event[i].total_p += times[i]/total * 100.0; + } + + // print report (with optional averages) + for (i=0; i> BUILD_LOG +cat < $SETTINGS +PLATFORM=$PLATFORM +PRECISION=$PRECISION +BUILD=$MODE +END +make clean +make >> BUILD_LOG 2>&1 +echo -e "\n\n---------------------------------------------\n\n" >> BUILD_LOG +} + +echo > BUILD_LOG + +PRECISION=SINGLE +MODE=debug +build +PRECISION=SINGLE +MODE=release +build +PRECISION=DOUBLE +MODE=debug +build +PRECISION=DOUBLE +MODE=release +build + +make clean +rm -f $SETTINGS diff --git a/extern/ode/dist/tools/build4.bat b/extern/ode/dist/tools/build4.bat new file mode 100755 index 00000000000..c87e9a9e2ba --- /dev/null +++ b/extern/ode/dist/tools/build4.bat @@ -0,0 +1,43 @@ +@echo off +rem build all four precision/release configurations and log the build messages +rem (used for debugging). + +setlocal + +set PLATFORM=cygwin +set SETTINGS=config\user-settings + +echo SINGLE debug > BUILD_LOG +echo PLATFORM=%PLATFORM%> %SETTINGS% +echo PRECISION=SINGLE>> %SETTINGS% +echo BUILD=debug>> %SETTINGS% +make clean +make >> BUILD_LOG +echo --------------------------------------------- >> BUILD_LOG + +echo DOUBLE debug >> BUILD_LOG +echo PLATFORM=%PLATFORM%> %SETTINGS% +echo PRECISION=DOUBLE>> %SETTINGS% +echo BUILD=debug>> %SETTINGS% +make clean +make >> BUILD_LOG +echo --------------------------------------------- >> BUILD_LOG + +echo SINGLE release >> BUILD_LOG +echo PLATFORM=%PLATFORM%> %SETTINGS% +echo PRECISION=SINGLE>> %SETTINGS% +echo BUILD=release>> %SETTINGS% +make clean +make >> BUILD_LOG +echo --------------------------------------------- >> BUILD_LOG + +echo DOUBLE release >> BUILD_LOG +echo PLATFORM=%PLATFORM%> %SETTINGS% +echo PRECISION=DOUBLE>> %SETTINGS% +echo BUILD=release>> %SETTINGS% +make clean +make >> BUILD_LOG +echo --------------------------------------------- >> BUILD_LOG + +make clean +del %SETTINGS% diff --git a/extern/ode/dist/tools/make_distribution b/extern/ode/dist/tools/make_distribution new file mode 100755 index 00000000000..ed6d52bcbfd --- /dev/null +++ b/extern/ode/dist/tools/make_distribution @@ -0,0 +1,45 @@ +#!/bin/sh + +VER=0.03 +# VER=`date +%y%m%d` + +if [ ! -f ode/src/ode.cpp ]; then + echo "run this from the ODE root directory" + exit 1 +fi + +ODE_DIR=`pwd` + +cd /tmp +if [ -d /tmp/ode-$VER ]; then + echo "remove /tmp/ode-$VER first" + exit 1 +fi + +mkdir /tmp/ode-$VER +cp -av $ODE_DIR/* /tmp/ode-$VER +find /tmp/ode-$VER -type d -name CVS -exec rm -rf {} \; -print +find /tmp/ode-$VER -type f -name *~ -exec rm -f {} \; -print +rmdir /tmp/ode-$VER/build + +cd /tmp/ode-$VER +make clean +cp config/user-settings.example config/user-settings + +cd ode/doc +./doccer ode.doc > ode.html + +cd /tmp/ode-$VER +echo -e "\n\nMake any modifications you want, then exit the shell:" +bash + +cd /tmp +tar cfvz ode-$VER.tgz ode-$VER +rm -rf /tmp/ode-$VER + +echo -e "\ntype to exit or 'c' to copy to q12" +read Q +if [ $Q ]; then + echo copying... + scp1 ode-$VER.tgz q12.org:~/q12/ode/release/ +fi diff --git a/extern/ode/dist/tools/process_deps b/extern/ode/dist/tools/process_deps new file mode 100755 index 00000000000..9b95ddac382 --- /dev/null +++ b/extern/ode/dist/tools/process_deps @@ -0,0 +1,11 @@ +#!/usr/bin/perl + +$a = join ('',); +$a =~ s/\\\n/ /g; # join continued lines +$a =~ s/(^\S+:)/$ARGV[0]$1/gm; # put prefix in front of rules +$a =~ s/\s+\/\S+/ /g; # remove absolute path dependencies +$a =~ s/\s+\n/\n/g; # remove whitespace at end of lines +$a =~ s/[ \t]+/ /g; # clean up interior whitespace +$a =~ s/ / \\\n /g; # put back line continuations + +print $a; diff --git a/extern/ode/patchfile.FreeBSD b/extern/ode/patchfile.FreeBSD new file mode 100644 index 00000000000..1725a3acc45 --- /dev/null +++ b/extern/ode/patchfile.FreeBSD @@ -0,0 +1,22 @@ +--- dist/Makefile.org Sat Jan 11 23:55:46 2003 ++++ dist/Makefile Sat Jan 11 23:55:36 2003 +@@ -242,14 +242,16 @@ + clean: + -$(DEL_CMD) $(ODE_OBJECTS) $(ODE_TEST_EXE) $(ODE_LIB) $(DRAWSTUFF_OBJECTS) $(DRAWSTUFF_TEST_EXE) $(DRAWSTUFF_LIB) ode/test/*$(OBJ) drawstuff/dstest/*$(OBJ) $(CONFIGURATOR_EXE) $(CONFIG_H) + ++# Patched for FreeBSD ++ + %$(OBJ): %.c +- $(CC) $(C_FLAGS) $(C_INC)$(INCPATH) $(DEFINES) $(C_OPT)1 $(C_OUT)$@ $< ++ $(CC) $(C_FLAGS) $(C_INC)$(INCPATH) -I/usr/X11R6/include $(DEFINES) $(C_OPT)1 $(C_OUT)$@ $< + + %$(OBJ): %.cpp +- $(CC) $(C_FLAGS) $(C_INC)$(INCPATH) $(DEFINES) $(C_OPT)$(OPT) $(C_OUT)$@ $< ++ $(CC) $(C_FLAGS) $(C_INC)$(INCPATH) -I/usr/X11R6/include $(DEFINES) $(C_OPT)$(OPT) $(C_OUT)$@ $< + + %.exe: %$(OBJ) +- $(CC) $(C_EXEOUT)$@ $< $(ODE_LIB) $(DRAWSTUFF_LIB) $(RESOURCE_FILE) $(LINK_OPENGL) $(LINK_MATH) ++ $(CC) $(C_EXEOUT)$@ $< $(ODE_LIB) $(DRAWSTUFF_LIB) $(RESOURCE_FILE) $(LINK_OPENGL) $(LINK_MATH) -lXext + + # windows specific rules + diff --git a/extern/qhull/CMakeLists.txt b/extern/qhull/CMakeLists.txt new file mode 100644 index 00000000000..2da72acbb44 --- /dev/null +++ b/extern/qhull/CMakeLists.txt @@ -0,0 +1,48 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC include src) + +SET(SRC + src/geom.c + src/geom2.c + src/global.c + src/io.c + src/mem.c + src/merge.c + src/poly.c + src/poly2.c + src/qhull.c + src/qset.c + src/stat.c + src/user.c +) + +BLENDERLIB(extern_qhull "${SRC}" "${INC}") +#, libtype=['game2','player'], priority=[50, 85] diff --git a/extern/qhull/COPYING.txt b/extern/qhull/COPYING.txt new file mode 100644 index 00000000000..1334eba6d0b --- /dev/null +++ b/extern/qhull/COPYING.txt @@ -0,0 +1,37 @@ + Qhull, Copyright (c) 1993-2002 + + The National Science and Technology Research Center for + Computation and Visualization of Geometric Structures + (The Geometry Center) + University of Minnesota + 400 Lind Hall + 207 Church Street S.E. + Minneapolis, MN 55455 USA + + email: qhull@geom.umn.edu + +This software includes Qhull from The Geometry Center. Qhull is +copyrighted as noted above. Qhull is free software and may be obtained +via http from www.geom.umn.edu. It may be freely copied, modified, +and redistributed under the following conditions: + +1. All copyright notices must remain intact in all files. + +2. A copy of this text file must be distributed along with any copies + of Qhull that you redistribute; this includes copies that you have + modified, or copies of programs or other software products that + include Qhull. + +3. If you modify Qhull, you must include a notice giving the + name of the person performing the modification, the date of + modification, and the reason for such modification. + +4. When distributing modified versions of Qhull, or other software + products that include Qhull, you must provide notice that the original + source code may be obtained as noted above. + +5. There is no warranty or other guarantee of fitness for Qhull, it is + provided solely "as is". Bug reports or fixes may be sent to + qhull_bug@geom.umn.edu; the authors may or may not act on them as + they desire. + diff --git a/extern/qhull/README.txt b/extern/qhull/README.txt new file mode 100644 index 00000000000..9ef958a1f47 --- /dev/null +++ b/extern/qhull/README.txt @@ -0,0 +1,318 @@ +Name + + qhull, rbox 2002.1 August 20, 2002 + +Convex hull, Delaunay triangulation, Voronoi diagrams, Halfspace intersection + + Documentation: + html/index.htm + + Available from: + + + + + Version 1 (simplicial only): + + + + News and a paper: + + + +Purpose + + Qhull is a general dimension convex hull program that reads a set + of points from stdin, and outputs the smallest convex set that contains + the points to stdout. It also generates Delaunay triangulations, Voronoi + diagrams, furthest-site Voronoi diagrams, and halfspace intersections + about a point. + + Rbox is a useful tool in generating input for Qhull; it generates + hypercubes, diamonds, cones, circles, simplices, spirals, + lattices, and random points. + + Qhull produces graphical output for Geomview. This helps with + understanding the output. + + +Environment requirements + + Qhull and rbox should run on all 32-bit and 64-bit computers. Use + an ANSI C or C++ compiler to compile the program. The software is + self-contained. + + Qhull is copyrighted software. Please read COPYING.txt and REGISTER.txt + before using or distributing Qhull. + +To contribute to Qhull + + Qhull is on Savannah, http://savannah.gnu.org/projects/qhull/ + +Qhull on Windows 95, 98, ME, NT, 2000, XP + + The zip file contains rbox.exe, qhull.exe, qconvex.exe, qdelaunay.exe, + qhalf.exe, qvoronoi.exe, documentation files, and source files. + + To install Qhull: + - Unzip the files into a directory. You may use WinZip32 + - Open a DOS window for the directory. + - In Windows 95, the DOS window needs improvement. + - Double-click on qhull\eg\qhull-go.bat to call doskey (arrow keys). + - Increase the size of the screen font to 8x12. + - If the text is too dim, fix the screen colors with shareware (e.g., crt.exe) + - If you use qhull a lot, consider using the Cygwin Unix shell, + Cygwin tools (http://sources.redhat.com/cygwin/) + - Execute 'qconvex' for a synopsis and examples. + - Execute 'rbox 10 | qconvex' to compute the convex hull of 10 random points. + - Execute 'rbox 10 | qconvex i TO file' to write results to 'file'. + - If an error occurs, Windows 95 sends the error to stdout instead of stderr + - use 'TO xxx' to send normal output to xxx and error output to stdout + - Browse the documentation: qhull\html\index.htm + +Compiling for Unix + + The gzip file, qhull.tgz, contains documentation and source files for + qhull and rbox. + + To unpack the gzip file + - tar zxf qhull.tgz + - cd qhull + + Compiling with the Debian Make:[R. Laboissiere] + - cd src + - ./Make-config.sh + - cd .. + - configure + - make + + Compiling with Makefile (i.e., Makefile.txt) + - cd src + - in Makefile, check the CC, CCOPTS1, PRINTMAN, and PRINTC defines + - the defaults are gcc and enscript + - CCOPTS1 should include the ANSI flag. It defines __STDC__ + - in user.h, check the definitions of qh_SECticks and qh_CPUclock. + - use '#define qh_CLOCKtype 2' for timing runs longer than 1 hour + - type: make + - this builds: qhull qconvex qdelaunay qhalf qvoronoi rbox libqhull.a + - type: make doc + - this prints the man page + - See also qhull/html/index.htm + - if your compiler reports many errors, it is probably not a ANSI C compiler + - you will need to set the -ansi switch or find another compiler + - if your compiler warns about missing prototypes for fprintf() etc. + - this is ok, your compiler should have these in stdio.h + - if your compiler warns about missing prototypes for memset() etc. + - include memory.h in qhull_a.h + - if your compiler is gcc-2.95.1, you need to set flag -fno-strict-aliasing. + - This flag is set by default for other versions [Karas, Krishnaswami] + - if your compiler reports "global.c: storage size of 'qh_qh' isn't known" + - delete the initializer "={0}" in global.c, stat.c and mem.c + - if your compiler warns about "stat.c: improper initializer" + - this is ok, the initializer is not used + - if you have trouble building libqhull.a with 'ar' + - try 'make -f Makefile.txt qhullx' + - if the code compiles, the qhull test case will automatically execute + - if an error occurs, there's an incompatibility between machines + - For gcc-2.95.1, you need to set flag -fno-strict-aliasing. + It is set by default for other versions of gcc [Karas, Krishnaswami] + - If you can, try a different compiler + - You can turn off the Qhull memory manager with qh_NOmem in mem.h + - You can turn off compiler optimization (-O2 in Makefile) + - If you find the source of the problem, please let us know + - if you have Geomview (www.geomview.org) + - try 'rbox 100 | qconvex G >a' and load 'a' into Geomview + - run 'q_eg' for Geomview examples of Qhull output (see qh-eg.htm) + - to install the programs and their man pages: + - define MANDIR and BINDIR + - type 'make install' + +Compiling for Windows NT, 2000, XP with cygwin (www.cygwin.com) + + - install cygwin with gcc, make, ar, and ln + - cd qhull/src + - make -f Makefile.txt + +Compiling for Windows 95, 98, NT, 2000, XP + + Qhull compiles as a console application in Visual C++ 5.0 at warning + level 3. + + Visual C++ quickstart for qhull.exe: + - create a "Win32 console application" called "qhull" + - add the following files: + geom.c geom2.c global.c io.c mem.c merge.c poly.c poly2.c qhull.c + qset.c stat.c unix.c user.c + - create a "Win32 console application" called "rbox" + - add rbox.c + + Visual C++ quickstart for qhull library, qconvex.exe, etc. + - To simplify setting up lots of projects, + - create a temporary "Win32 console application" called "source" + - add all .c files from .../src/... + - In Tools::Options::Tab + Set tab size to 8 and indent size to 2 + + - create a "Win32 console application" called "rbox" + - move rbox.c from "qhull source" + - for Project:Settings..., Link + you only need the default libraries + - build the project + + - create a "Win32 static library" called "library" + - move these files from "qhull source" + geom.c geom2.c global.c io.c mem.c merge.c poly.c poly2.c qhull.c + qset.c stat.c user.c + - set the library file (use the same for debug and release) + - build the project + + - create a "Win32 console application" called "qhull" + - move unix.c from "qhull source" + - Set the library file in Project:Settings..., Link + - Qhull does not use other libraries + + - create a "Win32 console application" called "qconvex" + - move qconvex.c from "qhull source" + - Set the library file in Project:Settings..., Link + + - do the same for qdelaun.c, qhalf, qvoronoi.c, user_eg.c, user_eg2.c + - delete "qhull sources" since it is no longer needed + - Set the library file in Project:Settings..., Link + - use Project:Settings to make any changes + - use batch build to rebuild everything + + Qhull compiles with Borland C++ 5.0 bcc32. A Makefile is included. + Execute 'make -f MBorland'. If you use the Borland IDE, set the ANSI + option in Options:Project:Compiler:Source:Language-compliance. + + Qhull compiles with Borland C++ 4.02 for Win32 and DOS Power Pack. + Use 'make -f MBorland -D_DPMI'. Qhull 1.0 compiles with Borland + C++ 4.02. For rbox 1.0, use "bcc32 -WX -w- -O2-e -erbox -lc rbox.c". + Use the same options for Qhull 1.0. [D. Zwick] + + Qhull compiles with Metrowerks C++ 1.7 with the ANSI option. + + If you turn on full warnings, the compiler will report a number of + unused variables, variables set but not used, and dead code. These are + intentional. For example, variables may be initialized (unnecessarily) + to prevent warnings about possible use of uninitialized variables. + +Compiling for the Power Macintosh + + Qhull compiles for the Power Macintosh with Metrowerk's C compiler. + It uses the SIOUX interface to read point coordinates and return output. + There is no graphical output. For project files, see 'Compiling for + Windows 95'. Instead of using SIOUX, Qhull may be embedded within an + application. + + Version 1 is available for Macintosh computers by download of qhull.sit.hqx + It reads point coordinates from a standard file and returns output + to a standard file. There is no graphical output. + + +Compiling for other machines + + Some users have reported problems with compiling Qhull under Irix 5.1. It + compiles under other versions of Irix. + + If you have troubles with the memory manager, you can turn it off by + defining qh_NOmem in mem.h. + + You may compile Qhull with a C++ compiler. + + +Distributed files + + README.txt // instructions for installing Qhull + REGISTER.txt // Qhull registration + COPYING.txt // copyright notice + Announce.txt // announcement + Changes.txt // change history for Qhull and rbox + qh-faq.htm // Frequently asked questions + qh-home.htm // Home page + qh-get.htm // Download page + html/index.htm // Manual + Makefile.txt // Makefile for Unix or cygwin 'make' + MBorland // Makefile for Borland C++/Win32 + Make-config.sh // Create Debian configure and automake + +src/ + rbox consists of: + rbox.exe // Win32 executable (.zip only) + rbox.htm // html manual + rbox.man // Unix man page + rbox.txt + rbox.c // source program + + qhull consists of: + qhull.exe // Win32 executables (.zip only) + qconvex.exe + qdelaunay.exe + qhalf.exe + qvoronoi.exe + qhull-go.bat // DOS window + qconvex.htm // html manuals + qdelaun.htm + qdelau_f.htm + qhalf.htm + qvoronoi.htm + qvoron_f.htm + qh-eg.htm + qh-impre.htm + qh-in.htm + index.htm + qh-opt*.htm + qh-quick.htm + qh--4d.gif,etc. // images for manual + qhull.man // Unix man page + qhull.txt + q_eg // shell script for Geomview examples + q_egtest // shell script for Geomview test examples + q_test // shell script to test qhull + + top-level source files: + src/index.htm // index to source files + qh-...htm // specific files + user.h // header file of user definable constants + qhull.h // header file for qhull + unix.c // Unix front end to qhull + qhull.c // Quickhull algorithm with partitioning + user.c // user re-definable functions + user_eg.c // example of incorporating qhull into a user program + user_eg2.c // more complex example + qhull_interface.cpp // call Qhull from C++ + + other source files: + qhull_a.h // include file for *.c + geom.c // geometric routines + geom2.c + geom.h + global.c // global variables + io.c // input-output routines + io.h + mem.c // memory routines, this is stand-alone code + mem.h + merge.c // merging of non-convex facets + merge.h + poly.c // polyhedron routines + poly2.c + poly.h + qset.c // set routines, this only depends on mem.c + qset.h + stat.c // statistics + stat.h + +Authors: + + C. Bradford Barber Hannu Huhdanpaa + bradb@geom.umn.edu hannu@geom.umn.edu + + c/o The Geometry Center + University of Minnesota + 400 Lind Hall + 207 Church Street S.E. + Minneapolis, MN 55455 + + This software was developed under NSF grants NSF/DMS-8920161 and + NSF-CCR-91-15793 750-7504 at the Geometry Center and Harvard + University. If you find Qhull useful, please let us know. diff --git a/extern/qhull/REGISTER.txt b/extern/qhull/REGISTER.txt new file mode 100644 index 00000000000..767eb1c0cda --- /dev/null +++ b/extern/qhull/REGISTER.txt @@ -0,0 +1,37 @@ +Dear User of Geometry Center Software: + +We would like to find out how you are using our software. Think of +Geometry Center software as a new kind of shareware: you share your +science and successes with us, and we share our software and support +with you. + +If you use Geometry Center software, please send us a note telling +us what you are doing with it. + +We need to know: + + (1) What you are working on - an abstract of your work would be + fine. + + (2) What Geometry Center software you use. + + (3) How that software has helped you, for example, by increasing + your productivity or allowing you to do things you could not do + before. In particular, if you feel that Geometry Center + software has had a direct bearing on your work, please tell us + about this. + +We encourage you to cite the use of any Geometry Center software you +have used in your publications. + +To cite Qhull, use + + Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull + algorithm for convex hulls," ACM Trans. on Mathematical Software, + Dec 1996. http://www.geom.umn.edu/software/qhull + +Please send e-mail to + + qhull@geom.umn.edu + +Thank you! diff --git a/extern/qhull/SConscript b/extern/qhull/SConscript new file mode 100644 index 00000000000..7f911d1b7f1 --- /dev/null +++ b/extern/qhull/SConscript @@ -0,0 +1,35 @@ +#!/usr/bin/python +import sys +import os + +Import('env') +defs = '' +cflags = [] +if sys.platform=='linux2' or sys.platform=='linux-i386': + cflags += ['-O2','-ansi'] +elif env['OURPLATFORM']=='win32-vc': + cflags += ['/O2'] +elif env['OURPLATFORM']=='win32-mingw': + cflags += ['-O2'] +elif sys.platform=='sunos5': + cflags += ['-O2', '-ansi'] +elif sys.platform=='darwin': + cflags += ['-O2', '-pipe', '-fPIC', '-funsigned-char', '-ffast-math'] + +sources = ['src/geom.c', + 'src/geom2.c', + 'src/global.c', + 'src/io.c', + 'src/mem.c', + 'src/merge.c', + 'src/poly.c', + 'src/poly2.c', + 'src/qhull.c', + 'src/qset.c', + 'src/stat.c', + 'src/user.c'] + + +incs = 'include src' + +env.BlenderLib ( 'extern_qhull', sources, Split(incs), Split(defs), libtype=['game2','player'], priority=[50, 85], compileflags = cflags) diff --git a/extern/qhull/VisualC6/qhull.dsw b/extern/qhull/VisualC6/qhull.dsw new file mode 100644 index 00000000000..96c68d8e34c --- /dev/null +++ b/extern/qhull/VisualC6/qhull.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "qhull"=".\qhull\qhull.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/extern/qhull/VisualC6/qhull/qhull.dsp b/extern/qhull/VisualC6/qhull/qhull.dsp new file mode 100644 index 00000000000..6e059b0994c --- /dev/null +++ b/extern/qhull/VisualC6/qhull/qhull.dsp @@ -0,0 +1,192 @@ +# Microsoft Developer Studio Project File - Name="qhull" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=qhull - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "qhull.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "qhull.mak" CFG="qhull - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qhull - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "qhull - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qhull - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +LINK32=cwlink.exe +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=XCOPY /Y ..\..\include\qhull\*.h ..\..\..\..\..\lib\windows\qhull\include\qhull\ XCOPY /Y Release\*.lib ..\..\..\..\..\lib\windows\qhull\lib\ +# End Special Build Tool + +!ELSEIF "$(CFG)" == "qhull - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +LINK32=cwlink.exe +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MT /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=XCOPY /Y ..\..\include\qhull\*.h ..\..\..\..\..\lib\windows\qhull\include\qhull\ XCOPY /Y Debug\*.lib ..\..\..\..\..\lib\windows\qhull\lib\Debug\ +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "qhull - Win32 Release" +# Name "qhull - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\src\geom.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\geom2.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\global.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\io.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\mem.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\merge.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\poly.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\poly2.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\qhull.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\qset.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\stat.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\user.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\src\geom.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\io.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\mem.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\merge.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\poly.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\qhull.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\qhull_a.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\qset.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\stat.h +# End Source File +# Begin Source File + +SOURCE=..\..\src\user.h +# End Source File +# End Group +# End Target +# End Project diff --git a/extern/qhull/include/qhull/geom.h b/extern/qhull/include/qhull/geom.h new file mode 100644 index 00000000000..32440cff56f --- /dev/null +++ b/extern/qhull/include/qhull/geom.h @@ -0,0 +1,177 @@ +/*
  ---------------------------------
+
+  geom.h 
+    header file for geometric routines
+
+   see qh-geom.htm and geom.c
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#ifndef qhDEFgeom
+#define qhDEFgeom 1
+
+/* ============ -macros- ======================== */
+
+/*----------------------------------
+   
+  fabs_(a)
+    returns the absolute value of a
+*/
+#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
+               
+/*----------------------------------
+  
+  fmax_(a,b)
+    returns the maximum value of a and b
+*/
+#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  fmin_(a,b)
+    returns the minimum value of a and b
+*/
+#define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  maximize_(maxval, val)
+    set maxval to val if val is greater than maxval
+*/
+#define maximize_( maxval, val ) {if (( maxval ) < ( val )) ( maxval )= ( val );}
+
+/*----------------------------------
+
+  minimize_(minval, val)
+    set minval to val if val is less than minval
+*/
+#define minimize_( minval, val ) {if (( minval ) > ( val )) ( minval )= ( val );}
+
+/*----------------------------------
+
+  det2_(a1, a2,     
+        b1, b2)
+  
+    compute a 2-d determinate
+*/
+#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
+
+/*----------------------------------
+  
+  det3_(a1, a2, a3,    
+       b1, b2, b3,
+       c1, c2, c3)
+  
+    compute a 3-d determinate
+*/
+#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
+                - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )
+
+/*----------------------------------
+  
+  dX( p1, p2 )
+  dY( p1, p2 )
+  dZ( p1, p2 )
+  
+    given two indices into rows[],
+
+    compute the difference between X, Y, or Z coordinates
+*/
+#define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
+#define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
+#define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
+#define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))
+
+/*============= prototypes in alphabetical order, infrequent at end ======= */
+
+void    qh_backnormal (realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
+void	qh_distplane (pointT *point, facetT *facet, realT *dist);
+facetT *qh_findbest (pointT *point, facetT *startfacet,
+		     boolT bestoutside, boolT isnewfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbesthorizon (boolT ischeckmax, pointT *point, 
+	             facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
+facetT *qh_findbestnew (pointT *point, facetT *startfacet, realT *dist, 
+		     boolT bestoutside, boolT *isoutside, int *numpart);
+void 	qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
+realT   qh_getangle(pointT *vect1, pointT *vect2);
+pointT *qh_getcenter(setT *vertices);
+pointT *qh_getcentrum(facetT *facet);
+realT   qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist);
+void    qh_normalize (coordT *normal, int dim, boolT toporient);
+void    qh_normalize2 (coordT *normal, int dim, boolT toporient, 
+            realT *minnorm, boolT *ismin);
+pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist);
+
+void    qh_setfacetplane(facetT *newfacets);
+void 	qh_sethyperplane_det (int dim, coordT **rows, coordT *point0, 
+              boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
+void 	qh_sethyperplane_gauss (int dim, coordT **rows, pointT *point0, 
+	     boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
+boolT   qh_sharpnewfacets (void);
+
+/*========= infrequently used code in geom2.c =============*/
+
+
+coordT *qh_copypoints (coordT *points, int numpoints, int dimension);
+void    qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
+realT 	qh_determinant (realT **rows, int dim, boolT *nearzero);
+realT   qh_detjoggle (pointT *points, int numpoints, int dimension);
+void    qh_detroundoff (void);
+realT   qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero);
+realT   qh_distnorm (int dim, pointT *point, pointT *normal, realT *offsetp);
+realT   qh_distround (int dimension, realT maxabs, realT maxsumabs);
+realT   qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv);
+realT   qh_facetarea (facetT *facet);
+realT   qh_facetarea_simplex (int dim, coordT *apex, setT *vertices, 
+          vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset);
+pointT *qh_facetcenter (setT *vertices);
+facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
+void    qh_getarea (facetT *facetlist);
+boolT   qh_gram_schmidt(int dim, realT **rows);
+boolT   qh_inthresholds (coordT *normal, realT *angle);
+void    qh_joggleinput (void);
+realT  *qh_maxabsval (realT *normal, int dim);
+setT   *qh_maxmin(pointT *points, int numpoints, int dimension);
+realT   qh_maxouter (void);
+void    qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
+realT   qh_minabsval (realT *normal, int dim);
+int     qh_mindiff (realT *vecA, realT *vecB, int dim);
+boolT   qh_orientoutside (facetT *facet);
+void    qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane);
+coordT  qh_pointdist(pointT *point1, pointT *point2, int dim);
+void    qh_printmatrix (FILE *fp, char *string, realT **rows, int numrow, int numcol);
+void    qh_printpoints (FILE *fp, char *string, setT *points);
+void    qh_projectinput (void);
+void 	qh_projectpoints (signed char *project, int n, realT *points, 
+             int numpoints, int dim, realT *newpoints, int newdim);
+int     qh_rand( void);
+void    qh_srand( int seed);
+realT   qh_randomfactor (void);
+void    qh_randommatrix (realT *buffer, int dim, realT **row);
+void    qh_rotateinput (realT **rows);
+void    qh_rotatepoints (realT *points, int numpoints, int dim, realT **rows);
+void    qh_scaleinput (void);
+void    qh_scalelast (coordT *points, int numpoints, int dim, coordT low,
+		   coordT high, coordT newhigh);
+void 	qh_scalepoints (pointT *points, int numpoints, int dim,
+  		realT *newlows, realT *newhighs);
+boolT   qh_sethalfspace (int dim, coordT *coords, coordT **nextp, 
+              coordT *normal, coordT *offset, coordT *feasible);
+coordT *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible);
+pointT *qh_voronoi_center (int dim, setT *points);
+
+#endif /* qhDEFgeom */
+
+
+
diff --git a/extern/qhull/include/qhull/io.h b/extern/qhull/include/qhull/io.h
new file mode 100644
index 00000000000..351d56b3708
--- /dev/null
+++ b/extern/qhull/include/qhull/io.h
@@ -0,0 +1,149 @@
+/*
  ---------------------------------
+
+   io.h 
+   declarations of Input/Output functions
+
+   see README, qhull.h and io.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFio
+#define qhDEFio 1
+
+/*============ constants and flags ==================*/
+
+/*----------------------------------
+  
+  qh_MAXfirst
+    maximum length of first two lines of stdin
+*/
+#define qh_MAXfirst  200
+
+/*----------------------------------
+  
+  qh_MINradius
+    min radius for Gp and Gv, fraction of maxcoord
+*/
+#define qh_MINradius 0.02
+
+/*----------------------------------
+  
+  qh_GEOMepsilon
+    adjust outer planes for 'lines closer' and geomview roundoff.  
+    This prevents bleed through.
+*/
+#define qh_GEOMepsilon 2e-3
+
+/*----------------------------------
+  
+  qh_WHITESPACE
+    possible values of white space
+*/
+#define qh_WHITESPACE " \n\t\v\r\f"
+
+
+/*----------------------------------
+  
+  qh_RIDGE
+    to select which ridges to print in qh_eachvoronoi
+*/
+typedef enum
+{
+    qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
+}
+qh_RIDGE;
+
+/*----------------------------------
+  
+  printvridgeT
+    prints results of qh_printvdiagram
+
+  see:
+    qh_printvridge for an example
+*/
+typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+
+/*============== -prototypes in alphabetical order =========*/
+
+void    dfacet( unsigned id);
+void    dvertex( unsigned id);
+void    qh_countfacets (facetT *facetlist, setT *facets, boolT printall, 
+              int *numfacetsp, int *numsimplicialp, int *totneighborsp, 
+              int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
+pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
+setT   *qh_detvridge (vertexT *vertex);
+setT   *qh_detvridge3 (vertexT *atvertex, vertexT *vertex);
+int     qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
+int     qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder);
+void	qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist);
+setT   *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets);
+void    qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane);
+void    qh_markkeep (facetT *facetlist);
+setT   *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp);
+void    qh_order_vertexneighbors(vertexT *vertex);
+void	qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall);
+void    qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void 	qh_printcenter (FILE *fp, int format, char *string, facetT *facet);
+void    qh_printcentrum (FILE *fp, facetT *facet, realT radius);
+void    qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printend4geom (FILE *fp, facetT *facet, int *num, boolT printall);
+void    qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void	qh_printfacet(FILE *fp, facetT *facet);
+void	qh_printfacet2math(FILE *fp, facetT *facet, int notfirst);
+void	qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
+			       facetT *facet, realT offset, realT color[3]);
+void	qh_printfacet3math (FILE *fp, facetT *facet, int notfirst);
+void	qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
+void	qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet3vertex(FILE *fp, facetT *facet, int format);
+void	qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format);
+void	qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format);
+void    qh_printfacetheader(FILE *fp, facetT *facet);
+void    qh_printfacetridges(FILE *fp, facetT *facet);
+void	qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void	qh_printhelp_degenerate(FILE *fp);
+void	qh_printhelp_singular(FILE *fp);
+void	qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
+  		   setT *vertices, realT color[3]);
+void	qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void    qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
+void	qh_printpoint(FILE *fp, char *string, pointT *point);
+void	qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id);
+void    qh_printpoint3 (FILE *fp, pointT *point);
+void    qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
+void    qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
+void	qh_printridge(FILE *fp, ridgeT *ridge);
+void    qh_printspheres(FILE *fp, setT *vertices, realT radius);
+void    qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+int     qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
+void	qh_printvertex(FILE *fp, vertexT *vertex);
+void	qh_printvertexlist (FILE *fp, char* string, facetT *facetlist,
+                         setT *facets, boolT printall);
+void	qh_printvertices (FILE *fp, char* string, setT *vertices);
+void    qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall);
+void    qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void    qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void	qh_produce_output(void);
+void    qh_projectdim3 (pointT *source, pointT *destination);
+int     qh_readfeasible (int dim, char *remainder);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+void    qh_setfeasible (int dim);
+boolT	qh_skipfacet(facetT *facet);
+
+#endif /* qhDEFio */
diff --git a/extern/qhull/include/qhull/mem.h b/extern/qhull/include/qhull/mem.h
new file mode 100644
index 00000000000..e9ebd1bb9bc
--- /dev/null
+++ b/extern/qhull/include/qhull/mem.h
@@ -0,0 +1,174 @@
+/*
  ---------------------------------
+
+   mem.h 
+     prototypes for memory management functions
+
+   see qh-mem.htm, mem.c and qset.h
+
+   for error handling, writes message and calls
+     qh_errexit (qhmem_ERRmem, NULL, NULL) if insufficient memory
+       and
+     qh_errexit (qhmem_ERRqhull, NULL, NULL) otherwise
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmem
+#define qhDEFmem
+
+/*---------------------------------
+  
+  qh_NOmem
+    turn off quick-fit memory allocation
+
+  notes:
+    mem.c implements Quickfit memory allocation for about 20% time
+    savings.  If it fails on your machine, try to locate the
+    problem, and send the answer to qhull@geom.umn.edu.  If this can
+    not be done, define qh_NOmem to use malloc/free instead.
+
+   #define qh_NOmem
+*/
+
+/*-------------------------------------------
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles 
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers.  If gcc is available, 
+    use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).
+
+   see qh_MEMalign in user.h for qhull's alignment
+*/
+
+#define qhmem_ERRmem 4    /* matches qh_ERRmem in qhull.h */
+#define qhmem_ERRqhull 5  /* matches qh_ERRqhull in qhull.h */
+
+/*----------------------------------
+  
+  ptr_intT
+    for casting a void* to an integer-type
+  
+  notes:
+    On 64-bit machines, a pointer may be larger than an 'int'.  
+    qh_meminit() checks that 'long' holds a 'void*'
+*/
+typedef unsigned long ptr_intT;
+
+/*----------------------------------
+ 
+  qhmemT
+    global memory structure for mem.c
+ 
+ notes:
+   users should ignore qhmem except for writing extensions
+   qhmem is allocated in mem.c 
+   
+   qhmem could be swapable like qh and qhstat, but then
+   multiple qh's and qhmem's would need to keep in synch.  
+   A swapable qhmem would also waste memory buffers.  As long
+   as memory operations are atomic, there is no problem with
+   multiple qh structures being active at the same time.
+   If you need separate address spaces, you can swap the
+   contents of qhmem.
+*/
+typedef struct qhmemT qhmemT;
+extern qhmemT qhmem; 
+
+struct qhmemT {               /* global memory management variables */
+  int      BUFsize;	      /* size of memory allocation buffer */
+  int      BUFinit;	      /* initial size of memory allocation buffer */
+  int      TABLEsize;         /* actual number of sizes in free list table */
+  int      NUMsizes;          /* maximum number of sizes in free list table */
+  int      LASTsize;          /* last size in free list table */
+  int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
+  void	 **freelists;          /* free list table, linked by offset 0 */
+  int     *sizetable;         /* size of each freelist */
+  int     *indextable;        /* size->index table */
+  void    *curbuffer;         /* current buffer, linked by offset 0 */
+  void    *freemem;           /*   free memory in curbuffer */
+  int 	   freesize;          /*   size of free memory in bytes */
+  void 	  *tempstack;         /* stack of temporary memory, managed by users */
+  FILE    *ferr;              /* file for reporting errors */
+  int      IStracing;         /* =5 if tracing memory allocations */
+  int      cntquick;          /* count of quick allocations */
+                              /* remove statistics doesn't effect speed */
+  int      cntshort;          /* count of short allocations */
+  int      cntlong;           /* count of long allocations */
+  int      curlong;           /* current count of inuse, long allocations */
+  int      freeshort;	      /* count of short memfrees */
+  int      freelong;	      /* count of long memfrees */
+  int      totshort;          /* total size of short allocations */
+  int      totlong;           /* total size of long allocations */
+  int      maxlong;           /* maximum totlong */
+  int      cntlarger;         /* count of setlarger's */
+  int      totlarger;         /* total copied by setlarger */
+};
+
+
+/*==================== -macros ====================*/
+
+/*----------------------------------
+   
+  qh_memalloc_(size, object, type)  
+    returns object of size bytes 
+	assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+
+#ifdef qh_NOmem
+#define qh_memalloc_(size, freelistp, object, type) {\
+  object= (type*)qh_memalloc (size); }
+#else /* !qh_NOmem */
+
+#define qh_memalloc_(size, freelistp, object, type) {\
+  freelistp= qhmem.freelists + qhmem.indextable[size];\
+  if ((object= (type*)*freelistp)) {\
+    qhmem.cntquick++;  \
+    *freelistp= *((void **)*freelistp);\
+  }else object= (type*)qh_memalloc (size);}
+#endif
+
+/*----------------------------------
+   
+  qh_memfree_(object, size) 
+    free up an object
+
+  notes:
+    object may be NULL
+    assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+#ifdef qh_NOmem
+#define qh_memfree_(object, size, freelistp) {\
+  qh_memfree (object, size); }
+#else /* !qh_NOmem */
+
+#define qh_memfree_(object, size, freelistp) {\
+  if (object) { \
+    qhmem .freeshort++;\
+    freelistp= qhmem.freelists + qhmem.indextable[size];\
+    *((void **)object)= *freelistp;\
+    *freelistp= object;}}
+#endif
+
+/*=============== prototypes in alphabetical order ============*/
+
+void *qh_memalloc(int insize);
+void qh_memfree (void *object, int size);
+void qh_memfreeshort (int *curlong, int *totlong);
+void qh_meminit (FILE *ferr);
+void qh_meminitbuffers (int tracelevel, int alignment, int numsizes,
+			int bufsize, int bufinit);
+void qh_memsetup (void);
+void qh_memsize(int size);
+void qh_memstatistics (FILE *fp);
+
+#endif /* qhDEFmem */
diff --git a/extern/qhull/include/qhull/merge.h b/extern/qhull/include/qhull/merge.h
new file mode 100644
index 00000000000..7fc2afa5967
--- /dev/null
+++ b/extern/qhull/include/qhull/merge.h
@@ -0,0 +1,171 @@
+/*
  ---------------------------------
+
+   merge.h 
+   header file for merge.c
+
+   see qh-merge.htm and merge.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmerge
+#define qhDEFmerge 1
+
+
+/*============ -constants- ==============*/
+
+/*----------------------------------
+
+  qh_ANGLEredundant
+    indicates redundant merge in mergeT->angle
+*/
+#define qh_ANGLEredundant 6.0
+
+/*----------------------------------
+  
+  qh_ANGLEdegen
+    indicates degenerate facet in mergeT->angle
+*/
+#define qh_ANGLEdegen     5.0
+
+/*----------------------------------
+  
+  qh_ANGLEconcave
+    offset to indicate concave facets in mergeT->angle
+  
+  notes:
+    concave facets are assigned the range of [2,4] in mergeT->angle
+    roundoff error may make the angle less than 2
+*/
+#define qh_ANGLEconcave  1.5
+
+/*----------------------------------
+  
+  MRG... (mergeType)
+    indicates the type of a merge (mergeT->type)
+*/
+typedef enum {	/* in sort order for facet_mergeset */
+  MRGnone= 0,
+  MRGcoplanar,		/* centrum coplanar */
+  MRGanglecoplanar,	/* angle coplanar */
+  			/* could detect half concave ridges */
+  MRGconcave,		/* concave ridge */
+  MRGflip,		/* flipped facet. facet1 == facet2 */
+  MRGridge,		/* duplicate ridge (qh_MERGEridge) */
+                        /* degen and redundant go onto degen_mergeset */
+  MRGdegen,		/* degenerate facet (not enough neighbors) facet1 == facet2 */
+  MRGredundant,		/* redundant facet (vertex subset) */
+  			/* merge_degenredundant assumes degen < redundant */
+  MRGmirror,	        /* mirror facet from qh_triangulate */
+  ENDmrg
+} mergeType;
+
+/*----------------------------------
+  
+  qh_MERGEapex
+    flag for qh_mergefacet() to indicate an apex merge  
+*/
+#define qh_MERGEapex     True
+
+/*============ -structures- ====================*/
+
+/*----------------------------------
+     
+  mergeT
+    structure used to merge facets
+*/
+
+typedef struct mergeT mergeT;
+struct mergeT {		/* initialize in qh_appendmergeset */
+  realT   angle;        /* angle between normals of facet1 and facet2 */
+  facetT *facet1; 	/* will merge facet1 into facet2 */
+  facetT *facet2;
+  mergeType type;
+};
+
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+     
+  FOREACHmerge_( merges ) {...}
+    assign 'merge' to each merge in merges
+       
+  notes:
+    uses 'mergeT *merge, **mergep;'
+    if qh_mergefacet(),
+      restart since qh.facet_mergeset may change
+    see FOREACHsetelement_
+*/
+#define FOREACHmerge_( merges ) FOREACHsetelement_(mergeT, merges, merge)
+
+/*============ prototypes in alphabetical order after pre/postmerge =======*/
+
+void    qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle);
+void    qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
+             boolT vneighbors);
+void    qh_all_merges (boolT othermerge, boolT vneighbors);
+void    qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle);
+setT   *qh_basevertices( facetT *samecycle);
+void    qh_checkconnect (void /* qh new_facets */);
+boolT   qh_checkzero (boolT testall);
+void    qh_copynonconvex (ridgeT *atridge);
+void    qh_degen_redundant_facet (facetT *facet);
+void   	qh_degen_redundant_neighbors (facetT *facet, facetT *delfacet);
+vertexT *qh_find_newvertex (vertexT *oldvertex, setT *vertices, setT *ridges);
+void    qh_findbest_test (boolT testcentrum, facetT *facet, facetT *neighbor,
+           facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
+facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
+void 	qh_flippedmerges(facetT *facetlist, boolT *wasmerge);
+void 	qh_forcedmerges( boolT *wasmerge);
+void	qh_getmergeset(facetT *facetlist);
+void 	qh_getmergeset_initial (facetT *facetlist);
+void    qh_hashridge (setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
+ridgeT *qh_hashridge_find (setT *hashtable, int hashsize, ridgeT *ridge, 
+              vertexT *vertex, vertexT *oldvertex, int *hashslot);
+void 	qh_makeridges(facetT *facet);
+void    qh_mark_dupridges(facetT *facetlist);
+void    qh_maydropneighbor (facetT *facet);
+int     qh_merge_degenredundant (void);
+void    qh_merge_nonconvex( facetT *facet1, facetT *facet2, mergeType mergetype);
+void    qh_mergecycle (facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_all (facetT *facetlist, boolT *wasmerge);
+void    qh_mergecycle_facets( facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_vneighbors( facetT *samecycle, facetT *newfacet);
+void 	qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex);
+void    qh_mergefacet2d (facetT *facet1, facetT *facet2);
+void 	qh_mergeneighbors(facetT *facet1, facetT *facet2);
+void 	qh_mergeridges(facetT *facet1, facetT *facet2);
+void    qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex);
+void    qh_mergevertex_del (vertexT *vertex, facetT *facet1, facetT *facet2);
+void    qh_mergevertex_neighbors(facetT *facet1, facetT *facet2);
+void	qh_mergevertices(setT *vertices1, setT **vertices);
+setT   *qh_neighbor_intersections (vertexT *vertex);
+void    qh_newvertices (setT *vertices);
+boolT   qh_reducevertices (void);
+vertexT *qh_redundant_vertex (vertexT *vertex);
+boolT   qh_remove_extravertices (facetT *facet);
+vertexT *qh_rename_sharedvertex (vertexT *vertex, facetT *facet);
+void	qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
+void    qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges,
+			facetT *oldfacet, facetT *neighborA);
+boolT 	qh_test_appendmerge (facetT *facet, facetT *neighbor);
+boolT   qh_test_vneighbors (void /* qh newfacet_list */);
+void    qh_tracemerge (facetT *facet1, facetT *facet2);
+void    qh_tracemerging (void);
+void    qh_updatetested( facetT *facet1, facetT *facet2);
+setT   *qh_vertexridges (vertexT *vertex);
+void    qh_vertexridges_facet (vertexT *vertex, facetT *facet, setT **ridges);
+void    qh_willdelete (facetT *facet, facetT *replace);
+
+#endif /* qhDEFmerge */
diff --git a/extern/qhull/include/qhull/poly.h b/extern/qhull/include/qhull/poly.h
new file mode 100644
index 00000000000..294ec9527fc
--- /dev/null
+++ b/extern/qhull/include/qhull/poly.h
@@ -0,0 +1,290 @@
+/*
  ---------------------------------
+
+   poly.h 
+   header file for poly.c and poly2.c
+
+   see qh-poly.htm, qhull.h and poly.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFpoly
+#define qhDEFpoly 1
+
+/*===============   constants ========================== */
+
+/*----------------------------------
+  
+  ALGORITHMfault   
+    use as argument to checkconvex() to report errors during buildhull
+*/
+#define qh_ALGORITHMfault 0
+
+/*----------------------------------
+  
+  DATAfault        
+    use as argument to checkconvex() to report errors during initialhull
+*/
+#define qh_DATAfault 1
+
+/*----------------------------------
+  
+  DUPLICATEridge
+    special value for facet->neighbor to indicate a duplicate ridge
+  
+  notes:
+    set by matchneighbor, used by matchmatch and mark_dupridge
+*/
+#define qh_DUPLICATEridge ( facetT * ) 1L
+
+/*----------------------------------
+  
+  MERGEridge       flag in facet
+    special value for facet->neighbor to indicate a merged ridge
+  
+  notes:
+    set by matchneighbor, used by matchmatch and mark_dupridge
+*/
+#define qh_MERGEridge ( facetT * ) 2L
+
+
+/*============ -structures- ====================*/
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+  
+  FORALLfacet_( facetlist ) { ... }
+    assign 'facet' to each facet in facetlist
+    
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+    
+  see:
+    FORALLfacets
+*/
+#define FORALLfacet_( facetlist ) if ( facetlist ) for( facet=( facetlist );facet && facet->next;facet=facet->next )
+
+/*----------------------------------
+  
+  FORALLnew_facets { ... } 
+    assign 'newfacet' to each facet in qh.newfacet_list
+    
+  notes:
+    uses 'facetT *newfacet;'
+    at exit, newfacet==NULL
+*/
+#define FORALLnew_facets for( newfacet=qh newfacet_list;newfacet && newfacet->next;newfacet=newfacet->next )
+
+/*----------------------------------
+  
+  FORALLvertex_( vertexlist ) { ... }
+    assign 'vertex' to each vertex in vertexlist
+    
+  notes:
+    uses 'vertexT *vertex;'
+    at exit, vertex==NULL
+*/
+#define FORALLvertex_( vertexlist ) for ( vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )
+
+/*----------------------------------
+  
+  FORALLvisible_facets { ... }
+    assign 'visible' to each visible facet in qh.visible_list
+    
+  notes:
+    uses 'vacetT *visible;'
+    at exit, visible==NULL
+*/
+#define FORALLvisible_facets for (visible=qh visible_list; visible && visible->visible; visible= visible->next)
+
+/*----------------------------------
+  
+  FORALLsame_( newfacet ) { ... } 
+    assign 'same' to each facet in newfacet->f.samecycle
+    
+  notes:
+    uses 'facetT *same;'
+    stops when it returns to newfacet
+*/
+#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)
+
+/*----------------------------------
+  
+  FORALLsame_cycle_( newfacet ) { ... } 
+    assign 'same' to each facet in newfacet->f.samecycle
+    
+  notes:
+    uses 'facetT *same;'
+    at exit, same == NULL
+*/
+#define FORALLsame_cycle_(newfacet) \
+     for (same= newfacet->f.samecycle; \
+         same; same= (same == newfacet ?  NULL : same->f.samecycle))
+
+/*----------------------------------
+  
+  FOREACHneighborA_( facet ) { ... }
+    assign 'neighborA' to each neighbor in facet->neighbors
+  
+  FOREACHneighborA_( vertex ) { ... }
+    assign 'neighborA' to each neighbor in vertex->neighbors
+  
+  declare:
+    facetT *neighborA, **neighborAp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)
+
+/*----------------------------------
+  
+  FOREACHvisible_( facets ) { ... } 
+    assign 'visible' to each facet in facets
+    
+  notes:
+    uses 'facetT *facet, *facetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
+
+/*----------------------------------
+  
+  FOREACHnewfacet_( facets ) { ... } 
+    assign 'newfacet' to each facet in facets
+    
+  notes:
+    uses 'facetT *newfacet, *newfacetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
+
+/*----------------------------------
+  
+  FOREACHvertexA_( vertices ) { ... } 
+    assign 'vertexA' to each vertex in vertices
+    
+  notes:
+    uses 'vertexT *vertexA, *vertexAp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
+
+/*----------------------------------
+  
+  FOREACHvertexreverse12_( vertices ) { ... } 
+    assign 'vertex' to each vertex in vertices
+    reverse order of first two vertices
+    
+  notes:
+    uses 'vertexT *vertex, *vertexp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
+
+
+/*=============== prototypes poly.c in alphabetical order ================*/
+
+void    qh_appendfacet(facetT *facet);
+void    qh_appendvertex(vertexT *vertex);
+void 	qh_attachnewfacets (void);
+boolT   qh_checkflipped (facetT *facet, realT *dist, boolT allerror);
+void	qh_delfacet(facetT *facet);
+void 	qh_deletevisible(void /*qh visible_list, qh horizon_list*/);
+setT   *qh_facetintersect (facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
+unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem);
+facetT *qh_makenewfacet(setT *vertices, boolT toporient, facetT *facet);
+void    qh_makenewplanes ( void /* newfacet_list */);
+facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew);
+facetT *qh_makenew_simplicial (facetT *visible, vertexT *apex, int *numnew);
+void    qh_matchneighbor (facetT *newfacet, int newskip, int hashsize,
+			  int *hashcount);
+void	qh_matchnewfacets (void);
+boolT   qh_matchvertices (int firstindex, setT *verticesA, int skipA, 
+			  setT *verticesB, int *skipB, boolT *same);
+facetT *qh_newfacet(void);
+ridgeT *qh_newridge(void);
+int     qh_pointid (pointT *point);
+void 	qh_removefacet(facetT *facet);
+void 	qh_removevertex(vertexT *vertex);
+void    qh_updatevertices (void);
+
+
+/*========== -prototypes poly2.c in alphabetical order ===========*/
+
+void    qh_addhash (void* newelem, setT *hashtable, int hashsize, unsigned hash);
+void 	qh_check_bestdist (void);
+void    qh_check_maxout (void);
+void    qh_check_output (void);
+void    qh_check_point (pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2);
+void   	qh_check_points(void);
+void 	qh_checkconvex(facetT *facetlist, int fault);
+void    qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp);
+void 	qh_checkflipped_all (facetT *facetlist);
+void 	qh_checkpolygon(facetT *facetlist);
+void    qh_checkvertex (vertexT *vertex);
+void 	qh_clearcenters (qh_CENTER type);
+void 	qh_createsimplex(setT *vertices);
+void 	qh_delridge(ridgeT *ridge);
+void    qh_delvertex (vertexT *vertex);
+setT   *qh_facet3vertex (facetT *facet);
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+facetT *qh_findfacet_all (pointT *point, realT *bestdist, boolT *isoutside,
+			  int *numpart);
+int 	qh_findgood (facetT *facetlist, int goodhorizon);
+void 	qh_findgood_all (facetT *facetlist);
+void    qh_furthestnext (void /* qh facet_list */);
+void    qh_furthestout (facetT *facet);
+void    qh_infiniteloop (facetT *facet);
+void 	qh_initbuild(void);
+void 	qh_initialhull(setT *vertices);
+setT   *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints);
+vertexT *qh_isvertex (pointT *point, setT *vertices);
+vertexT *qh_makenewfacets (pointT *point /*horizon_list, visible_list*/);
+void    qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount);
+void    qh_nearcoplanar ( void /* qh.facet_list */);
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp);
+int 	qh_newhashtable(int newsize);
+vertexT *qh_newvertex(pointT *point);
+ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp);
+void    qh_outcoplanar (void /* facet_list */);
+pointT *qh_point (int id);
+void 	qh_point_add (setT *set, pointT *point, void *elem);
+setT   *qh_pointfacet (void /*qh facet_list*/);
+setT   *qh_pointvertex (void /*qh facet_list*/);
+void 	qh_prependfacet(facetT *facet, facetT **facetlist);
+void	qh_printhashtable(FILE *fp);
+void    qh_printlists (void);
+void    qh_resetlists (boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/);
+void    qh_setvoronoi_all (void);
+void	qh_triangulate (void /*qh facet_list*/);
+void    qh_triangulate_facet (facetT *facetA, vertexT **first_vertex);
+void    qh_triangulate_link (facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
+void	qh_triangulate_mirror (facetT *facetA, facetT *facetB);
+void    qh_triangulate_null (facetT *facetA);
+void    qh_vertexintersect(setT **vertexsetA,setT *vertexsetB);
+setT   *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB);
+void    qh_vertexneighbors (void /*qh facet_list*/);
+boolT 	qh_vertexsubset(setT *vertexsetA, setT *vertexsetB);
+
+
+#endif /* qhDEFpoly */
diff --git a/extern/qhull/include/qhull/qhull.h b/extern/qhull/include/qhull/qhull.h
new file mode 100644
index 00000000000..896ec1e9c18
--- /dev/null
+++ b/extern/qhull/include/qhull/qhull.h
@@ -0,0 +1,1048 @@
+/*
  ---------------------------------
+
+   qhull.h
+   user-level header file for using qhull.a library
+
+   see qh-qhull.htm, qhull_a.h
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   NOTE: access to qh_qh is via the 'qh' macro.  This allows
+   qh_qh to be either a pointer or a structure.  An example
+   of using qh is "qh DROPdim" which accesses the DROPdim
+   field of qh_qh.  Similarly, access to qh_qhstat is via
+   the 'qhstat' macro.
+
+   includes function prototypes for qhull.c, geom.c, global.c, io.c, user.c
+
+   use mem.h for mem.c
+   use qset.h for qset.c
+
+   see unix.c for an example of using qhull.h
+
+   recompile qhull if you change this file
+*/
+
+#ifndef qhDEFqhull
+#define qhDEFqhull 1
+
+/*=========================== -included files ==============*/
+
+#include 
+#include 
+#include 
+
+#if __MWERKS__ && __POWERPC__
+#include  
+#include  
+#include	
+#endif
+
+#ifndef __STDC__
+#ifndef __cplusplus
+#if     !_MSC_VER
+#error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
+#error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
+#error  your compiler is a standard C compiler, you can delete this warning from qhull.h
+#endif
+#endif
+#endif
+
+#include "user.h"      /* user defineable constants */
+
+/*============ constants and basic types ====================*/
+
+/*----------------------------------
+
+  qh_VERSION
+    version string by year and date
+
+    the revision increases on code changes only
+
+  notes:
+    change date:    Changes.txt, Announce.txt, README.txt, qhull.man
+                    qhull-news.html, Eudora signatures, 
+    change version: README.txt, qhull.html, file_id.diz, Makefile
+    change year:    Copying.txt
+    check download size
+    recompile user_eg.c, rbox.c, qhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c
+    make copy of qhull-news.html as qh-news.htm
+*/
+
+#define qh_VERSION "2002.1 2002/8/20"
+
+/*----------------------------------
+
+  coordT
+    coordinates and coefficients are stored as realT (i.e., double)
+
+  notes:
+    could use 'float' for data and 'double' for calculations (realT vs. coordT)
+      This requires many type casts, and adjusted error bounds.
+      Also C compilers may do expressions in double anyway.
+*/
+#define coordT realT
+
+/*----------------------------------
+
+  pointT
+    a point is an array of DIM3 coordinates
+*/
+#define pointT coordT
+
+/*----------------------------------
+
+  flagT
+    Boolean flag as a bit
+*/
+#define flagT unsigned int
+
+/*----------------------------------
+
+  boolT
+    boolean value, either True or False
+
+  notes:
+    needed for portability
+*/
+#define boolT unsigned int
+#ifdef False
+#undef False
+#endif
+#ifdef True
+#undef True
+#endif
+#define False 0
+#define True 1
+
+/*----------------------------------
+
+  qh_CENTER
+    to distinguish facet->center
+*/
+typedef enum
+{
+    qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum
+}
+qh_CENTER;
+
+/*----------------------------------
+
+  qh_PRINT
+    output formats for printing (qh.PRINTout).
+    'Fa' 'FV' 'Fc' 'FC' 
+       
+
+   notes:
+   some of these names are similar to qh names.  The similar names are only
+   used in switch statements in qh_printbegin() etc.
+*/
+typedef enum {qh_PRINTnone= 0, 
+  qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
+  qh_PRINTcoplanars, qh_PRINTcentrums, 
+  qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
+  qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors, 
+  qh_PRINTnormals, qh_PRINTouter,          /* 'n' 'Fo' 'i' 'm' 'Fm' 'o' */
+  qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff, 
+  qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
+  qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize, 
+  qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
+  qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
+  qh_PRINTEND} qh_PRINT;
+
+/*----------------------------------
+
+  qh_ALL
+    argument flag for selecting everything
+*/
+#define qh_ALL      True
+#define qh_NOupper  True     /* argument for qh_findbest */
+#define qh_IScheckmax  True     /* argument for qh_findbesthorizon */
+#define qh_ISnewfacets  True     /* argument for qh_findbest */
+#define qh_RESETvisible  True     /* argument for qh_resetlists */
+
+/*----------------------------------
+
+  qh_ERR
+    Qhull exit codes, for indicating errors
+*/
+#define qh_ERRnone  0    /* no error occurred during qhull */
+#define qh_ERRinput 1    /* input inconsistency */
+#define qh_ERRsingular 2 /* singular input data */
+#define qh_ERRprec  3    /* precision error */
+#define qh_ERRmem   4    /* insufficient memory, matches mem.h */
+#define qh_ERRqhull 5    /* internal error detected, matches mem.h */
+
+/* ============ -structures- ====================
+   each of the following structures is defined by a typedef
+   all realT and coordT fields occur at the beginning of a structure
+        (otherwise space may be wasted due to alignment)
+   define all flags together and pack into 32-bit number
+*/
+
+typedef struct vertexT vertexT;
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;          /* defined in qset.h */
+#endif
+
+/*----------------------------------
+
+  facetT
+    defines a facet
+
+  notes:
+   qhull() generates the hull as a list of facets.
+
+  topological information:
+    f.previous,next     doubly-linked list of facets
+    f.vertices          set of vertices
+    f.ridges            set of ridges
+    f.neighbors         set of neighbors
+    f.toporient         True if facet has top-orientation (else bottom)
+
+  geometric information:
+    f.offset,normal     hyperplane equation
+    f.maxoutside        offset to outer plane -- all points inside
+    f.center            centrum for testing convexity
+    f.simplicial        True if facet is simplicial
+    f.flipped           True if facet does not include qh.interior_point
+
+  for constructing hull:
+    f.visible           True if facet on list of visible facets (will be deleted)
+    f.newfacet          True if facet on list of newly created facets
+    f.coplanarset       set of points coplanar with this facet
+                        (includes near-inside points for later testing)
+    f.outsideset        set of points outside of this facet
+    f.furthestdist      distance to furthest point of outside set
+    f.visitid           marks visited facets during a loop
+    f.replace           replacement facet for to-be-deleted, visible facets
+    f.samecycle,newcycle cycle of facets for merging into horizon facet
+
+  see below for other flags and fields
+*/
+struct facetT {
+#if !qh_COMPUTEfurthest
+  coordT   furthestdist;/* distance to furthest point of outsideset */
+#endif
+#if qh_MAXoutside
+  coordT   maxoutside;  /* max computed distance of point to facet
+  			Before QHULLfinished this is an approximation
+  			since maxdist not always set for mergefacet
+			Actual outer plane is +DISTround and
+			computed outer plane is +2*DISTround */
+#endif
+  coordT   offset;      /* exact offset of hyperplane from origin */
+  coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
+			/*   if tricoplanar, shared with a neighbor */
+  union {               /* in order of testing */
+   realT   area;        /* area of facet, only in io.c if  ->isarea */
+   facetT *replace;	/*  replacement facet if ->visible and NEWfacets
+  			     is NULL only if qh_mergedegen_redundant or interior */
+   facetT *samecycle;   /*  cycle of facets from the same visible/horizon intersection,
+   			     if ->newfacet */
+   facetT *newcycle;    /*  in horizon facet, current samecycle of new facets */ 
+   facetT *trivisible;  /* visible facet for ->tricoplanar facets during qh_triangulate() */
+   facetT *triowner;    /* owner facet for ->tricoplanar, !isarea facets w/ ->keepcentrum */
+  }f;
+  coordT  *center;      /*  centrum for convexity, qh CENTERtype == qh_AScentrum */
+      			/*  Voronoi center, qh CENTERtype == qh_ASvoronoi */
+			/*   if tricoplanar, shared with a neighbor */
+  facetT  *previous;    /* previous facet in the facet_list */
+  facetT  *next;        /* next facet in the facet_list */
+  setT    *vertices;    /* vertices for this facet, inverse sorted by ID 
+                           if simplicial, 1st vertex was apex/furthest */
+  setT    *ridges;      /* explicit ridges for nonsimplicial facets.
+  			   for simplicial facets, neighbors defines ridge */
+  setT    *neighbors;   /* neighbors of the facet.  If simplicial, the kth
+			   neighbor is opposite the kth vertex, and the first
+			   neighbor is the horizon facet for the first vertex*/
+  setT    *outsideset;  /* set of points outside this facet
+		           if non-empty, last point is furthest
+			   if NARROWhull, includes coplanars for partitioning*/
+  setT    *coplanarset; /* set of points coplanar with this facet
+  			   > qh.min_vertex and <= facet->max_outside
+                           a point is assigned to the furthest facet
+		           if non-empty, last point is furthest away */
+  unsigned visitid;     /* visit_id, for visiting all neighbors,
+			   all uses are independent */
+  unsigned id;	        /* unique identifier from qh facet_id */
+  unsigned nummerge:9;  /* number of merges */
+#define qh_MAXnummerge 511 /*     2^9-1, 32 flags total, see "flags:" in io.c */
+  flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
+			  /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
+			  /*   all tricoplanars share the same apex */
+                          /*   if ->degenerate, does not span facet (one logical ridge) */
+                          /*   one tricoplanar has ->keepcentrum and ->coplanarset */
+                          /*   during qh_triangulate, f.trivisible points to original facet */
+  flagT	   newfacet:1;  /* True if facet on qh newfacet_list (new or merged) */
+  flagT	   visible:1;   /* True if visible facet (will be deleted) */
+  flagT    toporient:1; /* True if created with top orientation
+			   after merging, use ridge orientation */
+  flagT    simplicial:1;/* True if simplicial facet, ->ridges may be implicit */
+  flagT    seen:1;      /* used to perform operations only once, like visitid */
+  flagT    seen2:1;     /* used to perform operations only once, like visitid */
+  flagT	   flipped:1;   /* True if facet is flipped */
+  flagT    upperdelaunay:1; /* True if facet is upper envelope of Delaunay triangulation */
+  flagT    notfurthest:1; /* True if last point of outsideset is not furthest*/
+
+/*-------- flags primarily for output ---------*/
+  flagT	   good:1;      /* True if a facet marked good for output */
+  flagT    isarea:1;    /* True if facet->f.area is defined */
+
+/*-------- flags for merging ------------------*/
+  flagT    dupridge:1;  /* True if duplicate ridge in facet */
+  flagT    mergeridge:1; /* True if facet or neighbor contains a qh_MERGEridge
+                            ->normal defined (also defined for mergeridge2) */
+  flagT    mergeridge2:1; /* True if neighbor contains a qh_MERGEridge (mark_dupridges */
+  flagT    coplanar:1;  /* True if horizon facet is coplanar at last use */
+  flagT     mergehorizon:1; /* True if will merge into horizon (->coplanar) */
+  flagT	    cycledone:1;/* True if mergecycle_all already done */
+  flagT    tested:1;    /* True if facet convexity has been tested (false after merge */
+  flagT    keepcentrum:1; /* True if keep old centrum after a merge, or marks owner for ->tricoplanar */
+  flagT	   newmerge:1;  /* True if facet is newly merged for reducevertices */
+  flagT	   degenerate:1; /* True if facet is degenerate (degen_mergeset or ->tricoplanar) */
+  flagT	   redundant:1;  /* True if facet is redundant (degen_mergeset) */
+};
+
+
+/*----------------------------------
+
+  ridgeT
+    defines a ridge
+
+  notes:
+  a ridge is DIM3-1 simplex between two neighboring facets.  If the
+  facets are non-simplicial, there may be more than one ridge between
+  two facets.  E.G. a 4-d hypercube has two triangles between each pair
+  of neighboring facets.
+
+  topological information:
+    vertices            a set of vertices
+    top,bottom          neighboring facets with orientation
+
+  geometric information:
+    tested              True if ridge is clearly convex
+    nonconvex           True if ridge is non-convex
+*/
+struct ridgeT {
+  setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID 
+                           NULL if a degen ridge (matchsame) */
+  facetT  *top;         /* top facet this ridge is part of */
+  facetT  *bottom;      /* bottom facet this ridge is part of */
+  unsigned id:24;       /* unique identifier, =>room for 8 flags */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    tested:1;    /* True when ridge is tested for convexity */
+  flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
+			   only one ridge between neighbors may have nonconvex */
+};
+
+/*----------------------------------
+
+  vertexT
+     defines a vertex
+
+  topological information:
+    next,previous       doubly-linked list of all vertices
+    neighbors           set of adjacent facets (only if qh.VERTEXneighbors)
+
+  geometric information:
+    point               array of DIM3 coordinates
+*/
+struct vertexT {
+  vertexT *next;        /* next vertex in vertex_list */
+  vertexT *previous;    /* previous vertex in vertex_list */
+  pointT  *point;       /* hull_dim coordinates (coordT) */
+  setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
+			   inits in io.c or after first merge */
+  unsigned visitid; /* for use with qh vertex_visit */
+  unsigned id:24;   /* unique identifier, =>room for 8 flags */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    seen2:1;     /* another seen flag */
+  flagT    delridge:1;  /* vertex was part of a deleted ridge */
+  flagT	   deleted:1;   /* true if vertex on qh del_vertices */
+  flagT    newlist:1;   /* true if vertex on qh newvertex_list */
+};
+
+/*======= -global variables -qh ============================*/
+
+/*----------------------------------
+
+  qh
+   all global variables for qhull are in qh, qhmem, and qhstat
+
+  notes:
+   qhmem is defined in mem.h and qhstat is defined in stat.h
+   access to qh_qh is via the "qh" macro.  See qh_QHpointer in user.h
+*/
+typedef struct qhT qhT;
+#if qh_QHpointer
+#define qh qh_qh->
+extern qhT *qh_qh;     /* allocated in global.c */
+#else
+#define qh qh_qh.
+extern qhT qh_qh;
+#endif
+
+struct qhT {
+
+/*----------------------------------
+
+  qh constants
+    configuration flags and constants for Qhull
+
+  notes:
+    The user configures Qhull by defining flags.  They are
+    copied into qh by qh_setflags().  qh-quick.htm#options defines the flags.
+*/
+  boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
+  boolT ANGLEmerge;	  /* true 'Qa' if sort potential merges by angle */
+  boolT APPROXhull;       /* true 'Wn' if MINoutside set */
+  realT MINoutside;       /*   'Wn' min. distance for an outside point */
+  boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
+                             for improving precision in Delaunay triangulations */
+  boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
+  boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
+  boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
+  boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
+  boolT CHECKfrequently;  /* true 'Tc' if checking frequently */
+  realT premerge_cos;     /*   'A-n'   cos_max when pre merging */
+  realT postmerge_cos;    /*   'An'    cos_max when post merging */
+  boolT DELAUNAY;         /* true 'd' if computing DELAUNAY triangulation */
+  boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
+  int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
+  boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
+  int   GOODpoint;        /* 1+n for 'QGn', good facet if visible/not(-) from point n*/
+  pointT *GOODpointp;     /*   the actual point */
+  boolT GOODthreshold;    /* true if qh lower_threshold/upper_threshold defined
+  			     false if qh SPLITthreshold */
+  int   GOODvertex;       /* 1+n, good facet if vertex for point n */
+  pointT *GOODvertexp;     /*   the actual point */
+  boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
+  int   IStracing;        /* trace execution, 0=none, 1=least, 4=most, -1=events */
+  int   KEEParea;         /* 'PAn' number of largest facets to keep */
+  boolT KEEPcoplanar;     /* true 'Qc' if keeping nearest facet for coplanar points */
+  boolT KEEPinside;       /* true 'Qi' if keeping nearest facet for inside points
+			      set automatically if 'd Qc' */
+  int   KEEPmerge;        /* 'PMn' number of facets to keep with most merges */
+  realT KEEPminArea;      /* 'PFn' minimum facet area to keep */
+  realT MAXcoplanar;      /* 'Un' max distance below a facet to be coplanar*/
+  boolT MERGEexact;	  /* true 'Qx' if exact merges (coplanar, degen, dupridge, flipped) */
+  boolT MERGEindependent; /* true 'Q2' if merging independent sets */
+  boolT MERGING;          /* true if exact-, pre- or post-merging, with angle and centrum tests */
+  realT   premerge_centrum;  /*   'C-n' centrum_radius when pre merging.  Default is round-off */
+  realT   postmerge_centrum; /*   'Cn' centrum_radius when post merging.  Default is round-off */
+  boolT MERGEvertices;	  /* true 'Q3' if merging redundant vertices */
+  realT MINvisible;       /* 'Vn' min. distance for a facet to be visible */
+  boolT NOnarrow;         /* true 'Q10' if no special processing for narrow distributions */
+  boolT NOnearinside;     /* true 'Q8' if ignore near-inside points when partitioning */
+  boolT NOpremerge;       /* true 'Q0' if no defaults for C-0 or Qx */
+  boolT ONLYgood; 	  /* true 'Qg' if process points with good visible or horizon facets */
+  boolT ONLYmax; 	  /* true 'Qm' if only process points that increase max_outside */
+  boolT PICKfurthest;     /* true 'Q9' if process furthest of furthest points*/
+  boolT POSTmerge;        /* true if merging after buildhull (Cn or An) */
+  boolT PREmerge;         /* true if merging during buildhull (C-n or A-n) */
+  			/* NOTE: some of these names are similar to qh_PRINT names */
+  boolT PRINTcentrums;	  /* true 'Gc' if printing centrums */
+  boolT PRINTcoplanar;    /* true 'Gp' if printing coplanar points */
+  int	PRINTdim;      	  /* print dimension for Geomview output */
+  boolT PRINTdots;        /* true 'Ga' if printing all points as dots */
+  boolT PRINTgood;        /* true 'Pg' if printing good facets */
+  boolT PRINTinner;	  /* true 'Gi' if printing inner planes */
+  boolT PRINTneighbors;	  /* true 'PG' if printing neighbors of good facets */
+  boolT PRINTnoplanes;	  /* true 'Gn' if printing no planes */
+  boolT PRINToptions1st;  /* true 'FO' if printing options to stderr */
+  boolT PRINTouter;	  /* true 'Go' if printing outer planes */
+  boolT PRINTprecision;   /* false 'Pp' if not reporting precision problems */
+  qh_PRINT PRINTout[qh_PRINTEND]; /* list of output formats to print */
+  boolT PRINTridges;      /* true 'Gr' if print ridges */
+  boolT PRINTspheres;     /* true 'Gv' if print vertices as spheres */
+  boolT PRINTstatistics;  /* true 'Ts' if printing statistics to stderr */
+  boolT PRINTsummary;     /* true 's' if printing summary to stderr */
+  boolT PRINTtransparent; /* true 'Gt' if print transparent outer ridges */
+  boolT PROJECTdelaunay;  /* true if DELAUNAY, no readpoints() and
+			     need projectinput() for Delaunay in qh_init_B */
+  int   PROJECTinput;     /* number of projected dimensions 'bn:0Bn:0' */
+  boolT QUICKhelp;	  /* true if quick help message for degen input */
+  boolT RANDOMdist;       /* true if randomly change distplane and setfacetplane */
+  realT RANDOMfactor;     /*    maximum random perturbation */
+  realT RANDOMa;         /*  qh_randomfactor is randr * RANDOMa + RANDOMb */
+  realT RANDOMb;
+  boolT RANDOMoutside;    /* true if select a random outside point */
+  int	REPORTfreq;       /* buildtracing reports every n facets */
+  int   REPORTfreq2;	  /* tracemerging reports every REPORTfreq/2 facets */
+  int	RERUN;            /* 'TRn' rerun qhull n times (qh.build_cnt) */
+  int	ROTATErandom;	  /* 'QRn' seed, 0 time, >= rotate input */
+  boolT SCALEinput;       /* true 'Qbk' if scaling input */
+  boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
+  boolT SETroundoff;      /* true 'E' if qh DISTround is predefined */
+  boolT SKIPcheckmax;	  /* true 'Q5' if skip qh_check_maxout */
+  boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
+  boolT SPLITthresholds;  /* true if upper_/lower_threshold defines a region
+                               used only for printing (not for qh ONLYgood) */
+  int	STOPcone;         /* 'TCn' 1+n for stopping after cone for point n*/
+			  /*       also used by qh_build_withresart for err exit*/
+  int	STOPpoint;        /* 'TVn' 'TV-n' 1+n for stopping after/before(-)
+			                adding point n */
+  int	TESTpoints;	  /* 'QTn' num of test points after qh.num_points.  Test points always coplanar. */
+  boolT TESTvneighbors;   /*  true 'Qv' if test vertex neighbors at end */
+  int   TRACElevel;       /* 'Tn' conditional IStracing level */
+  int	TRACElastrun;	  /*  qh.TRACElevel applies to last qh.RERUN */
+  int   TRACEpoint;       /* 'TPn' start tracing when point n is a vertex */
+  realT TRACEdist;        /* 'TWn' start tracing when merge distance too big */
+  int   TRACEmerge;       /* 'TMn' start tracing before this merge */
+  boolT TRIangulate;	  /* true 'Qt' if triangulate non-simplicial facets */
+  boolT TRInormals;	  /* true 'Q11' if triangulate duplicates normals (sets Qt) */
+  boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
+  boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
+  boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
+  boolT VORONOI;	  /* true 'v' if computing Voronoi diagram */
+
+  /*--------input constants ---------*/
+  realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
+  boolT DOcheckmax;       /* true if calling qh_check_maxout (qh_initqhull_globals) */
+  char	*feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
+  coordT *feasible_point;  /*    as coordinates, both malloc'd */
+  boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io.c */
+  boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
+  int 	hull_dim;         /* dimension of hull, set by initbuffers */
+  int 	input_dim;	  /* dimension of input, set by initbuffers */
+  int 	num_points;       /* number of input points */
+  pointT *first_point;    /* array of input points, see POINTSmalloc */
+  boolT POINTSmalloc;     /*   true if qh first_point/num_points allocated */
+  pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
+  boolT input_malloc;     /* true if qh input_points malloc'd */
+  char 	qhull_command[256];/* command line that invoked this program */
+  char 	rbox_command[256]; /* command line that produced the input points */
+  char  qhull_options[512];/* descriptive list of options */
+  int   qhull_optionlen;  /*    length of last line */
+  int   qhull_optionsiz;  /*     size of qhull_options before qh_initbuild */
+  boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
+  boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx'.  sets ZEROall_ok */
+  realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
+                             must set either GOODthreshold or SPLITthreshold
+  			     if Delaunay, default is 0.0 for upper envelope */
+  realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
+  realT *upper_bound;     /* scale point[k] to new upper bound */
+  realT *lower_bound;     /* scale point[k] to new lower bound
+  			     project if both upper_ and lower_bound == 0 */
+
+/*----------------------------------
+
+  qh precision constants
+    precision constants for Qhull
+
+  notes:
+    qh_detroundoff() computes the maximum roundoff error for distance
+    and other computations.  It also sets default values for the
+    qh constants above.
+*/
+  realT ANGLEround;       /* max round off error for angles */
+  realT centrum_radius;   /* max centrum radius for convexity (roundoff added) */
+  realT cos_max;	  /* max cosine for convexity (roundoff added) */
+  realT DISTround;        /* max round off error for distances, 'E' overrides */
+  realT MAXabs_coord;     /* max absolute coordinate */
+  realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
+  realT MAXsumcoord;      /* max sum of coordinates */
+  realT MAXwidth;         /* max rectilinear width of point coordinates */
+  realT MINdenom_1;       /* min. abs. value for 1/x */
+  realT MINdenom;         /*    use divzero if denominator < MINdenom */
+  realT MINdenom_1_2;     /* min. abs. val for 1/x that allows normalization */
+  realT MINdenom_2;       /*    use divzero if denominator < MINdenom_2 */
+  realT MINlastcoord;     /* min. last coordinate for qh_scalelast */
+  boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */
+  realT *NEARzero;        /* hull_dim array for near zero in gausselim */
+  realT NEARinside;       /* keep points for qh_check_maxout if close to facet */
+  realT ONEmerge;         /* max distance for merging simplicial facets */
+  realT outside_err;      /* application's epsilon for coplanar points
+                             qh_check_bestdist() qh_check_points() reports error if point outside */
+  realT WIDEfacet;        /* size of wide facet for skipping ridge in
+			     area computation and locking centrum */
+  
+/*----------------------------------
+
+  qh internal constants
+    internal constants for Qhull
+*/
+  char qhull[sizeof("qhull")]; /* for checking ownership */
+  void *old_stat;         /* pointer to saved qh_qhstat, qh_save_qhull */
+  jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() */
+  char jmpXtra[40];       /* extra bytes in case jmp_buf is defined wrong by compiler */
+  jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() */
+  char jmpXtra2[40];      /* extra bytes in case jmp_buf is defined wrong by compiler*/
+  FILE *fin;              /* pointer to input file, init by qh_meminit */
+  FILE *fout;             /* pointer to output file */
+  FILE *ferr;             /* pointer to error file */
+  pointT *interior_point; /* center point of the initial simplex*/
+  int   normal_size;      /* size in bytes for facet normals and point coords*/
+  int   center_size;      /* size in bytes for Voronoi centers */
+  int   TEMPsize;         /* size for small, temporary sets (in quick mem) */
+
+/*----------------------------------
+
+  qh facet and vertex lists
+    defines lists of facets, new facets, visible facets, vertices, and
+    new vertices.  Includes counts, next ids, and trace ids.
+  see:
+    qh_resetlists()
+*/
+  facetT *facet_list;     /* first facet */
+  facetT  *facet_tail;     /* end of facet_list (dummy facet) */
+  facetT *facet_next;     /* next facet for buildhull()
+    			     previous facets do not have outside sets
+                             NARROWhull: previous facets may have coplanar outside sets for qh_outcoplanar */
+  facetT *newfacet_list;  /* list of new facets to end of facet_list */
+  facetT *visible_list;   /* list of visible facets preceeding newfacet_list,
+                             facet->visible set */
+  int       num_visible;  /* current number of visible facets */
+  unsigned tracefacet_id;  /* set at init, then can print whenever */
+  facetT *tracefacet;     /*   set in newfacet/mergefacet, undone in delfacet*/
+  unsigned tracevertex_id;  /* set at buildtracing, can print whenever */
+  vertexT *tracevertex;     /*   set in newvertex, undone in delvertex*/
+  vertexT *vertex_list;     /* list of all vertices, to vertex_tail */
+  vertexT  *vertex_tail;    /*      end of vertex_list (dummy vertex) */
+  vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
+                             all vertices have 'newlist' set */
+  int 	num_facets;	  /* number of facets in facet_list
+			     includes visble faces (num_visible) */
+  int 	num_vertices;     /* number of vertices in facet_list */
+  int   num_outside;      /* number of points in outsidesets (for tracing and RANDOMoutside)
+                               includes coplanar outsideset points for NARROWhull/qh_outcoplanar() */
+  int   num_good;         /* number of good facets (after findgood_all) */
+  unsigned facet_id;      /* ID of next, new facet from newfacet() */
+  unsigned ridge_id;      /* ID of next, new ridge from newridge() */
+  unsigned vertex_id;     /* ID of next, new vertex from newvertex() */
+
+/*----------------------------------
+
+  qh global variables
+    defines minimum and maximum distances, next visit ids, several flags,
+    and other global variables.
+    initialize in qh_initbuild or qh_maxmin if used in qh_buildhull
+*/
+  unsigned long hulltime; /* ignore time to set up input and randomize */
+                          /*   use unsigned to avoid wrap-around errors */
+  boolT ALLOWrestart;     /* true if qh_precision can use qh.restartexit */
+  int   build_cnt;        /* number of calls to qh_initbuild */
+  qh_CENTER CENTERtype;   /* current type of facet->center, qh_CENTER */
+  int 	furthest_id;      /* pointid of furthest point, for tracing */
+  facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
+  realT JOGGLEmax;        /* set 'QJn' if randomly joggle input */
+  boolT maxoutdone;       /* set qh_check_maxout(), cleared by qh_addpoint() */
+  realT max_outside;      /* maximum distance from a point to a facet,
+			       before roundoff, not simplicial vertices
+			       actual outer plane is +DISTround and
+			       computed outer plane is +2*DISTround */
+  realT max_vertex;       /* maximum distance (>0) from vertex to a facet,
+			       before roundoff, due to a merge */
+  realT min_vertex;       /* minimum distance (<0) from vertex to a facet,
+			       before roundoff, due to a merge
+			       if qh.JOGGLEmax, qh_makenewplanes sets it
+  			       recomputed if qh.DOcheckmax, default -qh.DISTround */
+  boolT NEWfacets;        /* true while visible facets invalid due to new or merge
+			      from makecone/attachnewfacets to deletevisible */
+  boolT findbestnew;	  /* true if partitioning calls qh_findbestnew */
+  boolT findbest_notsharp; /* true if new facets are at least 90 degrees */
+  boolT NOerrexit;        /* true if qh.errexit is not available */
+  realT PRINTcradius;     /* radius for printing centrums */
+  realT PRINTradius;      /* radius for printing vertex spheres and points */
+  boolT POSTmerging;      /* true when post merging */
+  int 	printoutvar;	  /* temporary variable for qh_printbegin, etc. */
+  int 	printoutnum;	  /* number of facets printed */
+  boolT QHULLfinished;    /* True after qhull() is finished */
+  realT totarea;          /* 'FA': total facet area computed by qh_getarea */
+  realT totvol;           /* 'FA': total volume computed by qh_getarea */
+  unsigned int visit_id;  /* unique ID for searching neighborhoods, */
+  unsigned int vertex_visit; /* unique ID for searching vertices */
+  boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */
+  boolT WAScoplanar;      /* True if qh_partitioncoplanar (qh_check_maxout) */
+  
+/*----------------------------------
+
+  qh global sets
+    defines sets for merging, initial simplex, hashing, extra input points,
+    and deleted vertices
+*/
+  setT *facet_mergeset;   /* temporary set of merges to be done */
+  setT *degen_mergeset;   /* temporary set of degenerate and redundant merges */
+  setT *hash_table;	  /* hash table for matching ridges in qh_matchfacets
+                             size is setsize() */
+  setT *other_points;     /* additional points (first is qh interior_point) */
+  setT *del_vertices;     /* vertices to partition and delete with visible
+                             facets.  Have deleted set for checkfacet */
+
+/*----------------------------------
+
+  qh global buffers
+    defines buffers for maxtrix operations, input, and error messages
+*/
+  coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom.c */
+  coordT **gm_row;        /* array of gm_matrix rows */
+  char* line;             /* malloc'd input line of maxline+1 chars */
+  int maxline;
+  coordT *half_space;     /* malloc'd input array for halfspace (qh normal_size+coordT) */
+  coordT *temp_malloc;    /* malloc'd input array for points */
+  
+/*----------------------------------
+
+  qh static variables
+    defines static variables for individual functions
+
+  notes:
+    do not use 'static' within a function.  Multiple instances of qhull
+    may exist.
+
+    do not assume zero initialization, 'QPn' may cause a restart
+*/
+  boolT ERREXITcalled;    /* true during errexit (prevents duplicate calls */
+  boolT firstcentrum; 	  /* for qh_printcentrum */
+  realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
+  realT last_high;
+  realT last_newhigh;
+  unsigned lastreport;    /* for qh_buildtracing */
+  int mergereport;        /* for qh_tracemerging */
+  boolT old_randomdist;   /* save RANDOMdist when io, tracing, or statistics */
+  int   ridgeoutnum;      /* number of ridges in 4OFF output */
+  void *old_qhstat;       /* for saving qh_qhstat in save_qhull() */
+  setT *old_tempstack;     /* for saving qhmem.tempstack in save_qhull */
+  setT *coplanarset;      /* set of coplanar facets for searching qh_findbesthorizon() */
+};
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+
+  otherfacet_(ridge, facet)
+    return neighboring facet for a ridge in facet
+*/
+#define otherfacet_(ridge, facet) \
+                        (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
+
+/*----------------------------------
+
+  getid_(p)
+    return ID for facet, ridge, or vertex
+    return MAXINT if NULL (-1 causes type conversion error )
+*/
+#define getid_(p)       ((p) ? (p)->id : -1)
+
+/*============== FORALL macros ===================*/
+
+/*----------------------------------
+
+  FORALLfacets { ... }
+    assign 'facet' to each facet in qh.facet_list
+
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+
+  see:
+    FORALLfacet_( facetlist )
+*/
+#define FORALLfacets for (facet=qh facet_list;facet && facet->next;facet=facet->next)
+
+/*----------------------------------
+
+  FORALLpoints { ... }
+    assign 'point' to each point in qh.first_point, qh.num_points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoints FORALLpoint_(qh first_point, qh num_points)
+
+/*----------------------------------
+
+  FORALLpoint_( points, num) { ... }
+    assign 'point' to each point in points array of num points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoint_(points, num) for(point= (points), \
+      pointtemp= (points)+qh hull_dim*(num); point < pointtemp; point += qh hull_dim)
+
+/*----------------------------------
+
+  FORALLvertices { ... }
+    assign 'vertex' to each vertex in qh.vertex_list
+
+  declare:
+    vertexT *vertex;
+
+  notes:
+    assumes qh.vertex_list terminated with a sentinel
+*/
+#define FORALLvertices for (vertex=qh vertex_list;vertex && vertex->next;vertex= vertex->next)
+
+/*----------------------------------
+
+  FOREACHfacet_( facets ) { ... }
+    assign 'facet' to each facet in facets
+
+  declare:
+    facetT *facet, **facetp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_( facet ) { ... }
+    assign 'neighbor' to each neighbor in facet->neighbors
+
+  FOREACHneighbor_( vertex ) { ... }
+    assign 'neighbor' to each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor, **neighborp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_( points ) { ... }
+    assign 'point' to each point in points set
+
+  declare:
+    pointT *point, **pointp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_( ridges ) { ... }
+    assign 'ridge' to each ridge in ridges set
+
+  declare:
+    ridgeT *ridge, **ridgep;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_( vertices ) { ... }
+    assign 'vertex' to each vertex in vertices set
+
+  declare:
+    vertexT *vertex, **vertexp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
+
+/*----------------------------------
+
+  FOREACHfacet_i_( facets ) { ... }
+    assign 'facet' and 'facet_i' for each facet in facets set
+
+  declare:
+    facetT *facet;
+    int     facet_n, facet_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHfacet_i_(facets)    FOREACHsetelement_i_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_i_( facet ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors
+
+  FOREACHneighbor_i_( vertex ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor;
+    int     neighbor_n, neighbor_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHneighbor_i_(facet)  FOREACHsetelement_i_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_i_( points ) { ... }
+    assign 'point' and 'point_i' for each point in points set
+
+  declare:
+    pointT *point;
+    int     point_n, point_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHpoint_i_(points)    FOREACHsetelement_i_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_i_( ridges ) { ... }
+    assign 'ridge' and 'ridge_i' for each ridge in ridges set
+
+  declare:
+    ridgeT *ridge;
+    int     ridge_n, ridge_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHridge_i_(ridges)    FOREACHsetelement_i_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_i_( vertices ) { ... }
+    assign 'vertex' and 'vertex_i' for each vertex in vertices set
+
+  declare:
+    vertexT *vertex;
+    int     vertex_n, vertex_i;
+
+  see:
+    FOREACHsetelement_i_
+ */
+#define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices,vertex)
+
+/********* -qhull.c prototypes (duplicated from qhull_a.h) **********************/
+
+void    qh_qhull (void);
+boolT   qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist);
+void	qh_printsummary(FILE *fp);
+
+/********* -user.c prototypes (alphabetical) **********************/
+
+void 	qh_errexit(int exitcode, facetT *facet, ridgeT *ridge);
+void 	qh_errprint(char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
+int     qh_new_qhull (int dim, int numpoints, coordT *points, boolT ismalloc,
+		char *qhull_cmd, FILE *outfile, FILE *errfile);
+void    qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall);
+void 	qh_user_memsizes (void);
+
+/***** -geom.c/geom2.c prototypes (duplicated from geom.h) ****************/
+
+facetT *qh_findbest (pointT *point, facetT *startfacet,
+		     boolT bestoutside, boolT newfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbestnew (pointT *point, facetT *startfacet,
+                     realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
+boolT   qh_gram_schmidt(int dim, realT **rows);
+void    qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane);
+void	qh_printsummary(FILE *fp);
+void    qh_projectinput (void);
+void    qh_randommatrix (realT *buffer, int dim, realT **row);
+void    qh_rotateinput (realT **rows);
+void    qh_scaleinput (void);
+void    qh_setdelaunay (int dim, int count, pointT *points);
+coordT  *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible);
+
+/***** -global.c prototypes (alphabetical) ***********************/
+
+unsigned long qh_clock (void);
+void 	qh_checkflags (char *command, char *hiddenflags);
+void 	qh_freebuffers (void);
+void    qh_freeqhull (boolT allmem);
+void    qh_init_A (FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
+void    qh_init_B (coordT *points, int numpoints, int dim, boolT ismalloc);
+void 	qh_init_qhull_command (int argc, char *argv[]);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+void 	qh_initflags (char *command);
+void 	qh_initqhull_buffers (void);
+void 	qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc);
+void    qh_initqhull_mem (void);
+void 	qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile);
+void 	qh_initthresholds (char *command);
+void    qh_option (char *option, int *i, realT *r);
+#if qh_QHpointer
+void 	qh_restore_qhull (qhT **oldqh);
+qhT    *qh_save_qhull (void);
+#endif
+
+/***** -io.c prototypes (duplicated from io.h) ***********************/
+
+void    dfacet( unsigned id);
+void    dvertex( unsigned id);
+void	qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void	qh_produce_output(void);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+
+
+/********* -mem.c prototypes (duplicated from mem.h) **********************/
+
+void qh_meminit (FILE *ferr);
+void qh_memfreeshort (int *curlong, int *totlong);
+
+/********* -poly.c/poly2.c prototypes (duplicated from poly.h) **********************/
+
+void    qh_check_output (void);
+void    qh_check_points (void);
+setT   *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets);
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp);
+pointT *qh_point (int id);
+setT   *qh_pointfacet (void /*qh.facet_list*/);
+int     qh_pointid (pointT *point);
+setT   *qh_pointvertex (void /*qh.facet_list*/);
+void    qh_setvoronoi_all (void);
+void	qh_triangulate (void /*qh facet_list*/);
+
+/********* -stat.c prototypes (duplicated from stat.h) **********************/
+
+void    qh_collectstatistics (void);
+void    qh_printallstatistics (FILE *fp, char *string);
+
+#endif /* qhDEFqhull */
diff --git a/extern/qhull/include/qhull/qhull_a.h b/extern/qhull/include/qhull/qhull_a.h
new file mode 100644
index 00000000000..d4e69b071be
--- /dev/null
+++ b/extern/qhull/include/qhull/qhull_a.h
@@ -0,0 +1,127 @@
+/*
  ---------------------------------
+
+   qhull_a.h 
+   all header files for compiling qhull
+
+   see qh-qhull.htm
+
+   see qhull.h for user-level definitions
+   
+   see user.h for user-defineable constants
+   
+   defines internal functions for qhull.c global.c
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
+           full parens around (x?y:z)
+	   use '#include qhull/qhull_a.h' to avoid name clashes
+*/
+
+#ifndef qhDEFqhulla
+#define qhDEFqhulla
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include     /* some compilers will not need float.h */
+#include 
+#include 
+#include 
+/*** uncomment here and qset.c
+     if string.h does not define memcpy()
+#include 
+*/
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+#include "geom.h"
+#include "merge.h"
+#include "poly.h"
+#include "io.h"
+#include "stat.h"
+
+#if qh_CLOCKtype == 2  /* defined in user.h from qhull.h */
+#include 
+#include 
+#include 
+#endif
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ */
+#pragma warning( disable : 4056)  /* float constant expression.  Looks like a compiler bug */
+#pragma warning( disable : 4146)  /* unary minus applied to unsigned type */
+#pragma warning( disable : 4244)  /* conversion from 'unsigned long' to 'real' */
+#pragma warning( disable : 4305)  /* conversion from 'const double' to 'float' */
+#endif
+
+/* ======= -macros- =========== */
+
+/*----------------------------------
+  
+  traceN((fp.ferr, "format\n", vars));  
+    calls fprintf if qh.IStracing >= N
+  
+  notes:
+    removing tracing reduces code size but doesn't change execution speed
+*/
+#ifndef qh_NOtrace
+#define trace0(args) {if (qh IStracing) fprintf args;}
+#define trace1(args) {if (qh IStracing >= 1) fprintf args;}
+#define trace2(args) {if (qh IStracing >= 2) fprintf args;}
+#define trace3(args) {if (qh IStracing >= 3) fprintf args;}
+#define trace4(args) {if (qh IStracing >= 4) fprintf args;}
+#define trace5(args) {if (qh IStracing >= 5) fprintf args;}
+#else /* qh_NOtrace */
+#define trace0(args) {}
+#define trace1(args) {}
+#define trace2(args) {}
+#define trace3(args) {}
+#define trace4(args) {}
+#define trace5(args) {}
+#endif /* qh_NOtrace */
+
+/***** -qhull.c prototypes (alphabetical after qhull) ********************/
+
+void 	qh_qhull (void);
+boolT   qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist);
+void 	qh_buildhull(void);
+void    qh_buildtracing (pointT *furthest, facetT *facet);
+void    qh_build_withrestart (void);
+void 	qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet);
+void    qh_findhorizon(pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
+pointT *qh_nextfurthest (facetT **visible);
+void 	qh_partitionall(setT *vertices, pointT *points,int npoints);
+void    qh_partitioncoplanar (pointT *point, facetT *facet, realT *dist);
+void    qh_partitionpoint (pointT *point, facetT *facet);
+void 	qh_partitionvisible(boolT allpoints, int *numpoints);
+void    qh_precision (char *reason);
+void	qh_printsummary(FILE *fp);
+
+/***** -global.c internal prototypes (alphabetical) ***********************/
+
+void    qh_appendprint (qh_PRINT format);
+void 	qh_freebuild (boolT allmem);
+void 	qh_freebuffers (void);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+int     qh_strtol (const char *s, char **endp);
+double  qh_strtod (const char *s, char **endp);
+
+/***** -stat.c internal prototypes (alphabetical) ***********************/
+
+void	qh_allstatA (void);
+void	qh_allstatB (void);
+void	qh_allstatC (void);
+void	qh_allstatD (void);
+void	qh_allstatE (void);
+void	qh_allstatE2 (void);
+void	qh_allstatF (void);
+void	qh_allstatG (void);
+void	qh_allstatH (void);
+void 	qh_freebuffers (void);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+
+#endif /* qhDEFqhulla */
diff --git a/extern/qhull/include/qhull/qset.h b/extern/qhull/include/qhull/qset.h
new file mode 100644
index 00000000000..6c0ff758de4
--- /dev/null
+++ b/extern/qhull/include/qhull/qset.h
@@ -0,0 +1,468 @@
+/*
  ---------------------------------
+
+   qset.h
+     header file for qset.c that implements set
+
+   see qh-set.htm and qset.c
+   
+   only uses mem.c, malloc/free
+
+   for error handling, writes message and calls
+      qh_errexit (qhmem_ERRqhull, NULL, NULL);
+   
+   set operations satisfy the following properties:
+    - sets have a max size, the actual size (if different) is stored at the end
+    - every set is NULL terminated
+    - sets may be sorted or unsorted, the caller must distinguish this
+   
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFset
+#define qhDEFset 1
+
+/*================= -structures- ===============*/
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
+#endif
+
+/*------------------------------------------
+   
+setT
+  a set or list of pointers with maximum size and actual size.
+
+variations:
+  unsorted, unique   -- a list of unique pointers with NULL terminator
+  			   user guarantees uniqueness
+  sorted	     -- a sorted list of unique pointers with NULL terminator
+  			   qset.c guarantees uniqueness
+  unsorted           -- a list of pointers terminated with NULL
+  indexed  	     -- an array of pointers with NULL elements 
+
+structure for set of n elements:
+
+	--------------
+	|  maxsize 
+	--------------
+	|  e[0] - a pointer, may be NULL for indexed sets
+	--------------
+	|  e[1]
+	
+	--------------
+	|  ...
+	--------------
+	|  e[n-1]
+	--------------
+	|  e[n] = NULL
+	--------------
+	|  ...
+	--------------
+	|  e[maxsize] - n+1 or NULL (determines actual size of set)
+	--------------
+
+*/
+
+/*-- setelemT -- internal type to allow both pointers and indices
+*/
+typedef union setelemT setelemT;
+union setelemT {
+  void    *p;
+  int      i;         /* integer used for e[maxSize] */
+};
+
+struct setT {
+  int maxsize;          /* maximum number of elements (except NULL) */
+  setelemT e[1];        /* array of pointers, tail is NULL */
+                        /* last slot (unless NULL) is actual size+1 
+                           e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
+                        /* this may generate a warning since e[] contains
+			   maxsize elements */
+};
+
+/*=========== -constants- =========================*/
+
+/*-------------------------------------
+   
+  SETelemsize
+    size of a set element in bytes
+*/
+#define SETelemsize sizeof(setelemT) 
+
+
+/*=========== -macros- =========================*/
+
+/*-------------------------------------
+   
+   FOREACHsetelement_(type, set, variable)
+     define FOREACH iterator
+
+   declare:  
+     assumes *variable and **variablep are declared
+     no space in "variable)" [DEC Alpha cc compiler]
+
+   each iteration:
+     variable is set element
+     variablep is one beyond variable.  
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+
+   example:  
+     #define FOREACHfacet_( facets ) FOREACHsetelement_( facetT, facets, facet )
+
+   notes:
+     use FOREACHsetelement_i_() if need index or include NULLs
+
+   WARNING: 
+     nested loops can't use the same variable (define another FOREACH)
+   
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+          variable##p= (type **)&((set)->e[0].p); \
+	  (variable= *variable##p++);)
+
+/*------------------------------------------
+
+   FOREACHsetelement_i_(type, set, variable)
+     define indexed FOREACH iterator
+
+   declare:  
+     type *variable, variable_n, variable_i;
+
+   each iteration:
+     variable is set element, may be NULL
+     variable_i is index, variable_n is qh_setsize()
+
+   to repeat an element:
+     variable_i--; variable_n-- repeats for deleted element
+
+   at exit:
+     variable==NULL and variable_i==variable_n
+
+   example:
+     #define FOREACHfacet_i_( facets ) FOREACHsetelement_i_( facetT, facets, facet )
+   
+   WARNING: 
+     nested loops can't use the same variable (define another FOREACH)
+   
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_i_(type, set, variable) \
+        if (((variable= NULL), set)) for (\
+          variable##_i= 0, variable= (type *)((set)->e[0].p), \
+                   variable##_n= qh_setsize(set);\
+          variable##_i < variable##_n;\
+          variable= (type *)((set)->e[++variable##_i].p) )
+
+/*----------------------------------------
+
+   FOREACHsetelementreverse_(type, set, variable)- 
+     define FOREACH iterator in reverse order
+
+   declare:  
+     assumes *variable and **variablep are declared
+     also declare 'int variabletemp'
+
+   each iteration:
+     variable is set element
+
+   to repeat an element:
+     variabletemp++; / *repeat* /
+
+   at exit:
+     variable is NULL
+
+   example:
+     #define FOREACHvertexreverse_( vertices ) FOREACHsetelementreverse_( vertexT, vertices, vertex )
+  
+   notes:
+     use FOREACHsetelementreverse12_() to reverse first two elements
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+	   variable##temp= qh_setsize(set)-1, variable= qh_setlast(set);\
+	   variable; variable= \
+	   ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))
+
+/*-------------------------------------
+
+   FOREACHsetelementreverse12_(type, set, variable)- 
+     define FOREACH iterator with e[1] and e[0] reversed
+
+   declare:  
+     assumes *variable and **variablep are declared
+
+   each iteration:
+     variable is set element
+     variablep is one after variable.  
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+  
+   example
+     #define FOREACHvertexreverse12_( vertices ) FOREACHsetelementreverse12_( vertexT, vertices, vertex )
+
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse12_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+          variable##p= (type **)&((set)->e[1].p); \
+	  (variable= *variable##p); \
+          variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
+	      (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))
+
+/*-------------------------------------
+
+   FOREACHelem_( set )- 
+     iterate elements in a set
+
+   declare:  
+     void *elem, *elemp;
+
+   each iteration:
+     elem is set element
+     elemp is one beyond
+
+   to repeat an element:
+     elemp--; / *repeat* /
+
+   at exit:
+     elem == NULL at end of loop
+  
+   example:
+     FOREACHelem_(set) {
+     
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)
+
+/*-------------------------------------
+
+   FOREACHset_( set )- 
+     iterate a set of sets
+
+   declare:  
+     setT *set, **setp;
+
+   each iteration:
+     set is set element
+     setp is one beyond
+
+   to repeat an element:
+     setp--; / *repeat* /
+
+   at exit:
+     set == NULL at end of loop
+  
+   example
+     FOREACHset_(sets) {
+     
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)
+
+/*-------------------------------------------
+
+   SETindex_( set, elem )
+     return index of elem in set
+
+   notes:   
+     for use with FOREACH iteration
+
+   example:
+     i= SETindex_(ridges, ridge)
+*/
+#define SETindex_(set, elem) ((void **)elem##p - (void **)&(set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETref_( elem )
+     l.h.s. for modifying the current element in a FOREACH iteration
+
+   example:
+     SETref_(ridge)= anotherridge;
+*/
+#define SETref_(elem) (elem##p[-1])
+
+/*-----------------------------------------
+
+   SETelem_(set, n)
+     return the n'th element of set
+   
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+      use SETelemt_() for type cast
+*/
+#define SETelem_(set, n)           ((set)->e[n].p)
+
+/*-----------------------------------------
+
+   SETelemt_(set, n, type)
+     return the n'th element of set as a type
+   
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+*/
+#define SETelemt_(set, n, type)    ((type*)((set)->e[n].p))
+
+/*-----------------------------------------
+
+   SETelemaddr_(set, n, type)
+     return address of the n'th element of a set
+   
+   notes:
+      assumes that n is valid [0..size] and set is defined 
+*/
+#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))
+
+/*-----------------------------------------
+
+   SETfirst_(set)
+     return first element of set
+   
+*/
+#define SETfirst_(set)             ((set)->e[0].p)
+
+/*-----------------------------------------
+
+   SETfirstt_(set, type)
+     return first element of set as a type
+   
+*/
+#define SETfirstt_(set, type)      ((type*)((set)->e[0].p))
+
+/*-----------------------------------------
+
+   SETsecond_(set)
+     return second element of set
+   
+*/
+#define SETsecond_(set)            ((set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETsecondt_(set, type)
+     return second element of set as a type
+*/
+#define SETsecondt_(set, type)     ((type*)((set)->e[1].p))
+
+/*-----------------------------------------
+
+   SETaddr_(set, type)
+       return address of set's elements
+*/
+#define SETaddr_(set,type)	   ((type **)(&((set)->e[0].p)))
+
+/*-----------------------------------------
+
+   SETreturnsize_(set, size) 
+     return size of a set
+   
+   notes:
+      set must be defined
+      use qh_setsize(set) unless speed is critical
+*/
+#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))
+
+/*-----------------------------------------
+
+   SETempty_(set) 
+     return true (1) if set is empty
+   
+   notes:
+      set may be NULL
+*/
+#define SETempty_(set) 	          (!set || (SETfirst_(set) ? 0:1))
+
+/*-----------------------------------------
+
+   SETtruncate_(set)
+     return first element of set
+
+   see:
+     qh_settruncate()
+   
+*/
+#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
+      set->e[size].p= NULL;}
+
+/*======= prototypes in alphabetical order ============*/
+
+void  qh_setaddsorted(setT **setp, void *elem);
+void  qh_setaddnth(setT **setp, int nth, void *newelem);
+void  qh_setappend(setT **setp, void *elem);
+void  qh_setappend_set(setT **setp, setT *setA);
+void  qh_setappend2ndlast(setT **setp, void *elem);
+void  qh_setcheck(setT *set, char *tname, int id);
+void  qh_setcompact(setT *set);
+setT *qh_setcopy(setT *set, int extra);
+void *qh_setdel(setT *set, void *elem);
+void *qh_setdellast(setT *set);
+void *qh_setdelnth(setT *set, int nth);
+void *qh_setdelnthsorted(setT *set, int nth);
+void *qh_setdelsorted(setT *set, void *newelem);
+setT *qh_setduplicate( setT *set, int elemsize);
+int   qh_setequal(setT *setA, setT *setB);
+int   qh_setequal_except (setT *setA, void *skipelemA, setT *setB, void *skipelemB);
+int   qh_setequal_skip (setT *setA, int skipA, setT *setB, int skipB);
+void  qh_setfree(setT **set);
+void  qh_setfree2( setT **setp, int elemsize);
+void  qh_setfreelong(setT **set);
+int   qh_setin(setT *set, void *setelem);
+int   qh_setindex(setT *set, void *setelem);
+void  qh_setlarger(setT **setp);
+void *qh_setlast(setT *set);
+setT *qh_setnew(int size);
+setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend);
+void  qh_setprint(FILE *fp, char* string, setT *set);
+void  qh_setreplace(setT *set, void *oldelem, void *newelem);
+int   qh_setsize(setT *set);
+setT *qh_settemp(int setsize);
+void  qh_settempfree(setT **set);
+void  qh_settempfree_all(void);
+setT *qh_settemppop(void);
+void  qh_settemppush(setT *set);
+void  qh_settruncate (setT *set, int size);
+int   qh_setunique (setT **set, void *elem);
+void  qh_setzero (setT *set, int index, int size);
+
+
+#endif /* qhDEFset */
diff --git a/extern/qhull/include/qhull/stat.h b/extern/qhull/include/qhull/stat.h
new file mode 100644
index 00000000000..1dae54ed21d
--- /dev/null
+++ b/extern/qhull/include/qhull/stat.h
@@ -0,0 +1,520 @@
+  /*
  ---------------------------------
+
+   stat.h 
+     contains all statistics that are collected for qhull
+
+   see qh-stat.htm and stat.c
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   recompile qhull if you change this file
+
+   Integer statistics are Z* while real statistics are W*.  
+
+   define maydebugx to call a routine at every statistic event
+
+*/
+
+#ifndef qhDEFstat
+#define qhDEFstat 1
+
+
+/*---------------------------------
+
+  qh_KEEPstatistics
+    0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
+*/
+#ifndef qh_KEEPstatistics
+#define qh_KEEPstatistics 1
+#endif
+
+/*---------------------------------
+
+  Zxxx for integers, Wxxx for reals
+
+  notes:
+    be sure that all statistics are defined in stat.c
+      otherwise initialization may core dump
+    can pick up all statistics by:
+      grep '[zw].*_[(][ZW]' *.c >z.x
+    remove trailers with query">-
+    remove leaders with  query-replace-regexp [ ^I]+  (
+*/
+#if qh_KEEPstatistics
+enum statistics {     /* alphabetical after Z/W */
+    Zacoplanar,
+    Wacoplanarmax,
+    Wacoplanartot,
+    Zangle,
+    Wangle,
+    Wanglemax,
+    Wanglemin,
+    Zangletests,
+    Wareatot,
+    Wareamax,
+    Wareamin,
+    Zavoidold,
+    Wavoidoldmax,
+    Wavoidoldtot,
+    Zback0,
+    Zbestcentrum,
+    Zbestdist,
+    Zcentrumtests,
+    Zcheckpart,
+    Zcomputefurthest,
+    Zconcave,
+    Wconcavemax,
+    Wconcavetot,
+    Zconcaveridges,
+    Zconcaveridge,
+    Zcoplanar,
+    Wcoplanarmax,
+    Wcoplanartot,
+    Zcoplanarangle,
+    Zcoplanarcentrum,
+    Zcoplanarhorizon,
+    Zcoplanarinside,
+    Zcoplanarpart,
+    Zcoplanarridges,
+    Wcpu,
+    Zcyclefacetmax,
+    Zcyclefacettot,
+    Zcyclehorizon,
+    Zcyclevertex,
+    Zdegen,
+    Wdegenmax,
+    Wdegentot,
+    Zdegenvertex,
+    Zdelfacetdup, 
+    Zdelridge,
+    Zdelvertextot,
+    Zdelvertexmax,
+    Zdetsimplex,
+    Zdistcheck,
+    Zdistconvex,
+    Zdistgood,
+    Zdistio,
+    Zdistplane,
+    Zdiststat,
+    Zdistvertex,
+    Zdistzero,
+    Zdoc1,
+    Zdoc2,
+    Zdoc3,
+    Zdoc4,
+    Zdoc5,
+    Zdoc6,
+    Zdoc7,
+    Zdoc8,
+    Zdoc9,
+    Zdoc10,
+    Zdoc11,
+    Zdoc12,
+    Zdropdegen,
+    Zdropneighbor,
+    Zdupflip,
+    Zduplicate,
+    Wduplicatemax,
+    Wduplicatetot,
+    Zdupridge,
+    Zdupsame,
+    Zflipped, 
+    Wflippedmax, 
+    Wflippedtot, 
+    Zflippedfacets,
+    Zfindbest,
+    Zfindbestmax,
+    Zfindbesttot,
+    Zfindcoplanar,
+    Zfindfail,
+    Zfindhorizon,
+    Zfindhorizonmax,
+    Zfindhorizontot,
+    Zfindjump,
+    Zfindnew,
+    Zfindnewmax,
+    Zfindnewtot,
+    Zfindnewjump,
+    Zfindnewsharp,
+    Zgauss0,
+    Zgoodfacet,
+    Zhashlookup,
+    Zhashridge,
+    Zhashridgetest,
+    Zhashtests,
+    Zinsidevisible,
+    Zintersect,
+    Zintersectfail,
+    Zintersectmax,
+    Zintersectnum,
+    Zintersecttot,
+    Zmaxneighbors,
+    Wmaxout,
+    Wmaxoutside,
+    Zmaxridges,
+    Zmaxvertex,
+    Zmaxvertices,
+    Zmaxvneighbors,
+    Zmemfacets,
+    Zmempoints,
+    Zmemridges,
+    Zmemvertices,
+    Zmergeflipdup,
+    Zmergehorizon,
+    Zmergeinittot,
+    Zmergeinitmax,
+    Zmergeinittot2,
+    Zmergeintohorizon,
+    Zmergenew,
+    Zmergesettot,
+    Zmergesetmax,
+    Zmergesettot2,
+    Zmergesimplex,
+    Zmergevertex,
+    Wmindenom,
+    Wminvertex,
+    Zminnorm,
+    Zmultiridge,
+    Znearlysingular,
+    Zneighbor,
+    Wnewbalance,
+    Wnewbalance2,
+    Znewfacettot,
+    Znewfacetmax,
+    Znewvertex,
+    Wnewvertex,
+    Wnewvertexmax,
+    Znoarea,
+    Znonsimplicial,
+    Znowsimplicial,
+    Znotgood,
+    Znotgoodnew,
+    Znotmax,
+    Znumfacets,
+    Znummergemax,
+    Znummergetot,
+    Znumneighbors,
+    Znumridges,
+    Znumvertices,
+    Znumvisibility,
+    Znumvneighbors,
+    Zonehorizon,
+    Zpartangle,
+    Zpartcoplanar,
+    Zpartflip,
+    Zparthorizon,
+    Zpartinside,
+    Zpartition, 
+    Zpartitionall,
+    Zpartnear,
+    Zpbalance,
+    Wpbalance,
+    Wpbalance2, 
+    Zpostfacets, 
+    Zpremergetot,
+    Zprocessed,
+    Zremvertex,
+    Zremvertexdel,
+    Zrenameall,
+    Zrenamepinch,
+    Zrenameshare,
+    Zretry,
+    Wretrymax,
+    Zridge,
+    Wridge,
+    Wridgemax,
+    Zridge0,
+    Wridge0,
+    Wridge0max,
+    Zridgemid,
+    Wridgemid,
+    Wridgemidmax,
+    Zridgeok,
+    Wridgeok,
+    Wridgeokmax,
+    Zsearchpoints,
+    Zsetplane,
+    Ztestvneighbor,
+    Ztotcheck,
+    Ztothorizon,
+    Ztotmerge,
+    Ztotpartcoplanar,
+    Ztotpartition,
+    Ztotridges,
+    Ztotvertices,
+    Ztotvisible,
+    Ztricoplanar,
+    Ztricoplanarmax,
+    Ztricoplanartot,
+    Ztridegen,
+    Ztrimirror,
+    Ztrinull,
+    Wvertexmax,
+    Wvertexmin,
+    Zvertexridge,
+    Zvertexridgetot,
+    Zvertexridgemax,
+    Zvertices,
+    Zvisfacettot,
+    Zvisfacetmax,
+    Zvisvertextot,
+    Zvisvertexmax,
+    Zwidefacet,
+    Zwidevertices,
+    ZEND};
+
+/*---------------------------------
+
+  Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0
+
+  notes:
+    be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
+*/
+#else
+enum statistics {     /* for zzdef etc. macros */
+  Zback0,
+  Zbestdist,
+  Zcentrumtests,
+  Zcheckpart,
+  Zconcaveridges,
+  Zcoplanarhorizon,
+  Zcoplanarpart,
+  Zcoplanarridges,
+  Zcyclefacettot,
+  Zcyclehorizon,
+  Zdelvertextot,
+  Zdistcheck,
+  Zdistconvex,
+  Zdistzero,
+  Zdoc1,
+  Zdoc2,
+  Zdoc3,
+  Zdoc11,
+  Zflippedfacets,
+  Zgauss0,
+  Zminnorm,
+  Zmultiridge,
+  Znearlysingular,
+  Wnewvertexmax,
+  Znumvisibility,
+  Zpartcoplanar,
+  Zpartition,
+  Zpartitionall,
+  Zprocessed,
+  Zretry,
+  Zridge,
+  Wridge,
+  Wridgemax,
+  Zridge0,
+  Wridge0,
+  Wridge0max,
+  Zridgemid,
+  Wridgemid,
+  Wridgemidmax,
+  Zridgeok,
+  Wridgeok,
+  Wridgeokmax,
+  Zsetplane,
+  Ztotmerge,
+    ZEND};
+#endif
+
+/*---------------------------------
+  
+  ztype
+    the type of a statistic sets its initial value.  
+
+  notes:
+    The type should be the same as the macro for collecting the statistic
+*/
+enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};
+
+/*========== macros and constants =============*/
+
+/*----------------------------------
+  
+  MAYdebugx
+    define as maydebug() to be called frequently for error trapping
+*/
+#define MAYdebugx 
+
+/*----------------------------------
+  
+  zzdef_, zdef_( type, name, doc, -1)
+    define a statistic (assumes 'qhstat.next= 0;')
+
+  zdef_( type, name, doc, count)
+    define an averaged statistic
+    printed as name/count
+*/
+#define zzdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
+   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
+#if qh_KEEPstatistics
+#define zdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
+   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
+#else
+#define zdef_(type,name,doc,count)
+#endif
+
+/*----------------------------------
+  
+  zzinc_( name ), zinc_( name)
+    increment an integer statistic
+*/
+#define zzinc_(id) {MAYdebugx; qhstat stats[id].i++;}
+#if qh_KEEPstatistics
+#define zinc_(id) {MAYdebugx; qhstat stats[id].i++;}
+#else
+#define zinc_(id) {}
+#endif
+
+/*----------------------------------
+  
+  zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
+    add value to an integer or real statistic
+*/
+#define zzadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
+#define wwadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
+#if qh_KEEPstatistics
+#define zadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
+#define wadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
+#else
+#define zadd_(id, val) {}
+#define wadd_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zzval_( name ), zval_( name ), wwval_( name )
+    set or return value of a statistic
+*/
+#define zzval_(id) ((qhstat stats[id]).i)
+#define wwval_(id) ((qhstat stats[id]).r)
+#if qh_KEEPstatistics
+#define zval_(id) ((qhstat stats[id]).i)
+#define wval_(id) ((qhstat stats[id]).r)
+#else
+#define zval_(id) qhstat tempi
+#define wval_(id) qhstat tempr
+#endif
+
+/*----------------------------------
+
+  zmax_( id, val ), wmax_( id, value )
+    maximize id with val
+*/
+#define wwmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
+#if qh_KEEPstatistics
+#define zmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].i,(val));}
+#define wmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
+#else
+#define zmax_(id, val) {}
+#define wmax_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zmin_( id, val ), wmin_( id, value )
+    minimize id with val
+*/
+#if qh_KEEPstatistics
+#define zmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].i,(val));}
+#define wmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].r,(val));}
+#else
+#define zmin_(id, val) {}
+#define wmin_(id, val) {}
+#endif
+
+/*================== stat.h types ==============*/
+
+
+/*----------------------------------
+ 
+  intrealT
+    union of integer and real, used for statistics
+*/
+typedef union intrealT intrealT;    /* union of int and realT */
+union intrealT {
+    int i;
+    realT r;
+};
+
+/*----------------------------------
+  
+  qhstat
+    global data structure for statistics
+  
+  notes:
+   access to qh_qhstat is via the "qhstat" macro.  There are two choices
+   qh_QHpointer = 1     access globals via a pointer
+                        enables qh_saveqhull() and qh_restoreqhull()
+		= 0     qh_qhstat is a static data structure
+		        only one instance of qhull() can be active at a time
+			default value
+   qh_QHpointer is defined in qhull.h
+
+   allocated in stat.c
+*/
+typedef struct qhstatT qhstatT; 
+#if qh_QHpointer
+#define qhstat qh_qhstat->
+extern qhstatT *qh_qhstat;
+#else
+#define qhstat qh_qhstat.
+extern qhstatT qh_qhstat; 
+#endif
+struct qhstatT {  
+  intrealT   stats[ZEND];     /* integer and real statistics */
+  unsigned   char id[ZEND+10]; /* id's in print order */
+  char      *doc[ZEND];       /* array of documentation strings */
+  short int  count[ZEND];     /* -1 if none, else index of count to use */
+  char       type[ZEND];      /* type, see ztypes above */
+  char       printed[ZEND];   /* true, if statistic has been printed */
+  intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */
+
+  int        next;            /* next index for zdef_ */
+  int        precision;       /* index for precision problems */
+  int        vridges;         /* index for Voronoi ridges */
+  int        tempi;
+  realT      tempr;
+};
+
+/*========== function prototypes ===========*/
+
+void    qh_allstatA(void);
+void    qh_allstatB(void);
+void    qh_allstatC(void);
+void    qh_allstatD(void);
+void    qh_allstatE(void);
+void    qh_allstatE2(void);
+void    qh_allstatF(void);
+void    qh_allstatG(void);
+void    qh_allstatH(void);
+void    qh_allstatI(void);
+void    qh_allstatistics (void);
+void    qh_collectstatistics (void);
+void	qh_freestatistics (void);
+void    qh_initstatistics (void);
+boolT 	qh_newstats (int index, int *nextindex);
+boolT 	qh_nostatistic (int i);
+void    qh_printallstatistics (FILE *fp, char *string);
+void    qh_printstatistics (FILE *fp, char *string);
+void  	qh_printstatlevel (FILE *fp, int id, int start);
+void  	qh_printstats (FILE *fp, int index, int *nextindex);
+realT   qh_stddev (int num, realT tot, realT tot2, realT *ave);
+
+#endif   /* qhDEFstat */
diff --git a/extern/qhull/include/qhull/user.h b/extern/qhull/include/qhull/user.h
new file mode 100644
index 00000000000..79558967a52
--- /dev/null
+++ b/extern/qhull/include/qhull/user.h
@@ -0,0 +1,762 @@
+/*
  ---------------------------------
+
+   user.h
+   user redefinable constants
+
+   see qh-user.htm.  see COPYING for copyright information.
+
+   before reading any code, review qhull.h for data structure definitions and 
+   the "qh" macro.
+*/
+
+#ifndef qhDEFuser
+#define qhDEFuser 1
+
+/*============= data types and configuration macros ==========*/
+
+/*----------------------------------
+  
+  realT
+    set the size of floating point numbers
+  
+  qh_REALdigits 
+    maximimum number of significant digits
+  
+  qh_REAL_1, qh_REAL_2n, qh_REAL_3n
+    format strings for printf
+  
+  qh_REALmax, qh_REALmin
+    maximum and minimum (near zero) values  
+  
+  qh_REALepsilon
+    machine roundoff.  Maximum roundoff error for addition and multiplication.
+    
+  notes:
+   Select whether to store floating point numbers in single precision (float)
+   or double precision (double).
+   
+   Use 'float' to save about 8% in time and 25% in space.  This is particularly
+   help if high-d where convex hulls are space limited.  Using 'float' also
+   reduces the printed size of Qhull's output since numbers have 8 digits of 
+   precision.
+   
+   Use 'double' when greater arithmetic precision is needed.  This is needed
+   for Delaunay triangulations and Voronoi diagrams when you are not merging 
+   facets.
+
+   If 'double' gives insufficient precision, your data probably includes
+   degeneracies.  If so you should use facet merging (done by default)
+   or exact arithmetic (see imprecision section of manual, qh-impre.htm).  
+   You may also use option 'Po' to force output despite precision errors.
+
+   You may use 'long double', but many format statements need to be changed
+   and you may need a 'long double' square root routine.  S. Grundmann
+   (sg@eeiwzb.et.tu-dresden.de) has done this.  He reports that the code runs 
+   much slower with little gain in precision.    
+
+   WARNING: on some machines,    int f(){realT a= REALmax;return (a == REALmax);}
+      returns False.  Use (a > REALmax/2) instead of (a == REALmax).
+
+   REALfloat =   1      all numbers are 'float' type
+             =   0      all numbers are 'double' type
+*/
+#define REALfloat 0
+
+#if (REALfloat == 1)
+#define realT float
+#define REALmax FLT_MAX
+#define REALmin FLT_MIN
+#define REALepsilon FLT_EPSILON
+#define qh_REALdigits 8   /* maximum number of significant digits */
+#define qh_REAL_1 "%6.8g "
+#define qh_REAL_2n "%6.8g %6.8g\n"
+#define qh_REAL_3n "%6.8g %6.8g %6.8g\n"
+
+#elif (REALfloat == 0)
+#define realT double
+#define REALmax DBL_MAX
+#define REALmin DBL_MIN
+#define REALepsilon DBL_EPSILON
+#define qh_REALdigits 16    /* maximum number of significant digits */
+#define qh_REAL_1 "%6.16g "
+#define qh_REAL_2n "%6.16g %6.16g\n"
+#define qh_REAL_3n "%6.16g %6.16g %6.16g\n"
+
+#else
+#error unknown float option
+#endif
+
+/*----------------------------------
+  
+  qh_CPUclock
+    define the clock() function for reporting the total time spent by Qhull
+    returns CPU ticks as a 'long int'
+    qh_CPUclock is only used for reporting the total time spent by Qhull
+
+  qh_SECticks 
+    the number of clock ticks per second
+
+  notes:
+    looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds
+    to define a custom clock, set qh_CLOCKtype to 0
+
+    if your system does not use clock() to return CPU ticks, replace
+    qh_CPUclock with the corresponding function.  It is converted
+    to unsigned long to prevent wrap-around during long runs.
+   
+
+   Set qh_CLOCKtype to
+   
+     1	   	for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond
+                Note:  may fail if more than 1 hour elapsed time
+
+     2	   	use qh_clock() with POSIX times() (see global.c)
+*/
+#define qh_CLOCKtype 1  /* change to the desired number */
+
+#if (qh_CLOCKtype == 1)
+
+#if defined (CLOCKS_PER_SECOND)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SECOND
+
+#elif defined (CLOCKS_PER_SEC)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SEC
+
+#elif defined (CLK_TCK)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLK_TCK
+
+#else
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks 1E6
+#endif
+
+#elif (qh_CLOCKtype == 2)
+#define qh_CPUclock    qh_clock()  /* return CPU clock */
+#define qh_SECticks 100
+
+#else /* qh_CLOCKtype == ? */
+#error unknown clock option
+#endif
+
+/*----------------------------------
+  
+  qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed
+    define random number generator
+
+    qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax.  
+    qh_RANDOMseed sets the random number seed for qh_RANDOMint
+
+  Set qh_RANDOMtype (default 5) to:
+    1       for random() with 31 bits (UCB)
+    2       for rand() with RAND_MAX or 15 bits (system 5)
+    3       for rand() with 31 bits (Sun)
+    4       for lrand48() with 31 bits (Solaris)
+    5       for qh_rand() with 31 bits (included with Qhull)
+  
+  notes:
+    Random numbers are used by rbox to generate point sets.  Random
+    numbers are used by Qhull to rotate the input ('QRn' option),
+    simulate a randomized algorithm ('Qr' option), and to simulate
+    roundoff errors ('Rn' option).
+
+    Random number generators differ between systems.  Most systems provide
+    rand() but the period varies.  The period of rand() is not critical
+    since qhull does not normally use random numbers.  
+
+    The default generator is Park & Miller's minimal standard random
+    number generator [CACM 31:1195 '88].  It is included with Qhull.
+
+    If qh_RANDOMmax is wrong, qhull will report a warning and Geomview 
+    output will likely be invisible.
+*/
+#define qh_RANDOMtype 5   /* *** change to the desired number *** */
+
+#if (qh_RANDOMtype == 1)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, random()/MAX */
+#define qh_RANDOMint random()
+#define qh_RANDOMseed_(seed) srandom(seed);
+
+#elif (qh_RANDOMtype == 2)
+#ifdef RAND_MAX
+#define qh_RANDOMmax ((realT)RAND_MAX)
+#else
+#define qh_RANDOMmax ((realT)32767)   /* 15 bits (System 5) */
+#endif
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+  
+#elif (qh_RANDOMtype == 3)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, Sun */
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+
+#elif (qh_RANDOMtype == 4)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, lrand38()/MAX */
+#define qh_RANDOMint lrand48()
+#define qh_RANDOMseed_(seed) srand48(seed);
+
+#elif (qh_RANDOMtype == 5)
+#define qh_RANDOMmax ((realT)2147483646UL)  /* 31 bits, qh_rand/MAX */
+#define qh_RANDOMint qh_rand()
+#define qh_RANDOMseed_(seed) qh_srand(seed);
+/* unlike rand(), never returns 0 */
+
+#else
+#error: unknown random option
+#endif
+
+/*----------------------------------
+  
+  qh_ORIENTclock
+    0 for inward pointing normals by Geomview convention
+*/
+#define qh_ORIENTclock 0 
+
+
+/*========= performance related constants =========*/
+
+/*----------------------------------
+  
+  qh_HASHfactor
+    total hash slots / used hash slots.  Must be at least 1.1.
+      
+  notes:
+    =2 for at worst 50% occupancy for qh hash_table and normally 25% occupancy
+*/
+#define qh_HASHfactor 2
+
+/*----------------------------------
+  
+  qh_VERIFYdirect
+    with 'Tv' verify all points against all facets if op count is smaller
+
+  notes:
+    if greater, calls qh_check_bestdist() instead
+*/
+#define qh_VERIFYdirect 1000000 
+
+/*----------------------------------
+  
+  qh_INITIALsearch
+     if qh_INITIALmax, search points up to this dimension
+*/
+#define qh_INITIALsearch 6
+
+/*----------------------------------
+  
+  qh_INITIALmax
+    if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex
+      
+  notes:
+    from points with non-zero determinants
+    use option 'Qs' to override (much slower)
+*/
+#define qh_INITIALmax 8
+
+/*----------------------------------
+  
+  qh_JOGGLEdefault
+    default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault
+
+  notes:
+    rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16
+    rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults
+    rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults
+    rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults
+    rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults
+    rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults
+    rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults
+    rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults
+    rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults
+    the later have about 20 points per facet, each of which may interfere
+
+    pick a value large enough to avoid retries on most inputs
+*/
+#define qh_JOGGLEdefault 30000.0
+
+/*----------------------------------
+  
+  qh_JOGGLEincrease
+    factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
+*/
+#define qh_JOGGLEincrease 10.0
+
+/*----------------------------------
+  
+  qh_JOGGLEretry
+    if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax
+
+  notes:
+    try twice at the original value in case of bad luck the first time
+*/
+#define qh_JOGGLEretry 2
+
+/*----------------------------------
+  
+  qh_JOGGLEagain
+    every following qh_JOGGLEagain, increase qh.JOGGLEmax
+
+  notes:
+    1 is OK since it's already failed qh_JOGGLEretry times
+*/
+#define qh_JOGGLEagain 1
+
+/*----------------------------------
+  
+  qh_JOGGLEmaxincrease
+    maximum qh.JOGGLEmax due to qh_JOGGLEincrease
+    relative to qh.MAXwidth
+
+  notes:
+    qh.joggleinput will retry at this value until qh_JOGGLEmaxretry
+*/
+#define qh_JOGGLEmaxincrease 1e-2
+
+/*----------------------------------
+  
+  qh_JOGGLEmaxretry
+    stop after qh_JOGGLEmaxretry attempts
+*/
+#define qh_JOGGLEmaxretry 100
+
+/*========= memory constants =========*/
+
+/*----------------------------------
+  
+  qh_MEMalign
+    memory alignment for qh_meminitbuffers() in global.c
+    
+  notes:
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles 
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers. 
+
+    If using gcc, best alignment is
+              #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
+*/
+#define qh_MEMalign fmax_(sizeof(realT), sizeof(void *))
+
+/*----------------------------------
+  
+  qh_MEMbufsize
+    size of additional memory buffers
+    
+  notes:
+    used for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */
+
+/*----------------------------------
+  
+  qh_MEMinitbuf
+    size of initial memory buffer
+    
+  notes:
+    use for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */
+
+/*----------------------------------
+  
+  qh_INFINITE
+    on output, indicates Voronoi center at infinity
+*/
+#define qh_INFINITE  -10.101
+
+/*----------------------------------
+  
+  qh_DEFAULTbox
+    default box size (Geomview expects 0.5)
+*/
+#define qh_DEFAULTbox 0.5 
+
+/*======= conditional compilation ============================*/
+
+/*----------------------------------
+
+  __cplusplus
+    defined by C++ compilers
+
+  __MSC_VER
+    defined by Microsoft Visual C++
+  
+  __MWERKS__ && __POWERPC__
+    defined by Metrowerks when compiling for the Power Macintosh
+
+  __STDC__
+    defined for strict ANSI C 
+*/
+
+/*----------------------------------
+ 
+  qh_COMPUTEfurthest 
+    compute furthest distance to an outside point instead of storing it with the facet
+    =1 to compute furthest
+  
+  notes:
+    computing furthest saves memory but costs time
+      about 40% more distance tests for partitioning
+      removes facet->furthestdist 
+*/
+#define qh_COMPUTEfurthest 0
+                         
+/*----------------------------------
+ 
+  qh_KEEPstatistics   
+    =0 removes most of statistic gathering and reporting
+
+  notes:
+    if 0, code size is reduced by about 4%.
+*/
+#define qh_KEEPstatistics 1
+                       
+/*----------------------------------
+ 
+  qh_MAXoutside 
+    record outer plane for each facet
+    =1 to record facet->maxoutside
+  
+  notes:
+    this takes a realT per facet and slightly slows down qhull
+    it produces better outer planes for geomview output 
+*/
+#define qh_MAXoutside 1
+
+/*----------------------------------
+ 
+  qh_NOmerge
+    disables facet merging if defined
+    
+  notes:
+    This saves about 10% space.
+    
+    Unless 'Q0'
+      qh_NOmerge sets 'QJ' to avoid precision errors
+
+    #define qh_NOmerge    
+
+  see:
+    qh_NOmem in mem.c
+    
+    see user.c/user_eg.c for removing io.o
+*/  
+    
+/*----------------------------------
+ 
+  qh_NOtrace
+    no tracing if defined 
+  
+  notes:
+    This saves about 5% space.
+
+    #define qh_NOtrace
+*/    
+
+/*----------------------------------
+  
+  qh_QHpointer
+    access global data with pointer or static structure
+
+  qh_QHpointer  = 1     access globals via a pointer to allocated memory
+                        enables qh_saveqhull() and qh_restoreqhull()
+			costs about 8% in time and 2% in space
+
+		= 0     qh_qh and qh_qhstat are static data structures
+		        only one instance of qhull() can be active at a time
+			default value
+
+  notes:
+    all global variables for qhull are in qh, qhmem, and qhstat
+    qh is defined in qhull.h
+    qhmem is defined in mem.h
+    qhstat is defined in stat.h
+
+  see:
+    user_eg.c for an example
+*/
+#define qh_QHpointer 0
+#if 0  /* sample code */
+    qhT *oldqhA, *oldqhB;
+
+    exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+    /* use results from first call to qh_new_qhull */
+    oldqhA= qh_save_qhull();
+    exitcode= qh_new_qhull (dimB, numpointsB, pointsB, ismalloc,
+                      flags, outfile, errfile); 
+    /* use results from second call to qh_new_qhull */
+    oldqhB= qh_save_qhull();
+    qh_restore_qhull (&oldqhA);
+    /* use results from first call to qh_new_qhull */
+    qh_freeqhull (qh_ALL);  /* frees all memory used by first call */
+    qh_restore_qhull (&oldqhB);
+    /* use results from second call to qh_new_qhull */
+    qh_freeqhull (!qh_ALL); /* frees long memory used by second call */
+    qh_memfreeshort (&curlong, &totlong);  /* frees short memory and memory allocator */
+#endif
+
+/*----------------------------------
+ 
+  qh_QUICKhelp        
+    =1 to use abbreviated help messages, e.g., for degenerate inputs
+*/
+#define qh_QUICKhelp    0  
+
+/* ============ -merge constants- ====================
+
+   These constants effect facet merging.  You probably will not need
+   to modify these.  They effect the performance of facet merging.
+*/
+
+/*----------------------------------
+  
+  qh_DIMmergeVertex
+    max dimension for vertex merging (it is not effective in high-d)
+*/
+#define qh_DIMmergeVertex 6
+
+/*----------------------------------
+  
+  qh_DIMreduceBuild
+     max dimension for vertex reduction during build (slow in high-d)
+*/
+#define qh_DIMreduceBuild 5
+
+/*----------------------------------
+     
+  qh_BESTcentrum
+     if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster)
+     else, qh_findbestneighbor() tests all vertices (much better merges)
+
+  qh_BESTcentrum2
+     if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums
+*/
+#define qh_BESTcentrum 20
+#define qh_BESTcentrum2 2
+
+/*----------------------------------
+  
+  qh_BESTnonconvex
+    if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges.
+    
+  notes:
+    It is needed because qh_findbestneighbor is slow for large facets
+*/
+#define qh_BESTnonconvex 15 
+
+/*----------------------------------
+  
+  qh_MAXnewmerges
+    if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums.
+     
+  notes:
+    It is needed because postmerge can merge many facets at once
+*/
+#define qh_MAXnewmerges 2
+
+/*----------------------------------
+  
+  qh_MAXnewcentrum
+    if <= dim+n vertices (n approximates the number of merges),
+      reset the centrum in qh_updatetested() and qh_mergecycle_facets()
+    
+  notes:
+    needed to reduce cost and because centrums may move too much if 
+    many vertices in high-d
+*/
+#define qh_MAXnewcentrum 5
+
+/*----------------------------------
+  
+  qh_COPLANARratio
+    for 3-d+ merging, qh.MINvisible is n*premerge_centrum
+
+  notes:
+    for non-merging, it's DISTround
+*/
+#define qh_COPLANARratio 3
+
+/*----------------------------------
+  
+  qh_DISToutside
+    When is a point clearly outside of a facet?  
+    Stops search in qh_findbestnew or qh_partitionall
+    qh_findbest uses qh.MINoutside since since it is only called if no merges.
+     
+  notes:
+    'Qf' always searches for best facet
+    if !qh.MERGING, same as qh.MINoutside. 
+    if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved
+      [Note: Zdelvertextot occurs normally with interior points]
+            RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv
+    When there is a sharp edge, need to move points to a
+    clearly good facet; otherwise may be lost in another partitioning.
+    if too big then O(n^2) behavior for partitioning in cone
+    if very small then important points not processed
+    Needed in qh_partitionall for
+      RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv
+    Needed in qh_findbestnew for many instances of
+      RBOX 1000 s Z1 G1e-13 t | QHULL Tv
+
+  See:  
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \
+     fmax_((qh MERGING ? 2 : 1)*qh MINoutside, qh max_outside))
+
+/*----------------------------------
+  
+  qh_RATIOnearinside
+    ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for
+    qh_check_maxout().  
+  
+  notes:
+    This is overkill since do not know the correct value.
+    It effects whether 'Qc' reports all coplanar points
+    Not used for 'd' since non-extreme points are coplanar
+*/
+#define qh_RATIOnearinside 5
+
+/*----------------------------------
+  
+  qh_SEARCHdist
+    When is a facet coplanar with the best facet?  
+    qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
+
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \
+      (qh max_outside + 2 * qh DISTround + fmax_( qh MINvisible, qh MAXcoplanar)));
+
+/*----------------------------------
+  
+  qh_USEfindbestnew
+     Always use qh_findbestnew for qh_partitionpoint, otherwise use
+     qh_findbestnew if merged new facet or sharpnewfacets.
+  
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50)
+
+/*----------------------------------
+  
+  qh_WIDEcoplanar
+    n*MAXcoplanar or n*MINvisible for a WIDEfacet 
+    
+    if vertex is further than qh.WIDEfacet from the hyperplane
+    then its ridges are not counted in computing the area, and
+    the facet's centrum is frozen. 
+    
+  notes:
+   qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar,
+      qh_WIDEcoplanar * qh.MINvisible);
+*/
+#define qh_WIDEcoplanar 6
+
+/*----------------------------------
+  
+  qh_MAXnarrow
+    max. cosine in initial hull that sets qh.NARROWhull
+       
+  notes:
+    If qh.NARROWhull, the initial partition does not make 
+    coplanar points.  If narrow, a coplanar point can be 
+    coplanar to two facets of opposite orientations and
+    distant from the exact convex hull.
+
+    Conservative estimate.  Don't actually see problems until it is -1.0
+*/
+#define qh_MAXnarrow -0.99999999
+
+/*----------------------------------
+  
+  qh_WARNnarrow
+    max. cosine in initial hull to warn about qh.NARROWhull
+      
+  notes:
+    this is a conservative estimate.  
+    Don't actually see problems until it is -1.0.  See qh-impre.htm
+*/
+#define qh_WARNnarrow -0.999999999999999
+
+/*----------------------------------
+  
+  qh_ZEROdelaunay
+    a zero Delaunay facet occurs for input sites coplanar with their convex hull
+    the last normal coefficient of a zero Delaunay facet is within
+        qh_ZEROdelaunay * qh.ANGLEround of 0
+      
+  notes:
+    qh_ZEROdelaunay does not allow for joggled input ('QJ').
+
+    You can avoid zero Delaunay facets by surrounding the input with a box.
+
+    Use option 'PDk:-n' to explicitly define zero Delaunay facets
+      k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation)
+      n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12')
+*/
+#define qh_ZEROdelaunay 2
+
+#endif /* qh_DEFuser */
+
+
+
diff --git a/extern/qhull/make/msvc_7_0/qhull.vcproj b/extern/qhull/make/msvc_7_0/qhull.vcproj
new file mode 100644
index 00000000000..1b754d8e076
--- /dev/null
+++ b/extern/qhull/make/msvc_7_0/qhull.vcproj
@@ -0,0 +1,677 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/qhull/src/Make-config.sh b/extern/qhull/src/Make-config.sh
new file mode 100755
index 00000000000..90bbb958599
--- /dev/null
+++ b/extern/qhull/src/Make-config.sh
@@ -0,0 +1,285 @@
+#!/bin/sh -e
+#
+# Make-config.sh
+#
+#     Setup for Debian build
+#
+#     Writes configure.in and Makefile.am files
+#     and runs automake and autoconfig
+#
+#     Use 'make dist' to build Unix distribution.
+#     Use 'configure; make' to build Qhull
+#
+#note:
+#     'configure; make' does not work under cygwin.
+#	src/unix.c:354: variable 'qh_qh' can't be auto-imported.
+#	Please read the documentation for ld's --enable-auto-import for details.
+
+###################################################
+###########  ../configure.in ######################
+###################################################
+
+echo Create ../configure.in
+cat >../configure.in <<\HERE-CONFIGURE
+dnl configure.in for the qhull package
+dnl Author: Rafael Laboissiere 
+dnl Created: Mon Dec  3 21:36:21 CET 2001
+
+AC_INIT(src/qhull.c)
+AM_INIT_AUTOMAKE(qhull, 2002.1)
+
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+AC_OUTPUT([Makefile src/Makefile html/Makefile eg/Makefile])
+
+HERE-CONFIGURE
+
+###################################################
+###########  ../Makefile.am #######################
+###################################################
+
+echo Create ../Makefile.am
+cat >../Makefile.am <<\HERE-TOP
+### Makefile.am for the qhull package (main)
+### Author: Rafael Laboissiere 
+### Created: Mon Dec  3 21:36:21 CET 2001
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+
+# which:
+doc_DATA = \
+  Announce.txt \
+  COPYING.txt \
+  README.txt \
+  REGISTER.txt
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+  $(doc_DATA) \
+  File_id.diz \
+  QHULL-GO.pif
+
+### Subdirectories for Automaking
+
+SUBDIRS = src html eg
+
+HERE-TOP
+
+###################################################
+###########  ../eg/Makefile.am ####################
+###################################################
+
+echo Create ../eg/Makefile.am
+cat >../eg/Makefile.am <<\HERE-AM
+### Makefile.am for the qhull package (eg)
+### Author: Rafael Laboissiere 
+### Created: Mon Dec  3 21:36:21 CET 2001
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+examplesdir = $(docdir)/examples
+
+# which:
+examples_DATA = \
+  q_eg \
+  q_egtest \
+  q_test \
+  Qhull-go.bat \
+  q_test.bat
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = $(examples_DATA)
+
+HERE-AM
+
+###################################################
+###########  ../html/Makefile.am ##################
+###################################################
+
+echo Create ../html/Makefile.am
+cat >../html/Makefile.am <<\HERE-HTML
+### Makefile.am for the qhull package (html)
+### Author: Rafael Laboissiere 
+### Created: Mon Dec  3 21:36:21 CET 2001
+
+### Man pages (trick to get around .man extension)
+
+%.1: %.man
+	cp $< $@
+CLEANFILES = *.1
+man_MANS = rbox.1 qhull.1
+
+### Documentation files
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+htmldir = $(docdir)/html
+
+# which:
+html_DATA = \
+  index.htm \
+  qconvex.htm \
+  qdelau_f.htm \
+  qdelaun.htm \
+  qh--4d.gif \
+  qh--cone.gif \
+  qh--dt.gif \
+  qh--geom.gif \
+  qh--half.gif \
+  qh--rand.gif \
+  qh-eg.htm \
+  qh-faq.htm \
+  qh-get.htm \
+  qh-home.htm \
+  qh-impre.htm \
+  qh-in.htm \
+  qh-optc.htm \
+  qh-optf.htm \
+  qh-optg.htm \
+  qh-opto.htm \
+  qh-optp.htm \
+  qh-optq.htm \
+  qh-optt.htm \
+  qh-quick.htm \
+  qhalf.htm \
+  qhull.htm \
+  qvoron_f.htm \
+  qvoronoi.htm \
+  rbox.htm
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+  $(html_DATA) \
+  qhull.man \
+  qhull.txt \
+  rbox.man \
+  rbox.txt
+
+HERE-HTML
+
+###################################################
+###########  ../src/Makefile.am ###################
+###################################################
+
+echo Create ../src/Makefile.am
+cat >../src/Makefile.am <<\HERE-SRC
+### Makefile.am for the qhull package (src)
+### Author: Rafael Laboissiere 
+### Created: Mon Dec  3 21:36:21 CET 2001
+
+### Shared Library
+
+# to:
+lib_LTLIBRARIES = libqhull.la
+
+# from:
+libqhull_la_SOURCES = \
+  user.c \
+  global.c \
+  stat.c \
+  io.c \
+  geom2.c \
+  poly2.c \
+  merge.c \
+  qhull.c \
+  geom.c \
+  poly.c \
+  qset.c \
+  mem.c
+
+# how:
+libqhull_la_LDFLAGS = -version-info 0:0:0 -lm
+
+### Utility programs
+
+# to:
+bin_PROGRAMS = qhull rbox qconvex qdelaunay qvoronoi qhalf
+
+# from:
+qhull_SOURCES = unix.c
+rbox_SOURCES = rbox.c
+qconvex_SOURCES = qconvex.c
+qdelaunay_SOURCES = qdelaun.c
+qvoronoi_SOURCES = qvoronoi.c
+qhalf_SOURCES = qhalf.c
+
+# how:
+qhull_LDADD = libqhull.la
+rbox_LDADD = libqhull.la
+qconvex_LDADD = libqhull.la
+qdelaunay_LDADD = libqhull.la
+qvoronoi_LDADD = libqhull.la
+qhalf_LDADD = libqhull.la
+
+### Include files
+
+pkginclude_HEADERS = \
+  geom.h \
+  mem.h \
+  poly.h \
+  qhull_a.h \
+  stat.h \
+  io.h \
+  merge.h \
+  qhull.h  \
+  qset.h \
+  user.h
+
+
+### Example programs
+
+# to:
+docdir = $(prefix)/share/doc/$(PACKAGE)
+examplesdir = $(docdir)/examples
+
+# which:
+examples_DATA = \
+  user_eg.c \
+  user_eg2.c \
+  qhull_interface.cpp \
+  Makefile.txt \
+  Make-config.sh \
+  MBorland
+
+doc_DATA = Changes.txt \
+    index.htm \
+    qh-geom.htm \
+    qh-globa.htm \
+    qh-io.htm \
+    qh-mem.htm \
+    qh-merge.htm \
+    qh-poly.htm \
+    qh-qhull.htm \
+    qh-set.htm \
+    qh-stat.htm \
+    qh-user.htm
+
+
+### Extra files to be included in the tarball
+
+EXTRA_DIST = \
+  $(doc_DATA) \
+  $(examples_DATA)
+
+HERE-SRC
+
+###################################################
+###########  run automake autoconf ################
+###################################################
+
+
+echo Run automake, libtoolize, and autoconf
+cd ..; aclocal &&\
+  automake --foreign --add-missing --force-missing && \
+  libtoolize --force && \
+  autoconf
+
diff --git a/extern/qhull/src/Makefile b/extern/qhull/src/Makefile
new file mode 100644
index 00000000000..a4f2aa4b5b9
--- /dev/null
+++ b/extern/qhull/src/Makefile
@@ -0,0 +1,59 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = qhull
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../include
+
+CSRCS = user.c global.c stat.c io.c geom2.c poly2.c \
+       merge.c qhull.c geom.c poly.c qset.c mem.c
+CCSRCS = 
+include nan_compile.mk 
+
+install: all debug
+	@[ -d $(NAN_QHULL) ] || mkdir -p $(NAN_QHULL)
+	@[ -d $(NAN_QHULL)/include/qhull ] || mkdir -p $(NAN_QHULL)/include/qhull
+	@[ -d $(NAN_QHULL)/lib ] || mkdir -p $(NAN_QHULL)/lib
+	@[ -d $(NAN_QHULL)/lib/debug ] || mkdir -p $(NAN_QHULL)/lib/debug
+	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/lib$(LIBNAME).a $(NAN_QHULL)/lib/
+#	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/debug/lib$(LIBNAME).a $(NAN_QHULL)/lib/debug/
+ifeq ($(OS),darwin)
+	ranlib $(NAN_QHULL)/lib/lib$(LIBNAME).a
+#	ranlib $(NAN_QHULL)/lib/debug/lib$(LIBNAME).a
+endif
+	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh ../include/qhull/*.h $(NAN_QHULL)/include/qhull
+
+
diff --git a/extern/qhull/src/Makefile.txt b/extern/qhull/src/Makefile.txt
new file mode 100644
index 00000000000..e87b66b49bc
--- /dev/null
+++ b/extern/qhull/src/Makefile.txt
@@ -0,0 +1,190 @@
+# Unix Makefile for qhull and rbox
+#
+#       see README.txt
+#
+#       make           to produce qhull qconvex qdelaunay qhalf qvoronoi rbox
+#       make qvoronoi  to produce qvoronoi (etc.)
+#       make qhullx    to produce qhull qconvex etc.  w/o using libqhull.a
+#       make doc       to print documentation
+#       make install   to copy qhull, rbox, qhull.1, rbox.1 to BINDIR, MANDIR
+#       make new       to rebuild qhull and rbox from source
+#
+#       make printall  to print all files
+#       make user_eg   to produce user_eg
+#       make user_eg2  to produce user_eg2
+#       make clean     to remove object files and core
+#       make cleanall  to remove all generated files
+#
+#       PRINTMAN --  command for printing manual pages
+#       PRINTC --  command for printing C files
+#       BINDIR -- directory where to copy executables
+#       MANDIR -- directory where to copy manual pages
+#       CC --     ANSI C or C++ compiler
+#       CCOPTS1 - options used to compile .c files
+#       CCOPTS2 -- options used to link .o files
+#
+#       CFILES -- .c files for printing
+#       HFILES -- .h files for printing
+#       DFILES -- documentation files
+#       MFILES -- man pages and html files
+#       TFILES -- .txt versions of html html files
+#       FILES -- all other files
+#       OBJS -- specifies the object files of libqhull.a
+#
+BINDIR  = /usr/local/bin
+MANDIR  = /usr/local/man/man1
+
+# if you do not have enscript, try a2ps or just use lpr.  The files are text.
+PRINTMAN = enscript -2rl
+PRINTC = enscript -2r
+# PRINTMAN = lpr
+# PRINTC = lpr
+
+#for Gnu's gcc compiler -O2 for optimization, -g for debugging, -Wall for check
+#
+CC     = gcc
+CCOPTS1 = -O2 -ansi 
+
+# for Sun's cc compiler, -fast or O2 for optimization, -g for debugging, -Xc for ANSI
+#CC = cc
+#CCOPTS1 = -Xc -v -fast
+
+# for Silicon Graphics cc compiler, -O2 for optimization, -g for debugging
+#CC = cc
+#CCOPTS1 = -ansi -O2
+
+# for Next cc compiler with fat executable
+#CC = cc
+#CCOPTS1 = -ansi -O2 -arch m68k -arch i386 -arch hppa
+
+# for loader, ld
+CCOPTS2 = $(CCOPTS1)
+
+# OBJS in execution frequency order.  CFILES after qhull.c are alphabetical
+OBJS = user.o global.o stat.o io.o geom2.o poly2.o \
+       merge.o qhull.o geom.o poly.o qset.o mem.o
+
+CFILES= unix.c qhull.c geom.c geom2.c global.c io.c mem.c merge.c poly.c \
+        poly2.c qset.c stat.c user.c qconvex.c qdelaun.c qhalf.c qvoronoi.c
+HFILES= user.h qhull.h qhull_a.h geom.h io.h mem.h merge.h poly.h qset.h stat.h
+TXTFILES= ../Announce.txt ../REGISTER.txt ../COPYING.txt ../README.txt Changes.txt
+DOCFILES= ../html/rbox.txt ../html/qhull.txt
+FILES=  Makefile rbox.c user_eg.c ../eg/q_test ../eg/q_egtest ../eg/q_eg
+HTMFILES= qhull.man rbox.man qh-in.htm qh-optg.htm qh-optt.htm qh-optp.htm \
+        index.htm qh-quick.htm qh-impre.htm qh-eg.htm \
+        qh-optc.htm qh-opto.htm qh-optf.htm qh-optq.htm \
+	    qh-c.htm qh-faq.htm qhull.htm qconvex.htm qdelaun.htm \
+		qh-geom.htm qh-globa.htm qh-io.htm qh-mem.htm qh-merge.htm \
+		qh-poly.htm qh-qhull.htm qh-set.htm qh-stat.htm qh-user.htm \
+		qdelau_f.htm qhalf.htm qvoronoi.htm qvoron_f.htm rbox.htm 
+
+all: rbox qconvex qdelaunay qhalf qvoronoi qhull
+
+unix.o:   qhull.h user.h mem.h
+qconvex.o:   qhull.h user.h mem.h
+qdelaun.o:   qhull.h user.h mem.h
+qhalf.o:   qhull.h user.h mem.h
+qvoronoi.o:   qhull.h user.h mem.h
+qhull.o:  $(HFILES)
+geom.o:   $(HFILES)
+geom2.o:  $(HFILES)
+global.o: $(HFILES)
+io.o:     $(HFILES)
+mem.o:    mem.h 
+merge.o:  $(HFILES)
+poly.o:   $(HFILES)
+poly2.o:  $(HFILES)
+qset.o:   qset.h mem.h 
+stat.o:   $(HFILES)
+user.o:   $(HFILES)
+
+.c.o:
+	$(CC) -c $(CCOPTS1) $<
+
+clean:
+	rm -f *.o ../core qconvex qdelaunay qhalf qvoronoi qhull libqhull.a \
+	    *.exe
+
+cleanall: clean
+	rm -f *~ ../rbox ../qhull ../qhalf ../qconvex ../qdelaunay ../qhalf\
+	   ../qvoronoi ../user_eg ../user_eg2 ../*.exe >/dev/null
+
+doc: 
+	$(PRINTMAN) $(TXTFILES) $(DOCFILES)
+
+install: all 
+	cp ../qconvex $(BINDIR)/qconvex
+	cp ../qdelaunay $(BINDIR)/qdelaunay
+	cp ../qhalf $(BINDIR)/qhalf
+	cp ../qhull $(BINDIR)/qhull
+	cp ../qvoronoi $(BINDIR)/qvoronoi
+	cp ../rbox $(BINDIR)/rbox
+	cp ../html/qhull.man $(MANDIR)/qhull.1
+	cp ../html/rbox.man $(MANDIR)/rbox.1
+
+new:    cleanall all
+
+printall: doc printh printc printf
+
+printh:
+	$(PRINTC) $(HFILES)
+
+printc:
+	$(PRINTC) $(CFILES)
+
+printf:
+	$(PRINTC) $(FILES) 
+
+libqhull.a: $(OBJS)
+	@echo if 'ar' or 'ranlib' fails, try 'make qhullx'
+	ar r libqhull.a $(OBJS)
+	@echo the next line may need to be removed.
+	-test -x /bin/ranlib -o -x /usr/bin/ranlib && ranlib libqhull.a
+
+# don't use ../qconvex.  Does not work on Red Hat Linux
+qconvex: qconvex.o libqhull.a
+	$(CC) -o qconvex $(CCOPTS2) qconvex.o -L. -lqhull -lm 
+	cp qconvex ..
+
+qdelaunay: qdelaun.o libqhull.a
+	$(CC) -o qdelaunay $(CCOPTS2) qdelaun.o -L. -lqhull -lm 
+	cp qdelaunay ..
+
+qhalf: qhalf.o libqhull.a
+	$(CC) -o qhalf $(CCOPTS2) qhalf.o -L. -lqhull -lm 
+	cp qhalf ..
+
+qvoronoi: qvoronoi.o libqhull.a
+	$(CC) -o qvoronoi $(CCOPTS2) qvoronoi.o -L. -lqhull -lm 
+	cp qvoronoi ..
+
+qhull: unix.o libqhull.a
+	$(CC) -o qhull $(CCOPTS2) unix.o -L. -lqhull -lm 
+	cp qhull ..
+	-chmod +x ../eg/q_test ../eg/q_eg ../eg/q_egtest
+	-cd ..; ./rbox D4 | ./qhull
+
+# compile qhull without using libqhull.a
+qhullx: qconvex.o qdelaun.o qhalf.o qvoronoi.o unix.o $(OBJS)
+	$(CC) -o qconvex $(CCOPTS2) qconvex.o $(OBJS) -lm 
+	$(CC) -o qdelaunay $(CCOPTS2) qdelaun.o $(OBJS) -lm 
+	$(CC) -o qhalf $(CCOPTS2) qhalf.o $(OBJS) -lm 
+	$(CC) -o qvoronoi $(CCOPTS2) qvoronoi.o $(OBJS) -lm 
+	$(CC) -o qhull $(CCOPTS2) unix.o $(OBJS) -lm 
+	cp qconvex qdelaunay qhalf qvoronoi qhull ..
+	-chmod +x ../eg/q_test ../eg/q_eg ../eg/q_egtest
+	-cd ..; ./rbox D4 | ./qhull
+
+rbox: rbox.o
+	$(CC) -o rbox rbox.o $(CCOPTS2) -lm
+	cp rbox ..
+
+user_eg: user_eg.o libqhull.a 
+	$(CC)  -o user_eg $(CCOPTS2) user_eg.o  -L. -lqhull -lm 
+	cp user_eg ..
+
+user_eg2: user_eg2.o libqhull.a 
+	$(CC)  -o user_eg2 $(CCOPTS2) user_eg2.o  -L. -lqhull -lm 
+	cp user_eg2 ..
+
+# end of Makefile
diff --git a/extern/qhull/src/geom.c b/extern/qhull/src/geom.c
new file mode 100644
index 00000000000..ca4bcaf2541
--- /dev/null
+++ b/extern/qhull/src/geom.c
@@ -0,0 +1,1230 @@
+/*
  ---------------------------------
+
+   geom.c 
+   geometric routines of qhull
+
+   see qh-geom.htm and geom.h
+
+   copyright (c) 1993-2002 The Geometry Center        
+
+   infrequent code goes into geom2.c
+*/
+   
+#include "qhull_a.h"
+   
+/*---------------------------------
+  
+  qh_distplane( point, facet, dist )
+    return distance from point to facet
+
+  returns:
+    dist
+    if qh.RANDOMdist, joggles result
+  
+  notes:  
+    dist > 0 if point is above facet (i.e., outside)
+    does not error (for sortfacets)
+    
+  see:
+    qh_distnorm in geom2.c
+*/
+void qh_distplane (pointT *point, facetT *facet, realT *dist) {
+  coordT *normal= facet->normal, *coordp, randr;
+  int k;
+  
+  switch(qh hull_dim){
+  case 2:
+    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
+    break;
+  case 3:
+    *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
+    break;
+  case 4:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
+    break;
+  case 5:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
+    break;
+  case 6:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
+    break;
+  case 7:  
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
+    break;
+  case 8:
+    *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
+    break;
+  default:
+    *dist= facet->offset;
+    coordp= point;
+    for (k= qh hull_dim; k--; )
+      *dist += *coordp++ * *normal++;
+    break;
+  }
+  zinc_(Zdistplane);
+  if (!qh RANDOMdist && qh IStracing < 4)
+    return;
+  if (qh RANDOMdist) {
+    randr= qh_RANDOMint;
+    *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *
+      qh RANDOMfactor * qh MAXabs_coord;
+  }
+  if (qh IStracing >= 4) {
+    fprintf (qh ferr, "qh_distplane: ");
+    fprintf (qh ferr, qh_REAL_1, *dist);
+    fprintf (qh ferr, "from p%d to f%d\n", qh_pointid(point), facet->id);
+  }
+  return;
+} /* distplane */
+
+
+/*---------------------------------
+  
+  qh_findbest( point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart )
+    find facet that is furthest below a point 
+    for upperDelaunay facets
+      returns facet only if !qh_NOupper and clearly above
+
+  input:
+    starts search at 'startfacet' (can not be flipped)
+    if !bestoutside (qh_ALL), stops at qh.MINoutside
+
+  returns:
+    best facet (reports error if NULL)
+    early out if isoutside defined and bestdist > qh.MINoutside
+    dist is distance to facet
+    isoutside is true if point is outside of facet
+    numpart counts the number of distance tests
+
+  see also:
+    qh_findbestnew()
+    
+  notes:
+    If merging (testhorizon), searches horizon facets of coplanar best facets because
+    after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d
+      avoid calls to distplane, function calls, and real number operations.
+    caller traces result
+    Optimized for outside points.   Tried recording a search set for qh_findhorizon.
+    Made code more complicated.
+
+  when called by qh_partitionvisible():
+    indicated by qh_ISnewfacets
+    qh.newfacet_list is list of simplicial, new facets
+    qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew)
+    qh.bestfacet_notsharp set if qh_sharpnewfacets returns False
+
+  when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(), 
+                 qh_check_bestdist(), qh_addpoint()
+    indicated by !qh_ISnewfacets
+    returns best facet in neighborhood of given facet
+      this is best facet overall if dist > -   qh.MAXcoplanar 
+        or hull has at least a "spherical" curvature
+
+  design:
+    initialize and test for early exit
+    repeat while there are better facets
+      for each neighbor of facet
+        exit if outside facet found
+	test for better facet
+    if point is inside and partitioning
+      test for new facets with a "sharp" intersection
+      if so, future calls go to qh_findbestnew()
+    test horizon facets
+*/
+facetT *qh_findbest (pointT *point, facetT *startfacet, 
+		     boolT bestoutside, boolT isnewfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart) {
+  realT bestdist= -REALmax/2 /* avoid underflow */;
+  facetT *facet, *neighbor, **neighborp, *bestfacet= NULL;
+ /* facetT *bestfacet_all= startfacet; */
+  int oldtrace= qh IStracing;
+  unsigned int visitid= ++qh visit_id;
+  int numpartnew=0;
+  boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
+
+  zinc_(Zfindbest);
+  if (qh IStracing >= 3 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid (point))) {
+    if (qh TRACElevel > qh IStracing)
+      qh IStracing= qh TRACElevel;
+    fprintf (qh ferr, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g\n",
+	     qh_pointid(point), startfacet->id, isnewfacets, bestoutside, qh MINoutside);
+    fprintf(qh ferr, "  testhorizon? %d noupper? %d", testhorizon, noupper);
+    fprintf (qh ferr, "  Last point added was p%d.", qh furthest_id);
+    fprintf(qh ferr, "  Last merge was #%d.  max_outside %2.2g\n", zzval_(Ztotmerge), qh max_outside);
+  }
+  if (isoutside)
+    *isoutside= True;
+  if (!startfacet->flipped) {  /* test startfacet */
+    *numpart= 1;
+    qh_distplane (point, startfacet, dist);  /* this code is duplicated below */
+    if (!bestoutside && *dist >= qh MINoutside 
+    && (!startfacet->upperdelaunay || !noupper)) {
+      bestfacet= startfacet;
+      goto LABELreturn_best;
+    }
+    bestdist= *dist;
+    if (!startfacet->upperdelaunay) {
+      bestfacet= startfacet;
+    } 
+  }else 
+    *numpart= 0;
+  startfacet->visitid= visitid;
+  facet= startfacet;
+  while (facet) {
+    trace4((qh ferr, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n", 
+                facet->id, bestdist, getid_(bestfacet)));
+    FOREACHneighbor_(facet) {
+      if (!neighbor->newfacet && isnewfacets)
+        continue;
+      if (neighbor->visitid == visitid)
+	continue;
+      neighbor->visitid= visitid;
+      if (!neighbor->flipped) {  /* code duplicated above */
+	(*numpart)++;
+	qh_distplane (point, neighbor, dist);
+	if (*dist > bestdist) {
+	  if (!bestoutside && *dist >= qh MINoutside 
+	  && (!neighbor->upperdelaunay || !noupper)) {
+	    bestfacet= neighbor;
+	    goto LABELreturn_best;
+	  }
+	  if (!neighbor->upperdelaunay) {
+	    bestfacet= neighbor;
+	    bestdist= *dist;
+	  }
+	  break; /* switch to neighor */
+	} /* end of *dist>bestdist */
+      } /* end of !flipped */
+    } /* end of FOREACHneighbor */
+    facet= neighbor;  /* non-NULL only if *dist>bestdist */
+  } /* end of while facet (directed search) */
+  if (isnewfacets) { 
+    if (!bestfacet) {
+      bestdist= -REALmax/2; 
+      bestfacet= qh_findbestnew (point, startfacet->next, &bestdist, bestoutside, isoutside, &numpartnew);
+      testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
+    }else if (!qh findbest_notsharp && bestdist < - qh DISTround) {
+      if (qh_sharpnewfacets()) { 
+	/* seldom used, qh_findbestnew will retest all facets */
+	zinc_(Zfindnewsharp);
+	bestfacet= qh_findbestnew (point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew);
+	testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */
+	qh findbestnew= True;
+      }else
+	qh findbest_notsharp= True;
+    }
+  }
+  if (!bestfacet) {
+    fprintf(qh ferr, "\n\
+qh_findbest: all neighbors of facet %d are flipped or upper Delaunay.\n\
+Please report this error to qhull_bug@geom.umn.edu with the input and all of the output.\n",
+       startfacet->id);
+    qh_errexit (qh_ERRqhull, startfacet, NULL);
+  }
+  if (testhorizon) 
+    bestfacet= qh_findbesthorizon (!qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew);
+  *dist= bestdist;
+  if (isoutside && bestdist < qh MINoutside)
+    *isoutside= False;
+LABELreturn_best:
+  zadd_(Zfindbesttot, *numpart);
+  zmax_(Zfindbestmax, *numpart);
+  (*numpart) += numpartnew;
+  qh IStracing= oldtrace;
+  return bestfacet;
+}  /* findbest */
+
+
+/*---------------------------------
+  
+  qh_findbesthorizon( qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart )
+    search coplanar and better horizon facets from startfacet/bestdist
+    ischeckmax turns off statistics and minsearch update
+    all arguments must be initialized
+  returns (ischeckmax):
+    best facet
+  returns (!ischeckmax):
+    best facet that is not upperdelaunay
+    allows upperdelaunay that is clearly outside
+  returns:
+    bestdist is distance to bestfacet
+    numpart -- updates number of distance tests
+
+  notes:
+    no early out -- use qh_findbest() or qh_findbestnew()
+    Searches coplanar or better horizon facets
+
+  when called by qh_check_maxout() (qh_IScheckmax)
+    startfacet must be closest to the point
+      Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum
+      even though other facets are below the point.
+    updates facet->maxoutside for good, visited facets
+    may return NULL
+
+    searchdist is qh.max_outside + 2 * DISTround
+      + max( MINvisible('Vn'), MAXcoplanar('Un'));
+    This setting is a guess.  It must be at least max_outside + 2*DISTround 
+    because a facet may have a geometric neighbor across a vertex
+
+  design:
+    for each horizon facet of coplanar best facets
+      continue if clearly inside
+      unless upperdelaunay or clearly outside
+         update best facet
+*/
+facetT *qh_findbesthorizon (boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) {
+  facetT *bestfacet= startfacet;
+  realT dist;
+  facetT *neighbor, **neighborp, *facet;
+  facetT *nextfacet= NULL; /* optimize last facet of coplanarset */
+  int numpartinit= *numpart, coplanarset_size;
+  unsigned int visitid= ++qh visit_id;
+  boolT newbest= False; /* for tracing */
+  realT minsearch, searchdist;  /* skip facets that are too far from point */
+
+  if (!ischeckmax) {
+    zinc_(Zfindhorizon);
+  }else {
+#if qh_MAXoutside
+    if ((!qh ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside)
+      startfacet->maxoutside= *bestdist;
+#endif
+  }
+  searchdist= qh_SEARCHdist; /* multiple of qh.max_outside and precision constants */
+  minsearch= *bestdist - searchdist;
+  if (ischeckmax) {
+    /* Always check coplanar facets.  Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */
+    minimize_(minsearch, -searchdist);
+  }
+  coplanarset_size= 0;
+  facet= startfacet;
+  while (True) {
+    trace4((qh ferr, "qh_findbesthorizon: neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g searchdist %2.2g\n", 
+		facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper,
+		minsearch, searchdist));
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == visitid) 
+	continue;
+      neighbor->visitid= visitid;
+      if (!neighbor->flipped) { 
+	qh_distplane (point, neighbor, &dist);
+	(*numpart)++;
+	if (dist > *bestdist) {
+	  if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh MINoutside)) {
+	    bestfacet= neighbor;
+	    *bestdist= dist;
+	    newbest= True;
+	    if (!ischeckmax) {
+	      minsearch= dist - searchdist;
+	      if (dist > *bestdist + searchdist) {
+		zinc_(Zfindjump);  /* everything in qh.coplanarset at least searchdist below */
+		coplanarset_size= 0;
+	      }
+	    }
+	  }
+	}else if (dist < minsearch) 
+	  continue;  /* if ischeckmax, dist can't be positive */
+#if qh_MAXoutside
+	if (ischeckmax && dist > neighbor->maxoutside)
+	  neighbor->maxoutside= dist;
+#endif      
+      } /* end of !flipped */
+      if (nextfacet) {
+	if (!coplanarset_size++) {
+	  SETfirst_(qh coplanarset)= nextfacet;
+	  SETtruncate_(qh coplanarset, 1);
+	}else
+  	  qh_setappend (&qh coplanarset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv
+						 and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv  */
+      }
+      nextfacet= neighbor;
+    } /* end of EACHneighbor */
+    facet= nextfacet;
+    if (facet) 
+      nextfacet= NULL;
+    else if (!coplanarset_size)
+      break; 
+    else if (!--coplanarset_size) {
+      facet= SETfirst_(qh coplanarset);
+      SETtruncate_(qh coplanarset, 0);
+    }else
+      facet= (facetT*)qh_setdellast (qh coplanarset);
+  } /* while True, for each facet in qh.coplanarset */
+  if (!ischeckmax) {
+    zadd_(Zfindhorizontot, *numpart - numpartinit);
+    zmax_(Zfindhorizonmax, *numpart - numpartinit);
+    if (newbest)
+      zinc_(Zparthorizon);
+  }
+  trace4((qh ferr, "qh_findbesthorizon: newbest? %d bestfacet f%d bestdist %2.2g\n", newbest, getid_(bestfacet), *bestdist));
+  return bestfacet;
+}  /* findbesthorizon */
+
+/*---------------------------------
+  
+  qh_findbestnew( point, startfacet, dist, isoutside, numpart )
+    find best newfacet for point
+    searches all of qh.newfacet_list starting at startfacet
+    searches horizon facets of coplanar best newfacets
+    searches all facets if startfacet == qh.facet_list
+  returns:
+    best new or horizon facet that is not upperdelaunay
+    early out if isoutside and not 'Qf'
+    dist is distance to facet
+    isoutside is true if point is outside of facet
+    numpart is number of distance tests
+
+  notes:
+    Always used for merged new facets (see qh_USEfindbestnew)
+    Avoids upperdelaunay facet unless (isoutside and outside)
+
+    Uses qh.visit_id, qh.coplanarset.  
+    If share visit_id with qh_findbest, coplanarset is incorrect.
+
+    If merging (testhorizon), searches horizon facets of coplanar best facets because
+    a point maybe coplanar to the bestfacet, below its horizon facet,
+    and above a horizon facet of a coplanar newfacet.  For example,
+      rbox 1000 s Z1 G1e-13 | qhull
+      rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc
+
+    qh_findbestnew() used if
+       qh_sharpnewfacets -- newfacets contains a sharp angle
+       if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew)
+
+  see also:
+    qh_partitionall() and qh_findbest()
+
+  design:
+    for each new facet starting from startfacet
+      test distance from point to facet
+      return facet if clearly outside
+      unless upperdelaunay and a lowerdelaunay exists
+         update best facet
+    test horizon facets
+*/
+facetT *qh_findbestnew (pointT *point, facetT *startfacet,
+	   realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) {
+  realT bestdist= -REALmax/2; /*, minsearch= -REALmax/2;*/
+  facetT *bestfacet= NULL, *facet;
+  int oldtrace= qh IStracing, i;
+  unsigned int visitid= ++qh visit_id;
+  realT distoutside= 0.0;
+  boolT isdistoutside; /* True if distoutside is defined */
+  boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */
+
+  if (!startfacet) {
+    if (qh MERGING)
+      fprintf(qh ferr, "qhull precision error (qh_findbestnew): merging has formed and deleted a cone of new facets.  Can not continue.\n");
+    else
+      fprintf(qh ferr, "qhull internal error (qh_findbestnew): no new facets for point p%d\n",
+      	      qh furthest_id);      
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  zinc_(Zfindnew);
+  if (qh BESToutside || bestoutside)
+    isdistoutside= False;
+  else {
+    isdistoutside= True;
+    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
+  }
+  if (isoutside)
+    *isoutside= True;
+  *numpart= 0;
+  if (qh IStracing >= 3 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid (point))) {
+    if (qh TRACElevel > qh IStracing)
+      qh IStracing= qh TRACElevel;
+    fprintf(qh ferr, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g\n",
+	     qh_pointid(point), startfacet->id, isdistoutside, distoutside);
+    fprintf(qh ferr, "  Last point added p%d visitid %d.",  qh furthest_id, visitid);
+    fprintf(qh ferr, "  Last merge was #%d.\n", zzval_(Ztotmerge));
+  }
+  /* visit all new facets starting with startfacet, maybe qh facet_list */
+  for (i= 0, facet= startfacet; i < 2; i++, facet= qh newfacet_list) {
+    FORALLfacet_(facet) {
+      if (facet == startfacet && i)
+	break;
+      facet->visitid= visitid;
+      if (!facet->flipped) {
+	qh_distplane (point, facet, dist);
+	(*numpart)++;
+	if (*dist > bestdist) {
+	  if (!facet->upperdelaunay || *dist >= qh MINoutside) {
+	    bestfacet= facet;
+	    if (isdistoutside && *dist >= distoutside)
+	      goto LABELreturn_bestnew;
+	    bestdist= *dist;
+  	  }
+	}
+      } /* end of !flipped */
+    } /* FORALLfacet from startfacet or qh newfacet_list */
+  }
+  if (testhorizon || !bestfacet)
+    bestfacet= qh_findbesthorizon (!qh_IScheckmax, point, bestfacet ? bestfacet : startfacet, 
+	                                !qh_NOupper, &bestdist, numpart);  
+  *dist= bestdist;
+  if (isoutside && *dist < qh MINoutside)
+    *isoutside= False;
+LABELreturn_bestnew:
+  zadd_(Zfindnewtot, *numpart);
+  zmax_(Zfindnewmax, *numpart);
+  trace4((qh ferr, "qh_findbestnew: bestfacet f%d bestdist %2.2g\n", getid_(bestfacet), *dist));
+  qh IStracing= oldtrace;
+  return bestfacet;
+}  /* findbestnew */
+
+/* ============ hyperplane functions -- keep code together [?] ============ */
+
+/*---------------------------------
+  
+  qh_backnormal( rows, numrow, numcol, sign, normal, nearzero )
+    given an upper-triangular rows array and a sign,
+    solve for normal equation x using back substitution over rows U
+
+  returns:
+     normal= x
+      
+     if will not be able to divzero() when normalized (qh.MINdenom_2 and qh.MINdenom_1_2),
+       if fails on last row
+         this means that the hyperplane intersects [0,..,1]
+         sets last coordinate of normal to sign
+       otherwise
+         sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0]
+         sets nearzero
+
+  notes:
+     assumes numrow == numcol-1
+
+     see Golub & van Loan 4.4-9 for back substitution
+
+     solves Ux=b where Ax=b and PA=LU
+     b= [0,...,0,sign or 0]  (sign is either -1 or +1)
+     last row of A= [0,...,0,1]
+
+     1) Ly=Pb == y=b since P only permutes the 0's of   b
+     
+  design:
+    for each row from end
+      perform back substitution
+      if near zero
+        use qh_divzero for division
+        if zero divide and not last row
+          set tail of normal to 0
+*/
+void qh_backnormal (realT **rows, int numrow, int numcol, boolT sign,
+  	coordT *normal, boolT *nearzero) {
+  int i, j;
+  coordT *normalp, *normal_tail, *ai, *ak;
+  realT diagonal;
+  boolT waszero;
+  int zerocol= -1;
+  
+  normalp= normal + numcol - 1;
+  *normalp--= (sign ? -1.0 : 1.0);
+  for(i= numrow; i--; ) {
+    *normalp= 0.0;
+    ai= rows[i] + i + 1;
+    ak= normalp+1;
+    for(j= i+1; j < numcol; j++)
+      *normalp -= *ai++ * *ak++;
+    diagonal= (rows[i])[i];
+    if (fabs_(diagonal) > qh MINdenom_2)
+      *(normalp--) /= diagonal;
+    else {
+      waszero= False;
+      *normalp= qh_divzero (*normalp, diagonal, qh MINdenom_1_2, &waszero);
+      if (waszero) {
+        zerocol= i;
+	*(normalp--)= (sign ? -1.0 : 1.0);
+	for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)
+	  *normal_tail= 0.0;
+      }else
+	normalp--;
+    }
+  }
+  if (zerocol != -1) {
+    zzinc_(Zback0);
+    *nearzero= True;
+    trace4((qh ferr, "qh_backnormal: zero diagonal at column %d.\n", i));
+    qh_precision ("zero diagonal on back substitution");
+  }
+} /* backnormal */
+
+/*---------------------------------
+  
+  qh_gausselim( rows, numrow, numcol, sign )
+    Gaussian elimination with partial pivoting
+
+  returns:
+    rows is upper triangular (includes row exchanges)
+    flips sign for each row exchange
+    sets nearzero if pivot[k] < qh.NEARzero[k], else clears it
+
+  notes:
+    if nearzero, the determinant's sign may be incorrect.
+    assumes numrow <= numcol
+
+  design:
+    for each row
+      determine pivot and exchange rows if necessary
+      test for near zero
+      perform gaussian elimination step
+*/
+void qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
+  realT *ai, *ak, *rowp, *pivotrow;
+  realT n, pivot, pivot_abs= 0.0, temp;
+  int i, j, k, pivoti, flip=0;
+  
+  *nearzero= False;
+  for(k= 0; k < numrow; k++) {
+    pivot_abs= fabs_((rows[k])[k]);
+    pivoti= k;
+    for(i= k+1; i < numrow; i++) {
+      if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
+	pivot_abs= temp;
+	pivoti= i;
+      }
+    }
+    if (pivoti != k) {
+      rowp= rows[pivoti]; 
+      rows[pivoti]= rows[k]; 
+      rows[k]= rowp; 
+      *sign ^= 1;
+      flip ^= 1;
+    }
+    if (pivot_abs <= qh NEARzero[k]) {
+      *nearzero= True;
+      if (pivot_abs == 0.0) {   /* remainder of column == 0 */
+	if (qh IStracing >= 4) {
+	  fprintf (qh ferr, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh DISTround);
+	  qh_printmatrix (qh ferr, "Matrix:", rows, numrow, numcol);
+	}
+	zzinc_(Zgauss0);
+        qh_precision ("zero pivot for Gaussian elimination");
+	goto LABELnextcol;
+      }
+    }
+    pivotrow= rows[k] + k;
+    pivot= *pivotrow++;  /* signed value of pivot, and remainder of row */
+    for(i= k+1; i < numrow; i++) {
+      ai= rows[i] + k;
+      ak= pivotrow;
+      n= (*ai++)/pivot;   /* divzero() not needed since |pivot| >= |*ai| */
+      for(j= numcol - (k+1); j--; )
+	*ai++ -= n * *ak++;
+    }
+  LABELnextcol:
+    ;
+  }
+  wmin_(Wmindenom, pivot_abs);  /* last pivot element */
+  if (qh IStracing >= 5)
+    qh_printmatrix (qh ferr, "qh_gausselem: result", rows, numrow, numcol);
+} /* gausselim */
+
+
+/*---------------------------------
+  
+  qh_getangle( vect1, vect2 )
+    returns the dot product of two vectors
+    if qh.RANDOMdist, joggles result
+
+  notes:
+    the angle may be > 1.0 or < -1.0 because of roundoff errors
+
+*/
+realT qh_getangle(pointT *vect1, pointT *vect2) {
+  realT angle= 0, randr;
+  int k;
+
+  for(k= qh hull_dim; k--; )
+    angle += *vect1++ * *vect2++;
+  if (qh RANDOMdist) {
+    randr= qh_RANDOMint;
+    angle += (2.0 * randr / qh_RANDOMmax - 1.0) *
+      qh RANDOMfactor;
+  }
+  trace4((qh ferr, "qh_getangle: %2.2g\n", angle));
+  return(angle);
+} /* getangle */
+
+
+/*---------------------------------
+  
+  qh_getcenter( vertices )
+    returns arithmetic center of a set of vertices as a new point
+
+  notes:
+    allocates point array for center
+*/
+pointT *qh_getcenter(setT *vertices) {
+  int k;
+  pointT *center, *coord;
+  vertexT *vertex, **vertexp;
+  int count= qh_setsize(vertices);
+
+  if (count < 2) {
+    fprintf (qh ferr, "qhull internal error (qh_getcenter): not defined for %d points\n", count);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  center= (pointT *)qh_memalloc(qh normal_size);
+  for (k=0; k < qh hull_dim; k++) {
+    coord= center+k;
+    *coord= 0.0;
+    FOREACHvertex_(vertices)
+      *coord += vertex->point[k];
+    *coord /= count;
+  }
+  return(center);
+} /* getcenter */
+
+
+/*---------------------------------
+  
+  qh_getcentrum( facet )
+    returns the centrum for a facet as a new point
+
+  notes:
+    allocates the centrum
+*/
+pointT *qh_getcentrum(facetT *facet) {
+  realT dist;
+  pointT *centrum, *point;
+
+  point= qh_getcenter(facet->vertices);
+  zzinc_(Zcentrumtests);
+  qh_distplane (point, facet, &dist);
+  centrum= qh_projectpoint(point, facet, dist);
+  qh_memfree(point, qh normal_size);
+  trace4((qh ferr, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
+	  facet->id, qh_setsize(facet->vertices), dist));
+  return centrum;
+} /* getcentrum */
+
+
+/*---------------------------------
+  
+  qh_getdistance( facet, neighbor, mindist, maxdist )
+    returns the maxdist and mindist distance of any vertex from neighbor
+
+  returns:
+    the max absolute value
+
+  design:
+    for each vertex of facet that is not in neighbor
+      test the distance from vertex to neighbor
+*/
+realT qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist) {
+  vertexT *vertex, **vertexp;
+  realT dist, maxd, mind;
+  
+  FOREACHvertex_(facet->vertices)
+    vertex->seen= False;
+  FOREACHvertex_(neighbor->vertices)
+    vertex->seen= True;
+  mind= 0.0;
+  maxd= 0.0;
+  FOREACHvertex_(facet->vertices) {
+    if (!vertex->seen) {
+      zzinc_(Zbestdist);
+      qh_distplane(vertex->point, neighbor, &dist);
+      if (dist < mind)
+	mind= dist;
+      else if (dist > maxd)
+	maxd= dist;
+    }
+  }
+  *mindist= mind;
+  *maxdist= maxd;
+  mind= -mind;
+  if (maxd > mind)
+    return maxd;
+  else
+    return mind;
+} /* getdistance */
+
+
+/*---------------------------------
+
+  qh_normalize( normal, dim, toporient )
+    normalize a vector and report if too small
+    does not use min norm
+  
+  see:
+    qh_normalize2
+*/
+void qh_normalize (coordT *normal, int dim, boolT toporient) {
+  qh_normalize2( normal, dim, toporient, NULL, NULL);
+} /* normalize */
+
+/*---------------------------------
+  
+  qh_normalize2( normal, dim, toporient, minnorm, ismin )
+    normalize a vector and report if too small
+    qh.MINdenom/MINdenom1 are the upper limits for divide overflow
+
+  returns:
+    normalized vector
+    flips sign if !toporient
+    if minnorm non-NULL, 
+      sets ismin if normal < minnorm
+
+  notes:
+    if zero norm
+       sets all elements to sqrt(1.0/dim)
+    if divide by zero (divzero ())
+       sets largest element to   +/-1
+       bumps Znearlysingular
+      
+  design:
+    computes norm
+    test for minnorm
+    if not near zero
+      normalizes normal
+    else if zero norm
+      sets normal to standard value
+    else
+      uses qh_divzero to normalize
+      if nearzero
+        sets norm to direction of maximum value
+*/
+void qh_normalize2 (coordT *normal, int dim, boolT toporient, 
+            realT *minnorm, boolT *ismin) {
+  int k;
+  realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
+  boolT zerodiv;
+
+  norm1= normal+1;
+  norm2= normal+2;
+  norm3= normal+3;
+  if (dim == 2)
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
+  else if (dim == 3)
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
+  else if (dim == 4) {
+    norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2) 
+               + (*norm3)*(*norm3));
+  }else if (dim > 4) {
+    norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2) 
+               + (*norm3)*(*norm3);
+    for (k= dim-4, colp= normal+4; k--; colp++)
+      norm += (*colp) * (*colp);
+    norm= sqrt(norm);
+  }
+  if (minnorm) {
+    if (norm < *minnorm) 
+      *ismin= True;
+    else
+      *ismin= False;
+  }
+  wmin_(Wmindenom, norm);
+  if (norm > qh MINdenom) {
+    if (!toporient)
+      norm= -norm;
+    *normal /= norm;
+    *norm1 /= norm;
+    if (dim == 2)
+      ; /* all done */
+    else if (dim == 3)
+      *norm2 /= norm;
+    else if (dim == 4) {
+      *norm2 /= norm;
+      *norm3 /= norm;
+    }else if (dim >4) {
+      *norm2 /= norm;
+      *norm3 /= norm;
+      for (k= dim-4, colp= normal+4; k--; )
+        *colp++ /= norm;
+    }
+  }else if (norm == 0.0) {
+    temp= sqrt (1.0/dim);
+    for (k= dim, colp= normal; k--; )
+      *colp++ = temp;
+  }else {
+    if (!toporient)
+      norm= -norm;
+    for (k= dim, colp= normal; k--; colp++) { /* k used below */
+      temp= qh_divzero (*colp, norm, qh MINdenom_1, &zerodiv);
+      if (!zerodiv)
+	*colp= temp;
+      else {
+	maxp= qh_maxabsval(normal, dim);
+	temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);
+	for (k= dim, colp= normal; k--; colp++)
+	  *colp= 0.0;
+	*maxp= temp;
+	zzinc_(Znearlysingular);
+	trace0((qh ferr, "qh_normalize: norm=%2.2g too small during p%d\n", 
+	       norm, qh furthest_id));
+	return;
+      }
+    }
+  }
+} /* normalize */
+
+
+/*---------------------------------
+  
+  qh_projectpoint( point, facet, dist )
+    project point onto a facet by dist
+
+  returns:
+    returns a new point
+    
+  notes:
+    if dist= distplane(point,facet)
+      this projects point to hyperplane
+    assumes qh_memfree_() is valid for normal_size
+*/
+pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist) {
+  pointT *newpoint, *np, *normal;
+  int normsize= qh normal_size,k;
+  void **freelistp; /* used !qh_NOmem */
+  
+  qh_memalloc_(normsize, freelistp, newpoint, pointT);
+  np= newpoint;
+  normal= facet->normal;
+  for(k= qh hull_dim; k--; )
+    *(np++)= *point++ - dist * *normal++;
+  return(newpoint);
+} /* projectpoint */
+
+  
+/*---------------------------------
+  
+  qh_setfacetplane( facet )
+    sets the hyperplane for a facet
+    if qh.RANDOMdist, joggles hyperplane
+
+  notes:
+    uses global buffers qh.gm_matrix and qh.gm_row
+    overwrites facet->normal if already defined
+    updates Wnewvertex if PRINTstatistics
+    sets facet->upperdelaunay if upper envelope of Delaunay triangulation
+
+  design:
+    copy vertex coordinates to qh.gm_matrix/gm_row
+    compute determinate
+    if nearzero
+      recompute determinate with gaussian elimination
+      if nearzero
+        force outside orientation by testing interior point
+*/
+void qh_setfacetplane(facetT *facet) {
+  pointT *point;
+  vertexT *vertex, **vertexp;
+  int k,i, normsize= qh normal_size, oldtrace= 0;
+  realT dist;
+  void **freelistp; /* used !qh_NOmem */
+  coordT *coord, *gmcoord;
+  pointT *point0= SETfirstt_(facet->vertices, vertexT)->point;
+  boolT nearzero= False;
+
+  zzinc_(Zsetplane);
+  if (!facet->normal)
+    qh_memalloc_(normsize, freelistp, facet->normal, coordT);
+  if (facet == qh tracefacet) {
+    oldtrace= qh IStracing;
+    qh IStracing= 5;
+    fprintf (qh ferr, "qh_setfacetplane: facet f%d created.\n", facet->id);
+    fprintf (qh ferr, "  Last point added to hull was p%d.", qh furthest_id);
+    if (zzval_(Ztotmerge))
+      fprintf(qh ferr, "  Last merge was #%d.", zzval_(Ztotmerge));
+    fprintf (qh ferr, "\n\nCurrent summary is:\n");
+      qh_printsummary (qh ferr);
+  }
+  if (qh hull_dim <= 4) {
+    i= 0;
+    if (qh RANDOMdist) {
+      gmcoord= qh gm_matrix;
+      FOREACHvertex_(facet->vertices) {
+        qh gm_row[i++]= gmcoord;
+	coord= vertex->point;
+	for (k= qh hull_dim; k--; )
+	  *(gmcoord++)= *coord++ * qh_randomfactor();
+      }	  
+    }else {
+      FOREACHvertex_(facet->vertices)
+       qh gm_row[i++]= vertex->point;
+    }
+    qh_sethyperplane_det(qh hull_dim, qh gm_row, point0, facet->toporient,
+                facet->normal, &facet->offset, &nearzero);
+  }
+  if (qh hull_dim > 4 || nearzero) {
+    i= 0;
+    gmcoord= qh gm_matrix;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->point != point0) {
+	qh gm_row[i++]= gmcoord;
+	coord= vertex->point;
+	point= point0;
+	for(k= qh hull_dim; k--; )
+	  *(gmcoord++)= *coord++ - *point++;
+      }
+    }
+    qh gm_row[i]= gmcoord;  /* for areasimplex */
+    if (qh RANDOMdist) {
+      gmcoord= qh gm_matrix;
+      for (i= qh hull_dim-1; i--; ) {
+	for (k= qh hull_dim; k--; )
+	  *(gmcoord++) *= qh_randomfactor();
+      }
+    }
+    qh_sethyperplane_gauss(qh hull_dim, qh gm_row, point0, facet->toporient,
+           	facet->normal, &facet->offset, &nearzero);
+    if (nearzero) { 
+      if (qh_orientoutside (facet)) {
+	trace0((qh ferr, "qh_setfacetplane: flipped orientation after testing interior_point during p%d\n", qh furthest_id));
+      /* this is part of using Gaussian Elimination.  For example in 5-d
+	   1 1 1 1 0
+	   1 1 1 1 1
+	   0 0 0 1 0
+	   0 1 0 0 0
+	   1 0 0 0 0
+	   norm= 0.38 0.38 -0.76 0.38 0
+	 has a determinate of 1, but g.e. after subtracting pt. 0 has
+	 0's in the diagonal, even with full pivoting.  It does work
+	 if you subtract pt. 4 instead. */
+      }
+    }
+  }
+  facet->upperdelaunay= False;
+  if (qh DELAUNAY) {
+    if (qh UPPERdelaunay) {     /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */
+      if (facet->normal[qh hull_dim -1] >= qh ANGLEround * qh_ZEROdelaunay)
+        facet->upperdelaunay= True;
+    }else {
+      if (facet->normal[qh hull_dim -1] > -qh ANGLEround * qh_ZEROdelaunay)
+        facet->upperdelaunay= True;
+    }
+  }
+  if (qh PRINTstatistics || qh IStracing || qh TRACElevel || qh JOGGLEmax < REALmax) {
+    qh old_randomdist= qh RANDOMdist;
+    qh RANDOMdist= False;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->point != point0) {
+	boolT istrace= False;
+	zinc_(Zdiststat);
+        qh_distplane(vertex->point, facet, &dist);
+        dist= fabs_(dist);
+        zinc_(Znewvertex);
+        wadd_(Wnewvertex, dist);
+        if (dist > wwval_(Wnewvertexmax)) {
+          wwval_(Wnewvertexmax)= dist;
+	  if (dist > qh max_outside) {
+	    qh max_outside= dist;  /* used by qh_maxouter() */
+	    if (dist > qh TRACEdist) 
+	      istrace= True;
+	  }
+	}else if (-dist > qh TRACEdist)
+	  istrace= True;
+	if (istrace) {
+	  fprintf (qh ferr, "qh_setfacetplane: ====== vertex p%d (v%d) increases max_outside to %2.2g for new facet f%d last p%d\n",
+	        qh_pointid(vertex->point), vertex->id, dist, facet->id, qh furthest_id);
+	  qh_errprint ("DISTANT", facet, NULL, NULL, NULL);
+	}
+      }
+    }
+    qh RANDOMdist= qh old_randomdist;
+  }
+  if (qh IStracing >= 3) {
+    fprintf (qh ferr, "qh_setfacetplane: f%d offset %2.2g normal: ",
+	     facet->id, facet->offset);
+    for (k=0; k < qh hull_dim; k++)
+      fprintf (qh ferr, "%2.2g ", facet->normal[k]);
+    fprintf (qh ferr, "\n");
+  }
+  if (facet == qh tracefacet)
+    qh IStracing= oldtrace;
+} /* setfacetplane */
+
+
+/*---------------------------------
+  
+  qh_sethyperplane_det( dim, rows, point0, toporient, normal, offset, nearzero )
+    given dim X dim array indexed by rows[], one row per point, 
+        toporient (flips all signs),
+        and point0 (any row)
+    set normalized hyperplane equation from oriented simplex
+
+  returns:
+    normal (normalized)
+    offset (places point0 on the hyperplane)
+    sets nearzero if hyperplane not through points
+
+  notes:
+    only defined for dim == 2..4
+    rows[] is not modified
+    solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
+    see Bower & Woodworth, A programmer's geometry, Butterworths 1983.
+
+  derivation of 3-d minnorm
+    Goal: all vertices V_i within qh.one_merge of hyperplane
+    Plan: exactly translate the facet so that V_0 is the origin
+          exactly rotate the facet so that V_1 is on the x-axis and y_2=0.
+          exactly rotate the effective perturbation to only effect n_0
+	     this introduces a factor of sqrt(3)
+    n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm
+    Let M_d be the max coordinate difference
+    Let M_a be the greater of M_d and the max abs. coordinate
+    Let u be machine roundoff and distround be max error for distance computation
+    The max error for n_0 is sqrt(3) u M_a M_d / norm.  n_1 is approx. 1 and n_2 is approx. 0
+    The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm.  Offset=0 at origin
+    Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge
+    Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d
+
+  derivation of 4-d minnorm
+    same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0
+     [if two vertices fixed on x-axis, can rotate the other two in yzw.]
+    n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3
+     [all other terms contain at least two factors nearly zero.]
+    The max error for n_0 is sqrt(4) u M_a M_d M_d / norm
+    Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge
+    Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d
+*/
+void qh_sethyperplane_det (int dim, coordT **rows, coordT *point0, 
+          boolT toporient, coordT *normal, realT *offset, boolT *nearzero) {
+  realT maxround, dist;
+  int i;
+  pointT *point;
+
+
+  if (dim == 2) {
+    normal[0]= dY(1,0);
+    normal[1]= dX(0,1);
+    qh_normalize2 (normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
+    *nearzero= False;  /* since nearzero norm => incident points */
+  }else if (dim == 3) {
+    normal[0]= det2_(dY(2,0), dZ(2,0),
+		     dY(1,0), dZ(1,0));
+    normal[1]= det2_(dX(1,0), dZ(1,0),
+		     dX(2,0), dZ(2,0));
+    normal[2]= det2_(dX(2,0), dY(2,0),
+		     dX(1,0), dY(1,0));
+    qh_normalize2 (normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
+	       + point0[2]*normal[2]);
+    maxround= qh DISTround;
+    for (i=dim; i--; ) {
+      point= rows[i];
+      if (point != point0) {
+        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
+	       + point[2]*normal[2]);
+        if (dist > maxround || dist < -maxround) {
+  	  *nearzero= True;
+	  break;
+	}
+      }
+    }
+  }else if (dim == 4) {
+    normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
+			dY(1,0), dZ(1,0), dW(1,0),
+			dY(3,0), dZ(3,0), dW(3,0));
+    normal[1]=   det3_(dX(2,0), dZ(2,0), dW(2,0),
+		        dX(1,0), dZ(1,0), dW(1,0),
+		        dX(3,0), dZ(3,0), dW(3,0));
+    normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
+			dX(1,0), dY(1,0), dW(1,0),
+			dX(3,0), dY(3,0), dW(3,0));
+    normal[3]=   det3_(dX(2,0), dY(2,0), dZ(2,0),
+		        dX(1,0), dY(1,0), dZ(1,0),
+		        dX(3,0), dY(3,0), dZ(3,0));
+    qh_normalize2 (normal, dim, toporient, NULL, NULL);
+    *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
+	       + point0[2]*normal[2] + point0[3]*normal[3]);
+    maxround= qh DISTround;
+    for (i=dim; i--; ) {
+      point= rows[i];
+      if (point != point0) {
+        dist= *offset + (point[0]*normal[0] + point[1]*normal[1]
+	       + point[2]*normal[2] + point[3]*normal[3]);
+        if (dist > maxround || dist < -maxround) {
+  	  *nearzero= True;
+	  break;
+	}
+      }
+    }
+  }
+  if (*nearzero) {
+    zzinc_(Zminnorm);
+    trace0((qh ferr, "qh_sethyperplane_det: degenerate norm during p%d.\n", qh furthest_id));
+    zzinc_(Znearlysingular);
+  }
+} /* sethyperplane_det */
+
+
+/*---------------------------------
+  
+  qh_sethyperplane_gauss( dim, rows, point0, toporient, normal, offset, nearzero )
+    given (dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
+    set normalized hyperplane equation from oriented simplex
+
+  returns:
+    normal (normalized)
+    offset (places point0 on the hyperplane)
+
+  notes:
+    if nearzero
+      orientation may be incorrect because of incorrect sign flips in gausselim
+    solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1] 
+        or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0] 
+    i.e., N is normal to the hyperplane, and the unnormalized
+        distance to [0 .. 1] is either 1 or   0
+
+  design:
+    perform gaussian elimination
+    flip sign for negative values
+    perform back substitution 
+    normalize result
+    compute offset
+*/
+void qh_sethyperplane_gauss (int dim, coordT **rows, pointT *point0, 
+		boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
+  coordT *pointcoord, *normalcoef;
+  int k;
+  boolT sign= toporient, nearzero2= False;
+  
+  qh_gausselim(rows, dim-1, dim, &sign, nearzero);
+  for(k= dim-1; k--; ) {
+    if ((rows[k])[k] < 0)
+      sign ^= 1;
+  }
+  if (*nearzero) {
+    zzinc_(Znearlysingular);
+    trace0((qh ferr, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh furthest_id));
+    qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
+  }else {
+    qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
+    if (nearzero2) {
+      zzinc_(Znearlysingular);
+      trace0((qh ferr, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh furthest_id));
+    }
+  }
+  if (nearzero2)
+    *nearzero= True;
+  qh_normalize2(normal, dim, True, NULL, NULL);
+  pointcoord= point0;
+  normalcoef= normal;
+  *offset= -(*pointcoord++ * *normalcoef++);
+  for(k= dim-1; k--; )
+    *offset -= *pointcoord++ * *normalcoef++;
+} /* sethyperplane_gauss */
+
+  
+
diff --git a/extern/qhull/src/geom.h b/extern/qhull/src/geom.h
new file mode 100644
index 00000000000..32440cff56f
--- /dev/null
+++ b/extern/qhull/src/geom.h
@@ -0,0 +1,177 @@
+/*
  ---------------------------------
+
+  geom.h 
+    header file for geometric routines
+
+   see qh-geom.htm and geom.c
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#ifndef qhDEFgeom
+#define qhDEFgeom 1
+
+/* ============ -macros- ======================== */
+
+/*----------------------------------
+   
+  fabs_(a)
+    returns the absolute value of a
+*/
+#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
+               
+/*----------------------------------
+  
+  fmax_(a,b)
+    returns the maximum value of a and b
+*/
+#define fmax_( a,b )  ( ( a ) < ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  fmin_(a,b)
+    returns the minimum value of a and b
+*/
+#define fmin_( a,b )  ( ( a ) > ( b ) ? ( b ) : ( a ) )
+
+/*----------------------------------
+
+  maximize_(maxval, val)
+    set maxval to val if val is greater than maxval
+*/
+#define maximize_( maxval, val ) {if (( maxval ) < ( val )) ( maxval )= ( val );}
+
+/*----------------------------------
+
+  minimize_(minval, val)
+    set minval to val if val is less than minval
+*/
+#define minimize_( minval, val ) {if (( minval ) > ( val )) ( minval )= ( val );}
+
+/*----------------------------------
+
+  det2_(a1, a2,     
+        b1, b2)
+  
+    compute a 2-d determinate
+*/
+#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
+
+/*----------------------------------
+  
+  det3_(a1, a2, a3,    
+       b1, b2, b3,
+       c1, c2, c3)
+  
+    compute a 3-d determinate
+*/
+#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
+                - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )
+
+/*----------------------------------
+  
+  dX( p1, p2 )
+  dY( p1, p2 )
+  dZ( p1, p2 )
+  
+    given two indices into rows[],
+
+    compute the difference between X, Y, or Z coordinates
+*/
+#define dX( p1,p2 )  ( *( rows[p1] ) - *( rows[p2] ))
+#define dY( p1,p2 )  ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
+#define dZ( p1,p2 )  ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
+#define dW( p1,p2 )  ( *( rows[p1]+3 ) - *( rows[p2]+3 ))
+
+/*============= prototypes in alphabetical order, infrequent at end ======= */
+
+void    qh_backnormal (realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
+void	qh_distplane (pointT *point, facetT *facet, realT *dist);
+facetT *qh_findbest (pointT *point, facetT *startfacet,
+		     boolT bestoutside, boolT isnewfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbesthorizon (boolT ischeckmax, pointT *point, 
+	             facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
+facetT *qh_findbestnew (pointT *point, facetT *startfacet, realT *dist, 
+		     boolT bestoutside, boolT *isoutside, int *numpart);
+void 	qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
+realT   qh_getangle(pointT *vect1, pointT *vect2);
+pointT *qh_getcenter(setT *vertices);
+pointT *qh_getcentrum(facetT *facet);
+realT   qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist);
+void    qh_normalize (coordT *normal, int dim, boolT toporient);
+void    qh_normalize2 (coordT *normal, int dim, boolT toporient, 
+            realT *minnorm, boolT *ismin);
+pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist);
+
+void    qh_setfacetplane(facetT *newfacets);
+void 	qh_sethyperplane_det (int dim, coordT **rows, coordT *point0, 
+              boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
+void 	qh_sethyperplane_gauss (int dim, coordT **rows, pointT *point0, 
+	     boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
+boolT   qh_sharpnewfacets (void);
+
+/*========= infrequently used code in geom2.c =============*/
+
+
+coordT *qh_copypoints (coordT *points, int numpoints, int dimension);
+void    qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
+realT 	qh_determinant (realT **rows, int dim, boolT *nearzero);
+realT   qh_detjoggle (pointT *points, int numpoints, int dimension);
+void    qh_detroundoff (void);
+realT   qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero);
+realT   qh_distnorm (int dim, pointT *point, pointT *normal, realT *offsetp);
+realT   qh_distround (int dimension, realT maxabs, realT maxsumabs);
+realT   qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv);
+realT   qh_facetarea (facetT *facet);
+realT   qh_facetarea_simplex (int dim, coordT *apex, setT *vertices, 
+          vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset);
+pointT *qh_facetcenter (setT *vertices);
+facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
+void    qh_getarea (facetT *facetlist);
+boolT   qh_gram_schmidt(int dim, realT **rows);
+boolT   qh_inthresholds (coordT *normal, realT *angle);
+void    qh_joggleinput (void);
+realT  *qh_maxabsval (realT *normal, int dim);
+setT   *qh_maxmin(pointT *points, int numpoints, int dimension);
+realT   qh_maxouter (void);
+void    qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
+realT   qh_minabsval (realT *normal, int dim);
+int     qh_mindiff (realT *vecA, realT *vecB, int dim);
+boolT   qh_orientoutside (facetT *facet);
+void    qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane);
+coordT  qh_pointdist(pointT *point1, pointT *point2, int dim);
+void    qh_printmatrix (FILE *fp, char *string, realT **rows, int numrow, int numcol);
+void    qh_printpoints (FILE *fp, char *string, setT *points);
+void    qh_projectinput (void);
+void 	qh_projectpoints (signed char *project, int n, realT *points, 
+             int numpoints, int dim, realT *newpoints, int newdim);
+int     qh_rand( void);
+void    qh_srand( int seed);
+realT   qh_randomfactor (void);
+void    qh_randommatrix (realT *buffer, int dim, realT **row);
+void    qh_rotateinput (realT **rows);
+void    qh_rotatepoints (realT *points, int numpoints, int dim, realT **rows);
+void    qh_scaleinput (void);
+void    qh_scalelast (coordT *points, int numpoints, int dim, coordT low,
+		   coordT high, coordT newhigh);
+void 	qh_scalepoints (pointT *points, int numpoints, int dim,
+  		realT *newlows, realT *newhighs);
+boolT   qh_sethalfspace (int dim, coordT *coords, coordT **nextp, 
+              coordT *normal, coordT *offset, coordT *feasible);
+coordT *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible);
+pointT *qh_voronoi_center (int dim, setT *points);
+
+#endif /* qhDEFgeom */
+
+
+
diff --git a/extern/qhull/src/geom2.c b/extern/qhull/src/geom2.c
new file mode 100644
index 00000000000..bd58ce1282b
--- /dev/null
+++ b/extern/qhull/src/geom2.c
@@ -0,0 +1,2160 @@
+/*
  ---------------------------------
+
+
+   geom2.c 
+   infrequently used geometric routines of qhull
+
+   see qh-geom.htm and geom.h
+
+   copyright (c) 1993-2002 The Geometry Center        
+
+   frequently used code goes into geom.c
+*/
+   
+#include "qhull_a.h"
+   
+/*================== functions in alphabetic order ============*/
+
+/*---------------------------------
+
+  qh_copypoints( points, numpoints, dimension)
+    return malloc'd copy of points
+*/
+coordT *qh_copypoints (coordT *points, int numpoints, int dimension) {
+  int size;
+  coordT *newpoints;
+
+  size= numpoints * dimension * sizeof(coordT);
+  if (!(newpoints=(coordT*)malloc(size))) {
+    fprintf(qh ferr, "qhull error: insufficient memory to copy %d points\n",
+        numpoints);
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  memcpy ((char *)newpoints, (char *)points, size);
+  return newpoints;
+} /* copypoints */
+
+/*---------------------------------
+  
+  qh_crossproduct( dim, vecA, vecB, vecC )
+    crossproduct of 2 dim vectors
+    C= A x B
+  
+  notes:
+    from Glasner, Graphics Gems I, p. 639
+    only defined for dim==3
+*/
+void qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]){
+
+  if (dim == 3) {
+    vecC[0]=   det2_(vecA[1], vecA[2],
+		     vecB[1], vecB[2]);
+    vecC[1]= - det2_(vecA[0], vecA[2],
+		     vecB[0], vecB[2]);
+    vecC[2]=   det2_(vecA[0], vecA[1],
+		     vecB[0], vecB[1]);
+  }
+} /* vcross */
+
+/*---------------------------------
+  
+  qh_determinant( rows, dim, nearzero )
+    compute signed determinant of a square matrix
+    uses qh.NEARzero to test for degenerate matrices
+
+  returns:
+    determinant
+    overwrites rows and the matrix
+    if dim == 2 or 3
+      nearzero iff determinant < qh NEARzero[dim-1]
+      (not quite correct, not critical)
+    if dim >= 4
+      nearzero iff diagonal[k] < qh NEARzero[k]
+*/
+realT qh_determinant (realT **rows, int dim, boolT *nearzero) {
+  realT det=0;
+  int i;
+  boolT sign= False;
+
+  *nearzero= False;
+  if (dim < 2) {
+    fprintf (qh ferr, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }else if (dim == 2) {
+    det= det2_(rows[0][0], rows[0][1],
+		 rows[1][0], rows[1][1]);
+    if (fabs_(det) < qh NEARzero[1])  /* not really correct, what should this be? */
+      *nearzero= True;
+  }else if (dim == 3) {
+    det= det3_(rows[0][0], rows[0][1], rows[0][2],
+		 rows[1][0], rows[1][1], rows[1][2],
+		 rows[2][0], rows[2][1], rows[2][2]);
+    if (fabs_(det) < qh NEARzero[2])  /* not really correct, what should this be? */
+      *nearzero= True;
+  }else {	
+    qh_gausselim(rows, dim, dim, &sign, nearzero);  /* if nearzero, diagonal still ok*/
+    det= 1.0;
+    for (i= dim; i--; )
+      det *= (rows[i])[i];
+    if (sign)
+      det= -det;
+  }
+  return det;
+} /* determinant */
+
+/*---------------------------------
+  
+  qh_detjoggle( points, numpoints, dimension )
+    determine default max joggle for point array
+      as qh_distround * qh_JOGGLEdefault
+
+  returns:
+    initial value for JOGGLEmax from points and REALepsilon
+
+  notes:
+    computes DISTround since qh_maxmin not called yet
+    if qh SCALElast, last dimension will be scaled later to MAXwidth
+
+    loop duplicated from qh_maxmin
+*/
+realT qh_detjoggle (pointT *points, int numpoints, int dimension) {
+  realT abscoord, distround, joggle, maxcoord, mincoord;
+  pointT *point, *pointtemp;
+  realT maxabs= -REALmax;
+  realT sumabs= 0;
+  realT maxwidth= 0;
+  int k;
+
+  for (k= 0; k < dimension; k++) {
+    if (qh SCALElast && k == dimension-1)
+      abscoord= maxwidth;
+    else if (qh DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */
+      abscoord= 2 * maxabs * maxabs;  /* may be low by qh hull_dim/2 */
+    else {
+      maxcoord= -REALmax;
+      mincoord= REALmax;
+      FORALLpoint_(points, numpoints) {
+	maximize_(maxcoord, point[k]);
+        minimize_(mincoord, point[k]);
+      }
+      maximize_(maxwidth, maxcoord-mincoord);
+      abscoord= fmax_(maxcoord, -mincoord);
+    }
+    sumabs += abscoord;
+    maximize_(maxabs, abscoord);
+  } /* for k */
+  distround= qh_distround (qh hull_dim, maxabs, sumabs);
+  joggle= distround * qh_JOGGLEdefault;
+  maximize_(joggle, REALepsilon * qh_JOGGLEdefault);
+  trace2((qh ferr, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth));
+  return joggle;
+} /* detjoggle */
+
+/*---------------------------------
+  
+  qh_detroundoff()
+    determine maximum roundoff errors from
+      REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord, 
+      qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1
+
+    accounts for qh.SETroundoff, qh.RANDOMdist, qh MERGEexact
+      qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum,
+      qh.postmerge_centrum, qh.MINoutside,
+      qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar
+
+  returns:
+    sets qh.DISTround, etc. (see below)
+    appends precision constants to qh.qhull_options
+
+  see:
+    qh_maxmin() for qh.NEARzero
+
+  design:
+    determine qh.DISTround for distance computations
+    determine minimum denominators for qh_divzero
+    determine qh.ANGLEround for angle computations
+    adjust qh.premerge_cos,... for roundoff error
+    determine qh.ONEmerge for maximum error due to a single merge
+    determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible,
+      qh.MINoutside, qh.WIDEfacet
+    initialize qh.max_vertex and qh.minvertex
+*/
+void qh_detroundoff (void) {
+
+  qh_option ("_max-width", NULL, &qh MAXwidth);
+  if (!qh SETroundoff) {
+    qh DISTround= qh_distround (qh hull_dim, qh MAXabs_coord, qh MAXsumcoord);
+    if (qh RANDOMdist)
+      qh DISTround += qh RANDOMfactor * qh MAXabs_coord;
+    qh_option ("Error-roundoff", NULL, &qh DISTround);
+  }
+  qh MINdenom= qh MINdenom_1 * qh MAXabs_coord;
+  qh MINdenom_1_2= sqrt (qh MINdenom_1 * qh hull_dim) ;  /* if will be normalized */
+  qh MINdenom_2= qh MINdenom_1_2 * qh MAXabs_coord;
+                                              /* for inner product */
+  qh ANGLEround= 1.01 * qh hull_dim * REALepsilon;
+  if (qh RANDOMdist)
+    qh ANGLEround += qh RANDOMfactor;
+  if (qh premerge_cos < REALmax/2) {
+    qh premerge_cos -= qh ANGLEround;
+    if (qh RANDOMdist) 
+      qh_option ("Angle-premerge-with-random", NULL, &qh premerge_cos);
+  }
+  if (qh postmerge_cos < REALmax/2) {
+    qh postmerge_cos -= qh ANGLEround;
+    if (qh RANDOMdist)
+      qh_option ("Angle-postmerge-with-random", NULL, &qh postmerge_cos);
+  }
+  qh premerge_centrum += 2 * qh DISTround;    /*2 for centrum and distplane()*/
+  qh postmerge_centrum += 2 * qh DISTround;
+  if (qh RANDOMdist && (qh MERGEexact || qh PREmerge))
+    qh_option ("Centrum-premerge-with-random", NULL, &qh premerge_centrum);
+  if (qh RANDOMdist && qh POSTmerge)
+    qh_option ("Centrum-postmerge-with-random", NULL, &qh postmerge_centrum);
+  { /* compute ONEmerge, max vertex offset for merging simplicial facets */
+    realT maxangle= 1.0, maxrho;
+    
+    minimize_(maxangle, qh premerge_cos);
+    minimize_(maxangle, qh postmerge_cos);
+    /* max diameter * sin theta + DISTround for vertex to its hyperplane */
+    qh ONEmerge= sqrt (qh hull_dim) * qh MAXwidth *
+      sqrt (1.0 - maxangle * maxangle) + qh DISTround;  
+    maxrho= qh hull_dim * qh premerge_centrum + qh DISTround;
+    maximize_(qh ONEmerge, maxrho);
+    maxrho= qh hull_dim * qh postmerge_centrum + qh DISTround;
+    maximize_(qh ONEmerge, maxrho);
+    if (qh MERGING)
+      qh_option ("_one-merge", NULL, &qh ONEmerge);
+  }
+  qh NEARinside= qh ONEmerge * qh_RATIOnearinside; /* only used if qh KEEPnearinside */
+  if (qh JOGGLEmax < REALmax/2 && (qh KEEPcoplanar || qh KEEPinside)) {
+    realT maxdist;	       /* adjust qh.NEARinside for joggle */
+    qh KEEPnearinside= True;   
+    maxdist= sqrt (qh hull_dim) * qh JOGGLEmax + qh DISTround;
+    maxdist= 2*maxdist;        /* vertex and coplanar point can joggle in opposite directions */
+    maximize_(qh NEARinside, maxdist);  /* must agree with qh_nearcoplanar() */
+  }
+  if (qh KEEPnearinside)
+    qh_option ("_near-inside", NULL, &qh NEARinside);
+  if (qh JOGGLEmax < qh DISTround) {
+    fprintf (qh ferr, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n",
+         qh JOGGLEmax, qh DISTround);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (qh MINvisible > REALmax/2) {
+    if (!qh MERGING)
+      qh MINvisible= qh DISTround;
+    else if (qh hull_dim <= 3)
+      qh MINvisible= qh premerge_centrum;
+    else
+      qh MINvisible= qh_COPLANARratio * qh premerge_centrum;
+    if (qh APPROXhull && qh MINvisible > qh MINoutside)
+      qh MINvisible= qh MINoutside;
+    qh_option ("Visible-distance", NULL, &qh MINvisible);
+  }
+  if (qh MAXcoplanar > REALmax/2) {
+    qh MAXcoplanar= qh MINvisible;
+    qh_option ("U-coplanar-distance", NULL, &qh MAXcoplanar);
+  }
+  if (!qh APPROXhull) {             /* user may specify qh MINoutside */
+    qh MINoutside= 2 * qh MINvisible;
+    if (qh premerge_cos < REALmax/2) 
+      maximize_(qh MINoutside, (1- qh premerge_cos) * qh MAXabs_coord);
+    qh_option ("Width-outside", NULL, &qh MINoutside);
+  }
+  qh WIDEfacet= qh MINoutside;
+  maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MAXcoplanar); 
+  maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MINvisible); 
+  qh_option ("_wide-facet", NULL, &qh WIDEfacet);
+  if (qh MINvisible > qh MINoutside + 3 * REALepsilon 
+  && !qh BESToutside && !qh FORCEoutput)
+    fprintf (qh ferr, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g.  Flipped facets are likely.\n",
+	     qh MINvisible, qh MINoutside);
+  qh max_vertex= qh DISTround;
+  qh min_vertex= -qh DISTround;
+  /* numeric constants reported in printsummary */
+} /* detroundoff */
+
+/*---------------------------------
+  
+  qh_detsimplex( apex, points, dim, nearzero )
+    compute determinant of a simplex with point apex and base points
+
+  returns:
+     signed determinant and nearzero from qh_determinant
+
+  notes:
+     uses qh.gm_matrix/qh.gm_row (assumes they're big enough)
+
+  design:
+    construct qm_matrix by subtracting apex from points
+    compute determinate
+*/
+realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero) {
+  pointT *coorda, *coordp, *gmcoord, *point, **pointp;
+  coordT **rows;
+  int k,  i=0;
+  realT det;
+
+  zinc_(Zdetsimplex);
+  gmcoord= qh gm_matrix;
+  rows= qh gm_row;
+  FOREACHpoint_(points) {
+    if (i == dim)
+      break;
+    rows[i++]= gmcoord;
+    coordp= point;
+    coorda= apex;
+    for (k= dim; k--; )
+      *(gmcoord++)= *coordp++ - *coorda++;
+  }
+  if (i < dim) {
+    fprintf (qh ferr, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n", 
+               i, dim);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  det= qh_determinant (rows, dim, nearzero);
+  trace2((qh ferr, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n",
+	  det, qh_pointid(apex), dim, *nearzero)); 
+  return det;
+} /* detsimplex */
+
+/*---------------------------------
+  
+  qh_distnorm( dim, point, normal, offset )
+    return distance from point to hyperplane at normal/offset
+
+  returns:
+    dist
+  
+  notes:  
+    dist > 0 if point is outside of hyperplane
+  
+  see:
+    qh_distplane in geom.c
+*/
+realT qh_distnorm (int dim, pointT *point, pointT *normal, realT *offsetp) {
+  coordT *normalp= normal, *coordp= point;
+  realT dist;
+  int k;
+
+  dist= *offsetp;
+  for (k= dim; k--; )
+    dist += *(coordp++) * *(normalp++);
+  return dist;
+} /* distnorm */
+
+/*---------------------------------
+
+  qh_distround ( dimension, maxabs, maxsumabs )
+    compute maximum round-off error for a distance computation
+      to a normalized hyperplane
+    maxabs is the maximum absolute value of a coordinate
+    maxsumabs is the maximum possible sum of absolute coordinate values
+
+  returns:
+    max dist round for REALepsilon
+
+  notes:
+    calculate roundoff error according to
+    Lemma 3.2-1 of Golub and van Loan "Matrix Computation"
+    use sqrt(dim) since one vector is normalized
+      or use maxsumabs since one vector is < 1
+*/
+realT qh_distround (int dimension, realT maxabs, realT maxsumabs) {
+  realT maxdistsum, maxround;
+
+  maxdistsum= sqrt (dimension) * maxabs;
+  minimize_( maxdistsum, maxsumabs);
+  maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs);
+              /* adds maxabs for offset */
+  trace4((qh ferr, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n",
+	         maxround, maxabs, maxsumabs, maxdistsum));
+  return maxround;
+} /* distround */
+
+/*---------------------------------
+  
+  qh_divzero( numer, denom, mindenom1, zerodiv )
+    divide by a number that's nearly zero
+    mindenom1= minimum denominator for dividing into 1.0
+
+  returns:
+    quotient
+    sets zerodiv and returns 0.0 if it would overflow
+  
+  design:
+    if numer is nearly zero and abs(numer) < abs(denom)
+      return numer/denom
+    else if numer is nearly zero
+      return 0 and zerodiv
+    else if denom/numer non-zero
+      return numer/denom
+    else
+      return 0 and zerodiv
+*/
+realT qh_divzero (realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
+  realT temp, numerx, denomx;
+  
+
+  if (numer < mindenom1 && numer > -mindenom1) {
+    numerx= fabs_(numer);
+    denomx= fabs_(denom);
+    if (numerx < denomx) {
+      *zerodiv= False;
+      return numer/denom;
+    }else {
+      *zerodiv= True;
+      return 0.0;
+    }
+  }
+  temp= denom/numer;
+  if (temp > mindenom1 || temp < -mindenom1) {
+    *zerodiv= False;
+    return numer/denom;
+  }else {
+    *zerodiv= True;
+    return 0.0;
+  }
+} /* divzero */
+  
+
+/*---------------------------------
+
+  qh_facetarea( facet )
+    return area for a facet
+  
+  notes:
+    if non-simplicial, 
+      uses centrum to triangulate facet and sums the projected areas.
+    if (qh DELAUNAY),
+      computes projected area instead for last coordinate
+    assumes facet->normal exists
+    projecting tricoplanar facets to the hyperplane does not appear to make a difference
+  
+  design:
+    if simplicial
+      compute area
+    else
+      for each ridge
+        compute area from centrum to ridge
+    negate area if upper Delaunay facet
+*/
+realT qh_facetarea (facetT *facet) {
+  vertexT *apex;
+  pointT *centrum;
+  realT area= 0.0;
+  ridgeT *ridge, **ridgep;
+
+  if (facet->simplicial) {
+    apex= SETfirstt_(facet->vertices, vertexT);
+    area= qh_facetarea_simplex (qh hull_dim, apex->point, facet->vertices, 
+                    apex, facet->toporient, facet->normal, &facet->offset);
+  }else {
+    if (qh CENTERtype == qh_AScentrum)
+      centrum= facet->center;
+    else
+      centrum= qh_getcentrum (facet);
+    FOREACHridge_(facet->ridges) 
+      area += qh_facetarea_simplex (qh hull_dim, centrum, ridge->vertices, 
+                 NULL, (ridge->top == facet),  facet->normal, &facet->offset);
+    if (qh CENTERtype != qh_AScentrum)
+      qh_memfree (centrum, qh normal_size);
+  }
+  if (facet->upperdelaunay && qh DELAUNAY)
+    area= -area;  /* the normal should be [0,...,1] */
+  trace4((qh ferr, "qh_facetarea: f%d area %2.2g\n", facet->id, area)); 
+  return area;
+} /* facetarea */
+
+/*---------------------------------
+
+  qh_facetarea_simplex( dim, apex, vertices, notvertex, toporient, normal, offset )
+    return area for a simplex defined by 
+      an apex, a base of vertices, an orientation, and a unit normal
+    if simplicial or tricoplanar facet, 
+      notvertex is defined and it is skipped in vertices
+  
+  returns:
+    computes area of simplex projected to plane [normal,offset]
+    returns 0 if vertex too far below plane (qh WIDEfacet)
+      vertex can't be apex of tricoplanar facet
+  
+  notes:
+    if (qh DELAUNAY),
+      computes projected area instead for last coordinate
+    uses qh gm_matrix/gm_row and qh hull_dim
+    helper function for qh_facetarea
+  
+  design:
+    if Notvertex
+      translate simplex to apex
+    else
+      project simplex to normal/offset
+      translate simplex to apex
+    if Delaunay
+      set last row/column to 0 with -1 on diagonal 
+    else
+      set last row to Normal
+    compute determinate
+    scale and flip sign for area
+*/
+realT qh_facetarea_simplex (int dim, coordT *apex, setT *vertices, 
+        vertexT *notvertex,  boolT toporient, coordT *normal, realT *offset) {
+  pointT *coorda, *coordp, *gmcoord;
+  coordT **rows, *normalp;
+  int k,  i=0;
+  realT area, dist;
+  vertexT *vertex, **vertexp;
+  boolT nearzero;
+
+  gmcoord= qh gm_matrix;
+  rows= qh gm_row;
+  FOREACHvertex_(vertices) {
+    if (vertex == notvertex)
+      continue;
+    rows[i++]= gmcoord;
+    coorda= apex;
+    coordp= vertex->point;
+    normalp= normal;
+    if (notvertex) {
+      for (k= dim; k--; )
+	*(gmcoord++)= *coordp++ - *coorda++;
+    }else {
+      dist= *offset;
+      for (k= dim; k--; )
+	dist += *coordp++ * *normalp++;
+      if (dist < -qh WIDEfacet) {
+	zinc_(Znoarea);
+	return 0.0;
+      }
+      coordp= vertex->point;
+      normalp= normal;
+      for (k= dim; k--; )
+	*(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++;
+    }
+  }
+  if (i != dim-1) {
+    fprintf (qh ferr, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n", 
+               i, dim);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  rows[i]= gmcoord;
+  if (qh DELAUNAY) {
+    for (i= 0; i < dim-1; i++)
+      rows[i][dim-1]= 0.0;
+    for (k= dim; k--; )
+      *(gmcoord++)= 0.0;
+    rows[dim-1][dim-1]= -1.0;
+  }else {
+    normalp= normal;
+    for (k= dim; k--; )
+      *(gmcoord++)= *normalp++;
+  }
+  zinc_(Zdetsimplex);
+  area= qh_determinant (rows, dim, &nearzero);
+  if (toporient)
+    area= -area;
+  area *= qh AREAfactor;
+  trace4((qh ferr, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n",
+	  area, qh_pointid(apex), toporient, nearzero)); 
+  return area;
+} /* facetarea_simplex */
+
+/*---------------------------------
+  
+  qh_facetcenter( vertices )
+    return Voronoi center (Voronoi vertex) for a facet's vertices
+
+  returns:
+    return temporary point equal to the center
+    
+  see:
+    qh_voronoi_center()
+*/
+pointT *qh_facetcenter (setT *vertices) {
+  setT *points= qh_settemp (qh_setsize (vertices));
+  vertexT *vertex, **vertexp;
+  pointT *center;
+  
+  FOREACHvertex_(vertices) 
+    qh_setappend (&points, vertex->point);
+  center= qh_voronoi_center (qh hull_dim-1, points);
+  qh_settempfree (&points);
+  return center;
+} /* facetcenter */
+
+/*---------------------------------
+  
+  qh_findgooddist( point, facetA, dist, facetlist )
+    find best good facet visible for point from facetA
+    assumes facetA is visible from point
+
+  returns:
+    best facet, i.e., good facet that is furthest from point
+      distance to best facet
+      NULL if none
+      
+    moves good, visible facets (and some other visible facets)
+      to end of qh facet_list
+
+  notes:
+    uses qh visit_id
+
+  design:
+    initialize bestfacet if facetA is good
+    move facetA to end of facetlist
+    for each facet on facetlist
+      for each unvisited neighbor of facet
+        move visible neighbors to end of facetlist
+        update best good neighbor
+        if no good neighbors, update best facet
+*/
+facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp, 
+               facetT **facetlist) {
+  realT bestdist= -REALmax, dist;
+  facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
+  boolT goodseen= False;  
+
+  if (facetA->good) {
+    zinc_(Zcheckpart);  /* calls from check_bestdist occur after print stats */
+    qh_distplane (point, facetA, &bestdist);
+    bestfacet= facetA;
+    goodseen= True;
+  }
+  qh_removefacet (facetA);
+  qh_appendfacet (facetA);
+  *facetlist= facetA;
+  facetA->visitid= ++qh visit_id;
+  FORALLfacet_(*facetlist) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == qh visit_id)
+        continue;
+      neighbor->visitid= qh visit_id;
+      if (goodseen && !neighbor->good)
+        continue;
+      zinc_(Zcheckpart); 
+      qh_distplane (point, neighbor, &dist);
+      if (dist > 0) {
+        qh_removefacet (neighbor);
+        qh_appendfacet (neighbor);
+        if (neighbor->good) {
+          goodseen= True;
+          if (dist > bestdist) {
+            bestdist= dist;
+            bestfacet= neighbor;
+          }
+        }
+      }
+    }
+  }
+  if (bestfacet) {
+    *distp= bestdist;
+    trace2((qh ferr, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
+      qh_pointid(point), bestdist, bestfacet->id));
+    return bestfacet;
+  }
+  trace4((qh ferr, "qh_findgooddist: no good facet for p%d above f%d\n", 
+      qh_pointid(point), facetA->id));
+  return NULL;
+}  /* findgooddist */
+    
+/*---------------------------------
+  
+  qh_getarea( facetlist )
+    set area of all facets in facetlist
+    collect statistics
+
+  returns:
+    sets qh totarea/totvol to total area and volume of convex hull
+    for Delaunay triangulation, computes projected area of the lower or upper hull
+      ignores upper hull if qh ATinfinity
+  
+  notes:
+    could compute outer volume by expanding facet area by rays from interior
+    the following attempt at perpendicular projection underestimated badly:
+      qh.totoutvol += (-dist + facet->maxoutside + qh DISTround) 
+                            * area/ qh hull_dim;
+  design:
+    for each facet on facetlist
+      compute facet->area
+      update qh.totarea and qh.totvol
+*/
+void qh_getarea (facetT *facetlist) {
+  realT area;
+  realT dist;
+  facetT *facet;
+
+  if (qh REPORTfreq)
+    fprintf (qh ferr, "computing area of each facet and volume of the convex hull\n");
+  else 
+    trace1((qh ferr, "qh_getarea: computing volume and area for each facet\n"));
+  qh totarea= qh totvol= 0.0;
+  FORALLfacet_(facetlist) {
+    if (!facet->normal)
+      continue;
+    if (facet->upperdelaunay && qh ATinfinity)
+      continue;
+    facet->f.area= area= qh_facetarea (facet);
+    facet->isarea= True;
+    if (qh DELAUNAY) {
+      if (facet->upperdelaunay == qh UPPERdelaunay)
+	qh totarea += area;
+    }else {
+      qh totarea += area;
+      qh_distplane (qh interior_point, facet, &dist);
+      qh totvol += -dist * area/ qh hull_dim;
+    }
+    if (qh PRINTstatistics) {
+      wadd_(Wareatot, area);
+      wmax_(Wareamax, area);
+      wmin_(Wareamin, area);
+    }
+  }
+} /* getarea */
+
+/*---------------------------------
+  
+  qh_gram_schmidt( dim, row )
+    implements Gram-Schmidt orthogonalization by rows
+
+  returns:
+    false if zero norm
+    overwrites rows[dim][dim]
+
+  notes:
+    see Golub & van Loan Algorithm 6.2-2
+    overflow due to small divisors not handled
+
+  design:
+    for each row
+      compute norm for row
+      if non-zero, normalize row
+      for each remaining rowA
+        compute inner product of row and rowA
+        reduce rowA by row * inner product
+*/
+boolT qh_gram_schmidt(int dim, realT **row) {
+  realT *rowi, *rowj, norm;
+  int i, j, k;
+  
+  for(i=0; i < dim; i++) {
+    rowi= row[i];
+    for (norm= 0.0, k= dim; k--; rowi++)
+      norm += *rowi * *rowi;
+    norm= sqrt(norm);
+    wmin_(Wmindenom, norm);
+    if (norm == 0.0)  /* either 0 or overflow due to sqrt */
+      return False;
+    for(k= dim; k--; )
+      *(--rowi) /= norm;  
+    for(j= i+1; j < dim; j++) {
+      rowj= row[j];
+      for(norm= 0.0, k=dim; k--; )
+	norm += *rowi++ * *rowj++;
+      for(k=dim; k--; )
+	*(--rowj) -= *(--rowi) * norm;
+    }
+  }
+  return True;
+} /* gram_schmidt */
+
+
+/*---------------------------------
+  
+  qh_inthresholds( normal, angle )
+    return True if normal within qh.lower_/upper_threshold
+
+  returns:
+    estimate of angle by summing of threshold diffs
+      angle may be NULL
+      smaller "angle" is better
+  
+  notes:
+    invalid if qh.SPLITthresholds
+
+  see:
+    qh.lower_threshold in qh_initbuild()
+    qh_initthresholds()
+
+  design:
+    for each dimension
+      test threshold
+*/
+boolT qh_inthresholds (coordT *normal, realT *angle) {
+  boolT within= True;
+  int k;
+  realT threshold;
+
+  if (angle)
+    *angle= 0.0;
+  for(k= 0; k < qh hull_dim; k++) {
+    threshold= qh lower_threshold[k];
+    if (threshold > -REALmax/2) {
+      if (normal[k] < threshold)
+        within= False;
+      if (angle) {
+	threshold -= normal[k];
+	*angle += fabs_(threshold);
+      }
+    }
+    if (qh upper_threshold[k] < REALmax/2) {
+      threshold= qh upper_threshold[k];
+      if (normal[k] > threshold)
+        within= False;
+      if (angle) {
+	threshold -= normal[k];
+	*angle += fabs_(threshold);
+      }
+    }
+  }
+  return within;
+} /* inthresholds */
+    
+
+/*---------------------------------
+  
+  qh_joggleinput()
+    randomly joggle input to Qhull by qh.JOGGLEmax
+    initial input is qh.first_point/qh.num_points of qh.hull_dim
+      repeated calls use qh.input_points/qh.num_points
+ 
+  returns:
+    joggles points at qh.first_point/qh.num_points
+    copies data to qh.input_points/qh.input_malloc if first time
+    determines qh.JOGGLEmax if it was zero
+    if qh.DELAUNAY
+      computes the Delaunay projection of the joggled points
+
+  notes:
+    if qh.DELAUNAY, unnecessarily joggles the last coordinate
+    the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease
+
+  design:
+    if qh.DELAUNAY
+      set qh.SCALElast for reduced precision errors
+    if first call
+      initialize qh.input_points to the original input points
+      if qh.JOGGLEmax == 0
+        determine default qh.JOGGLEmax
+    else
+      increase qh.JOGGLEmax according to qh.build_cnt
+    joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax]
+    if qh.DELAUNAY
+      sets the Delaunay projection
+*/
+void qh_joggleinput (void) {
+  int size, i, seed;
+  coordT *coordp, *inputp;
+  realT randr, randa, randb;
+
+  if (!qh input_points) { /* first call */
+    qh input_points= qh first_point;
+    qh input_malloc= qh POINTSmalloc;
+    size= qh num_points * qh hull_dim * sizeof(coordT);
+    if (!(qh first_point=(coordT*)malloc(size))) {
+      fprintf(qh ferr, "qhull error: insufficient memory to joggle %d points\n",
+          qh num_points);
+      qh_errexit(qh_ERRmem, NULL, NULL);
+    }
+    qh POINTSmalloc= True;
+    if (qh JOGGLEmax == 0.0) {
+      qh JOGGLEmax= qh_detjoggle (qh input_points, qh num_points, qh hull_dim);
+      qh_option ("QJoggle", NULL, &qh JOGGLEmax);
+    }
+  }else {                 /* repeated call */
+    if (!qh RERUN && qh build_cnt > qh_JOGGLEretry) {
+      if (((qh build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) {
+	realT maxjoggle= qh MAXwidth * qh_JOGGLEmaxincrease;
+	if (qh JOGGLEmax < maxjoggle) {
+	  qh JOGGLEmax *= qh_JOGGLEincrease;
+	  minimize_(qh JOGGLEmax, maxjoggle); 
+	}
+      }
+    }
+    qh_option ("QJoggle", NULL, &qh JOGGLEmax);
+  }
+  if (qh build_cnt > 1 && qh JOGGLEmax > fmax_(qh MAXwidth/4, 0.1)) {
+      fprintf (qh ferr, "qhull error: the current joggle for 'QJn', %.2g, is too large for the width\nof the input.  If possible, recompile Qhull with higher-precision reals.\n",
+	        qh JOGGLEmax);
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  /* for some reason, using qh ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */
+  seed= qh_RANDOMint;
+  qh_option ("_joggle-seed", &seed, NULL);
+  trace0((qh ferr, "qh_joggleinput: joggle input by %2.2g with seed %d\n", 
+    qh JOGGLEmax, seed));
+  inputp= qh input_points;
+  coordp= qh first_point;
+  randa= 2.0 * qh JOGGLEmax/qh_RANDOMmax;
+  randb= -qh JOGGLEmax;
+  size= qh num_points * qh hull_dim;
+  for (i= size; i--; ) {
+    randr= qh_RANDOMint;
+    *(coordp++)= *(inputp++) + (randr * randa + randb);
+  }
+  if (qh DELAUNAY) {
+    qh last_low= qh last_high= qh last_newhigh= REALmax;
+    qh_setdelaunay (qh hull_dim, qh num_points, qh first_point);
+  }
+} /* joggleinput */
+
+/*---------------------------------
+  
+  qh_maxabsval( normal, dim )
+    return pointer to maximum absolute value of a dim vector
+    returns NULL if dim=0
+*/
+realT *qh_maxabsval (realT *normal, int dim) {
+  realT maxval= -REALmax;
+  realT *maxp= NULL, *colp, absval;
+  int k;
+
+  for (k= dim, colp= normal; k--; colp++) {
+    absval= fabs_(*colp);
+    if (absval > maxval) {
+      maxval= absval;
+      maxp= colp;
+    }
+  }
+  return maxp;
+} /* maxabsval */
+
+
+/*---------------------------------
+  
+  qh_maxmin( points, numpoints, dimension )
+    return max/min points for each dimension      
+    determine max and min coordinates
+
+  returns:
+    returns a temporary set of max and min points
+      may include duplicate points. Does not include qh.GOODpoint
+    sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth
+         qh.MAXlastcoord, qh.MINlastcoord
+    initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok
+
+  notes:
+    loop duplicated in qh_detjoggle()
+
+  design:
+    initialize global precision variables
+    checks definition of REAL...
+    for each dimension
+      for each point
+        collect maximum and minimum point
+      collect maximum of maximums and minimum of minimums
+      determine qh.NEARzero for Gaussian Elimination
+*/
+setT *qh_maxmin(pointT *points, int numpoints, int dimension) {
+  int k;
+  realT maxcoord, temp;
+  pointT *minimum, *maximum, *point, *pointtemp;
+  setT *set;
+
+  qh max_outside= 0.0;
+  qh MAXabs_coord= 0.0;
+  qh MAXwidth= -REALmax;
+  qh MAXsumcoord= 0.0;
+  qh min_vertex= 0.0;
+  qh WAScoplanar= False;
+  if (qh ZEROcentrum)
+    qh ZEROall_ok= True;
+  if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax
+  && REALmax > 0.0 && -REALmax < 0.0)
+    ; /* all ok */
+  else {
+    fprintf (qh ferr, "qhull error: floating point constants in user.h are wrong\n\
+REALepsilon %g REALmin %g REALmax %g -REALmax %g\n",
+	     REALepsilon, REALmin, REALmax, -REALmax);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  set= qh_settemp(2*dimension);
+  for(k= 0; k < dimension; k++) {
+    if (points == qh GOODpointp)
+      minimum= maximum= points + dimension;
+    else
+      minimum= maximum= points;
+    FORALLpoint_(points, numpoints) {
+      if (point == qh GOODpointp)
+	continue;
+      if (maximum[k] < point[k])
+	maximum= point;
+      else if (minimum[k] > point[k])
+	minimum= point;
+    }
+    if (k == dimension-1) {
+      qh MINlastcoord= minimum[k];
+      qh MAXlastcoord= maximum[k];
+    }
+    if (qh SCALElast && k == dimension-1)
+      maxcoord= qh MAXwidth;
+    else {
+      maxcoord= fmax_(maximum[k], -minimum[k]);
+      if (qh GOODpointp) {
+        temp= fmax_(qh GOODpointp[k], -qh GOODpointp[k]);
+        maximize_(maxcoord, temp);
+      }
+      temp= maximum[k] - minimum[k];
+      maximize_(qh MAXwidth, temp);
+    }
+    maximize_(qh MAXabs_coord, maxcoord);
+    qh MAXsumcoord += maxcoord;
+    qh_setappend (&set, maximum);
+    qh_setappend (&set, minimum);
+    /* calculation of qh NEARzero is based on error formula 4.4-13 of
+       Golub & van Loan, authors say n^3 can be ignored and 10 be used in
+       place of rho */
+    qh NEARzero[k]= 80 * qh MAXsumcoord * REALepsilon;
+  }
+  if (qh IStracing >=1)
+    qh_printpoints (qh ferr, "qh_maxmin: found the max and min points (by dim):", set);
+  return(set);
+} /* maxmin */
+
+/*---------------------------------
+
+  qh_maxouter()
+    return maximum distance from facet to outer plane
+    normally this is qh.max_outside+qh.DISTround
+    does not include qh.JOGGLEmax
+
+  see:
+    qh_outerinner()
+    
+  notes:
+    need to add another qh.DISTround if testing actual point with computation
+
+  for joggle:
+    qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex)
+    need to use Wnewvertexmax since could have a coplanar point for a high 
+      facet that is replaced by a low facet
+    need to add qh.JOGGLEmax if testing input points
+*/
+realT qh_maxouter (void) {
+  realT dist;
+
+  dist= fmax_(qh max_outside, qh DISTround);
+  dist += qh DISTround;
+  trace4((qh ferr, "qh_maxouter: max distance from facet to outer plane is %2.2g max_outside is %2.2g\n", dist, qh max_outside));
+  return dist;
+} /* maxouter */
+
+/*---------------------------------
+  
+  qh_maxsimplex( dim, maxpoints, points, numpoints, simplex )
+    determines maximum simplex for a set of points 
+    starts from points already in simplex
+    skips qh.GOODpointp (assumes that it isn't in maxpoints)
+  
+  returns:
+    simplex with dim+1 points
+
+  notes:
+    assumes at least pointsneeded points in points
+    maximizes determinate for x,y,z,w, etc.
+    uses maxpoints as long as determinate is clearly non-zero
+
+  design:
+    initialize simplex with at least two points
+      (find points with max or min x coordinate)
+    for each remaining dimension
+      add point that maximizes the determinate
+        (use points from maxpoints first)    
+*/
+void qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
+  pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
+  boolT nearzero, maxnearzero= False;
+  int k, sizinit;
+  realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;
+
+  sizinit= qh_setsize (*simplex);
+  if (sizinit < 2) {
+    if (qh_setsize (maxpoints) >= 2) {
+      FOREACHpoint_(maxpoints) {
+        if (maxcoord < point[0]) {
+          maxcoord= point[0];
+          maxx= point;
+        }
+	if (mincoord > point[0]) {
+          mincoord= point[0];
+          minx= point;
+        }
+      }
+    }else {
+      FORALLpoint_(points, numpoints) {
+	if (point == qh GOODpointp)
+	  continue;
+        if (maxcoord < point[0]) {
+	  maxcoord= point[0];
+          maxx= point;
+        }
+	if (mincoord > point[0]) {
+          mincoord= point[0];
+          minx= point;
+	}
+      }
+    }
+    qh_setunique (simplex, minx);
+    if (qh_setsize (*simplex) < 2)
+      qh_setunique (simplex, maxx);
+    sizinit= qh_setsize (*simplex);
+    if (sizinit < 2) {
+      qh_precision ("input has same x coordinate");
+      if (zzval_(Zsetplane) > qh hull_dim+1) {
+	fprintf (qh ferr, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n",
+		 qh_setsize(maxpoints)+numpoints);
+	qh_errexit (qh_ERRprec, NULL, NULL);
+      }else {
+	fprintf (qh ferr, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh hull_dim);
+	qh_errexit (qh_ERRinput, NULL, NULL);
+      }
+    }
+  }
+  for(k= sizinit; k < dim+1; k++) {
+    maxpoint= NULL;
+    maxdet= -REALmax;
+    FOREACHpoint_(maxpoints) {
+      if (!qh_setin (*simplex, point)) {
+        det= qh_detsimplex(point, *simplex, k, &nearzero);
+        if ((det= fabs_(det)) > maxdet) {
+	  maxdet= det;
+          maxpoint= point;
+	  maxnearzero= nearzero;
+        }
+      }
+    }
+    if (!maxpoint || maxnearzero) {
+      zinc_(Zsearchpoints);
+      if (!maxpoint) {
+        trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1));
+      }else {
+        trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n",
+		k+1, qh_pointid(maxpoint), maxdet));
+      }
+      FORALLpoint_(points, numpoints) {
+	if (point == qh GOODpointp)
+	  continue;
+        if (!qh_setin (*simplex, point)) {
+          det= qh_detsimplex(point, *simplex, k, &nearzero);
+          if ((det= fabs_(det)) > maxdet) {
+	    maxdet= det;
+            maxpoint= point;
+	    maxnearzero= nearzero;
+	  }
+        }
+      }
+    } /* !maxpoint */
+    if (!maxpoint) {
+      fprintf (qh ferr, "qhull internal error (qh_maxsimplex): not enough points available\n");
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }
+    qh_setappend(simplex, maxpoint);
+    trace1((qh ferr, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",
+	    qh_pointid(maxpoint), k+1, maxdet));
+  } /* k */ 
+} /* maxsimplex */
+
+/*---------------------------------
+  
+  qh_minabsval( normal, dim )
+    return minimum absolute value of a dim vector
+*/
+realT qh_minabsval (realT *normal, int dim) {
+  realT minval= 0;
+  realT maxval= 0;
+  realT *colp;
+  int k;
+
+  for (k= dim, colp= normal; k--; colp++) {
+    maximize_(maxval, *colp);
+    minimize_(minval, *colp);
+  }
+  return fmax_(maxval, -minval);
+} /* minabsval */
+
+
+/*---------------------------------
+  
+  qh_mindif( vecA, vecB, dim )
+    return index of min abs. difference of two vectors
+*/
+int qh_mindiff (realT *vecA, realT *vecB, int dim) {
+  realT mindiff= REALmax, diff;
+  realT *vecAp= vecA, *vecBp= vecB;
+  int k, mink= 0;
+
+  for (k= 0; k < dim; k++) {
+    diff= *vecAp++ - *vecBp++;
+    diff= fabs_(diff);
+    if (diff < mindiff) {
+      mindiff= diff;
+      mink= k;
+    }
+  }
+  return mink;
+} /* mindiff */
+
+
+
+/*---------------------------------
+  
+  qh_orientoutside( facet  )
+    make facet outside oriented via qh.interior_point
+
+  returns:
+    True if facet reversed orientation.
+*/
+boolT qh_orientoutside (facetT *facet) {
+  int k;
+  realT dist;
+
+  qh_distplane (qh interior_point, facet, &dist);
+  if (dist > 0) {
+    for (k= qh hull_dim; k--; )
+      facet->normal[k]= -facet->normal[k];
+    facet->offset= -facet->offset;
+    return True;
+  }
+  return False;
+} /* orientoutside */
+
+/*---------------------------------
+  
+  qh_outerinner( facet, outerplane, innerplane  )
+    if facet and qh.maxoutdone (i.e., qh_check_maxout)
+      returns outer and inner plane for facet
+    else
+      returns maximum outer and inner plane
+    accounts for qh.JOGGLEmax
+
+  see:
+    qh_maxouter(), qh_check_bestdist(), qh_check_points()
+
+  notes:
+    outerplaner or innerplane may be NULL
+    
+    includes qh.DISTround for actual points
+    adds another qh.DISTround if testing with floating point arithmetic
+*/
+void qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane) {
+  realT dist, mindist;
+  vertexT *vertex, **vertexp;
+
+  if (outerplane) {
+    if (!qh_MAXoutside || !facet || !qh maxoutdone) {
+      *outerplane= qh_maxouter();       /* includes qh.DISTround */
+    }else { /* qh_MAXoutside ... */
+#if qh_MAXoutside 
+      *outerplane= facet->maxoutside + qh DISTround;
+#endif
+      
+    }
+    if (qh JOGGLEmax < REALmax/2)
+      *outerplane += qh JOGGLEmax * sqrt (qh hull_dim);
+  }
+  if (innerplane) {
+    if (facet) {
+      mindist= REALmax;
+      FOREACHvertex_(facet->vertices) {
+        zinc_(Zdistio);
+        qh_distplane (vertex->point, facet, &dist);
+        minimize_(mindist, dist);
+      }
+      *innerplane= mindist - qh DISTround;
+    }else 
+      *innerplane= qh min_vertex - qh DISTround;
+    if (qh JOGGLEmax < REALmax/2)
+      *innerplane -= qh JOGGLEmax * sqrt (qh hull_dim);
+  }
+} /* outerinner */
+
+/*---------------------------------
+  
+  qh_pointdist( point1, point2, dim )
+    return distance between two points
+
+  notes:
+    returns distance squared if 'dim' is negative
+*/
+coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
+  coordT dist, diff;
+  int k;
+  
+  dist= 0.0;
+  for (k= (dim > 0 ? dim : -dim); k--; ) {
+    diff= *point1++ - *point2++;
+    dist += diff * diff;
+  }
+  if (dim > 0)
+    return(sqrt(dist));
+  return dist;
+} /* pointdist */
+
+
+/*---------------------------------
+  
+  qh_printmatrix( fp, string, rows, numrow, numcol )
+    print matrix to fp given by row vectors
+    print string as header
+
+  notes:
+    print a vector by qh_printmatrix(fp, "", &vect, 1, len)
+*/
+void qh_printmatrix (FILE *fp, char *string, realT **rows, int numrow, int numcol) {
+  realT *rowp;
+  realT r; /*bug fix*/
+  int i,k;
+
+  fprintf (fp, "%s\n", string);
+  for (i= 0; i < numrow; i++) {
+    rowp= rows[i];
+    for (k= 0; k < numcol; k++) {
+      r= *rowp++;
+      fprintf (fp, "%6.3g ", r);
+    }
+    fprintf (fp, "\n");
+  }
+} /* printmatrix */
+
+  
+/*---------------------------------
+  
+  qh_printpoints( fp, string, points )
+    print pointids to fp for a set of points
+    if string, prints string and 'p' point ids
+*/
+void qh_printpoints (FILE *fp, char *string, setT *points) {
+  pointT *point, **pointp;
+
+  if (string) {
+    fprintf (fp, "%s", string);
+    FOREACHpoint_(points) 
+      fprintf (fp, " p%d", qh_pointid(point));
+    fprintf (fp, "\n");
+  }else {
+    FOREACHpoint_(points) 
+      fprintf (fp, " %d", qh_pointid(point));
+    fprintf (fp, "\n");
+  }
+} /* printpoints */
+
+  
+/*---------------------------------
+  
+  qh_projectinput()
+    project input points using qh.lower_bound/upper_bound and qh DELAUNAY
+    if qh.lower_bound[k]=qh.upper_bound[k]= 0, 
+      removes dimension k 
+    if halfspace intersection
+      removes dimension k from qh.feasible_point
+    input points in qh first_point, num_points, input_dim
+
+  returns:
+    new point array in qh first_point of qh hull_dim coordinates
+    sets qh POINTSmalloc
+    if qh DELAUNAY 
+      projects points to paraboloid
+      lowbound/highbound is also projected
+    if qh ATinfinity
+      adds point "at-infinity"
+    if qh POINTSmalloc 
+      frees old point array
+
+  notes:
+    checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY
+
+
+  design:
+    sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay)
+    determines newdim and newnum for qh hull_dim and qh num_points
+    projects points to newpoints
+    projects qh.lower_bound to itself
+    projects qh.upper_bound to itself
+    if qh DELAUNAY
+      if qh ATINFINITY
+        projects points to paraboloid
+        computes "infinity" point as vertex average and 10% above all points 
+      else
+        uses qh_setdelaunay to project points to paraboloid
+*/
+void qh_projectinput (void) {
+  int k,i;
+  int newdim= qh input_dim, newnum= qh num_points;
+  signed char *project;
+  int size= (qh input_dim+1)*sizeof(*project);
+  pointT *newpoints, *coord, *infinity;
+  realT paraboloid, maxboloid= 0;
+  
+  project= (signed char*)qh_memalloc (size);
+  memset ((char*)project, 0, size);
+  for (k= 0; k < qh input_dim; k++) {   /* skip Delaunay bound */
+    if (qh lower_bound[k] == 0 && qh upper_bound[k] == 0) {
+      project[k]= -1;
+      newdim--;
+    }
+  }
+  if (qh DELAUNAY) {
+    project[k]= 1;
+    newdim++;
+    if (qh ATinfinity)
+      newnum++;
+  }
+  if (newdim != qh hull_dim) {
+    fprintf(qh ferr, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh hull_dim);
+    qh_errexit(qh_ERRqhull, NULL, NULL);
+  }
+  if (!(newpoints=(coordT*)malloc(newnum*newdim*sizeof(coordT)))){
+    fprintf(qh ferr, "qhull error: insufficient memory to project %d points\n",
+           qh num_points);
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  qh_projectpoints (project, qh input_dim+1, qh first_point,
+                    qh num_points, qh input_dim, newpoints, newdim);
+  trace1((qh ferr, "qh_projectinput: updating lower and upper_bound\n"));
+  qh_projectpoints (project, qh input_dim+1, qh lower_bound,
+                    1, qh input_dim+1, qh lower_bound, newdim+1);
+  qh_projectpoints (project, qh input_dim+1, qh upper_bound,
+                    1, qh input_dim+1, qh upper_bound, newdim+1);
+  if (qh HALFspace) {
+    if (!qh feasible_point) {
+      fprintf(qh ferr, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n");
+      qh_errexit(qh_ERRqhull, NULL, NULL);
+    }
+    qh_projectpoints (project, qh input_dim, qh feasible_point,
+		      1, qh input_dim, qh feasible_point, newdim);
+  }
+  qh_memfree(project, ((qh input_dim+1)*sizeof(*project)));
+  if (qh POINTSmalloc)
+    free (qh first_point);
+  qh first_point= newpoints;
+  qh POINTSmalloc= True;
+  if (qh DELAUNAY && qh ATinfinity) {
+    coord= qh first_point;
+    infinity= qh first_point + qh hull_dim * qh num_points;
+    for (k=qh hull_dim-1; k--; )
+      infinity[k]= 0.0;
+    for (i=qh num_points; i--; ) {
+      paraboloid= 0.0;
+      for (k=qh hull_dim-1; k--; ) {
+        paraboloid += *coord * *coord;
+	infinity[k] += *coord;
+        coord++;
+      }
+      *(coord++)= paraboloid;
+      maximize_(maxboloid, paraboloid);
+    }
+    /* coord == infinity */
+    for (k=qh hull_dim-1; k--; )
+      *(coord++) /= qh num_points;
+    *(coord++)= maxboloid * 1.1;
+    qh num_points++;
+    trace0((qh ferr, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
+  }else if (qh DELAUNAY)  /* !qh ATinfinity */
+    qh_setdelaunay( qh hull_dim, qh num_points, qh first_point);
+} /* projectinput */
+
+  
+/*---------------------------------
+  
+  qh_projectpoints( project, n, points, numpoints, dim, newpoints, newdim )
+    project points/numpoints/dim to newpoints/newdim
+    if project[k] == -1
+      delete dimension k 
+    if project[k] == 1 
+      add dimension k by duplicating previous column
+    n is size of project
+
+  notes:
+    newpoints may be points if only adding dimension at end
+
+  design:
+    check that 'project' and 'newdim' agree
+    for each dimension
+      if project == -1
+        skip dimension
+      else
+        determine start of column in newpoints
+        determine start of column in points 
+          if project == +1, duplicate previous column
+        copy dimension (column) from points to newpoints
+*/
+void qh_projectpoints (signed char *project, int n, realT *points, 
+        int numpoints, int dim, realT *newpoints, int newdim) {
+  int testdim= dim, oldk=0, newk=0, i,j=0,k;
+  realT *newp, *oldp;
+  
+  for (k= 0; k < n; k++)
+    testdim += project[k];
+  if (testdim != newdim) {
+    fprintf (qh ferr, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n",
+      newdim, testdim);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  for (j= 0; j= dim)
+	  continue;
+	oldp= points+oldk;
+      }else 
+	oldp= points+oldk++;
+      for (i=numpoints; i--; ) {
+        *newp= *oldp;
+        newp += newdim;
+        oldp += dim;
+      }
+    }
+    if (oldk >= dim)
+      break;
+  }
+  trace1((qh ferr, "qh_projectpoints: projected %d points from dim %d to dim %d\n", 
+    numpoints, dim, newdim));
+} /* projectpoints */
+        
+
+/*---------------------------------
+  
+  qh_rand() 
+  qh_srand( seed )
+    generate pseudo-random number between 1 and 2^31 -2
+
+  notes:
+    from Park & Miller's minimimal standard random number generator
+       Communications of the ACM, 31:1192-1201, 1988.
+    does not use 0 or 2^31 -1
+       this is silently enforced by qh_srand()
+    can make 'Rn' much faster by moving qh_rand to qh_distplane
+*/
+int qh_rand_seed= 1;  /* define as global variable instead of using qh */
+
+int qh_rand( void) {
+#define qh_rand_a 16807
+#define qh_rand_m 2147483647
+#define qh_rand_q 127773  /* m div a */
+#define qh_rand_r 2836    /* m mod a */
+  int lo, hi, test;
+  int seed = qh_rand_seed;
+
+  hi = seed / qh_rand_q;  /* seed div q */
+  lo = seed % qh_rand_q;  /* seed mod q */
+  test = qh_rand_a * lo - qh_rand_r * hi;
+  if (test > 0)
+    seed= test;
+  else
+    seed= test + qh_rand_m;
+  qh_rand_seed= seed;
+  /* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax;  for testing */
+  /* seed = qh_RANDOMmax;  for testing */
+  return seed;
+} /* rand */
+
+void qh_srand( int seed) {
+  if (seed < 1)
+    qh_rand_seed= 1;
+  else if (seed >= qh_rand_m)
+    qh_rand_seed= qh_rand_m - 1;
+  else
+    qh_rand_seed= seed;
+} /* qh_srand */
+
+/*---------------------------------
+  
+  qh_randomfactor()
+    return a random factor within qh.RANDOMmax of 1.0
+
+  notes:
+    qh.RANDOMa/b are defined in global.c
+*/
+realT qh_randomfactor (void) {
+  realT randr;
+
+  randr= qh_RANDOMint;
+  return randr * qh RANDOMa + qh RANDOMb;
+} /* randomfactor */
+
+/*---------------------------------
+  
+  qh_randommatrix( buffer, dim, rows )
+    generate a random dim X dim matrix in range [-1,1]
+    assumes buffer is [dim+1, dim]
+
+  returns:
+    sets buffer to random numbers
+    sets rows to rows of buffer
+      sets row[dim] as scratch row
+*/
+void qh_randommatrix (realT *buffer, int dim, realT **rows) {
+  int i, k;
+  realT **rowi, *coord, realr;
+
+  coord= buffer;
+  rowi= rows;
+  for (i=0; i < dim; i++) {
+    *(rowi++)= coord;
+    for (k=0; k < dim; k++) {
+      realr= qh_RANDOMint;
+      *(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
+    }
+  }
+  *rowi= coord;
+} /* randommatrix */
+
+        
+/*---------------------------------
+  
+  qh_rotateinput( rows )
+    rotate input using row matrix
+    input points given by qh first_point, num_points, hull_dim
+    assumes rows[dim] is a scratch buffer
+    if qh POINTSmalloc, overwrites input points, else mallocs a new array
+
+  returns:
+    rotated input
+    sets qh POINTSmalloc
+
+  design:
+    see qh_rotatepoints
+*/
+void qh_rotateinput (realT **rows) {
+
+  if (!qh POINTSmalloc) {
+    qh first_point= qh_copypoints (qh first_point, qh num_points, qh hull_dim);
+    qh POINTSmalloc= True;
+  }
+  qh_rotatepoints (qh first_point, qh num_points, qh hull_dim, rows);
+}  /* rotateinput */
+
+/*---------------------------------
+  
+  qh_rotatepoints( points, numpoints, dim, row )
+    rotate numpoints points by a d-dim row matrix
+    assumes rows[dim] is a scratch buffer
+
+  returns:
+    rotated points in place
+
+  design:
+    for each point
+      for each coordinate
+        use row[dim] to compute partial inner product
+      for each coordinate
+        rotate by partial inner product
+*/
+void qh_rotatepoints (realT *points, int numpoints, int dim, realT **row) {
+  realT *point, *rowi, *coord= NULL, sum, *newval;
+  int i,j,k;
+
+  if (qh IStracing >= 1)
+    qh_printmatrix (qh ferr, "qh_rotatepoints: rotate points by", row, dim, dim);
+  for (point= points, j= numpoints; j--; point += dim) {
+    newval= row[dim];
+    for (i= 0; i < dim; i++) {
+      rowi= row[i];
+      coord= point;
+      for (sum= 0.0, k= dim; k--; )
+        sum += *rowi++ * *coord++;
+      *(newval++)= sum;
+    }
+    for (k= dim; k--; )
+      *(--coord)= *(--newval);
+  }
+} /* rotatepoints */  
+  
+
+/*---------------------------------
+  
+  qh_scaleinput()
+    scale input points using qh low_bound/high_bound
+    input points given by qh first_point, num_points, hull_dim
+    if qh POINTSmalloc, overwrites input points, else mallocs a new array
+
+  returns:
+    scales coordinates of points to low_bound[k], high_bound[k]
+    sets qh POINTSmalloc
+
+  design:
+    see qh_scalepoints
+*/
+void qh_scaleinput (void) {
+
+  if (!qh POINTSmalloc) {
+    qh first_point= qh_copypoints (qh first_point, qh num_points, qh hull_dim);
+    qh POINTSmalloc= True;
+  }
+  qh_scalepoints (qh first_point, qh num_points, qh hull_dim,
+       qh lower_bound, qh upper_bound);
+}  /* scaleinput */
+  
+/*---------------------------------
+  
+  qh_scalelast( points, numpoints, dim, low, high, newhigh )
+    scale last coordinate to [0,m] for Delaunay triangulations
+    input points given by points, numpoints, dim
+
+  returns:
+    changes scale of last coordinate from [low, high] to [0, newhigh]
+    overwrites last coordinate of each point
+    saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay()
+
+  notes:
+    when called by qh_setdelaunay, low/high may not match actual data
+    
+  design:
+    compute scale and shift factors
+    apply to last coordinate of each point
+*/
+void qh_scalelast (coordT *points, int numpoints, int dim, coordT low,
+		   coordT high, coordT newhigh) {
+  realT scale, shift;
+  coordT *coord;
+  int i;
+  boolT nearzero= False;
+
+  trace4((qh ferr, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n",
+    low, high, newhigh));
+  qh last_low= low;
+  qh last_high= high;
+  qh last_newhigh= newhigh;
+  scale= qh_divzero (newhigh, high - low,
+                  qh MINdenom_1, &nearzero);
+  if (nearzero) {
+    if (qh DELAUNAY)
+      fprintf (qh ferr, "qhull input error: can not scale last coordinate.  Input is cocircular\n   or cospherical.   Use option 'Qz' to add a point at infinity.\n");
+    else
+      fprintf (qh ferr, "qhull input error: can not scale last coordinate.  New bounds [0, %2.2g] are too wide for\nexisting bounds [%2.2g, %2.2g] (width %2.2g)\n",
+		newhigh, low, high, high-low);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  shift= - low * newhigh / (high-low);
+  coord= points + dim - 1;
+  for (i= numpoints; i--; coord += dim)
+    *coord= *coord * scale + shift;
+} /* scalelast */
+
+/*---------------------------------
+  
+  qh_scalepoints( points, numpoints, dim, newlows, newhighs )
+    scale points to new lowbound and highbound
+    retains old bound when newlow= -REALmax or newhigh= +REALmax
+
+  returns:
+    scaled points
+    overwrites old points
+
+  design:
+    for each coordinate
+      compute current low and high bound
+      compute scale and shift factors
+      scale all points
+      enforce new low and high bound for all points
+*/
+void qh_scalepoints (pointT *points, int numpoints, int dim,
+	realT *newlows, realT *newhighs) {
+  int i,k;
+  realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
+  boolT nearzero= False;
+     
+  for (k= 0; k < dim; k++) {
+    newhigh= newhighs[k];
+    newlow= newlows[k];
+    if (newhigh > REALmax/2 && newlow < -REALmax/2)
+      continue;
+    low= REALmax;
+    high= -REALmax;
+    for (i= numpoints, coord= points+k; i--; coord += dim) {
+      minimize_(low, *coord);
+      maximize_(high, *coord);
+    }
+    if (newhigh > REALmax/2)
+      newhigh= high;
+    if (newlow < -REALmax/2)
+      newlow= low;
+    if (qh DELAUNAY && k == dim-1 && newhigh < newlow) {
+      fprintf (qh ferr, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n",
+	       k, k, newhigh, newlow);
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    scale= qh_divzero (newhigh - newlow, high - low,
+                  qh MINdenom_1, &nearzero);
+    if (nearzero) {
+      fprintf (qh ferr, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n",
+              k, newlow, newhigh, low, high);
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    shift= (newlow * high - low * newhigh)/(high-low);
+    coord= points+k;
+    for (i= numpoints; i--; coord += dim)
+      *coord= *coord * scale + shift;
+    coord= points+k;
+    if (newlow < newhigh) {
+      mincoord= newlow;
+      maxcoord= newhigh;
+    }else {
+      mincoord= newhigh;
+      maxcoord= newlow;
+    }
+    for (i= numpoints; i--; coord += dim) {
+      minimize_(*coord, maxcoord);  /* because of roundoff error */
+      maximize_(*coord, mincoord);
+    }
+    trace0((qh ferr, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",
+      k, low, high, newlow, newhigh, numpoints, scale, shift));
+  }
+} /* scalepoints */    
+
+       
+/*---------------------------------
+  
+  qh_setdelaunay( dim, count, points )
+    project count points to dim-d paraboloid for Delaunay triangulation
+    
+    dim is one more than the dimension of the input set
+    assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation)
+
+    points is a dim*count realT array.  The first dim-1 coordinates
+    are the coordinates of the first input point.  array[dim] is
+    the first coordinate of the second input point.  array[2*dim] is
+    the first coordinate of the third input point.
+
+    if qh.last_low defined (i.e., 'Qbb' called qh_scalelast)
+      calls qh_scalelast to scale the last coordinate the same as the other points
+
+  returns:
+    for each point
+      sets point[dim-1] to sum of squares of coordinates
+    scale points to 'Qbb' if needed
+      
+  notes:
+    to project one point, use
+      qh_setdelaunay (qh hull_dim, 1, point)
+      
+    Do not use options 'Qbk', 'QBk', or 'QbB' since they scale 
+    the coordinates after the original projection.
+
+*/
+void qh_setdelaunay (int dim, int count, pointT *points) {
+  int i, k;
+  coordT *coordp, coord;
+  realT paraboloid;
+
+  trace0((qh ferr, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count));
+  coordp= points;
+  for (i= 0; i < count; i++) {
+    coord= *coordp++;
+    paraboloid= coord*coord;
+    for (k= dim-2; k--; ) {
+      coord= *coordp++;
+      paraboloid += coord*coord;
+    }
+    *coordp++ = paraboloid;
+  }
+  if (qh last_low < REALmax/2) 
+    qh_scalelast (points, count, dim, qh last_low, qh last_high, qh last_newhigh);
+} /* setdelaunay */
+
+  
+/*---------------------------------
+  
+  qh_sethalfspace( dim, coords, nextp, normal, offset, feasible )
+    set point to dual of halfspace relative to feasible point
+    halfspace is normal coefficients and offset.
+
+  returns:
+    false if feasible point is outside of hull (error message already reported)
+    overwrites coordinates for point at dim coords
+    nextp= next point (coords)
+
+  design:
+    compute distance from feasible point to halfspace
+    divide each normal coefficient by -dist
+*/
+boolT qh_sethalfspace (int dim, coordT *coords, coordT **nextp, 
+         coordT *normal, coordT *offset, coordT *feasible) {
+  coordT *normp= normal, *feasiblep= feasible, *coordp= coords;
+  realT dist;
+  realT r; /*bug fix*/
+  int k;
+  boolT zerodiv;
+
+  dist= *offset;
+  for (k= dim; k--; )
+    dist += *(normp++) * *(feasiblep++);
+  if (dist > 0)
+    goto LABELerroroutside;
+  normp= normal;
+  if (dist < -qh MINdenom) {
+    for (k= dim; k--; )
+      *(coordp++)= *(normp++) / -dist;
+  }else {
+    for (k= dim; k--; ) {
+      *(coordp++)= qh_divzero (*(normp++), -dist, qh MINdenom_1, &zerodiv);
+      if (zerodiv) 
+        goto LABELerroroutside;
+    }
+  }
+  *nextp= coordp;
+  if (qh IStracing >= 4) {
+    fprintf (qh ferr, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset);
+    for (k= dim, coordp= coords; k--; ) {
+      r= *coordp++;
+      fprintf (qh ferr, " %6.2g", r);
+    }
+    fprintf (qh ferr, "\n");
+  }
+  return True;
+LABELerroroutside:
+  feasiblep= feasible;
+  normp= normal;
+  fprintf(qh ferr, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: ");
+  for (k= dim; k--; )
+    fprintf (qh ferr, qh_REAL_1, r=*(feasiblep++));
+  fprintf (qh ferr, "\n     halfspace: "); 
+  for (k= dim; k--; )
+    fprintf (qh ferr, qh_REAL_1, r=*(normp++));
+  fprintf (qh ferr, "\n     at offset: ");
+  fprintf (qh ferr, qh_REAL_1, *offset);
+  fprintf (qh ferr, " and distance: ");
+  fprintf (qh ferr, qh_REAL_1, dist);
+  fprintf (qh ferr, "\n");
+  return False;
+} /* sethalfspace */
+
+/*---------------------------------
+  
+  qh_sethalfspace_all( dim, count, halfspaces, feasible )
+    generate dual for halfspace intersection with feasible point
+    array of count halfspaces
+      each halfspace is normal coefficients followed by offset 
+      the origin is inside the halfspace if the offset is negative
+
+  returns:
+    malloc'd array of count X dim-1 points
+
+  notes:
+    call before qh_init_B or qh_initqhull_globals 
+    unused/untested code: please email bradb@shore.net if this works ok for you
+    If using option 'Fp', also set qh feasible_point. It is a malloc'd array 
+      that is freed by qh_freebuffers.
+
+  design:
+    see qh_sethalfspace
+*/
+coordT *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible) {
+  int i, newdim;
+  pointT *newpoints;
+  coordT *coordp, *normalp, *offsetp;
+
+  trace0((qh ferr, "qh_sethalfspace_all: compute dual for halfspace intersection\n"));
+  newdim= dim - 1;
+  if (!(newpoints=(coordT*)malloc(count*newdim*sizeof(coordT)))){
+    fprintf(qh ferr, "qhull error: insufficient memory to compute dual of %d halfspaces\n",
+          count);
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  coordp= newpoints;
+  normalp= halfspaces;
+  for (i= 0; i < count; i++) {
+    offsetp= normalp + newdim;
+    if (!qh_sethalfspace (newdim, coordp, &coordp, normalp, offsetp, feasible)) {
+      fprintf (qh ferr, "The halfspace was at index %d\n", i);
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    normalp= offsetp + 1;
+  }
+  return newpoints;
+} /* sethalfspace_all */
+
+  
+/*---------------------------------
+  
+  qh_sharpnewfacets()
+
+  returns:
+    true if could be an acute angle (facets in different quadrants)
+ 
+  notes:
+    for qh_findbest
+
+  design:
+    for all facets on qh.newfacet_list
+      if two facets are in different quadrants
+        set issharp
+*/
+boolT qh_sharpnewfacets () {
+  facetT *facet;
+  boolT issharp = False;
+  int *quadrant, k;
+  
+  quadrant= (int*)qh_memalloc (qh hull_dim * sizeof(int));
+  FORALLfacet_(qh newfacet_list) {
+    if (facet == qh newfacet_list) {
+      for (k= qh hull_dim; k--; )
+      	quadrant[ k]= (facet->normal[ k] > 0);
+    }else {
+      for (k= qh hull_dim; k--; ) {
+        if (quadrant[ k] != (facet->normal[ k] > 0)) {
+          issharp= True;
+          break;
+        }
+      }
+    }
+    if (issharp)
+      break;
+  }
+  qh_memfree( quadrant, qh hull_dim * sizeof(int));
+  trace3((qh ferr, "qh_sharpnewfacets: %d\n", issharp));
+  return issharp;
+} /* sharpnewfacets */
+
+/*---------------------------------
+  
+  qh_voronoi_center( dim, points )
+    return Voronoi center for a set of points
+    dim is the orginal dimension of the points
+    gh.gm_matrix/qh.gm_row are scratch buffers
+
+  returns:
+    center as a temporary point
+    if non-simplicial, 
+      returns center for max simplex of points
+
+  notes:
+    from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65
+
+  design:
+    if non-simplicial
+      determine max simplex for points
+    translate point0 of simplex to origin
+    compute sum of squares of diagonal
+    compute determinate
+    compute Voronoi center (see Bowyer & Woodwark)
+*/
+pointT *qh_voronoi_center (int dim, setT *points) {
+  pointT *point, **pointp, *point0;
+  pointT *center= (pointT*)qh_memalloc (qh center_size);
+  setT *simplex;
+  int i, j, k, size= qh_setsize(points);
+  coordT *gmcoord;
+  realT *diffp, sum2, *sum2row, *sum2p, det, factor;
+  boolT nearzero, infinite;
+
+  if (size == dim+1)
+    simplex= points;
+  else if (size < dim+1) {
+    fprintf (qh ferr, "qhull internal error (qh_voronoi_center):\n  need at least %d points to construct a Voronoi center\n",
+	     dim+1);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }else {
+    simplex= qh_settemp (dim+1);
+    qh_maxsimplex (dim, points, NULL, 0, &simplex);
+  }
+  point0= SETfirstt_(simplex, pointT);
+  gmcoord= qh gm_matrix;
+  for (k=0; k < dim; k++) {
+    qh gm_row[k]= gmcoord;
+    FOREACHpoint_(simplex) {
+      if (point != point0)
+        *(gmcoord++)= point[k] - point0[k];
+    }
+  }
+  sum2row= gmcoord;
+  for (i=0; i < dim; i++) {
+    sum2= 0.0;
+    for (k= 0; k < dim; k++) {
+      diffp= qh gm_row[k] + i;
+      sum2 += *diffp * *diffp;
+    }
+    *(gmcoord++)= sum2;
+  }
+  det= qh_determinant (qh gm_row, dim, &nearzero);
+  factor= qh_divzero (0.5, det, qh MINdenom, &infinite);
+  if (infinite) {
+    for (k=dim; k--; )
+      center[k]= qh_INFINITE;
+    if (qh IStracing)
+      qh_printpoints (qh ferr, "qh_voronoi_center: at infinity for ", simplex);
+  }else {
+    for (i=0; i < dim; i++) {
+      gmcoord= qh gm_matrix;
+      sum2p= sum2row;
+      for (k=0; k < dim; k++) {
+	qh gm_row[k]= gmcoord;
+	if (k == i) {
+	  for (j= dim; j--; )
+	    *(gmcoord++)= *sum2p++;
+	}else {
+	  FOREACHpoint_(simplex) {
+	    if (point != point0)
+	      *(gmcoord++)= point[k] - point0[k];
+	  }
+	}
+      }
+      center[i]= qh_determinant (qh gm_row, dim, &nearzero)*factor + point0[i];
+    }
+#ifndef qh_NOtrace
+    if (qh IStracing >= 3) {
+      fprintf (qh ferr, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
+      qh_printmatrix (qh ferr, "center:", ¢er, 1, dim);
+      if (qh IStracing >= 5) {
+	qh_printpoints (qh ferr, "points", simplex);
+	FOREACHpoint_(simplex)
+	  fprintf (qh ferr, "p%d dist %.2g, ", qh_pointid (point),
+		   qh_pointdist (point, center, dim));
+	fprintf (qh ferr, "\n");
+      }
+    }
+#endif
+  }
+  if (simplex != points)
+    qh_settempfree (&simplex);
+  return center;
+} /* voronoi_center */
+
diff --git a/extern/qhull/src/global.c b/extern/qhull/src/global.c
new file mode 100644
index 00000000000..d3e141aa985
--- /dev/null
+++ b/extern/qhull/src/global.c
@@ -0,0 +1,2018 @@
+/*
  ---------------------------------
+
+   global.c
+   initializes all the globals of the qhull application
+
+   see README
+
+   see qhull.h for qh.globals and function prototypes
+
+   see qhull_a.h for internal functions
+
+   copyright (c) 1993-2002, The Geometry Center
+ */
+
+#include "qhull_a.h"
+
+/*========= qh definition =======================*/
+
+#if qh_QHpointer
+qhT *qh_qh= NULL;	/* pointer to all global variables */
+#else
+qhT qh_qh;     		/* all global variables.
+			   Add "= {0}" if this causes a compiler error.
+			   Also qh_qhstat in stat.c and qhmem in mem.c.  */
+#endif
+
+/*---------------------------------
+
+  qh_appendprint( printFormat )
+    append printFormat to qh.PRINTout unless already defined
+*/
+void qh_appendprint (qh_PRINT format) {
+  int i;
+
+  for (i=0; i < qh_PRINTEND; i++) {
+    if (qh PRINTout[i] == format && format != qh_PRINTqhull)
+      break;
+    if (!qh PRINTout[i]) {
+      qh PRINTout[i]= format;
+      break;
+    }
+  }
+} /* appendprint */
+     
+/*---------------------------------
+  
+  qh_checkflags( commandStr, hiddenFlags )
+    errors if commandStr contains hiddenFlags
+    hiddenFlags starts and ends with a space and is space deliminated (checked)
+
+  notes:
+    ignores first word (e.g., "qconvex i")
+    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
+  
+  see:
+    qh_initflags() initializes Qhull according to commandStr
+*/
+void qh_checkflags(char *command, char *hiddenflags) {
+  char *s= command, *t, *chkerr, key, opt, prevopt;
+  char chkkey[]= "   ";
+  char chkopt[]=  "    ";
+  char chkopt2[]= "     ";
+
+  if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
+    fprintf(qh ferr, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (strpbrk(hiddenflags, ",\n\r\t")) { 
+    fprintf(qh ferr, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  while (*s && !isspace(*s))  /* skip program name */
+    s++;
+  while (*s) {
+    while (*s && isspace(*s))
+      s++;
+    if (*s == '-')
+      s++;
+    if (!*s)
+      break;
+    key = *s++;
+    chkerr = NULL;
+    if (key == '\'') {         /* TO 'file name' */
+      t= strchr(s, '\'');
+      if (!t) {
+	fprintf(qh ferr, "qhull error (qh_checkflags): missing the 2nd single-quote for:\n%s\n", s-1);
+	qh_errexit(qh_ERRinput, NULL, NULL);
+      }
+      s= t+1;
+      continue;
+    }
+    chkkey[1]= key;
+    if (strstr(hiddenflags, chkkey)) {
+      chkerr= chkkey;
+    }else if (isupper(key)) {
+      opt= ' ';
+      prevopt= ' ';
+      chkopt[1]= key;
+      chkopt2[1]= key;
+      while (!chkerr && *s && !isspace(*s)) {
+	opt= *s++;
+	if (isalpha(opt)) {
+	  chkopt[2]= opt;
+	  if (strstr(hiddenflags, chkopt))
+	    chkerr= chkopt;
+	  if (prevopt != ' ') {
+ 	    chkopt2[2]= prevopt;
+ 	    chkopt2[3]= opt;
+	    if (strstr(hiddenflags, chkopt2))
+	      chkerr= chkopt2;
+	  }
+	}else if (key == 'Q' && isdigit(opt) && prevopt != 'b' 
+	      && (prevopt == ' ' || islower(prevopt))) {
+  	    chkopt[2]= opt;
+	    if (strstr(hiddenflags, chkopt))
+	      chkerr= chkopt;
+	}else {
+	  qh_strtod (s-1, &t);
+	  if (s < t)
+	    s= t;
+	}
+        prevopt= opt;
+      }
+    }
+    if (chkerr) {
+      *chkerr= '\'';
+      chkerr[strlen(chkerr)-1]=  '\'';
+      fprintf(qh ferr, "qhull error: option %s is not used with this program.\n             It may be used with qhull.\n", chkerr);
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+  }
+} /* checkflags */
+    
+/*---------------------------------
+  
+  qh_clock()
+    return user CPU time in 100ths (qh_SECtick)
+    only defined for qh_CLOCKtype == 2
+
+  notes:
+    use first value to determine time 0
+    from Stevens '92 8.15
+*/
+unsigned long qh_clock (void) {
+
+#if (qh_CLOCKtype == 2)
+  struct tms time;
+  static long clktck;  /* initialized first call */
+  double ratio, cpu;
+  unsigned long ticks;
+
+  if (!clktck) {
+    if ((clktck= sysconf (_SC_CLK_TCK)) < 0) {
+      fprintf (qh ferr, "qhull internal error (qh_clock): sysconf() failed.  Use qh_CLOCKtype 1 in user.h\n");
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }
+  }
+  if (times (&time) == -1) {
+    fprintf (qh ferr, "qhull internal error (qh_clock): times() failed.  Use qh_CLOCKtype 1 in user.h\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  ratio= qh_SECticks / (double)clktck;
+  ticks= time.tms_utime * ratio;
+  return ticks;
+#else
+  fprintf (qh ferr, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n");
+  qh_errexit (qh_ERRqhull, NULL, NULL); /* never returns */
+  return 0;
+#endif
+} /* clock */
+
+/*---------------------------------
+
+  qh_freebuffers()
+    free up global memory buffers
+
+  notes:
+    must match qh_initbuffers()
+*/
+void qh_freebuffers (void) {
+
+  trace5((qh ferr, "qh_freebuffers: freeing up global memory buffers\n"));
+  /* allocated by qh_initqhull_buffers */
+  qh_memfree (qh NEARzero, qh hull_dim * sizeof(realT));
+  qh_memfree (qh lower_threshold, (qh input_dim+1) * sizeof(realT));
+  qh_memfree (qh upper_threshold, (qh input_dim+1) * sizeof(realT));
+  qh_memfree (qh lower_bound, (qh input_dim+1) * sizeof(realT));
+  qh_memfree (qh upper_bound, (qh input_dim+1) * sizeof(realT));
+  qh_memfree (qh gm_matrix, (qh hull_dim+1) * qh hull_dim * sizeof(coordT));
+  qh_memfree (qh gm_row, (qh hull_dim+1) * sizeof(coordT *));
+  qh NEARzero= qh lower_threshold= qh upper_threshold= NULL;
+  qh lower_bound= qh upper_bound= NULL;
+  qh gm_matrix= NULL;
+  qh gm_row= NULL;
+  qh_setfree (&qh other_points);
+  qh_setfree (&qh del_vertices);
+  qh_setfree (&qh coplanarset);
+  if (qh line)                /* allocated by qh_readinput, freed if no error */
+    free (qh line);
+  if (qh half_space)
+    free (qh half_space);
+  if (qh temp_malloc)
+    free (qh temp_malloc);
+  if (qh feasible_point)      /* allocated by qh_readfeasible */
+    free (qh feasible_point);
+  if (qh feasible_string)     /* allocated by qh_initflags */
+    free (qh feasible_string);
+  qh line= qh feasible_string= NULL;
+  qh half_space= qh feasible_point= qh temp_malloc= NULL;
+  /* usually allocated by qh_readinput */
+  if (qh first_point && qh POINTSmalloc) {
+    free(qh first_point);
+    qh first_point= NULL;
+  }
+  if (qh input_points && qh input_malloc) { /* set by qh_joggleinput */
+    free (qh input_points);
+    qh input_points= NULL;
+  }
+  trace5((qh ferr, "qh_freebuffers: finished\n"));
+} /* freebuffers */
+
+
+/*---------------------------------
+
+  qh_freebuild( allmem )
+    free global memory used by qh_initbuild and qh_buildhull
+    if !allmem,
+      does not free short memory (freed by qh_memfreeshort)
+
+  design:
+    free centrums
+    free each vertex
+    mark unattached ridges
+    for each facet
+      free ridges
+      free outside set, coplanar set, neighbor set, ridge set, vertex set
+      free facet
+    free hash table
+    free interior point
+    free merge set
+    free temporary sets
+*/
+void qh_freebuild (boolT allmem) {
+  facetT *facet;
+  vertexT *vertex;
+  ridgeT *ridge, **ridgep;
+  mergeT *merge, **mergep;
+
+  trace1((qh ferr, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
+  if (qh del_vertices)
+    qh_settruncate (qh del_vertices, 0);
+  if (allmem) {
+    qh_clearcenters (qh_ASnone);
+    while ((vertex= qh vertex_list)) {
+      if (vertex->next)
+        qh_delvertex (vertex);
+      else {
+        qh_memfree (vertex, sizeof(vertexT));
+        qh newvertex_list= qh vertex_list= NULL;
+      }
+    }
+  }else if (qh VERTEXneighbors) {
+    FORALLvertices
+      qh_setfreelong (&(vertex->neighbors));
+  }
+  qh VERTEXneighbors= False;
+  qh GOODclosest= NULL;
+  if (allmem) {
+    FORALLfacets {
+      FOREACHridge_(facet->ridges)
+        ridge->seen= False;
+    }
+    FORALLfacets {
+      if (facet->visible) {
+	FOREACHridge_(facet->ridges) {
+	  if (!otherfacet_(ridge, facet)->visible)
+	    ridge->seen= True;  /* an unattached ridge */
+	}
+      }
+    }
+    while ((facet= qh facet_list)) {
+      FOREACHridge_(facet->ridges) {
+        if (ridge->seen) {
+          qh_setfree(&(ridge->vertices));
+          qh_memfree(ridge, sizeof(ridgeT));
+        }else
+          ridge->seen= True;
+      }
+      qh_setfree (&(facet->outsideset));
+      qh_setfree (&(facet->coplanarset));
+      qh_setfree (&(facet->neighbors));
+      qh_setfree (&(facet->ridges));
+      qh_setfree (&(facet->vertices));
+      if (facet->next)
+        qh_delfacet (facet);
+      else {
+        qh_memfree (facet, sizeof(facetT));
+        qh visible_list= qh newfacet_list= qh facet_list= NULL;
+      }
+    }
+  }else {
+    FORALLfacets {
+      qh_setfreelong (&(facet->outsideset));
+      qh_setfreelong (&(facet->coplanarset));
+      if (!facet->simplicial) {
+        qh_setfreelong (&(facet->neighbors));
+        qh_setfreelong (&(facet->ridges));
+        qh_setfreelong (&(facet->vertices));
+      }
+    }
+  }
+  qh_setfree (&(qh hash_table));
+  qh_memfree (qh interior_point, qh normal_size);
+  qh interior_point= NULL;
+  FOREACHmerge_(qh facet_mergeset)  /* usually empty */
+    qh_memfree (merge, sizeof(mergeT));
+  qh facet_mergeset= NULL;  /* temp set */
+  qh degen_mergeset= NULL;  /* temp set */
+  qh_settempfree_all();
+} /* freebuild */
+
+/*---------------------------------
+
+  qh_freeqhull( allmem )
+    free global memory
+    if !allmem,
+      does not free short memory (freed by qh_memfreeshort)
+
+  notes:
+    sets qh.NOerrexit in case caller forgets to
+
+  design:
+    free global and temporary memory from qh_initbuild and qh_buildhull
+    free buffers
+    free statistics
+*/
+void qh_freeqhull (boolT allmem) {
+
+  trace1((qh ferr, "qh_freeqhull: free global memory\n"));
+  qh NOerrexit= True;  /* no more setjmp since called at exit */
+  qh_freebuild (allmem);
+  qh_freebuffers();
+  qh_freestatistics();
+#if qh_QHpointer
+  free (qh_qh);
+  qh_qh= NULL;
+#else
+  memset((char *)&qh_qh, 0, sizeof(qhT));
+  qh NOerrexit= True;
+#endif
+} /* freeqhull */
+
+/*---------------------------------
+
+  qh_init_A( infile, outfile, errfile, argc, argv )
+    initialize memory and stdio files
+    convert input options to option string (qh.qhull_command)
+
+  notes:
+    infile may be NULL if qh_readpoints() is not called
+
+    errfile should always be defined.  It is used for reporting
+    errors.  outfile is used for output and format options.
+
+    argc/argv may be 0/NULL
+
+    called before error handling initialized
+    qh_errexit() may not be used
+*/
+void qh_init_A (FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {
+  qh_meminit (errfile);
+  qh_initqhull_start (infile, outfile, errfile);
+  qh_init_qhull_command (argc, argv);
+} /* init_A */
+
+/*---------------------------------
+
+  qh_init_B( points, numpoints, dim, ismalloc )
+    initialize globals for points array
+
+    points has numpoints dim-dimensional points
+      points[0] is the first coordinate of the first point
+      points[1] is the second coordinate of the first point
+      points[dim] is the first coordinate of the second point
+
+    ismalloc=True
+      Qhull will call free(points) on exit or input transformation
+    ismalloc=False
+      Qhull will allocate a new point array if needed for input transformation
+
+    qh.qhull_command
+      is the option string.
+      It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags
+
+  returns:
+    if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay)
+      projects the input to a new point array
+
+        if qh.DELAUNAY,
+          qh.hull_dim is increased by one
+        if qh.ATinfinity,
+          qh_projectinput adds point-at-infinity for Delaunay tri.
+
+    if qh.SCALEinput
+      changes the upper and lower bounds of the input, see qh_scaleinput()
+
+    if qh.ROTATEinput
+      rotates the input by a random rotation, see qh_rotateinput()
+      if qh.DELAUNAY
+        rotates about the last coordinate
+
+  notes:
+    called after points are defined
+    qh_errexit() may be used
+*/
+void qh_init_B (coordT *points, int numpoints, int dim, boolT ismalloc) {
+  qh_initqhull_globals (points, numpoints, dim, ismalloc);
+  if (qhmem.LASTsize == 0)
+    qh_initqhull_mem();
+  /* mem.c and qset.c are initialized */
+  qh_initqhull_buffers();
+  qh_initthresholds (qh qhull_command);
+  if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay))
+    qh_projectinput();
+  if (qh SCALEinput)
+    qh_scaleinput();
+  if (qh ROTATErandom >= 0) {
+    qh_randommatrix (qh gm_matrix, qh hull_dim, qh gm_row);
+    if (qh DELAUNAY) {
+      int k, lastk= qh hull_dim-1;
+      for (k= 0; k < lastk; k++) {
+        qh gm_row[k][lastk]= 0.0;
+        qh gm_row[lastk][k]= 0.0;
+      }
+      qh gm_row[lastk][lastk]= 1.0;
+    }
+    qh_gram_schmidt (qh hull_dim, qh gm_row);
+    qh_rotateinput (qh gm_row);
+  }
+} /* init_B */
+
+/*---------------------------------
+
+  qh_init_qhull_command( argc, argv )
+    build qh.qhull_command from argc/argv
+
+  returns:
+    a space-deliminated string of options (just as typed)
+
+  notes:
+    makes option string easy to input and output
+
+    argc/argv may be 0/NULL
+*/
+void qh_init_qhull_command(int argc, char *argv[]) {
+  int i;
+  char *s;
+
+  if (argc) {
+    if ((s= strrchr( argv[0], '\\'))) /* Borland gives full path */
+      strcpy (qh qhull_command, s+1);
+    else
+      strcpy (qh qhull_command, argv[0]);
+    if ((s= strstr (qh qhull_command, ".EXE"))
+    ||  (s= strstr (qh qhull_command, ".exe")))
+      *s= '\0';
+  }
+  for (i=1; i < argc; i++) {
+    if (strlen (qh qhull_command) + strlen(argv[i]) + 1 < sizeof(qh qhull_command)) {
+      strcat (qh qhull_command, " ");
+      strcat (qh qhull_command, argv[i]);
+    }else {
+      fprintf (qh ferr, "qhull input error: more than %d characters in command line\n",
+        (int)sizeof(qh qhull_command));
+      exit (1);  /* can not use qh_errexit */
+    }
+  }
+} /* init_qhull_command */
+
+/*---------------------------------
+
+  qh_initflags( commandStr )
+    set flags and initialized constants from commandStr
+
+  returns:
+    sets qh.qhull_command to command if needed
+
+  notes:
+    ignores first word (e.g., "qhull d")
+    use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
+
+  see:
+    qh_initthresholds() continues processing of 'Pdn' and 'PDn'
+    'prompt' in unix.c for documentation
+
+  design:
+    for each space-deliminated option group
+      if top-level option
+        check syntax
+        append approriate option to option string
+        set appropriate global variable or append printFormat to print options
+      else
+        for each sub-option
+          check syntax
+          append approriate option to option string
+          set appropriate global variable or append printFormat to print options
+
+
+*/
+void qh_initflags(char *command) {
+  int k, i, lastproject;
+  char *s= command, *t, *prev_s, *start, key;
+  boolT isgeom= False, wasproject;
+  realT r;
+
+  if (command != &qh qhull_command[0]) {
+    *qh qhull_command= '\0';
+    strncat( qh qhull_command, command, sizeof( qh qhull_command));
+  }
+  while (*s && !isspace(*s))  /* skip program name */
+    s++;
+  while (*s) {
+    while (*s && isspace(*s))
+      s++;
+    if (*s == '-')
+      s++;
+    if (!*s)
+      break;
+    prev_s= s;
+    switch (*s++) {
+    case 'd':
+      qh_option ("delaunay", NULL, NULL);
+      qh DELAUNAY= True;
+      break;
+    case 'f':
+      qh_option ("facets", NULL, NULL);
+      qh_appendprint (qh_PRINTfacets);
+      break;
+    case 'i':
+      qh_option ("incidence", NULL, NULL);
+      qh_appendprint (qh_PRINTincidences);
+      break;
+    case 'm':
+      qh_option ("mathematica", NULL, NULL);
+      qh_appendprint (qh_PRINTmathematica);
+      break;
+    case 'n':
+      qh_option ("normals", NULL, NULL);
+      qh_appendprint (qh_PRINTnormals);
+      break;
+    case 'o':
+      qh_option ("offFile", NULL, NULL);
+      qh_appendprint (qh_PRINToff);
+      break;
+    case 'p':
+      qh_option ("points", NULL, NULL);
+      qh_appendprint (qh_PRINTpoints);
+      break;
+    case 's':
+      qh_option ("summary", NULL, NULL);
+      qh PRINTsummary= True;
+      break;
+    case 'v':
+      qh_option ("voronoi", NULL, NULL);
+      qh VORONOI= True;
+      qh DELAUNAY= True;
+      break;
+    case 'A':
+      if (!isdigit(*s) && *s != '.' && *s != '-')
+	fprintf(qh ferr, "qhull warning: no maximum cosine angle given for option 'An'.  Ignored.\n");
+      else {
+	if (*s == '-') {
+	  qh premerge_cos= -qh_strtod (s, &s);
+          qh_option ("Angle-premerge-", NULL, &qh premerge_cos);
+	  qh PREmerge= True;
+	}else {
+	  qh postmerge_cos= qh_strtod (s, &s);
+          qh_option ("Angle-postmerge", NULL, &qh postmerge_cos);
+	  qh POSTmerge= True;
+	}
+	qh MERGING= True;
+      }
+      break;
+    case 'C':
+      if (!isdigit(*s) && *s != '.' && *s != '-')
+	fprintf(qh ferr, "qhull warning: no centrum radius given for option 'Cn'.  Ignored.\n");
+      else {
+	if (*s == '-') {
+	  qh premerge_centrum= -qh_strtod (s, &s);
+          qh_option ("Centrum-premerge-", NULL, &qh premerge_centrum);
+	  qh PREmerge= True;
+	}else {
+	  qh postmerge_centrum= qh_strtod (s, &s);
+          qh_option ("Centrum-postmerge", NULL, &qh postmerge_centrum);
+	  qh POSTmerge= True;
+	}
+	qh MERGING= True;
+      }
+      break;
+    case 'E':
+      if (*s == '-')
+	fprintf(qh ferr, "qhull warning: negative maximum roundoff given for option 'An'.  Ignored.\n");
+      else if (!isdigit(*s))
+	fprintf(qh ferr, "qhull warning: no maximum roundoff given for option 'En'.  Ignored.\n");
+      else {
+	qh DISTround= qh_strtod (s, &s);
+        qh_option ("Distance-roundoff", NULL, &qh DISTround);
+	qh SETroundoff= True;
+      }
+      break;
+    case 'H':
+      start= s;
+      qh HALFspace= True;
+      qh_strtod (s, &t);
+      while (t > s)  {
+        if (*t && !isspace (*t)) {
+	  if (*t == ',')
+	    t++;
+	  else
+	    fprintf (qh ferr, "qhull warning: origin for Halfspace intersection should be 'Hn,n,n,...'\n");
+	}
+        s= t;
+	qh_strtod (s, &t);
+      }
+      if (start < t) {
+        if (!(qh feasible_string= (char*)calloc (t-start+1, 1))) {
+          fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
+          qh_errexit(qh_ERRmem, NULL, NULL);
+        }
+        strncpy (qh feasible_string, start, t-start);
+        qh_option ("Halfspace-about", NULL, NULL);
+        qh_option (qh feasible_string, NULL, NULL);
+      }else
+        qh_option ("Halfspace", NULL, NULL);
+      break;
+    case 'R':
+      if (!isdigit(*s))
+	fprintf(qh ferr, "qhull warning: missing random perturbation for option 'Rn'.  Ignored\n");
+      else {
+	qh RANDOMfactor= qh_strtod (s, &s);
+        qh_option ("Random_perturb", NULL, &qh RANDOMfactor);
+        qh RANDOMdist= True;
+      }
+      break;
+    case 'V':
+      if (!isdigit(*s) && *s != '-')
+	fprintf(qh ferr, "qhull warning: missing visible distance for option 'Vn'.  Ignored\n");
+      else {
+	qh MINvisible= qh_strtod (s, &s);
+        qh_option ("Visible", NULL, &qh MINvisible);
+      }
+      break;
+    case 'U':
+      if (!isdigit(*s) && *s != '-')
+	fprintf(qh ferr, "qhull warning: missing coplanar distance for option 'Un'.  Ignored\n");
+      else {
+	qh MAXcoplanar= qh_strtod (s, &s);
+        qh_option ("U-coplanar", NULL, &qh MAXcoplanar);
+      }
+      break;
+    case 'W':
+      if (*s == '-')
+	fprintf(qh ferr, "qhull warning: negative outside width for option 'Wn'.  Ignored.\n");
+      else if (!isdigit(*s))
+	fprintf(qh ferr, "qhull warning: missing outside width for option 'Wn'.  Ignored\n");
+      else {
+	qh MINoutside= qh_strtod (s, &s);
+        qh_option ("W-outside", NULL, &qh MINoutside);
+        qh APPROXhull= True;
+      }
+      break;
+    /************  sub menus ***************/
+    case 'F':
+      while (*s && !isspace(*s)) {
+	switch(*s++) {
+	case 'a':
+	  qh_option ("Farea", NULL, NULL);
+	  qh_appendprint (qh_PRINTarea);
+	  qh GETarea= True;
+	  break;
+	case 'A':
+	  qh_option ("FArea-total", NULL, NULL);
+	  qh GETarea= True;
+	  break;
+        case 'c':
+          qh_option ("Fcoplanars", NULL, NULL);
+          qh_appendprint (qh_PRINTcoplanars);
+          break;
+        case 'C':
+          qh_option ("FCentrums", NULL, NULL);
+          qh_appendprint (qh_PRINTcentrums);
+          break;
+	case 'd':
+          qh_option ("Fd-cdd-in", NULL, NULL);
+	  qh CDDinput= True;
+	  break;
+	case 'D':
+          qh_option ("FD-cdd-out", NULL, NULL);
+	  qh CDDoutput= True;
+	  break;
+	case 'F':
+	  qh_option ("FFacets-xridge", NULL, NULL);
+          qh_appendprint (qh_PRINTfacets_xridge);
+	  break;
+        case 'i':
+          qh_option ("Finner", NULL, NULL);
+          qh_appendprint (qh_PRINTinner);
+          break;
+        case 'I':
+          qh_option ("FIDs", NULL, NULL);
+          qh_appendprint (qh_PRINTids);
+          break;
+        case 'm':
+          qh_option ("Fmerges", NULL, NULL);
+          qh_appendprint (qh_PRINTmerges);
+          break;
+        case 'n':
+          qh_option ("Fneighbors", NULL, NULL);
+          qh_appendprint (qh_PRINTneighbors);
+          break;
+        case 'N':
+          qh_option ("FNeighbors-vertex", NULL, NULL);
+          qh_appendprint (qh_PRINTvneighbors);
+          break;
+        case 'o':
+          qh_option ("Fouter", NULL, NULL);
+          qh_appendprint (qh_PRINTouter);
+          break;
+	case 'O':
+	  if (qh PRINToptions1st) {
+	    qh_option ("FOptions", NULL, NULL);
+	    qh_appendprint (qh_PRINToptions);
+	  }else
+	    qh PRINToptions1st= True;
+	  break;
+	case 'p':
+	  qh_option ("Fpoint-intersect", NULL, NULL);
+	  qh_appendprint (qh_PRINTpointintersect);
+	  break;
+	case 'P':
+	  qh_option ("FPoint-nearest", NULL, NULL);
+	  qh_appendprint (qh_PRINTpointnearest);
+	  break;
+	case 'Q':
+	  qh_option ("FQhull", NULL, NULL);
+	  qh_appendprint (qh_PRINTqhull);
+	  break;
+        case 's':
+          qh_option ("Fsummary", NULL, NULL);
+          qh_appendprint (qh_PRINTsummary);
+          break;
+        case 'S':
+          qh_option ("FSize", NULL, NULL);
+          qh_appendprint (qh_PRINTsize);
+          qh GETarea= True;
+          break;
+        case 't':
+          qh_option ("Ftriangles", NULL, NULL);
+          qh_appendprint (qh_PRINTtriangles);
+          break;
+        case 'v':
+          /* option set in qh_initqhull_globals */
+          qh_appendprint (qh_PRINTvertices);
+          break;
+        case 'V':
+          qh_option ("FVertex-average", NULL, NULL);
+          qh_appendprint (qh_PRINTaverage);
+          break;
+	case 'x':
+	  qh_option ("Fxtremes", NULL, NULL);
+	  qh_appendprint (qh_PRINTextremes);
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'F' output option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    case 'G':
+      isgeom= True;
+      qh_appendprint (qh_PRINTgeom);
+      while (*s && !isspace(*s)) {
+	switch(*s++) {
+        case 'a':
+          qh_option ("Gall-points", NULL, NULL);
+          qh PRINTdots= True;
+          break;
+        case 'c':
+          qh_option ("Gcentrums", NULL, NULL);
+          qh PRINTcentrums= True;
+          break;
+	case 'h':
+          qh_option ("Gintersections", NULL, NULL);
+	  qh DOintersections= True;
+	  break;
+	case 'i':
+          qh_option ("Ginner", NULL, NULL);
+	  qh PRINTinner= True;
+	  break;
+	case 'n':
+          qh_option ("Gno-planes", NULL, NULL);
+	  qh PRINTnoplanes= True;
+	  break;
+	case 'o':
+          qh_option ("Gouter", NULL, NULL);
+	  qh PRINTouter= True;
+	  break;
+	case 'p':
+          qh_option ("Gpoints", NULL, NULL);
+	  qh PRINTcoplanar= True;
+	  break;
+	case 'r':
+          qh_option ("Gridges", NULL, NULL);
+	  qh PRINTridges= True;
+	  break;
+	case 't':
+          qh_option ("Gtransparent", NULL, NULL);
+	  qh PRINTtransparent= True;
+	  break;
+	case 'v':
+          qh_option ("Gvertices", NULL, NULL);
+	  qh PRINTspheres= True;
+	  break;
+	case 'D':
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing dimension for option 'GDn'\n");
+	  else {
+	    if (qh DROPdim >= 0)
+	      fprintf (qh ferr, "qhull warning: can only drop one dimension.  Previous 'GD%d' ignored\n",
+	           qh DROPdim);
+  	    qh DROPdim= qh_strtol (s, &s);
+            qh_option ("GDrop-dim", &qh DROPdim, NULL);
+          }
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'G' print option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    case 'P':
+      while (*s && !isspace(*s)) {
+	switch(*s++) {
+	case 'd': case 'D':  /* see qh_initthresholds() */
+	  key= s[-1];
+	  i= qh_strtol (s, &s);
+	  r= 0;
+	  if (*s == ':') {
+	    s++;
+	    r= qh_strtod (s, &s);
+	  }
+	  if (key == 'd')
+  	    qh_option ("Pdrop-facets-dim-less", &i, &r);
+  	  else
+  	    qh_option ("PDrop-facets-dim-more", &i, &r);
+	  break;
+        case 'g':
+          qh_option ("Pgood-facets", NULL, NULL);
+          qh PRINTgood= True;
+          break;
+        case 'G':
+          qh_option ("PGood-facet-neighbors", NULL, NULL);
+          qh PRINTneighbors= True;
+          break;
+        case 'o':
+          qh_option ("Poutput-forced", NULL, NULL);
+          qh FORCEoutput= True;
+          break;
+        case 'p':
+          qh_option ("Pprecision-ignore", NULL, NULL);
+          qh PRINTprecision= False;
+          break;
+	case 'A':
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing facet count for keep area option 'PAn'\n");
+	  else {
+  	    qh KEEParea= qh_strtol (s, &s);
+            qh_option ("PArea-keep", &qh KEEParea, NULL);
+            qh GETarea= True;
+          }
+	  break;
+	case 'F':
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing facet area for option 'PFn'\n");
+	  else {
+  	    qh KEEPminArea= qh_strtod (s, &s);
+            qh_option ("PFacet-area-keep", NULL, &qh KEEPminArea);
+            qh GETarea= True;
+          }
+	  break;
+	case 'M':
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing merge count for option 'PMn'\n");
+	  else {
+  	    qh KEEPmerge= qh_strtol (s, &s);
+            qh_option ("PMerge-keep", &qh KEEPmerge, NULL);
+          }
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'P' print option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    case 'Q':
+      lastproject= -1;
+      while (*s && !isspace(*s)) {
+	switch(*s++) {
+	case 'b': case 'B':  /* handled by qh_initthresholds */
+	  key= s[-1];
+	  if (key == 'b' && *s == 'B') {
+	    s++;
+	    r= qh_DEFAULTbox;
+	    qh SCALEinput= True;
+	    qh_option ("QbBound-unit-box", NULL, &r);
+	    break;
+	  }
+	  if (key == 'b' && *s == 'b') {
+	    s++;
+	    qh SCALElast= True;
+	    qh_option ("Qbbound-last", NULL, NULL);
+	    break;
+	  }
+	  k= qh_strtol (s, &s);
+	  r= 0.0;
+	  wasproject= False;
+	  if (*s == ':') {
+	    s++;
+	    if ((r= qh_strtod(s, &s)) == 0.0) {
+ 	      t= s;            /* need true dimension for memory allocation */
+	      while (*t && !isspace(*t)) {
+	        if (toupper(*t++) == 'B'
+	         && k == qh_strtol (t, &t)
+	         && *t++ == ':'
+	         && qh_strtod(t, &t) == 0.0) {
+	          qh PROJECTinput++;
+	          trace2((qh ferr, "qh_initflags: project dimension %d\n", k));
+	          qh_option ("Qb-project-dim", &k, NULL);
+		  wasproject= True;
+	          lastproject= k;
+	          break;
+		}
+	      }
+	    }
+  	  }
+	  if (!wasproject) {
+	    if (lastproject == k && r == 0.0)
+	      lastproject= -1;  /* doesn't catch all possible sequences */
+	    else if (key == 'b') {
+	      qh SCALEinput= True;
+	      if (r == 0.0)
+		r= -qh_DEFAULTbox;
+	      qh_option ("Qbound-dim-low", &k, &r);
+	    }else {
+	      qh SCALEinput= True;
+	      if (r == 0.0)
+		r= qh_DEFAULTbox;
+	      qh_option ("QBound-dim-high", &k, &r);
+	    }
+	  }
+	  break;
+	case 'c':
+	  qh_option ("Qcoplanar-keep", NULL, NULL);
+	  qh KEEPcoplanar= True;
+	  break;
+	case 'f':
+	  qh_option ("Qfurthest-outside", NULL, NULL);
+	  qh BESToutside= True;
+	  break;
+	case 'g':
+	  qh_option ("Qgood-facets-only", NULL, NULL);
+	  qh ONLYgood= True;
+	  break;
+	case 'i':
+	  qh_option ("Qinterior-keep", NULL, NULL);
+	  qh KEEPinside= True;
+	  break;
+	case 'm':
+	  qh_option ("Qmax-outside-only", NULL, NULL);
+	  qh ONLYmax= True;
+	  break;
+	case 'r':
+	  qh_option ("Qrandom-outside", NULL, NULL);
+	  qh RANDOMoutside= True;
+	  break;
+	case 's':
+	  qh_option ("Qsearch-initial-simplex", NULL, NULL);
+	  qh ALLpoints= True;
+	  break;
+	case 't':
+	  qh_option ("Qtriangulate", NULL, NULL);
+	  qh TRIangulate= True;
+	  break;
+	case 'T':
+	  qh_option ("QTestPoints", NULL, NULL);
+	  if (!isdigit (*s))
+	    fprintf (qh ferr, "qhull input error: missing number of test points for option 'QTn'\n");
+	  else {
+  	    qh TESTpoints= qh_strtol (s, &s);
+            qh_option ("QTestPoints", &qh TESTpoints, NULL);
+          }
+	  break;
+	case 'u':
+	  qh_option ("QupperDelaunay", NULL, NULL);
+	  qh UPPERdelaunay= True;
+	  break;
+	case 'v':
+	  qh_option ("Qvertex-neighbors-convex", NULL, NULL);
+	  qh TESTvneighbors= True;
+	  break;
+	case 'x':
+	  qh_option ("Qxact-merge", NULL, NULL);
+	  qh MERGEexact= True;
+	  break;
+	case 'z':
+	  qh_option ("Qz-infinity-point", NULL, NULL);
+	  qh ATinfinity= True;
+	  break;
+	case '0':
+	  qh_option ("Q0-no-premerge", NULL, NULL);
+	  qh NOpremerge= True;
+	  break;
+	case '1':
+	  if (!isdigit(*s)) {
+	    qh_option ("Q1-no-angle-sort", NULL, NULL);
+	    qh ANGLEmerge= False;
+	    break; 
+	  }
+	  switch(*s++) {
+  	  case '0':
+	    qh_option ("Q10-no-narrow", NULL, NULL);
+	    qh NOnarrow= True;
+	    break; 
+  	  case '1':
+	    qh_option ("Q11-trinormals Qtriangulate", NULL, NULL);
+	    qh TRInormals= True;
+	    qh TRIangulate= True;
+	    break; 
+	  default:
+	    s--;
+	    fprintf (qh ferr, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]);
+	    while (*++s && !isspace(*s));
+	    break;
+	  }
+	  break;
+	case '2':
+	  qh_option ("Q2-no-merge-independent", NULL, NULL);
+	  qh MERGEindependent= False;
+	  goto LABELcheckdigit;
+	  break; /* no warnings */
+	case '3':
+	  qh_option ("Q3-no-merge-vertices", NULL, NULL);
+	  qh MERGEvertices= False;
+	LABELcheckdigit:
+	  if (isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: can not follow '1', '2', or '3' with a digit.  '%c' skipped.\n",
+	             *s++);
+	  break;
+	case '4':
+	  qh_option ("Q4-avoid-old-into-new", NULL, NULL);
+	  qh AVOIDold= True;
+	  break;
+	case '5':
+	  qh_option ("Q5-no-check-outer", NULL, NULL);
+	  qh SKIPcheckmax= True;
+	  break;
+	case '6':
+	  qh_option ("Q6-no-concave-merge", NULL, NULL);
+	  qh SKIPconvex= True;
+	  break;
+	case '7':
+	  qh_option ("Q7-no-breadth-first", NULL, NULL);
+	  qh VIRTUALmemory= True;
+	  break;
+	case '8':
+	  qh_option ("Q8-no-near-inside", NULL, NULL);
+	  qh NOnearinside= True;
+	  break;
+	case '9':
+	  qh_option ("Q9-pick-furthest", NULL, NULL);
+	  qh PICKfurthest= True;
+	  break;
+	case 'G':
+	  i= qh_strtol (s, &t);
+	  if (qh GOODpoint)
+	    fprintf (qh ferr, "qhull warning: good point already defined for option 'QGn'.  Ignored\n");
+          else if (s == t)
+	    fprintf (qh ferr, "qhull warning: missing good point id for option 'QGn'.  Ignored\n");
+	  else if (i < 0 || *s == '-') {
+ 	    qh GOODpoint= i-1;
+  	    qh_option ("QGood-if-dont-see-point", &i, NULL);
+	  }else {
+ 	    qh GOODpoint= i+1;
+  	    qh_option ("QGood-if-see-point", &i, NULL);
+  	  }
+ 	  s= t;
+	  break;
+	case 'J':
+          if (!isdigit(*s) && *s != '-')
+   	    qh JOGGLEmax= 0.0;
+	  else {
+ 	    qh JOGGLEmax= (realT) qh_strtod (s, &s);
+            qh_option ("QJoggle", NULL, &qh JOGGLEmax);
+	  }
+	  break;
+	case 'R':
+          if (!isdigit(*s) && *s != '-')
+	    fprintf (qh ferr, "qhull warning: missing random seed for option 'QRn'.  Ignored\n");
+	  else {
+ 	    qh ROTATErandom= i= qh_strtol(s, &s);
+   	    if (i > 0)
+   	      qh_option ("QRotate-id", &i, NULL );
+	    else if (i < -1)
+   	      qh_option ("QRandom-seed", &i, NULL );
+          }
+	  break;
+	case 'V':
+	  i= qh_strtol (s, &t);
+	  if (qh GOODvertex)
+	    fprintf (qh ferr, "qhull warning: good vertex already defined for option 'QVn'.  Ignored\n");
+          else if (s == t)
+	    fprintf (qh ferr, "qhull warning: no good point id given for option 'QVn'.  Ignored\n");
+	  else if (i < 0) {
+ 	    qh GOODvertex= i - 1;
+ 	    qh_option ("QV-good-facets-not-point", &i, NULL);
+	  }else {
+  	    qh_option ("QV-good-facets-point", &i, NULL);
+	    qh GOODvertex= i + 1;
+          }
+ 	  s= t;
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'Q' qhull option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    case 'T':
+      while (*s && !isspace(*s)) {
+	if (isdigit(*s) || *s == '-')
+	  qh IStracing= qh_strtol(s, &s);
+	else switch(*s++) {
+	case 'c':
+          qh_option ("Tcheck-frequently", NULL, NULL);
+	  qh CHECKfrequently= True;
+	  break;
+	case 's':
+          qh_option ("Tstatistics", NULL, NULL);
+	  qh PRINTstatistics= True;
+	  break;
+	case 'v':
+          qh_option ("Tverify", NULL, NULL);
+	  qh VERIFYoutput= True;
+	  break;
+	case 'z':
+	  if (!qh fout)
+	    fprintf (qh ferr, "qhull warning: output file undefined (stdout).  Option 'Tz' ignored.\n");
+	  else {
+	    qh_option ("Tz-stdout", NULL, NULL);
+  	    qh ferr= qh fout;
+  	    qhmem.ferr= qh fout;
+	  }
+	  break;
+	case 'C':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing point id for cone for trace option 'TCn'.  Ignored\n");
+	  else {
+	    i= qh_strtol (s, &s);
+	    qh_option ("TCone-stop", &i, NULL);
+	    qh STOPcone= i + 1;
+          }
+	  break;
+	case 'F':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing frequency count for trace option 'TFn'.  Ignored\n");
+	  else {
+	    qh REPORTfreq= qh_strtol (s, &s);
+            qh_option ("TFacet-log", &qh REPORTfreq, NULL);
+	    qh REPORTfreq2= qh REPORTfreq/2;  /* for tracemerging() */
+	  }
+	  break;
+	case 'I':
+	  if (s[0] != ' ' || s[1] == '\"' || s[1] == '\'' ||isspace (s[1])) {
+	    s++;
+	    fprintf (qh ferr, "qhull warning: option 'TI' mistyped.\nUse 'TI', one space, file name, and space or end-of-line.\nDo not use quotes.  Option 'FI' ignored.\n");
+	  }else {  /* not a procedure because of qh_option (filename, NULL, NULL); */
+	    char filename[500], *t= filename;
+
+	    s++;
+	    while (*s) {
+	      if (t - filename >= sizeof (filename)-2) {
+		fprintf (qh ferr, "qhull error: filename for 'TI' too long.\n");
+		qh_errexit (qh_ERRinput, NULL, NULL);
+	      }
+	      if (isspace (*s))
+		break;
+	      *(t++)= *s++;
+	    }
+	    *t= '\0';
+	    if (!freopen (filename, "r", stdin)) {
+	      fprintf (qh ferr, "qhull error: could not open file \"%s\".", filename);
+	      qh_errexit (qh_ERRinput, NULL, NULL);
+	    }else {
+	      qh_option ("TInput-file", NULL, NULL);
+	      qh_option (filename, NULL, NULL);
+	    }
+	  }
+	  break;
+	case 'O':
+	  if (s[0] != ' ' || s[1] == '\"' || isspace (s[1])) {
+	    s++;
+	    fprintf (qh ferr, "qhull warning: option 'TO' mistyped.\nUse 'TO', one space, file name, and space or end-of-line.\nThe file name may be enclosed in single quotes.\nDo not use double quotes.  Option 'FO' ignored.\n");
+	  }else {  /* not a procedure because of qh_option (filename, NULL, NULL); */
+	    char filename[500], *t= filename;
+	    boolT isquote= False;
+
+	    s++;
+	    if (*s == '\'') {
+	      isquote= True;
+	      s++;
+	    }
+	    while (*s) {
+	      if (t - filename >= sizeof (filename)-2) {
+		fprintf (qh ferr, "qhull error: filename for 'TO' too long.\n");
+		qh_errexit (qh_ERRinput, NULL, NULL);
+	      }
+	      if (isquote) {
+		if (*s == '\'') {
+		  s++;
+		  isquote= False;
+		  break;
+		}
+	      }else if (isspace (*s))
+		break;
+	      *(t++)= *s++;
+	    }
+	    *t= '\0';
+	    if (isquote)
+	      fprintf (qh ferr, "qhull error: missing end quote for option 'TO'.  Rest of line ignored.\n");
+	    else if (!freopen (filename, "w", stdout)) {
+	      fprintf (qh ferr, "qhull error: could not open file \"%s\".", filename);
+	      qh_errexit (qh_ERRinput, NULL, NULL);
+	    }else {
+	      qh_option ("TOutput-file", NULL, NULL);
+	      qh_option (filename, NULL, NULL);
+	    }
+	  }
+	  break;
+	case 'P':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing point id for trace option 'TPn'.  Ignored\n");
+	  else {
+	    qh TRACEpoint= qh_strtol (s, &s);
+            qh_option ("Trace-point", &qh TRACEpoint, NULL);
+          }
+	  break;
+	case 'M':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing merge id for trace option 'TMn'.  Ignored\n");
+	  else {
+	    qh TRACEmerge= qh_strtol (s, &s);
+            qh_option ("Trace-merge", &qh TRACEmerge, NULL);
+          }
+	  break;
+	case 'R':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing rerun count for trace option 'TRn'.  Ignored\n");
+	  else {
+	    qh RERUN= qh_strtol (s, &s);
+            qh_option ("TRerun", &qh RERUN, NULL);
+          }
+	  break;
+	case 'V':
+	  i= qh_strtol (s, &t);
+	  if (s == t)
+	    fprintf (qh ferr, "qhull warning: missing furthest point id for trace option 'TVn'.  Ignored\n");
+	  else if (i < 0) {
+	    qh STOPpoint= i - 1;
+            qh_option ("TV-stop-before-point", &i, NULL);
+	  }else {
+	    qh STOPpoint= i + 1;
+            qh_option ("TV-stop-after-point", &i, NULL);
+          }
+          s= t;
+	  break;
+	case 'W':
+	  if (!isdigit(*s))
+	    fprintf (qh ferr, "qhull warning: missing max width for trace option 'TWn'.  Ignored\n");
+	  else {
+ 	    qh TRACEdist= (realT) qh_strtod (s, &s);
+            qh_option ("TWide-trace", NULL, &qh TRACEdist);
+          }
+	  break;
+	default:
+	  s--;
+	  fprintf (qh ferr, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]);
+	  while (*++s && !isspace(*s));
+	  break;
+	}
+      }
+      break;
+    default:
+      fprintf (qh ferr, "qhull warning: unknown flag %c (%x)\n", (int)s[-1],
+	       (int)s[-1]);
+      break;
+    }
+    if (s-1 == prev_s && *s && !isspace(*s)) {
+      fprintf (qh ferr, "qhull warning: missing space after flag %c (%x); reserved for menu. Skipped.\n",
+	       (int)*prev_s, (int)*prev_s);
+      while (*s && !isspace(*s))
+	s++;
+    }
+  }
+  if (isgeom && !qh FORCEoutput && qh PRINTout[1])
+    fprintf (qh ferr, "qhull warning: additional output formats are not compatible with Geomview\n");
+  /* set derived values in qh_initqhull_globals */
+} /* initflags */
+
+
+/*---------------------------------
+
+  qh_initqhull_buffers()
+    initialize global memory buffers
+
+  notes:
+    must match qh_freebuffers()
+*/
+void qh_initqhull_buffers (void) {
+  int k;
+
+  qh TEMPsize= (qhmem.LASTsize - sizeof (setT))/SETelemsize;
+  if (qh TEMPsize <= 0 || qh TEMPsize > qhmem.LASTsize)
+    qh TEMPsize= 8;  /* e.g., if qh_NOmem */
+  qh other_points= qh_setnew (qh TEMPsize);
+  qh del_vertices= qh_setnew (qh TEMPsize);
+  qh coplanarset= qh_setnew (qh TEMPsize);
+  qh NEARzero= (realT *)qh_memalloc(qh hull_dim * sizeof(realT));
+  qh lower_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
+  qh upper_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
+  qh lower_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
+  qh upper_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
+  for(k= qh input_dim+1; k--; ) {
+    qh lower_threshold[k]= -REALmax;
+    qh upper_threshold[k]= REALmax;
+    qh lower_bound[k]= -REALmax;
+    qh upper_bound[k]= REALmax;
+  }
+  qh gm_matrix= (coordT *)qh_memalloc((qh hull_dim+1) * qh hull_dim * sizeof(coordT));
+  qh gm_row= (coordT **)qh_memalloc((qh hull_dim+1) * sizeof(coordT *));
+} /* initqhull_buffers */
+
+/*---------------------------------
+
+  qh_initqhull_globals( points, numpoints, dim, ismalloc )
+    initialize globals
+    if ismalloc
+      points were malloc'd and qhull should free at end
+
+  returns:
+    sets qh.first_point, num_points, input_dim, hull_dim and others
+    seeds random number generator (seed=1 if tracing)
+    modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput)
+    adjust user flags as needed
+    also checks DIM3 dependencies and constants
+
+  notes:
+    do not use qh_point() since an input transformation may move them elsewhere
+
+  see:
+    qh_initqhull_start() sets default values for non-zero globals
+
+  design:
+    initialize points array from input arguments
+    test for qh.ZEROcentrum
+      (i.e., use opposite vertex instead of cetrum for convexity testing)
+    test for qh.PRINTgood (i.e., only print 'good' facets)
+    initialize qh.CENTERtype, qh.normal_size,
+      qh.center_size, qh.TRACEpoint/level,
+    initialize and test random numbers
+    check for conflicting print output options
+*/
+void qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc) {
+  int seed, pointsneeded, extra= 0, i, randi, k;
+  boolT printgeom= False, printmath= False, printcoplanar= False;
+  realT randr;
+  realT factorial;
+
+  time_t timedata;
+
+  trace0((qh ferr, "qh_initqhull_globals: for %s | %s\n", qh rbox_command,
+      qh qhull_command));
+  qh POINTSmalloc= ismalloc;
+  qh first_point= points;
+  qh num_points= numpoints;
+  qh hull_dim= qh input_dim= dim;
+  if (!qh NOpremerge && !qh MERGEexact && !qh PREmerge && qh JOGGLEmax > REALmax/2) {
+    qh MERGING= True;
+    if (qh hull_dim <= 4) {
+      qh PREmerge= True;
+      qh_option ("_pre-merge", NULL, NULL);
+    }else {
+      qh MERGEexact= True;
+      qh_option ("Qxact_merge", NULL, NULL);
+    }
+  }else if (qh MERGEexact) 
+    qh MERGING= True;
+  if (!qh NOpremerge && qh JOGGLEmax > REALmax/2) {
+#ifdef qh_NOmerge
+    qh JOGGLEmax= 0.0;
+#endif
+  }
+  if (qh TRIangulate && qh JOGGLEmax < REALmax/2 && qh PRINTprecision)
+    fprintf(qh ferr, "qhull warning: joggle ('QJ') always produces simplicial output.  Triangulated output ('Qt') does nothing.\n");
+  if (qh JOGGLEmax < REALmax/2 && qh DELAUNAY && !qh SCALEinput && !qh SCALElast) {
+    qh SCALElast= True;
+    qh_option ("Qbbound-last-qj", NULL, NULL);
+  }
+  if (qh MERGING && !qh POSTmerge && qh premerge_cos > REALmax/2
+  && qh premerge_centrum == 0) {
+    qh ZEROcentrum= True;
+    qh ZEROall_ok= True;
+    qh_option ("_zero-centrum", NULL, NULL);
+  }
+  if (qh JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh PRINTprecision)
+    fprintf(qh ferr, "qhull warning: real epsilon, %2.2g, is probably too large for joggle ('QJn')\nRecompile with double precision reals (see user.h).\n",
+          REALepsilon);
+#ifdef qh_NOmerge
+  if (qh MERGING) {
+    fprintf (qh ferr, "qhull input error: merging not installed (qh_NOmerge + 'Qx', 'Cn' or 'An')\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+#endif
+  if (!(qh PRINTgood || qh PRINTneighbors)) {
+    if (qh KEEParea || qh KEEPminArea < REALmax/2 || qh KEEPmerge || qh DELAUNAY
+	|| (!qh ONLYgood && (qh GOODvertex || qh GOODpoint))) {
+      qh PRINTgood= True;
+      qh_option ("Pgood", NULL, NULL);
+    }
+  }
+  if (qh DELAUNAY && qh KEEPcoplanar && !qh KEEPinside) {
+    qh KEEPinside= True;
+    qh_option ("Qinterior-keep", NULL, NULL);
+  }
+  if (qh DELAUNAY && qh HALFspace) {
+    fprintf (qh ferr, "qhull input error: can not use Delaunay ('d') or Voronoi ('v') with halfspace intersection ('H')\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (!qh DELAUNAY && (qh UPPERdelaunay || qh ATinfinity)) {
+    fprintf (qh ferr, "qhull input error: use upper-Delaunay ('Qu') or infinity-point ('Qz') with Delaunay ('d') or Voronoi ('v')\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (qh UPPERdelaunay && qh ATinfinity) {
+    fprintf (qh ferr, "qhull input error: can not use infinity-point ('Qz') with upper-Delaunay ('Qu')\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (qh SCALElast && !qh DELAUNAY && qh PRINTprecision)
+    fprintf (qh ferr, "qhull input warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n");
+  qh DOcheckmax= (!qh SKIPcheckmax && qh MERGING );
+  qh KEEPnearinside= (qh DOcheckmax && !(qh KEEPinside && qh KEEPcoplanar) 
+                          && !qh NOnearinside);
+  if (qh MERGING)
+    qh CENTERtype= qh_AScentrum;
+  else if (qh VORONOI)
+    qh CENTERtype= qh_ASvoronoi;
+  if (qh TESTvneighbors && !qh MERGING) {
+    fprintf(qh ferr, "qhull input error: test vertex neighbors ('Qv') needs a merge option\n");
+    qh_errexit (qh_ERRinput, NULL ,NULL);
+  }
+  if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) {
+    qh hull_dim -= qh PROJECTinput;
+    if (qh DELAUNAY) {
+      qh hull_dim++;
+      extra= 1;
+    }
+  }
+  if (qh hull_dim <= 1) {
+    fprintf(qh ferr, "qhull error: dimension %d must be > 1\n", qh hull_dim);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  for (k= 2, factorial=1.0; k < qh hull_dim; k++)
+    factorial *= k;
+  qh AREAfactor= 1.0 / factorial;
+  trace2((qh ferr, "qh_initqhull_globals: initialize globals.  dim %d numpoints %d malloc? %d projected %d to hull_dim %d\n",
+	dim, numpoints, ismalloc, qh PROJECTinput, qh hull_dim));
+  qh normal_size= qh hull_dim * sizeof(coordT);
+  qh center_size= qh normal_size - sizeof(coordT);
+  pointsneeded= qh hull_dim+1;
+  if (qh hull_dim > qh_DIMmergeVertex) {
+    qh MERGEvertices= False;
+    qh_option ("Q3-no-merge-vertices-dim-high", NULL, NULL);
+  }
+  if (qh GOODpoint)
+    pointsneeded++;
+#ifdef qh_NOtrace
+  if (qh IStracing) {
+    fprintf (qh ferr, "qhull input error: tracing is not installed (qh_NOtrace in user.h)");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+#endif
+  if (qh RERUN > 1) {
+    qh TRACElastrun= qh IStracing; /* qh_build_withrestart duplicates next conditional */
+    if (qh IStracing != -1)
+      qh IStracing= 0;
+  }else if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
+    qh TRACElevel= (qh IStracing? qh IStracing : 3);
+    qh IStracing= 0;
+  }
+  if (qh ROTATErandom == 0 || qh ROTATErandom == -1) {
+    seed= time (&timedata);
+    if (qh ROTATErandom  == -1) {
+      seed= -seed;
+      qh_option ("QRandom-seed", &seed, NULL );
+    }else
+      qh_option ("QRotate-random", &seed, NULL);
+    qh ROTATErandom= seed;
+  }
+  seed= qh ROTATErandom;
+  if (seed == INT_MIN)    /* default value */
+    seed= 1;
+  else if (seed < 0)
+    seed= -seed;
+  qh_RANDOMseed_(seed);
+  randr= 0.0;
+  for (i= 1000; i--; ) {
+    randi= qh_RANDOMint;
+    randr += randi;
+    if (randi > qh_RANDOMmax) {
+      fprintf (qh ferr, "\
+qhull configuration error (qh_RANDOMmax in user.h):\n\
+   random integer %d > qh_RANDOMmax (%.8g)\n",
+	       randi, qh_RANDOMmax);
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+  }
+  qh_RANDOMseed_(seed);
+  randr = randr/1000;
+  if (randr < qh_RANDOMmax/10
+  || randr > qh_RANDOMmax * 5)
+    fprintf (qh ferr, "\
+qhull configuration warning (qh_RANDOMmax in user.h):\n\
+   average of 1000 random integers (%.2g) is much different than expected (%.2g).\n\
+   Is qh_RANDOMmax (%.2g) wrong?\n",
+	     randr, qh_RANDOMmax/2.0, qh_RANDOMmax);
+  qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax;
+  qh RANDOMb= 1.0 - qh RANDOMfactor;
+  if (qh_HASHfactor < 1.1) {
+    fprintf(qh ferr, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1.  Qhull uses linear hash probing\n",
+      qh_HASHfactor);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  if (numpoints+extra < pointsneeded) {
+    fprintf(qh ferr,"qhull input error: not enough points (%d) to construct initial simplex (need %d)\n",
+	    numpoints, pointsneeded);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (qh PRINTtransparent) {
+    if (qh hull_dim != 4 || !qh DELAUNAY || qh VORONOI || qh DROPdim >= 0) {
+      fprintf(qh ferr,"qhull input error: transparent Delaunay ('Gt') needs 3-d Delaunay ('d') w/o 'GDn'\n");
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+    qh DROPdim = 3;
+    qh PRINTridges = True;
+  }
+  for (i= qh_PRINTEND; i--; ) {
+    if (qh PRINTout[i] == qh_PRINTgeom)
+      printgeom= True;
+    else if (qh PRINTout[i] == qh_PRINTmathematica)
+      printmath= True;
+    else if (qh PRINTout[i] == qh_PRINTcoplanars)
+      printcoplanar= True;
+    else if (qh PRINTout[i] == qh_PRINTpointnearest)
+      printcoplanar= True;
+    else if (qh PRINTout[i] == qh_PRINTpointintersect && !qh HALFspace) {
+      fprintf (qh ferr, "qhull input error: option 'Fp' is only used for \nhalfspace intersection ('Hn,n,n').\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }else if (qh PRINTout[i] == qh_PRINTtriangles && (qh HALFspace || qh VORONOI)) {
+      fprintf (qh ferr, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }else if (qh PRINTout[i] == qh_PRINTcentrums && qh VORONOI) {
+      fprintf (qh ferr, "qhull input error: option 'FC' is not available for Voronoi vertices ('v')\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }else if (qh PRINTout[i] == qh_PRINTvertices) {
+      if (qh VORONOI)
+        qh_option ("Fvoronoi", NULL, NULL);
+      else 
+        qh_option ("Fvertices", NULL, NULL);
+    }
+  }
+  if (printcoplanar && qh DELAUNAY && qh JOGGLEmax < REALmax/2) {
+    if (qh PRINTprecision) 
+      fprintf (qh ferr, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
+  }
+  if (!qh KEEPcoplanar && !qh KEEPinside && !qh ONLYgood) {
+    if ((qh PRINTcoplanar && qh PRINTspheres) || printcoplanar) {
+      qh KEEPcoplanar = True;
+      qh_option ("Qcoplanar", NULL, NULL);
+    }
+  }
+  if (printmath && (qh hull_dim > 3 || qh VORONOI)) {
+    fprintf (qh ferr, "qhull input error: Mathematica output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (printgeom) {
+    if (qh hull_dim > 4) {
+      fprintf (qh ferr, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    if (qh PRINTnoplanes && !(qh PRINTcoplanar + qh PRINTcentrums
+     + qh PRINTdots + qh PRINTspheres + qh DOintersections + qh PRINTridges)) {
+      fprintf (qh ferr, "qhull input error: no output specified for Geomview\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    if (qh VORONOI && (qh hull_dim > 3 || qh DROPdim >= 0)) {
+      fprintf (qh ferr, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    /* can not warn about furthest-site Geomview output: no lower_threshold */
+    if (qh hull_dim == 4 && qh DROPdim == -1 &&
+	(qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
+      fprintf (qh ferr, "qhull input warning: coplanars, vertices, and centrums output not\n\
+available for 4-d output (ignored).  Could use 'GDn' instead.\n");
+      qh PRINTcoplanar= qh PRINTspheres= qh PRINTcentrums= False;
+    }
+  }
+  qh PRINTdim= qh hull_dim;
+  if (qh DROPdim >=0) {    /* after Geomview checks */
+    if (qh DROPdim < qh hull_dim) {
+      qh PRINTdim--;
+      if (!printgeom || qh hull_dim < 3)
+        fprintf (qh ferr, "qhull input warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh DROPdim);
+    }else
+      qh DROPdim= -1;
+  }else if (qh VORONOI) {
+    qh DROPdim= qh hull_dim-1;
+    qh PRINTdim= qh hull_dim-1;
+  }
+} /* initqhull_globals */
+ 
+/*---------------------------------
+
+  qh_initqhull_mem(  )
+    initialize mem.c for qhull
+    qh.hull_dim and qh.normal_size determine some of the allocation sizes
+    if qh.MERGING,
+      includes ridgeT
+    calls qh_user_memsizes() to add up to 10 additional sizes for quick allocation
+      (see numsizes below)
+
+  returns:
+    mem.c already for qh_memalloc/qh_memfree (errors if called beforehand)
+
+  notes:
+    qh_produceoutput() prints memsizes
+
+*/
+void qh_initqhull_mem (void) {
+  int numsizes;
+  int i;
+
+  numsizes= 8+10;
+  qh_meminitbuffers (qh IStracing, qh_MEMalign, numsizes,
+                     qh_MEMbufsize,qh_MEMinitbuf);
+  qh_memsize(sizeof(vertexT));
+  if (qh MERGING) {
+    qh_memsize(sizeof(ridgeT));
+    qh_memsize(sizeof(mergeT));
+  }
+  qh_memsize(sizeof(facetT));
+  i= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;  /* ridge.vertices */
+  qh_memsize(i);
+  qh_memsize(qh normal_size);        /* normal */
+  i += SETelemsize;                 /* facet.vertices, .ridges, .neighbors */
+  qh_memsize(i);
+  qh_user_memsizes();
+  qh_memsetup();
+} /* initqhull_mem */
+
+/*---------------------------------
+
+  qh_initqhull_start( infile, outfile, errfile )
+    start initialization of qhull
+    initialize statistics, stdio, default values for global variables
+
+  see:
+    qh_maxmin() determines the precision constants
+*/
+void qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile) {
+
+  qh_CPUclock; /* start the clock */
+#if qh_QHpointer
+  if (!(qh_qh= (qhT *)malloc (sizeof(qhT)))) {
+    fprintf (errfile, "qhull error (qh_initqhull_globals): insufficient memory\n");
+    exit (qh_ERRmem);  /* no error handler */
+  }
+  memset((char *)qh_qh, 0, sizeof(qhT));   /* every field is 0, FALSE, NULL */
+#else
+  memset((char *)&qh_qh, 0, sizeof(qhT));
+#endif
+  strcat (qh qhull, "qhull");
+  qh_initstatistics();
+  qh ANGLEmerge= True;
+  qh DROPdim= -1;
+  qh ferr= errfile;
+  qh fin= infile;
+  qh fout= outfile;
+  qh furthest_id= -1;
+  qh JOGGLEmax= REALmax;
+  qh KEEPminArea = REALmax;
+  qh last_low= REALmax;
+  qh last_high= REALmax;
+  qh last_newhigh= REALmax;
+  qh max_outside= 0.0;
+  qh max_vertex= 0.0;
+  qh MAXabs_coord= 0.0;
+  qh MAXsumcoord= 0.0;
+  qh MAXwidth= -REALmax;
+  qh MERGEindependent= True;
+  qh MINdenom_1= fmax_(1.0/REALmax, REALmin); /* used by qh_scalepoints */
+  qh MINoutside= 0.0;
+  qh MINvisible= REALmax;
+  qh MAXcoplanar= REALmax;
+  qh outside_err= REALmax;
+  qh premerge_centrum= 0.0;
+  qh premerge_cos= REALmax;
+  qh PRINTprecision= True;
+  qh PRINTradius= 0.0;
+  qh postmerge_cos= REALmax;
+  qh postmerge_centrum= 0.0;
+  qh ROTATErandom= INT_MIN;
+  qh MERGEvertices= True;
+  qh totarea= 0.0;
+  qh totvol= 0.0;
+  qh TRACEdist= REALmax;
+  qh TRACEpoint= -1; /* recompile or use 'TPn' */
+  qh tracefacet_id= UINT_MAX;  /* recompile to trace a facet */
+  qh tracevertex_id= UINT_MAX; /* recompile to trace a vertex */
+  qh_RANDOMseed_(1);
+} /* initqhull_start */
+
+/*---------------------------------
+
+  qh_initthresholds( commandString )
+    set thresholds for printing and scaling from commandString
+
+  returns:
+    sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used
+
+  see:
+    qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk'
+    qh_inthresholds()
+
+  design:
+    for each 'Pdn' or 'PDn' option
+      check syntax
+      set qh.lower_threshold or qh.upper_threshold
+    set qh.GOODthreshold if an unbounded threshold is used
+    set qh.SPLITthreshold if a bounded threshold is used
+*/
+void qh_initthresholds(char *command) {
+  realT value;
+  int index, maxdim, k;
+  char *s= command;
+  char key;
+
+  maxdim= qh input_dim;
+  if (qh DELAUNAY && (qh PROJECTdelaunay || qh PROJECTinput))
+    maxdim++;
+  while (*s) {
+    if (*s == '-')
+      s++;
+    if (*s == 'P') {
+      s++;
+      while (*s && !isspace(key= *s++)) {
+	if (key == 'd' || key == 'D') {
+	  if (!isdigit(*s)) {
+	    fprintf(qh ferr, "qhull warning: no dimension given for Print option '%c' at: %s.  Ignored\n",
+		    key, s-1);
+	    continue;
+	  }
+	  index= qh_strtol (s, &s);
+	  if (index >= qh hull_dim) {
+	    fprintf(qh ferr, "qhull warning: dimension %d for Print option '%c' is >= %d.  Ignored\n",
+	        index, key, qh hull_dim);
+	    continue;
+	  }
+	  if (*s == ':') {
+	    s++;
+	    value= qh_strtod(s, &s);
+	    if (fabs((double)value) > 1.0) {
+	      fprintf(qh ferr, "qhull warning: value %2.4g for Print option %c is > +1 or < -1.  Ignored\n",
+	              value, key);
+	      continue;
+	    }
+	  }else
+	    value= 0.0;
+	  if (key == 'd')
+	    qh lower_threshold[index]= value;
+	  else
+	    qh upper_threshold[index]= value;
+	}
+      }
+    }else if (*s == 'Q') {
+      s++;
+      while (*s && !isspace(key= *s++)) {
+	if (key == 'b' && *s == 'B') {
+	  s++;
+	  for (k=maxdim; k--; ) {
+	    qh lower_bound[k]= -qh_DEFAULTbox;
+	    qh upper_bound[k]= qh_DEFAULTbox;
+	  }
+	}else if (key == 'b' && *s == 'b')
+	  s++;
+	else if (key == 'b' || key == 'B') {
+	  if (!isdigit(*s)) {
+	    fprintf(qh ferr, "qhull warning: no dimension given for Qhull option %c.  Ignored\n",
+		    key);
+	    continue;
+	  }
+	  index= qh_strtol (s, &s);
+	  if (index >= maxdim) {
+	    fprintf(qh ferr, "qhull warning: dimension %d for Qhull option %c is >= %d.  Ignored\n",
+	        index, key, maxdim);
+	    continue;
+	  }
+	  if (*s == ':') {
+	    s++;
+	    value= qh_strtod(s, &s);
+	  }else if (key == 'b')
+	    value= -qh_DEFAULTbox;
+	  else
+	    value= qh_DEFAULTbox;
+	  if (key == 'b')
+	    qh lower_bound[index]= value;
+	  else
+	    qh upper_bound[index]= value;
+	}
+      }
+    }else {
+      while (*s && !isspace (*s))
+        s++;
+    }
+    while (isspace (*s))
+      s++;
+  }
+  for (k= qh hull_dim; k--; ) {
+    if (qh lower_threshold[k] > -REALmax/2) {
+      qh GOODthreshold= True;
+      if (qh upper_threshold[k] < REALmax/2) {
+        qh SPLITthresholds= True;
+        qh GOODthreshold= False;
+        break;
+      }
+    }else if (qh upper_threshold[k] < REALmax/2)
+      qh GOODthreshold= True;
+  }
+} /* initthresholds */
+
+/*---------------------------------
+
+  qh_option( option, intVal, realVal )
+    add an option description to qh.qhull_options
+
+  notes:
+    will be printed with statistics ('Ts') and errors
+    strlen(option) < 40
+*/
+void qh_option (char *option, int *i, realT *r) {
+  char buf[200];
+  int len, maxlen;
+
+  sprintf (buf, "  %s", option);
+  if (i)
+    sprintf (buf+strlen(buf), " %d", *i);
+  if (r)
+    sprintf (buf+strlen(buf), " %2.2g", *r);
+  len= strlen(buf);
+  qh qhull_optionlen += len;
+  maxlen= sizeof (qh qhull_options) - len -1;
+  maximize_(maxlen, 0);
+  if (qh qhull_optionlen >= 80 && maxlen > 0) {
+    qh qhull_optionlen= len;
+    strncat (qh qhull_options, "\n", maxlen--);
+  }
+  strncat (qh qhull_options, buf, maxlen);
+} /* option */
+
+#if qh_QHpointer
+/*---------------------------------
+
+  qh_restore_qhull( oldqh )
+    restores a previously saved qhull
+    also restores qh_qhstat and qhmem.tempstack
+
+  notes:
+    errors if current qhull hasn't been saved or freed
+    uses qhmem for error reporting
+
+  NOTE 1998/5/11:
+    Freeing memory after qh_save_qhull and qh_restore_qhull
+    is complicated.  The procedures will be redesigned.
+
+  see:
+    qh_save_qhull()
+*/
+void qh_restore_qhull (qhT **oldqh) {
+
+  if (*oldqh && strcmp ((*oldqh)->qhull, "qhull")) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): %p is not a qhull data structure\n",
+                  *oldqh);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  if (qh_qh) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): did not save or free existing qhull\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  if (!*oldqh || !(*oldqh)->old_qhstat) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): did not previously save qhull %p\n",
+                  *oldqh);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh_qh= *oldqh;
+  *oldqh= NULL;
+  qh_qhstat= qh old_qhstat;
+  qhmem.tempstack= qh old_tempstack;
+  trace1((qh ferr, "qh_restore_qhull: restored qhull from %p\n", *oldqh));
+} /* restore_qhull */
+
+/*---------------------------------
+
+  qh_save_qhull(  )
+    saves qhull for a later qh_restore_qhull
+    also saves qh_qhstat and qhmem.tempstack
+
+  returns:
+    qh_qh=NULL
+
+  notes:
+    need to initialize qhull or call qh_restore_qhull before continuing
+
+  NOTE 1998/5/11:
+    Freeing memory after qh_save_qhull and qh_restore_qhull
+    is complicated.  The procedures will be redesigned.
+
+  see:
+    qh_restore_qhull()
+*/
+qhT *qh_save_qhull (void) {
+  qhT *oldqh;
+
+  trace1((qhmem.ferr, "qh_save_qhull: save qhull %p\n", qh_qh));
+  if (!qh_qh) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_save_qhull): qhull not initialized\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh old_qhstat= qh_qhstat;
+  qh_qhstat= NULL;
+  qh old_tempstack= qhmem.tempstack;
+  qhmem.tempstack= NULL;
+  oldqh= qh_qh;
+  qh_qh= NULL;
+  return oldqh;
+} /* save_qhull */
+
+#endif
+
+/*---------------------------------
+
+  qh_strtol( s, endp) qh_strtod( s, endp)
+    internal versions of strtol() and strtod()
+    does not skip trailing spaces
+  notes:
+    some implementations of strtol()/strtod() skip trailing spaces
+*/
+double qh_strtod (const char *s, char **endp) {
+  double result;
+
+  result= strtod (s, endp);
+  if (s < (*endp) && (*endp)[-1] == ' ')
+    (*endp)--;
+  return result;
+} /* strtod */
+
+int qh_strtol (const char *s, char **endp) {
+  int result;
+
+  result= (int) strtol (s, endp, 10);
+  if (s< (*endp) && (*endp)[-1] == ' ')
+    (*endp)--;
+  return result;
+} /* strtol */
diff --git a/extern/qhull/src/io.c b/extern/qhull/src/io.c
new file mode 100644
index 00000000000..9b0ccdd0b24
--- /dev/null
+++ b/extern/qhull/src/io.c
@@ -0,0 +1,4089 @@
+/*
  ---------------------------------
+
+   io.c 
+   Input/Output routines of qhull application
+
+   see qh-io.htm and io.h
+
+   see user.c for qh_errprint and qh_printfacetlist
+
+   unix.c calls qh_readpoints and qh_produce_output
+
+   unix.c and user.c are the only callers of io.c functions
+   This allows the user to avoid loading io.o from qhull.a
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#include "qhull_a.h"
+
+/*========= -prototypes for internal functions ========= */
+
+static int qh_compare_facetarea(const void *p1, const void *p2);
+static int qh_compare_facetmerge(const void *p1, const void *p2);
+static int qh_compare_facetvisit(const void *p1, const void *p2);
+int qh_compare_vertexpoint(const void *p1, const void *p2); /* not used */
+
+/*========= -functions in alphabetical order after qh_produce_output()  =====*/
+
+/*---------------------------------
+  
+  qh_produce_output()
+    prints out the result of qhull in desired format
+    if qh.GETarea
+      computes and prints area and volume
+    qh.PRINTout[] is an array of output formats
+
+  notes:
+    prints output in qh.PRINTout order
+*/
+void qh_produce_output(void) {
+  int i, tempsize= qh_setsize ((setT*)qhmem.tempstack), d_1;
+
+  if (qh VORONOI) {
+    qh_clearcenters (qh_ASvoronoi);
+    qh_vertexneighbors();
+  }
+  if (qh TRIangulate) {
+    qh_triangulate(); 
+    if (qh VERIFYoutput && !qh CHECKfrequently) 
+      qh_checkpolygon (qh facet_list);
+  }
+  qh_findgood_all (qh facet_list); 
+  if (qh GETarea)
+    qh_getarea(qh facet_list);
+  if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
+    qh_markkeep (qh facet_list);
+  if (qh PRINTsummary)
+    qh_printsummary(qh ferr);
+  else if (qh PRINTout[0] == qh_PRINTnone)
+    qh_printsummary(qh fout);
+  for (i= 0; i < qh_PRINTEND; i++)
+    qh_printfacets (qh fout, qh PRINTout[i], qh facet_list, NULL, !qh_ALL);
+  qh_allstatistics();
+  if (qh PRINTprecision && !qh MERGING && (qh JOGGLEmax > REALmax/2 || qh RERUN))
+    qh_printstats (qh ferr, qhstat precision, NULL);
+  if (qh VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0)) 
+    qh_printstats (qh ferr, qhstat vridges, NULL);
+  if (qh PRINTstatistics) {
+    qh_collectstatistics();
+    qh_printstatistics(qh ferr, "");
+    qh_memstatistics (qh ferr);
+    d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
+    fprintf(qh ferr, "\
+    size in bytes: merge %ld ridge %ld vertex %ld facet %ld\n\
+         normal %d ridge vertices %d facet vertices or neighbors %ld\n",
+	    sizeof(mergeT), sizeof(ridgeT),
+	    sizeof(vertexT), sizeof(facetT),
+	    qh normal_size, d_1, d_1 + SETelemsize);
+  }
+  if (qh_setsize ((setT*)qhmem.tempstack) != tempsize) {
+    fprintf (qh ferr, "qhull internal error (qh_produce_output): temporary sets not empty (%d)\n",
+	     qh_setsize ((setT*)qhmem.tempstack));
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+} /* produce_output */
+
+
+/*---------------------------------
+  
+  dfacet( id )
+    print facet by id, for debugging
+
+*/
+void dfacet (unsigned id) {
+  facetT *facet;
+
+  FORALLfacets {
+    if (facet->id == id) {
+      qh_printfacet (qh fout, facet);
+      break;
+    }
+  }
+} /* dfacet */
+
+
+/*---------------------------------
+  
+  dvertex( id )
+    print vertex by id, for debugging
+*/
+void dvertex (unsigned id) {
+  vertexT *vertex;
+
+  FORALLvertices {
+    if (vertex->id == id) {
+      qh_printvertex (qh fout, vertex);
+      break;
+    }
+  }
+} /* dvertex */
+
+
+/*---------------------------------
+  
+  qh_compare_vertexpoint( p1, p2 )
+    used by qsort() to order vertices by point id 
+*/
+int qh_compare_vertexpoint(const void *p1, const void *p2) {
+  vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
+ 
+  return ((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
+} /* compare_vertexpoint */
+
+/*---------------------------------
+  
+  qh_compare_facetarea( p1, p2 )
+    used by qsort() to order facets by area
+*/
+static int qh_compare_facetarea(const void *p1, const void *p2) {
+  facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
+
+  if (!a->isarea)
+    return -1;
+  if (!b->isarea)
+    return 1; 
+  if (a->f.area > b->f.area)
+    return 1;
+  else if (a->f.area == b->f.area)
+    return 0;
+  return -1;
+} /* compare_facetarea */
+
+/*---------------------------------
+  
+  qh_compare_facetmerge( p1, p2 )
+    used by qsort() to order facets by number of merges
+*/
+static int qh_compare_facetmerge(const void *p1, const void *p2) {
+  facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
+ 
+  return (a->nummerge - b->nummerge);
+} /* compare_facetvisit */
+
+/*---------------------------------
+  
+  qh_compare_facetvisit( p1, p2 )
+    used by qsort() to order facets by visit id or id
+*/
+static int qh_compare_facetvisit(const void *p1, const void *p2) {
+  facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
+  int i,j;
+
+  if (!(i= a->visitid))
+    i= - a->id; /* do not convert to int */
+  if (!(j= b->visitid))
+    j= - b->id;
+  return (i - j);
+} /* compare_facetvisit */
+
+/*---------------------------------
+  
+  qh_countfacets( facetlist, facets, printall, 
+          numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars  )
+    count good facets for printing and set visitid
+    if allfacets, ignores qh_skipfacet()
+
+  notes:
+    qh_printsummary and qh_countfacets must match counts
+
+  returns:
+    numfacets, numsimplicial, total neighbors, numridges, coplanars
+    each facet with ->visitid indicating 1-relative position
+      ->visitid==0 indicates not good
+  
+  notes
+    numfacets >= numsimplicial
+    if qh.NEWfacets, 
+      does not count visible facets (matches qh_printafacet)
+
+  design:
+    for all facets on facetlist and in facets set
+      unless facet is skipped or visible (i.e., will be deleted)
+        mark facet->visitid
+        update counts
+*/
+void qh_countfacets (facetT *facetlist, setT *facets, boolT printall,
+    int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
+  facetT *facet, **facetp;
+  int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;
+
+  FORALLfacet_(facetlist) {
+    if ((facet->visible && qh NEWfacets)
+    || (!printall && qh_skipfacet(facet)))
+      facet->visitid= 0;
+    else {
+      facet->visitid= ++numfacets;
+      totneighbors += qh_setsize (facet->neighbors);
+      if (facet->simplicial) {
+        numsimplicial++;
+	if (facet->keepcentrum && facet->tricoplanar)
+	  numtricoplanars++;
+      }else
+        numridges += qh_setsize (facet->ridges);
+      if (facet->coplanarset)
+        numcoplanars += qh_setsize (facet->coplanarset);
+    }
+  }
+  FOREACHfacet_(facets) {
+    if ((facet->visible && qh NEWfacets)
+    || (!printall && qh_skipfacet(facet)))
+      facet->visitid= 0;
+    else {
+      facet->visitid= ++numfacets;
+      totneighbors += qh_setsize (facet->neighbors);
+      if (facet->simplicial){
+        numsimplicial++;
+	if (facet->keepcentrum && facet->tricoplanar)
+	  numtricoplanars++;
+      }else
+        numridges += qh_setsize (facet->ridges);
+      if (facet->coplanarset)
+        numcoplanars += qh_setsize (facet->coplanarset);
+    }
+  }
+  qh visit_id += numfacets+1;
+  *numfacetsp= numfacets;
+  *numsimplicialp= numsimplicial;
+  *totneighborsp= totneighbors;
+  *numridgesp= numridges;
+  *numcoplanarsp= numcoplanars;
+  *numtricoplanarsp= numtricoplanars;
+} /* countfacets */
+
+/*---------------------------------
+  
+  qh_detvnorm( vertex, vertexA, centers, offset )
+    compute separating plane of the Voronoi diagram for a pair of input sites
+    centers= set of facets (i.e., Voronoi vertices)
+      facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)
+        
+  assumes:
+    qh_ASvoronoi and qh_vertexneighbors() already set
+  
+  returns:
+    norm
+      a pointer into qh.gm_matrix to qh.hull_dim-1 reals
+      copy the data before reusing qh.gm_matrix
+    offset
+      if 'QVn'
+        sign adjusted so that qh.GOODvertexp is inside
+      else
+        sign adjusted so that vertex is inside
+      
+    qh.gm_matrix= simplex of points from centers relative to first center
+    
+  notes:
+    in io.c so that code for 'v Tv' can be removed by removing io.c
+    returns pointer into qh.gm_matrix to avoid tracking of temporary memory
+  
+  design:
+    determine midpoint of input sites
+    build points as the set of Voronoi vertices
+    select a simplex from points (if necessary)
+      include midpoint if the Voronoi region is unbounded
+    relocate the first vertex of the simplex to the origin
+    compute the normalized hyperplane through the simplex
+    orient the hyperplane toward 'QVn' or 'vertex'
+    if 'Tv' or 'Ts'
+      if bounded
+        test that hyperplane is the perpendicular bisector of the input sites
+      test that Voronoi vertices not in the simplex are still on the hyperplane
+    free up temporary memory
+*/
+pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
+  facetT *facet, **facetp;
+  int  i, k, pointid, pointidA, point_i, point_n;
+  setT *simplex= NULL;
+  pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
+  coordT *coord, *gmcoord, *normalp;
+  setT *points= qh_settemp (qh TEMPsize);
+  boolT nearzero= False;
+  boolT unbounded= False;
+  int numcenters= 0;
+  int dim= qh hull_dim - 1;
+  realT dist, offset, angle, zero= 0.0;
+
+  midpoint= qh gm_matrix + qh hull_dim * qh hull_dim;  /* last row */
+  for (k= 0; k < dim; k++)
+    midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
+  FOREACHfacet_(centers) {
+    numcenters++;
+    if (!facet->visitid)
+      unbounded= True;
+    else {
+      if (!facet->center)
+        facet->center= qh_facetcenter (facet->vertices);
+      qh_setappend (&points, facet->center);
+    }
+  }
+  if (numcenters > dim) {
+    simplex= qh_settemp (qh TEMPsize);
+    qh_setappend (&simplex, vertex->point);
+    if (unbounded)
+      qh_setappend (&simplex, midpoint);
+    qh_maxsimplex (dim, points, NULL, 0, &simplex);
+    qh_setdelnth (simplex, 0);
+  }else if (numcenters == dim) {
+    if (unbounded)
+      qh_setappend (&points, midpoint);
+    simplex= points; 
+  }else {
+    fprintf(qh ferr, "qh_detvnorm: too few points (%d) to compute separating plane\n", numcenters);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  i= 0;
+  gmcoord= qh gm_matrix;
+  point0= SETfirstt_(simplex, pointT);
+  FOREACHpoint_(simplex) {
+    if (qh IStracing >= 4)
+      qh_printmatrix(qh ferr, "qh_detvnorm: Voronoi vertex or midpoint", 
+                              &point, 1, dim);
+    if (point != point0) {
+      qh gm_row[i++]= gmcoord;
+      coord= point0;
+      for (k= dim; k--; )
+        *(gmcoord++)= *point++ - *coord++;
+    }
+  }
+  qh gm_row[i]= gmcoord;  /* does not overlap midpoint, may be used later for qh_areasimplex */
+  normal= gmcoord;
+  qh_sethyperplane_gauss (dim, qh gm_row, point0, True,
+           	normal, &offset, &nearzero);
+  if (qh GOODvertexp == vertexA->point)
+    inpoint= vertexA->point;
+  else
+    inpoint= vertex->point;
+  zinc_(Zdistio);
+  dist= qh_distnorm (dim, inpoint, normal, &offset);
+  if (dist > 0) {
+    offset= -offset;
+    normalp= normal;
+    for (k= dim; k--; ) {
+      *normalp= -(*normalp);
+      normalp++;
+    }
+  }
+  if (qh VERIFYoutput || qh PRINTstatistics) {
+    pointid= qh_pointid (vertex->point);
+    pointidA= qh_pointid (vertexA->point);
+    if (!unbounded) {
+      zinc_(Zdiststat);
+      dist= qh_distnorm (dim, midpoint, normal, &offset);
+      if (dist < 0)
+        dist= -dist;
+      zzinc_(Zridgemid);
+      wwmax_(Wridgemidmax, dist);
+      wwadd_(Wridgemid, dist);
+      trace4((qh ferr, "qh_detvnorm: points %d %d midpoint dist %2.2g\n",
+                 pointid, pointidA, dist));
+      for (k= 0; k < dim; k++) 
+        midpoint[k]= vertexA->point[k] - vertex->point[k];  /* overwrites midpoint! */
+      qh_normalize (midpoint, dim, False);
+      angle= qh_distnorm (dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
+      if (angle < 0.0)
+	angle= angle + 1.0;
+      else
+	angle= angle - 1.0;
+      if (angle < 0.0)
+	angle -= angle;
+      trace4((qh ferr, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n",
+                 pointid, pointidA, angle, nearzero));
+      if (nearzero) {
+        zzinc_(Zridge0);
+        wwmax_(Wridge0max, angle);
+        wwadd_(Wridge0, angle);
+      }else {
+        zzinc_(Zridgeok)
+        wwmax_(Wridgeokmax, angle);
+        wwadd_(Wridgeok, angle);
+      }
+    }
+    if (simplex != points) {
+      FOREACHpoint_i_(points) {
+        if (!qh_setin (simplex, point)) {
+          facet= SETelemt_(centers, point_i, facetT);
+	  zinc_(Zdiststat);
+  	  dist= qh_distnorm (dim, point, normal, &offset);
+          if (dist < 0)
+            dist= -dist;
+	  zzinc_(Zridge);
+          wwmax_(Wridgemax, dist);
+          wwadd_(Wridge, dist);
+          trace4((qh ferr, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n",
+                             pointid, pointidA, facet->visitid, dist));
+        }
+      }
+    }
+  }
+  *offsetp= offset;
+  if (simplex != points)
+    qh_settempfree (&simplex);
+  qh_settempfree (&points);
+  return normal;
+} /* detvnorm */
+
+/*---------------------------------
+
+  qh_detvridge( vertexA )
+    determine Voronoi ridge from 'seen' neighbors of vertexA
+    include one vertex-at-infinite if an !neighbor->visitid
+
+  returns:
+    temporary set of centers (facets, i.e., Voronoi vertices)
+    sorted by center id
+*/
+setT *qh_detvridge (vertexT *vertex) {
+  setT *centers= qh_settemp (qh TEMPsize);
+  setT *tricenters= qh_settemp (qh TEMPsize);
+  facetT *neighbor, **neighborp;
+  boolT firstinf= True;
+  
+  FOREACHneighbor_(vertex) {
+    if (neighbor->seen) {
+      if (neighbor->visitid) {
+	if (!neighbor->tricoplanar || qh_setunique (&tricenters, neighbor->center)) 
+	  qh_setappend (¢ers, neighbor);
+      }else if (firstinf) {
+        firstinf= False;
+        qh_setappend (¢ers, neighbor);
+      }
+    }
+  }
+  qsort (SETaddr_(centers, facetT), qh_setsize (centers),
+             sizeof (facetT *), qh_compare_facetvisit);
+  qh_settempfree (&tricenters);
+  return centers;
+} /* detvridge */      
+
+/*---------------------------------
+
+  qh_detvridge3( atvertex, vertex )
+    determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
+    include one vertex-at-infinite for !neighbor->visitid
+    assumes all facet->seen2= True
+
+  returns:
+    temporary set of centers (facets, i.e., Voronoi vertices)
+    listed in adjacency order (not oriented)
+    all facet->seen2= True
+
+  design:
+    mark all neighbors of atvertex
+    for each adjacent neighbor of both atvertex and vertex
+      if neighbor selected
+        add neighbor to set of Voronoi vertices
+*/
+setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex) {
+  setT *centers= qh_settemp (qh TEMPsize);
+  setT *tricenters= qh_settemp (qh TEMPsize);
+  facetT *neighbor, **neighborp, *facet= NULL;
+  boolT firstinf= True;
+  
+  FOREACHneighbor_(atvertex)
+    neighbor->seen2= False;
+  FOREACHneighbor_(vertex) {
+    if (!neighbor->seen2) {
+      facet= neighbor;
+      break;
+    }
+  }
+  while (facet) { 
+    facet->seen2= True;
+    if (neighbor->seen) {
+      if (facet->visitid) {
+	if (!facet->tricoplanar || qh_setunique (&tricenters, facet->center)) 
+	  qh_setappend (¢ers, facet);
+      }else if (firstinf) {
+        firstinf= False;
+        qh_setappend (¢ers, facet);
+      }
+    }
+    FOREACHneighbor_(facet) {
+      if (!neighbor->seen2) {
+	if (qh_setin (vertex->neighbors, neighbor))
+          break;
+	else
+	  neighbor->seen2= True;
+      }
+    }
+    facet= neighbor;
+  }
+  if (qh CHECKfrequently) {
+    FOREACHneighbor_(vertex) {
+      if (!neighbor->seen2) {
+	fprintf (stderr, "qh_detvridge3: neigbors of vertex p%d are not connected at facet %d\n",
+	         qh_pointid (vertex->point), neighbor->id);
+	qh_errexit (qh_ERRqhull, neighbor, NULL);
+      }
+    }
+  }
+  FOREACHneighbor_(atvertex) 
+    neighbor->seen2= True;
+  qh_settempfree (&tricenters);
+  return centers;
+} /* detvridge3 */      
+
+/*---------------------------------
+  
+  qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder )
+    if visitall,
+      visit all Voronoi ridges for vertex (i.e., an input site)
+    else
+      visit all unvisited Voronoi ridges for vertex
+      all vertex->seen= False if unvisited
+    assumes
+      all facet->seen= False
+      all facet->seen2= True (for qh_detvridge3)
+      all facet->visitid == 0 if vertex_at_infinity
+                         == index of Voronoi vertex 
+                         >= qh.num_facets if ignored
+    innerouter:
+      qh_RIDGEall--  both inner (bounded) and outer (unbounded) ridges
+      qh_RIDGEinner- only inner
+      qh_RIDGEouter- only outer
+      
+    if inorder
+      orders vertices for 3-d Voronoi diagrams
+  
+  returns:
+    number of visited ridges (does not include previously visited ridges)
+    
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers)
+        fp== any pointer (assumes FILE*)
+        vertex,vertexA= pair of input sites that define a Voronoi ridge
+        centers= set of facets (i.e., Voronoi vertices)
+                 ->visitid == index or 0 if vertex_at_infinity
+                 ordered for 3-d Voronoi diagram
+  notes:
+    uses qh.vertex_visit
+  
+  see:
+    qh_eachvoronoi_all()
+  
+  design:
+    mark selected neighbors of atvertex
+    for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
+      for each unvisited vertex 
+        if atvertex and vertex share more than d-1 neighbors
+          bump totalcount
+          if printvridge defined
+            build the set of shared neighbors (i.e., Voronoi vertices)
+            call printvridge
+*/
+int qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
+  boolT unbounded;
+  int count;
+  facetT *neighbor, **neighborp, *neighborA, **neighborAp;
+  setT *centers;
+  setT *tricenters= qh_settemp (qh TEMPsize);
+
+  vertexT *vertex, **vertexp;
+  boolT firstinf;
+  unsigned int numfacets= (unsigned int)qh num_facets;
+  int totridges= 0;
+
+  qh vertex_visit++;
+  atvertex->seen= True;
+  if (visitall) {
+    FORALLvertices 
+      vertex->seen= False;
+  }
+  FOREACHneighbor_(atvertex) {
+    if (neighbor->visitid < numfacets) 
+      neighbor->seen= True;
+  }
+  FOREACHneighbor_(atvertex) {
+    if (neighbor->seen) {
+      FOREACHvertex_(neighbor->vertices) {
+        if (vertex->visitid != qh vertex_visit && !vertex->seen) {
+	  vertex->visitid= qh vertex_visit;
+          count= 0;
+          firstinf= True;
+	  qh_settruncate (tricenters, 0);
+          FOREACHneighborA_(vertex) {
+            if (neighborA->seen) {
+	      if (neighborA->visitid) {
+		if (!neighborA->tricoplanar || qh_setunique (&tricenters, neighborA->center))
+		  count++;
+              }else if (firstinf) {
+                count++;
+                firstinf= False;
+	      }
+	    }
+          }
+          if (count >= qh hull_dim - 1) {  /* e.g., 3 for 3-d Voronoi */
+            if (firstinf) {
+              if (innerouter == qh_RIDGEouter)
+                continue;
+              unbounded= False;
+            }else {
+              if (innerouter == qh_RIDGEinner)
+                continue;
+              unbounded= True;
+            }
+            totridges++;
+            trace4((qh ferr, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n",
+                  count, qh_pointid (atvertex->point), qh_pointid (vertex->point)));
+            if (printvridge) { 
+	      if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */
+                centers= qh_detvridge3 (atvertex, vertex);
+	      else
+                centers= qh_detvridge (vertex);
+              (*printvridge) (fp, atvertex, vertex, centers, unbounded);
+              qh_settempfree (¢ers);
+            }
+          }
+        }
+      }
+    }
+  }
+  FOREACHneighbor_(atvertex) 
+    neighbor->seen= False;
+  qh_settempfree (&tricenters);
+  return totridges;
+} /* eachvoronoi */
+  
+
+/*---------------------------------
+  
+  qh_eachvoronoi_all( fp, printvridge, isupper, innerouter, inorder )
+    visit all Voronoi ridges
+    
+    innerouter:
+      see qh_eachvoronoi()
+      
+    if inorder
+      orders vertices for 3-d Voronoi diagrams
+    
+  returns
+    total number of ridges 
+
+    if isupper == facet->upperdelaunay  (i.e., a Vornoi vertex)
+      facet->visitid= Voronoi vertex index (same as 'o' format)
+    else 
+      facet->visitid= 0
+
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers)
+      [see qh_eachvoronoi]
+      
+  notes:
+    Not used for qhull.exe
+    same effect as qh_printvdiagram but ridges not sorted by point id
+*/
+int qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder) {
+  facetT *facet;
+  vertexT *vertex;
+  int numcenters= 1;  /* vertex 0 is vertex-at-infinity */
+  int totridges= 0;
+
+  qh_clearcenters (qh_ASvoronoi);
+  qh_vertexneighbors();
+  maximize_(qh visit_id, (unsigned) qh num_facets);
+  FORALLfacets {
+    facet->visitid= 0;
+    facet->seen= False;
+    facet->seen2= True;
+  }
+  FORALLfacets {
+    if (facet->upperdelaunay == isupper)
+      facet->visitid= numcenters++;
+  }
+  FORALLvertices 
+    vertex->seen= False;
+  FORALLvertices {
+    if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
+      continue;
+    totridges += qh_eachvoronoi (fp, printvridge, vertex, 
+                   !qh_ALL, innerouter, inorder);
+  }
+  return totridges;
+} /* eachvoronoi_all */
+      
+/*---------------------------------
+  
+  qh_facet2point( facet, point0, point1, mindist )
+    return two projected temporary vertices for a 2-d facet
+    may be non-simplicial
+
+  returns:
+    point0 and point1 oriented and projected to the facet
+    returns mindist (maximum distance below plane)
+*/
+void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
+  vertexT *vertex0, *vertex1;
+  realT dist;
+  
+  if (facet->toporient ^ qh_ORIENTclock) {
+    vertex0= SETfirstt_(facet->vertices, vertexT);
+    vertex1= SETsecondt_(facet->vertices, vertexT);
+  }else {
+    vertex1= SETfirstt_(facet->vertices, vertexT);
+    vertex0= SETsecondt_(facet->vertices, vertexT);
+  }
+  zadd_(Zdistio, 2);
+  qh_distplane(vertex0->point, facet, &dist);
+  *mindist= dist;
+  *point0= qh_projectpoint(vertex0->point, facet, dist);
+  qh_distplane(vertex1->point, facet, &dist);
+  minimize_(*mindist, dist);		
+  *point1= qh_projectpoint(vertex1->point, facet, dist);
+} /* facet2point */
+
+
+/*---------------------------------
+  
+  qh_facetvertices( facetlist, facets, allfacets )
+    returns temporary set of vertices in a set and/or list of facets
+    if allfacets, ignores qh_skipfacet()
+
+  returns:
+    vertices with qh.vertex_visit
+    
+  notes:
+    optimized for allfacets of facet_list
+
+  design:
+    if allfacets of facet_list
+      create vertex set from vertex_list
+    else
+      for each selected facet in facets or facetlist
+        append unvisited vertices to vertex set
+*/
+setT *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets) {
+  setT *vertices;
+  facetT *facet, **facetp;
+  vertexT *vertex, **vertexp;
+
+  qh vertex_visit++;
+  if (facetlist == qh facet_list && allfacets && !facets) {
+    vertices= qh_settemp (qh num_vertices);
+    FORALLvertices {
+      vertex->visitid= qh vertex_visit; 
+      qh_setappend (&vertices, vertex);
+    }
+  }else {
+    vertices= qh_settemp (qh TEMPsize);
+    FORALLfacet_(facetlist) {
+      if (!allfacets && qh_skipfacet (facet))
+        continue;
+      FOREACHvertex_(facet->vertices) {
+        if (vertex->visitid != qh vertex_visit) {
+          vertex->visitid= qh vertex_visit;
+          qh_setappend (&vertices, vertex);
+        }
+      }
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (!allfacets && qh_skipfacet (facet))
+      continue;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh vertex_visit) {
+        vertex->visitid= qh vertex_visit;
+        qh_setappend (&vertices, vertex);
+      }
+    }
+  }
+  return vertices;
+} /* facetvertices */
+
+/*---------------------------------
+  
+  qh_geomplanes( facet, outerplane, innerplane )
+    return outer and inner planes for Geomview 
+    qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
+
+  notes:
+    assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
+*/
+void qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane) {
+  realT radius;
+
+  if (qh MERGING || qh JOGGLEmax < REALmax/2) {
+    qh_outerinner (facet, outerplane, innerplane);
+    radius= qh PRINTradius;
+    if (qh JOGGLEmax < REALmax/2)
+      radius -= qh JOGGLEmax * sqrt (qh hull_dim);  /* already accounted for in qh_outerinner() */
+    *outerplane += radius;
+    *innerplane -= radius;
+    if (qh PRINTcoplanar || qh PRINTspheres) {
+      *outerplane += qh MAXabs_coord * qh_GEOMepsilon;
+      *innerplane -= qh MAXabs_coord * qh_GEOMepsilon;
+    }
+  }else 
+    *innerplane= *outerplane= 0;
+} /* geomplanes */
+
+
+/*---------------------------------
+  
+  qh_markkeep( facetlist )
+    mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
+    ignores visible facets (not part of convex hull)
+
+  returns:
+    may clear facet->good
+    recomputes qh.num_good
+
+  design:
+    get set of good facets
+    if qh.KEEParea
+      sort facets by area
+      clear facet->good for all but n largest facets
+    if qh.KEEPmerge
+      sort facets by merge count
+      clear facet->good for all but n most merged facets
+    if qh.KEEPminarea
+      clear facet->good if area too small
+    update qh.num_good    
+*/
+void qh_markkeep (facetT *facetlist) {
+  facetT *facet, **facetp;
+  setT *facets= qh_settemp (qh num_facets);
+  int size, count;
+
+  trace2((qh ferr, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n",
+          qh KEEParea, qh KEEPmerge, qh KEEPminArea));
+  FORALLfacet_(facetlist) {
+    if (!facet->visible && facet->good)
+      qh_setappend (&facets, facet);
+  }
+  size= qh_setsize (facets);
+  if (qh KEEParea) {
+    qsort (SETaddr_(facets, facetT), size,
+             sizeof (facetT *), qh_compare_facetarea);
+    if ((count= size - qh KEEParea) > 0) {
+      FOREACHfacet_(facets) {
+        facet->good= False;
+        if (--count == 0)
+          break;
+      }
+    }
+  }
+  if (qh KEEPmerge) {
+    qsort (SETaddr_(facets, facetT), size,
+             sizeof (facetT *), qh_compare_facetmerge);
+    if ((count= size - qh KEEPmerge) > 0) {
+      FOREACHfacet_(facets) {
+        facet->good= False;
+        if (--count == 0)
+          break;
+      }
+    }
+  }
+  if (qh KEEPminArea < REALmax/2) {
+    FOREACHfacet_(facets) {
+      if (!facet->isarea || facet->f.area < qh KEEPminArea)
+	facet->good= False;
+    }
+  }
+  qh_settempfree (&facets);
+  count= 0;
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      count++;
+  }
+  qh num_good= count;
+} /* markkeep */
+
+
+/*---------------------------------
+  
+  qh_markvoronoi( facetlist, facets, printall, islower, numcenters )
+    mark voronoi vertices for printing by site pairs
+  
+  returns:
+    temporary set of vertices indexed by pointid
+    islower set if printing lower hull (i.e., at least one facet is lower hull)
+    numcenters= total number of Voronoi vertices
+    bumps qh.printoutnum for vertex-at-infinity
+    clears all facet->seen and sets facet->seen2
+    
+    if selected
+      facet->visitid= Voronoi vertex id
+    else if upper hull (or 'Qu' and lower hull)
+      facet->visitid= 0
+    else
+      facet->visitid >= qh num_facets
+  
+  notes:
+    ignores qh.ATinfinity, if defined
+*/
+setT *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp) {
+  int numcenters=0;
+  facetT *facet, **facetp;
+  setT *vertices;
+  boolT islower= False;
+
+  qh printoutnum++;
+  qh_clearcenters (qh_ASvoronoi);  /* in case, qh_printvdiagram2 called by user */
+  qh_vertexneighbors();
+  vertices= qh_pointvertex();
+  if (qh ATinfinity) 
+    SETelem_(vertices, qh num_points-1)= NULL;
+  qh visit_id++;
+  maximize_(qh visit_id, (unsigned) qh num_facets);
+  FORALLfacet_(facetlist) { 
+    if (printall || !qh_skipfacet (facet)) {
+      if (!facet->upperdelaunay) {
+        islower= True;
+	break;
+      }
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (printall || !qh_skipfacet (facet)) {
+      if (!facet->upperdelaunay) {
+        islower= True;
+	break;
+      }
+    }
+  }
+  FORALLfacets {
+    if (facet->normal && (facet->upperdelaunay == islower))
+      facet->visitid= 0;  /* facetlist or facets may overwrite */
+    else
+      facet->visitid= qh visit_id;
+    facet->seen= False;
+    facet->seen2= True;
+  }
+  numcenters++;  /* qh_INFINITE */
+  FORALLfacet_(facetlist) {
+    if (printall || !qh_skipfacet (facet))
+      facet->visitid= numcenters++;
+  }
+  FOREACHfacet_(facets) {
+    if (printall || !qh_skipfacet (facet))
+      facet->visitid= numcenters++;  
+  }
+  *islowerp= islower;
+  *numcentersp= numcenters;
+  trace2((qh ferr, "qh_markvoronoi: islower %d numcenters %d\n", islower, numcenters));
+  return vertices;
+} /* markvoronoi */
+
+/*---------------------------------
+  
+  qh_order_vertexneighbors( vertex )
+    order facet neighbors of a 2-d or 3-d vertex by adjacency
+
+  notes:
+    does not orient the neighbors
+
+  design:
+    initialize a new neighbor set with the first facet in vertex->neighbors
+    while vertex->neighbors non-empty
+      select next neighbor in the previous facet's neighbor set
+    set vertex->neighbors to the new neighbor set
+*/
+void qh_order_vertexneighbors(vertexT *vertex) {
+  setT *newset;
+  facetT *facet, *neighbor, **neighborp;
+
+  trace4((qh ferr, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
+  newset= qh_settemp (qh_setsize (vertex->neighbors));
+  facet= (facetT*)qh_setdellast (vertex->neighbors);
+  qh_setappend (&newset, facet);
+  while (qh_setsize (vertex->neighbors)) {
+    FOREACHneighbor_(vertex) {
+      if (qh_setin (facet->neighbors, neighbor)) {
+        qh_setdel(vertex->neighbors, neighbor);
+        qh_setappend (&newset, neighbor);
+        facet= neighbor;
+        break;
+      }
+    }
+    if (!neighbor) {
+      fprintf (qh ferr, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
+        vertex->id, facet->id);
+      qh_errexit (qh_ERRqhull, facet, NULL);
+    }
+  }
+  qh_setfree (&vertex->neighbors);
+  qh_settemppop ();
+  vertex->neighbors= newset;
+} /* order_vertexneighbors */
+
+/*---------------------------------
+  
+  qh_printafacet( fp, format, facet, printall )
+    print facet to fp in given output format (see qh.PRINTout)
+
+  returns:
+    nop if !printall and qh_skipfacet()
+    nop if visible facet and NEWfacets and format != PRINTfacets
+    must match qh_countfacets
+
+  notes
+    preserves qh.visit_id
+    facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
+
+  see
+    qh_printbegin() and qh_printend()
+
+  design:
+    test for printing facet
+    call appropriate routine for format
+    or output results directly
+*/
+void qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall) {
+  realT color[4], offset, dist, outerplane, innerplane;
+  boolT zerodiv;
+  coordT *point, *normp, *coordp, **pointp, *feasiblep;
+  int k;
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+
+  if (!printall && qh_skipfacet (facet))
+    return;
+  if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
+    return;
+  qh printoutnum++;
+  switch (format) {
+  case qh_PRINTarea:
+    if (facet->isarea) {
+      fprintf (fp, qh_REAL_1, facet->f.area);
+      fprintf (fp, "\n");
+    }else
+      fprintf (fp, "0\n");
+    break;
+  case qh_PRINTcoplanars:
+    fprintf (fp, "%d", qh_setsize (facet->coplanarset));
+    FOREACHpoint_(facet->coplanarset)
+      fprintf (fp, " %d", qh_pointid (point));
+    fprintf (fp, "\n");
+    break;
+  case qh_PRINTcentrums:
+    qh_printcenter (fp, format, NULL, facet);
+    break;
+  case qh_PRINTfacets:
+    qh_printfacet (fp, facet);
+    break;
+  case qh_PRINTfacets_xridge:
+    qh_printfacetheader (fp, facet);
+    break;
+  case qh_PRINTgeom:  /* either 2 , 3, or 4-d by qh_printbegin */
+    if (!facet->normal)
+      break;
+    for (k= qh hull_dim; k--; ) {
+      color[k]= (facet->normal[k]+1.0)/2.0;
+      maximize_(color[k], -1.0);
+      minimize_(color[k], +1.0);
+    }
+    qh_projectdim3 (color, color);
+    if (qh PRINTdim != qh hull_dim)
+      qh_normalize2 (color, 3, True, NULL, NULL);
+    if (qh hull_dim <= 2)
+      qh_printfacet2geom (fp, facet, color);
+    else if (qh hull_dim == 3) {
+      if (facet->simplicial)
+        qh_printfacet3geom_simplicial (fp, facet, color);
+      else
+        qh_printfacet3geom_nonsimplicial (fp, facet, color);
+    }else {
+      if (facet->simplicial)
+        qh_printfacet4geom_simplicial (fp, facet, color);
+      else
+        qh_printfacet4geom_nonsimplicial (fp, facet, color);
+    }
+    break;
+  case qh_PRINTids:
+    fprintf (fp, "%d\n", facet->id);
+    break;
+  case qh_PRINTincidences:
+  case qh_PRINToff:
+  case qh_PRINTtriangles:
+    if (qh hull_dim == 3 && format != qh_PRINTtriangles) 
+      qh_printfacet3vertex (fp, facet, format);
+    else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
+      qh_printfacetNvertex_simplicial (fp, facet, format);
+    else
+      qh_printfacetNvertex_nonsimplicial (fp, facet, qh printoutvar++, format);
+    break;
+  case qh_PRINTinner:
+    qh_outerinner (facet, NULL, &innerplane);
+    offset= facet->offset - innerplane;
+    goto LABELprintnorm;
+    break; /* prevent warning */
+  case qh_PRINTmerges:
+    fprintf (fp, "%d\n", facet->nummerge);
+    break;
+  case qh_PRINTnormals:
+    offset= facet->offset;
+    goto LABELprintnorm;
+    break; /* prevent warning */
+  case qh_PRINTouter:
+    qh_outerinner (facet, &outerplane, NULL);
+    offset= facet->offset - outerplane;
+  LABELprintnorm:
+    if (!facet->normal) {
+      fprintf (fp, "no normal for facet f%d\n", facet->id);
+      break;
+    }
+    if (qh CDDoutput) {
+      fprintf (fp, qh_REAL_1, -offset);
+      for (k=0; k < qh hull_dim; k++) 
+	fprintf (fp, qh_REAL_1, -facet->normal[k]);
+    }else {
+      for (k=0; k < qh hull_dim; k++) 
+	fprintf (fp, qh_REAL_1, facet->normal[k]);
+      fprintf (fp, qh_REAL_1, offset);
+    }
+    fprintf (fp, "\n");
+    break;
+  case qh_PRINTmathematica:  /* either 2 or 3-d by qh_printbegin */
+    if (qh hull_dim == 2)
+      qh_printfacet2math (fp, facet, qh printoutvar++);
+    else 
+      qh_printfacet3math (fp, facet, qh printoutvar++);
+    break;
+  case qh_PRINTneighbors:
+    fprintf (fp, "%d", qh_setsize (facet->neighbors));
+    FOREACHneighbor_(facet)
+      fprintf (fp, " %d", 
+	       neighbor->visitid ? neighbor->visitid - 1: - neighbor->id);
+    fprintf (fp, "\n");
+    break;
+  case qh_PRINTpointintersect:
+    if (!qh feasible_point) {
+      fprintf (fp, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
+      qh_errexit( qh_ERRinput, NULL, NULL);
+    }
+    if (facet->offset > 0)
+      goto LABELprintinfinite;
+    point= coordp= (coordT*)qh_memalloc (qh normal_size);
+    normp= facet->normal;
+    feasiblep= qh feasible_point;
+    if (facet->offset < -qh MINdenom) {
+      for (k= qh hull_dim; k--; )
+        *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
+    }else {
+      for (k= qh hull_dim; k--; ) {
+        *(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,
+				 &zerodiv) + *(feasiblep++);
+        if (zerodiv) {
+          qh_memfree (point, qh normal_size);
+          goto LABELprintinfinite;
+        }
+      }
+    }
+    qh_printpoint (fp, NULL, point);
+    qh_memfree (point, qh normal_size);
+    break;
+  LABELprintinfinite:
+    for (k= qh hull_dim; k--; )
+      fprintf (fp, qh_REAL_1, qh_INFINITE);
+    fprintf (fp, "\n");   
+    break;
+  case qh_PRINTpointnearest:
+    FOREACHpoint_(facet->coplanarset) {
+      int id, id2;
+      vertex= qh_nearvertex (facet, point, &dist);
+      id= qh_pointid (vertex->point);
+      id2= qh_pointid (point);
+      fprintf (fp, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
+    }
+    break;
+  case qh_PRINTpoints:  /* VORONOI only by qh_printbegin */
+    if (qh CDDoutput)
+      fprintf (fp, "1 ");
+    qh_printcenter (fp, format, NULL, facet);
+    break;
+  case qh_PRINTvertices:
+    fprintf (fp, "%d", qh_setsize (facet->vertices));
+    FOREACHvertex_(facet->vertices)
+      fprintf (fp, " %d", qh_pointid (vertex->point));
+    fprintf (fp, "\n");
+    break;
+  }
+} /* printafacet */
+
+/*---------------------------------
+  
+  qh_printbegin(  )
+    prints header for all output formats
+
+  returns:
+    checks for valid format
+  
+  notes:
+    uses qh.visit_id for 3/4off
+    changes qh.interior_point if printing centrums
+    qh_countfacets clears facet->visitid for non-good facets
+    
+  see
+    qh_printend() and qh_printafacet()
+    
+  design:
+    count facets and related statistics
+    print header for format
+*/
+void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
+  int i, num;
+  facetT *facet, **facetp;
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+  pointT *point, **pointp, *pointtemp;
+
+  qh printoutnum= 0;
+  qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
+  switch (format) {
+  case qh_PRINTnone:
+    break;
+  case qh_PRINTarea:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTcoplanars:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTcentrums:
+    if (qh CENTERtype == qh_ASnone)
+      qh_clearcenters (qh_AScentrum);
+    fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
+    break;
+  case qh_PRINTfacets:
+  case qh_PRINTfacets_xridge:
+    if (facetlist)
+      qh_printvertexlist (fp, "Vertices and facets:\n", facetlist, facets, printall);
+    break;
+  case qh_PRINTgeom: 
+    if (qh hull_dim > 4)  /* qh_initqhull_globals also checks */
+      goto LABELnoformat;
+    if (qh VORONOI && qh hull_dim > 3)  /* PRINTdim == DROPdim == hull_dim-1 */
+      goto LABELnoformat;
+    if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
+      fprintf (qh ferr, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
+    if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
+			     (qh PRINTdim == 4 && qh PRINTcentrums)))
+      fprintf (qh ferr, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
+    if (qh PRINTdim == 4 && (qh PRINTspheres))
+      fprintf (qh ferr, "qhull warning: output for vertices not implemented in 4-d\n");
+    if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
+      fprintf (qh ferr, "qhull warning: 'Gnh' generates no output in 4-d\n");
+    if (qh PRINTdim == 2) {
+      fprintf(fp, "{appearance {linewidth 3} LIST # %s | %s\n",
+	      qh rbox_command, qh qhull_command);
+    }else if (qh PRINTdim == 3) {
+      fprintf(fp, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
+	      qh rbox_command, qh qhull_command);
+    }else if (qh PRINTdim == 4) {
+      qh visit_id++;
+      num= 0;
+      FORALLfacet_(facetlist)    /* get number of ridges to be printed */
+        qh_printend4geom (NULL, facet, &num, printall);
+      FOREACHfacet_(facets)
+        qh_printend4geom (NULL, facet, &num, printall);
+      qh ridgeoutnum= num;
+      qh printoutvar= 0;  /* counts number of ridges in output */
+      fprintf (fp, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
+    }
+    if (qh PRINTdots) {
+      qh printoutnum++;
+      num= qh num_points + qh_setsize (qh other_points);
+      if (qh DELAUNAY && qh ATinfinity)
+	num--;
+      if (qh PRINTdim == 4)
+        fprintf (fp, "4VECT %d %d 1\n", num, num);
+      else
+	fprintf (fp, "VECT %d %d 1\n", num, num);
+      for (i= num; i--; ) {
+        if (i % 20 == 0)
+          fprintf (fp, "\n");
+	fprintf (fp, "1 ");
+      }
+      fprintf (fp, "# 1 point per line\n1 ");
+      for (i= num-1; i--; ) {
+        if (i % 20 == 0)
+          fprintf (fp, "\n");
+	fprintf (fp, "0 ");
+      }
+      fprintf (fp, "# 1 color for all\n");
+      FORALLpoints {
+        if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
+	  if (qh PRINTdim == 4)
+	    qh_printpoint (fp, NULL, point);
+	  else
+	    qh_printpoint3 (fp, point);
+	}
+      }
+      FOREACHpoint_(qh other_points) {
+	if (qh PRINTdim == 4)
+	  qh_printpoint (fp, NULL, point);
+	else
+	  qh_printpoint3 (fp, point);
+      }
+      fprintf (fp, "0 1 1 1  # color of points\n");
+    }
+    if (qh PRINTdim == 4  && !qh PRINTnoplanes)
+      /* 4dview loads up multiple 4OFF objects slowly */
+      fprintf(fp, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
+    qh PRINTcradius= 2 * qh DISTround;  /* include test DISTround */
+    if (qh PREmerge) {
+      maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
+    }else if (qh POSTmerge)
+      maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
+    qh PRINTradius= qh PRINTcradius;
+    if (qh PRINTspheres + qh PRINTcoplanar)
+      maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius);
+    if (qh premerge_cos < REALmax/2) {
+      maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord);
+    }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
+      maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord);
+    }
+    maximize_(qh PRINTradius, qh MINvisible); 
+    if (qh JOGGLEmax < REALmax/2)
+      qh PRINTradius += qh JOGGLEmax * sqrt (qh hull_dim);
+    if (qh PRINTdim != 4 &&
+	(qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
+      vertices= qh_facetvertices (facetlist, facets, printall);
+      if (qh PRINTspheres && qh PRINTdim <= 3)
+         qh_printspheres (fp, vertices, qh PRINTradius);
+      if (qh PRINTcoplanar || qh PRINTcentrums) {
+        qh firstcentrum= True;
+        if (qh PRINTcoplanar&& !qh PRINTspheres) {
+          FOREACHvertex_(vertices) 
+            qh_printpointvect2 (fp, vertex->point, NULL,
+				qh interior_point, qh PRINTradius);
+	}
+        FORALLfacet_(facetlist) {
+	  if (!printall && qh_skipfacet(facet))
+	    continue;
+	  if (!facet->normal)
+	    continue;
+          if (qh PRINTcentrums && qh PRINTdim <= 3)
+            qh_printcentrum (fp, facet, qh PRINTcradius);
+	  if (!qh PRINTcoplanar)
+	    continue;
+          FOREACHpoint_(facet->coplanarset)
+            qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
+          FOREACHpoint_(facet->outsideset)
+            qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
+        }
+        FOREACHfacet_(facets) {
+	  if (!printall && qh_skipfacet(facet))
+	    continue;
+	  if (!facet->normal)
+	    continue;
+          if (qh PRINTcentrums && qh PRINTdim <= 3)
+            qh_printcentrum (fp, facet, qh PRINTcradius);
+	  if (!qh PRINTcoplanar)
+	    continue;
+          FOREACHpoint_(facet->coplanarset)
+            qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
+          FOREACHpoint_(facet->outsideset)
+            qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
+        }
+      }
+      qh_settempfree (&vertices);
+    }
+    qh visit_id++; /* for printing hyperplane intersections */
+    break;
+  case qh_PRINTids:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTincidences:
+    if (qh VORONOI && qh PRINTprecision)
+      fprintf (qh ferr, "qhull warning: writing Delaunay.  Use 'p' or 'o' for Voronoi centers\n");
+    qh printoutvar= qh vertex_id;  /* centrum id for non-simplicial facets */
+    if (qh hull_dim <= 3)
+      fprintf(fp, "%d\n", numfacets);
+    else
+      fprintf(fp, "%d\n", numsimplicial+numridges);
+    break;
+  case qh_PRINTinner:
+  case qh_PRINTnormals:
+  case qh_PRINTouter:
+    if (qh CDDoutput)
+      fprintf (fp, "%s | %s\nbegin\n    %d %d real\n", qh rbox_command, 
+              qh qhull_command, numfacets, qh hull_dim+1);
+    else
+      fprintf (fp, "%d\n%d\n", qh hull_dim+1, numfacets);
+    break;
+  case qh_PRINTmathematica:  
+    if (qh hull_dim > 3)  /* qh_initbuffers also checks */
+      goto LABELnoformat;
+    if (qh VORONOI)
+      fprintf (qh ferr, "qhull warning: output is the Delaunay triangulation\n");
+    fprintf(fp, "{\n");
+    qh printoutvar= 0;   /* counts number of facets for notfirst */
+    break;
+  case qh_PRINTmerges:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTpointintersect:
+    fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
+    break;
+  case qh_PRINTneighbors:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINToff:
+  case qh_PRINTtriangles:
+    if (qh VORONOI)
+      goto LABELnoformat;
+    num = qh hull_dim;
+    if (format == qh_PRINToff || qh hull_dim == 2)
+      fprintf (fp, "%d\n%d %d %d\n", num, 
+        qh num_points+qh_setsize (qh other_points), numfacets, totneighbors/2);
+    else { /* qh_PRINTtriangles */
+      qh printoutvar= qh num_points+qh_setsize (qh other_points); /* first centrum */
+      if (qh DELAUNAY)
+        num--;  /* drop last dimension */
+      fprintf (fp, "%d\n%d %d %d\n", num, qh printoutvar 
+	+ numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
+    }
+    FORALLpoints
+      qh_printpointid (qh fout, NULL, num, point, -1);
+    FOREACHpoint_(qh other_points)
+      qh_printpointid (qh fout, NULL, num, point, -1);
+    if (format == qh_PRINTtriangles && qh hull_dim > 2) {
+      FORALLfacets {
+	if (!facet->simplicial && facet->visitid)
+          qh_printcenter (qh fout, format, NULL, facet);
+      }
+    }
+    break;
+  case qh_PRINTpointnearest:
+    fprintf (fp, "%d\n", numcoplanars);
+    break;
+  case qh_PRINTpoints:
+    if (!qh VORONOI)
+      goto LABELnoformat;
+    if (qh CDDoutput)
+      fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
+             qh qhull_command, numfacets, qh hull_dim);
+    else
+      fprintf (fp, "%d\n%d\n", qh hull_dim-1, numfacets);
+    break;
+  case qh_PRINTvertices:
+    fprintf (fp, "%d\n", numfacets);
+    break;
+  case qh_PRINTsummary:
+  default:
+  LABELnoformat:
+    fprintf (qh ferr, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
+         qh hull_dim);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+} /* printbegin */
+
+/*---------------------------------
+  
+  qh_printcenter( fp, string, facet )
+    print facet->center as centrum or Voronoi center
+    string may be NULL.  Don't include '%' codes.
+    nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
+    if upper envelope of Delaunay triangulation and point at-infinity
+      prints qh_INFINITE instead;
+
+  notes:
+    defines facet->center if needed
+    if format=PRINTgeom, adds a 0 if would otherwise be 2-d
+*/
+void qh_printcenter (FILE *fp, int format, char *string, facetT *facet) {
+  int k, num;
+
+  if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
+    return;
+  if (string)
+    fprintf (fp, string, facet->id);
+  if (qh CENTERtype == qh_ASvoronoi) {
+    num= qh hull_dim-1;
+    if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
+      if (!facet->center)
+        facet->center= qh_facetcenter (facet->vertices);
+      for (k=0; k < num; k++)
+        fprintf (fp, qh_REAL_1, facet->center[k]);
+    }else {
+      for (k=0; k < num; k++)
+        fprintf (fp, qh_REAL_1, qh_INFINITE);
+    }
+  }else /* qh CENTERtype == qh_AScentrum */ {
+    num= qh hull_dim;
+    if (format == qh_PRINTtriangles && qh DELAUNAY) 
+      num--;
+    if (!facet->center) 
+      facet->center= qh_getcentrum (facet);
+    for (k=0; k < num; k++)
+      fprintf (fp, qh_REAL_1, facet->center[k]);
+  }
+  if (format == qh_PRINTgeom && num == 2)
+    fprintf (fp, " 0\n");
+  else
+    fprintf (fp, "\n");
+} /* printcenter */
+
+/*---------------------------------
+  
+  qh_printcentrum( fp, facet, radius )
+    print centrum for a facet in OOGL format
+    radius defines size of centrum
+    2-d or 3-d only
+
+  returns:
+    defines facet->center if needed
+*/
+void qh_printcentrum (FILE *fp, facetT *facet, realT radius) {
+  pointT *centrum, *projpt;
+  boolT tempcentrum= False;
+  realT xaxis[4], yaxis[4], normal[4], dist;
+  realT green[3]={0, 1, 0};
+  vertexT *apex;
+  int k;
+  
+  if (qh CENTERtype == qh_AScentrum) {
+    if (!facet->center)
+      facet->center= qh_getcentrum (facet);
+    centrum= facet->center;
+  }else {
+    centrum= qh_getcentrum (facet);
+    tempcentrum= True;
+  }
+  fprintf (fp, "{appearance {-normal -edge normscale 0} ");
+  if (qh firstcentrum) {
+    qh firstcentrum= False;
+    fprintf (fp, "{INST geom { define centrum CQUAD  # f%d\n\
+-0.3 -0.3 0.0001     0 0 1 1\n\
+ 0.3 -0.3 0.0001     0 0 1 1\n\
+ 0.3  0.3 0.0001     0 0 1 1\n\
+-0.3  0.3 0.0001     0 0 1 1 } transform { \n", facet->id);
+  }else
+    fprintf (fp, "{INST geom { : centrum } transform { # f%d\n", facet->id);
+  apex= SETfirstt_(facet->vertices, vertexT);
+  qh_distplane(apex->point, facet, &dist);
+  projpt= qh_projectpoint(apex->point, facet, dist);
+  for (k= qh hull_dim; k--; ) {
+    xaxis[k]= projpt[k] - centrum[k];
+    normal[k]= facet->normal[k];
+  }
+  if (qh hull_dim == 2) {
+    xaxis[2]= 0;
+    normal[2]= 0;
+  }else if (qh hull_dim == 4) {
+    qh_projectdim3 (xaxis, xaxis);
+    qh_projectdim3 (normal, normal);
+    qh_normalize2 (normal, qh PRINTdim, True, NULL, NULL);
+  }
+  qh_crossproduct (3, xaxis, normal, yaxis);
+  fprintf (fp, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
+  fprintf (fp, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
+  fprintf (fp, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
+  qh_printpoint3 (fp, centrum);
+  fprintf (fp, "1 }}}\n"); 
+  qh_memfree (projpt, qh normal_size);
+  qh_printpointvect (fp, centrum, facet->normal, NULL, radius, green);
+  if (tempcentrum)
+    qh_memfree (centrum, qh normal_size);
+} /* printcentrum */
+  
+/*---------------------------------
+  
+  qh_printend( fp, format )
+    prints trailer for all output formats
+
+  see:
+    qh_printbegin() and qh_printafacet()
+      
+*/
+void qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  int num;
+  facetT *facet, **facetp;
+
+  if (!qh printoutnum)
+    fprintf (qh ferr, "qhull warning: no facets printed\n");
+  switch (format) {
+  case qh_PRINTgeom:
+    if (qh hull_dim == 4 && qh DROPdim < 0  && !qh PRINTnoplanes) {
+      qh visit_id++;
+      num= 0;
+      FORALLfacet_(facetlist)
+        qh_printend4geom (fp, facet,&num, printall);
+      FOREACHfacet_(facets) 
+        qh_printend4geom (fp, facet, &num, printall);
+      if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
+	fprintf (qh ferr, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh ridgeoutnum, qh printoutvar, num);
+	qh_errexit (qh_ERRqhull, NULL, NULL);
+      }
+    }else
+      fprintf(fp, "}\n");
+    break;
+  case qh_PRINTinner:
+  case qh_PRINTnormals:
+  case qh_PRINTouter:
+    if (qh CDDoutput) 
+      fprintf (fp, "end\n");
+    break;
+  case qh_PRINTmathematica:
+    fprintf(fp, "}\n");
+    break;
+  case qh_PRINTpoints:
+    if (qh CDDoutput)
+      fprintf (fp, "end\n");
+    break;
+  }
+} /* printend */
+
+/*---------------------------------
+  
+  qh_printend4geom( fp, facet, numridges, printall )
+    helper function for qh_printbegin/printend
+
+  returns:
+    number of printed ridges
+  
+  notes:
+    just counts printed ridges if fp=NULL
+    uses facet->visitid
+    must agree with qh_printfacet4geom...
+
+  design:
+    computes color for facet from its normal
+    prints each ridge of facet 
+*/
+void qh_printend4geom (FILE *fp, facetT *facet, int *nump, boolT printall) {
+  realT color[3];
+  int i, num= *nump;
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  
+  if (!printall && qh_skipfacet(facet))
+    return;
+  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
+    return;
+  if (!facet->normal)
+    return;
+  if (fp) {
+    for (i=0; i < 3; i++) {
+      color[i]= (facet->normal[i]+1.0)/2.0;
+      maximize_(color[i], -1.0);
+      minimize_(color[i], +1.0);
+    }
+  }
+  facet->visitid= qh visit_id;
+  if (facet->simplicial) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh visit_id) {
+	if (fp)
+          fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
+		 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
+		 facet->id, neighbor->id);
+	num++;
+      }
+    }
+  }else {
+    FOREACHridge_(facet->ridges) {
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->visitid != qh visit_id) {
+	if (fp)
+          fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
+		 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
+		 ridge->id, facet->id, neighbor->id);
+	num++;
+      }
+    }
+  }
+  *nump= num;
+} /* printend4geom */
+
+/*---------------------------------
+  
+  qh_printextremes( fp, facetlist, facets, printall )
+    print extreme points for convex hulls or halfspace intersections
+
+  notes:
+    #points, followed by ids, one per line
+    
+    sorted by id
+    same order as qh_printpoints_out if no coplanar/interior points
+*/
+void qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall) {
+  setT *vertices, *points;
+  pointT *point;
+  vertexT *vertex, **vertexp;
+  int id;
+  int numpoints=0, point_i, point_n;
+  int allpoints= qh num_points + qh_setsize (qh other_points);
+
+  points= qh_settemp (allpoints);
+  qh_setzero (points, 0, allpoints);
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  FOREACHvertex_(vertices) {
+    id= qh_pointid (vertex->point);
+    if (id >= 0) {
+      SETelem_(points, id)= vertex->point;
+      numpoints++;
+    }
+  }
+  qh_settempfree (&vertices);
+  fprintf (fp, "%d\n", numpoints);
+  FOREACHpoint_i_(points) {
+    if (point) 
+      fprintf (fp, "%d\n", point_i);
+  }
+  qh_settempfree (&points);
+} /* printextremes */
+
+/*---------------------------------
+  
+  qh_printextremes_2d( fp, facetlist, facets, printall )
+    prints point ids for facets in qh_ORIENTclock order
+
+  notes:
+    #points, followed by ids, one per line
+    if facetlist/facets are disjoint than the output includes skips
+    errors if facets form a loop
+    does not print coplanar points
+*/
+void qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
+  int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
+  setT *vertices;
+  facetT *facet, *startfacet, *nextfacet;
+  vertexT *vertexA, *vertexB;
+
+  qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh visit_id */
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  fprintf(fp, "%d\n", qh_setsize (vertices));
+  qh_settempfree (&vertices);
+  if (!numfacets)
+    return;
+  facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
+  qh vertex_visit++;
+  qh visit_id++;
+  do {
+    if (facet->toporient ^ qh_ORIENTclock) {
+      vertexA= SETfirstt_(facet->vertices, vertexT);
+      vertexB= SETsecondt_(facet->vertices, vertexT);
+      nextfacet= SETfirstt_(facet->neighbors, facetT);
+    }else {
+      vertexA= SETsecondt_(facet->vertices, vertexT);
+      vertexB= SETfirstt_(facet->vertices, vertexT);
+      nextfacet= SETsecondt_(facet->neighbors, facetT);
+    }
+    if (facet->visitid == qh visit_id) {
+      fprintf(qh ferr, "qh_printextremes_2d: loop in facet list.  facet %d nextfacet %d\n",
+                 facet->id, nextfacet->id);
+      qh_errexit2 (qh_ERRqhull, facet, nextfacet);
+    }
+    if (facet->visitid) {
+      if (vertexA->visitid != qh vertex_visit) {
+	vertexA->visitid= qh vertex_visit;
+	fprintf(fp, "%d\n", qh_pointid (vertexA->point));
+      }
+      if (vertexB->visitid != qh vertex_visit) {
+	vertexB->visitid= qh vertex_visit;
+	fprintf(fp, "%d\n", qh_pointid (vertexB->point));
+      }
+    }
+    facet->visitid= qh visit_id;
+    facet= nextfacet;
+  }while (facet && facet != startfacet);
+} /* printextremes_2d */
+
+/*---------------------------------
+  
+  qh_printextremes_d( fp, facetlist, facets, printall )
+    print extreme points of input sites for Delaunay triangulations
+
+  notes:
+    #points, followed by ids, one per line
+    
+    unordered
+*/
+void qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
+  setT *vertices;
+  vertexT *vertex, **vertexp;
+  boolT upperseen, lowerseen;
+  facetT *neighbor, **neighborp;
+  int numpoints=0;
+
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  qh_vertexneighbors();
+  FOREACHvertex_(vertices) {
+    upperseen= lowerseen= False;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->upperdelaunay)
+        upperseen= True;
+      else
+        lowerseen= True;
+    }
+    if (upperseen && lowerseen) {
+      vertex->seen= True;
+      numpoints++;
+    }else
+      vertex->seen= False;
+  }
+  fprintf (fp, "%d\n", numpoints);
+  FOREACHvertex_(vertices) {
+    if (vertex->seen)
+      fprintf (fp, "%d\n", qh_pointid (vertex->point));
+  }
+  qh_settempfree (&vertices);
+} /* printextremes_d */
+
+/*---------------------------------
+  
+  qh_printfacet( fp, facet )
+    prints all fields of a facet to fp
+
+  notes:
+    ridges printed in neighbor order
+*/
+void qh_printfacet(FILE *fp, facetT *facet) {
+
+  qh_printfacetheader (fp, facet);
+  if (facet->ridges)
+    qh_printfacetridges (fp, facet);
+} /* printfacet */
+
+
+/*---------------------------------
+  
+  qh_printfacet2geom( fp, facet, color )
+    print facet as part of a 2-d VECT for Geomview
+  
+    notes:
+      assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
+      mindist is calculated within io.c.  maxoutside is calculated elsewhere
+      so a DISTround error may have occured.
+*/
+void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
+  pointT *point0, *point1;
+  realT mindist, innerplane, outerplane;
+  int k;
+
+  qh_facet2point (facet, &point0, &point1, &mindist);
+  qh_geomplanes (facet, &outerplane, &innerplane);
+  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
+    qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color);
+  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
+                outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
+    for(k= 3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color);
+  }
+  qh_memfree (point1, qh normal_size);
+  qh_memfree (point0, qh normal_size); 
+} /* printfacet2geom */
+
+/*---------------------------------
+  
+  qh_printfacet2geom_points( fp, point1, point2, facet, offset, color )
+    prints a 2-d facet as a VECT with 2 points at some offset.   
+    The points are on the facet's plane.
+*/
+void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
+			       facetT *facet, realT offset, realT color[3]) {
+  pointT *p1= point1, *p2= point2;
+
+  fprintf(fp, "VECT 1 2 1 2 1 # f%d\n", facet->id);
+  if (offset != 0.0) {
+    p1= qh_projectpoint (p1, facet, -offset);
+    p2= qh_projectpoint (p2, facet, -offset);
+  }
+  fprintf(fp, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
+           p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
+  if (offset != 0.0) {
+    qh_memfree (p1, qh normal_size);
+    qh_memfree (p2, qh normal_size);
+  }
+  fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+} /* printfacet2geom_points */
+
+
+/*---------------------------------
+  
+  qh_printfacet2math( fp, facet, notfirst )
+    print 2-d Mathematica output for a facet
+    may be non-simplicial
+
+  notes:
+    use %16.8f since Mathematica 2.2 does not handle exponential format
+*/
+void qh_printfacet2math(FILE *fp, facetT *facet, int notfirst) {
+  pointT *point0, *point1;
+  realT mindist;
+  
+  qh_facet2point (facet, &point0, &point1, &mindist);
+  if (notfirst)
+    fprintf(fp, ",");
+  fprintf(fp, "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n",
+	  point0[0], point0[1], point1[0], point1[1]);
+  qh_memfree (point1, qh normal_size);
+  qh_memfree (point0, qh normal_size);
+} /* printfacet2math */
+
+
+/*---------------------------------
+  
+  qh_printfacet3geom_nonsimplicial( fp, facet, color )
+    print Geomview OFF for a 3-d nonsimplicial facet.
+    if DOintersections, prints ridges to unvisited neighbors (qh visit_id) 
+
+  notes
+    uses facet->visitid for intersections and ridges
+*/
+void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
+  ridgeT *ridge, **ridgep;
+  setT *projectedpoints, *vertices;
+  vertexT *vertex, **vertexp, *vertexA, *vertexB;
+  pointT *projpt, *point, **pointp;
+  facetT *neighbor;
+  realT dist, outerplane, innerplane;
+  int cntvertices, k;
+  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
+
+  qh_geomplanes (facet, &outerplane, &innerplane); 
+  vertices= qh_facet3vertex (facet); /* oriented */
+  cntvertices= qh_setsize(vertices);
+  projectedpoints= qh_settemp(cntvertices);
+  FOREACHvertex_(vertices) {
+    zinc_(Zdistio);
+    qh_distplane(vertex->point, facet, &dist);
+    projpt= qh_projectpoint(vertex->point, facet, dist);
+    qh_setappend (&projectedpoints, projpt);
+  }
+  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
+    qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color);
+  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
+                outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
+    for (k=3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color);
+  }
+  FOREACHpoint_(projectedpoints)
+    qh_memfree (point, qh normal_size);
+  qh_settempfree(&projectedpoints);
+  qh_settempfree(&vertices);
+  if ((qh DOintersections || qh PRINTridges)
+  && (!facet->visible || !qh NEWfacets)) {
+    facet->visitid= qh visit_id;
+    FOREACHridge_(facet->ridges) {
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->visitid != qh visit_id) {
+        if (qh DOintersections)
+          qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
+        if (qh PRINTridges) {
+          vertexA= SETfirstt_(ridge->vertices, vertexT);
+          vertexB= SETsecondt_(ridge->vertices, vertexT);
+          qh_printline3geom (fp, vertexA->point, vertexB->point, green);
+        }
+      }
+    }
+  }
+} /* printfacet3geom_nonsimplicial */
+
+/*---------------------------------
+  
+  qh_printfacet3geom_points( fp, points, facet, offset )
+    prints a 3-d facet as OFF Geomview object. 
+    offset is relative to the facet's hyperplane
+    Facet is determined as a list of points
+*/
+void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
+  int k, n= qh_setsize(points), i;
+  pointT *point, **pointp;
+  setT *printpoints;
+
+  fprintf(fp, "{ OFF %d 1 1 # f%d\n", n, facet->id);
+  if (offset != 0.0) {
+    printpoints= qh_settemp (n);
+    FOREACHpoint_(points) 
+      qh_setappend (&printpoints, qh_projectpoint(point, facet, -offset));
+  }else
+    printpoints= points;
+  FOREACHpoint_(printpoints) {
+    for (k=0; k < qh hull_dim; k++) {
+      if (k == qh DROPdim)
+        fprintf(fp, "0 ");
+      else
+        fprintf(fp, "%8.4g ", point[k]);
+    }
+    if (printpoints != points)
+      qh_memfree (point, qh normal_size);
+    fprintf (fp, "\n");
+  }
+  if (printpoints != points)
+    qh_settempfree (&printpoints);
+  fprintf(fp, "%d ", n);
+  for(i= 0; i < n; i++)
+    fprintf(fp, "%d ", i);
+  fprintf(fp, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
+} /* printfacet3geom_points */
+
+
+/*---------------------------------
+  
+  qh_printfacet3geom_simplicial(  )
+    print Geomview OFF for a 3-d simplicial facet.
+
+  notes:
+    may flip color
+    uses facet->visitid for intersections and ridges
+
+    assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
+    innerplane may be off by qh DISTround.  Maxoutside is calculated elsewhere
+    so a DISTround error may have occured.
+*/
+void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
+  setT *points, *vertices;
+  vertexT *vertex, **vertexp, *vertexA, *vertexB;
+  facetT *neighbor, **neighborp;
+  realT outerplane, innerplane;
+  realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
+  int k;
+
+  qh_geomplanes (facet, &outerplane, &innerplane); 
+  vertices= qh_facet3vertex (facet);
+  points= qh_settemp (qh TEMPsize);
+  FOREACHvertex_(vertices)
+    qh_setappend(&points, vertex->point);
+  if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
+    qh_printfacet3geom_points(fp, points, facet, outerplane, color);
+  if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
+              outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
+    for (k= 3; k--; )
+      color[k]= 1.0 - color[k];
+    qh_printfacet3geom_points(fp, points, facet, innerplane, color);
+  }
+  qh_settempfree(&points);
+  qh_settempfree(&vertices);
+  if ((qh DOintersections || qh PRINTridges)
+  && (!facet->visible || !qh NEWfacets)) {
+    facet->visitid= qh visit_id;
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh visit_id) {
+	vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
+	                  SETindex_(facet->neighbors, neighbor), 0);
+        if (qh DOintersections)
+	   qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black); 
+        if (qh PRINTridges) {
+          vertexA= SETfirstt_(vertices, vertexT);
+          vertexB= SETsecondt_(vertices, vertexT);
+          qh_printline3geom (fp, vertexA->point, vertexB->point, green);
+        }
+	qh_setfree(&vertices);
+      }
+    }
+  }
+} /* printfacet3geom_simplicial */
+
+/*---------------------------------
+  
+  qh_printfacet3math( fp, facet, notfirst )
+    print 3-d Mathematica output for a facet
+
+  notes:
+    may be non-simplicial
+    use %16.8f since Mathematica 2.2 does not handle exponential format
+*/
+void qh_printfacet3math (FILE *fp, facetT *facet, int notfirst) {
+  vertexT *vertex, **vertexp;
+  setT *points, *vertices;
+  pointT *point, **pointp;
+  boolT firstpoint= True;
+  realT dist;
+  
+  if (notfirst)
+    fprintf(fp, ",\n");
+  vertices= qh_facet3vertex (facet);
+  points= qh_settemp (qh_setsize (vertices));
+  FOREACHvertex_(vertices) {
+    zinc_(Zdistio);
+    qh_distplane(vertex->point, facet, &dist);
+    point= qh_projectpoint(vertex->point, facet, dist);
+    qh_setappend (&points, point);
+  }
+  fprintf(fp, "Polygon[{");
+  FOREACHpoint_(points) {
+    if (firstpoint)
+      firstpoint= False;
+    else
+      fprintf(fp, ",\n");
+    fprintf(fp, "{%16.8f, %16.8f, %16.8f}", point[0], point[1], point[2]);
+  }
+  FOREACHpoint_(points)
+    qh_memfree (point, qh normal_size);
+  qh_settempfree(&points);
+  qh_settempfree(&vertices);
+  fprintf(fp, "}]");
+} /* printfacet3math */
+
+
+/*---------------------------------
+  
+  qh_printfacet3vertex( fp, facet, format )
+    print vertices in a 3-d facet as point ids
+
+  notes:
+    prints number of vertices first if format == qh_PRINToff
+    the facet may be non-simplicial
+*/
+void qh_printfacet3vertex(FILE *fp, facetT *facet, int format) {
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+
+  vertices= qh_facet3vertex (facet);
+  if (format == qh_PRINToff)
+    fprintf (fp, "%d ", qh_setsize (vertices));
+  FOREACHvertex_(vertices) 
+    fprintf (fp, "%d ", qh_pointid(vertex->point));
+  fprintf (fp, "\n");
+  qh_settempfree(&vertices);
+} /* printfacet3vertex */
+
+
+/*---------------------------------
+  
+  qh_printfacet4geom_nonsimplicial(  )
+    print Geomview 4OFF file for a 4d nonsimplicial facet
+    prints all ridges to unvisited neighbors (qh.visit_id)
+    if qh.DROPdim
+      prints in OFF format
+  
+  notes:
+    must agree with printend4geom()
+*/
+void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
+  facetT *neighbor;
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, **vertexp;
+  pointT *point;
+  int k;
+  realT dist;
+  
+  facet->visitid= qh visit_id;
+  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
+    return;
+  FOREACHridge_(facet->ridges) {
+    neighbor= otherfacet_(ridge, facet);
+    if (neighbor->visitid == qh visit_id) 
+      continue;
+    if (qh PRINTtransparent && !neighbor->good)
+      continue;  
+    if (qh DOintersections)
+      qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
+    else {
+      if (qh DROPdim >= 0) 
+	fprintf(fp, "OFF 3 1 1 # f%d\n", facet->id);
+      else {
+	qh printoutvar++;
+	fprintf (fp, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
+      }
+      FOREACHvertex_(ridge->vertices) {
+	zinc_(Zdistio);
+	qh_distplane(vertex->point,facet, &dist);
+	point=qh_projectpoint(vertex->point,facet, dist);
+	for(k= 0; k < qh hull_dim; k++) {
+	  if (k != qh DROPdim)
+  	    fprintf(fp, "%8.4g ", point[k]);
+  	}
+	fprintf (fp, "\n");
+	qh_memfree (point, qh normal_size);
+      }
+      if (qh DROPdim >= 0)
+        fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
+    }
+  }
+} /* printfacet4geom_nonsimplicial */
+
+
+/*---------------------------------
+  
+  qh_printfacet4geom_simplicial( fp, facet, color )
+    print Geomview 4OFF file for a 4d simplicial facet
+    prints triangles for unvisited neighbors (qh.visit_id)
+
+  notes:
+    must agree with printend4geom()
+*/
+void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
+  setT *vertices;
+  facetT *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  int k;
+  
+  facet->visitid= qh visit_id;
+  if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
+    return;
+  FOREACHneighbor_(facet) {
+    if (neighbor->visitid == qh visit_id)
+      continue;
+    if (qh PRINTtransparent && !neighbor->good)
+      continue;  
+    vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
+	                  SETindex_(facet->neighbors, neighbor), 0);
+    if (qh DOintersections)
+      qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
+    else {
+      if (qh DROPdim >= 0) 
+	fprintf(fp, "OFF 3 1 1 # ridge between f%d f%d\n",
+		facet->id, neighbor->id);
+      else {
+	qh printoutvar++;
+	fprintf (fp, "# ridge between f%d f%d\n", facet->id, neighbor->id);
+      }
+      FOREACHvertex_(vertices) {
+	for(k= 0; k < qh hull_dim; k++) {
+	  if (k != qh DROPdim)
+  	    fprintf(fp, "%8.4g ", vertex->point[k]);
+  	}
+	fprintf (fp, "\n");
+      }
+      if (qh DROPdim >= 0) 
+        fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
+    }
+    qh_setfree(&vertices);
+  }
+} /* printfacet4geom_simplicial */
+
+
+/*---------------------------------
+  
+  qh_printfacetNvertex_nonsimplicial( fp, facet, id, format )
+    print vertices for an N-d non-simplicial facet
+    triangulates each ridge to the id
+*/
+void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format) {
+  vertexT *vertex, **vertexp;
+  ridgeT *ridge, **ridgep;
+
+  if (facet->visible && qh NEWfacets)
+    return;
+  FOREACHridge_(facet->ridges) {
+    if (format == qh_PRINTtriangles)
+      fprintf(fp, "%d ", qh hull_dim);
+    fprintf(fp, "%d ", id);
+    if ((ridge->top == facet) ^ qh_ORIENTclock) {
+      FOREACHvertex_(ridge->vertices)
+        fprintf(fp, "%d ", qh_pointid(vertex->point));
+    }else {
+      FOREACHvertexreverse12_(ridge->vertices)
+        fprintf(fp, "%d ", qh_pointid(vertex->point));
+    }
+    fprintf(fp, "\n");
+  }
+} /* printfacetNvertex_nonsimplicial */
+
+
+/*---------------------------------
+  
+  qh_printfacetNvertex_simplicial( fp, facet, format )
+    print vertices for an N-d simplicial facet
+    prints vertices for non-simplicial facets
+      2-d facets (orientation preserved by qh_mergefacet2d)
+      PRINToff ('o') for 4-d and higher
+*/
+void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format) {
+  vertexT *vertex, **vertexp;
+
+  if (format == qh_PRINToff || format == qh_PRINTtriangles)
+    fprintf (fp, "%d ", qh_setsize (facet->vertices));
+  if ((facet->toporient ^ qh_ORIENTclock) 
+  || (qh hull_dim > 2 && !facet->simplicial)) {
+    FOREACHvertex_(facet->vertices)
+      fprintf(fp, "%d ", qh_pointid(vertex->point));
+  }else {
+    FOREACHvertexreverse12_(facet->vertices)
+      fprintf(fp, "%d ", qh_pointid(vertex->point));
+  }
+  fprintf(fp, "\n");
+} /* printfacetNvertex_simplicial */
+
+
+/*---------------------------------
+  
+  qh_printfacetheader( fp, facet )
+    prints header fields of a facet to fp
+    
+  notes:
+    for 'f' output and debugging
+*/
+void qh_printfacetheader(FILE *fp, facetT *facet) {
+  pointT *point, **pointp, *furthest;
+  facetT *neighbor, **neighborp;
+  realT dist;
+
+  if (facet == qh_MERGEridge) {
+    fprintf (fp, " MERGEridge\n");
+    return;
+  }else if (facet == qh_DUPLICATEridge) {
+    fprintf (fp, " DUPLICATEridge\n");
+    return;
+  }else if (!facet) {
+    fprintf (fp, " NULLfacet\n");
+    return;
+  }
+  qh old_randomdist= qh RANDOMdist;
+  qh RANDOMdist= False;
+  fprintf(fp, "- f%d\n", facet->id);
+  fprintf(fp, "    - flags:");
+  if (facet->toporient) 
+    fprintf(fp, " top");
+  else
+    fprintf(fp, " bottom");
+  if (facet->simplicial)
+    fprintf(fp, " simplicial");
+  if (facet->tricoplanar)
+    fprintf(fp, " tricoplanar");
+  if (facet->upperdelaunay)
+    fprintf(fp, " upperDelaunay");
+  if (facet->visible)
+    fprintf(fp, " visible");
+  if (facet->newfacet)
+    fprintf(fp, " new");
+  if (facet->tested)
+    fprintf(fp, " tested");
+  if (!facet->good)
+    fprintf(fp, " notG");
+  if (facet->seen)
+    fprintf(fp, " seen");
+  if (facet->coplanar)
+    fprintf(fp, " coplanar");
+  if (facet->mergehorizon)
+    fprintf(fp, " mergehorizon");
+  if (facet->keepcentrum)
+    fprintf(fp, " keepcentrum");
+  if (facet->dupridge)
+    fprintf(fp, " dupridge");
+  if (facet->mergeridge && !facet->mergeridge2)
+    fprintf(fp, " mergeridge1");
+  if (facet->mergeridge2)
+    fprintf(fp, " mergeridge2");
+  if (facet->newmerge)
+    fprintf(fp, " newmerge");
+  if (facet->flipped) 
+    fprintf(fp, " flipped");
+  if (facet->notfurthest) 
+    fprintf(fp, " notfurthest");
+  if (facet->degenerate)
+    fprintf(fp, " degenerate");
+  if (facet->redundant)
+    fprintf(fp, " redundant");
+  fprintf(fp, "\n");
+  if (facet->isarea)
+    fprintf(fp, "    - area: %2.2g\n", facet->f.area);
+  else if (qh NEWfacets && facet->visible && facet->f.replace)
+    fprintf(fp, "    - replacement: f%d\n", facet->f.replace->id);
+  else if (facet->newfacet) {
+    if (facet->f.samecycle && facet->f.samecycle != facet)
+      fprintf(fp, "    - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
+  }else if (facet->tricoplanar /* !isarea */) {
+    if (facet->f.triowner)
+      fprintf(fp, "    - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
+  }else if (facet->f.newcycle)
+    fprintf(fp, "    - was horizon to f%d\n", facet->f.newcycle->id);
+  if (facet->nummerge)
+    fprintf(fp, "    - merges: %d\n", facet->nummerge);
+  qh_printpointid(fp, "    - normal: ", qh hull_dim, facet->normal, -1);
+  fprintf(fp, "    - offset: %10.7g\n", facet->offset);
+  if (qh CENTERtype == qh_ASvoronoi || facet->center)
+    qh_printcenter (fp, qh_PRINTfacets, "    - center: ", facet);
+#if qh_MAXoutside
+  if (facet->maxoutside > qh DISTround)
+    fprintf(fp, "    - maxoutside: %10.7g\n", facet->maxoutside);
+#endif
+  if (!SETempty_(facet->outsideset)) {
+    furthest= (pointT*)qh_setlast(facet->outsideset);
+    if (qh_setsize (facet->outsideset) < 6) {
+      fprintf(fp, "    - outside set (furthest p%d):\n", qh_pointid(furthest));
+      FOREACHpoint_(facet->outsideset)
+	qh_printpoint(fp, "     ", point);
+    }else if (qh_setsize (facet->outsideset) < 21) {
+      qh_printpoints(fp, "    - outside set:", facet->outsideset);
+    }else {
+      fprintf(fp, "    - outside set:  %d points.", qh_setsize(facet->outsideset));
+      qh_printpoint(fp, "  Furthest", furthest);
+    }
+#if !qh_COMPUTEfurthest
+    fprintf(fp, "    - furthest distance= %2.2g\n", facet->furthestdist);
+#endif
+  }
+  if (!SETempty_(facet->coplanarset)) {
+    furthest= (pointT*)qh_setlast(facet->coplanarset);
+    if (qh_setsize (facet->coplanarset) < 6) {
+      fprintf(fp, "    - coplanar set (furthest p%d):\n", qh_pointid(furthest));
+      FOREACHpoint_(facet->coplanarset)
+	qh_printpoint(fp, "     ", point);
+    }else if (qh_setsize (facet->coplanarset) < 21) {
+      qh_printpoints(fp, "    - coplanar set:", facet->coplanarset);
+    }else {
+      fprintf(fp, "    - coplanar set:  %d points.", qh_setsize(facet->coplanarset));
+      qh_printpoint(fp, "  Furthest", furthest);
+    }
+    zinc_(Zdistio);
+    qh_distplane (furthest, facet, &dist);
+    fprintf(fp, "      furthest distance= %2.2g\n", dist);
+  }
+  qh_printvertices (fp, "    - vertices:", facet->vertices);
+  fprintf(fp, "    - neighboring facets: ");
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge)
+      fprintf(fp, " MERGE");
+    else if (neighbor == qh_DUPLICATEridge)
+      fprintf(fp, " DUP");
+    else
+      fprintf(fp, " f%d", neighbor->id);
+  }
+  fprintf(fp, "\n");
+  qh RANDOMdist= qh old_randomdist;
+} /* printfacetheader */
+
+
+/*---------------------------------
+  
+  qh_printfacetridges( fp, facet )
+    prints ridges of a facet to fp
+
+  notes:
+    ridges printed in neighbor order
+    assumes the ridges exist
+    for 'f' output
+*/
+void qh_printfacetridges(FILE *fp, facetT *facet) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int numridges= 0;
+
+
+  if (facet->visible && qh NEWfacets) {
+    fprintf(fp, "    - ridges (ids may be garbage):");
+    FOREACHridge_(facet->ridges)
+      fprintf(fp, " r%d", ridge->id);
+    fprintf(fp, "\n");
+  }else {
+    fprintf(fp, "    - ridges:\n");
+    FOREACHridge_(facet->ridges)
+      ridge->seen= False;
+    if (qh hull_dim == 3) {
+      ridge= SETfirstt_(facet->ridges, ridgeT);
+      while (ridge && !ridge->seen) {
+	ridge->seen= True;
+	qh_printridge(fp, ridge);
+	numridges++;
+	ridge= qh_nextridge3d (ridge, facet, NULL);
+	}
+    }else {
+      FOREACHneighbor_(facet) {
+	FOREACHridge_(facet->ridges) {
+	  if (otherfacet_(ridge,facet) == neighbor) {
+	    ridge->seen= True;
+	    qh_printridge(fp, ridge);
+	    numridges++;
+	  }
+	}
+      }
+    }
+    if (numridges != qh_setsize (facet->ridges)) {
+      fprintf (fp, "     - all ridges:");
+      FOREACHridge_(facet->ridges) 
+	fprintf (fp, " r%d", ridge->id);
+        fprintf (fp, "\n");
+    }
+    FOREACHridge_(facet->ridges) {
+      if (!ridge->seen) 
+	qh_printridge(fp, ridge);
+    }
+  }
+} /* printfacetridges */
+
+/*---------------------------------
+  
+  qh_printfacets( fp, format, facetlist, facets, printall )
+    prints facetlist and/or facet set in output format
+  
+  notes:
+    also used for specialized formats ('FO' and summary)
+    turns off 'Rn' option since want actual numbers
+*/
+void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
+  facetT *facet, **facetp;
+  setT *vertices;
+  coordT *center;
+  realT outerplane, innerplane;
+
+  qh old_randomdist= qh RANDOMdist;
+  qh RANDOMdist= False;
+  if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
+    fprintf (qh ferr, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
+  if (format == qh_PRINTnone)
+    ; /* print nothing */
+  else if (format == qh_PRINTaverage) {
+    vertices= qh_facetvertices (facetlist, facets, printall);
+    center= qh_getcenter (vertices);
+    fprintf (fp, "%d 1\n", qh hull_dim);
+    qh_printpointid (fp, NULL, qh hull_dim, center, -1);
+    qh_memfree (center, qh normal_size);
+    qh_settempfree (&vertices);
+  }else if (format == qh_PRINTextremes) {
+    if (qh DELAUNAY)
+      qh_printextremes_d (fp, facetlist, facets, printall);
+    else if (qh hull_dim == 2)
+      qh_printextremes_2d (fp, facetlist, facets, printall);
+    else 
+      qh_printextremes (fp, facetlist, facets, printall);
+  }else if (format == qh_PRINToptions)
+    fprintf(fp, "Options selected for Qhull %s:\n%s\n", qh_VERSION, qh qhull_options);
+  else if (format == qh_PRINTpoints && !qh VORONOI)
+    qh_printpoints_out (fp, facetlist, facets, printall);
+  else if (format == qh_PRINTqhull)
+    fprintf (fp, "%s | %s\n", qh rbox_command, qh qhull_command);
+  else if (format == qh_PRINTsize) {
+    fprintf (fp, "0\n2 ");
+    fprintf (fp, qh_REAL_1, qh totarea);
+    fprintf (fp, qh_REAL_1, qh totvol);
+    fprintf (fp, "\n");
+  }else if (format == qh_PRINTsummary) {
+    qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
+    vertices= qh_facetvertices (facetlist, facets, printall); 
+    fprintf (fp, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh hull_dim, 
+                qh num_points + qh_setsize (qh other_points),
+                qh num_vertices, qh num_facets - qh num_visible,
+                qh_setsize (vertices), numfacets, numcoplanars, 
+		numfacets - numsimplicial, zzval_(Zdelvertextot), 
+		numtricoplanars);
+    qh_settempfree (&vertices);
+    qh_outerinner (NULL, &outerplane, &innerplane);
+    fprintf (fp, qh_REAL_2n, outerplane, innerplane);
+  }else if (format == qh_PRINTvneighbors)
+    qh_printvneighbors (fp, facetlist, facets, printall);
+  else if (qh VORONOI && format == qh_PRINToff)
+    qh_printvoronoi (fp, format, facetlist, facets, printall);
+  else if (qh VORONOI && format == qh_PRINTgeom) {
+    qh_printbegin (fp, format, facetlist, facets, printall);
+    qh_printvoronoi (fp, format, facetlist, facets, printall);
+    qh_printend (fp, format, facetlist, facets, printall);
+  }else if (qh VORONOI 
+  && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
+    qh_printvdiagram (fp, format, facetlist, facets, printall);
+  else {
+    qh_printbegin (fp, format, facetlist, facets, printall);
+    FORALLfacet_(facetlist)
+      qh_printafacet (fp, format, facet, printall);
+    FOREACHfacet_(facets) 
+      qh_printafacet (fp, format, facet, printall);
+    qh_printend (fp, format, facetlist, facets, printall);
+  }
+  qh RANDOMdist= qh old_randomdist;
+} /* printfacets */
+
+
+/*---------------------------------
+  
+  qh_printhelp_degenerate( fp )
+    prints descriptive message for precision error
+
+  notes:
+    no message if qh_QUICKhelp
+*/
+void qh_printhelp_degenerate(FILE *fp) {
+  
+  if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2) 
+    fprintf(fp, "\n\
+A Qhull error has occurred.  Qhull should have corrected the above\n\
+precision error.  Please send the input and all of the output to\n\
+qhull_bug@geom.umn.edu\n");
+  else if (!qh_QUICKhelp) {
+    fprintf(fp, "\n\
+Precision problems were detected during construction of the convex hull.\n\
+This occurs because convex hull algorithms assume that calculations are\n\
+exact, but floating-point arithmetic has roundoff errors.\n\
+\n\
+To correct for precision problems, do not use 'Q0'.  By default, Qhull\n\
+selects 'C-0' or 'Qx' and merges non-convex facets.  With option 'QJ',\n\
+Qhull joggles the input to prevent precision problems.  See \"Imprecision\n\
+in Qhull\" (qh-impre.htm).\n\
+\n\
+If you use 'Q0', the output may include\n\
+coplanar ridges, concave ridges, and flipped facets.  In 4-d and higher,\n\
+Qhull may produce a ridge with four neighbors or two facets with the same \n\
+vertices.  Qhull reports these events when they occur.  It stops when a\n\
+concave ridge, flipped facet, or duplicate facet occurs.\n");
+#if REALfloat
+    fprintf (fp, "\
+\n\
+Qhull is currently using single precision arithmetic.  The following\n\
+will probably remove the precision problems:\n\
+  - recompile qhull for double precision (#define REALfloat 0 in user.h).\n");
+#endif
+    if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
+      fprintf( fp, "\
+\n\
+When computing the Delaunay triangulation of coordinates > 1.0,\n\
+  - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
+    if (qh DELAUNAY && !qh ATinfinity) 
+      fprintf( fp, "\
+When computing the Delaunay triangulation:\n\
+  - use 'Qz' to add a point at-infinity.  This reduces precision problems.\n");
+ 
+    fprintf(fp, "\
+\n\
+If you need triangular output:\n\
+  - use option 'Qt' to triangulate the output\n\
+  - use option 'QJ' to joggle the input points and remove precision errors\n\
+  - use option 'Ft'.  It triangulates non-simplicial facets with added points.\n\
+\n\
+If you must use 'Q0',\n\
+try one or more of the following options.  They can not guarantee an output.\n\
+  - use 'QbB' to scale the input to a cube.\n\
+  - use 'Po' to produce output and prevent partitioning for flipped facets\n\
+  - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
+  - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
+  - options 'Qf', 'Qbb', and 'QR0' may also help\n",
+               qh DISTround);
+    fprintf(fp, "\
+\n\
+To guarantee simplicial output:\n\
+  - use option 'Qt' to triangulate the output\n\
+  - use option 'QJ' to joggle the input points and remove precision errors\n\
+  - use option 'Ft' to triangulate the output by adding points\n\
+  - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
+");
+  }
+} /* printhelp_degenerate */
+
+
+/*---------------------------------
+  
+  qh_printhelp_singular( fp )
+    prints descriptive message for singular input
+*/
+void qh_printhelp_singular(FILE *fp) {
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+  realT min, max, *coord, dist;
+  int i,k;
+  
+  fprintf(fp, "\n\
+The input to qhull appears to be less than %d dimensional, or a\n\
+computation has overflowed.\n\n\
+Qhull could not construct a clearly convex simplex from points:\n",
+           qh hull_dim);
+  qh_printvertexlist (fp, "", qh facet_list, NULL, qh_ALL);
+  if (!qh_QUICKhelp)
+    fprintf(fp, "\n\
+The center point is coplanar with a facet, or a vertex is coplanar\n\
+with a neighboring facet.  The maximum round off error for\n\
+computing distances is %2.2g.  The center point, facets and distances\n\
+to the center point are as follows:\n\n", qh DISTround);
+  qh_printpointid (fp, "center point", qh hull_dim, qh interior_point, -1);
+  fprintf (fp, "\n");
+  FORALLfacets {
+    fprintf (fp, "facet");
+    FOREACHvertex_(facet->vertices)
+      fprintf (fp, " p%d", qh_pointid(vertex->point));
+    zinc_(Zdistio);
+    qh_distplane(qh interior_point, facet, &dist);
+    fprintf (fp, " distance= %4.2g\n", dist);
+  }
+  if (!qh_QUICKhelp) {
+    if (qh HALFspace) 
+      fprintf (fp, "\n\
+These points are the dual of the given halfspaces.  They indicate that\n\
+the intersection is degenerate.\n");
+    fprintf (fp,"\n\
+These points either have a maximum or minimum x-coordinate, or\n\
+they maximize the determinant for k coordinates.  Trial points\n\
+are first selected from points that maximize a coordinate.\n");
+    if (qh hull_dim >= qh_INITIALmax)
+      fprintf (fp, "\n\
+Because of the high dimension, the min x-coordinate and max-coordinate\n\
+points are used if the determinant is non-zero.  Option 'Qs' will\n\
+do a better, though much slower, job.  Instead of 'Qs', you can change\n\
+the points by randomly rotating the input with 'QR0'.\n");
+  }
+  fprintf (fp, "\nThe min and max coordinates for each dimension are:\n");
+  for (k=0; k < qh hull_dim; k++) {
+    min= REALmax;
+    max= -REALmin;
+    for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
+      maximize_(max, *coord);
+      minimize_(min, *coord);
+    }
+    fprintf (fp, "  %d:  %8.4g  %8.4g  difference= %4.4g\n", k, min, max, max-min);
+  }
+  if (!qh_QUICKhelp) {
+    fprintf (fp, "\n\
+If the input should be full dimensional, you have several options that\n\
+may determine an initial simplex:\n\
+  - use 'QJ'  to joggle the input and make it full dimensional\n\
+  - use 'QbB' to scale the points to the unit cube\n\
+  - use 'QR0' to randomly rotate the input for different maximum points\n\
+  - use 'Qs'  to search all points for the initial simplex\n\
+  - use 'En'  to specify a maximum roundoff error less than %2.2g.\n\
+  - trace execution with 'T3' to see the determinant for each point.\n",
+                     qh DISTround);
+#if REALfloat
+    fprintf (fp, "\
+  - recompile qhull for double precision (#define REALfloat 0 in qhull.h).\n");
+#endif
+    fprintf (fp, "\n\
+If the input is lower dimensional:\n\
+  - use 'QJ' to joggle the input and make it full dimensional\n\
+  - use 'Qbk:0Bk:0' to delete coordinate k from the input.  You should\n\
+    pick the coordinate with the least range.  The hull will have the\n\
+    correct topology.\n\
+  - determine the flat containing the points, rotate the points\n\
+    into a coordinate plane, and delete the other coordinates.\n\
+  - add one or more points to make the input full dimensional.\n\
+");
+    if (qh DELAUNAY && !qh ATinfinity)
+      fprintf (fp, "\n\n\
+This is a Delaunay triangulation and the input is co-circular or co-spherical:\n\
+  - use 'Qz' to add a point \"at infinity\" (i.e., above the paraboloid)\n\
+  - or use 'QJ' to joggle the input and avoid co-circular data\n");
+  }
+} /* printhelp_singular */
+
+/*---------------------------------
+  
+  qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color )
+    print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
+*/
+void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
+		   setT *vertices, realT color[3]) {
+  realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
+  vertexT *vertex, **vertexp;
+  int i, k;
+  boolT nearzero1, nearzero2;
+  
+  costheta= qh_getangle(facet1->normal, facet2->normal);
+  denominator= 1 - costheta * costheta;
+  i= qh_setsize(vertices);
+  if (qh hull_dim == 3)
+    fprintf(fp, "VECT 1 %d 1 %d 1 ", i, i);
+  else if (qh hull_dim == 4 && qh DROPdim >= 0)
+    fprintf(fp, "OFF 3 1 1 ");
+  else
+    qh printoutvar++;
+  fprintf (fp, "# intersect f%d f%d\n", facet1->id, facet2->id);
+  mindenom= 1 / (10.0 * qh MAXabs_coord);
+  FOREACHvertex_(vertices) {
+    zadd_(Zdistio, 2);
+    qh_distplane(vertex->point, facet1, &dist1);
+    qh_distplane(vertex->point, facet2, &dist2);
+    s= qh_divzero (-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
+    t= qh_divzero (-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
+    if (nearzero1 || nearzero2)
+      s= t= 0.0;
+    for(k= qh hull_dim; k--; )
+      p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
+    if (qh PRINTdim <= 3) {
+      qh_projectdim3 (p, p);
+      fprintf(fp, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
+    }else 
+      fprintf(fp, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
+    if (nearzero1+nearzero2)
+      fprintf (fp, "p%d (coplanar facets)\n", qh_pointid (vertex->point));
+    else
+      fprintf (fp, "projected p%d\n", qh_pointid (vertex->point));
+  }
+  if (qh hull_dim == 3)
+    fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]); 
+  else if (qh hull_dim == 4 && qh DROPdim >= 0)  
+    fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
+} /* printhyperplaneintersection */
+
+/*---------------------------------
+  
+  qh_printline3geom( fp, pointA, pointB, color )
+    prints a line as a VECT
+    prints 0's for qh.DROPdim
+  
+  notes:
+    if pointA == pointB, 
+      it's a 1 point VECT
+*/
+void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
+  int k;
+  realT pA[4], pB[4];
+
+  qh_projectdim3(pointA, pA);
+  qh_projectdim3(pointB, pB);
+  if ((fabs(pA[0] - pB[0]) > 1e-3) || 
+      (fabs(pA[1] - pB[1]) > 1e-3) || 
+      (fabs(pA[2] - pB[2]) > 1e-3)) {
+    fprintf (fp, "VECT 1 2 1 2 1\n");
+    for (k= 0; k < 3; k++)
+       fprintf (fp, "%8.4g ", pB[k]);
+    fprintf (fp, " # p%d\n", qh_pointid (pointB));
+  }else
+    fprintf (fp, "VECT 1 1 1 1 1\n");
+  for (k=0; k < 3; k++)
+    fprintf (fp, "%8.4g ", pA[k]);
+  fprintf (fp, " # p%d\n", qh_pointid (pointA));
+  fprintf (fp, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
+}
+
+/*---------------------------------
+  
+  qh_printneighborhood( fp, format, facetA, facetB, printall )
+    print neighborhood of one or two facets
+
+  notes:
+    calls qh_findgood_all() 
+    bumps qh.visit_id
+*/
+void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall) {
+  facetT *neighbor, **neighborp, *facet;
+  setT *facets;
+
+  if (format == qh_PRINTnone)
+    return;
+  qh_findgood_all (qh facet_list);
+  if (facetA == facetB)
+    facetB= NULL;
+  facets= qh_settemp (2*(qh_setsize (facetA->neighbors)+1));
+  qh visit_id++;
+  for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
+    if (facet->visitid != qh visit_id) {
+      facet->visitid= qh visit_id;
+      qh_setappend (&facets, facet);
+    }
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid == qh visit_id)
+        continue;
+      neighbor->visitid= qh visit_id;
+      if (printall || !qh_skipfacet (neighbor))
+        qh_setappend (&facets, neighbor);
+    }
+  }
+  qh_printfacets (fp, format, NULL, facets, printall);
+  qh_settempfree (&facets);
+} /* printneighborhood */
+
+/*---------------------------------
+  
+  qh_printpoint( fp, string, point )
+  qh_printpointid( fp, string, dim, point, id )
+    prints the coordinates of a point
+
+  returns:
+    if string is defined
+      prints 'string p%d' (skips p%d if id=-1)
+
+  notes:
+    nop if point is NULL
+    prints id unless it is undefined (-1)
+*/
+void qh_printpoint(FILE *fp, char *string, pointT *point) {
+  int id= qh_pointid( point);
+
+  qh_printpointid( fp, string, qh hull_dim, point, id);
+} /* printpoint */
+
+void qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id) {
+  int k;
+  realT r; /*bug fix*/
+  
+  if (!point)
+    return;
+  if (string) {
+    fputs (string, fp);
+   if (id != -1)
+      fprintf(fp, " p%d: ", id);
+  }
+  for(k= dim; k--; ) {
+    r= *point++;
+    if (string)
+      fprintf(fp, " %8.4g", r);
+    else
+      fprintf(fp, qh_REAL_1, r);
+  }
+  fprintf(fp, "\n");
+} /* printpointid */
+
+/*---------------------------------
+  
+  qh_printpoint3( fp, point )
+    prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
+*/
+void qh_printpoint3 (FILE *fp, pointT *point) {
+  int k;
+  realT p[4];
+  
+  qh_projectdim3 (point, p);
+  for (k=0; k < 3; k++)
+    fprintf (fp, "%8.4g ", p[k]);
+  fprintf (fp, " # p%d\n", qh_pointid (point));
+} /* printpoint3 */
+
+/*----------------------------------------
+-printpoints- print pointids for a set of points starting at index 
+   see geom.c
+*/
+
+/*---------------------------------
+  
+  qh_printpoints_out( fp, facetlist, facets, printall )
+    prints vertices, coplanar/inside points, for facets by their point coordinates
+    allows qh.CDDoutput
+
+  notes:
+    same format as qhull input
+    if no coplanar/interior points,
+      same order as qh_printextremes
+*/
+void qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall) {
+  int allpoints= qh num_points + qh_setsize (qh other_points);
+  int numpoints=0, point_i, point_n;
+  setT *vertices, *points;
+  facetT *facet, **facetp;
+  pointT *point, **pointp;
+  vertexT *vertex, **vertexp;
+  int id;
+
+  points= qh_settemp (allpoints);
+  qh_setzero (points, 0, allpoints);
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  FOREACHvertex_(vertices) {
+    id= qh_pointid (vertex->point);
+    if (id >= 0)
+      SETelem_(points, id)= vertex->point;
+  }
+  if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
+    FORALLfacet_(facetlist) {
+      if (!printall && qh_skipfacet(facet))
+        continue;
+      FOREACHpoint_(facet->coplanarset) {
+        id= qh_pointid (point);
+        if (id >= 0)
+          SETelem_(points, id)= point;
+      }
+    }
+    FOREACHfacet_(facets) {
+      if (!printall && qh_skipfacet(facet))
+        continue;
+      FOREACHpoint_(facet->coplanarset) {
+        id= qh_pointid (point);
+        if (id >= 0)
+          SETelem_(points, id)= point;
+      }
+    }
+  }
+  qh_settempfree (&vertices);
+  FOREACHpoint_i_(points) {
+    if (point)
+      numpoints++;
+  }
+  if (qh CDDoutput)
+    fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
+             qh qhull_command, numpoints, qh hull_dim + 1);
+  else
+    fprintf (fp, "%d\n%d\n", qh hull_dim, numpoints);
+  FOREACHpoint_i_(points) {
+    if (point) {
+      if (qh CDDoutput)
+	fprintf (fp, "1 ");
+      qh_printpoint (fp, NULL, point);
+    }
+  }
+  if (qh CDDoutput)
+    fprintf (fp, "end\n");
+  qh_settempfree (&points);
+} /* printpoints_out */
+  
+
+/*---------------------------------
+  
+  qh_printpointvect( fp, point, normal, center, radius, color )
+    prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
+*/
+void qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
+  realT diff[4], pointA[4];
+  int k;
+  
+  for (k= qh hull_dim; k--; ) {
+    if (center)
+      diff[k]= point[k]-center[k];
+    else if (normal) 
+      diff[k]= normal[k];
+    else
+      diff[k]= 0;
+  }
+  if (center)
+    qh_normalize2 (diff, qh hull_dim, True, NULL, NULL);
+  for (k= qh hull_dim; k--; ) 
+    pointA[k]= point[k]+diff[k] * radius;
+  qh_printline3geom (fp, point, pointA, color);
+} /* printpointvect */  
+
+/*---------------------------------
+  
+  qh_printpointvect2( fp, point, normal, center, radius )
+    prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
+*/
+void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
+  realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
+
+  qh_printpointvect (fp, point, normal, center, radius, red);
+  qh_printpointvect (fp, point, normal, center, -radius, yellow);
+} /* printpointvect2 */
+
+/*---------------------------------
+  
+  qh_printridge( fp, ridge )
+    prints the information in a ridge
+
+  notes:
+    for qh_printfacetridges()
+*/
+void qh_printridge(FILE *fp, ridgeT *ridge) {
+  
+  fprintf(fp, "     - r%d", ridge->id);
+  if (ridge->tested)
+    fprintf (fp, " tested");
+  if (ridge->nonconvex)
+    fprintf (fp, " nonconvex");
+  fprintf (fp, "\n");
+  qh_printvertices (fp, "           vertices:", ridge->vertices);
+  if (ridge->top && ridge->bottom)
+    fprintf(fp, "           between f%d and f%d\n",
+	    ridge->top->id, ridge->bottom->id);
+} /* printridge */
+
+/*---------------------------------
+  
+  qh_printspheres( fp, vertices, radius )
+    prints 3-d vertices as OFF spheres
+
+  notes:
+    inflated octahedron from Stuart Levy earth/mksphere2
+*/
+void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
+  vertexT *vertex, **vertexp;
+
+  qh printoutnum++;
+  fprintf (fp, "{appearance {-edge -normal normscale 0} {\n\
+INST geom {define vsphere OFF\n\
+18 32 48\n\
+\n\
+0 0 1\n\
+1 0 0\n\
+0 1 0\n\
+-1 0 0\n\
+0 -1 0\n\
+0 0 -1\n\
+0.707107 0 0.707107\n\
+0 -0.707107 0.707107\n\
+0.707107 -0.707107 0\n\
+-0.707107 0 0.707107\n\
+-0.707107 -0.707107 0\n\
+0 0.707107 0.707107\n\
+-0.707107 0.707107 0\n\
+0.707107 0.707107 0\n\
+0.707107 0 -0.707107\n\
+0 0.707107 -0.707107\n\
+-0.707107 0 -0.707107\n\
+0 -0.707107 -0.707107\n\
+\n\
+3 0 6 11\n\
+3 0 7 6	\n\
+3 0 9 7	\n\
+3 0 11 9\n\
+3 1 6 8	\n\
+3 1 8 14\n\
+3 1 13 6\n\
+3 1 14 13\n\
+3 2 11 13\n\
+3 2 12 11\n\
+3 2 13 15\n\
+3 2 15 12\n\
+3 3 9 12\n\
+3 3 10 9\n\
+3 3 12 16\n\
+3 3 16 10\n\
+3 4 7 10\n\
+3 4 8 7\n\
+3 4 10 17\n\
+3 4 17 8\n\
+3 5 14 17\n\
+3 5 15 14\n\
+3 5 16 15\n\
+3 5 17 16\n\
+3 6 13 11\n\
+3 7 8 6\n\
+3 9 10 7\n\
+3 11 12 9\n\
+3 14 8 17\n\
+3 15 13 14\n\
+3 16 12 15\n\
+3 17 10 16\n} transforms { TLIST\n");
+  FOREACHvertex_(vertices) {
+    fprintf(fp, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
+      radius, vertex->id, radius, radius);
+    qh_printpoint3 (fp, vertex->point);
+    fprintf (fp, "1\n");
+  }
+  fprintf (fp, "}}}\n");
+} /* printspheres */
+
+
+/*----------------------------------------------
+-printsummary-
+                see qhull.c
+*/
+
+/*---------------------------------
+  
+  qh_printvdiagram( fp, format, facetlist, facets, printall )
+    print voronoi diagram
+      # of pairs of input sites
+      #indices site1 site2 vertex1 ...
+    
+    sites indexed by input point id
+      point 0 is the first input point
+    vertices indexed by 'o' and 'p' order
+      vertex 0 is the 'vertex-at-infinity'
+      vertex 1 is the first Voronoi vertex
+
+  see:
+    qh_printvoronoi()
+    qh_eachvoronoi_all()
+
+  notes:
+    if all facets are upperdelaunay, 
+      prints upper hull (furthest-site Voronoi diagram)
+*/
+void qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  setT *vertices;
+  int totcount, numcenters;
+  boolT islower;
+  qh_RIDGE innerouter= qh_RIDGEall;
+  printvridgeT printvridge= NULL;
+
+  if (format == qh_PRINTvertices) {
+    innerouter= qh_RIDGEall;
+    printvridge= qh_printvridge;
+  }else if (format == qh_PRINTinner) {
+    innerouter= qh_RIDGEinner;
+    printvridge= qh_printvnorm;
+  }else if (format == qh_PRINTouter) {
+    innerouter= qh_RIDGEouter;
+    printvridge= qh_printvnorm;
+  }else {
+    fprintf(qh ferr, "qh_printvdiagram: unknown print format %d.\n", format);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
+  totcount= qh_printvdiagram2 (NULL, NULL, vertices, innerouter, False);
+  fprintf (fp, "%d\n", totcount);
+  totcount= qh_printvdiagram2 (fp, printvridge, vertices, innerouter, True /* inorder*/);
+  qh_settempfree (&vertices);
+#if 0  /* for testing qh_eachvoronoi_all */
+  fprintf (fp, "\n");
+  totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
+  fprintf (fp, "%d\n", totcount);
+#endif
+} /* printvdiagram */
+  
+/*---------------------------------
+  
+  qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder )
+    visit all pairs of input sites (vertices) for selected Voronoi vertices
+    vertices may include NULLs
+  
+  innerouter:
+    qh_RIDGEall   print inner ridges (bounded) and outer ridges (unbounded)
+    qh_RIDGEinner print only inner ridges
+    qh_RIDGEouter print only outer ridges
+  
+  inorder:
+    print 3-d Voronoi vertices in order
+  
+  assumes:
+    qh_markvoronoi marked facet->visitid for Voronoi vertices
+    all facet->seen= False
+    all facet->seen2= True
+  
+  returns:
+    total number of Voronoi ridges 
+    if printvridge,
+      calls printvridge( fp, vertex, vertexA, centers) for each ridge
+      [see qh_eachvoronoi()]
+  
+  see:
+    qh_eachvoronoi_all()
+*/
+int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
+  int totcount= 0;
+  int vertex_i, vertex_n;
+  vertexT *vertex;
+
+  FORALLvertices 
+    vertex->seen= False;
+  FOREACHvertex_i_(vertices) {
+    if (vertex) {
+      if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
+	continue;
+      totcount += qh_eachvoronoi (fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
+    }
+  }
+  return totcount;
+} /* printvdiagram2 */
+  
+/*---------------------------------
+  
+  qh_printvertex( fp, vertex )
+    prints the information in a vertex
+*/
+void qh_printvertex(FILE *fp, vertexT *vertex) {
+  pointT *point;
+  int k, count= 0;
+  facetT *neighbor, **neighborp;
+  realT r; /*bug fix*/
+
+  if (!vertex) {
+    fprintf (fp, "  NULLvertex\n");
+    return;
+  }
+  fprintf(fp, "- p%d (v%d):", qh_pointid(vertex->point), vertex->id);
+  point= vertex->point;
+  if (point) {
+    for(k= qh hull_dim; k--; ) {
+      r= *point++;
+      fprintf(fp, " %5.2g", r);
+    }
+  }
+  if (vertex->deleted)
+    fprintf(fp, " deleted");
+  if (vertex->delridge)
+    fprintf (fp, " ridgedeleted");
+  fprintf(fp, "\n");
+  if (vertex->neighbors) {
+    fprintf(fp, "  neighbors:");
+    FOREACHneighbor_(vertex) {
+      if (++count % 100 == 0)
+	fprintf (fp, "\n     ");
+      fprintf(fp, " f%d", neighbor->id);
+    }
+    fprintf(fp, "\n");
+  }
+} /* printvertex */
+
+
+/*---------------------------------
+  
+  qh_printvertexlist( fp, string, facetlist, facets, printall )
+    prints vertices used by a facetlist or facet set
+    tests qh_skipfacet() if !printall
+*/
+void qh_printvertexlist (FILE *fp, char* string, facetT *facetlist, 
+                         setT *facets, boolT printall) {
+  vertexT *vertex, **vertexp;
+  setT *vertices;
+  
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  fputs (string, fp);
+  FOREACHvertex_(vertices)
+    qh_printvertex(fp, vertex);
+  qh_settempfree (&vertices);
+} /* printvertexlist */
+
+
+/*---------------------------------
+  
+  qh_printvertices( fp, string, vertices )
+    prints vertices in a set
+*/
+void qh_printvertices(FILE *fp, char* string, setT *vertices) {
+  vertexT *vertex, **vertexp;
+  
+  fputs (string, fp);
+  FOREACHvertex_(vertices) 
+    fprintf (fp, " p%d (v%d)", qh_pointid(vertex->point), vertex->id);
+  fprintf(fp, "\n");
+} /* printvertices */
+
+/*---------------------------------
+  
+  qh_printvneighbors( fp, facetlist, facets, printall )
+    print vertex neighbors of vertices in facetlist and facets ('FN')
+
+  notes:
+    qh_countfacets clears facet->visitid for non-printed facets
+
+  design:
+    collect facet count and related statistics
+    if necessary, build neighbor sets for each vertex
+    collect vertices in facetlist and facets
+    build a point array for point->vertex and point->coplanar facet
+    for each point
+      list vertex neighbors or coplanar facet
+*/
+void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
+  int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
+  setT *vertices, *vertex_points, *coplanar_points;
+  int numpoints= qh num_points + qh_setsize (qh other_points);
+  vertexT *vertex, **vertexp;
+  int vertex_i, vertex_n;
+  facetT *facet, **facetp, *neighbor, **neighborp;
+  pointT *point, **pointp;
+
+  qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial, 
+      &totneighbors, &numridges, &numcoplanars, &numtricoplanars);  /* sets facet->visitid */
+  fprintf (fp, "%d\n", numpoints);
+  qh_vertexneighbors();
+  vertices= qh_facetvertices (facetlist, facets, printall);
+  vertex_points= qh_settemp (numpoints);
+  coplanar_points= qh_settemp (numpoints);
+  qh_setzero (vertex_points, 0, numpoints);
+  qh_setzero (coplanar_points, 0, numpoints);
+  FOREACHvertex_(vertices)
+    qh_point_add (vertex_points, vertex->point, vertex);
+  FORALLfacet_(facetlist) {
+    FOREACHpoint_(facet->coplanarset)
+      qh_point_add (coplanar_points, point, facet);
+  }
+  FOREACHfacet_(facets) {
+    FOREACHpoint_(facet->coplanarset)
+      qh_point_add (coplanar_points, point, facet);
+  }
+  FOREACHvertex_i_(vertex_points) {
+    if (vertex) { 
+      numneighbors= qh_setsize (vertex->neighbors);
+      fprintf (fp, "%d", numneighbors);
+      if (qh hull_dim == 3)
+        qh_order_vertexneighbors (vertex);
+      else if (qh hull_dim >= 4)
+        qsort (SETaddr_(vertex->neighbors, facetT), numneighbors,
+             sizeof (facetT *), qh_compare_facetvisit);
+      FOREACHneighbor_(vertex) 
+        fprintf (fp, " %d", 
+		 neighbor->visitid ? neighbor->visitid - 1 : - neighbor->id);
+      fprintf (fp, "\n");
+    }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
+      fprintf (fp, "1 %d\n",
+                  facet->visitid ? facet->visitid - 1 : - facet->id);
+    else
+      fprintf (fp, "0\n");
+  }
+  qh_settempfree (&coplanar_points);
+  qh_settempfree (&vertex_points);
+  qh_settempfree (&vertices);
+} /* printvneighbors */
+
+/*---------------------------------
+  
+  qh_printvoronoi( fp, format, facetlist, facets, printall )
+    print voronoi diagram in 'o' or 'G' format
+    for 'o' format
+      prints voronoi centers for each facet and for infinity
+      for each vertex, lists ids of printed facets or infinity
+      assumes facetlist and facets are disjoint
+    for 'G' format
+      prints an OFF object
+      adds a 0 coordinate to center
+      prints infinity but does not list in vertices
+
+  see:
+    qh_printvdiagram()
+
+  notes:
+    if 'o', 
+      prints a line for each point except "at-infinity"
+    if all facets are upperdelaunay, 
+      reverses lower and upper hull
+*/
+void qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
+  int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
+  facetT *facet, **facetp, *neighbor, **neighborp;
+  setT *vertices;
+  vertexT *vertex;
+  boolT islower;
+  unsigned int numfacets= (unsigned int) qh num_facets;
+
+  vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
+  FOREACHvertex_i_(vertices) {
+    if (vertex) {
+      numvertices++;
+      numneighbors = numinf = 0;
+      FOREACHneighbor_(vertex) {
+        if (neighbor->visitid == 0)
+	  numinf= 1;
+        else if (neighbor->visitid < numfacets)
+          numneighbors++;
+      }
+      if (numinf && !numneighbors) {
+	SETelem_(vertices, vertex_i)= NULL;
+	numvertices--;
+      }
+    }
+  }
+  if (format == qh_PRINTgeom) 
+    fprintf (fp, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n", 
+                numcenters, numvertices);
+  else
+    fprintf (fp, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
+  if (format == qh_PRINTgeom) {
+    for (k= qh hull_dim-1; k--; )
+      fprintf (fp, qh_REAL_1, 0.0);
+    fprintf (fp, " 0 # infinity not used\n");
+  }else {
+    for (k= qh hull_dim-1; k--; )
+      fprintf (fp, qh_REAL_1, qh_INFINITE);
+    fprintf (fp, "\n");
+  }
+  FORALLfacet_(facetlist) {
+    if (facet->visitid && facet->visitid < numfacets) {
+      if (format == qh_PRINTgeom)
+        fprintf (fp, "# %d f%d\n", vid++, facet->id);
+      qh_printcenter (fp, format, NULL, facet);
+    }
+  }
+  FOREACHfacet_(facets) {
+    if (facet->visitid && facet->visitid < numfacets) {
+      if (format == qh_PRINTgeom)
+        fprintf (fp, "# %d f%d\n", vid++, facet->id);
+      qh_printcenter (fp, format, NULL, facet);
+    }
+  }
+  FOREACHvertex_i_(vertices) {
+    numneighbors= 0;
+    numinf=0;
+    if (vertex) {
+      if (qh hull_dim == 3)
+        qh_order_vertexneighbors(vertex);
+      else if (qh hull_dim >= 4)
+        qsort (SETaddr_(vertex->neighbors, vertexT), 
+	     qh_setsize (vertex->neighbors),
+	     sizeof (facetT *), qh_compare_facetvisit);
+      FOREACHneighbor_(vertex) {
+        if (neighbor->visitid == 0)
+	  numinf= 1;
+	else if (neighbor->visitid < numfacets)
+          numneighbors++;
+      }
+    }
+    if (format == qh_PRINTgeom) {
+      if (vertex) {
+	fprintf (fp, "%d", numneighbors);
+	if (vertex) {
+	  FOREACHneighbor_(vertex) {
+	    if (neighbor->visitid && neighbor->visitid < numfacets)
+	      fprintf (fp, " %d", neighbor->visitid);
+	  }
+	}
+	fprintf (fp, " # p%d (v%d)\n", vertex_i, vertex->id);
+      }else
+	fprintf (fp, " # p%d is coplanar or isolated\n", vertex_i);
+    }else {
+      if (numinf)
+	numneighbors++;
+      fprintf (fp, "%d", numneighbors);
+      if (vertex) {
+        FOREACHneighbor_(vertex) {
+  	  if (neighbor->visitid == 0) {
+  	    if (numinf) {
+  	      numinf= 0;
+	      fprintf (fp, " %d", neighbor->visitid);
+	    }
+	  }else if (neighbor->visitid < numfacets)
+	    fprintf (fp, " %d", neighbor->visitid);
+	}
+      }
+      fprintf (fp, "\n");
+    }
+  }
+  if (format == qh_PRINTgeom)
+    fprintf (fp, "}\n");
+  qh_settempfree (&vertices);
+} /* printvoronoi */
+  
+/*---------------------------------
+  
+  qh_printvnorm( fp, vertex, vertexA, centers, unbounded )
+    print one separating plane of the Voronoi diagram for a pair of input sites
+    unbounded==True if centers includes vertex-at-infinity
+  
+  assumes:
+    qh_ASvoronoi and qh_vertexneighbors() already set
+    
+  see:
+    qh_printvdiagram()
+    qh_eachvoronoi()
+*/
+void qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
+  pointT *normal;
+  realT offset;
+  int k;
+  
+  normal= qh_detvnorm (vertex, vertexA, centers, &offset);
+  fprintf (fp, "%d %d %d ", 
+      2+qh hull_dim, qh_pointid (vertex->point), qh_pointid (vertexA->point));
+  for (k= 0; k< qh hull_dim-1; k++)
+    fprintf (fp, qh_REAL_1, normal[k]);
+  fprintf (fp, qh_REAL_1, offset);
+  fprintf (fp, "\n");
+} /* printvnorm */
+
+/*---------------------------------
+  
+  qh_printvridge( fp, vertex, vertexA, centers, unbounded )
+    print one ridge of the Voronoi diagram for a pair of input sites
+    unbounded==True if centers includes vertex-at-infinity
+  
+  see:
+    qh_printvdiagram()
+  
+  notes:
+    the user may use a different function
+*/
+void qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
+  facetT *facet, **facetp;
+
+  fprintf (fp, "%d %d %d", qh_setsize (centers)+2, 
+       qh_pointid (vertex->point), qh_pointid (vertexA->point));
+  FOREACHfacet_(centers) 
+    fprintf (fp, " %d", facet->visitid);
+  fprintf (fp, "\n");
+} /* printvridge */
+
+/*---------------------------------
+  
+  qh_projectdim3( source, destination )
+    project 2-d 3-d or 4-d point to a 3-d point
+    uses qh.DROPdim and qh.hull_dim
+    source and destination may be the same
+    
+  notes:
+    allocate 4 elements to destination just in case
+*/
+void qh_projectdim3 (pointT *source, pointT *destination) {
+  int i,k;
+
+  for (k= 0, i=0; k < qh hull_dim; k++) {
+    if (qh hull_dim == 4) {
+      if (k != qh DROPdim)
+        destination[i++]= source[k];
+    }else if (k == qh DROPdim)
+      destination[i++]= 0;
+    else
+      destination[i++]= source[k];
+  }
+  while (i < 3)
+    destination[i++]= 0.0;
+} /* projectdim3 */
+
+/*---------------------------------
+  
+  qh_readfeasible( dim, remainder )
+    read feasible point from remainder string and qh.fin
+
+  returns:
+    number of lines read from qh.fin
+    sets qh.FEASIBLEpoint with malloc'd coordinates
+
+  notes:
+    checks for qh.HALFspace
+    assumes dim > 1
+
+  see:
+    qh_setfeasible
+*/
+int qh_readfeasible (int dim, char *remainder) {
+  boolT isfirst= True;
+  int linecount= 0, tokcount= 0;
+  char *s, *t, firstline[qh_MAXfirst+1];
+  coordT *coords, value;
+
+  if (!qh HALFspace) {
+    fprintf  (qh ferr, "qhull input error: feasible point (dim 1 coords) is only valid for halfspace intersection\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }  
+  if (qh feasible_string)
+    fprintf  (qh ferr, "qhull input warning: feasible point (dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
+  if (!(qh feasible_point= (coordT*)malloc (dim* sizeof(coordT)))) {
+    fprintf(qh ferr, "qhull error: insufficient memory for feasible point\n");
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  coords= qh feasible_point;
+  while ((s= (isfirst ?  remainder : fgets(firstline, qh_MAXfirst, qh fin)))) {
+    if (isfirst)
+      isfirst= False;
+    else
+      linecount++;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      value= qh_strtod (s, &t);
+      if (s == t)
+        break;
+      s= t;
+      *(coords++)= value;
+      if (++tokcount == dim) {
+        while (isspace (*s))
+          s++;
+        qh_strtod (s, &t);
+        if (s != t) {
+          fprintf (qh ferr, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
+               s);
+          qh_errexit (qh_ERRinput, NULL, NULL);
+        }
+        return linecount;
+      }
+    }
+  }
+  fprintf (qh ferr, "qhull input error: only %d coordinates.  Could not read %d-d feasible point.\n",
+           tokcount, dim);
+  qh_errexit (qh_ERRinput, NULL, NULL);
+  return 0;
+} /* readfeasible */
+
+/*---------------------------------
+  
+  qh_readpoints( numpoints, dimension, ismalloc )
+    read points from qh.fin into qh.first_point, qh.num_points
+    qh.fin is lines of coordinates, one per vertex, first line number of points
+    if 'rbox D4',
+      gives message
+    if qh.ATinfinity,
+      adds point-at-infinity for Delaunay triangulations
+
+  returns:
+    number of points, array of point coordinates, dimension, ismalloc True
+    if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
+        and clears qh.PROJECTdelaunay
+    if qh.HALFspace, reads optional feasible point, reads halfspaces,
+        converts to dual.
+
+  for feasible point in "cdd format" in 3-d:
+    3 1
+    coordinates
+    comments
+    begin
+    n 4 real/integer
+    ...
+    end
+
+  notes:
+    dimension will change in qh_initqhull_globals if qh.PROJECTinput
+    uses malloc() since qh_mem not initialized
+    FIXUP: this routine needs rewriting
+*/
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
+  coordT *points, *coords, *infinity= NULL;
+  realT paraboloid, maxboloid= -REALmax, value;
+  realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
+  char *s, *t, firstline[qh_MAXfirst+1];
+  int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
+  int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
+  int tokcount= 0, linecount=0, maxcount, coordcount=0;
+  boolT islong, isfirst= True, wasbegin= False;
+  boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;
+
+  if (qh CDDinput) {
+    while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
+      linecount++;
+      if (qh HALFspace && linecount == 1 && isdigit(*s)) {
+	dimfeasible= qh_strtol (s, &s);	
+	while (isspace(*s))
+          s++;
+        if (qh_strtol (s, &s) == 1)
+          linecount += qh_readfeasible (dimfeasible, s);
+        else
+          dimfeasible= 0;
+      }else if (!memcmp (firstline, "begin", 5) || !memcmp (firstline, "BEGIN", 5))
+        break;
+      else if (!*qh rbox_command)
+	strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
+    }
+    if (!s) {
+      fprintf (qh ferr, "qhull input error: missing \"begin\" for cdd-formated input\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+  }
+  while(!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
+    linecount++;
+    if (!memcmp (s, "begin", 5) || !memcmp (s, "BEGIN", 5))
+      wasbegin= True;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      if (!*s)
+        break;
+      if (!isdigit(*s)) {
+        if (!*qh rbox_command) {
+          strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
+	  firsttext= linecount;
+        }
+        break;
+      }
+      if (!diminput) 
+        diminput= qh_strtol (s, &s);
+      else {
+        numinput= qh_strtol (s, &s);
+        if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
+          linecount += qh_readfeasible (diminput, s); /* checks if ok */
+          dimfeasible= diminput;
+          diminput= numinput= 0;
+        }else 
+          break;
+      }
+    }
+  }
+  if (!s) {
+    fprintf(qh ferr, "qhull input error: short input file.  Did not find dimension and number of points\n");
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (diminput > numinput) {
+    tempi= diminput;	/* exchange dim and n, e.g., for cdd input format */
+    diminput= numinput;
+    numinput= tempi;
+  }
+  if (diminput < 2) {
+    fprintf(qh ferr,"qhull input error: dimension %d (first number) should be at least 2\n",
+	    diminput);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (isdelaunay) {
+    qh PROJECTdelaunay= False;
+    if (qh CDDinput)
+      *dimension= diminput;
+    else
+      *dimension= diminput+1;
+    *numpoints= numinput;
+    if (qh ATinfinity)
+      (*numpoints)++;
+  }else if (qh HALFspace) {
+    *dimension= diminput - 1;
+    *numpoints= numinput;
+    if (diminput < 3) {
+      fprintf(qh ferr,"qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
+  	    diminput);
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+    if (dimfeasible) {
+      if (dimfeasible != *dimension) {
+        fprintf(qh ferr,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
+          dimfeasible, diminput);
+        qh_errexit(qh_ERRinput, NULL, NULL);
+      }
+    }else 
+      qh_setfeasible (*dimension);
+  }else {
+    if (qh CDDinput) 
+      *dimension= diminput-1;
+    else
+      *dimension= diminput;
+    *numpoints= numinput;
+  }
+  qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
+  if (qh HALFspace) {
+    qh half_space= coordp= (coordT*) malloc (qh normal_size + sizeof(coordT));
+    if (qh CDDinput) {
+      offsetp= qh half_space;
+      normalp= offsetp + 1;
+    }else {
+      normalp= qh half_space;
+      offsetp= normalp + *dimension;
+    }
+  } 
+  qh maxline= diminput * (qh_REALdigits + 5);
+  maximize_(qh maxline, 500);
+  qh line= (char*)malloc ((qh maxline+1) * sizeof (char));
+  *ismalloc= True;  /* use malloc since memory not setup */
+  coords= points= qh temp_malloc= 
+        (coordT*)malloc((*numpoints)*(*dimension)*sizeof(coordT));
+  if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
+    fprintf(qh ferr, "qhull error: insufficient memory to read %d points\n",
+	    numinput);
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  if (isdelaunay && qh ATinfinity) {
+    infinity= points + numinput * (*dimension);
+    for (k= (*dimension) - 1; k--; )
+      infinity[k]= 0.0;
+  }
+  maxcount= numinput * diminput;
+  paraboloid= 0.0;
+  while ((s= (isfirst ?  s : fgets(qh line, qh maxline, qh fin)))) {
+    if (!isfirst) {
+      linecount++;
+      if (*s == 'e' || *s == 'E') {
+	if (!memcmp (s, "end", 3) || !memcmp (s, "END", 3)) {
+	  if (qh CDDinput )
+	    break;
+	  else if (wasbegin) 
+	    fprintf (qh ferr, "qhull input warning: the input appears to be in cdd format.  If so, use 'Fd'\n");
+	}
+      }
+    }
+    islong= False;
+    while (*s) {
+      while (isspace(*s))
+        s++;
+      value= qh_strtod (s, &t);
+      if (s == t) {
+        if (!*qh rbox_command)
+ 	 strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
+        if (*s && !firsttext) 
+          firsttext= linecount;
+        if (!islong && !firstshort && coordcount)
+          firstshort= linecount;
+        break;
+      }
+      if (!firstpoint)
+	firstpoint= linecount;
+      s= t;
+      if (++tokcount > maxcount)
+        continue;
+      if (qh HALFspace) {
+	if (qh CDDinput) 
+	  *(coordp++)= -value; /* both coefficients and offset */
+	else
+	  *(coordp++)= value;
+      }else {
+        *(coords++)= value;
+        if (qh CDDinput && !coordcount) {
+          if (value != 1.0) {
+            fprintf (qh ferr, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
+                   linecount);
+            qh_errexit (qh_ERRinput, NULL, NULL);
+          }
+          coords--;
+        }else if (isdelaunay) {
+	  paraboloid += value * value;
+	  if (qh ATinfinity) {
+	    if (qh CDDinput)
+	      infinity[coordcount-1] += value;
+	    else
+	      infinity[coordcount] += value;
+	  }
+	}
+      }
+      if (++coordcount == diminput) {
+        coordcount= 0;
+        if (isdelaunay) {
+          *(coords++)= paraboloid;
+          maximize_(maxboloid, paraboloid);
+          paraboloid= 0.0;
+        }else if (qh HALFspace) {
+          if (!qh_sethalfspace (*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
+	    fprintf (qh ferr, "The halfspace was on line %d\n", linecount);
+	    if (wasbegin)
+	      fprintf (qh ferr, "The input appears to be in cdd format.  If so, you should use option 'Fd'\n");
+	    qh_errexit (qh_ERRinput, NULL, NULL);
+	  }
+          coordp= qh half_space;
+        }          
+        while (isspace(*s))
+          s++;
+        if (*s) {
+          islong= True;
+          if (!firstlong)
+            firstlong= linecount;
+	}
+      }
+    }
+    if (!islong && !firstshort && coordcount)
+      firstshort= linecount;
+    if (!isfirst && s - qh line >= qh maxline) {
+      fprintf(qh ferr, "qhull input error: line %d contained more than %d characters\n", 
+	      linecount, (int) (s - qh line));
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+    isfirst= False;
+  }
+  if (tokcount != maxcount) {
+    newnum= fmin_(numinput, tokcount/diminput);
+    fprintf(qh ferr,"\
+qhull warning: instead of %d %d-dimensional points, input contains\n\
+%d points and %d extra coordinates.  Line %d is the first\npoint",
+       numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);
+    if (firsttext)
+      fprintf(qh ferr, ", line %d is the first comment", firsttext);
+    if (firstshort)
+      fprintf(qh ferr, ", line %d is the first short\nline", firstshort);
+    if (firstlong)
+      fprintf(qh ferr, ", line %d is the first long line", firstlong);
+    fprintf(qh ferr, ".  Continue with %d points.\n", newnum);
+    numinput= newnum;
+    if (isdelaunay && qh ATinfinity) {
+      for (k= tokcount % diminput; k--; )
+	infinity[k] -= *(--coords);
+      *numpoints= newnum+1;
+    }else {
+      coords -= tokcount % diminput;
+      *numpoints= newnum;
+    }
+  }
+  if (isdelaunay && qh ATinfinity) {
+    for (k= (*dimension) -1; k--; )
+      infinity[k] /= numinput;
+    if (coords == infinity)
+      coords += (*dimension) -1;
+    else {
+      for (k= 0; k < (*dimension) -1; k++)
+	*(coords++)= infinity[k];
+    }
+    *(coords++)= maxboloid * 1.1;
+  }
+  if (qh rbox_command[0]) {
+    qh rbox_command[strlen(qh rbox_command)-1]= '\0';
+    if (!strcmp (qh rbox_command, "./rbox D4")) 
+      fprintf (qh ferr, "\n\
+This is the qhull test case.  If any errors or core dumps occur,\n\
+recompile qhull with 'make new'.  If errors still occur, there is\n\
+an incompatibility.  You should try a different compiler.  You can also\n\
+change the choices in user.h.  If you discover the source of the problem,\n\
+please send mail to qhull_bug@geom.umn.edu.\n\
+\n\
+Type 'qhull' for a short list of options.\n");
+  }
+  free (qh line);
+  qh line= NULL;
+  if (qh half_space) {
+    free (qh half_space);
+    qh half_space= NULL;
+  }
+  qh temp_malloc= NULL;
+  trace1((qh ferr,"qh_readpoints: read in %d %d-dimensional points\n",
+	  numinput, diminput));
+  return(points);
+} /* readpoints */
+
+
+/*---------------------------------
+  
+  qh_setfeasible( dim )
+    set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format
+
+  notes:
+    "n,n,n" already checked by qh_initflags()
+    see qh_readfeasible()
+*/
+void qh_setfeasible (int dim) {
+  int tokcount= 0;
+  char *s;
+  coordT *coords, value;
+
+  if (!(s= qh feasible_string)) {
+    fprintf(qh ferr, "\
+qhull input error: halfspace intersection needs a feasible point.\n\
+Either prepend the input with 1 point or use 'Hn,n,n'.  See manual.\n");
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  if (!(qh feasible_point= (pointT*)malloc (dim* sizeof(coordT)))) {
+    fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
+    qh_errexit(qh_ERRmem, NULL, NULL);
+  }
+  coords= qh feasible_point;
+  while (*s) {
+    value= qh_strtod (s, &s);
+    if (++tokcount > dim) {
+      fprintf (qh ferr, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
+          qh feasible_string, dim);
+      break;
+    }
+    *(coords++)= value;
+    if (*s)
+      s++;
+  }
+  while (++tokcount <= dim)    
+    *(coords++)= 0.0;
+} /* setfeasible */
+
+/*---------------------------------
+  
+  qh_skipfacet( facet )
+    returns 'True' if this facet is not to be printed 
+
+  notes:
+    based on the user provided slice thresholds and 'good' specifications
+*/
+boolT qh_skipfacet(facetT *facet) {
+  facetT *neighbor, **neighborp;
+
+  if (qh PRINTneighbors) {
+    if (facet->good)
+      return !qh PRINTgood;
+    FOREACHneighbor_(facet) {
+      if (neighbor->good)
+	return False;
+    }
+    return True;
+  }else if (qh PRINTgood)
+    return !facet->good;
+  else if (!facet->normal)
+    return True;
+  return (!qh_inthresholds (facet->normal, NULL));
+} /* skipfacet */
+
diff --git a/extern/qhull/src/io.h b/extern/qhull/src/io.h
new file mode 100644
index 00000000000..351d56b3708
--- /dev/null
+++ b/extern/qhull/src/io.h
@@ -0,0 +1,149 @@
+/*
  ---------------------------------
+
+   io.h 
+   declarations of Input/Output functions
+
+   see README, qhull.h and io.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFio
+#define qhDEFio 1
+
+/*============ constants and flags ==================*/
+
+/*----------------------------------
+  
+  qh_MAXfirst
+    maximum length of first two lines of stdin
+*/
+#define qh_MAXfirst  200
+
+/*----------------------------------
+  
+  qh_MINradius
+    min radius for Gp and Gv, fraction of maxcoord
+*/
+#define qh_MINradius 0.02
+
+/*----------------------------------
+  
+  qh_GEOMepsilon
+    adjust outer planes for 'lines closer' and geomview roundoff.  
+    This prevents bleed through.
+*/
+#define qh_GEOMepsilon 2e-3
+
+/*----------------------------------
+  
+  qh_WHITESPACE
+    possible values of white space
+*/
+#define qh_WHITESPACE " \n\t\v\r\f"
+
+
+/*----------------------------------
+  
+  qh_RIDGE
+    to select which ridges to print in qh_eachvoronoi
+*/
+typedef enum
+{
+    qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
+}
+qh_RIDGE;
+
+/*----------------------------------
+  
+  printvridgeT
+    prints results of qh_printvdiagram
+
+  see:
+    qh_printvridge for an example
+*/
+typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+
+/*============== -prototypes in alphabetical order =========*/
+
+void    dfacet( unsigned id);
+void    dvertex( unsigned id);
+void    qh_countfacets (facetT *facetlist, setT *facets, boolT printall, 
+              int *numfacetsp, int *numsimplicialp, int *totneighborsp, 
+              int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
+pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
+setT   *qh_detvridge (vertexT *vertex);
+setT   *qh_detvridge3 (vertexT *atvertex, vertexT *vertex);
+int     qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
+int     qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder);
+void	qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist);
+setT   *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets);
+void    qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane);
+void    qh_markkeep (facetT *facetlist);
+setT   *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp);
+void    qh_order_vertexneighbors(vertexT *vertex);
+void	qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall);
+void    qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void 	qh_printcenter (FILE *fp, int format, char *string, facetT *facet);
+void    qh_printcentrum (FILE *fp, facetT *facet, realT radius);
+void    qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printend4geom (FILE *fp, facetT *facet, int *num, boolT printall);
+void    qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void	qh_printfacet(FILE *fp, facetT *facet);
+void	qh_printfacet2math(FILE *fp, facetT *facet, int notfirst);
+void	qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]);
+void    qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
+			       facetT *facet, realT offset, realT color[3]);
+void	qh_printfacet3math (FILE *fp, facetT *facet, int notfirst);
+void	qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
+void	qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet3vertex(FILE *fp, facetT *facet, int format);
+void	qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
+void	qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format);
+void	qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format);
+void    qh_printfacetheader(FILE *fp, facetT *facet);
+void    qh_printfacetridges(FILE *fp, facetT *facet);
+void	qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void	qh_printhelp_degenerate(FILE *fp);
+void	qh_printhelp_singular(FILE *fp);
+void	qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
+  		   setT *vertices, realT color[3]);
+void	qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void    qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
+void	qh_printpoint(FILE *fp, char *string, pointT *point);
+void	qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id);
+void    qh_printpoint3 (FILE *fp, pointT *point);
+void    qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall);
+void    qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
+void    qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
+void	qh_printridge(FILE *fp, ridgeT *ridge);
+void    qh_printspheres(FILE *fp, setT *vertices, realT radius);
+void    qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+int     qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
+void	qh_printvertex(FILE *fp, vertexT *vertex);
+void	qh_printvertexlist (FILE *fp, char* string, facetT *facetlist,
+                         setT *facets, boolT printall);
+void	qh_printvertices (FILE *fp, char* string, setT *vertices);
+void    qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall);
+void    qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall);
+void    qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void    qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
+void	qh_produce_output(void);
+void    qh_projectdim3 (pointT *source, pointT *destination);
+int     qh_readfeasible (int dim, char *remainder);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+void    qh_setfeasible (int dim);
+boolT	qh_skipfacet(facetT *facet);
+
+#endif /* qhDEFio */
diff --git a/extern/qhull/src/mem.c b/extern/qhull/src/mem.c
new file mode 100644
index 00000000000..72934626684
--- /dev/null
+++ b/extern/qhull/src/mem.c
@@ -0,0 +1,447 @@
+/*
  ---------------------------------
+
+  mem.c 
+    memory management routines for qhull
+
+  This is a standalone program.
+   
+  To initialize memory:
+
+    qh_meminit (stderr);  
+    qh_meminitbuffers (qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
+    qh_memsize(sizeof(facetT));
+    qh_memsize(sizeof(facetT));
+    ...
+    qh_memsetup();
+    
+  To free up all memory buffers:
+    qh_memfreeshort (&curlong, &totlong);
+         
+  if qh_NOmem, 
+    malloc/free is used instead of mem.c
+
+  notes: 
+    uses Quickfit algorithm (freelists for commonly allocated sizes)
+    assumes small sizes for freelists (it discards the tail of memory buffers)
+   
+  see:
+    qh-mem.htm and mem.h
+    global.c (qh_initbuffers) for an example of using mem.c 
+   
+  copyright (c) 1993-2002 The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include "mem.h"
+
+#ifndef qhDEFqhull
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+void    qh_errexit(int exitcode, facetT *, ridgeT *);
+#endif
+
+/*============ -global data structure ==============
+    see mem.h for definition
+*/
+
+qhmemT qhmem= {0};     /* remove "= {0}" if this causes a compiler error */
+
+#ifndef qh_NOmem
+
+/*============= internal functions ==============*/
+  
+static int qh_intcompare(const void *i, const void *j);
+
+/*========== functions in alphabetical order ======== */
+
+/*---------------------------------
+  
+  qh_intcompare( i, j )
+    used by qsort and bsearch to compare two integers
+*/
+static int qh_intcompare(const void *i, const void *j) {
+  return(*((int *)i) - *((int *)j));
+} /* intcompare */
+
+
+/*----------------------------------
+   
+  qh_memalloc( insize )  
+    returns object of insize bytes
+    qhmem is the global memory structure 
+    
+  returns:
+    pointer to allocated memory 
+    errors if insufficient memory
+
+  notes:
+    use explicit type conversion to avoid type warnings on some compilers
+    actual object may be larger than insize
+    use qh_memalloc_() for inline code for quick allocations
+    logs allocations if 'T5'
+  
+  design:
+    if size < qhmem.LASTsize
+      if qhmem.freelists[size] non-empty
+        return first object on freelist
+      else
+        round up request to size of qhmem.freelists[size]
+        allocate new allocation buffer if necessary
+        allocate object from allocation buffer
+    else
+      allocate object with malloc()
+*/
+void *qh_memalloc(int insize) {
+  void **freelistp, *newbuffer;
+  int index, size;
+  int outsize, bufsize;
+  void *object;
+
+  if ((unsigned) insize <= (unsigned) qhmem.LASTsize) {
+    index= qhmem.indextable[insize];
+    freelistp= qhmem.freelists+index;
+    if ((object= *freelistp)) {
+      qhmem.cntquick++;  
+      *freelistp= *((void **)*freelistp);  /* replace freelist with next object */
+      return (object);
+    }else {
+      outsize= qhmem.sizetable[index];
+      qhmem.cntshort++;
+      if (outsize > qhmem .freesize) {
+	if (!qhmem.curbuffer)
+	  bufsize= qhmem.BUFinit;
+        else
+	  bufsize= qhmem.BUFsize;
+        qhmem.totshort += bufsize;
+	if (!(newbuffer= malloc(bufsize))) {
+	  fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+	  qh_errexit(qhmem_ERRmem, NULL, NULL);
+	} 
+	*((void **)newbuffer)= qhmem.curbuffer;  /* prepend newbuffer to curbuffer 
+						    list */
+	qhmem.curbuffer= newbuffer;
+        size= (sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
+	qhmem.freemem= (void *)((char *)newbuffer+size);
+	qhmem.freesize= bufsize - size;
+      }
+      object= qhmem.freemem;
+      qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
+      qhmem.freesize -= outsize;
+      return object;
+    }
+  }else {                     /* long allocation */
+    if (!qhmem.indextable) {
+      fprintf (qhmem.ferr, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
+      qh_errexit(qhmem_ERRqhull, NULL, NULL);
+    }
+    outsize= insize;
+    qhmem .cntlong++;
+    qhmem .curlong++;
+    qhmem .totlong += outsize;
+    if (qhmem.maxlong < qhmem.totlong)
+      qhmem.maxlong= qhmem.totlong;
+    if (!(object= malloc(outsize))) {
+      fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+      qh_errexit(qhmem_ERRmem, NULL, NULL);
+    }
+    if (qhmem.IStracing >= 5)
+      fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", outsize, object);
+  }
+  return (object);
+} /* memalloc */
+
+
+/*----------------------------------
+   
+  qh_memfree( object, size ) 
+    free up an object of size bytes
+    size is insize from qh_memalloc
+
+  notes:
+    object may be NULL
+    type checking warns if using (void **)object
+    use qh_memfree_() for quick free's of small objects
+ 
+  design:
+    if size <= qhmem.LASTsize
+      append object to corresponding freelist
+    else
+      call free(object)
+*/
+void qh_memfree(void *object, int size) {
+  void **freelistp;
+
+  if (!object)
+    return;
+  if (size <= qhmem.LASTsize) {
+    qhmem .freeshort++;
+    freelistp= qhmem.freelists + qhmem.indextable[size];
+    *((void **)object)= *freelistp;
+    *freelistp= object;
+  }else {
+    qhmem .freelong++;
+    qhmem .totlong -= size;
+    free (object);
+    if (qhmem.IStracing >= 5)
+      fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
+  }
+} /* memfree */
+
+
+/*---------------------------------
+  
+  qh_memfreeshort( curlong, totlong )
+    frees up all short and qhmem memory allocations
+
+  returns:
+    number and size of current long allocations
+*/
+void qh_memfreeshort (int *curlong, int *totlong) {
+  void *buffer, *nextbuffer;
+
+  *curlong= qhmem .cntlong - qhmem .freelong;
+  *totlong= qhmem .totlong;
+  for(buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) {
+    nextbuffer= *((void **) buffer);
+    free(buffer);
+  }
+  qhmem.curbuffer= NULL;
+  if (qhmem .LASTsize) {
+    free (qhmem .indextable);
+    free (qhmem .freelists);
+    free (qhmem .sizetable);
+  }
+  memset((char *)&qhmem, 0, sizeof qhmem);  /* every field is 0, FALSE, NULL */
+} /* memfreeshort */
+
+
+/*----------------------------------
+   
+  qh_meminit( ferr )
+    initialize qhmem and test sizeof( void*)
+*/
+void qh_meminit (FILE *ferr) {
+  
+  memset((char *)&qhmem, 0, sizeof qhmem);  /* every field is 0, FALSE, NULL */
+  qhmem.ferr= ferr;
+  if (sizeof(void*) < sizeof(int)) {
+    fprintf (ferr, "qhull internal error (qh_meminit): sizeof(void*) < sizeof(int).  qset.c will not work\n");
+    exit (1);  /* can not use qh_errexit() */
+  }
+} /* meminit */
+
+/*---------------------------------
+  
+  qh_meminitbuffers( tracelevel, alignment, numsizes, bufsize, bufinit )
+    initialize qhmem
+    if tracelevel >= 5, trace memory allocations
+    alignment= desired address alignment for memory allocations
+    numsizes= number of freelists
+    bufsize=  size of additional memory buffers for short allocations
+    bufinit=  size of initial memory buffer for short allocations
+*/
+void qh_meminitbuffers (int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
+
+  qhmem.IStracing= tracelevel;
+  qhmem.NUMsizes= numsizes;
+  qhmem.BUFsize= bufsize;
+  qhmem.BUFinit= bufinit;
+  qhmem.ALIGNmask= alignment-1;
+  if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  qhmem.sizetable= (int *) calloc (numsizes, sizeof(int));
+  qhmem.freelists= (void **) calloc (numsizes, sizeof(void *));
+  if (!qhmem.sizetable || !qhmem.freelists) {
+    fprintf(qhmem.ferr, "qhull error (qh_meminit): insufficient memory\n");
+    qh_errexit (qhmem_ERRmem, NULL, NULL);
+  }
+  if (qhmem.IStracing >= 1)
+    fprintf (qhmem.ferr, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
+} /* meminitbuffers */
+
+/*---------------------------------
+  
+  qh_memsetup()
+    set up memory after running memsize()
+*/
+void qh_memsetup (void) {
+  int k,i;
+
+  qsort(qhmem.sizetable, qhmem.TABLEsize, sizeof(int), qh_intcompare);
+  qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
+  if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit) {
+    fprintf (qhmem.ferr, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
+            qhmem .LASTsize, qhmem .BUFsize, qhmem .BUFinit);
+    qh_errexit(qhmem_ERRmem, NULL, NULL);
+  }
+  if (!(qhmem.indextable= (int *)malloc((qhmem.LASTsize+1) * sizeof(int)))) {
+    fprintf(qhmem.ferr, "qhull error (qh_memsetup): insufficient memory\n");
+    qh_errexit(qhmem_ERRmem, NULL, NULL);
+  }
+  for(k=qhmem.LASTsize+1; k--; )
+    qhmem.indextable[k]= k;
+  i= 0;
+  for(k= 0; k <= qhmem.LASTsize; k++) {
+    if (qhmem.indextable[k] <= qhmem.sizetable[i])
+      qhmem.indextable[k]= i;
+    else
+      qhmem.indextable[k]= ++i;
+  }
+} /* memsetup */
+
+/*---------------------------------
+  
+  qh_memsize( size )
+    define a free list for this size
+*/
+void qh_memsize(int size) {
+  int k;
+
+  if (qhmem .LASTsize) {
+    fprintf (qhmem .ferr, "qhull error (qh_memsize): called after qhmem_setup\n");
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
+  for(k= qhmem.TABLEsize; k--; ) {
+    if (qhmem.sizetable[k] == size)
+      return;
+  }
+  if (qhmem.TABLEsize < qhmem.NUMsizes)
+    qhmem.sizetable[qhmem.TABLEsize++]= size;
+  else
+    fprintf(qhmem.ferr, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
+} /* memsize */
+
+
+/*---------------------------------
+  
+  qh_memstatistics( fp )
+    print out memory statistics
+
+  notes:
+    does not account for wasted memory at the end of each block
+*/
+void qh_memstatistics (FILE *fp) {
+  int i, count, totfree= 0;
+  void *object;
+  
+  for (i=0; i < qhmem.TABLEsize; i++) {
+    count=0;
+    for (object= qhmem .freelists[i]; object; object= *((void **)object))
+      count++;
+    totfree += qhmem.sizetable[i] * count;
+  }
+  fprintf (fp, "\nmemory statistics:\n\
+%7d quick allocations\n\
+%7d short allocations\n\
+%7d long allocations\n\
+%7d short frees\n\
+%7d long frees\n\
+%7d bytes of short memory in use\n\
+%7d bytes of short memory in freelists\n\
+%7d bytes of long memory allocated (except for input)\n\
+%7d bytes of long memory in use (in %d pieces)\n\
+%7d bytes per memory buffer (initially %d bytes)\n",
+	   qhmem .cntquick, qhmem.cntshort, qhmem.cntlong,
+	   qhmem .freeshort, qhmem.freelong, 
+	   qhmem .totshort - qhmem .freesize - totfree,
+	   totfree,
+	   qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong,
+	   qhmem .BUFsize, qhmem .BUFinit);
+  if (qhmem.cntlarger) {
+    fprintf (fp, "%7d calls to qh_setlarger\n%7.2g     average copy size\n",
+	   qhmem.cntlarger, ((float) qhmem.totlarger)/ qhmem.cntlarger);
+    fprintf (fp, "  freelists (bytes->count):");
+  }
+  for (i=0; i < qhmem.TABLEsize; i++) {
+    count=0;
+    for (object= qhmem .freelists[i]; object; object= *((void **)object))
+      count++;
+    fprintf (fp, " %d->%d", qhmem.sizetable[i], count);
+  }
+  fprintf (fp, "\n\n");
+} /* memstatistics */
+
+
+/*---------------------------------
+  
+  qh_NOmem
+    turn off quick-fit memory allocation
+
+  notes:
+    uses malloc() and free() instead
+*/
+#else /* qh_NOmem */
+
+void *qh_memalloc(int insize) {
+  void *object;
+
+  if (!(object= malloc(insize))) {
+    fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
+    qh_errexit(qhmem_ERRmem, NULL, NULL);
+  }
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", insize, object);
+  return object;
+}
+
+void qh_memfree(void *object, int size) {
+
+  if (!object)
+    return;
+  free (object);
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
+}
+
+void qh_memfreeshort (int *curlong, int *totlong) {
+
+  memset((char *)&qhmem, 0, sizeof qhmem);  /* every field is 0, FALSE, NULL */
+  *curlong= 0;
+  *totlong= 0;
+}
+
+void qh_meminit (FILE *ferr) {
+
+  memset((char *)&qhmem, 0, sizeof qhmem);  /* every field is 0, FALSE, NULL */
+  qhmem.ferr= ferr;
+  if (sizeof(void*) < sizeof(int)) {
+    fprintf (ferr, "qhull internal error (qh_meminit): sizeof(void*) < sizeof(int).  qset.c will not work\n");
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+}
+
+void qh_meminitbuffers (int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
+
+  qhmem.IStracing= tracelevel;
+
+}
+
+void qh_memsetup (void) {
+
+}
+
+void qh_memsize(int size) {
+
+}
+
+void qh_memstatistics (FILE *fp) {
+
+}
+
+#endif /* qh_NOmem */
diff --git a/extern/qhull/src/mem.h b/extern/qhull/src/mem.h
new file mode 100644
index 00000000000..e9ebd1bb9bc
--- /dev/null
+++ b/extern/qhull/src/mem.h
@@ -0,0 +1,174 @@
+/*
  ---------------------------------
+
+   mem.h 
+     prototypes for memory management functions
+
+   see qh-mem.htm, mem.c and qset.h
+
+   for error handling, writes message and calls
+     qh_errexit (qhmem_ERRmem, NULL, NULL) if insufficient memory
+       and
+     qh_errexit (qhmem_ERRqhull, NULL, NULL) otherwise
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmem
+#define qhDEFmem
+
+/*---------------------------------
+  
+  qh_NOmem
+    turn off quick-fit memory allocation
+
+  notes:
+    mem.c implements Quickfit memory allocation for about 20% time
+    savings.  If it fails on your machine, try to locate the
+    problem, and send the answer to qhull@geom.umn.edu.  If this can
+    not be done, define qh_NOmem to use malloc/free instead.
+
+   #define qh_NOmem
+*/
+
+/*-------------------------------------------
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles 
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers.  If gcc is available, 
+    use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).
+
+   see qh_MEMalign in user.h for qhull's alignment
+*/
+
+#define qhmem_ERRmem 4    /* matches qh_ERRmem in qhull.h */
+#define qhmem_ERRqhull 5  /* matches qh_ERRqhull in qhull.h */
+
+/*----------------------------------
+  
+  ptr_intT
+    for casting a void* to an integer-type
+  
+  notes:
+    On 64-bit machines, a pointer may be larger than an 'int'.  
+    qh_meminit() checks that 'long' holds a 'void*'
+*/
+typedef unsigned long ptr_intT;
+
+/*----------------------------------
+ 
+  qhmemT
+    global memory structure for mem.c
+ 
+ notes:
+   users should ignore qhmem except for writing extensions
+   qhmem is allocated in mem.c 
+   
+   qhmem could be swapable like qh and qhstat, but then
+   multiple qh's and qhmem's would need to keep in synch.  
+   A swapable qhmem would also waste memory buffers.  As long
+   as memory operations are atomic, there is no problem with
+   multiple qh structures being active at the same time.
+   If you need separate address spaces, you can swap the
+   contents of qhmem.
+*/
+typedef struct qhmemT qhmemT;
+extern qhmemT qhmem; 
+
+struct qhmemT {               /* global memory management variables */
+  int      BUFsize;	      /* size of memory allocation buffer */
+  int      BUFinit;	      /* initial size of memory allocation buffer */
+  int      TABLEsize;         /* actual number of sizes in free list table */
+  int      NUMsizes;          /* maximum number of sizes in free list table */
+  int      LASTsize;          /* last size in free list table */
+  int      ALIGNmask;         /* worst-case alignment, must be 2^n-1 */
+  void	 **freelists;          /* free list table, linked by offset 0 */
+  int     *sizetable;         /* size of each freelist */
+  int     *indextable;        /* size->index table */
+  void    *curbuffer;         /* current buffer, linked by offset 0 */
+  void    *freemem;           /*   free memory in curbuffer */
+  int 	   freesize;          /*   size of free memory in bytes */
+  void 	  *tempstack;         /* stack of temporary memory, managed by users */
+  FILE    *ferr;              /* file for reporting errors */
+  int      IStracing;         /* =5 if tracing memory allocations */
+  int      cntquick;          /* count of quick allocations */
+                              /* remove statistics doesn't effect speed */
+  int      cntshort;          /* count of short allocations */
+  int      cntlong;           /* count of long allocations */
+  int      curlong;           /* current count of inuse, long allocations */
+  int      freeshort;	      /* count of short memfrees */
+  int      freelong;	      /* count of long memfrees */
+  int      totshort;          /* total size of short allocations */
+  int      totlong;           /* total size of long allocations */
+  int      maxlong;           /* maximum totlong */
+  int      cntlarger;         /* count of setlarger's */
+  int      totlarger;         /* total copied by setlarger */
+};
+
+
+/*==================== -macros ====================*/
+
+/*----------------------------------
+   
+  qh_memalloc_(size, object, type)  
+    returns object of size bytes 
+	assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+
+#ifdef qh_NOmem
+#define qh_memalloc_(size, freelistp, object, type) {\
+  object= (type*)qh_memalloc (size); }
+#else /* !qh_NOmem */
+
+#define qh_memalloc_(size, freelistp, object, type) {\
+  freelistp= qhmem.freelists + qhmem.indextable[size];\
+  if ((object= (type*)*freelistp)) {\
+    qhmem.cntquick++;  \
+    *freelistp= *((void **)*freelistp);\
+  }else object= (type*)qh_memalloc (size);}
+#endif
+
+/*----------------------------------
+   
+  qh_memfree_(object, size) 
+    free up an object
+
+  notes:
+    object may be NULL
+    assumes size<=qhmem.LASTsize and void **freelistp is a temp
+*/
+#ifdef qh_NOmem
+#define qh_memfree_(object, size, freelistp) {\
+  qh_memfree (object, size); }
+#else /* !qh_NOmem */
+
+#define qh_memfree_(object, size, freelistp) {\
+  if (object) { \
+    qhmem .freeshort++;\
+    freelistp= qhmem.freelists + qhmem.indextable[size];\
+    *((void **)object)= *freelistp;\
+    *freelistp= object;}}
+#endif
+
+/*=============== prototypes in alphabetical order ============*/
+
+void *qh_memalloc(int insize);
+void qh_memfree (void *object, int size);
+void qh_memfreeshort (int *curlong, int *totlong);
+void qh_meminit (FILE *ferr);
+void qh_meminitbuffers (int tracelevel, int alignment, int numsizes,
+			int bufsize, int bufinit);
+void qh_memsetup (void);
+void qh_memsize(int size);
+void qh_memstatistics (FILE *fp);
+
+#endif /* qhDEFmem */
diff --git a/extern/qhull/src/merge.c b/extern/qhull/src/merge.c
new file mode 100644
index 00000000000..34ecda1865f
--- /dev/null
+++ b/extern/qhull/src/merge.c
@@ -0,0 +1,3626 @@
+/*
  ---------------------------------
+
+   merge.c 
+   merges non-convex facets
+
+   see qh-merge.htm and merge.h
+
+   other modules call qh_premerge() and qh_postmerge()
+
+   the user may call qh_postmerge() to perform additional merges.
+
+   To remove deleted facets and vertices (qhull() in qhull.c):
+     qh_partitionvisible (!qh_ALL, &numoutside);  // visible_list, newfacet_list
+     qh_deletevisible ();         // qh.visible_list
+     qh_resetlists (False, qh_RESETvisible);       // qh.visible_list newvertex_list newfacet_list 
+
+   assumes qh.CENTERtype= centrum
+
+   merges occur in qh_mergefacet and in qh_mergecycle
+   vertex->neighbors not set until the first merge occurs
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#include "qhull_a.h"
+
+#ifndef qh_NOmerge
+
+/*=========== internal prototypes =========*/
+
+static int qh_compareangle(const void *p1, const void *p2);
+static int qh_comparemerge(const void *p1, const void *p2);
+static int qh_comparevisit (const void *p1, const void *p2);
+
+																														
+/*===== functions (alphabetical after premerge and postmerge) ======*/
+
+/*---------------------------------
+  
+  qh_premerge( apex, maxcentrum )
+    pre-merge nonconvex facets in qh.newfacet_list for apex
+    maxcentrum defines coplanar and concave (qh_test_appendmerge)
+
+  returns:
+    deleted facets added to qh.visible_list with facet->visible set
+
+  notes:
+    uses globals, qh.MERGEexact, qh.PREmerge
+
+  design:
+    mark duplicate ridges in qh.newfacet_list
+    merge facet cycles in qh.newfacet_list
+    merge duplicate ridges and concave facets in qh.newfacet_list
+    check merged facet cycles for degenerate and redundant facets
+    merge degenerate and redundant facets
+    collect coplanar and concave facets
+    merge concave, coplanar, degenerate, and redundant facets
+*/
+void qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle) {
+  boolT othermerge= False;
+  facetT *newfacet;
+  
+  if (qh ZEROcentrum && qh_checkzero(!qh_ALL))
+    return;    
+  trace2((qh ferr, "qh_premerge: premerge centrum %2.2g angle %2.2g for apex v%d facetlist f%d\n",
+	    maxcentrum, maxangle, apex->id, getid_(qh newfacet_list)));
+  if (qh IStracing >= 4 && qh num_facets < 50)
+    qh_printlists();
+  qh centrum_radius= maxcentrum;
+  qh cos_max= maxangle;
+  qh degen_mergeset= qh_settemp (qh TEMPsize);
+  qh facet_mergeset= qh_settemp (qh TEMPsize);
+  if (qh hull_dim >=3) { 
+    qh_mark_dupridges (qh newfacet_list); /* facet_mergeset */
+    qh_mergecycle_all (qh newfacet_list, &othermerge);
+    qh_forcedmerges (&othermerge /* qh facet_mergeset */); 
+    FORALLnew_facets {  /* test samecycle merges */
+      if (!newfacet->simplicial && !newfacet->mergeridge)
+	qh_degen_redundant_neighbors (newfacet, NULL);
+    }
+    if (qh_merge_degenredundant())
+      othermerge= True;
+  }else /* qh hull_dim == 2 */
+    qh_mergecycle_all (qh newfacet_list, &othermerge);
+  qh_flippedmerges (qh newfacet_list, &othermerge);
+  if (!qh MERGEexact || zzval_(Ztotmerge)) {
+    zinc_(Zpremergetot);
+    qh POSTmerging= False;
+    qh_getmergeset_initial (qh newfacet_list);
+    qh_all_merges (othermerge, False);
+  }
+  qh_settempfree(&qh facet_mergeset);
+  qh_settempfree(&qh degen_mergeset);
+} /* premerge */
+  
+/*---------------------------------
+  
+  qh_postmerge( reason, maxcentrum, maxangle, vneighbors )
+    post-merge nonconvex facets as defined by maxcentrum and maxangle
+    'reason' is for reporting progress
+    if vneighbors, 
+      calls qh_test_vneighbors at end of qh_all_merge 
+    if firstmerge, 
+      calls qh_reducevertices before qh_getmergeset
+
+  returns:
+    if first call (qh.visible_list != qh.facet_list), 
+      builds qh.facet_newlist, qh.newvertex_list
+    deleted facets added to qh.visible_list with facet->visible
+    qh.visible_list == qh.facet_list
+
+  notes:
+
+
+  design:
+    if first call
+      set qh.visible_list and qh.newfacet_list to qh.facet_list
+      add all facets to qh.newfacet_list
+      mark non-simplicial facets, facet->newmerge
+      set qh.newvertext_list to qh.vertex_list
+      add all vertices to qh.newvertex_list
+      if a pre-merge occured
+        set vertex->delridge {will retest the ridge}
+        if qh.MERGEexact
+          call qh_reducevertices()
+      if no pre-merging 
+        merge flipped facets
+    determine non-convex facets
+    merge all non-convex facets
+*/
+void qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
+                      boolT vneighbors) {
+  facetT *newfacet;
+  boolT othermerges= False;
+  vertexT *vertex;
+
+  if (qh REPORTfreq || qh IStracing) {
+    qh_buildtracing (NULL, NULL);
+    qh_printsummary (qh ferr);
+    if (qh PRINTstatistics) 
+      qh_printallstatistics (qh ferr, "reason");
+    fprintf (qh ferr, "\n%s with 'C%.2g' and 'A%.2g'\n", 
+        reason, maxcentrum, maxangle);
+  }
+  trace2((qh ferr, "qh_postmerge: postmerge.  test vneighbors? %d\n",
+	    vneighbors));
+  qh centrum_radius= maxcentrum;
+  qh cos_max= maxangle;
+  qh POSTmerging= True;
+  qh degen_mergeset= qh_settemp (qh TEMPsize);
+  qh facet_mergeset= qh_settemp (qh TEMPsize);
+  if (qh visible_list != qh facet_list) {  /* first call */
+    qh NEWfacets= True;
+    qh visible_list= qh newfacet_list= qh facet_list;
+    FORALLnew_facets {
+      newfacet->newfacet= True;
+       if (!newfacet->simplicial)
+        newfacet->newmerge= True;
+     zinc_(Zpostfacets);
+    }
+    qh newvertex_list= qh vertex_list;
+    FORALLvertices
+      vertex->newlist= True;
+    if (qh VERTEXneighbors) { /* a merge has occurred */
+      FORALLvertices
+	vertex->delridge= True; /* test for redundant, needed? */
+      if (qh MERGEexact) {
+	if (qh hull_dim <= qh_DIMreduceBuild)
+	  qh_reducevertices(); /* was skipped during pre-merging */
+      }
+    }
+    if (!qh PREmerge && !qh MERGEexact) 
+      qh_flippedmerges (qh newfacet_list, &othermerges);
+  }
+  qh_getmergeset_initial (qh newfacet_list);
+  qh_all_merges (False, vneighbors);
+  qh_settempfree(&qh facet_mergeset);
+  qh_settempfree(&qh degen_mergeset);
+} /* post_merge */
+
+/*---------------------------------
+  
+  qh_all_merges( othermerge, vneighbors )
+    merge all non-convex facets
+    
+    set othermerge if already merged facets (for qh_reducevertices)
+    if vneighbors
+      tests vertex neighbors for convexity at end
+    qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list
+    qh.degen_mergeset is defined
+    if qh.MERGEexact && !qh.POSTmerging, 
+      does not merge coplanar facets
+
+  returns:
+    deleted facets added to qh.visible_list with facet->visible
+    deleted vertices added qh.delvertex_list with vertex->delvertex
+  
+  notes:
+    unless !qh.MERGEindependent, 
+      merges facets in independent sets
+    uses qh.newfacet_list as argument since merges call qh_removefacet()
+
+  design:
+    while merges occur
+      for each merge in qh.facet_mergeset
+        unless one of the facets was already merged in this pass
+          merge the facets
+        test merged facets for additional merges
+        add merges to qh.facet_mergeset
+      if vertices record neighboring facets
+        rename redundant vertices
+          update qh.facet_mergeset
+    if vneighbors ??
+      tests vertex neighbors for convexity at end
+*/
+void qh_all_merges (boolT othermerge, boolT vneighbors) {
+  facetT *facet1, *facet2;
+  mergeT *merge;
+  boolT wasmerge= True, isreduce;
+  void **freelistp;  /* used !qh_NOmem */
+  vertexT *vertex;
+  mergeType mergetype;
+  int numcoplanar=0, numconcave=0, numdegenredun= 0, numnewmerges= 0;
+  
+  trace2((qh ferr, "qh_all_merges: starting to merge facets beginning from f%d\n",
+	    getid_(qh newfacet_list)));
+  while (True) {
+    wasmerge= False;
+    while (qh_setsize (qh facet_mergeset)) {
+      while ((merge= (mergeT*)qh_setdellast(qh facet_mergeset))) {
+	facet1= merge->facet1;
+	facet2= merge->facet2;
+	mergetype= merge->type;
+	qh_memfree_(merge, sizeof(mergeT), freelistp);
+	if (facet1->visible || facet2->visible) /*deleted facet*/
+	  continue;  
+	if ((facet1->newfacet && !facet1->tested)
+	        || (facet2->newfacet && !facet2->tested)) {
+	  if (qh MERGEindependent && mergetype <= MRGanglecoplanar)
+	    continue;      /* perform independent sets of merges */
+	}
+	qh_merge_nonconvex (facet1, facet2, mergetype);
+        numdegenredun += qh_merge_degenredundant();
+        numnewmerges++;
+        wasmerge= True;
+	if (mergetype == MRGconcave)
+	  numconcave++;
+	else /* MRGcoplanar or MRGanglecoplanar */
+	  numcoplanar++;
+      } /* while setdellast */
+      if (qh POSTmerging && qh hull_dim <= qh_DIMreduceBuild 
+      && numnewmerges > qh_MAXnewmerges) {
+	numnewmerges= 0;
+	qh_reducevertices();  /* otherwise large post merges too slow */
+      }
+      qh_getmergeset (qh newfacet_list); /* facet_mergeset */
+    } /* while mergeset */
+    if (qh VERTEXneighbors) {
+      isreduce= False;
+      if (qh hull_dim >=4 && qh POSTmerging) {
+	FORALLvertices  
+	  vertex->delridge= True;
+	isreduce= True;
+      }
+      if ((wasmerge || othermerge) && (!qh MERGEexact || qh POSTmerging) 
+	  && qh hull_dim <= qh_DIMreduceBuild) {
+	othermerge= False;
+	isreduce= True;
+      }
+      if (isreduce) {
+	if (qh_reducevertices()) {
+	  qh_getmergeset (qh newfacet_list); /* facet_mergeset */
+	  continue;
+	}
+      }
+    }
+    if (vneighbors && qh_test_vneighbors(/* qh newfacet_list */)) 
+      continue;
+    break;
+  } /* while (True) */
+  if (qh CHECKfrequently && !qh MERGEexact) {
+    qh old_randomdist= qh RANDOMdist;
+    qh RANDOMdist= False;
+    qh_checkconvex (qh newfacet_list, qh_ALGORITHMfault);
+    /* qh_checkconnect (); [this is slow and it changes the facet order] */
+    qh RANDOMdist= qh old_randomdist;
+  }
+  trace1((qh ferr, "qh_all_merges: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n",
+    numcoplanar, numconcave, numdegenredun));
+  if (qh IStracing >= 4 && qh num_facets < 50)
+    qh_printlists ();
+} /* all_merges */
+
+
+/*---------------------------------
+  
+  qh_appendmergeset( facet, neighbor, mergetype, angle )
+    appends an entry to qh.facet_mergeset or qh.degen_mergeset
+
+    angle ignored if NULL or !qh.ANGLEmerge
+
+  returns:
+    merge appended to facet_mergeset or degen_mergeset
+      sets ->degenerate or ->redundant if degen_mergeset
+  
+  see:
+    qh_test_appendmerge()
+
+  design:
+    allocate merge entry
+    if regular merge
+      append to qh.facet_mergeset
+    else if degenerate merge and qh.facet_mergeset is all degenerate
+      append to qh.degen_mergeset 
+    else if degenerate merge
+      prepend to qh.degen_mergeset 
+    else if redundant merge
+      append to qh.degen_mergeset 
+*/
+void qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle) {
+  mergeT *merge, *lastmerge;
+  void **freelistp; /* used !qh_NOmem */
+
+  if (facet->redundant)
+    return;
+  if (facet->degenerate && mergetype == MRGdegen)
+    return;
+  qh_memalloc_(sizeof(mergeT), freelistp, merge, mergeT);
+  merge->facet1= facet;
+  merge->facet2= neighbor;
+  merge->type= mergetype;
+  if (angle && qh ANGLEmerge)
+    merge->angle= *angle;
+  if (mergetype < MRGdegen)
+    qh_setappend (&(qh facet_mergeset), merge);
+  else if (mergetype == MRGdegen) {
+    facet->degenerate= True;
+    if (!(lastmerge= (mergeT*)qh_setlast (qh degen_mergeset)) 
+    || lastmerge->type == MRGdegen)
+      qh_setappend (&(qh degen_mergeset), merge);
+    else
+      qh_setaddnth (&(qh degen_mergeset), 0, merge);
+  }else if (mergetype == MRGredundant) {
+    facet->redundant= True;
+    qh_setappend (&(qh degen_mergeset), merge);
+  }else /* mergetype == MRGmirror */ {
+    if (facet->redundant || neighbor->redundant) {
+      fprintf(qh ferr, "qhull error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet\n",
+	   facet->id, neighbor->id);
+      qh_errexit2 (qh_ERRqhull, facet, neighbor);
+    }
+    if (!qh_setequal (facet->vertices, neighbor->vertices)) {
+      fprintf(qh ferr, "qhull error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n",
+	   facet->id, neighbor->id);
+      qh_errexit2 (qh_ERRqhull, facet, neighbor);
+    }
+    facet->redundant= True;
+    neighbor->redundant= True;
+    qh_setappend (&(qh degen_mergeset), merge);
+  }
+} /* appendmergeset */
+
+
+/*---------------------------------
+  
+  qh_basevertices( samecycle )
+    return temporary set of base vertices for samecycle
+    samecycle is first facet in the cycle
+    assumes apex is SETfirst_( samecycle->vertices )
+
+  returns:
+    vertices (settemp)
+    all ->seen are cleared
+
+  notes:
+    uses qh_vertex_visit;
+
+  design:
+    for each facet in samecycle
+      for each unseen vertex in facet->vertices
+        append to result  
+*/
+setT *qh_basevertices (facetT *samecycle) {
+  facetT *same;
+  vertexT *apex, *vertex, **vertexp;
+  setT *vertices= qh_settemp (qh TEMPsize);
+  
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  apex->visitid= ++qh vertex_visit;
+  FORALLsame_cycle_(samecycle) {
+    if (same->mergeridge)
+      continue;
+    FOREACHvertex_(same->vertices) {
+      if (vertex->visitid != qh vertex_visit) {
+        qh_setappend (&vertices, vertex);
+        vertex->visitid= qh vertex_visit;
+        vertex->seen= False;
+      }
+    }
+  }
+  trace4((qh ferr, "qh_basevertices: found %d vertices\n", 
+         qh_setsize (vertices)));
+  return vertices;
+} /* basevertices */
+
+/*---------------------------------
+  
+  qh_checkconnect()
+    check that new facets are connected
+    new facets are on qh.newfacet_list
+    
+  notes:
+    this is slow and it changes the order of the facets
+    uses qh.visit_id
+
+  design:
+    move first new facet to end of qh.facet_list
+    for all newly appended facets
+      append unvisited neighbors to end of qh.facet_list
+    for all new facets
+      report error if unvisited
+*/
+void qh_checkconnect (void /* qh newfacet_list */) {
+  facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp;
+
+  facet= qh newfacet_list;
+  qh_removefacet (facet);
+  qh_appendfacet (facet);
+  facet->visitid= ++qh visit_id;
+  FORALLfacet_(facet) {
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh visit_id) {
+        qh_removefacet (neighbor);
+        qh_appendfacet (neighbor);
+        neighbor->visitid= qh visit_id;
+      }
+    }
+  }
+  FORALLnew_facets {
+    if (newfacet->visitid == qh visit_id)
+      break;
+    fprintf(qh ferr, "qhull error: f%d is not attached to the new facets\n",
+         newfacet->id);
+    errfacet= newfacet;
+  }
+  if (errfacet)
+    qh_errexit (qh_ERRqhull, errfacet, NULL);
+} /* checkconnect */
+
+/*---------------------------------
+  
+  qh_checkzero( testall )
+    check that facets are clearly convex for qh.DISTround with qh.MERGEexact
+
+    if testall, 
+      test all facets for qh.MERGEexact post-merging
+    else 
+      test qh.newfacet_list
+      
+    if qh.MERGEexact, 
+      allows coplanar ridges
+      skips convexity test while qh.ZEROall_ok
+
+  returns:
+    True if all facets !flipped, !dupridge, normal
+         if all horizon facets are simplicial
+         if all vertices are clearly below neighbor
+         if all opposite vertices of horizon are below 
+    clears qh.ZEROall_ok if any problems or coplanar facets
+
+  notes:
+    uses qh.vertex_visit
+    horizon facets may define multiple new facets
+
+  design:
+    for all facets in qh.newfacet_list or qh.facet_list
+      check for flagged faults (flipped, etc.)
+    for all facets in qh.newfacet_list or qh.facet_list
+      for each neighbor of facet
+        skip horizon facets for qh.newfacet_list
+        test the opposite vertex
+      if qh.newfacet_list
+        test the other vertices in the facet's horizon facet
+*/
+boolT qh_checkzero (boolT testall) {
+  facetT *facet, *neighbor, **neighborp;
+  facetT *horizon, *facetlist;
+  int neighbor_i;
+  vertexT *vertex, **vertexp;
+  realT dist;
+
+  if (testall) 
+    facetlist= qh facet_list;
+  else {
+    facetlist= qh newfacet_list;
+    FORALLfacet_(facetlist) {
+      horizon= SETfirstt_(facet->neighbors, facetT);
+      if (!horizon->simplicial)
+        goto LABELproblem;
+      if (facet->flipped || facet->dupridge || !facet->normal)
+        goto LABELproblem;
+    }
+    if (qh MERGEexact && qh ZEROall_ok) {
+      trace2((qh ferr, "qh_checkzero: skip convexity check until first pre-merge\n"));
+      return True;
+    }
+  }
+  FORALLfacet_(facetlist) {
+    qh vertex_visit++;
+    neighbor_i= 0;
+    horizon= NULL;
+    FOREACHneighbor_(facet) {
+      if (!neighbor_i && !testall) {
+        horizon= neighbor;
+	neighbor_i++;
+        continue; /* horizon facet tested in qh_findhorizon */
+      }
+      vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
+      vertex->visitid= qh vertex_visit;
+      zzinc_(Zdistzero);
+      qh_distplane (vertex->point, neighbor, &dist);
+      if (dist >= -qh DISTround) {
+        qh ZEROall_ok= False;
+        if (!qh MERGEexact || testall || dist > qh DISTround)
+          goto LABELnonconvex;
+      }
+    }
+    if (!testall) {
+      FOREACHvertex_(horizon->vertices) {
+	if (vertex->visitid != qh vertex_visit) {
+	  zzinc_(Zdistzero);
+	  qh_distplane (vertex->point, facet, &dist);
+	  if (dist >= -qh DISTround) {
+	    qh ZEROall_ok= False;
+	    if (!qh MERGEexact || dist > qh DISTround)
+	      goto LABELnonconvex;
+	  }
+	  break;
+	}
+      }
+    }
+  }
+  trace2((qh ferr, "qh_checkzero: testall %d, facets are %s\n", testall,
+        (qh MERGEexact && !testall) ? 
+           "not concave, flipped, or duplicate ridged" : "clearly convex"));
+  return True;
+
+ LABELproblem:
+  qh ZEROall_ok= False;
+  trace2((qh ferr, "qh_checkzero: facet f%d needs pre-merging\n",
+       facet->id));
+  return False;
+
+ LABELnonconvex:
+  trace2((qh ferr, "qh_checkzero: facet f%d and f%d are not clearly convex.  v%d dist %.2g\n",
+         facet->id, neighbor->id, vertex->id, dist));
+  return False;
+} /* checkzero */
+
+/*---------------------------------
+  
+  qh_compareangle( angle1, angle2 )
+    used by qsort() to order merges by angle
+*/
+static int qh_compareangle(const void *p1, const void *p2) {
+  mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
+ 
+  return ((a->angle > b->angle) ? 1 : -1);
+} /* compareangle */
+
+/*---------------------------------
+  
+  qh_comparemerge( merge1, merge2 )
+    used by qsort() to order merges
+*/
+static int qh_comparemerge(const void *p1, const void *p2) {
+  mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
+ 
+  return (a->type - b->type);
+} /* comparemerge */
+
+/*---------------------------------
+  
+  qh_comparevisit( vertex1, vertex2 )
+    used by qsort() to order vertices by their visitid
+*/
+static int qh_comparevisit (const void *p1, const void *p2) {
+  vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
+ 
+  return (a->visitid - b->visitid);
+} /* comparevisit */
+
+/*---------------------------------
+  
+  qh_copynonconvex( atridge )
+    set non-convex flag on other ridges (if any) between same neighbors
+
+  notes:
+    may be faster if use smaller ridge set
+
+  design:
+    for each ridge of atridge's top facet
+      if ridge shares the same neighbor
+        set nonconvex flag
+*/
+void qh_copynonconvex (ridgeT *atridge) {
+  facetT *facet, *otherfacet;
+  ridgeT *ridge, **ridgep;
+
+  facet= atridge->top;
+  otherfacet= atridge->bottom;
+  FOREACHridge_(facet->ridges) {
+    if (otherfacet == otherfacet_(ridge, facet) && ridge != atridge) {
+      ridge->nonconvex= True;
+      trace4((qh ferr, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n",
+	      atridge->id, ridge->id));
+      break;
+    }
+  }
+} /* copynonconvex */
+
+/*---------------------------------
+  
+  qh_degen_redundant_facet( facet )
+    check facet for degen. or redundancy
+
+  notes:
+    bumps vertex_visit
+    called if a facet was redundant but no longer is (qh_merge_degenredundant)
+    qh_appendmergeset() only appends first reference to facet (i.e., redundant)
+
+  see:
+    qh_degen_redundant_neighbors()
+
+  design:
+    test for redundant neighbor
+    test for degenerate facet
+*/
+void qh_degen_redundant_facet (facetT *facet) {
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+
+  trace4((qh ferr, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n",
+	  facet->id));
+  FOREACHneighbor_(facet) {
+    qh vertex_visit++;
+    FOREACHvertex_(neighbor->vertices)
+      vertex->visitid= qh vertex_visit;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh vertex_visit)
+	break;
+    }
+    if (!vertex) {
+      qh_appendmergeset (facet, neighbor, MRGredundant, NULL);
+      trace2((qh ferr, "qh_degen_redundant_facet: f%d is contained in f%d.  merge\n", facet->id, neighbor->id)); 
+      return;
+    }
+  }
+  if (qh_setsize (facet->neighbors) < qh hull_dim) {
+    qh_appendmergeset (facet, facet, MRGdegen, NULL);
+    trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));
+  }
+} /* degen_redundant_facet */
+
+
+/*---------------------------------
+  
+  qh_degen_redundant_neighbors( facet, delfacet,  )
+    append degenerate and redundant neighbors to facet_mergeset
+    if delfacet, 
+      only checks neighbors of both delfacet and facet
+    also checks current facet for degeneracy
+
+  notes:
+    bumps vertex_visit
+    called for each qh_mergefacet() and qh_mergecycle()
+    merge and statistics occur in merge_nonconvex
+    qh_appendmergeset() only appends first reference to facet (i.e., redundant)
+      it appends redundant facets after degenerate ones
+
+    a degenerate facet has fewer than hull_dim neighbors
+    a redundant facet's vertices is a subset of its neighbor's vertices
+    tests for redundant merges first (appendmergeset is nop for others)
+    in a merge, only needs to test neighbors of merged facet
+  
+  see:
+    qh_merge_degenredundant() and qh_degen_redundant_facet()
+
+  design:
+    test for degenerate facet
+    test for redundant neighbor
+    test for degenerate neighbor
+*/
+void qh_degen_redundant_neighbors (facetT *facet, facetT *delfacet) {
+  vertexT *vertex, **vertexp;
+  facetT *neighbor, **neighborp;
+  int size;
+
+  trace4((qh ferr, "qh_degen_redundant_neighbors: test neighbors of f%d with delfacet f%d\n", 
+	  facet->id, getid_(delfacet)));
+  if ((size= qh_setsize (facet->neighbors)) < qh hull_dim) {
+    qh_appendmergeset (facet, facet, MRGdegen, NULL);
+    trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size));
+  }
+  if (!delfacet)
+    delfacet= facet;
+  qh vertex_visit++;
+  FOREACHvertex_(facet->vertices)
+    vertex->visitid= qh vertex_visit;
+  FOREACHneighbor_(delfacet) {
+    /* uses early out instead of checking vertex count */
+    if (neighbor == facet)
+      continue;
+    FOREACHvertex_(neighbor->vertices) {
+      if (vertex->visitid != qh vertex_visit)
+        break;
+    }
+    if (!vertex) {
+      qh_appendmergeset (neighbor, facet, MRGredundant, NULL);
+      trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is contained in f%d.  merge\n", neighbor->id, facet->id)); 
+    }
+  }
+  FOREACHneighbor_(delfacet) {   /* redundant merges occur first */
+    if (neighbor == facet)
+      continue;
+    if ((size= qh_setsize (neighbor->neighbors)) < qh hull_dim) {
+      qh_appendmergeset (neighbor, neighbor, MRGdegen, NULL);
+      trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.  Neighbor of f%d.\n", neighbor->id, size, facet->id)); 
+    }
+  }
+} /* degen_redundant_neighbors */
+
+
+/*---------------------------------
+  
+  qh_find_newvertex( oldvertex, vertices, ridges )
+    locate new vertex for renaming old vertex
+    vertices is a set of possible new vertices
+      vertices sorted by number of deleted ridges
+
+  returns:
+    newvertex or NULL
+      each ridge includes both vertex and oldvertex
+    vertices sorted by number of deleted ridges
+      
+  notes:
+    modifies vertex->visitid
+    new vertex is in one of the ridges
+    renaming will not cause a duplicate ridge
+    renaming will minimize the number of deleted ridges
+    newvertex may not be adjacent in the dual (though unlikely)
+
+  design:
+    for each vertex in vertices
+      set vertex->visitid to number of references in ridges
+    remove unvisited vertices 
+    set qh.vertex_visit above all possible values
+    sort vertices by number of references in ridges
+    add each ridge to qh.hash_table
+    for each vertex in vertices
+      look for a vertex that would not cause a duplicate ridge after a rename
+*/
+vertexT *qh_find_newvertex (vertexT *oldvertex, setT *vertices, setT *ridges) {
+  vertexT *vertex, **vertexp;
+  setT *newridges;
+  ridgeT *ridge, **ridgep;
+  int size, hashsize;
+  int hash;
+
+#ifndef qh_NOtrace
+  if (qh IStracing >= 4) {
+    fprintf (qh ferr, "qh_find_newvertex: find new vertex for v%d from ",
+	     oldvertex->id);
+    FOREACHvertex_(vertices) 
+      fprintf (qh ferr, "v%d ", vertex->id);
+    FOREACHridge_(ridges)
+      fprintf (qh ferr, "r%d ", ridge->id);
+    fprintf (qh ferr, "\n");
+  }
+#endif
+  FOREACHvertex_(vertices) 
+    vertex->visitid= 0;
+  FOREACHridge_(ridges) {
+    FOREACHvertex_(ridge->vertices) 
+      vertex->visitid++;
+  }
+  FOREACHvertex_(vertices) {
+    if (!vertex->visitid) {
+      qh_setdelnth (vertices, SETindex_(vertices,vertex));
+      vertexp--; /* repeat since deleted this vertex */
+    }
+  }
+  qh vertex_visit += qh_setsize (ridges);
+  if (!qh_setsize (vertices)) {
+    trace4((qh ferr, "qh_find_newvertex: vertices not in ridges for v%d\n",
+	    oldvertex->id));
+    return NULL;
+  }
+  qsort (SETaddr_(vertices, vertexT), qh_setsize (vertices),
+	        sizeof (vertexT *), qh_comparevisit);
+  /* can now use qh vertex_visit */
+  if (qh PRINTstatistics) {
+    size= qh_setsize (vertices);
+    zinc_(Zintersect);
+    zadd_(Zintersecttot, size);
+    zmax_(Zintersectmax, size);
+  }
+  hashsize= qh_newhashtable (qh_setsize (ridges));
+  FOREACHridge_(ridges)
+    qh_hashridge (qh hash_table, hashsize, ridge, oldvertex);
+  FOREACHvertex_(vertices) {
+    newridges= qh_vertexridges (vertex);
+    FOREACHridge_(newridges) {
+      if (qh_hashridge_find (qh hash_table, hashsize, ridge, vertex, oldvertex, &hash)) {
+	zinc_(Zdupridge);
+	break;
+      }
+    }
+    qh_settempfree (&newridges);
+    if (!ridge)
+      break;  /* found a rename */
+  }
+  if (vertex) {
+    /* counted in qh_renamevertex */
+    trace2((qh ferr, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
+      vertex->id, oldvertex->id, qh_setsize (vertices), qh_setsize (ridges)));
+  }else {
+    zinc_(Zfindfail);
+    trace0((qh ferr, "qh_find_newvertex: no vertex for renaming v%d (all duplicated ridges) during p%d\n",
+      oldvertex->id, qh furthest_id));
+  }
+  qh_setfree (&qh hash_table);
+  return vertex;
+} /* find_newvertex */
+
+/*---------------------------------
+  
+  qh_findbest_test( testcentrum, facet, neighbor, bestfacet, dist, mindist, maxdist )
+    test neighbor of facet for qh_findbestneighbor()
+    if testcentrum,
+      tests centrum (assumes it is defined)
+    else 
+      tests vertices
+
+  returns:
+    if a better facet (i.e., vertices/centrum of facet closer to neighbor)
+      updates bestfacet, dist, mindist, and maxdist
+*/
+void qh_findbest_test (boolT testcentrum, facetT *facet, facetT *neighbor,
+      facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
+  realT dist, mindist, maxdist;
+
+  if (testcentrum) {
+    zzinc_(Zbestdist);
+    qh_distplane(facet->center, neighbor, &dist);
+    dist *= qh hull_dim; /* estimate furthest vertex */
+    if (dist < 0) {
+      maxdist= 0;
+      mindist= dist;
+      dist= -dist;
+    }else
+      maxdist= dist;
+  }else
+    dist= qh_getdistance (facet, neighbor, &mindist, &maxdist);
+  if (dist < *distp) {
+    *bestfacet= neighbor;
+    *mindistp= mindist;
+    *maxdistp= maxdist;
+    *distp= dist;
+  }
+} /* findbest_test */
+
+/*---------------------------------
+  
+  qh_findbestneighbor( facet, dist, mindist, maxdist )
+    finds best neighbor (least dist) of a facet for merging
+
+  returns:
+    returns min and max distances and their max absolute value
+  
+  notes:
+    avoids merging old into new
+    assumes ridge->nonconvex only set on one ridge between a pair of facets
+    could use an early out predicate but not worth it
+
+  design:
+    if a large facet
+      will test centrum
+    else
+      will test vertices
+    if a large facet
+      test nonconvex neighbors for best merge
+    else
+      test all neighbors for the best merge
+    if testing centrum
+      get distance information
+*/
+facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
+  facetT *neighbor, **neighborp, *bestfacet= NULL;
+  ridgeT *ridge, **ridgep;
+  boolT nonconvex= True, testcentrum= False;
+  int size= qh_setsize (facet->vertices);
+
+  *distp= REALmax;
+  if (size > qh_BESTcentrum2 * qh hull_dim + qh_BESTcentrum) {
+    testcentrum= True;
+    zinc_(Zbestcentrum);
+    if (!facet->center)
+       facet->center= qh_getcentrum (facet);
+  }
+  if (size > qh hull_dim + qh_BESTnonconvex) {
+    FOREACHridge_(facet->ridges) {
+      if (ridge->nonconvex) {
+        neighbor= otherfacet_(ridge, facet);
+	qh_findbest_test (testcentrum, facet, neighbor,
+			  &bestfacet, distp, mindistp, maxdistp);
+      }
+    }
+  }
+  if (!bestfacet) {     
+    nonconvex= False;
+    FOREACHneighbor_(facet)
+      qh_findbest_test (testcentrum, facet, neighbor,
+			&bestfacet, distp, mindistp, maxdistp);
+  }
+  if (!bestfacet) {
+    fprintf (qh ferr, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id);
+    
+    qh_errexit (qh_ERRqhull, facet, NULL);
+  }
+  if (testcentrum) 
+    qh_getdistance (facet, bestfacet, mindistp, maxdistp);
+  trace3((qh ferr, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
+     bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
+  return(bestfacet);
+} /* findbestneighbor */
+
+
+/*---------------------------------
+  
+  qh_flippedmerges( facetlist, wasmerge )
+    merge flipped facets into best neighbor
+    assumes qh.facet_mergeset at top of temporary stack
+
+  returns:
+    no flipped facets on facetlist
+    sets wasmerge if merge occurred
+    degen/redundant merges passed through
+
+  notes:
+    othermerges not needed since qh.facet_mergeset is empty before & after
+      keep it in case of change
+
+  design:
+    append flipped facets to qh.facetmergeset
+    for each flipped merge
+      find best neighbor
+      merge facet into neighbor
+      merge degenerate and redundant facets
+    remove flipped merges from qh.facet_mergeset
+*/
+void qh_flippedmerges(facetT *facetlist, boolT *wasmerge) {
+  facetT *facet, *neighbor, *facet1;
+  realT dist, mindist, maxdist;
+  mergeT *merge, **mergep;
+  setT *othermerges;
+  int nummerge=0;
+
+  trace4((qh ferr, "qh_flippedmerges: begin\n"));
+  FORALLfacet_(facetlist) {
+    if (facet->flipped && !facet->visible) 
+      qh_appendmergeset (facet, facet, MRGflip, NULL);
+  }
+  othermerges= qh_settemppop(); /* was facet_mergeset */
+  qh facet_mergeset= qh_settemp (qh TEMPsize);
+  qh_settemppush (othermerges);
+  FOREACHmerge_(othermerges) {
+    facet1= merge->facet1;
+    if (merge->type != MRGflip || facet1->visible) 
+      continue;
+    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+      qhmem.IStracing= qh IStracing= qh TRACElevel;
+    neighbor= qh_findbestneighbor (facet1, &dist, &mindist, &maxdist);
+    trace0((qh ferr, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n",
+      facet1->id, neighbor->id, dist, qh furthest_id));
+    qh_mergefacet (facet1, neighbor, &mindist, &maxdist, !qh_MERGEapex);
+    nummerge++;
+    if (qh PRINTstatistics) {
+      zinc_(Zflipped);
+      wadd_(Wflippedtot, dist);
+      wmax_(Wflippedmax, dist);
+    }
+    qh_merge_degenredundant();
+  }
+  FOREACHmerge_(othermerges) {
+    if (merge->facet1->visible || merge->facet2->visible)
+      qh_memfree (merge, sizeof(mergeT));
+    else
+      qh_setappend (&qh facet_mergeset, merge);
+  }
+  qh_settempfree (&othermerges);
+  if (nummerge)
+    *wasmerge= True;
+  trace1((qh ferr, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));
+} /* flippedmerges */
+
+
+/*---------------------------------
+  
+  qh_forcedmerges( wasmerge )
+    merge duplicated ridges
+
+  returns:
+    removes all duplicate ridges on facet_mergeset
+    wasmerge set if merge
+    qh.facet_mergeset may include non-forced merges (none for now)
+    qh.degen_mergeset includes degen/redun merges
+
+  notes: 
+    duplicate ridges occur when the horizon is pinched,
+        i.e. a subridge occurs in more than two horizon ridges.
+     could rename vertices that pinch the horizon
+    assumes qh_merge_degenredundant() has not be called
+    othermerges isn't needed since facet_mergeset is empty afterwards
+      keep it in case of change
+
+  design:
+    for each duplicate ridge
+      find current facets by chasing f.replace links
+      determine best direction for facet
+      merge one facet into the other
+      remove duplicate ridges from qh.facet_mergeset
+*/
+void qh_forcedmerges(boolT *wasmerge) {
+  facetT *facet1, *facet2;
+  mergeT *merge, **mergep;
+  realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2;
+  setT *othermerges;
+  int nummerge=0, numflip=0;
+
+  if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+    qhmem.IStracing= qh IStracing= qh TRACElevel;
+  trace4((qh ferr, "qh_forcedmerges: begin\n"));  
+  othermerges= qh_settemppop(); /* was facet_mergeset */
+  qh facet_mergeset= qh_settemp (qh TEMPsize);
+  qh_settemppush (othermerges);
+  FOREACHmerge_(othermerges) {
+    if (merge->type != MRGridge) 
+    	continue;
+    facet1= merge->facet1;
+    facet2= merge->facet2;
+    while (facet1->visible)    	 /* must exist, no qh_merge_degenredunant */
+      facet1= facet1->f.replace; /* previously merged facet */
+    while (facet2->visible)
+      facet2= facet2->f.replace; /* previously merged facet */
+    if (facet1 == facet2)
+      continue;
+    if (!qh_setin (facet2->neighbors, facet1)) {
+      fprintf (qh ferr, "qhull internal error (qh_forcedmerges): f%d and f%d had a duplicate ridge but as f%d and f%d they are no longer neighbors\n",
+	       merge->facet1->id, merge->facet2->id, facet1->id, facet2->id);
+      qh_errexit2 (qh_ERRqhull, facet1, facet2);
+    }
+    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+      qhmem.IStracing= qh IStracing= qh TRACElevel;
+    dist1= qh_getdistance (facet1, facet2, &mindist1, &maxdist1);
+    dist2= qh_getdistance (facet2, facet1, &mindist2, &maxdist2);
+    trace0((qh ferr, "qh_forcedmerges: duplicate ridge between f%d and f%d, dist %2.2g and reverse dist %2.2g during p%d\n",
+	    facet1->id, facet2->id, dist1, dist2, qh furthest_id));
+    if (dist1 < dist2) 
+      qh_mergefacet (facet1, facet2, &mindist1, &maxdist1, !qh_MERGEapex);
+    else {
+      qh_mergefacet (facet2, facet1, &mindist2, &maxdist2, !qh_MERGEapex);
+      dist1= dist2;
+      facet1= facet2;
+    }
+    if (facet1->flipped) {
+      zinc_(Zmergeflipdup);
+      numflip++;
+    }else
+      nummerge++;
+    if (qh PRINTstatistics) {
+      zinc_(Zduplicate);
+      wadd_(Wduplicatetot, dist1);
+      wmax_(Wduplicatemax, dist1);
+    }
+  }
+  FOREACHmerge_(othermerges) {
+    if (merge->type == MRGridge)
+      qh_memfree (merge, sizeof(mergeT));
+    else
+      qh_setappend (&qh facet_mergeset, merge);
+  }
+  qh_settempfree (&othermerges);
+  if (nummerge)
+    *wasmerge= True;
+  trace1((qh ferr, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n", 
+                nummerge, numflip));
+} /* forcedmerges */
+
+
+/*---------------------------------
+  
+  qh_getmergeset( facetlist )
+    determines nonconvex facets on facetlist
+    tests !tested ridges and nonconvex ridges of !tested facets
+
+  returns:
+    returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged
+    all ridges tested
+  
+  notes:
+    assumes no nonconvex ridges with both facets tested
+    uses facet->tested/ridge->tested to prevent duplicate tests
+    can not limit tests to modified ridges since the centrum changed
+    uses qh.visit_id
+  
+  see:
+    qh_getmergeset_initial()
+
+  design:
+    for each facet on facetlist
+      for each ridge of facet
+        if untested ridge
+          test ridge for convexity
+          if non-convex
+            append ridge to qh.facet_mergeset
+    sort qh.facet_mergeset by angle  
+*/
+void qh_getmergeset(facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int nummerges;
+  
+  nummerges= qh_setsize (qh facet_mergeset);
+  trace4((qh ferr, "qh_getmergeset: started.\n"));
+  qh visit_id++;
+  FORALLfacet_(facetlist) {
+    if (facet->tested)
+      continue;
+    facet->visitid= qh visit_id;
+    facet->tested= True;  /* must be non-simplicial due to merge */
+    FOREACHneighbor_(facet)
+      neighbor->seen= False;
+    FOREACHridge_(facet->ridges) {
+      if (ridge->tested && !ridge->nonconvex)
+	continue;
+      /* if tested & nonconvex, need to append merge */
+      neighbor= otherfacet_(ridge, facet);
+      if (neighbor->seen) {
+	ridge->tested= True;
+	ridge->nonconvex= False;
+      }else if (neighbor->visitid != qh visit_id) {
+        ridge->tested= True;
+        ridge->nonconvex= False;
+	neighbor->seen= True;      /* only one ridge is marked nonconvex */
+	if (qh_test_appendmerge (facet, neighbor))
+	  ridge->nonconvex= True;
+      }
+    }
+  }
+  nummerges= qh_setsize (qh facet_mergeset);
+  if (qh ANGLEmerge)
+    qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_compareangle);
+  else
+    qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_comparemerge);
+  if (qh POSTmerging) {
+    zadd_(Zmergesettot2, nummerges);
+  }else {
+    zadd_(Zmergesettot, nummerges);
+    zmax_(Zmergesetmax, nummerges);
+  }
+  trace2((qh ferr, "qh_getmergeset: %d merges found\n", nummerges));
+} /* getmergeset */
+
+
+/*---------------------------------
+  
+  qh_getmergeset_initial( facetlist )
+    determine initial qh.facet_mergeset for facets
+    tests all facet/neighbor pairs on facetlist
+
+  returns:
+    sorted qh.facet_mergeset with nonconvex ridges
+    sets facet->tested, ridge->tested, and ridge->nonconvex
+
+  notes:
+    uses visit_id, assumes ridge->nonconvex is False
+
+  see:
+    qh_getmergeset()
+
+  design:
+    for each facet on facetlist
+      for each untested neighbor of facet
+        test facet and neighbor for convexity
+        if non-convex
+          append merge to qh.facet_mergeset
+          mark one of the ridges as nonconvex
+    sort qh.facet_mergeset by angle
+*/
+void qh_getmergeset_initial (facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int nummerges;
+
+  qh visit_id++;
+  FORALLfacet_(facetlist) {
+    facet->visitid= qh visit_id;
+    facet->tested= True;
+    FOREACHneighbor_(facet) {
+      if (neighbor->visitid != qh visit_id) {
+        if (qh_test_appendmerge (facet, neighbor)) {
+          FOREACHridge_(neighbor->ridges) {
+            if (facet == otherfacet_(ridge, neighbor)) {
+              ridge->nonconvex= True;
+              break;	/* only one ridge is marked nonconvex */
+            }
+          }
+        }
+      }
+    }
+    FOREACHridge_(facet->ridges)
+      ridge->tested= True;
+  }
+  nummerges= qh_setsize (qh facet_mergeset);
+  if (qh ANGLEmerge)
+    qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_compareangle);
+  else
+    qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_comparemerge);
+  if (qh POSTmerging) {
+    zadd_(Zmergeinittot2, nummerges);
+  }else {
+    zadd_(Zmergeinittot, nummerges);
+    zmax_(Zmergeinitmax, nummerges);
+  }
+  trace2((qh ferr, "qh_getmergeset_initial: %d merges found\n", nummerges));
+} /* getmergeset_initial */
+
+
+/*---------------------------------
+  
+  qh_hashridge( hashtable, hashsize, ridge, oldvertex )
+    add ridge to hashtable without oldvertex
+
+  notes:
+    assumes hashtable is large enough
+
+  design:
+    determine hash value for ridge without oldvertex
+    find next empty slot for ridge
+*/
+void qh_hashridge (setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
+  int hash;
+  ridgeT *ridgeA;
+
+  hash= (int)qh_gethash (hashsize, ridge->vertices, qh hull_dim-1, 0, oldvertex);
+  while (True) {
+    if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
+      SETelem_(hashtable, hash)= ridge;
+      break;
+    }else if (ridgeA == ridge)
+      break;
+    if (++hash == hashsize)
+      hash= 0;
+  }
+} /* hashridge */
+
+
+/*---------------------------------
+  
+  qh_hashridge_find( hashtable, hashsize, ridge, vertex, oldvertex, hashslot )
+    returns matching ridge without oldvertex in hashtable 
+      for ridge without vertex
+    if oldvertex is NULL 
+      matches with any one skip
+
+  returns:
+    matching ridge or NULL
+    if no match,
+      if ridge already in   table
+        hashslot= -1 
+      else 
+        hashslot= next NULL index
+        
+  notes:
+    assumes hashtable is large enough
+    can't match ridge to itself
+
+  design:
+    get hash value for ridge without vertex
+    for each hashslot
+      return match if ridge matches ridgeA without oldvertex
+*/
+ridgeT *qh_hashridge_find (setT *hashtable, int hashsize, ridgeT *ridge, 
+              vertexT *vertex, vertexT *oldvertex, int *hashslot) {
+  int hash;
+  ridgeT *ridgeA;
+
+  *hashslot= 0;
+  zinc_(Zhashridge);
+  hash= (int)qh_gethash (hashsize, ridge->vertices, qh hull_dim-1, 0, vertex);
+  while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) {
+    if (ridgeA == ridge)
+      *hashslot= -1;      
+    else {
+      zinc_(Zhashridgetest);
+      if (qh_setequal_except (ridge->vertices, vertex, ridgeA->vertices, oldvertex))
+        return ridgeA;
+    }
+    if (++hash == hashsize)
+      hash= 0;
+  }
+  if (!*hashslot)
+    *hashslot= hash;
+  return NULL;
+} /* hashridge_find */
+
+
+/*---------------------------------
+  
+  qh_makeridges( facet )
+    creates explicit ridges between simplicial facets
+
+  returns:
+    facet with ridges and without qh_MERGEridge
+    ->simplicial is False
+  
+  notes:
+    allows qh_MERGEridge flag
+    uses existing ridges
+    duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges)
+
+  see:
+    qh_mergecycle_ridges()
+
+  design:
+    look for qh_MERGEridge neighbors
+    mark neighbors that already have ridges
+    for each unprocessed neighbor of facet    
+      create a ridge for neighbor and facet
+    if any qh_MERGEridge neighbors
+      delete qh_MERGEridge flags (already handled by qh_mark_dupridges)
+*/
+void qh_makeridges(facetT *facet) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  int neighbor_i, neighbor_n;
+  boolT toporient, mergeridge= False;
+  
+  if (!facet->simplicial)
+    return;
+  trace4((qh ferr, "qh_makeridges: make ridges for f%d\n", facet->id));
+  facet->simplicial= False;
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge)
+      mergeridge= True;
+    else
+      neighbor->seen= False;
+  }
+  FOREACHridge_(facet->ridges)
+    otherfacet_(ridge, facet)->seen= True;
+  FOREACHneighbor_i_(facet) {
+    if (neighbor == qh_MERGEridge)
+      continue;  /* fixed by qh_mark_dupridges */
+    else if (!neighbor->seen) {  /* no current ridges */
+      ridge= qh_newridge();
+      ridge->vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
+					                  neighbor_i, 0);
+      toporient= facet->toporient ^ (neighbor_i & 0x1);
+      if (toporient) {
+        ridge->top= facet;
+        ridge->bottom= neighbor;
+      }else {
+        ridge->top= neighbor;
+        ridge->bottom= facet;
+      }
+#if 0 /* this also works */
+      flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);
+      if (facet->toporient ^ (skip1 & 0x1) ^ flip) {
+        ridge->top= neighbor;
+        ridge->bottom= facet;
+      }else {
+        ridge->top= facet;
+        ridge->bottom= neighbor;
+      }
+#endif
+      qh_setappend(&(facet->ridges), ridge);
+      qh_setappend(&(neighbor->ridges), ridge);
+    }
+  }
+  if (mergeridge) {
+    while (qh_setdel (facet->neighbors, qh_MERGEridge))
+      ; /* delete each one */
+  }
+} /* makeridges */
+
+
+/*---------------------------------
+  
+  qh_mark_dupridges( facetlist )
+    add duplicated ridges to qh.facet_mergeset
+    facet->dupridge is true
+
+  returns:
+    duplicate ridges on qh.facet_mergeset
+    ->mergeridge/->mergeridge2 set
+    duplicate ridges marked by qh_MERGEridge and both sides facet->dupridge
+    no MERGEridges in neighbor sets
+    
+  notes:
+    duplicate ridges occur when the horizon is pinched,
+        i.e. a subridge occurs in more than two horizon ridges.
+    could rename vertices that pinch the horizon
+    uses qh.visit_id
+
+  design:
+    for all facets on facetlist
+      if facet contains a duplicate ridge
+        for each neighbor of facet
+          if neighbor marked qh_MERGEridge (one side of the merge)
+            set facet->mergeridge      
+          else
+            if neighbor contains a duplicate ridge 
+            and the back link is qh_MERGEridge
+              append duplicate ridge to qh.facet_mergeset
+   for each duplicate ridge
+     make ridge sets in preparation for merging
+     remove qh_MERGEridge from neighbor set
+   for each duplicate ridge
+     restore the missing neighbor from the neighbor set that was qh_MERGEridge
+     add the missing ridge for this neighbor
+*/
+void qh_mark_dupridges(facetT *facetlist) {
+  facetT *facet, *neighbor, **neighborp;
+  int nummerge=0;
+  mergeT *merge, **mergep;
+  
+
+  trace4((qh ferr, "qh_mark_dupridges: identify duplicate ridges\n"));  
+  FORALLfacet_(facetlist) {
+    if (facet->dupridge) {
+      FOREACHneighbor_(facet) {
+        if (neighbor == qh_MERGEridge) {
+	  facet->mergeridge= True;
+	  continue;
+	}
+        if (neighbor->dupridge
+	&& !qh_setin (neighbor->neighbors, facet)) { /* qh_MERGEridge */
+	  qh_appendmergeset (facet, neighbor, MRGridge, NULL);
+	  facet->mergeridge2= True;
+	  facet->mergeridge= True;
+	  nummerge++;
+	}
+      }
+    }
+  }
+  if (!nummerge)
+    return;
+  FORALLfacet_(facetlist) {            /* gets rid of qh_MERGEridge */
+    if (facet->mergeridge && !facet->mergeridge2)   
+      qh_makeridges (facet);
+  }
+  FOREACHmerge_(qh facet_mergeset) {   /* restore the missing neighbors */
+    if (merge->type == MRGridge) {
+      qh_setappend (&merge->facet2->neighbors, merge->facet1);
+      qh_makeridges (merge->facet1);   /* and the missing ridges */
+    }
+  }
+  trace1((qh ferr, "qh_mark_dupridges: found %d duplicated ridges\n", 
+                nummerge));
+} /* mark_dupridges */
+
+/*---------------------------------
+  
+  qh_maydropneighbor( facet )
+    drop neighbor relationship if no ridge between facet and neighbor
+
+  returns:
+    neighbor sets updated
+    appends degenerate facets to qh.facet_mergeset
+  
+  notes:
+    won't cause redundant facets since vertex inclusion is the same
+    may drop vertex and neighbor if no ridge
+    uses qh.visit_id
+
+  design:
+    visit all neighbors with ridges
+    for each unvisited neighbor of facet
+      delete neighbor and facet from the neighbor sets
+      if neighbor becomes degenerate
+        append neighbor to qh.degen_mergeset
+    if facet is degenerate
+      append facet to qh.degen_mergeset
+*/
+void qh_maydropneighbor (facetT *facet) {
+  ridgeT *ridge, **ridgep;
+  realT angledegen= qh_ANGLEdegen;
+  facetT *neighbor, **neighborp;
+
+  qh visit_id++;
+  trace4((qh ferr, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
+	  facet->id));
+  FOREACHridge_(facet->ridges) {
+    ridge->top->visitid= qh visit_id;
+    ridge->bottom->visitid= qh visit_id;
+  }
+  FOREACHneighbor_(facet) {
+    if (neighbor->visitid != qh visit_id) {
+      trace0((qh ferr, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors during p%d\n",
+	    facet->id, neighbor->id, qh furthest_id));
+      zinc_(Zdropneighbor);
+      qh_setdel (facet->neighbors, neighbor);
+      neighborp--;  /* repeat, deleted a neighbor */
+      qh_setdel (neighbor->neighbors, facet);
+      if (qh_setsize (neighbor->neighbors) < qh hull_dim) {
+        zinc_(Zdropdegen);
+        qh_appendmergeset (neighbor, neighbor, MRGdegen, &angledegen);
+        trace2((qh ferr, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
+      }
+    }
+  }
+  if (qh_setsize (facet->neighbors) < qh hull_dim) {
+    zinc_(Zdropdegen);
+    qh_appendmergeset (facet, facet, MRGdegen, &angledegen);
+    trace2((qh ferr, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
+  }
+} /* maydropneighbor */
+
+
+/*---------------------------------
+  
+  qh_merge_degenredundant()
+    merge all degenerate and redundant facets
+    qh.degen_mergeset contains merges from qh_degen_redundant_neighbors()
+
+  returns:
+    number of merges performed
+    resets facet->degenerate/redundant
+    if deleted (visible) facet has no neighbors
+      sets ->f.replace to NULL
+
+  notes:
+    redundant merges happen before degenerate ones
+    merging and renaming vertices can result in degen/redundant facets
+
+  design:
+    for each merge on qh.degen_mergeset
+      if redundant merge
+        if non-redundant facet merged into redundant facet
+          recheck facet for redundancy
+        else
+          merge redundant facet into other facet
+*/
+int qh_merge_degenredundant (void) {
+  int size;
+  mergeT *merge;
+  facetT *bestneighbor, *facet1, *facet2;
+  realT dist, mindist, maxdist;
+  vertexT *vertex, **vertexp;
+  int nummerges= 0;
+  mergeType mergetype;
+
+  while ((merge= (mergeT*)qh_setdellast (qh degen_mergeset))) {
+    facet1= merge->facet1;
+    facet2= merge->facet2;
+    mergetype= merge->type;
+    qh_memfree (merge, sizeof(mergeT));
+    if (facet1->visible)
+      continue;
+    facet1->degenerate= False; 
+    facet1->redundant= False; 
+    if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+      qhmem.IStracing= qh IStracing= qh TRACElevel;
+    if (mergetype == MRGredundant) {
+      zinc_(Zneighbor);
+      while (facet2->visible) {
+        if (!facet2->f.replace) {
+          fprintf (qh ferr, "qhull internal error (qh_merge_degenredunant): f%d redundant but f%d has no replacement\n",
+	       facet1->id, facet2->id);
+          qh_errexit2 (qh_ERRqhull, facet1, facet2);
+        }
+        facet2= facet2->f.replace;
+      }
+      if (facet1 == facet2) {
+	qh_degen_redundant_facet (facet1); /* in case of others */
+	continue;
+      }
+      trace2((qh ferr, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n",
+	    facet1->id, facet2->id));
+      qh_mergefacet(facet1, facet2, NULL, NULL, !qh_MERGEapex);
+      /* merge distance is already accounted for */
+      nummerges++;
+    }else {  /* mergetype == MRGdegen, other merges may have fixed */
+      if (!(size= qh_setsize (facet1->neighbors))) {
+        zinc_(Zdelfacetdup);
+        trace2((qh ferr, "qh_merge_degenredundant: facet f%d has no neighbors.  Deleted\n", facet1->id));
+        qh_willdelete (facet1, NULL);
+        FOREACHvertex_(facet1->vertices) {
+  	  qh_setdel (vertex->neighbors, facet1);
+	  if (!SETfirst_(vertex->neighbors)) {
+	    zinc_(Zdegenvertex);
+	    trace2((qh ferr, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
+         	 vertex->id, facet1->id));
+	    vertex->deleted= True;
+	    qh_setappend (&qh del_vertices, vertex);
+	  }
+        }
+        nummerges++;
+      }else if (size < qh hull_dim) {
+        bestneighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
+        trace2((qh ferr, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
+	      facet1->id, size, bestneighbor->id, dist));
+        qh_mergefacet(facet1, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
+        nummerges++;
+        if (qh PRINTstatistics) {
+	  zinc_(Zdegen);
+	  wadd_(Wdegentot, dist);
+	  wmax_(Wdegenmax, dist);
+        }
+      }	/* else, another merge fixed the degeneracy and redundancy tested */
+    }
+  }
+  return nummerges;
+} /* merge_degenredundant */
+
+/*---------------------------------
+  
+  qh_merge_nonconvex( facet1, facet2, mergetype )
+    remove non-convex ridge between facet1 into facet2 
+    mergetype gives why the facet's are non-convex
+
+  returns:
+    merges one of the facets into the best neighbor
+    
+  design:
+    if one of the facets is a new facet
+      prefer merging new facet into old facet
+    find best neighbors for both facets
+    merge the nearest facet into its best neighbor
+    update the statistics
+*/
+void qh_merge_nonconvex (facetT *facet1, facetT *facet2, mergeType mergetype) {
+  facetT *bestfacet, *bestneighbor, *neighbor;
+  realT dist, dist2, mindist, mindist2, maxdist, maxdist2;
+
+  if (qh TRACEmerge-1 == zzval_(Ztotmerge))
+    qhmem.IStracing= qh IStracing= qh TRACElevel;
+  trace3((qh ferr, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n",
+      zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype));
+  /* concave or coplanar */
+  if (!facet1->newfacet) {
+    bestfacet= facet2;   /* avoid merging old facet if new is ok */
+    facet2= facet1;
+    facet1= bestfacet;
+  }else
+    bestfacet= facet1;
+  bestneighbor= qh_findbestneighbor(bestfacet, &dist, &mindist, &maxdist);
+  neighbor= qh_findbestneighbor(facet2, &dist2, &mindist2, &maxdist2);
+  if (dist < dist2) {
+    qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
+  }else if (qh AVOIDold && !facet2->newfacet
+  && ((mindist >= -qh MAXcoplanar && maxdist <= qh max_outside)
+       || dist * 1.5 < dist2)) {
+    zinc_(Zavoidold);
+    wadd_(Wavoidoldtot, dist);
+    wmax_(Wavoidoldmax, dist);
+    trace2((qh ferr, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g.  Use f%d dist %2.2g instead\n",
+           facet2->id, dist2, facet1->id, dist2));
+    qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex);
+  }else {
+    qh_mergefacet(facet2, neighbor, &mindist2, &maxdist2, !qh_MERGEapex);
+    dist= dist2;
+  }
+  if (qh PRINTstatistics) {
+    if (mergetype == MRGanglecoplanar) {
+      zinc_(Zacoplanar);
+      wadd_(Wacoplanartot, dist);
+      wmax_(Wacoplanarmax, dist);
+    }else if (mergetype == MRGconcave) {
+      zinc_(Zconcave);
+      wadd_(Wconcavetot, dist);
+      wmax_(Wconcavemax, dist);
+    }else { /* MRGcoplanar */
+      zinc_(Zcoplanar);
+      wadd_(Wcoplanartot, dist);
+      wmax_(Wcoplanarmax, dist);
+    }
+  }
+} /* merge_nonconvex */
+
+/*---------------------------------
+  
+  qh_mergecycle( samecycle, newfacet )
+    merge a cycle of facets starting at samecycle into a newfacet 
+    newfacet is a horizon facet with ->normal
+    samecycle facets are simplicial from an apex
+
+  returns:
+    initializes vertex neighbors on first merge
+    samecycle deleted (placed on qh.visible_list)
+    newfacet at end of qh.facet_list
+    deleted vertices on qh.del_vertices
+
+  see:
+    qh_mergefacet()
+    called by qh_mergecycle_all() for multiple, same cycle facets
+
+  design:
+    make vertex neighbors if necessary
+    make ridges for newfacet
+    merge neighbor sets of samecycle into newfacet
+    merge ridges of samecycle into newfacet
+    merge vertex neighbors of samecycle into newfacet
+    make apex of samecycle the apex of newfacet
+    if newfacet wasn't a new facet
+      add its vertices to qh.newvertex_list
+    delete samecycle facets a make newfacet a newfacet
+*/
+void qh_mergecycle (facetT *samecycle, facetT *newfacet) {
+  int traceonce= False, tracerestore= 0;
+  vertexT *apex;
+#ifndef qh_NOtrace
+  facetT *same;
+#endif
+
+  if (newfacet->tricoplanar) {
+    if (!qh TRInormals) {
+      fprintf (qh ferr, "qh_mergecycle: does not work for tricoplanar facets.  Use option 'Q11'\n");
+      qh_errexit (qh_ERRqhull, newfacet, NULL);
+    }
+    newfacet->tricoplanar= False;
+    newfacet->keepcentrum= False;
+  }
+  if (!qh VERTEXneighbors)
+    qh_vertexneighbors();
+  zzinc_(Ztotmerge);
+  if (qh REPORTfreq2 && qh POSTmerging) {
+    if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
+      qh_tracemerging();
+  }
+#ifndef qh_NOtrace
+  if (qh TRACEmerge == zzval_(Ztotmerge))
+    qhmem.IStracing= qh IStracing= qh TRACElevel;
+  trace2((qh ferr, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n", 
+        zzval_(Ztotmerge), samecycle->id, newfacet->id));
+  if (newfacet == qh tracefacet) {
+    tracerestore= qh IStracing;
+    qh IStracing= 4;
+    fprintf (qh ferr, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n",
+	       zzval_(Ztotmerge), samecycle->id, newfacet->id,  qh furthest_id);
+    traceonce= True;
+  }
+  if (qh IStracing >=4) {
+    fprintf (qh ferr, "  same cycle:");
+    FORALLsame_cycle_(samecycle)
+      fprintf(qh ferr, " f%d", same->id);
+    fprintf (qh ferr, "\n");
+  }
+  if (qh IStracing >=4)
+    qh_errprint ("MERGING CYCLE", samecycle, newfacet, NULL, NULL);
+#endif /* !qh_NOtrace */
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  qh_makeridges (newfacet);
+  qh_mergecycle_neighbors (samecycle, newfacet);
+  qh_mergecycle_ridges (samecycle, newfacet);
+  qh_mergecycle_vneighbors (samecycle, newfacet);
+  if (SETfirstt_(newfacet->vertices, vertexT) != apex) 
+    qh_setaddnth (&newfacet->vertices, 0, apex);  /* apex has last id */
+  if (!newfacet->newfacet)
+    qh_newvertices (newfacet->vertices);
+  qh_mergecycle_facets (samecycle, newfacet);
+  qh_tracemerge (samecycle, newfacet);
+  /* check for degen_redundant_neighbors after qh_forcedmerges() */
+  if (traceonce) {
+    fprintf (qh ferr, "qh_mergecycle: end of trace facet\n");
+    qh IStracing= tracerestore;
+  }
+} /* mergecycle */
+
+/*---------------------------------
+  
+  qh_mergecycle_all( facetlist, wasmerge )
+    merge all samecycles of coplanar facets into horizon
+    don't merge facets with ->mergeridge (these already have ->normal)
+    all facets are simplicial from apex
+    all facet->cycledone == False
+
+  returns:
+    all newfacets merged into coplanar horizon facets
+    deleted vertices on  qh.del_vertices
+    sets wasmerge if any merge
+
+  see:
+    calls qh_mergecycle for multiple, same cycle facets
+
+  design:
+    for each facet on facetlist
+      skip facets with duplicate ridges and normals
+      check that facet is in a samecycle (->mergehorizon)
+      if facet only member of samecycle
+	sets vertex->delridge for all vertices except apex
+        merge facet into horizon
+      else
+        mark all facets in samecycle
+        remove facets with duplicate ridges from samecycle
+        merge samecycle into horizon (deletes facets from facetlist)
+*/
+void qh_mergecycle_all (facetT *facetlist, boolT *wasmerge) {
+  facetT *facet, *same, *prev, *horizon;
+  facetT *samecycle= NULL, *nextfacet, *nextsame;
+  vertexT *apex, *vertex, **vertexp;
+  int cycles=0, total=0, facets, nummerge;
+
+  trace2((qh ferr, "qh_mergecycle_all: begin\n"));
+  for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) {
+    if (facet->normal)
+      continue;
+    if (!facet->mergehorizon) {
+      fprintf (qh ferr, "qh_mergecycle_all: f%d without normal\n", facet->id);
+      qh_errexit (qh_ERRqhull, facet, NULL);
+    }
+    horizon= SETfirstt_(facet->neighbors, facetT);
+    if (facet->f.samecycle == facet) {
+      zinc_(Zonehorizon);  
+      /* merge distance done in qh_findhorizon */
+      apex= SETfirstt_(facet->vertices, vertexT);
+      FOREACHvertex_(facet->vertices) {
+	if (vertex != apex)
+          vertex->delridge= True;
+      }
+      horizon->f.newcycle= NULL;
+      qh_mergefacet (facet, horizon, NULL, NULL, qh_MERGEapex);
+    }else {
+      samecycle= facet;
+      facets= 0;
+      prev= facet;
+      for (same= facet->f.samecycle; same;  /* FORALLsame_cycle_(facet) */
+	   same= (same == facet ? NULL :nextsame)) { /* ends at facet */
+	nextsame= same->f.samecycle;
+        if (same->cycledone || same->visible)
+          qh_infiniteloop (same);
+        same->cycledone= True;
+        if (same->normal) { 
+          prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */
+	  same->f.samecycle= NULL;
+        }else {
+          prev= same;
+	  facets++;
+	}
+      }
+      while (nextfacet && nextfacet->cycledone)  /* will delete samecycle */
+	nextfacet= nextfacet->next;
+      horizon->f.newcycle= NULL;
+      qh_mergecycle (samecycle, horizon);
+      nummerge= horizon->nummerge + facets;
+      if (nummerge > qh_MAXnummerge) 
+      	horizon->nummerge= qh_MAXnummerge;
+      else
+        horizon->nummerge= nummerge;
+      zzinc_(Zcyclehorizon);
+      total += facets;
+      zzadd_(Zcyclefacettot, facets);
+      zmax_(Zcyclefacetmax, facets);
+    }
+    cycles++;
+  }
+  if (cycles)
+    *wasmerge= True;
+  trace1((qh ferr, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles));
+} /* mergecycle_all */
+
+/*---------------------------------
+  
+  qh_mergecycle_facets( samecycle, newfacet )
+    finish merge of samecycle into newfacet
+
+  returns:
+    samecycle prepended to visible_list for later deletion and partitioning
+      each facet->f.replace == newfacet
+      
+    newfacet moved to end of qh.facet_list
+      makes newfacet a newfacet (get's facet1->id if it was old)
+      sets newfacet->newmerge
+      clears newfacet->center (unless merging into a large facet)
+      clears newfacet->tested and ridge->tested for facet1
+      
+    adds neighboring facets to facet_mergeset if redundant or degenerate
+
+  design:
+    make newfacet a new facet and set its flags
+    move samecycle facets to qh.visible_list for later deletion
+    unless newfacet is large
+      remove its centrum
+*/
+void qh_mergecycle_facets (facetT *samecycle, facetT *newfacet) {
+  facetT *same, *next;
+  
+  trace4((qh ferr, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n"));  
+  qh_removefacet(newfacet);  /* append as a newfacet to end of qh facet_list */
+  qh_appendfacet(newfacet);
+  newfacet->newfacet= True;
+  newfacet->simplicial= False;
+  newfacet->newmerge= True;
+  
+  for (same= samecycle->f.samecycle; same; same= (same == samecycle ?  NULL : next)) {
+    next= same->f.samecycle;  /* reused by willdelete */
+    qh_willdelete (same, newfacet);
+  }
+  if (newfacet->center 
+      && qh_setsize (newfacet->vertices) <= qh hull_dim + qh_MAXnewcentrum) {
+    qh_memfree (newfacet->center, qh normal_size);
+    newfacet->center= NULL;
+  }
+  trace3((qh ferr, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n", 
+             samecycle->id, newfacet->id));
+} /* mergecycle_facets */
+
+/*---------------------------------
+  
+  qh_mergecycle_neighbors( samecycle, newfacet )
+    add neighbors for samecycle facets to newfacet
+
+  returns:
+    newfacet with updated neighbors and vice-versa
+    newfacet has ridges
+    all neighbors of newfacet marked with qh.visit_id
+    samecycle facets marked with qh.visit_id-1
+    ridges updated for simplicial neighbors of samecycle with a ridge
+
+  notes:
+    assumes newfacet not in samecycle
+    usually, samecycle facets are new, simplicial facets without internal ridges 
+      not so if horizon facet is coplanar to two different samecycles
+  
+  see:
+    qh_mergeneighbors()
+
+  design:
+    check samecycle
+    delete neighbors from newfacet that are also in samecycle
+    for each neighbor of a facet in samecycle
+      if neighbor is simplicial
+        if first visit
+          move the neighbor relation to newfacet
+          update facet links for its ridges
+        else
+          make ridges for neighbor
+          remove samecycle reference
+      else
+        update neighbor sets
+*/
+void qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet) {
+  facetT *same, *neighbor, **neighborp;
+  int delneighbors= 0, newneighbors= 0;
+  unsigned int samevisitid;
+  ridgeT *ridge, **ridgep;
+
+  samevisitid= ++qh visit_id;
+  FORALLsame_cycle_(samecycle) {
+    if (same->visitid == samevisitid || same->visible)
+      qh_infiniteloop (samecycle);
+    same->visitid= samevisitid;
+  }
+  newfacet->visitid= ++qh visit_id;
+  trace4((qh ferr, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n"));  
+  FOREACHneighbor_(newfacet) {
+    if (neighbor->visitid == samevisitid) {
+      SETref_(neighbor)= NULL;  /* samecycle neighbors deleted */
+      delneighbors++;
+    }else
+      neighbor->visitid= qh visit_id;
+  }
+  qh_setcompact (newfacet->neighbors);
+
+  trace4((qh ferr, "qh_mergecycle_neighbors: update neighbors\n"));  
+  FORALLsame_cycle_(samecycle) {
+    FOREACHneighbor_(same) {
+      if (neighbor->visitid == samevisitid)
+	continue;
+      if (neighbor->simplicial) {
+	if (neighbor->visitid != qh visit_id) {
+	  qh_setappend (&newfacet->neighbors, neighbor);
+	  qh_setreplace (neighbor->neighbors, same, newfacet);
+	  newneighbors++;
+	  neighbor->visitid= qh visit_id;
+	  FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */
+	    if (ridge->top == same) {
+	      ridge->top= newfacet;
+	      break;
+	    }else if (ridge->bottom == same) {
+	      ridge->bottom= newfacet;
+	      break;
+	    }
+	  }
+	}else {
+	  qh_makeridges (neighbor);
+	  qh_setdel (neighbor->neighbors, same);
+	  /* same can't be horizon facet for neighbor */
+	}
+      }else { /* non-simplicial neighbor */
+        qh_setdel (neighbor->neighbors, same);
+        if (neighbor->visitid != qh visit_id) {
+          qh_setappend (&neighbor->neighbors, newfacet);
+          qh_setappend (&newfacet->neighbors, neighbor);
+          neighbor->visitid= qh visit_id;
+          newneighbors++;
+        } 
+      }
+    }
+  }
+  trace2((qh ferr, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n", 
+             delneighbors, newneighbors));
+} /* mergecycle_neighbors */
+
+/*---------------------------------
+  
+  qh_mergecycle_ridges( samecycle, newfacet )
+    add ridges/neighbors for facets in samecycle to newfacet
+    all new/old neighbors of newfacet marked with qh.visit_id
+    facets in samecycle marked with qh.visit_id-1
+    newfacet marked with qh.visit_id
+
+  returns:
+    newfacet has merged ridges
+  
+  notes:
+    ridge already updated for simplicial neighbors of samecycle with a ridge
+
+  see:
+    qh_mergeridges()
+    qh_makeridges()
+
+  design:
+    remove ridges between newfacet and samecycle
+    for each facet in samecycle
+      for each ridge in facet
+        update facet pointers in ridge
+        skip ridges processed in qh_mergecycle_neighors
+        free ridges between newfacet and samecycle
+        free ridges between facets of samecycle (on 2nd visit)
+        append remaining ridges to newfacet
+      if simpilicial facet
+        for each neighbor of facet
+          if simplicial facet
+          and not samecycle facet or newfacet
+            make ridge between neighbor and newfacet
+*/
+void qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet) {
+  facetT *same, *neighbor= NULL;
+  int numold=0, numnew=0;
+  int neighbor_i, neighbor_n;
+  unsigned int samevisitid;
+  ridgeT *ridge, **ridgep;
+  boolT toporient;
+  void **freelistp; /* used !qh_NOmem */
+
+  trace4((qh ferr, "qh_mergecycle_ridges: delete shared ridges from newfacet\n"));  
+  samevisitid= qh visit_id -1;
+  FOREACHridge_(newfacet->ridges) {
+    neighbor= otherfacet_(ridge, newfacet);
+    if (neighbor->visitid == samevisitid)
+      SETref_(ridge)= NULL; /* ridge free'd below */  
+  }
+  qh_setcompact (newfacet->ridges);
+  
+  trace4((qh ferr, "qh_mergecycle_ridges: add ridges to newfacet\n"));  
+  FORALLsame_cycle_(samecycle) {
+    FOREACHridge_(same->ridges) {
+      if (ridge->top == same) {
+        ridge->top= newfacet;
+	neighbor= ridge->bottom;
+      }else if (ridge->bottom == same) {
+	ridge->bottom= newfacet;
+	neighbor= ridge->top;
+      }else if (ridge->top == newfacet || ridge->bottom == newfacet) {
+        qh_setappend (&newfacet->ridges, ridge);
+        numold++;  /* already set by qh_mergecycle_neighbors */
+	continue;  
+      }else {
+	fprintf (qh ferr, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id);
+	qh_errexit (qh_ERRqhull, NULL, ridge);
+      }
+      if (neighbor == newfacet) {
+        qh_setfree(&(ridge->vertices)); 
+        qh_memfree_(ridge, sizeof(ridgeT), freelistp);
+        numold++;
+      }else if (neighbor->visitid == samevisitid) {
+	qh_setdel (neighbor->ridges, ridge);
+	qh_setfree(&(ridge->vertices)); 
+	qh_memfree_(ridge, sizeof(ridgeT), freelistp);
+	numold++;
+      }else {
+        qh_setappend (&newfacet->ridges, ridge);
+        numold++;
+      }
+    }
+    if (same->ridges)
+      qh_settruncate (same->ridges, 0);
+    if (!same->simplicial)
+      continue;
+    FOREACHneighbor_i_(same) {       /* note: !newfact->simplicial */
+      if (neighbor->visitid != samevisitid && neighbor->simplicial) {
+        ridge= qh_newridge();
+        ridge->vertices= qh_setnew_delnthsorted (same->vertices, qh hull_dim,
+  					                  neighbor_i, 0);
+        toporient= same->toporient ^ (neighbor_i & 0x1);
+        if (toporient) {
+          ridge->top= newfacet;
+          ridge->bottom= neighbor;
+        }else {
+          ridge->top= neighbor;
+          ridge->bottom= newfacet;
+        }
+        qh_setappend(&(newfacet->ridges), ridge);
+        qh_setappend(&(neighbor->ridges), ridge);
+        numnew++;
+      }
+    }
+  }
+
+  trace2((qh ferr, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n", 
+             numold, numnew));
+} /* mergecycle_ridges */
+
+/*---------------------------------
+  
+  qh_mergecycle_vneighbors( samecycle, newfacet )
+    create vertex neighbors for newfacet from vertices of facets in samecycle
+    samecycle marked with visitid == qh.visit_id - 1
+
+  returns:
+    newfacet vertices with updated neighbors
+    marks newfacet with qh.visit_id-1
+    deletes vertices that are merged away
+    sets delridge on all vertices (faster here than in mergecycle_ridges)
+
+  see:
+    qh_mergevertex_neighbors()
+
+  design:
+    for each vertex of samecycle facet
+      set vertex->delridge
+      delete samecycle facets from vertex neighbors
+      append newfacet to vertex neighbors
+      if vertex only in newfacet
+        delete it from newfacet
+        add it to qh.del_vertices for later deletion
+*/
+void qh_mergecycle_vneighbors (facetT *samecycle, facetT *newfacet) {
+  facetT *neighbor, **neighborp;
+  unsigned int mergeid;
+  vertexT *vertex, **vertexp, *apex;
+  setT *vertices;
+  
+  trace4((qh ferr, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n"));  
+  mergeid= qh visit_id - 1;
+  newfacet->visitid= mergeid;
+  vertices= qh_basevertices (samecycle); /* temp */
+  apex= SETfirstt_(samecycle->vertices, vertexT);
+  qh_setappend (&vertices, apex);
+  FOREACHvertex_(vertices) {
+    vertex->delridge= True;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->visitid == mergeid)
+        SETref_(neighbor)= NULL;
+    }
+    qh_setcompact (vertex->neighbors);
+    qh_setappend (&vertex->neighbors, newfacet);
+    if (!SETsecond_(vertex->neighbors)) {
+      zinc_(Zcyclevertex);
+      trace2((qh ferr, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n",
+        vertex->id, samecycle->id, newfacet->id));
+      qh_setdelsorted (newfacet->vertices, vertex);
+      vertex->deleted= True;
+      qh_setappend (&qh del_vertices, vertex);
+    }
+  }
+  qh_settempfree (&vertices);
+  trace3((qh ferr, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n", 
+             samecycle->id, newfacet->id));
+} /* mergecycle_vneighbors */
+
+/*---------------------------------
+  
+  qh_mergefacet( facet1, facet2, mindist, maxdist, mergeapex )
+    merges facet1 into facet2
+    mergeapex==qh_MERGEapex if merging new facet into coplanar horizon
+    
+  returns:
+    qh.max_outside and qh.min_vertex updated
+    initializes vertex neighbors on first merge
+
+  returns:
+    facet2 contains facet1's vertices, neighbors, and ridges
+      facet2 moved to end of qh.facet_list
+      makes facet2 a newfacet
+      sets facet2->newmerge set
+      clears facet2->center (unless merging into a large facet)
+      clears facet2->tested and ridge->tested for facet1
+
+    facet1 prepended to visible_list for later deletion and partitioning
+      facet1->f.replace == facet2
+
+    adds neighboring facets to facet_mergeset if redundant or degenerate
+
+  notes: 
+    mindist/maxdist may be NULL
+    traces merge if fmax_(maxdist,-mindist) > TRACEdist
+
+  see: 
+    qh_mergecycle()
+
+  design:
+    trace merge and check for degenerate simplex
+    make ridges for both facets
+    update qh.max_outside, qh.max_vertex, qh.min_vertex
+    update facet2->maxoutside and keepcentrum
+    update facet2->nummerge
+    update tested flags for facet2
+    if facet1 is simplicial
+      merge facet1 into facet2
+    else
+      merge facet1's neighbors into facet2
+      merge facet1's ridges into facet2
+      merge facet1's vertices into facet2
+      merge facet1's vertex neighbors into facet2
+      add facet2's vertices to qh.new_vertexlist
+      unless qh_MERGEapex
+        test facet2 for degenerate or redundant neighbors
+      move facet1 to qh.visible_list for later deletion
+      move facet2 to end of qh.newfacet_list
+*/
+void qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex) {
+  boolT traceonce= False;
+  vertexT *vertex, **vertexp;
+  int tracerestore=0, nummerge;
+
+  if (facet1->tricoplanar || facet2->tricoplanar) {
+    if (!qh TRInormals) {
+      fprintf (qh ferr, "qh_mergefacet: does not work for tricoplanar facets.  Use option 'Q11'\n");
+      qh_errexit2 (qh_ERRqhull, facet1, facet2);
+    }
+    if (facet2->tricoplanar) {
+      facet2->tricoplanar= False;
+      facet2->keepcentrum= False;
+    }
+  }
+  zzinc_(Ztotmerge);
+  if (qh REPORTfreq2 && qh POSTmerging) {
+    if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2)
+      qh_tracemerging();
+  }
+#ifndef qh_NOtrace
+  if (qh build_cnt >= qh RERUN) {
+    if (mindist && (-*mindist > qh TRACEdist || *maxdist > qh TRACEdist)) {
+      tracerestore= 0;
+      qh IStracing= qh TRACElevel;
+      traceonce= True;
+      fprintf (qh ferr, "qh_mergefacet: ========= trace wide merge #%d (%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge),
+	     fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh furthest_id);
+    }else if (facet1 == qh tracefacet || facet2 == qh tracefacet) {
+      tracerestore= qh IStracing;
+      qh IStracing= 4;
+      traceonce= True;
+      fprintf (qh ferr, "qh_mergefacet: ========= trace merge #%d involving f%d, furthest is p%d\n",
+		 zzval_(Ztotmerge), qh tracefacet_id,  qh furthest_id);
+    }
+  }
+  if (qh IStracing >= 2) {
+    realT mergemin= -2;
+    realT mergemax= -2;
+    
+    if (mindist) {
+      mergemin= *mindist;
+      mergemax= *maxdist;
+    }
+    fprintf (qh ferr, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g\n", 
+    zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax);
+  }
+#endif /* !qh_NOtrace */
+  if (facet1 == facet2 || facet1->visible || facet2->visible) {
+    fprintf (qh ferr, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet\n",
+	     facet1->id, facet2->id);
+    qh_errexit2 (qh_ERRqhull, facet1, facet2);
+  }
+  if (qh num_facets - qh num_visible <= qh hull_dim + 1) {
+    fprintf(qh ferr, "\n\
+qhull precision error: Only %d facets remain.  Can not merge another\n\
+pair.  The input is too degenerate or the convexity constraints are\n\
+too strong.\n", qh hull_dim+1);
+    if (qh hull_dim >= 5 && !qh MERGEexact)
+      fprintf(qh ferr, "Option 'Qx' may avoid this problem.\n");
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (!qh VERTEXneighbors)
+    qh_vertexneighbors();
+  qh_makeridges(facet1);
+  qh_makeridges(facet2);
+  if (qh IStracing >=4)
+    qh_errprint ("MERGING", facet1, facet2, NULL, NULL);
+  if (mindist) {
+    maximize_(qh max_outside, *maxdist);
+    maximize_(qh max_vertex, *maxdist);
+#if qh_MAXoutside
+    maximize_(facet2->maxoutside, *maxdist);
+#endif
+    minimize_(qh min_vertex, *mindist);
+    if (!facet2->keepcentrum 
+    && (*maxdist > qh WIDEfacet || *mindist < -qh WIDEfacet)) {
+      facet2->keepcentrum= True;
+      zinc_(Zwidefacet);
+    }
+  }
+  nummerge= facet1->nummerge + facet2->nummerge + 1;
+  if (nummerge >= qh_MAXnummerge) 
+    facet2->nummerge= qh_MAXnummerge;
+  else
+    facet2->nummerge= nummerge;
+  facet2->newmerge= True;
+  facet2->dupridge= False;
+  qh_updatetested  (facet1, facet2);
+  if (qh hull_dim > 2 && qh_setsize (facet1->vertices) == qh hull_dim)
+    qh_mergesimplex (facet1, facet2, mergeapex);
+  else {
+    qh vertex_visit++;
+    FOREACHvertex_(facet2->vertices)
+      vertex->visitid= qh vertex_visit;
+    if (qh hull_dim == 2) 
+      qh_mergefacet2d(facet1, facet2);
+    else {
+      qh_mergeneighbors(facet1, facet2);
+      qh_mergevertices(facet1->vertices, &facet2->vertices);
+    }
+    qh_mergeridges(facet1, facet2);
+    qh_mergevertex_neighbors(facet1, facet2);
+    if (!facet2->newfacet)
+      qh_newvertices (facet2->vertices);
+  }
+  if (!mergeapex)
+    qh_degen_redundant_neighbors (facet2, facet1);
+  if (facet2->coplanar || !facet2->newfacet) {
+    zinc_(Zmergeintohorizon);
+  }else if (!facet1->newfacet && facet2->newfacet) {
+    zinc_(Zmergehorizon);
+  }else {
+    zinc_(Zmergenew);
+  }
+  qh_willdelete (facet1, facet2);
+  qh_removefacet(facet2);  /* append as a newfacet to end of qh facet_list */
+  qh_appendfacet(facet2);
+  facet2->newfacet= True;
+  facet2->tested= False;
+  qh_tracemerge (facet1, facet2);
+  if (traceonce) {
+    fprintf (qh ferr, "qh_mergefacet: end of wide tracing\n");
+    qh IStracing= tracerestore;
+  }
+} /* mergefacet */
+
+
+/*---------------------------------
+  
+  qh_mergefacet2d( facet1, facet2 )
+    in 2d, merges neighbors and vertices of facet1 into facet2
+    
+  returns:
+    build ridges for neighbors if necessary
+    facet2 looks like a simplicial facet except for centrum, ridges
+      neighbors are opposite the corresponding vertex
+      maintains orientation of facet2
+
+  notes:
+    qh_mergefacet() retains non-simplicial structures
+      they are not needed in 2d, but later routines may use them
+    preserves qh.vertex_visit for qh_mergevertex_neighbors()
+  
+  design:
+    get vertices and neighbors
+    determine new vertices and neighbors
+    set new vertices and neighbors and adjust orientation
+    make ridges for new neighbor if needed
+*/
+void qh_mergefacet2d (facetT *facet1, facetT *facet2) {
+  vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
+  facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB;
+
+  vertex1A= SETfirstt_(facet1->vertices, vertexT);
+  vertex1B= SETsecondt_(facet1->vertices, vertexT);
+  vertex2A= SETfirstt_(facet2->vertices, vertexT);
+  vertex2B= SETsecondt_(facet2->vertices, vertexT);
+  neighbor1A= SETfirstt_(facet1->neighbors, facetT);
+  neighbor1B= SETsecondt_(facet1->neighbors, facetT);
+  neighbor2A= SETfirstt_(facet2->neighbors, facetT);
+  neighbor2B= SETsecondt_(facet2->neighbors, facetT);
+  if (vertex1A == vertex2A) {
+    vertexA= vertex1B;
+    vertexB= vertex2B;
+    neighborA= neighbor2A;
+    neighborB= neighbor1A;
+  }else if (vertex1A == vertex2B) {
+    vertexA= vertex1B;
+    vertexB= vertex2A;
+    neighborA= neighbor2B;
+    neighborB= neighbor1A;
+  }else if (vertex1B == vertex2A) {
+    vertexA= vertex1A;
+    vertexB= vertex2B;
+    neighborA= neighbor2A;
+    neighborB= neighbor1B;
+  }else { /* 1B == 2B */
+    vertexA= vertex1A;
+    vertexB= vertex2A;
+    neighborA= neighbor2B;
+    neighborB= neighbor1B;
+  }
+  /* vertexB always from facet2, neighborB always from facet1 */
+  if (vertexA->id > vertexB->id) {
+    SETfirst_(facet2->vertices)= vertexA;
+    SETsecond_(facet2->vertices)= vertexB;
+    if (vertexB == vertex2A)
+      facet2->toporient= !facet2->toporient;
+    SETfirst_(facet2->neighbors)= neighborA;
+    SETsecond_(facet2->neighbors)= neighborB;
+  }else {
+    SETfirst_(facet2->vertices)= vertexB;
+    SETsecond_(facet2->vertices)= vertexA;
+    if (vertexB == vertex2B)
+      facet2->toporient= !facet2->toporient;
+    SETfirst_(facet2->neighbors)= neighborB;
+    SETsecond_(facet2->neighbors)= neighborA;
+  }
+  qh_makeridges (neighborB);
+  qh_setreplace(neighborB->neighbors, facet1, facet2);
+  trace4((qh ferr, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n",
+       vertexA->id, neighborB->id, facet1->id, facet2->id));
+} /* mergefacet2d */
+
+
+/*---------------------------------
+  
+  qh_mergeneighbors( facet1, facet2 )
+    merges the neighbors of facet1 into facet2
+
+  see: 
+    qh_mergecycle_neighbors()
+
+  design:
+    for each neighbor of facet1
+      if neighbor is also a neighbor of facet2
+        if neighbor is simpilicial
+          make ridges for later deletion as a degenerate facet
+        update its neighbor set
+      else
+        move the neighbor relation to facet2
+    remove the neighbor relation for facet1 and facet2
+*/
+void qh_mergeneighbors(facetT *facet1, facetT *facet2) {
+  facetT *neighbor, **neighborp;
+
+  trace4((qh ferr, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
+	  facet1->id, facet2->id));
+  qh visit_id++;
+  FOREACHneighbor_(facet2) {
+    neighbor->visitid= qh visit_id;
+  }
+  FOREACHneighbor_(facet1) {
+    if (neighbor->visitid == qh visit_id) {
+      if (neighbor->simplicial)    /* is degen, needs ridges */
+	qh_makeridges (neighbor);
+      if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/
+	qh_setdel (neighbor->neighbors, facet1);
+      else {
+        qh_setdel(neighbor->neighbors, facet2);
+        qh_setreplace(neighbor->neighbors, facet1, facet2);
+      }
+    }else if (neighbor != facet2) {
+      qh_setappend(&(facet2->neighbors), neighbor);
+      qh_setreplace(neighbor->neighbors, facet1, facet2);
+    }
+  }
+  qh_setdel(facet1->neighbors, facet2);  /* here for makeridges */
+  qh_setdel(facet2->neighbors, facet1);
+} /* mergeneighbors */
+
+
+/*---------------------------------
+  
+  qh_mergeridges( facet1, facet2 )
+    merges the ridge set of facet1 into facet2
+
+  returns:
+    may delete all ridges for a vertex
+    sets vertex->delridge on deleted ridges
+
+  see:
+    qh_mergecycle_ridges()
+
+  design:
+    delete ridges between facet1 and facet2
+      mark (delridge) vertices on these ridges for later testing   
+    for each remaining ridge
+      rename facet1 to facet2  
+*/
+void qh_mergeridges(facetT *facet1, facetT *facet2) {
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, **vertexp;
+
+  trace4((qh ferr, "qh_mergeridges: merge ridges of f%d and f%d\n",
+	  facet1->id, facet2->id));
+  FOREACHridge_(facet2->ridges) {
+    if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
+      FOREACHvertex_(ridge->vertices)
+        vertex->delridge= True;
+      qh_delridge(ridge);  /* expensive in high-d, could rebuild */
+      ridgep--; /*repeat*/
+    }
+  }
+  FOREACHridge_(facet1->ridges) {
+    if (ridge->top == facet1)
+      ridge->top= facet2;
+    else
+      ridge->bottom= facet2;
+    qh_setappend(&(facet2->ridges), ridge);
+  }
+} /* mergeridges */
+
+
+/*---------------------------------
+  
+  qh_mergesimplex( facet1, facet2, mergeapex )
+    merge simplicial facet1 into facet2
+    mergeapex==qh_MERGEapex if merging samecycle into horizon facet
+      vertex id is latest (most recently created)
+    facet1 may be contained in facet2
+    ridges exist for both facets
+
+  returns:
+    facet2 with updated vertices, ridges, neighbors
+    updated neighbors for facet1's vertices
+    facet1 not deleted
+    sets vertex->delridge on deleted ridges
+  
+  notes:
+    special case code since this is the most common merge
+    called from qh_mergefacet()
+
+  design:
+    if qh_MERGEapex
+      add vertices of facet2 to qh.new_vertexlist if necessary
+      add apex to facet2
+    else
+      for each ridge between facet1 and facet2
+        set vertex->delridge
+      determine the apex for facet1 (i.e., vertex to be merged)
+      unless apex already in facet2
+        insert apex into vertices for facet2
+      add vertices of facet2 to qh.new_vertexlist if necessary
+      add apex to qh.new_vertexlist if necessary
+      for each vertex of facet1
+        if apex
+          rename facet1 to facet2 in its vertex neighbors
+        else
+          delete facet1 from vertex neighors
+          if only in facet2
+            add vertex to qh.del_vertices for later deletion
+      for each ridge of facet1
+        delete ridges between facet1 and facet2
+        append other ridges to facet2 after renaming facet to facet2
+*/
+void qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex) {
+  vertexT *vertex, **vertexp, *apex;
+  ridgeT *ridge, **ridgep;
+  boolT issubset= False;
+  int vertex_i= -1, vertex_n;
+  facetT *neighbor, **neighborp, *otherfacet;
+
+  if (mergeapex) {
+    if (!facet2->newfacet)
+      qh_newvertices (facet2->vertices);  /* apex is new */
+    apex= SETfirstt_(facet1->vertices, vertexT);
+    if (SETfirstt_(facet2->vertices, vertexT) != apex) 
+      qh_setaddnth (&facet2->vertices, 0, apex);  /* apex has last id */
+    else
+      issubset= True;
+  }else {
+    zinc_(Zmergesimplex);
+    FOREACHvertex_(facet1->vertices)
+      vertex->seen= False;
+    FOREACHridge_(facet1->ridges) {
+      if (otherfacet_(ridge, facet1) == facet2) {
+	FOREACHvertex_(ridge->vertices) {
+	  vertex->seen= True;
+	  vertex->delridge= True;
+	}
+	break;
+      }
+    }
+    FOREACHvertex_(facet1->vertices) {
+      if (!vertex->seen)
+	break;  /* must occur */
+    }
+    apex= vertex;
+    trace4((qh ferr, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n",
+	  apex->id, facet1->id, facet2->id));
+    FOREACHvertex_i_(facet2->vertices) {
+      if (vertex->id < apex->id) {
+	break;
+      }else if (vertex->id == apex->id) {
+	issubset= True;
+	break;
+      }
+    }
+    if (!issubset)
+      qh_setaddnth (&facet2->vertices, vertex_i, apex);
+    if (!facet2->newfacet)
+      qh_newvertices (facet2->vertices);
+    else if (!apex->newlist) {
+      qh_removevertex (apex);
+      qh_appendvertex (apex);
+    }
+  }
+  trace4((qh ferr, "qh_mergesimplex: update vertex neighbors of f%d\n",
+	  facet1->id));
+  FOREACHvertex_(facet1->vertices) {
+    if (vertex == apex && !issubset)
+      qh_setreplace (vertex->neighbors, facet1, facet2);
+    else {
+      qh_setdel (vertex->neighbors, facet1);
+      if (!SETsecond_(vertex->neighbors))
+	qh_mergevertex_del (vertex, facet1, facet2);
+    }
+  }
+  trace4((qh ferr, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n",
+	  facet1->id, facet2->id));
+  qh visit_id++;
+  FOREACHneighbor_(facet2)
+    neighbor->visitid= qh visit_id;
+  FOREACHridge_(facet1->ridges) {
+    otherfacet= otherfacet_(ridge, facet1);
+    if (otherfacet == facet2) {
+      qh_setdel (facet2->ridges, ridge);
+      qh_setfree(&(ridge->vertices)); 
+      qh_memfree (ridge, sizeof(ridgeT));
+      qh_setdel (facet2->neighbors, facet1);
+    }else {
+      qh_setappend (&facet2->ridges, ridge);
+      if (otherfacet->visitid != qh visit_id) {
+	qh_setappend (&facet2->neighbors, otherfacet);
+	qh_setreplace (otherfacet->neighbors, facet1, facet2);
+	otherfacet->visitid= qh visit_id;
+      }else {
+	if (otherfacet->simplicial)    /* is degen, needs ridges */
+	  qh_makeridges (otherfacet);
+	if (SETfirstt_(otherfacet->neighbors, facetT) != facet1)
+	  qh_setdel (otherfacet->neighbors, facet1);
+	else {   /*keep newfacet->neighbors->horizon*/
+	  qh_setdel(otherfacet->neighbors, facet2);
+	  qh_setreplace(otherfacet->neighbors, facet1, facet2);
+	}
+      }
+      if (ridge->top == facet1) /* wait until after qh_makeridges */
+	ridge->top= facet2;
+      else 
+	ridge->bottom= facet2;
+    }
+  }
+  SETfirst_(facet1->ridges)= NULL; /* it will be deleted */
+  trace3((qh ferr, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n",
+	  facet1->id, getid_(apex), facet2->id));
+} /* mergesimplex */
+
+/*---------------------------------
+  
+  qh_mergevertex_del( vertex, facet1, facet2 )
+    delete a vertex because of merging facet1 into facet2
+
+  returns:
+    deletes vertex from facet2
+    adds vertex to qh.del_vertices for later deletion 
+*/
+void qh_mergevertex_del (vertexT *vertex, facetT *facet1, facetT *facet2) {
+
+  zinc_(Zmergevertex);
+  trace2((qh ferr, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n",
+          vertex->id, facet1->id, facet2->id));
+  qh_setdelsorted (facet2->vertices, vertex);
+  vertex->deleted= True;
+  qh_setappend (&qh del_vertices, vertex);
+} /* mergevertex_del */
+
+/*---------------------------------
+  
+  qh_mergevertex_neighbors( facet1, facet2 )
+    merge the vertex neighbors of facet1 to facet2
+
+  returns:
+    if vertex is current qh.vertex_visit
+      deletes facet1 from vertex->neighbors
+    else
+      renames facet1 to facet2 in vertex->neighbors 
+    deletes vertices if only one neighbor
+  
+  notes:
+    assumes vertex neighbor sets are good
+*/
+void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2) {
+  vertexT *vertex, **vertexp;
+
+  trace4((qh ferr, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",
+	  facet1->id, facet2->id));
+  if (qh tracevertex) {
+    fprintf (qh ferr, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n",
+	     facet1->id, facet2->id, qh furthest_id, qh tracevertex->neighbors->e[0].p);
+    qh_errprint ("TRACE", NULL, NULL, NULL, qh tracevertex);
+  }
+  FOREACHvertex_(facet1->vertices) {
+    if (vertex->visitid != qh vertex_visit) 
+      qh_setreplace(vertex->neighbors, facet1, facet2);
+    else {
+      qh_setdel(vertex->neighbors, facet1);
+      if (!SETsecond_(vertex->neighbors))
+	qh_mergevertex_del (vertex, facet1, facet2);
+    }
+  }
+  if (qh tracevertex) 
+    qh_errprint ("TRACE", NULL, NULL, NULL, qh tracevertex);
+} /* mergevertex_neighbors */
+
+
+/*---------------------------------
+  
+  qh_mergevertices( vertices1, vertices2 )
+    merges the vertex set of facet1 into facet2
+
+  returns:
+    replaces vertices2 with merged set
+    preserves vertex_visit for qh_mergevertex_neighbors
+    updates qh.newvertex_list
+
+  design:
+    create a merged set of both vertices (in inverse id order)
+*/
+void qh_mergevertices(setT *vertices1, setT **vertices2) {
+  int newsize= qh_setsize(vertices1)+qh_setsize(*vertices2) - qh hull_dim + 1;
+  setT *mergedvertices;
+  vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);
+
+  mergedvertices= qh_settemp (newsize);
+  FOREACHvertex_(vertices1) {
+    if (!*vertex2 || vertex->id > (*vertex2)->id)
+      qh_setappend (&mergedvertices, vertex);
+    else {
+      while (*vertex2 && (*vertex2)->id > vertex->id)
+	qh_setappend (&mergedvertices, *vertex2++);
+      if (!*vertex2 || (*vertex2)->id < vertex->id)
+	qh_setappend (&mergedvertices, vertex);
+      else
+	qh_setappend (&mergedvertices, *vertex2++);
+    }
+  }
+  while (*vertex2)
+    qh_setappend (&mergedvertices, *vertex2++);
+  if (newsize < qh_setsize (mergedvertices)) {
+    fprintf (qh ferr, "qhull internal error (qh_mergevertices): facets did not share a ridge\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh_setfree(vertices2);
+  *vertices2= mergedvertices;
+  qh_settemppop ();
+} /* mergevertices */
+
+
+/*---------------------------------
+  
+  qh_neighbor_intersections( vertex )
+    return intersection of all vertices in vertex->neighbors except for vertex
+
+  returns:
+    returns temporary set of vertices
+    does not include vertex
+    NULL if a neighbor is simplicial
+    NULL if empty set
+    
+  notes:
+    used for renaming vertices
+
+  design:
+    initialize the intersection set with vertices of the first two neighbors
+    delete vertex from the intersection
+    for each remaining neighbor
+      intersect its vertex set with the intersection set
+      return NULL if empty
+    return the intersection set  
+*/
+setT *qh_neighbor_intersections (vertexT *vertex) {
+  facetT *neighbor, **neighborp, *neighborA, *neighborB;
+  setT *intersect;
+  int neighbor_i, neighbor_n;
+
+  FOREACHneighbor_(vertex) {
+    if (neighbor->simplicial)
+      return NULL;
+  }
+  neighborA= SETfirstt_(vertex->neighbors, facetT);
+  neighborB= SETsecondt_(vertex->neighbors, facetT);
+  zinc_(Zintersectnum);
+  if (!neighborA)
+    return NULL;
+  if (!neighborB)
+    intersect= qh_setcopy (neighborA->vertices, 0);
+  else
+    intersect= qh_vertexintersect_new (neighborA->vertices, neighborB->vertices);
+  qh_settemppush (intersect);
+  qh_setdelsorted (intersect, vertex);
+  FOREACHneighbor_i_(vertex) {
+    if (neighbor_i >= 2) {
+      zinc_(Zintersectnum);
+      qh_vertexintersect (&intersect, neighbor->vertices);
+      if (!SETfirst_(intersect)) {
+        zinc_(Zintersectfail);
+        qh_settempfree (&intersect);
+        return NULL;
+      }
+    }
+  }
+  trace3((qh ferr, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n", 
+          qh_setsize (intersect), vertex->id));
+  return intersect;
+} /* neighbor_intersections */
+
+/*---------------------------------
+  
+  qh_newvertices( vertices )
+    add vertices to end of qh.vertex_list (marks as new vertices)
+
+  returns:
+    vertices on qh.newvertex_list
+    vertex->newlist set
+*/
+void qh_newvertices (setT *vertices) {
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (!vertex->newlist) {
+      qh_removevertex (vertex);
+      qh_appendvertex (vertex);
+    }
+  }
+} /* newvertices */
+
+/*---------------------------------
+  
+  qh_reducevertices()
+    reduce extra vertices, shared vertices, and redundant vertices
+    facet->newmerge is set if merged since last call
+    if !qh.MERGEvertices, only removes extra vertices
+
+  returns:
+    True if also merged degen_redundant facets
+    vertices are renamed if possible
+    clears facet->newmerge and vertex->delridge
+
+  notes:
+    ignored if 2-d
+
+  design:
+    merge any degenerate or redundant facets
+    for each newly merged facet
+      remove extra vertices
+    if qh.MERGEvertices
+      for each newly merged facet
+        for each vertex
+          if vertex was on a deleted ridge
+            rename vertex if it is shared
+      remove delridge flag from new vertices
+*/
+boolT qh_reducevertices (void) {
+  int numshare=0, numrename= 0;
+  boolT degenredun= False;
+  facetT *newfacet;
+  vertexT *vertex, **vertexp;
+
+  if (qh hull_dim == 2) 
+    return False;
+  if (qh_merge_degenredundant())
+    degenredun= True;
+ LABELrestart:
+  FORALLnew_facets {
+    if (newfacet->newmerge) { 
+      if (!qh MERGEvertices)
+        newfacet->newmerge= False;
+      qh_remove_extravertices (newfacet);
+    }
+  }
+  if (!qh MERGEvertices)
+    return False;
+  FORALLnew_facets {
+    if (newfacet->newmerge) {
+      newfacet->newmerge= False;
+      FOREACHvertex_(newfacet->vertices) {
+	if (vertex->delridge) {
+	  if (qh_rename_sharedvertex (vertex, newfacet)) {
+	    numshare++;
+	    vertexp--; /* repeat since deleted vertex */
+	  }
+        }
+      }
+    }
+  }
+  FORALLvertex_(qh newvertex_list) {
+    if (vertex->delridge && !vertex->deleted) {
+      vertex->delridge= False;
+      if (qh hull_dim >= 4 && qh_redundant_vertex (vertex)) {
+	numrename++;
+	if (qh_merge_degenredundant()) {
+	  degenredun= True;
+	  goto LABELrestart;
+	}
+      }
+    }
+  }
+  trace1((qh ferr, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n",
+	  numshare, numrename, degenredun));
+  return degenredun;
+} /* reducevertices */
+      
+/*---------------------------------
+  
+  qh_redundant_vertex( vertex )
+    detect and rename a redundant vertex
+    vertices have full vertex->neighbors 
+
+  returns:
+    returns true if find a redundant vertex
+      deletes vertex (vertex->deleted)
+  
+  notes:
+    only needed if vertex->delridge and hull_dim >= 4
+    may add degenerate facets to qh.facet_mergeset
+    doesn't change vertex->neighbors or create redundant facets
+
+  design:
+    intersect vertices of all facet neighbors of vertex
+    determine ridges for these vertices
+    if find a new vertex for vertex amoung these ridges and vertices
+      rename vertex to the new vertex
+*/
+vertexT *qh_redundant_vertex (vertexT *vertex) {
+  vertexT *newvertex= NULL;
+  setT *vertices, *ridges;
+
+  trace3((qh ferr, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id));  
+  if ((vertices= qh_neighbor_intersections (vertex))) {
+    ridges= qh_vertexridges (vertex);
+    if ((newvertex= qh_find_newvertex (vertex, vertices, ridges)))
+      qh_renamevertex (vertex, newvertex, ridges, NULL, NULL);
+    qh_settempfree (&ridges);
+    qh_settempfree (&vertices);
+  }
+  return newvertex;
+} /* redundant_vertex */
+
+/*---------------------------------
+  
+  qh_remove_extravertices( facet )
+    remove extra vertices from non-simplicial facets
+
+  returns:
+    returns True if it finds them
+
+  design:
+    for each vertex in facet
+      if vertex not in a ridge (i.e., no longer used)
+        delete vertex from facet
+        delete facet from vertice's neighbors
+        unless vertex in another facet
+          add vertex to qh.del_vertices for later deletion
+*/
+boolT qh_remove_extravertices (facetT *facet) {
+  ridgeT *ridge, **ridgep;
+  vertexT *vertex, **vertexp;
+  boolT foundrem= False;
+
+  trace4((qh ferr, "qh_remove_extravertices: test f%d for extra vertices\n",
+	  facet->id));
+  FOREACHvertex_(facet->vertices)
+    vertex->seen= False;
+  FOREACHridge_(facet->ridges) { 
+    FOREACHvertex_(ridge->vertices)
+      vertex->seen= True;
+  }
+  FOREACHvertex_(facet->vertices) {
+    if (!vertex->seen) {
+      foundrem= True;
+      zinc_(Zremvertex);
+      qh_setdelsorted (facet->vertices, vertex);
+      qh_setdel (vertex->neighbors, facet);
+      if (!qh_setsize (vertex->neighbors)) {
+	vertex->deleted= True;
+	qh_setappend (&qh del_vertices, vertex);
+	zinc_(Zremvertexdel);
+	trace2((qh ferr, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
+      }else
+	trace3((qh ferr, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
+      vertexp--; /*repeat*/
+    }
+  }
+  return foundrem;
+} /* remove_extravertices */
+
+/*---------------------------------
+  
+  qh_rename_sharedvertex( vertex, facet )
+    detect and rename if shared vertex in facet
+    vertices have full ->neighbors
+
+  returns:
+    newvertex or NULL
+    the vertex may still exist in other facets (i.e., a neighbor was pinched)
+    does not change facet->neighbors
+    updates vertex->neighbors
+  
+  notes:
+    a shared vertex for a facet is only in ridges to one neighbor
+    this may undo a pinched facet
+ 
+    it does not catch pinches involving multiple facets.  These appear
+      to be difficult to detect, since an exhaustive search is too expensive.
+
+  design:
+    if vertex only has two neighbors
+      determine the ridges that contain the vertex
+      determine the vertices shared by both neighbors
+      if can find a new vertex in this set
+        rename the vertex to the new vertex
+*/
+vertexT *qh_rename_sharedvertex (vertexT *vertex, facetT *facet) {
+  facetT *neighbor, **neighborp, *neighborA= NULL;
+  setT *vertices, *ridges;
+  vertexT *newvertex;
+
+  if (qh_setsize (vertex->neighbors) == 2) {
+    neighborA= SETfirstt_(vertex->neighbors, facetT);
+    if (neighborA == facet)
+      neighborA= SETsecondt_(vertex->neighbors, facetT);
+  }else if (qh hull_dim == 3)
+    return NULL;
+  else {
+    qh visit_id++;
+    FOREACHneighbor_(facet)
+      neighbor->visitid= qh visit_id;
+    FOREACHneighbor_(vertex) {
+      if (neighbor->visitid == qh visit_id) {
+        if (neighborA)
+          return NULL;
+        neighborA= neighbor;
+      }
+    }
+    if (!neighborA) {
+      fprintf (qh ferr, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n",
+        vertex->id, facet->id);
+      qh_errprint ("ERRONEOUS", facet, NULL, NULL, vertex);
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }
+  }
+  /* the vertex is shared by facet and neighborA */
+  ridges= qh_settemp (qh TEMPsize);
+  neighborA->visitid= ++qh visit_id;
+  qh_vertexridges_facet (vertex, facet, &ridges);
+  trace2((qh ferr, "qh_rename_sharedvertex: p%d (v%d) is shared by f%d (%d ridges) and f%d\n",
+    qh_pointid(vertex->point), vertex->id, facet->id, qh_setsize (ridges), neighborA->id));
+  zinc_(Zintersectnum);
+  vertices= qh_vertexintersect_new (facet->vertices, neighborA->vertices);
+  qh_setdel (vertices, vertex);
+  qh_settemppush (vertices);
+  if ((newvertex= qh_find_newvertex (vertex, vertices, ridges))) 
+    qh_renamevertex (vertex, newvertex, ridges, facet, neighborA);
+  qh_settempfree (&vertices);
+  qh_settempfree (&ridges);
+  return newvertex;
+} /* rename_sharedvertex */
+
+/*---------------------------------
+  
+  qh_renameridgevertex( ridge, oldvertex, newvertex )
+    renames oldvertex as newvertex in ridge
+
+  returns:
+  
+  design:
+    delete oldvertex from ridge
+    if newvertex already in ridge
+      copy ridge->noconvex to another ridge if possible
+      delete the ridge
+    else
+      insert newvertex into the ridge
+      adjust the ridge's orientation
+*/
+void qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
+  int nth= 0, oldnth;
+  facetT *temp;
+  vertexT *vertex, **vertexp;
+
+  oldnth= qh_setindex (ridge->vertices, oldvertex);
+  qh_setdelnthsorted (ridge->vertices, oldnth);
+  FOREACHvertex_(ridge->vertices) {
+    if (vertex == newvertex) {
+      zinc_(Zdelridge);
+      if (ridge->nonconvex) /* only one ridge has nonconvex set */
+	qh_copynonconvex (ridge);
+      qh_delridge (ridge);
+      trace2((qh ferr, "qh_renameridgevertex: ridge r%d deleted.  It contained both v%d and v%d\n",
+        ridge->id, oldvertex->id, newvertex->id));
+      return;
+    }
+    if (vertex->id < newvertex->id)
+      break;
+    nth++;
+  }
+  qh_setaddnth(&ridge->vertices, nth, newvertex);
+  if (abs(oldnth - nth)%2) {
+    trace3((qh ferr, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n", 
+	    ridge->id));
+    temp= ridge->top;
+    ridge->top= ridge->bottom;
+    ridge->bottom= temp;
+  }
+} /* renameridgevertex */
+
+
+/*---------------------------------
+  
+  qh_renamevertex( oldvertex, newvertex, ridges, oldfacet, neighborA )
+    renames oldvertex as newvertex in ridges 
+    gives oldfacet/neighborA if oldvertex is shared between two facets
+
+  returns:
+    oldvertex may still exist afterwards
+    
+
+  notes:
+    can not change neighbors of newvertex (since it's a subset)
+
+  design:
+    for each ridge in ridges
+      rename oldvertex to newvertex and delete degenerate ridges
+    if oldfacet not defined
+      for each neighbor of oldvertex
+        delete oldvertex from neighbor's vertices
+        remove extra vertices from neighbor
+      add oldvertex to qh.del_vertices
+    else if oldvertex only between oldfacet and neighborA
+      delete oldvertex from oldfacet and neighborA
+      add oldvertex to qh.del_vertices
+    else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched)
+      delete oldvertex from oldfacet
+      delete oldfacet from oldvertice's neighbors
+      remove extra vertices (e.g., oldvertex) from neighborA
+*/
+void qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
+  facetT *neighbor, **neighborp;
+  ridgeT *ridge, **ridgep;
+  boolT istrace= False;
+
+  if (qh IStracing >= 2 || oldvertex->id == qh tracevertex_id ||
+	newvertex->id == qh tracevertex_id)
+    istrace= True;
+  FOREACHridge_(ridges) 
+    qh_renameridgevertex (ridge, oldvertex, newvertex);
+  if (!oldfacet) {
+    zinc_(Zrenameall);
+    if (istrace)
+      fprintf (qh ferr, "qh_renamevertex: renamed v%d to v%d in several facets\n",
+               oldvertex->id, newvertex->id);
+    FOREACHneighbor_(oldvertex) {
+      qh_maydropneighbor (neighbor);
+      qh_setdelsorted (neighbor->vertices, oldvertex);
+      if (qh_remove_extravertices (neighbor))
+        neighborp--; /* neighbor may be deleted */
+    }
+    if (!oldvertex->deleted) {
+      oldvertex->deleted= True;
+      qh_setappend (&qh del_vertices, oldvertex);
+    }
+  }else if (qh_setsize (oldvertex->neighbors) == 2) {
+    zinc_(Zrenameshare);
+    if (istrace)
+      fprintf (qh ferr, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n", 
+               oldvertex->id, newvertex->id, oldfacet->id);
+    FOREACHneighbor_(oldvertex)
+      qh_setdelsorted (neighbor->vertices, oldvertex);
+    oldvertex->deleted= True;
+    qh_setappend (&qh del_vertices, oldvertex);
+  }else {
+    zinc_(Zrenamepinch);
+    if (istrace || qh IStracing)
+      fprintf (qh ferr, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n", 
+               oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);
+    qh_setdelsorted (oldfacet->vertices, oldvertex);
+    qh_setdel (oldvertex->neighbors, oldfacet);
+    qh_remove_extravertices (neighborA);
+  }
+} /* renamevertex */
+
+
+/*---------------------------------
+  
+  qh_test_appendmerge( facet, neighbor )
+    tests facet/neighbor for convexity
+    appends to mergeset if non-convex
+    if pre-merging, 
+      nop if qh.SKIPconvex, or qh.MERGEexact and coplanar
+
+  returns:
+    true if appends facet/neighbor to mergeset
+    sets facet->center as needed
+    does not change facet->seen
+
+  design:
+    if qh.cos_max is defined
+      if the angle between facet normals is too shallow
+        append an angle-coplanar merge to qh.mergeset
+        return True
+    make facet's centrum if needed
+    if facet's centrum is above the neighbor
+      set isconcave
+    else
+      if facet's centrum is not below the neighbor
+        set iscoplanar
+      make neighbor's centrum if needed
+      if neighbor's centrum is above the facet
+        set isconcave
+      else if neighbor's centrum is not below the facet
+        set iscoplanar
+   if isconcave or iscoplanar
+     get angle if needed
+     append concave or coplanar merge to qh.mergeset
+*/
+boolT qh_test_appendmerge (facetT *facet, facetT *neighbor) {
+  realT dist, dist2= -REALmax, angle= -REALmax;
+  boolT isconcave= False, iscoplanar= False, okangle= False;
+
+  if (qh SKIPconvex && !qh POSTmerging)
+    return False;
+  if ((!qh MERGEexact || qh POSTmerging) && qh cos_max < REALmax/2) {
+    angle= qh_getangle(facet->normal, neighbor->normal);
+    zinc_(Zangletests);
+    if (angle > qh cos_max) {
+      zinc_(Zcoplanarangle);
+      qh_appendmergeset(facet, neighbor, MRGanglecoplanar, &angle);
+      trace2((qh ferr, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
+         angle, facet->id, neighbor->id));
+      return True;
+    }else
+      okangle= True;
+  }
+  if (!facet->center)
+    facet->center= qh_getcentrum (facet);
+  zzinc_(Zcentrumtests);
+  qh_distplane(facet->center, neighbor, &dist);
+  if (dist > qh centrum_radius)
+    isconcave= True;
+  else {
+    if (dist > -qh centrum_radius)
+      iscoplanar= True;
+    if (!neighbor->center)
+      neighbor->center= qh_getcentrum (neighbor);
+    zzinc_(Zcentrumtests);
+    qh_distplane(neighbor->center, facet, &dist2);
+    if (dist2 > qh centrum_radius)
+      isconcave= True;
+    else if (!iscoplanar && dist2 > -qh centrum_radius)
+      iscoplanar= True;
+  }
+  if (!isconcave && (!iscoplanar || (qh MERGEexact && !qh POSTmerging)))
+    return False;
+  if (!okangle && qh ANGLEmerge) {
+    angle= qh_getangle(facet->normal, neighbor->normal);
+    zinc_(Zangletests);
+  }
+  if (isconcave) {
+    zinc_(Zconcaveridge);
+    if (qh ANGLEmerge)
+      angle += qh_ANGLEconcave + 0.5;
+    qh_appendmergeset(facet, neighbor, MRGconcave, &angle);
+    trace0((qh ferr, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g during p%d\n",
+	   facet->id, neighbor->id, dist, dist2, angle, qh furthest_id));
+  }else /* iscoplanar */ {
+    zinc_(Zcoplanarcentrum);
+    qh_appendmergeset(facet, neighbor, MRGcoplanar, &angle);
+    trace2((qh ferr, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",
+	      facet->id, neighbor->id, dist, dist2, angle));
+  }
+  return True;
+} /* test_appendmerge */
+
+/*---------------------------------
+  
+  qh_test_vneighbors()
+    test vertex neighbors for convexity
+    tests all facets on qh.newfacet_list
+
+  returns:
+    true if non-convex vneighbors appended to qh.facet_mergeset
+    initializes vertex neighbors if needed
+
+  notes:
+    assumes all facet neighbors have been tested
+    this can be expensive
+    this does not guarantee that a centrum is below all facets
+      but it is unlikely
+    uses qh.visit_id
+
+  design:
+    build vertex neighbors if necessary
+    for all new facets
+      for all vertices
+        for each unvisited facet neighbor of the vertex
+          test new facet and neighbor for convexity
+*/
+boolT qh_test_vneighbors (void /* qh newfacet_list */) {
+  facetT *newfacet, *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  int nummerges= 0;
+
+  trace1((qh ferr, "qh_test_vneighbors: testing vertex neighbors for convexity\n"));
+  if (!qh VERTEXneighbors)
+    qh_vertexneighbors();
+  FORALLnew_facets 
+    newfacet->seen= False;
+  FORALLnew_facets {
+    newfacet->seen= True;
+    newfacet->visitid= qh visit_id++;
+    FOREACHneighbor_(newfacet)
+      newfacet->visitid= qh visit_id;
+    FOREACHvertex_(newfacet->vertices) {
+      FOREACHneighbor_(vertex) {
+      	if (neighbor->seen || neighbor->visitid == qh visit_id)
+      	  continue;
+      	if (qh_test_appendmerge (newfacet, neighbor))
+          nummerges++;
+      }
+    }
+  }
+  zadd_(Ztestvneighbor, nummerges);
+  trace1((qh ferr, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n",
+           nummerges));
+  return (nummerges > 0);    
+} /* test_vneighbors */
+
+/*---------------------------------
+  
+  qh_tracemerge( facet1, facet2 )
+    print trace message after merge
+*/
+void qh_tracemerge (facetT *facet1, facetT *facet2) {
+  boolT waserror= False;
+
+#ifndef qh_NOtrace
+  if (qh IStracing >= 4) 
+    qh_errprint ("MERGED", facet2, NULL, NULL, NULL);
+  if (facet2 == qh tracefacet || (qh tracevertex && qh tracevertex->newlist)) {
+    fprintf (qh ferr, "qh_tracemerge: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh furthest_id);
+    if (facet2 != qh tracefacet)
+      qh_errprint ("TRACE", qh tracefacet, 
+        (qh tracevertex && qh tracevertex->neighbors) ? 
+           SETfirstt_(qh tracevertex->neighbors, facetT) : NULL,
+        NULL, qh tracevertex);      
+  }
+  if (qh tracevertex) {
+    if (qh tracevertex->deleted)
+      fprintf (qh ferr, "qh_tracemerge: trace vertex deleted at furthest p%d\n",
+	    qh furthest_id);
+    else
+      qh_checkvertex (qh tracevertex);
+  }
+  if (qh tracefacet) {
+    qh_checkfacet (qh tracefacet, True, &waserror);
+    if (waserror)
+      qh_errexit (qh_ERRqhull, qh tracefacet, NULL);
+  }
+#endif /* !qh_NOtrace */
+  if (qh CHECKfrequently || qh IStracing >= 4) { /* can't check polygon here */
+    qh_checkfacet (facet2, True, &waserror);
+    if (waserror)
+      qh_errexit(qh_ERRqhull, NULL, NULL);
+  }
+} /* tracemerge */
+
+/*---------------------------------
+  
+  qh_tracemerging()
+    print trace message during POSTmerging
+
+  returns:
+    updates qh.mergereport
+  
+  notes:
+    called from qh_mergecycle() and qh_mergefacet()
+  
+  see:
+    qh_buildtracing()
+*/
+void qh_tracemerging (void) {
+  realT cpu;
+  int total;
+  time_t timedata;
+  struct tm *tp;
+
+  qh mergereport= zzval_(Ztotmerge);
+  time (&timedata);
+  tp= localtime (&timedata);
+  cpu= qh_CPUclock;
+  cpu /= qh_SECticks;
+  total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+  fprintf (qh ferr, "\n\
+At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets.  The hull\n\
+  contains %d facets and %d vertices.\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu,
+      total, qh num_facets - qh num_visible,
+      qh num_vertices-qh_setsize (qh del_vertices));
+} /* tracemerging */
+
+/*---------------------------------
+  
+  qh_updatetested( facet1, facet2 )
+    clear facet2->tested and facet1->ridge->tested for merge
+
+  returns:
+    deletes facet2->center unless it's already large
+      if so, clears facet2->ridge->tested
+
+  design:
+    clear facet2->tested
+    clear ridge->tested for facet1's ridges
+    if facet2 has a centrum
+      if facet2 is large
+        set facet2->keepcentrum 
+      else if facet2 has 3 vertices due to many merges, or not large and post merging
+        clear facet2->keepcentrum
+      unless facet2->keepcentrum
+        clear facet2->center to recompute centrum later
+        clear ridge->tested for facet2's ridges
+*/
+void qh_updatetested (facetT *facet1, facetT *facet2) {
+  ridgeT *ridge, **ridgep;
+  int size;
+  
+  facet2->tested= False;
+  FOREACHridge_(facet1->ridges)
+    ridge->tested= False;
+  if (!facet2->center)
+    return;
+  size= qh_setsize (facet2->vertices);
+  if (!facet2->keepcentrum) {
+    if (size > qh hull_dim + qh_MAXnewcentrum) {
+      facet2->keepcentrum= True;
+      zinc_(Zwidevertices);
+    }
+  }else if (size <= qh hull_dim + qh_MAXnewcentrum) {
+    /* center and keepcentrum was set */
+    if (size == qh hull_dim || qh POSTmerging)
+      facet2->keepcentrum= False; /* if many merges need to recompute centrum */
+  }
+  if (!facet2->keepcentrum) {
+    qh_memfree (facet2->center, qh normal_size);
+    facet2->center= NULL;
+    FOREACHridge_(facet2->ridges)
+      ridge->tested= False;
+  }
+} /* updatetested */
+
+/*---------------------------------
+  
+  qh_vertexridges( vertex )
+    return temporary set of ridges adjacent to a vertex
+    vertex->neighbors defined
+
+  ntoes:
+    uses qh.visit_id
+    does not include implicit ridges for simplicial facets
+
+  design:
+    for each neighbor of vertex
+      add ridges that include the vertex to ridges  
+*/
+setT *qh_vertexridges (vertexT *vertex) {
+  facetT *neighbor, **neighborp;
+  setT *ridges= qh_settemp (qh TEMPsize);
+  int size;
+
+  qh visit_id++;
+  FOREACHneighbor_(vertex)
+    neighbor->visitid= qh visit_id;
+  FOREACHneighbor_(vertex) {
+    if (*neighborp)   /* no new ridges in last neighbor */
+      qh_vertexridges_facet (vertex, neighbor, &ridges);
+  }
+  if (qh PRINTstatistics || qh IStracing) {
+    size= qh_setsize (ridges);
+    zinc_(Zvertexridge);
+    zadd_(Zvertexridgetot, size);
+    zmax_(Zvertexridgemax, size);
+    trace3((qh ferr, "qh_vertexridges: found %d ridges for v%d\n",
+             size, vertex->id));
+  }
+  return ridges;
+} /* vertexridges */
+
+/*---------------------------------
+  
+  qh_vertexridges_facet( vertex, facet, ridges )
+    add adjacent ridges for vertex in facet
+    neighbor->visitid==qh.visit_id if it hasn't been visited
+
+  returns:
+    ridges updated
+    sets facet->visitid to qh.visit_id-1
+
+  design:
+    for each ridge of facet
+      if ridge of visited neighbor (i.e., unprocessed)
+        if vertex in ridge
+          append ridge to vertex
+    mark facet processed
+*/
+void qh_vertexridges_facet (vertexT *vertex, facetT *facet, setT **ridges) {
+  ridgeT *ridge, **ridgep;
+  facetT *neighbor;
+
+  FOREACHridge_(facet->ridges) {
+    neighbor= otherfacet_(ridge, facet);
+    if (neighbor->visitid == qh visit_id 
+    && qh_setin (ridge->vertices, vertex))
+      qh_setappend (ridges, ridge);
+  }
+  facet->visitid= qh visit_id-1;
+} /* vertexridges_facet */
+
+/*---------------------------------
+  
+  qh_willdelete( facet, replace )
+    moves facet to visible list
+    sets facet->f.replace to replace (may be NULL)
+
+  returns:
+    bumps qh.num_visible
+*/
+void qh_willdelete (facetT *facet, facetT *replace) {
+
+  qh_removefacet(facet);
+  qh_prependfacet (facet, &qh visible_list);
+  qh num_visible++;
+  facet->visible= True;
+  facet->f.replace= replace;
+} /* willdelete */
+
+#else /* qh_NOmerge */
+void qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle) {
+}
+void qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
+                      boolT vneighbors) {
+}
+boolT qh_checkzero (boolT testall) {
+   }
+#endif /* qh_NOmerge */
+
diff --git a/extern/qhull/src/merge.h b/extern/qhull/src/merge.h
new file mode 100644
index 00000000000..7fc2afa5967
--- /dev/null
+++ b/extern/qhull/src/merge.h
@@ -0,0 +1,171 @@
+/*
  ---------------------------------
+
+   merge.h 
+   header file for merge.c
+
+   see qh-merge.htm and merge.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFmerge
+#define qhDEFmerge 1
+
+
+/*============ -constants- ==============*/
+
+/*----------------------------------
+
+  qh_ANGLEredundant
+    indicates redundant merge in mergeT->angle
+*/
+#define qh_ANGLEredundant 6.0
+
+/*----------------------------------
+  
+  qh_ANGLEdegen
+    indicates degenerate facet in mergeT->angle
+*/
+#define qh_ANGLEdegen     5.0
+
+/*----------------------------------
+  
+  qh_ANGLEconcave
+    offset to indicate concave facets in mergeT->angle
+  
+  notes:
+    concave facets are assigned the range of [2,4] in mergeT->angle
+    roundoff error may make the angle less than 2
+*/
+#define qh_ANGLEconcave  1.5
+
+/*----------------------------------
+  
+  MRG... (mergeType)
+    indicates the type of a merge (mergeT->type)
+*/
+typedef enum {	/* in sort order for facet_mergeset */
+  MRGnone= 0,
+  MRGcoplanar,		/* centrum coplanar */
+  MRGanglecoplanar,	/* angle coplanar */
+  			/* could detect half concave ridges */
+  MRGconcave,		/* concave ridge */
+  MRGflip,		/* flipped facet. facet1 == facet2 */
+  MRGridge,		/* duplicate ridge (qh_MERGEridge) */
+                        /* degen and redundant go onto degen_mergeset */
+  MRGdegen,		/* degenerate facet (not enough neighbors) facet1 == facet2 */
+  MRGredundant,		/* redundant facet (vertex subset) */
+  			/* merge_degenredundant assumes degen < redundant */
+  MRGmirror,	        /* mirror facet from qh_triangulate */
+  ENDmrg
+} mergeType;
+
+/*----------------------------------
+  
+  qh_MERGEapex
+    flag for qh_mergefacet() to indicate an apex merge  
+*/
+#define qh_MERGEapex     True
+
+/*============ -structures- ====================*/
+
+/*----------------------------------
+     
+  mergeT
+    structure used to merge facets
+*/
+
+typedef struct mergeT mergeT;
+struct mergeT {		/* initialize in qh_appendmergeset */
+  realT   angle;        /* angle between normals of facet1 and facet2 */
+  facetT *facet1; 	/* will merge facet1 into facet2 */
+  facetT *facet2;
+  mergeType type;
+};
+
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+     
+  FOREACHmerge_( merges ) {...}
+    assign 'merge' to each merge in merges
+       
+  notes:
+    uses 'mergeT *merge, **mergep;'
+    if qh_mergefacet(),
+      restart since qh.facet_mergeset may change
+    see FOREACHsetelement_
+*/
+#define FOREACHmerge_( merges ) FOREACHsetelement_(mergeT, merges, merge)
+
+/*============ prototypes in alphabetical order after pre/postmerge =======*/
+
+void    qh_premerge (vertexT *apex, realT maxcentrum, realT maxangle);
+void    qh_postmerge (char *reason, realT maxcentrum, realT maxangle, 
+             boolT vneighbors);
+void    qh_all_merges (boolT othermerge, boolT vneighbors);
+void    qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle);
+setT   *qh_basevertices( facetT *samecycle);
+void    qh_checkconnect (void /* qh new_facets */);
+boolT   qh_checkzero (boolT testall);
+void    qh_copynonconvex (ridgeT *atridge);
+void    qh_degen_redundant_facet (facetT *facet);
+void   	qh_degen_redundant_neighbors (facetT *facet, facetT *delfacet);
+vertexT *qh_find_newvertex (vertexT *oldvertex, setT *vertices, setT *ridges);
+void    qh_findbest_test (boolT testcentrum, facetT *facet, facetT *neighbor,
+           facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
+facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
+void 	qh_flippedmerges(facetT *facetlist, boolT *wasmerge);
+void 	qh_forcedmerges( boolT *wasmerge);
+void	qh_getmergeset(facetT *facetlist);
+void 	qh_getmergeset_initial (facetT *facetlist);
+void    qh_hashridge (setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
+ridgeT *qh_hashridge_find (setT *hashtable, int hashsize, ridgeT *ridge, 
+              vertexT *vertex, vertexT *oldvertex, int *hashslot);
+void 	qh_makeridges(facetT *facet);
+void    qh_mark_dupridges(facetT *facetlist);
+void    qh_maydropneighbor (facetT *facet);
+int     qh_merge_degenredundant (void);
+void    qh_merge_nonconvex( facetT *facet1, facetT *facet2, mergeType mergetype);
+void    qh_mergecycle (facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_all (facetT *facetlist, boolT *wasmerge);
+void    qh_mergecycle_facets( facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet);
+void    qh_mergecycle_vneighbors( facetT *samecycle, facetT *newfacet);
+void 	qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex);
+void    qh_mergefacet2d (facetT *facet1, facetT *facet2);
+void 	qh_mergeneighbors(facetT *facet1, facetT *facet2);
+void 	qh_mergeridges(facetT *facet1, facetT *facet2);
+void    qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex);
+void    qh_mergevertex_del (vertexT *vertex, facetT *facet1, facetT *facet2);
+void    qh_mergevertex_neighbors(facetT *facet1, facetT *facet2);
+void	qh_mergevertices(setT *vertices1, setT **vertices);
+setT   *qh_neighbor_intersections (vertexT *vertex);
+void    qh_newvertices (setT *vertices);
+boolT   qh_reducevertices (void);
+vertexT *qh_redundant_vertex (vertexT *vertex);
+boolT   qh_remove_extravertices (facetT *facet);
+vertexT *qh_rename_sharedvertex (vertexT *vertex, facetT *facet);
+void	qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
+void    qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges,
+			facetT *oldfacet, facetT *neighborA);
+boolT 	qh_test_appendmerge (facetT *facet, facetT *neighbor);
+boolT   qh_test_vneighbors (void /* qh newfacet_list */);
+void    qh_tracemerge (facetT *facet1, facetT *facet2);
+void    qh_tracemerging (void);
+void    qh_updatetested( facetT *facet1, facetT *facet2);
+setT   *qh_vertexridges (vertexT *vertex);
+void    qh_vertexridges_facet (vertexT *vertex, facetT *facet, setT **ridges);
+void    qh_willdelete (facetT *facet, facetT *replace);
+
+#endif /* qhDEFmerge */
diff --git a/extern/qhull/src/poly.c b/extern/qhull/src/poly.c
new file mode 100644
index 00000000000..6319e43d66a
--- /dev/null
+++ b/extern/qhull/src/poly.c
@@ -0,0 +1,1180 @@
+/*
  ---------------------------------
+
+   poly.c 
+   implements polygons and simplices
+
+   see qh-poly.htm, poly.h and qhull.h
+
+   infrequent code is in poly2.c 
+   (all but top 50 and their callers 12/3/95)
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*======== functions in alphabetical order ==========*/
+
+/*---------------------------------
+  
+  qh_appendfacet( facet )
+    appends facet to end of qh.facet_list,
+
+  returns:
+    updates qh.newfacet_list, facet_next, facet_list
+    increments qh.numfacets
+  
+  notes:
+    assumes qh.facet_list/facet_tail is defined (createsimplex)
+
+  see:
+    qh_removefacet()
+
+*/
+void qh_appendfacet(facetT *facet) {
+  facetT *tail= qh facet_tail;
+
+  if (tail == qh newfacet_list)
+    qh newfacet_list= facet;
+  if (tail == qh facet_next)
+    qh facet_next= facet;
+  facet->previous= tail->previous;
+  facet->next= tail;
+  if (tail->previous)
+    tail->previous->next= facet;
+  else
+    qh facet_list= facet;
+  tail->previous= facet;
+  qh num_facets++;
+  trace4((qh ferr, "qh_appendfacet: append f%d to facet_list\n", facet->id));
+} /* appendfacet */
+
+
+/*---------------------------------
+  
+  qh_appendvertex( vertex )
+    appends vertex to end of qh.vertex_list,
+
+  returns:
+    sets vertex->newlist
+    updates qh.vertex_list, newvertex_list
+    increments qh.num_vertices
+
+  notes:
+    assumes qh.vertex_list/vertex_tail is defined (createsimplex)
+
+*/
+void qh_appendvertex (vertexT *vertex) {
+  vertexT *tail= qh vertex_tail;
+
+  if (tail == qh newvertex_list)
+    qh newvertex_list= vertex;
+  vertex->newlist= True;
+  vertex->previous= tail->previous;
+  vertex->next= tail;
+  if (tail->previous)
+    tail->previous->next= vertex;
+  else
+    qh vertex_list= vertex;
+  tail->previous= vertex;
+  qh num_vertices++;
+  trace4((qh ferr, "qh_appendvertex: append v%d to vertex_list\n", vertex->id));
+} /* appendvertex */
+
+
+/*---------------------------------
+  
+  qh_attachnewfacets( )
+    attach horizon facets to new facets in qh.newfacet_list
+    newfacets have neighbor and ridge links to horizon but not vice versa
+    only needed for qh.ONLYgood
+
+  returns:
+    set qh.NEWfacets
+    horizon facets linked to new facets 
+      ridges changed from visible facets to new facets
+      simplicial ridges deleted
+    qh.visible_list, no ridges valid
+    facet->f.replace is a newfacet (if any)
+
+  design:
+    delete interior ridges and neighbor sets by
+      for each visible, non-simplicial facet
+        for each ridge
+          if last visit or if neighbor is simplicial
+            if horizon neighbor
+              delete ridge for horizon's ridge set
+            delete ridge
+        erase neighbor set
+    attach horizon facets and new facets by
+      for all new facets
+        if corresponding horizon facet is simplicial
+          locate corresponding visible facet {may be more than one}
+          link visible facet to new facet
+          replace visible facet with new facet in horizon
+        else it's non-simplicial
+          for all visible neighbors of the horizon facet
+            link visible neighbor to new facet
+            delete visible neighbor from horizon facet
+          append new facet to horizon's neighbors
+          the first ridge of the new facet is the horizon ridge
+          link the new facet into the horizon ridge
+*/
+void qh_attachnewfacets (void ) {
+  facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
+  ridgeT *ridge, **ridgep;
+
+  qh NEWfacets= True;
+  trace3((qh ferr, "qh_attachnewfacets: delete interior ridges\n"));
+  qh visit_id++;
+  FORALLvisible_facets {
+    visible->visitid= qh visit_id;
+    if (visible->ridges) {
+      FOREACHridge_(visible->ridges) {
+	neighbor= otherfacet_(ridge, visible);
+	if (neighbor->visitid == qh visit_id
+	    || (!neighbor->visible && neighbor->simplicial)) {
+	  if (!neighbor->visible)  /* delete ridge for simplicial horizon */
+	    qh_setdel (neighbor->ridges, ridge);
+	  qh_setfree (&(ridge->vertices)); /* delete on 2nd visit */
+	  qh_memfree (ridge, sizeof(ridgeT));
+	}
+      }
+      SETfirst_(visible->ridges)= NULL;
+    }
+    SETfirst_(visible->neighbors)= NULL;
+  }
+  trace1((qh ferr, "qh_attachnewfacets: attach horizon facets to new facets\n"));
+  FORALLnew_facets {
+    horizon= SETfirstt_(newfacet->neighbors, facetT);
+    if (horizon->simplicial) {
+      visible= NULL;
+      FOREACHneighbor_(horizon) {   /* may have more than one horizon ridge */
+	if (neighbor->visible) {
+	  if (visible) {
+	    if (qh_setequal_skip (newfacet->vertices, 0, horizon->vertices,
+				  SETindex_(horizon->neighbors, neighbor))) {
+	      visible= neighbor;
+	      break;
+	    }
+	  }else
+	    visible= neighbor;
+	}
+      }
+      if (visible) {
+	visible->f.replace= newfacet;
+	qh_setreplace (horizon->neighbors, visible, newfacet);
+      }else {
+	fprintf (qh ferr, "qhull internal error (qh_attachnewfacets): couldn't find visible facet for horizon f%d of newfacet f%d\n",
+		 horizon->id, newfacet->id);
+	qh_errexit2 (qh_ERRqhull, horizon, newfacet);
+      }
+    }else { /* non-simplicial, with a ridge for newfacet */
+      FOREACHneighbor_(horizon) {    /* may hold for many new facets */
+	if (neighbor->visible) {
+	  neighbor->f.replace= newfacet;
+	  qh_setdelnth (horizon->neighbors,
+			SETindex_(horizon->neighbors, neighbor));
+	  neighborp--; /* repeat */
+	}
+      }
+      qh_setappend (&horizon->neighbors, newfacet);
+      ridge= SETfirstt_(newfacet->ridges, ridgeT);
+      if (ridge->top == horizon)
+	ridge->bottom= newfacet;
+      else
+	ridge->top= newfacet;
+      }
+  } /* newfacets */
+  if (qh PRINTstatistics) {
+    FORALLvisible_facets {
+      if (!visible->f.replace) 
+	zinc_(Zinsidevisible);
+    }
+  }
+} /* attachnewfacets */
+
+/*---------------------------------
+  
+  qh_checkflipped( facet, dist, allerror )
+    checks facet orientation to interior point
+
+    if allerror set,
+      tests against qh.DISTround
+    else
+      tests against 0 since tested against DISTround before
+
+  returns:
+    False if it flipped orientation (sets facet->flipped)
+    distance if non-NULL
+*/
+boolT qh_checkflipped (facetT *facet, realT *distp, boolT allerror) {
+  realT dist;
+
+  if (facet->flipped && !distp)
+    return False;
+  zzinc_(Zdistcheck);
+  qh_distplane(qh interior_point, facet, &dist);
+  if (distp)
+    *distp= dist;
+  if ((allerror && dist > -qh DISTround)|| (!allerror && dist >= 0.0)) {
+    facet->flipped= True;
+    zzinc_(Zflippedfacets);
+    trace0((qh ferr, "qh_checkflipped: facet f%d is flipped, distance= %6.12g during p%d\n",
+              facet->id, dist, qh furthest_id));
+    qh_precision ("flipped facet");
+    return False;
+  }
+  return True;
+} /* checkflipped */
+
+/*---------------------------------
+  
+  qh_delfacet( facet )
+    removes facet from facet_list and frees up its memory
+
+  notes:
+    assumes vertices and ridges already freed
+*/
+void qh_delfacet(facetT *facet) {
+  void **freelistp; /* used !qh_NOmem */
+
+  trace4((qh ferr, "qh_delfacet: delete f%d\n", facet->id));
+  if (facet == qh tracefacet)
+    qh tracefacet= NULL;
+  if (facet == qh GOODclosest)
+    qh GOODclosest= NULL;
+  qh_removefacet(facet);
+  if (!facet->tricoplanar || facet->keepcentrum) {
+    qh_memfree_(facet->normal, qh normal_size, freelistp);
+    if (qh CENTERtype == qh_ASvoronoi) {   /* uses macro calls */
+      qh_memfree_(facet->center, qh center_size, freelistp);
+    }else /* AScentrum */ {
+      qh_memfree_(facet->center, qh normal_size, freelistp);
+    }
+  }
+  qh_setfree(&(facet->neighbors));
+  if (facet->ridges)
+    qh_setfree(&(facet->ridges));
+  qh_setfree(&(facet->vertices));
+  if (facet->outsideset)
+    qh_setfree(&(facet->outsideset));
+  if (facet->coplanarset)
+    qh_setfree(&(facet->coplanarset));
+  qh_memfree_(facet, sizeof(facetT), freelistp);
+} /* delfacet */
+
+
+/*---------------------------------
+  
+  qh_deletevisible()
+    delete visible facets and vertices
+
+  returns:
+    deletes each facet and removes from facetlist
+    at exit, qh.visible_list empty (== qh.newfacet_list)
+
+  notes:
+    ridges already deleted
+    horizon facets do not reference facets on qh.visible_list
+    new facets in qh.newfacet_list
+    uses   qh.visit_id;
+*/
+void qh_deletevisible (void /*qh visible_list*/) {
+  facetT *visible, *nextfacet;
+  vertexT *vertex, **vertexp;
+  int numvisible= 0, numdel= qh_setsize(qh del_vertices);
+
+  trace1((qh ferr, "qh_deletevisible: delete %d visible facets and %d vertices\n",
+         qh num_visible, numdel));
+  for (visible= qh visible_list; visible && visible->visible; 
+                visible= nextfacet) { /* deleting current */
+    nextfacet= visible->next;        
+    numvisible++;
+    qh_delfacet(visible);
+  }
+  if (numvisible != qh num_visible) {
+    fprintf (qh ferr, "qhull internal error (qh_deletevisible): qh num_visible %d is not number of visible facets %d\n",
+             qh num_visible, numvisible);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh num_visible= 0;
+  zadd_(Zvisfacettot, numvisible);
+  zmax_(Zvisfacetmax, numvisible);
+  zzadd_(Zdelvertextot, numdel);
+  zmax_(Zdelvertexmax, numdel);
+  FOREACHvertex_(qh del_vertices) 
+    qh_delvertex (vertex);
+  qh_settruncate (qh del_vertices, 0);
+} /* deletevisible */
+
+/*---------------------------------
+  
+  qh_facetintersect( facetA, facetB, skipa, skipB, prepend )
+    return vertices for intersection of two simplicial facets
+    may include 1 prepended entry (if more, need to settemppush)
+    
+  returns:
+    returns set of qh.hull_dim-1 + prepend vertices
+    returns skipped index for each test and checks for exactly one
+
+  notes:
+    does not need settemp since set in quick memory
+  
+  see also:
+    qh_vertexintersect and qh_vertexintersect_new
+    use qh_setnew_delnthsorted to get nth ridge (no skip information)
+
+  design:
+    locate skipped vertex by scanning facet A's neighbors
+    locate skipped vertex by scanning facet B's neighbors
+    intersect the vertex sets
+*/
+setT *qh_facetintersect (facetT *facetA, facetT *facetB,
+			 int *skipA,int *skipB, int prepend) {
+  setT *intersect;
+  int dim= qh hull_dim, i, j;
+  facetT **neighborsA, **neighborsB;
+
+  neighborsA= SETaddr_(facetA->neighbors, facetT);
+  neighborsB= SETaddr_(facetB->neighbors, facetT);
+  i= j= 0;
+  if (facetB == *neighborsA++)
+    *skipA= 0;
+  else if (facetB == *neighborsA++)
+    *skipA= 1;
+  else if (facetB == *neighborsA++)
+    *skipA= 2;
+  else {
+    for (i= 3; i < dim; i++) {
+      if (facetB == *neighborsA++) {
+        *skipA= i;
+        break;
+      }
+    }
+  }
+  if (facetA == *neighborsB++)
+    *skipB= 0;
+  else if (facetA == *neighborsB++)
+    *skipB= 1;
+  else if (facetA == *neighborsB++)
+    *skipB= 2;
+  else {
+    for (j= 3; j < dim; j++) {
+      if (facetA == *neighborsB++) {
+        *skipB= j;
+        break;
+      }
+    }
+  }
+  if (i >= dim || j >= dim) {
+    fprintf (qh ferr, "qhull internal error (qh_facetintersect): f%d or f%d not in others neighbors\n",
+            facetA->id, facetB->id);
+    qh_errexit2 (qh_ERRqhull, facetA, facetB);
+  }
+  intersect= qh_setnew_delnthsorted (facetA->vertices, qh hull_dim, *skipA, prepend);
+  trace4((qh ferr, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
+	  facetA->id, *skipA, facetB->id, *skipB));
+  return(intersect);
+} /* facetintersect */
+
+/*---------------------------------
+  
+  qh_gethash( hashsize, set, size, firstindex, skipelem )
+    return hashvalue for a set with firstindex and skipelem
+
+  notes:
+    assumes at least firstindex+1 elements
+    assumes skipelem is NULL, in set, or part of hash
+    
+    hashes memory addresses which may change over different runs of the same data
+    using sum for hash does badly in high d
+*/
+unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem) {
+  void **elemp= SETelemaddr_(set, firstindex, void);
+  ptr_intT hash = 0, elem;
+  int i;
+
+  switch (size-firstindex) {
+  case 1:
+    hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem;
+    break;
+  case 2:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem;
+    break;
+  case 3:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      - (ptr_intT) skipelem;
+    break;
+  case 4:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] - (ptr_intT) skipelem;
+    break;
+  case 5:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem;
+    break;
+  case 6:
+    hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2]
+      + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5]
+      - (ptr_intT) skipelem;
+    break;
+  default:
+    hash= 0;
+    i= 3;
+    do {     /* this is about 10% in 10-d */
+      if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) {
+        hash ^= (elem << i) + (elem >> (32-i));
+	i += 3;
+	if (i >= 32)
+	  i -= 32;
+      }
+    }while(*elemp);
+    break;
+  }
+  hash %= (ptr_intT) hashsize;
+  /* hash= 0; for debugging purposes */
+  return hash;
+} /* gethash */
+
+/*---------------------------------
+  
+  qh_makenewfacet( vertices, toporient, horizon )
+    creates a toporient? facet from vertices
+
+  returns:
+    returns newfacet
+      adds newfacet to qh.facet_list
+      newfacet->vertices= vertices
+      if horizon
+        newfacet->neighbor= horizon, but not vice versa
+    newvertex_list updated with vertices
+*/
+facetT *qh_makenewfacet(setT *vertices, boolT toporient,facetT *horizon) {
+  facetT *newfacet;
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (!vertex->newlist) {
+      qh_removevertex (vertex);
+      qh_appendvertex (vertex);
+    }
+  }
+  newfacet= qh_newfacet();
+  newfacet->vertices= vertices;
+  newfacet->toporient= toporient;
+  if (horizon)
+    qh_setappend(&(newfacet->neighbors), horizon);
+  qh_appendfacet(newfacet);
+  return(newfacet);
+} /* makenewfacet */
+
+
+/*---------------------------------
+  
+  qh_makenewplanes()
+    make new hyperplanes for facets on qh.newfacet_list
+
+  returns:
+    all facets have hyperplanes or are marked for   merging
+    doesn't create hyperplane if horizon is coplanar (will merge)
+    updates qh.min_vertex if qh.JOGGLEmax
+
+  notes:
+    facet->f.samecycle is defined for facet->mergehorizon facets
+*/
+void qh_makenewplanes (void /* newfacet_list */) {
+  facetT *newfacet;
+
+  FORALLnew_facets {
+    if (!newfacet->mergehorizon)
+      qh_setfacetplane (newfacet);  
+  }
+  if (qh JOGGLEmax < REALmax/2)  
+    minimize_(qh min_vertex, -wwval_(Wnewvertexmax));
+} /* makenewplanes */
+
+/*---------------------------------
+  
+  qh_makenew_nonsimplicial( visible, apex, numnew )
+    make new facets for ridges of a visible facet
+    
+  returns:
+    first newfacet, bumps numnew as needed
+    attaches new facets if !qh.ONLYgood
+    marks ridge neighbors for simplicial visible
+    if (qh.ONLYgood)
+      ridges on newfacet, horizon, and visible
+    else
+      ridge and neighbors between newfacet and   horizon
+      visible facet's ridges are deleted    
+
+  notes:
+    qh.visit_id if visible has already been processed
+    sets neighbor->seen for building f.samecycle
+      assumes all 'seen' flags initially false
+    
+  design:
+    for each ridge of visible facet
+      get neighbor of visible facet
+      if neighbor was already processed
+        delete the ridge (will delete all visible facets later)
+      if neighbor is a horizon facet
+        create a new facet
+        if neighbor coplanar
+          adds newfacet to f.samecycle for later merging
+        else 
+          updates neighbor's neighbor set
+          (checks for non-simplicial facet with multiple ridges to visible facet)
+        updates neighbor's ridge set
+        (checks for simplicial neighbor to non-simplicial visible facet)
+	(deletes ridge if neighbor is simplicial)
+          
+*/
+#ifndef qh_NOmerge
+facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew) {
+  void **freelistp; /* used !qh_NOmem */
+  ridgeT *ridge, **ridgep;
+  facetT *neighbor, *newfacet= NULL, *samecycle;
+  setT *vertices;
+  boolT toporient;
+  int ridgeid;
+
+  FOREACHridge_(visible->ridges) {
+    ridgeid= ridge->id;
+    neighbor= otherfacet_(ridge, visible);
+    if (neighbor->visible) {
+      if (!qh ONLYgood) {
+        if (neighbor->visitid == qh visit_id) {
+          qh_setfree (&(ridge->vertices));  /* delete on 2nd visit */
+	  qh_memfree_(ridge, sizeof(ridgeT), freelistp);
+	}
+      }
+    }else {  /* neighbor is an horizon facet */
+      toporient= (ridge->top == visible);
+      vertices= qh_setnew (qh hull_dim); /* makes sure this is quick */
+      qh_setappend (&vertices, apex);
+      qh_setappend_set (&vertices, ridge->vertices);
+      newfacet= qh_makenewfacet(vertices, toporient, neighbor);
+      (*numnew)++;
+      if (neighbor->coplanar) {
+	newfacet->mergehorizon= True;
+        if (!neighbor->seen) {
+          newfacet->f.samecycle= newfacet;
+          neighbor->f.newcycle= newfacet;
+        }else {
+          samecycle= neighbor->f.newcycle;
+          newfacet->f.samecycle= samecycle->f.samecycle;
+          samecycle->f.samecycle= newfacet;
+	}
+      }
+      if (qh ONLYgood) {
+        if (!neighbor->simplicial)
+ 	  qh_setappend(&(newfacet->ridges), ridge);
+      }else {  /* qh_attachnewfacets */
+        if (neighbor->seen) {
+	  if (neighbor->simplicial) {
+	    fprintf (qh ferr, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n", 
+	           neighbor->id, visible->id);
+	    qh_errexit2 (qh_ERRqhull, neighbor, visible);
+	  }
+	  qh_setappend (&(neighbor->neighbors), newfacet);
+	}else
+          qh_setreplace (neighbor->neighbors, visible, newfacet);
+        if (neighbor->simplicial) {
+          qh_setdel (neighbor->ridges, ridge);
+          qh_setfree (&(ridge->vertices)); 
+	  qh_memfree (ridge, sizeof(ridgeT));
+	}else {
+ 	  qh_setappend(&(newfacet->ridges), ridge);
+ 	  if (toporient)
+ 	    ridge->top= newfacet;
+ 	  else
+ 	    ridge->bottom= newfacet;
+ 	}
+      trace4((qh ferr, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",
+	    newfacet->id, apex->id, ridgeid, neighbor->id));
+      }
+    }
+    neighbor->seen= True;        
+  } /* for each ridge */
+  if (!qh ONLYgood)
+    SETfirst_(visible->ridges)= NULL;
+  return newfacet;
+} /* makenew_nonsimplicial */
+#else /* qh_NOmerge */
+facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew) {
+  return NULL;
+}
+#endif /* qh_NOmerge */
+
+/*---------------------------------
+  
+  qh_makenew_simplicial( visible, apex, numnew )
+    make new facets for simplicial visible facet and apex
+
+  returns:
+    attaches new facets if (!qh.ONLYgood)
+      neighbors between newfacet and horizon
+
+  notes:
+    nop if neighbor->seen or neighbor->visible (see qh_makenew_nonsimplicial)
+
+  design:
+    locate neighboring horizon facet for visible facet
+    determine vertices and orientation
+    create new facet
+    if coplanar,
+      add new facet to f.samecycle
+    update horizon facet's neighbor list        
+*/
+facetT *qh_makenew_simplicial (facetT *visible, vertexT *apex, int *numnew) {
+  facetT *neighbor, **neighborp, *newfacet= NULL;
+  setT *vertices;
+  boolT flip, toporient;
+  int horizonskip, visibleskip;
+
+  FOREACHneighbor_(visible) {
+    if (!neighbor->seen && !neighbor->visible) {
+      vertices= qh_facetintersect(neighbor,visible, &horizonskip, &visibleskip, 1);
+      SETfirst_(vertices)= apex;
+      flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1));
+      if (neighbor->toporient)         
+	toporient= horizonskip & 0x1;
+      else
+	toporient= (horizonskip & 0x1) ^ 0x1;
+      newfacet= qh_makenewfacet(vertices, toporient, neighbor);
+      (*numnew)++;
+      if (neighbor->coplanar && (qh PREmerge || qh MERGEexact)) {
+#ifndef qh_NOmerge
+	newfacet->f.samecycle= newfacet;
+	newfacet->mergehorizon= True;
+#endif
+      }
+      if (!qh ONLYgood)
+        SETelem_(neighbor->neighbors, horizonskip)= newfacet;
+      trace4((qh ferr, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n",
+	    newfacet->id, toporient, apex->id, neighbor->id, horizonskip,
+	      neighbor->toporient, visible->id, visibleskip, flip));
+    }
+  }
+  return newfacet;
+} /* makenew_simplicial */
+
+/*---------------------------------
+  
+  qh_matchneighbor( newfacet, newskip, hashsize, hashcount )
+    either match subridge of newfacet with neighbor or add to hash_table
+
+  returns:
+    duplicate ridges are unmatched and marked by qh_DUPLICATEridge
+
+  notes:
+    ridge is newfacet->vertices w/o newskip vertex
+    do not allocate memory (need to free hash_table cleanly)
+    uses linear hash chains
+  
+  see also:
+    qh_matchduplicates
+
+  design:
+    for each possible matching facet in qh.hash_table
+      if vertices match
+        set ismatch, if facets have opposite orientation
+        if ismatch and matching facet doesn't have a match
+          match the facets by updating their neighbor sets
+        else
+          indicate a duplicate ridge
+          set facet hyperplane for later testing
+          add facet to hashtable
+          unless the other facet was already a duplicate ridge
+            mark both facets with a duplicate ridge
+            add other facet (if defined) to hash table
+*/
+void qh_matchneighbor (facetT *newfacet, int newskip, int hashsize, int *hashcount) {
+  boolT newfound= False;   /* True, if new facet is already in hash chain */
+  boolT same, ismatch;
+  int hash, scan;
+  facetT *facet, *matchfacet;
+  int skip, matchskip;
+
+  hash= (int)qh_gethash (hashsize, newfacet->vertices, qh hull_dim, 1, 
+                     SETelem_(newfacet->vertices, newskip));
+  trace4((qh ferr, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",
+	  newfacet->id, newskip, hash, *hashcount));
+  zinc_(Zhashlookup);
+  for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT)); 
+       scan= (++scan >= hashsize ? 0 : scan)) {
+    if (facet == newfacet) {
+      newfound= True;
+      continue;
+    }
+    zinc_(Zhashtests);
+    if (qh_matchvertices (1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
+      if (SETelem_(newfacet->vertices, newskip) == 
+          SETelem_(facet->vertices, skip)) {
+        qh_precision ("two facets with the same vertices");
+        fprintf (qh ferr, "qhull precision error: Vertex sets are the same for f%d and f%d.  Can not force output.\n",
+          facet->id, newfacet->id);
+        qh_errexit2 (qh_ERRprec, facet, newfacet);
+      }
+      ismatch= (same == (newfacet->toporient ^ facet->toporient));
+      matchfacet= SETelemt_(facet->neighbors, skip, facetT);
+      if (ismatch && !matchfacet) {
+        SETelem_(facet->neighbors, skip)= newfacet;
+        SETelem_(newfacet->neighbors, newskip)= facet;
+        (*hashcount)--;
+        trace4((qh ferr, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",
+           facet->id, skip, newfacet->id, newskip));
+        return;
+      }
+      if (!qh PREmerge && !qh MERGEexact) {
+        qh_precision ("a ridge with more than two neighbors");
+	fprintf (qh ferr, "qhull precision error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors.  Can not continue.\n",
+		 facet->id, newfacet->id, getid_(matchfacet));
+	qh_errexit2 (qh_ERRprec, facet, newfacet);
+      }
+      SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;
+      newfacet->dupridge= True;
+      if (!newfacet->normal)
+	qh_setfacetplane (newfacet);
+      qh_addhash (newfacet, qh hash_table, hashsize, hash);
+      (*hashcount)++;
+      if (!facet->normal)
+	qh_setfacetplane (facet);
+      if (matchfacet != qh_DUPLICATEridge) {
+	SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;
+	facet->dupridge= True;
+	if (!facet->normal)
+	  qh_setfacetplane (facet);
+	if (matchfacet) {
+	  matchskip= qh_setindex (matchfacet->neighbors, facet);
+	  SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge;
+	  matchfacet->dupridge= True;
+	  if (!matchfacet->normal)
+	    qh_setfacetplane (matchfacet);
+	  qh_addhash (matchfacet, qh hash_table, hashsize, hash);
+	  *hashcount += 2;
+	}
+      }
+      trace4((qh ferr, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n",
+	   newfacet->id, newskip, facet->id, skip, 
+	   (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)), 
+	   ismatch, hash));
+      return; /* end of duplicate ridge */
+    }
+  }
+  if (!newfound) 
+    SETelem_(qh hash_table, scan)= newfacet;  /* same as qh_addhash */
+  (*hashcount)++;
+  trace4((qh ferr, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
+           newfacet->id, newskip, hash));
+} /* matchneighbor */
+
+
+/*---------------------------------
+  
+  qh_matchnewfacets()
+    match newfacets in qh.newfacet_list to their newfacet neighbors
+
+  returns:
+    qh.newfacet_list with full neighbor sets
+      get vertices with nth neighbor by deleting nth vertex
+    if qh.PREmerge/MERGEexact or qh.FORCEoutput 
+      sets facet->flippped if flipped normal (also prevents point partitioning)
+    if duplicate ridges and qh.PREmerge/MERGEexact
+      sets facet->dupridge
+      missing neighbor links identifies extra ridges to be merging (qh_MERGEridge)
+
+  notes:
+    newfacets already have neighbor[0] (horizon facet)
+    assumes qh.hash_table is NULL
+    vertex->neighbors has not been updated yet
+    do not allocate memory after qh.hash_table (need to free it cleanly)
+
+  design:
+    delete neighbor sets for all new facets
+    initialize a hash table
+    for all new facets
+      match facet with neighbors
+    if unmatched facets (due to duplicate ridges)
+      for each new facet with a duplicate ridge
+        match it with a facet
+    check for flipped facets
+*/
+void qh_matchnewfacets (void /* qh newfacet_list */) {
+  int numnew=0, hashcount=0, newskip;
+  facetT *newfacet, *neighbor;
+  int dim= qh hull_dim, hashsize, neighbor_i, neighbor_n;
+  setT *neighbors;
+#ifndef qh_NOtrace
+  int facet_i, facet_n, numfree= 0;
+  facetT *facet;
+#endif
+  
+  trace1((qh ferr, "qh_matchnewfacets: match neighbors for new facets.\n"));
+  FORALLnew_facets {
+    numnew++;
+    {  /* inline qh_setzero (newfacet->neighbors, 1, qh hull_dim); */
+      neighbors= newfacet->neighbors;
+      neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/
+      memset ((char *)SETelemaddr_(neighbors, 1, void), 0, dim * SETelemsize);
+    }    
+  }
+  qh_newhashtable (numnew*(qh hull_dim-1)); /* twice what is normally needed,
+                                     but every ridge could be DUPLICATEridge */
+  hashsize= qh_setsize (qh hash_table);
+  FORALLnew_facets {
+    for (newskip=1; newskipneighbors, k, facetT);
+	  if (!neighbor || neighbor == qh_DUPLICATEridge)
+	    count++;
+	}
+	if (facet == newfacet)
+	  break;
+      }
+      if (count != hashcount) {
+	fprintf (qh ferr, "qh_matchnewfacets: after adding facet %d, hashcount %d != count %d\n",
+		 newfacet->id, hashcount, count);
+	qh_errexit (qh_ERRqhull, newfacet, NULL);
+      }
+    }
+#endif  /* end of trap code */
+  }
+  if (hashcount) {
+    FORALLnew_facets {
+      if (newfacet->dupridge) {
+        FOREACHneighbor_i_(newfacet) {
+          if (neighbor == qh_DUPLICATEridge) {
+            qh_matchduplicates (newfacet, neighbor_i, hashsize, &hashcount);
+         	    /* this may report MERGEfacet */
+	  }
+        }
+      }
+    }
+  }
+  if (hashcount) {
+    fprintf (qh ferr, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n",
+        hashcount);
+    qh_printhashtable (qh ferr);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+#ifndef qh_NOtrace
+  if (qh IStracing >= 2) {
+    FOREACHfacet_i_(qh hash_table) {
+      if (!facet)
+        numfree++;
+    }
+    fprintf (qh ferr, "qh_matchnewfacets: %d new facets, %d unused hash entries .  hashsize %d\n",
+	     numnew, numfree, qh_setsize (qh hash_table));
+  }
+#endif /* !qh_NOtrace */
+  qh_setfree (&qh hash_table);
+  if (qh PREmerge || qh MERGEexact) {
+    if (qh IStracing >= 4)
+      qh_printfacetlist (qh newfacet_list, NULL, qh_ALL);
+    FORALLnew_facets {
+      if (newfacet->normal)
+	qh_checkflipped (newfacet, NULL, qh_ALL);
+    }
+  }else if (qh FORCEoutput)
+    qh_checkflipped_all (qh newfacet_list);  /* prints warnings for flipped */
+} /* matchnewfacets */
+
+    
+/*---------------------------------
+  
+  qh_matchvertices( firstindex, verticesA, skipA, verticesB, skipB, same )
+    tests whether vertices match with a single skip
+    starts match at firstindex since all new facets have a common vertex
+
+  returns:
+    true if matched vertices
+    skip index for each set
+    sets same iff vertices have the same orientation
+
+  notes:
+    assumes skipA is in A and both sets are the same size
+
+  design:
+    set up pointers
+    scan both sets checking for a match
+    test orientation
+*/
+boolT qh_matchvertices (int firstindex, setT *verticesA, int skipA, 
+       setT *verticesB, int *skipB, boolT *same) {
+  vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;
+
+  elemAp= SETelemaddr_(verticesA, firstindex, vertexT);
+  elemBp= SETelemaddr_(verticesB, firstindex, vertexT);
+  skipAp= SETelemaddr_(verticesA, skipA, vertexT);
+  do if (elemAp != skipAp) {
+    while (*elemAp != *elemBp++) {
+      if (skipBp)
+        return False;
+      skipBp= elemBp;  /* one extra like FOREACH */
+    }
+  }while(*(++elemAp));
+  if (!skipBp)
+    skipBp= ++elemBp;
+  *skipB= SETindex_(verticesB, skipB);
+  *same= !(((ptr_intT)skipA & 0x1) ^ ((ptr_intT)*skipB & 0x1));
+  trace4((qh ferr, "qh_matchvertices: matched by skip %d (v%d) and skip %d (v%d) same? %d\n",
+	  skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));
+  return (True);
+} /* matchvertices */
+
+/*---------------------------------
+  
+  qh_newfacet()
+    return a new facet 
+
+  returns:
+    all fields initialized or cleared   (NULL)
+    preallocates neighbors set
+*/
+facetT *qh_newfacet(void) {
+  facetT *facet;
+  void **freelistp; /* used !qh_NOmem */
+  
+  qh_memalloc_(sizeof(facetT), freelistp, facet, facetT);
+  memset ((char *)facet, 0, sizeof(facetT));
+  if (qh facet_id == qh tracefacet_id)
+    qh tracefacet= facet;
+  facet->id= qh facet_id++;
+  facet->neighbors= qh_setnew(qh hull_dim);
+#if !qh_COMPUTEfurthest
+  facet->furthestdist= 0.0;
+#endif
+#if qh_MAXoutside
+  if (qh FORCEoutput && qh APPROXhull)
+    facet->maxoutside= qh MINoutside;
+  else
+    facet->maxoutside= qh DISTround;
+#endif
+  facet->simplicial= True;
+  facet->good= True;
+  facet->newfacet= True;
+  trace4((qh ferr, "qh_newfacet: created facet f%d\n", facet->id));
+  return (facet);
+} /* newfacet */
+
+
+/*---------------------------------
+  
+  qh_newridge()
+    return a new ridge
+*/
+ridgeT *qh_newridge(void) {
+  ridgeT *ridge;
+  void **freelistp;   /* used !qh_NOmem */
+
+  qh_memalloc_(sizeof(ridgeT), freelistp, ridge, ridgeT);
+  memset ((char *)ridge, 0, sizeof(ridgeT));
+  zinc_(Ztotridges);
+  if (qh ridge_id == 0xFFFFFF) {
+    fprintf(qh ferr, "\
+qhull warning: more than %d ridges.  ID field overflows and two ridges\n\
+may have the same identifier.  Otherwise output ok.\n", 0xFFFFFF);
+  }
+  ridge->id= qh ridge_id++;     
+  trace4((qh ferr, "qh_newridge: created ridge r%d\n", ridge->id));
+  return (ridge);
+} /* newridge */
+
+
+/*---------------------------------
+  
+  qh_pointid(  )
+    return id for a point, 
+    returns -3 if null, -2 if interior, or -1 if not known
+
+  alternative code:
+    unsigned long id;
+    id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size;
+
+  notes:
+    if point not in point array
+      the code does a comparison of unrelated pointers.
+*/
+int qh_pointid (pointT *point) {
+  long offset, id;
+
+  if (!point)
+    id= -3;
+  else if (point == qh interior_point)
+    id= -2;
+  else if (point >= qh first_point
+  && point < qh first_point + qh num_points * qh hull_dim) {
+    offset= point - qh first_point;
+    id= offset / qh hull_dim;
+  }else if ((id= qh_setindex (qh other_points, point)) != -1)
+    id += qh num_points;
+  else
+    id= -1;
+  return (int) id;
+} /* pointid */
+  
+/*---------------------------------
+  
+  qh_removefacet( facet )
+    unlinks facet from qh.facet_list,
+
+  returns:
+    updates qh.facet_list .newfacet_list .facet_next visible_list
+    decrements qh.num_facets
+
+  see:
+    qh_appendfacet
+*/
+void qh_removefacet(facetT *facet) {
+  facetT *next= facet->next, *previous= facet->previous;
+  
+  if (facet == qh newfacet_list)
+    qh newfacet_list= next;
+  if (facet == qh facet_next)
+    qh facet_next= next;
+  if (facet == qh visible_list)
+    qh visible_list= next; 
+  if (previous) {
+    previous->next= next;
+    next->previous= previous;
+  }else {  /* 1st facet in qh facet_list */
+    qh facet_list= next;
+    qh facet_list->previous= NULL;
+  }
+  qh num_facets--;
+  trace4((qh ferr, "qh_removefacet: remove f%d from facet_list\n", facet->id));
+} /* removefacet */
+
+
+/*---------------------------------
+  
+  qh_removevertex( vertex )
+    unlinks vertex from qh.vertex_list,
+
+  returns:
+    updates qh.vertex_list .newvertex_list 
+    decrements qh.num_vertices
+*/
+void qh_removevertex(vertexT *vertex) {
+  vertexT *next= vertex->next, *previous= vertex->previous;
+  
+  if (vertex == qh newvertex_list)
+    qh newvertex_list= next;
+  if (previous) {
+    previous->next= next;
+    next->previous= previous;
+  }else {  /* 1st vertex in qh vertex_list */
+    qh vertex_list= vertex->next;
+    qh vertex_list->previous= NULL;
+  }
+  qh num_vertices--;
+  trace4((qh ferr, "qh_removevertex: remove v%d from vertex_list\n", vertex->id));
+} /* removevertex */
+
+
+/*---------------------------------
+  
+  qh_updatevertices()
+    update vertex neighbors and delete interior vertices
+
+  returns:
+    if qh.VERTEXneighbors, updates neighbors for each vertex
+      if qh.newvertex_list, 
+         removes visible neighbors  from vertex neighbors
+      if qh.newfacet_list
+         adds new facets to vertex neighbors
+    if qh.visible_list
+       interior vertices added to qh.del_vertices for later partitioning
+
+  design:
+    if qh.VERTEXneighbors
+      deletes references to visible facets from vertex neighbors
+      appends new facets to the neighbor list for each vertex
+      checks all vertices of visible facets
+        removes visible facets from neighbor lists
+        marks unused vertices for deletion
+*/
+void qh_updatevertices (void /*qh newvertex_list, newfacet_list, visible_list*/) {
+  facetT *newfacet= NULL, *neighbor, **neighborp, *visible;
+  vertexT *vertex, **vertexp;
+
+  trace3((qh ferr, "qh_updatevertices: delete interior vertices and update vertex->neighbors\n"));
+  if (qh VERTEXneighbors) {
+    FORALLvertex_(qh newvertex_list) {
+      FOREACHneighbor_(vertex) {
+	if (neighbor->visible) 
+	  SETref_(neighbor)= NULL;
+      }
+      qh_setcompact (vertex->neighbors);
+    }
+    FORALLnew_facets {
+      FOREACHvertex_(newfacet->vertices)
+        qh_setappend (&vertex->neighbors, newfacet);
+    }
+    FORALLvisible_facets {
+      FOREACHvertex_(visible->vertices) {
+        if (!vertex->newlist && !vertex->deleted) {
+  	  FOREACHneighbor_(vertex) { /* this can happen under merging */
+	    if (!neighbor->visible)
+	      break;
+	  }
+	  if (neighbor)
+	    qh_setdel (vertex->neighbors, visible);
+	  else {
+	    vertex->deleted= True;
+	    qh_setappend (&qh del_vertices, vertex);
+	    trace2((qh ferr, "qh_updatevertices: delete vertex p%d (v%d) in f%d\n",
+		  qh_pointid(vertex->point), vertex->id, visible->id));
+  	  }
+        }
+      }
+    }
+  }else {  /* !VERTEXneighbors */
+    FORALLvisible_facets {
+      FOREACHvertex_(visible->vertices) {
+        if (!vertex->newlist && !vertex->deleted) {
+          vertex->deleted= True;
+	  qh_setappend (&qh del_vertices, vertex);
+	  trace2((qh ferr, "qh_updatevertices: delete vertex p%d (v%d) in f%d\n",
+		  qh_pointid(vertex->point), vertex->id, visible->id));
+  	}
+      }
+    }
+  }
+} /* updatevertices */
+
+
+
diff --git a/extern/qhull/src/poly.h b/extern/qhull/src/poly.h
new file mode 100644
index 00000000000..294ec9527fc
--- /dev/null
+++ b/extern/qhull/src/poly.h
@@ -0,0 +1,290 @@
+/*
  ---------------------------------
+
+   poly.h 
+   header file for poly.c and poly2.c
+
+   see qh-poly.htm, qhull.h and poly.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFpoly
+#define qhDEFpoly 1
+
+/*===============   constants ========================== */
+
+/*----------------------------------
+  
+  ALGORITHMfault   
+    use as argument to checkconvex() to report errors during buildhull
+*/
+#define qh_ALGORITHMfault 0
+
+/*----------------------------------
+  
+  DATAfault        
+    use as argument to checkconvex() to report errors during initialhull
+*/
+#define qh_DATAfault 1
+
+/*----------------------------------
+  
+  DUPLICATEridge
+    special value for facet->neighbor to indicate a duplicate ridge
+  
+  notes:
+    set by matchneighbor, used by matchmatch and mark_dupridge
+*/
+#define qh_DUPLICATEridge ( facetT * ) 1L
+
+/*----------------------------------
+  
+  MERGEridge       flag in facet
+    special value for facet->neighbor to indicate a merged ridge
+  
+  notes:
+    set by matchneighbor, used by matchmatch and mark_dupridge
+*/
+#define qh_MERGEridge ( facetT * ) 2L
+
+
+/*============ -structures- ====================*/
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+  
+  FORALLfacet_( facetlist ) { ... }
+    assign 'facet' to each facet in facetlist
+    
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+    
+  see:
+    FORALLfacets
+*/
+#define FORALLfacet_( facetlist ) if ( facetlist ) for( facet=( facetlist );facet && facet->next;facet=facet->next )
+
+/*----------------------------------
+  
+  FORALLnew_facets { ... } 
+    assign 'newfacet' to each facet in qh.newfacet_list
+    
+  notes:
+    uses 'facetT *newfacet;'
+    at exit, newfacet==NULL
+*/
+#define FORALLnew_facets for( newfacet=qh newfacet_list;newfacet && newfacet->next;newfacet=newfacet->next )
+
+/*----------------------------------
+  
+  FORALLvertex_( vertexlist ) { ... }
+    assign 'vertex' to each vertex in vertexlist
+    
+  notes:
+    uses 'vertexT *vertex;'
+    at exit, vertex==NULL
+*/
+#define FORALLvertex_( vertexlist ) for ( vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )
+
+/*----------------------------------
+  
+  FORALLvisible_facets { ... }
+    assign 'visible' to each visible facet in qh.visible_list
+    
+  notes:
+    uses 'vacetT *visible;'
+    at exit, visible==NULL
+*/
+#define FORALLvisible_facets for (visible=qh visible_list; visible && visible->visible; visible= visible->next)
+
+/*----------------------------------
+  
+  FORALLsame_( newfacet ) { ... } 
+    assign 'same' to each facet in newfacet->f.samecycle
+    
+  notes:
+    uses 'facetT *same;'
+    stops when it returns to newfacet
+*/
+#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)
+
+/*----------------------------------
+  
+  FORALLsame_cycle_( newfacet ) { ... } 
+    assign 'same' to each facet in newfacet->f.samecycle
+    
+  notes:
+    uses 'facetT *same;'
+    at exit, same == NULL
+*/
+#define FORALLsame_cycle_(newfacet) \
+     for (same= newfacet->f.samecycle; \
+         same; same= (same == newfacet ?  NULL : same->f.samecycle))
+
+/*----------------------------------
+  
+  FOREACHneighborA_( facet ) { ... }
+    assign 'neighborA' to each neighbor in facet->neighbors
+  
+  FOREACHneighborA_( vertex ) { ... }
+    assign 'neighborA' to each neighbor in vertex->neighbors
+  
+  declare:
+    facetT *neighborA, **neighborAp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighborA_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighborA)
+
+/*----------------------------------
+  
+  FOREACHvisible_( facets ) { ... } 
+    assign 'visible' to each facet in facets
+    
+  notes:
+    uses 'facetT *facet, *facetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
+
+/*----------------------------------
+  
+  FOREACHnewfacet_( facets ) { ... } 
+    assign 'newfacet' to each facet in facets
+    
+  notes:
+    uses 'facetT *newfacet, *newfacetp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
+
+/*----------------------------------
+  
+  FOREACHvertexA_( vertices ) { ... } 
+    assign 'vertexA' to each vertex in vertices
+    
+  notes:
+    uses 'vertexT *vertexA, *vertexAp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
+
+/*----------------------------------
+  
+  FOREACHvertexreverse12_( vertices ) { ... } 
+    assign 'vertex' to each vertex in vertices
+    reverse order of first two vertices
+    
+  notes:
+    uses 'vertexT *vertex, *vertexp;'
+    see FOREACHsetelement_
+*/
+#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
+
+
+/*=============== prototypes poly.c in alphabetical order ================*/
+
+void    qh_appendfacet(facetT *facet);
+void    qh_appendvertex(vertexT *vertex);
+void 	qh_attachnewfacets (void);
+boolT   qh_checkflipped (facetT *facet, realT *dist, boolT allerror);
+void	qh_delfacet(facetT *facet);
+void 	qh_deletevisible(void /*qh visible_list, qh horizon_list*/);
+setT   *qh_facetintersect (facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
+unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem);
+facetT *qh_makenewfacet(setT *vertices, boolT toporient, facetT *facet);
+void    qh_makenewplanes ( void /* newfacet_list */);
+facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew);
+facetT *qh_makenew_simplicial (facetT *visible, vertexT *apex, int *numnew);
+void    qh_matchneighbor (facetT *newfacet, int newskip, int hashsize,
+			  int *hashcount);
+void	qh_matchnewfacets (void);
+boolT   qh_matchvertices (int firstindex, setT *verticesA, int skipA, 
+			  setT *verticesB, int *skipB, boolT *same);
+facetT *qh_newfacet(void);
+ridgeT *qh_newridge(void);
+int     qh_pointid (pointT *point);
+void 	qh_removefacet(facetT *facet);
+void 	qh_removevertex(vertexT *vertex);
+void    qh_updatevertices (void);
+
+
+/*========== -prototypes poly2.c in alphabetical order ===========*/
+
+void    qh_addhash (void* newelem, setT *hashtable, int hashsize, unsigned hash);
+void 	qh_check_bestdist (void);
+void    qh_check_maxout (void);
+void    qh_check_output (void);
+void    qh_check_point (pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2);
+void   	qh_check_points(void);
+void 	qh_checkconvex(facetT *facetlist, int fault);
+void    qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp);
+void 	qh_checkflipped_all (facetT *facetlist);
+void 	qh_checkpolygon(facetT *facetlist);
+void    qh_checkvertex (vertexT *vertex);
+void 	qh_clearcenters (qh_CENTER type);
+void 	qh_createsimplex(setT *vertices);
+void 	qh_delridge(ridgeT *ridge);
+void    qh_delvertex (vertexT *vertex);
+setT   *qh_facet3vertex (facetT *facet);
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+facetT *qh_findfacet_all (pointT *point, realT *bestdist, boolT *isoutside,
+			  int *numpart);
+int 	qh_findgood (facetT *facetlist, int goodhorizon);
+void 	qh_findgood_all (facetT *facetlist);
+void    qh_furthestnext (void /* qh facet_list */);
+void    qh_furthestout (facetT *facet);
+void    qh_infiniteloop (facetT *facet);
+void 	qh_initbuild(void);
+void 	qh_initialhull(setT *vertices);
+setT   *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints);
+vertexT *qh_isvertex (pointT *point, setT *vertices);
+vertexT *qh_makenewfacets (pointT *point /*horizon_list, visible_list*/);
+void    qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount);
+void    qh_nearcoplanar ( void /* qh.facet_list */);
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp);
+int 	qh_newhashtable(int newsize);
+vertexT *qh_newvertex(pointT *point);
+ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp);
+void    qh_outcoplanar (void /* facet_list */);
+pointT *qh_point (int id);
+void 	qh_point_add (setT *set, pointT *point, void *elem);
+setT   *qh_pointfacet (void /*qh facet_list*/);
+setT   *qh_pointvertex (void /*qh facet_list*/);
+void 	qh_prependfacet(facetT *facet, facetT **facetlist);
+void	qh_printhashtable(FILE *fp);
+void    qh_printlists (void);
+void    qh_resetlists (boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/);
+void    qh_setvoronoi_all (void);
+void	qh_triangulate (void /*qh facet_list*/);
+void    qh_triangulate_facet (facetT *facetA, vertexT **first_vertex);
+void    qh_triangulate_link (facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
+void	qh_triangulate_mirror (facetT *facetA, facetT *facetB);
+void    qh_triangulate_null (facetT *facetA);
+void    qh_vertexintersect(setT **vertexsetA,setT *vertexsetB);
+setT   *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB);
+void    qh_vertexneighbors (void /*qh facet_list*/);
+boolT 	qh_vertexsubset(setT *vertexsetA, setT *vertexsetB);
+
+
+#endif /* qhDEFpoly */
diff --git a/extern/qhull/src/poly2.c b/extern/qhull/src/poly2.c
new file mode 100644
index 00000000000..713faab8bed
--- /dev/null
+++ b/extern/qhull/src/poly2.c
@@ -0,0 +1,3070 @@
+/*
  ---------------------------------
+
+   poly2.c 
+   implements polygons and simplices
+
+   see qh-poly.htm, poly.h and qhull.h
+
+   frequently used code is in poly.c
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*======== functions in alphabetical order ==========*/
+
+/*---------------------------------
+  
+  qh_addhash( newelem, hashtable, hashsize, hash )
+    add newelem to linear hash table at hash if not already there
+*/
+void qh_addhash (void* newelem, setT *hashtable, int hashsize, unsigned hash) {
+  int scan;
+  void *elem;
+
+  for (scan= (int)hash; (elem= SETelem_(hashtable, scan)); 
+       scan= (++scan >= hashsize ? 0 : scan)) {
+    if (elem == newelem)
+      break;
+  }
+  /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
+  if (!elem)
+    SETelem_(hashtable, scan)= newelem;
+} /* addhash */
+
+/*---------------------------------
+  
+  qh_check_bestdist()
+    check that all points are within max_outside of the nearest facet
+    if qh.ONLYgood,
+      ignores !good facets
+
+  see: 
+    qh_check_maxout(), qh_outerinner()
+
+  notes:
+    only called from qh_check_points()
+      seldom used since qh.MERGING is almost always set
+    if notverified>0 at end of routine
+      some points were well inside the hull.  If the hull contains
+      a lens-shaped component, these points were not verified.  Use
+      options 'Qi Tv' to verify all points.  (Exhaustive check also verifies)
+
+  design:
+    determine facet for each point (if any)
+    for each point
+      start with the assigned facet or with the first facet
+      find the best facet for the point and check all coplanar facets
+      error if point is outside of facet
+*/
+void qh_check_bestdist (void) {
+  boolT waserror= False, unassigned;
+  facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
+  facetT *facetlist; 
+  realT dist, maxoutside, maxdist= -REALmax;
+  pointT *point;
+  int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0;
+  setT *facets;
+
+  trace1((qh ferr, "qh_check_bestdist: check points below nearest facet.  Facet_list f%d\n",
+      qh facet_list->id));
+  maxoutside= qh_maxouter();
+  maxoutside += qh DISTround;
+  /* one more qh.DISTround for check computation */
+  trace1((qh ferr, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
+  facets= qh_pointfacet (/*qh facet_list*/);
+  if (!qh_QUICKhelp && qh PRINTprecision)
+    fprintf (qh ferr, "\n\
+qhull output completed.  Verifying that %d points are\n\
+below %2.2g of the nearest %sfacet.\n",
+	     qh_setsize(facets), maxoutside, (qh ONLYgood ?  "good " : ""));
+  FOREACHfacet_i_(facets) {  /* for each point with facet assignment */
+    if (facet)
+      unassigned= False;
+    else {
+      unassigned= True;
+      facet= qh facet_list;
+    }
+    point= qh_point(facet_i);
+    if (point == qh GOODpointp)
+      continue;
+    qh_distplane(point, facet, &dist);
+    numpart++;
+    bestfacet= qh_findbesthorizon (!qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart);
+    /* occurs after statistics reported */
+    maximize_(maxdist, dist);
+    if (dist > maxoutside) {
+      if (qh ONLYgood && !bestfacet->good 
+	  && !((bestfacet= qh_findgooddist (point, bestfacet, &dist, &facetlist))
+	       && dist > maxoutside))
+	notgood++;
+      else {
+	waserror= True;
+	fprintf(qh ferr, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n", 
+		facet_i, bestfacet->id, dist, maxoutside);
+	if (errfacet1 != bestfacet) {
+	  errfacet2= errfacet1;
+	  errfacet1= bestfacet;
+	}
+      }
+    }else if (unassigned && dist < -qh MAXcoplanar)
+      notverified++;
+  }
+  qh_settempfree (&facets);
+  if (notverified && !qh DELAUNAY && !qh_QUICKhelp && qh PRINTprecision) 
+    fprintf(qh ferr, "\n%d points were well inside the hull.  If the hull contains\n\
+a lens-shaped component, these points were not verified.  Use\n\
+options 'Qci Tv' to verify all points.\n", notverified); 
+  if (maxdist > qh outside_err) {
+    fprintf( qh ferr, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull.  The maximum value (qh.outside_err) is %6.2g\n",
+              maxdist, qh outside_err);
+    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
+  }else if (waserror && qh outside_err > REALmax/2)
+    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
+  else if (waserror)
+    ;                       /* the error was logged to qh.ferr but does not effect the output */
+  trace0((qh ferr, "qh_check_bestdist: max distance outside %2.2g\n", maxdist));
+} /* check_bestdist */
+
+/*---------------------------------
+  
+  qh_check_maxout()
+    updates qh.max_outside by checking all points against bestfacet
+    if qh.ONLYgood, ignores !good facets
+
+  returns:
+    updates facet->maxoutside via qh_findbesthorizon()
+    sets qh.maxoutdone
+    if printing qh.min_vertex (qh_outerinner), 
+      it is updated to the current vertices
+    removes inside/coplanar points from coplanarset as needed
+
+  notes:
+    defines coplanar as min_vertex instead of MAXcoplanar 
+    may not need to check near-inside points because of qh.MAXcoplanar 
+      and qh.KEEPnearinside (before it was -DISTround)
+
+  see also:
+    qh_check_bestdist()
+
+  design:
+    if qh.min_vertex is needed
+      for all neighbors of all vertices
+        test distance from vertex to neighbor
+    determine facet for each point (if any)
+    for each point with an assigned facet
+      find the best facet for the point and check all coplanar facets
+        (updates outer planes)
+    remove near-inside points from coplanar sets
+*/
+#ifndef qh_NOmerge
+void qh_check_maxout (void) {
+  facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist;
+  realT dist, maxoutside, minvertex, old_maxoutside;
+  pointT *point;
+  int numpart= 0, facet_i, facet_n, notgood= 0;
+  setT *facets, *vertices;
+  vertexT *vertex;
+
+  trace1((qh ferr, "qh_check_maxout: check and update maxoutside for each facet.\n"));
+  maxoutside= minvertex= 0;
+  if (qh VERTEXneighbors 
+  && (qh PRINTsummary || qh KEEPinside || qh KEEPcoplanar 
+	|| qh TRACElevel || qh PRINTstatistics
+	|| qh PRINTout[0] == qh_PRINTsummary || qh PRINTout[0] == qh_PRINTnone)) { 
+    trace1((qh ferr, "qh_check_maxout: determine actual maxoutside and minvertex\n"));
+    vertices= qh_pointvertex (/*qh facet_list*/);
+    FORALLvertices {
+      FOREACHneighbor_(vertex) {
+        zinc_(Zdistvertex);  /* distance also computed by main loop below */
+	qh_distplane (vertex->point, neighbor, &dist);
+	minimize_(minvertex, dist);
+	if (-dist > qh TRACEdist || dist > qh TRACEdist 
+	|| neighbor == qh tracefacet || vertex == qh tracevertex)
+	  fprintf (qh ferr, "qh_check_maxout: p%d (v%d) is %.2g from f%d\n",
+		    qh_pointid (vertex->point), vertex->id, dist, neighbor->id);
+      }
+    }
+    if (qh MERGING) {
+      wmin_(Wminvertex, qh min_vertex);
+    }
+    qh min_vertex= minvertex;
+    qh_settempfree (&vertices);  
+  }
+  facets= qh_pointfacet (/*qh facet_list*/);
+  do {
+    old_maxoutside= fmax_(qh max_outside, maxoutside);
+    FOREACHfacet_i_(facets) {     /* for each point with facet assignment */
+      if (facet) { 
+	point= qh_point(facet_i);
+	if (point == qh GOODpointp)
+	  continue;
+	zinc_(Ztotcheck);
+	qh_distplane(point, facet, &dist);
+	numpart++;
+	bestfacet= qh_findbesthorizon (qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart);
+	if (bestfacet && dist > maxoutside) {
+	  if (qh ONLYgood && !bestfacet->good 
+	  && !((bestfacet= qh_findgooddist (point, bestfacet, &dist, &facetlist))
+	       && dist > maxoutside))
+	    notgood++;
+	  else
+	    maxoutside= dist;
+	}
+	if (dist > qh TRACEdist || (bestfacet && bestfacet == qh tracefacet))
+	  fprintf (qh ferr, "qh_check_maxout: p%d is %.2g above f%d\n",
+		     qh_pointid (point), dist, bestfacet->id);
+      }
+    }
+  }while 
+    (maxoutside > 2*old_maxoutside);
+    /* if qh.maxoutside increases substantially, qh_SEARCHdist is not valid 
+          e.g., RBOX 5000 s Z1 G1e-13 t1001200614 | qhull */
+  zzadd_(Zcheckpart, numpart);
+  qh_settempfree (&facets);
+  wval_(Wmaxout)= maxoutside - qh max_outside;
+  wmax_(Wmaxoutside, qh max_outside);
+  qh max_outside= maxoutside;
+  qh_nearcoplanar (/*qh.facet_list*/);
+  qh maxoutdone= True;
+  trace1((qh ferr, "qh_check_maxout: maxoutside %2.2g, min_vertex %2.2g, outside of not good %d\n",
+       maxoutside, qh min_vertex, notgood));
+} /* check_maxout */
+#else /* qh_NOmerge */
+void qh_check_maxout (void) {
+}
+#endif
+
+/*---------------------------------
+  
+  qh_check_output()
+    performs the checks at the end of qhull algorithm
+    Maybe called after voronoi output.  Will recompute otherwise centrums are Voronoi centers instead
+*/
+void qh_check_output (void) {
+  int i;
+
+  if (qh STOPcone)
+    return;
+  if (qh VERIFYoutput | qh IStracing | qh CHECKfrequently) {
+    qh_checkpolygon (qh facet_list);
+    qh_checkflipped_all (qh facet_list);
+    qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
+  }else if (!qh MERGING && qh_newstats (qhstat precision, &i)) {
+    qh_checkflipped_all (qh facet_list);
+    qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
+  }
+} /* check_output */
+
+
+
+/*---------------------------------
+  
+  qh_check_point( point, facet, maxoutside, maxdist, errfacet1, errfacet2 )
+    check that point is less than maxoutside from facet
+*/
+void qh_check_point (pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2) {
+  realT dist;
+
+  /* occurs after statistics reported */
+  qh_distplane(point, facet, &dist);
+  if (dist > *maxoutside) {
+    if (*errfacet1 != facet) {
+      *errfacet2= *errfacet1;
+      *errfacet1= facet;
+    }
+    fprintf(qh ferr, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n", 
+	      qh_pointid(point), facet->id, dist, *maxoutside);
+  }
+  maximize_(*maxdist, dist);
+} /* qh_check_point */
+
+
+/*---------------------------------
+  
+  qh_check_points()
+    checks that all points are inside all facets
+
+  notes:
+    if many points and qh_check_maxout not called (i.e., !qh.MERGING), 
+       calls qh_findbesthorizon (seldom done).
+    ignores flipped facets
+    maxoutside includes 2 qh.DISTrounds
+      one qh.DISTround for the computed distances in qh_check_points
+    qh_printafacet and qh_printsummary needs only one qh.DISTround
+    the computation for qh.VERIFYdirect does not account for qh.other_points
+
+  design:
+    if many points
+      use qh_check_bestdist()
+    else
+      for all facets
+        for all points
+          check that point is inside facet
+*/
+void qh_check_points (void) {
+  facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
+  realT total, maxoutside, maxdist= -REALmax;
+  pointT *point, **pointp, *pointtemp;
+  boolT testouter;
+
+  maxoutside= qh_maxouter();
+  maxoutside += qh DISTround;
+  /* one more qh.DISTround for check computation */
+  trace1((qh ferr, "qh_check_points: check all points below %2.2g of all facet planes\n",
+	  maxoutside));
+  if (qh num_good)   /* miss counts other_points and !good facets */
+     total= (float) qh num_good * qh num_points;
+  else
+     total= (float) qh num_facets * qh num_points;
+  if (total >= qh_VERIFYdirect && !qh maxoutdone) {
+    if (!qh_QUICKhelp && qh SKIPcheckmax && qh MERGING)
+      fprintf (qh ferr, "\n\
+qhull input warning: merging without checking outer planes ('Q5' or 'Po').\n\
+Verify may report that a point is outside of a facet.\n");
+    qh_check_bestdist();
+  }else {
+    if (qh_MAXoutside && qh maxoutdone)
+      testouter= True;
+    else
+      testouter= False;
+    if (!qh_QUICKhelp) {
+      if (qh MERGEexact)
+	fprintf (qh ferr, "\n\
+qhull input warning: exact merge ('Qx').  Verify may report that a point\n\
+is outside of a facet.  See qh-optq.htm#Qx\n");
+      else if (qh SKIPcheckmax || qh NOnearinside)
+	fprintf (qh ferr, "\n\
+qhull input warning: no outer plane check ('Q5') or no processing of\n\
+near-inside points ('Q8').  Verify may report that a point is outside\n\
+of a facet.\n");
+    }
+    if (qh PRINTprecision) {
+      if (testouter)
+	fprintf (qh ferr, "\n\
+Output completed.  Verifying that all points are below outer planes of\n\
+all %sfacets.  Will make %2.0f distance computations.\n", 
+	      (qh ONLYgood ?  "good " : ""), total);
+      else
+	fprintf (qh ferr, "\n\
+Output completed.  Verifying that all points are below %2.2g of\n\
+all %sfacets.  Will make %2.0f distance computations.\n", 
+	      maxoutside, (qh ONLYgood ?  "good " : ""), total);
+    }
+    FORALLfacets {
+      if (!facet->good && qh ONLYgood)
+        continue;
+      if (facet->flipped)
+        continue;
+      if (!facet->normal) {
+	fprintf( qh ferr, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id);
+        continue;
+      }
+      if (testouter) {
+#if qh_MAXoutside
+	maxoutside= facet->maxoutside + 2* qh DISTround;
+	/* one DISTround to actual point and another to computed point */
+#endif
+      }
+      FORALLpoints {
+	if (point != qh GOODpointp)
+	  qh_check_point (point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
+      }
+      FOREACHpoint_(qh other_points) {
+	if (point != qh GOODpointp)
+	  qh_check_point (point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2);
+      }
+    }
+    if (maxdist > qh outside_err) {
+      fprintf( qh ferr, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull.  The maximum value (qh.outside_err) is %6.2g\n",
+                maxdist, qh outside_err );
+      qh_errexit2( qh_ERRprec, errfacet1, errfacet2 );
+    }else if (errfacet1 && qh outside_err > REALmax/2)
+        qh_errexit2( qh_ERRprec, errfacet1, errfacet2 );
+    else if (errfacet1)
+        ;  /* the error was logged to qh.ferr but does not effect the output */
+    trace0((qh ferr, "qh_check_points: max distance outside %2.2g\n", maxdist));
+  }
+} /* check_points */
+
+
+/*---------------------------------
+  
+  qh_checkconvex( facetlist, fault )
+    check that each ridge in facetlist is convex
+    fault = qh_DATAfault if reporting errors
+          = qh_ALGORITHMfault otherwise
+
+  returns:
+    counts Zconcaveridges and Zcoplanarridges
+    errors if concaveridge or if merging an coplanar ridge
+
+  note:
+    if not merging, 
+      tests vertices for neighboring simplicial facets
+    else if ZEROcentrum, 
+      tests vertices for neighboring simplicial   facets
+    else 
+      tests centrums of neighboring facets
+
+  design:
+    for all facets
+      report flipped facets
+      if ZEROcentrum and simplicial neighbors
+        test vertices for neighboring simplicial facets
+      else
+        test centrum against all neighbors 
+*/
+void qh_checkconvex(facetT *facetlist, int fault) {
+  facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
+  vertexT *vertex;
+  realT dist;
+  pointT *centrum;
+  boolT waserror= False, centrum_warning= False, tempcentrum= False, allsimplicial;
+  int neighbor_i;
+
+  trace1((qh ferr, "qh_checkconvex: check all ridges are convex\n"));
+  if (!qh RERUN) {
+    zzval_(Zconcaveridges)= 0;
+    zzval_(Zcoplanarridges)= 0;
+  }
+  FORALLfacet_(facetlist) {
+    if (facet->flipped) {
+      qh_precision ("flipped facet");
+      fprintf (qh ferr, "qhull precision error: f%d is flipped (interior point is outside)\n",
+	       facet->id);
+      errfacet1= facet;
+      waserror= True;
+      continue;
+    }
+    if (qh MERGING && (!qh ZEROcentrum || !facet->simplicial || facet->tricoplanar))
+      allsimplicial= False;
+    else {
+      allsimplicial= True;
+      neighbor_i= 0;
+      FOREACHneighbor_(facet) {
+        vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT);
+	if (!neighbor->simplicial || neighbor->tricoplanar) {
+	  allsimplicial= False;
+	  continue;
+	}
+        qh_distplane (vertex->point, neighbor, &dist);
+        if (dist > -qh DISTround) {
+	  if (fault == qh_DATAfault) {
+            qh_precision ("coplanar or concave ridge");
+	    fprintf (qh ferr, "qhull precision error: initial simplex is not convex. Distance=%.2g\n", dist);
+	    qh_errexit(qh_ERRsingular, NULL, NULL);
+	  }
+          if (dist > qh DISTround) {
+            zzinc_(Zconcaveridges);
+            qh_precision ("concave ridge");
+            fprintf (qh ferr, "qhull precision error: f%d is concave to f%d, since p%d (v%d) is %6.4g above\n",
+              facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
+            errfacet1= facet;
+            errfacet2= neighbor;
+            waserror= True;
+          }else if (qh ZEROcentrum) {
+            if (dist > 0) {     /* qh_checkzero checks that dist < - qh DISTround */
+              zzinc_(Zcoplanarridges); 
+              qh_precision ("coplanar ridge");
+              fprintf (qh ferr, "qhull precision error: f%d is clearly not convex to f%d, since p%d (v%d) is %6.4g above\n",
+                facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
+              errfacet1= facet;
+              errfacet2= neighbor;
+              waserror= True;
+	    }
+	  }else {              
+            zzinc_(Zcoplanarridges);
+            qh_precision ("coplanar ridge");
+            trace0((qh ferr, "qhull precision error: f%d may be coplanar to f%d, since p%d (v%d) is within %6.4g during p%d\n",
+              facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist, qh furthest_id));
+          }
+        }
+      }
+    }
+    if (!allsimplicial) {
+      if (qh CENTERtype == qh_AScentrum) {
+        if (!facet->center)
+          facet->center= qh_getcentrum (facet);
+        centrum= facet->center;
+      }else {
+	if (!centrum_warning && (!facet->simplicial || facet->tricoplanar)) {
+	   centrum_warning= True;
+	   fprintf (qh ferr, "qhull note: recomputing centrums for convexity test.  This may lead to false, precision errors.\n");
+	}
+        centrum= qh_getcentrum(facet);
+        tempcentrum= True;
+      }
+      FOREACHneighbor_(facet) {
+	if (qh ZEROcentrum && facet->simplicial && neighbor->simplicial)
+	  continue;
+	if (facet->tricoplanar || neighbor->tricoplanar)
+	  continue;
+        zzinc_(Zdistconvex);
+        qh_distplane (centrum, neighbor, &dist);
+        if (dist > qh DISTround) {
+          zzinc_(Zconcaveridges);
+          qh_precision ("concave ridge");
+          fprintf (qh ferr, "qhull precision error: f%d is concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
+            facet->id, neighbor->id, facet->id, dist, neighbor->id);
+          errfacet1= facet;
+          errfacet2= neighbor;
+          waserror= True;
+	}else if (dist >= 0.0) {   /* if arithmetic always rounds the same,
+				     can test against centrum radius instead */
+          zzinc_(Zcoplanarridges);
+          qh_precision ("coplanar ridge");
+          fprintf (qh ferr, "qhull precision error: f%d is coplanar or concave to f%d.  Centrum of f%d is %6.4g above f%d\n",
+            facet->id, neighbor->id, facet->id, dist, neighbor->id);
+	  errfacet1= facet;
+	  errfacet2= neighbor;
+	  waserror= True;
+        }
+      }
+      if (tempcentrum)
+        qh_memfree(centrum, qh normal_size);
+    }
+  }
+  if (waserror && !qh FORCEoutput)
+    qh_errexit2 (qh_ERRprec, errfacet1, errfacet2);
+} /* checkconvex */
+
+
+/*---------------------------------
+  
+  qh_checkfacet( facet, newmerge, waserror )
+    checks for consistency errors in facet
+    newmerge set if from merge.c
+
+  returns:
+    sets waserror if any error occurs
+
+  checks:
+    vertex ids are inverse sorted
+    unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
+    if non-simplicial, at least as many ridges as neighbors
+    neighbors are not duplicated
+    ridges are not duplicated
+    in 3-d, ridges=verticies
+    (qh.hull_dim-1) ridge vertices
+    neighbors are reciprocated
+    ridge neighbors are facet neighbors and a ridge for every neighbor
+    simplicial neighbors match facetintersect
+    vertex intersection matches vertices of common ridges 
+    vertex neighbors and facet vertices agree
+    all ridges have distinct vertex sets
+
+  notes:  
+    uses neighbor->seen
+
+  design:
+    check sets
+    check vertices
+    check sizes of neighbors and vertices
+    check for qh_MERGEridge and qh_DUPLICATEridge flags
+    check neighbor set
+    check ridge set
+    check ridges, neighbors, and vertices
+*/
+void qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp) {
+  facetT *neighbor, **neighborp, *errother=NULL;
+  ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2;
+  vertexT *vertex, **vertexp;
+  unsigned previousid= INT_MAX;
+  int numneighbors, numvertices, numridges=0, numRvertices=0;
+  boolT waserror= False;
+  int skipA, skipB, ridge_i, ridge_n, i;
+  setT *intersection;
+
+  if (facet->visible) {
+    fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d is on the visible_list\n",
+      facet->id);
+    qh_errexit (qh_ERRqhull, facet, NULL);
+  }
+  if (!facet->normal) {
+    fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d does not have  a normal\n",
+      facet->id);
+    waserror= True;
+  }
+  qh_setcheck (facet->vertices, "vertices for f", facet->id);
+  qh_setcheck (facet->ridges, "ridges for f", facet->id);
+  qh_setcheck (facet->outsideset, "outsideset for f", facet->id);
+  qh_setcheck (facet->coplanarset, "coplanarset for f", facet->id);
+  qh_setcheck (facet->neighbors, "neighbors for f", facet->id);
+  FOREACHvertex_(facet->vertices) {
+    if (vertex->deleted) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
+      qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
+      waserror= True;
+    }
+    if (vertex->id >= previousid) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
+      waserror= True;
+      break;
+    }
+    previousid= vertex->id;
+  }
+  numneighbors= qh_setsize(facet->neighbors);
+  numvertices= qh_setsize(facet->vertices);
+  numridges= qh_setsize(facet->ridges);
+  if (facet->simplicial) {
+    if (numvertices+numneighbors != 2*qh hull_dim 
+    && !facet->degenerate && !facet->redundant) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh hull_dim\n", 
+                facet->id, numvertices, numneighbors);
+      qh_setprint (qh ferr, "", facet->neighbors);
+      waserror= True;
+    }
+  }else { /* non-simplicial */
+    if (!newmerge 
+    &&(numvertices < qh hull_dim || numneighbors < qh hull_dim)
+    && !facet->degenerate && !facet->redundant) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh hull_dim\n",
+         facet->id, numvertices, numneighbors);
+       waserror= True;
+    }
+    /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */
+    if (numridges < numneighbors
+    ||(qh hull_dim == 3 && numvertices > numridges && !qh NEWfacets)
+    ||(qh hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
+      if (!facet->degenerate && !facet->redundant) {
+	fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or (3-d) > #vertices %d or (2-d) not all 2\n",
+	    facet->id, numridges, numneighbors, numvertices);
+	waserror= True;
+      }
+    }
+  }
+  FOREACHneighbor_(facet) {
+    if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d still has a MERGE or DUP neighbor\n", facet->id);
+      qh_errexit (qh_ERRqhull, facet, NULL);
+    }
+    neighbor->seen= True;
+  }
+  FOREACHneighbor_(facet) {
+    if (!qh_setin(neighbor->neighbors, facet)) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
+	      facet->id, neighbor->id, neighbor->id, facet->id);
+      errother= neighbor;
+      waserror= True;
+    }
+    if (!neighbor->seen) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n",
+	      facet->id, neighbor->id);
+      errother= neighbor;
+      waserror= True;
+    }    
+    neighbor->seen= False;
+  }
+  FOREACHridge_(facet->ridges) {
+    qh_setcheck (ridge->vertices, "vertices for r", ridge->id);
+    ridge->seen= False;
+  }
+  FOREACHridge_(facet->ridges) {
+    if (ridge->seen) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n",
+	      facet->id, ridge->id);
+      errridge= ridge;
+      waserror= True;
+    }    
+    ridge->seen= True;
+    numRvertices= qh_setsize(ridge->vertices);
+    if (numRvertices != qh hull_dim - 1) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n", 
+                ridge->top->id, ridge->bottom->id, numRvertices);
+      errridge= ridge;
+      waserror= True;
+    }
+    neighbor= otherfacet_(ridge, facet);
+    neighbor->seen= True;
+    if (!qh_setin(facet->neighbors, neighbor)) {
+      fprintf(qh ferr, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
+           facet->id, neighbor->id, ridge->id);
+      errridge= ridge;
+      waserror= True;
+    }
+  }
+  if (!facet->simplicial) {
+    FOREACHneighbor_(facet) {
+      if (!neighbor->seen) {
+        fprintf(qh ferr, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
+	      facet->id, neighbor->id);
+	errother= neighbor;
+        waserror= True;
+      }
+      intersection= qh_vertexintersect_new(facet->vertices, neighbor->vertices);
+      qh_settemppush (intersection);
+      FOREACHvertex_(facet->vertices) {
+	vertex->seen= False;
+	vertex->seen2= False;
+      }
+      FOREACHvertex_(intersection)
+	vertex->seen= True;
+      FOREACHridge_(facet->ridges) {
+	if (neighbor != otherfacet_(ridge, facet))
+	    continue;
+	FOREACHvertex_(ridge->vertices) {
+	  if (!vertex->seen) {
+	    fprintf (qh ferr, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n",
+  	          vertex->id, ridge->id, facet->id, neighbor->id);
+	    qh_errexit (qh_ERRqhull, facet, ridge);
+	  }
+	  vertex->seen2= True;
+	}
+      }
+      if (!newmerge) {
+	FOREACHvertex_(intersection) {
+	  if (!vertex->seen2) {
+	    if (qh IStracing >=3 || !qh MERGING) {
+	      fprintf (qh ferr, "qhull precision error (qh_checkfacet): vertex v%d in f%d intersect f%d but\n\
+ not in a ridge.  This is ok under merging.  Last point was p%d\n",
+		     vertex->id, facet->id, neighbor->id, qh furthest_id);
+	      if (!qh FORCEoutput && !qh MERGING) {
+		qh_errprint ("ERRONEOUS", facet, neighbor, NULL, vertex);
+		if (!qh MERGING)
+		  qh_errexit (qh_ERRqhull, NULL, NULL);
+	      }
+	    }
+	  }
+	}
+      }      
+      qh_settempfree (&intersection);
+    }
+  }else { /* simplicial */
+    FOREACHneighbor_(facet) {
+      if (neighbor->simplicial) {    
+	skipA= SETindex_(facet->neighbors, neighbor);
+	skipB= qh_setindex (neighbor->neighbors, facet);
+	if (!qh_setequal_skip (facet->vertices, skipA, neighbor->vertices, skipB)) {
+	  fprintf (qh ferr, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
+		   facet->id, skipA, neighbor->id, skipB);
+	  errother= neighbor;
+	  waserror= True;
+	}
+      }
+    }
+  }
+  if (qh hull_dim < 5 && (qh IStracing > 2 || qh CHECKfrequently)) {
+    FOREACHridge_i_(facet->ridges) {           /* expensive */
+      for (i= ridge_i+1; i < ridge_n; i++) {
+	ridge2= SETelemt_(facet->ridges, i, ridgeT);
+	if (qh_setequal (ridge->vertices, ridge2->vertices)) {
+	  fprintf (qh ferr, "qh_checkfacet: ridges r%d and r%d have the same vertices\n",
+		  ridge->id, ridge2->id);
+	  errridge= ridge;
+	  waserror= True;
+	}
+      }
+    }
+  }
+  if (waserror) {
+    qh_errprint("ERRONEOUS", facet, errother, errridge, NULL);
+    *waserrorp= True;
+  }
+} /* checkfacet */
+
+
+/*---------------------------------
+  
+  qh_checkflipped_all( facetlist )
+    checks orientation of facets in list against interior point
+*/
+void qh_checkflipped_all (facetT *facetlist) {
+  facetT *facet;
+  boolT waserror= False;
+  realT dist;
+
+  if (facetlist == qh facet_list)
+    zzval_(Zflippedfacets)= 0;
+  FORALLfacet_(facetlist) {
+    if (facet->normal && !qh_checkflipped (facet, &dist, !qh_ALL)) {
+      fprintf(qh ferr, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
+	      facet->id, dist);
+      if (!qh FORCEoutput) {
+	qh_errprint("ERRONEOUS", facet, NULL, NULL, NULL);
+	waserror= True;
+      }
+    }
+  }
+  if (waserror) {
+    fprintf (qh ferr, "\n\
+A flipped facet occurs when its distance to the interior point is\n\
+greater than %2.2g, the maximum roundoff error.\n", -qh DISTround);
+    qh_errexit(qh_ERRprec, NULL, NULL);
+  }
+} /* checkflipped_all */
+
+/*---------------------------------
+  
+  qh_checkpolygon( facetlist )
+    checks the correctness of the structure
+
+  notes:
+    call with either qh.facet_list or qh.newfacet_list
+    checks num_facets and num_vertices if qh.facet_list
+
+  design:
+    for each facet
+      checks facet and outside set
+    initializes vertexlist
+    for each facet
+      checks vertex set
+    if checking all facets (qh.facetlist)
+      check facet count
+      if qh.VERTEXneighbors
+        check vertex neighbors and count
+      check vertex count
+*/
+void qh_checkpolygon(facetT *facetlist) {
+  facetT *facet;
+  vertexT *vertex, **vertexp, *vertexlist;
+  int numfacets= 0, numvertices= 0, numridges= 0;
+  int totvneighbors= 0, totvertices= 0;
+  boolT waserror= False, nextseen= False, visibleseen= False;
+  
+  trace1((qh ferr, "qh_checkpolygon: check all facets from f%d\n", facetlist->id));
+  if (facetlist != qh facet_list || qh ONLYgood)
+    nextseen= True;
+  FORALLfacet_(facetlist) {
+    if (facet == qh visible_list)
+      visibleseen= True;
+    if (!facet->visible) {
+      if (!nextseen) {
+	if (facet == qh facet_next)
+	  nextseen= True;
+	else if (qh_setsize (facet->outsideset)) {
+	  if (!qh NARROWhull
+#if !qh_COMPUTEfurthest
+	       || facet->furthestdist >= qh MINoutside
+#endif
+			) {
+	    fprintf (qh ferr, "qhull internal error (qh_checkpolygon): f%d has outside points before qh facet_next\n",
+		     facet->id);
+	    qh_errexit (qh_ERRqhull, facet, NULL);
+	  }
+	}
+      }
+      numfacets++;
+      qh_checkfacet(facet, False, &waserror);
+    }
+  }
+  if (qh visible_list && !visibleseen && facetlist == qh facet_list) {
+    fprintf (qh ferr, "qhull internal error (qh_checkpolygon): visible list f%d no longer on facet list\n", qh visible_list->id);
+    qh_printlists();
+    qh_errexit (qh_ERRqhull, qh visible_list, NULL);
+  }
+  if (facetlist == qh facet_list)
+    vertexlist= qh vertex_list;
+  else if (facetlist == qh newfacet_list)
+    vertexlist= qh newvertex_list;
+  else
+    vertexlist= NULL;
+  FORALLvertex_(vertexlist) {
+    vertex->seen= False;
+    vertex->visitid= 0;
+  }  
+  FORALLfacet_(facetlist) {
+    if (facet->visible)
+      continue;
+    if (facet->simplicial)
+      numridges += qh hull_dim;
+    else
+      numridges += qh_setsize (facet->ridges);
+    FOREACHvertex_(facet->vertices) {
+      vertex->visitid++;
+      if (!vertex->seen) {
+	vertex->seen= True;
+	numvertices++;
+	if (qh_pointid (vertex->point) == -1) {
+	  fprintf (qh ferr, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n",
+		   vertex->point, vertex->id, qh first_point);
+	  waserror= True;
+	}
+      }
+    }
+  }
+  qh vertex_visit += numfacets;
+  if (facetlist == qh facet_list) {
+    if (numfacets != qh num_facets - qh num_visible) {
+      fprintf(qh ferr, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n",
+	      numfacets, qh num_facets, qh num_visible);
+      waserror= True;
+    }
+    qh vertex_visit++;
+    if (qh VERTEXneighbors) {
+      FORALLvertices {
+	qh_setcheck (vertex->neighbors, "neighbors for v", vertex->id);
+	if (vertex->deleted)
+	  continue;
+	totvneighbors += qh_setsize (vertex->neighbors);
+      }
+      FORALLfacet_(facetlist)
+	totvertices += qh_setsize (facet->vertices);
+      if (totvneighbors != totvertices) {
+	fprintf(qh ferr, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent.  Totvneighbors %d, totvertices %d\n",
+		totvneighbors, totvertices);
+	waserror= True;
+      }
+    }
+    if (numvertices != qh num_vertices - qh_setsize(qh del_vertices)) {
+      fprintf(qh ferr, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
+	      numvertices, qh num_vertices - qh_setsize(qh del_vertices));
+      waserror= True;
+    }
+    if (qh hull_dim == 2 && numvertices != numfacets) {
+      fprintf (qh ferr, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n",
+        numvertices, numfacets);
+      waserror= True;
+    }
+    if (qh hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
+      fprintf (qh ferr, "qhull warning: #vertices %d + #facets %d - #edges %d != 2\n\
+	A vertex appears twice in a edge list.  May occur during merging.",
+        numvertices, numfacets, numridges/2);
+      /* occurs if lots of merging and a vertex ends up twice in an edge list.  e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */
+    }
+  }
+  if (waserror) 
+    qh_errexit(qh_ERRqhull, NULL, NULL);
+} /* checkpolygon */
+
+
+/*---------------------------------
+  
+  qh_checkvertex( vertex )
+    check vertex for consistency
+    checks vertex->neighbors
+
+  notes:
+    neighbors checked efficiently in checkpolygon
+*/
+void qh_checkvertex (vertexT *vertex) {
+  boolT waserror= False;
+  facetT *neighbor, **neighborp, *errfacet=NULL;
+
+  if (qh_pointid (vertex->point) == -1) {
+    fprintf (qh ferr, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point);
+    waserror= True;
+  }
+  if (vertex->id >= qh vertex_id) {
+    fprintf (qh ferr, "qhull internal error (qh_checkvertex): unknown vertex id %d\n", vertex->id);
+    waserror= True;
+  }
+  if (!waserror && !vertex->deleted) {
+    if (qh_setsize (vertex->neighbors)) {
+      FOREACHneighbor_(vertex) {
+        if (!qh_setin (neighbor->vertices, vertex)) {
+          fprintf (qh ferr, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
+	  errfacet= neighbor;
+	  waserror= True;
+	}
+      }
+    }
+  }
+  if (waserror) {
+    qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
+    qh_errexit (qh_ERRqhull, errfacet, NULL);
+  }
+} /* checkvertex */
+  
+/*---------------------------------
+  
+  qh_clearcenters( type )
+    clear old data from facet->center
+
+  notes:
+    sets new centertype
+    nop if CENTERtype is the same
+*/
+void qh_clearcenters (qh_CENTER type) {
+  facetT *facet;
+  
+  if (qh CENTERtype != type) {
+    FORALLfacets {
+      if (qh CENTERtype == qh_ASvoronoi){
+        if (facet->center) {
+          qh_memfree (facet->center, qh center_size);
+          facet->center= NULL;
+        }
+      }else /* qh CENTERtype == qh_AScentrum */ {
+        if (facet->center) {
+          qh_memfree (facet->center, qh normal_size);
+	  facet->center= NULL;
+        }
+      }
+    }
+    qh CENTERtype= type;
+  }
+  trace2((qh ferr, "qh_clearcenters: switched to center type %d\n", type));
+} /* clearcenters */
+
+/*---------------------------------
+  
+  qh_createsimplex( vertices )
+    creates a simplex from a set of vertices
+
+  returns:
+    initializes qh.facet_list to the simplex
+    initializes qh.newfacet_list, .facet_tail
+    initializes qh.vertex_list, .newvertex_list, .vertex_tail
+
+  design:
+    initializes lists
+    for each vertex
+      create a new facet
+    for each new facet
+      create its neighbor set
+*/
+void qh_createsimplex(setT *vertices) {
+  facetT *facet= NULL, *newfacet;
+  boolT toporient= True;
+  int vertex_i, vertex_n, nth;
+  setT *newfacets= qh_settemp (qh hull_dim+1);
+  vertexT *vertex;
+  
+  qh facet_list= qh newfacet_list= qh facet_tail= qh_newfacet();
+  qh num_facets= qh num_vertices= qh num_visible= 0;
+  qh vertex_list= qh newvertex_list= qh vertex_tail= qh_newvertex(NULL);
+  FOREACHvertex_i_(vertices) {
+    newfacet= qh_newfacet();
+    newfacet->vertices= qh_setnew_delnthsorted (vertices, vertex_n,
+						vertex_i, 0);
+    newfacet->toporient= toporient;
+    qh_appendfacet(newfacet);
+    newfacet->newfacet= True;
+    qh_appendvertex (vertex);
+    qh_setappend (&newfacets, newfacet);
+    toporient ^= True;
+  }
+  FORALLnew_facets {
+    nth= 0;
+    FORALLfacet_(qh newfacet_list) {
+      if (facet != newfacet) 
+        SETelem_(newfacet->neighbors, nth++)= facet;
+    }
+    qh_settruncate (newfacet->neighbors, qh hull_dim);
+  }
+  qh_settempfree (&newfacets);
+  trace1((qh ferr, "qh_createsimplex: created simplex\n"));
+} /* createsimplex */
+
+/*---------------------------------
+  
+  qh_delridge( ridge )
+    deletes ridge from data structures it belongs to
+    frees up its memory
+
+  notes:
+    in merge.c, caller sets vertex->delridge for each vertex
+    ridges also freed in qh_freeqhull
+*/
+void qh_delridge(ridgeT *ridge) {
+  void **freelistp; /* used !qh_NOmem */
+  
+  qh_setdel(ridge->top->ridges, ridge);
+  qh_setdel(ridge->bottom->ridges, ridge);
+  qh_setfree(&(ridge->vertices));
+  qh_memfree_(ridge, sizeof(ridgeT), freelistp);
+} /* delridge */
+
+
+/*---------------------------------
+  
+  qh_delvertex( vertex )
+    deletes a vertex and frees its memory
+
+  notes:
+    assumes vertex->adjacencies have been updated if needed
+    unlinks from vertex_list
+*/
+void qh_delvertex (vertexT *vertex) {
+
+  if (vertex == qh tracevertex)
+    qh tracevertex= NULL;
+  qh_removevertex (vertex);
+  qh_setfree (&vertex->neighbors);
+  qh_memfree(vertex, sizeof(vertexT));
+} /* delvertex */
+
+
+/*---------------------------------
+  
+  qh_facet3vertex(  )
+    return temporary set of 3-d vertices in qh_ORIENTclock order
+
+  design:
+    if simplicial facet
+      build set from facet->vertices with facet->toporient
+    else
+      for each ridge in order
+        build set from ridge's vertices
+*/
+setT *qh_facet3vertex (facetT *facet) {
+  ridgeT *ridge, *firstridge;
+  vertexT *vertex;
+  int cntvertices, cntprojected=0;
+  setT *vertices;
+
+  cntvertices= qh_setsize(facet->vertices);
+  vertices= qh_settemp (cntvertices);
+  if (facet->simplicial) {
+    if (cntvertices != 3) {
+      fprintf (qh ferr, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n", 
+                  cntvertices, facet->id);
+      qh_errexit(qh_ERRqhull, facet, NULL);
+    }
+    qh_setappend (&vertices, SETfirst_(facet->vertices));
+    if (facet->toporient ^ qh_ORIENTclock)
+      qh_setappend (&vertices, SETsecond_(facet->vertices));
+    else
+      qh_setaddnth (&vertices, 0, SETsecond_(facet->vertices));
+    qh_setappend (&vertices, SETelem_(facet->vertices, 2));
+  }else {
+    ridge= firstridge= SETfirstt_(facet->ridges, ridgeT);   /* no infinite */
+    while ((ridge= qh_nextridge3d (ridge, facet, &vertex))) {
+      qh_setappend (&vertices, vertex);
+      if (++cntprojected > cntvertices || ridge == firstridge)
+        break;
+    }
+    if (!ridge || cntprojected != cntvertices) {
+      fprintf (qh ferr, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up.  got at least %d\n", 
+                  facet->id, cntprojected);
+      qh_errexit(qh_ERRqhull, facet, ridge);
+    }
+  }
+  return vertices;
+} /* facet3vertex */
+
+/*---------------------------------
+  
+  qh_findbestfacet( point, bestoutside, bestdist, isoutside )
+    find facet that is furthest below a point 
+
+    for Delaunay triangulations, 
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. 
+
+  returns:
+    if bestoutside is set (e.g., qh_ALL)
+      returns best facet that is not upperdelaunay
+      if Delaunay and inside, point is outside circumsphere of bestfacet
+    else
+      returns first facet below point
+      if point is inside, returns nearest, !upperdelaunay facet
+    distance to facet
+    isoutside set if outside of facet
+    
+  notes:
+    this works for all distributions
+    if inside, qh_findbestfacet performs an exhaustive search
+       this may be too conservative.  Sometimes it is clearly required.
+    qh_findbestfacet is not used by qhull.
+    uses qh.visit_id and qh.coplanarset
+    
+  see:
+    qh_findbest
+*/
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside) {
+  facetT *bestfacet= NULL;
+  int numpart, totpart= 0;
+  
+  bestfacet= qh_findbest (point, qh facet_list, 
+			    bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */,
+			    bestdist, isoutside, &totpart);
+  if (*bestdist < -qh DISTround) {
+    bestfacet= qh_findfacet_all (point, bestdist, isoutside, &numpart);
+    totpart += numpart;
+    if ((isoutside && bestoutside)
+    || (!isoutside && bestfacet->upperdelaunay)) {
+      bestfacet= qh_findbest (point, bestfacet, 
+			    bestoutside, False, bestoutside,
+			    bestdist, isoutside, &totpart);
+      totpart += numpart;
+    }
+  }
+  trace3((qh ferr, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n",
+	  bestfacet->id, *bestdist, *isoutside, totpart));
+  return bestfacet;
+} /* findbestfacet */ 
+ 
+/*---------------------------------
+  
+  qh_findfacet_all( point, bestdist, isoutside, numpart )
+    exhaustive search for facet below a point 
+
+    for Delaunay triangulations, 
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. 
+
+  returns:
+    returns first facet below point
+    if point is inside, 
+      returns nearest facet
+    distance to facet
+    isoutside if point is outside of the hull
+    number of distance tests
+*/
+facetT *qh_findfacet_all (pointT *point, realT *bestdist, boolT *isoutside,
+			  int *numpart) {
+  facetT *bestfacet= NULL, *facet;
+  realT dist;
+  int totpart= 0;
+  
+  *bestdist= REALmin;
+  *isoutside= False;
+  FORALLfacets {
+    if (facet->flipped || !facet->normal)
+      continue;
+    totpart++;
+    qh_distplane (point, facet, &dist);
+    if (dist > *bestdist) {
+      *bestdist= dist;
+      bestfacet= facet;
+      if (dist > qh MINoutside) {
+        *isoutside= True;
+        break;
+      }
+    }
+  }
+  *numpart= totpart;
+  trace3((qh ferr, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n",
+	  getid_(bestfacet), *bestdist, *isoutside, totpart));
+  return bestfacet;
+} /* findfacet_all */ 
+ 
+/*---------------------------------
+  
+  qh_findgood( facetlist, goodhorizon )
+    identify good facets for qh.PRINTgood
+    if qh.GOODvertex>0
+      facet includes point as vertex
+      if !match, returns goodhorizon
+      inactive if qh.MERGING
+    if qh.GOODpoint
+      facet is visible or coplanar (>0) or not visible (<0) 
+    if qh.GOODthreshold
+      facet->normal matches threshold
+    if !goodhorizon and !match, 
+      selects facet with closest angle
+      sets GOODclosest
+      
+  returns:
+    number of new, good facets found
+    determines facet->good
+    may update qh.GOODclosest
+    
+  notes:
+    qh_findgood_all further reduces the good region
+
+  design:
+    count good facets
+    mark good facets for qh.GOODpoint  
+    mark good facets for qh.GOODthreshold
+    if necessary
+      update qh.GOODclosest  
+*/
+int qh_findgood (facetT *facetlist, int goodhorizon) {
+  facetT *facet, *bestfacet= NULL;
+  realT angle, bestangle= REALmax, dist;
+  int  numgood=0;
+
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      numgood++;
+  }
+  if (qh GOODvertex>0 && !qh MERGING) {
+    FORALLfacet_(facetlist) {
+      if (!qh_isvertex (qh GOODvertexp, facet->vertices)) {
+        facet->good= False;
+        numgood--;
+      }
+    }
+  }
+  if (qh GOODpoint && numgood) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && facet->normal) {
+        zinc_(Zdistgood);
+        qh_distplane (qh GOODpointp, facet, &dist);
+        if ((qh GOODpoint > 0) ^ (dist > 0.0)) {
+          facet->good= False;
+          numgood--;
+        }
+      }
+    }
+  }
+  if (qh GOODthreshold && (numgood || goodhorizon || qh GOODclosest)) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && facet->normal) {
+        if (!qh_inthresholds (facet->normal, &angle)) {
+          facet->good= False;
+          numgood--;
+          if (angle < bestangle) {
+            bestangle= angle;
+            bestfacet= facet;
+          }
+        }
+      }
+    }
+    if (!numgood && (!goodhorizon || qh GOODclosest)) {
+      if (qh GOODclosest) {
+	if (qh GOODclosest->visible)
+	  qh GOODclosest= NULL;
+	else {
+	  qh_inthresholds (qh GOODclosest->normal, &angle);
+	  if (angle < bestangle)
+	    bestfacet= qh GOODclosest;
+	}
+      }
+      if (bestfacet && bestfacet != qh GOODclosest) {
+	if (qh GOODclosest)
+	  qh GOODclosest->good= False;
+	qh GOODclosest= bestfacet;
+	bestfacet->good= True;
+	numgood++;
+	trace2((qh ferr, "qh_findgood: f%d is closest (%2.2g) to thresholds\n", 
+           bestfacet->id, bestangle));
+	return numgood;
+      }
+    }else if (qh GOODclosest) { /* numgood > 0 */
+      qh GOODclosest->good= False;
+      qh GOODclosest= NULL;
+    }
+  }
+  zadd_(Zgoodfacet, numgood);
+  trace2((qh ferr, "qh_findgood: found %d good facets with %d good horizon\n",
+               numgood, goodhorizon));
+  if (!numgood && qh GOODvertex>0 && !qh MERGING) 
+    return goodhorizon;
+  return numgood;
+} /* findgood */
+
+/*---------------------------------
+  
+  qh_findgood_all( facetlist )
+    apply other constraints for good facets (used by qh.PRINTgood)
+    if qh.GOODvertex 
+      facet includes (>0) or doesn't include (<0) point as vertex
+      if last good facet and ONLYgood, prints warning and continues
+    if qh.SPLITthresholds
+      facet->normal matches threshold, or if none, the closest one
+    calls qh_findgood
+    nop if good not used
+
+  returns:
+    clears facet->good if not good
+    sets qh.num_good
+
+  notes:
+    this is like qh_findgood but more restrictive
+
+  design:
+    uses qh_findgood to mark good facets
+    marks facets for qh.GOODvertex
+    marks facets for qh.SPLITthreholds  
+*/
+void qh_findgood_all (facetT *facetlist) {
+  facetT *facet, *bestfacet=NULL;
+  realT angle, bestangle= REALmax;
+  int  numgood=0, startgood;
+
+  if (!qh GOODvertex && !qh GOODthreshold && !qh GOODpoint 
+  && !qh SPLITthresholds)
+    return;
+  if (!qh ONLYgood)
+    qh_findgood (qh facet_list, 0);
+  FORALLfacet_(facetlist) {
+    if (facet->good)
+      numgood++;
+  }
+  if (qh GOODvertex <0 || (qh GOODvertex > 0 && qh MERGING)) {
+    FORALLfacet_(facetlist) {
+      if (facet->good && ((qh GOODvertex > 0) ^ !!qh_isvertex (qh GOODvertexp, facet->vertices))) {
+        if (!--numgood) {
+	  if (qh ONLYgood) {
+            fprintf (qh ferr, "qhull warning: good vertex p%d does not match last good facet f%d.  Ignored.\n",
+               qh_pointid(qh GOODvertexp), facet->id);
+	    return;
+	  }else if (qh GOODvertex > 0)
+            fprintf (qh ferr, "qhull warning: point p%d is not a vertex ('QV%d').\n",
+		qh GOODvertex-1, qh GOODvertex-1);
+	  else
+            fprintf (qh ferr, "qhull warning: point p%d is a vertex for every facet ('QV-%d').\n",
+	        -qh GOODvertex - 1, -qh GOODvertex - 1);
+        }
+        facet->good= False;
+      }
+    }
+  }
+  startgood= numgood;
+  if (qh SPLITthresholds) {
+    FORALLfacet_(facetlist) {
+      if (facet->good) {
+        if (!qh_inthresholds (facet->normal, &angle)) {
+          facet->good= False;
+          numgood--;
+          if (angle < bestangle) {
+            bestangle= angle;
+            bestfacet= facet;
+          }
+        }
+      }
+    }
+    if (!numgood && bestfacet) {
+      bestfacet->good= True;
+      numgood++;
+      trace0((qh ferr, "qh_findgood_all: f%d is closest (%2.2g) to thresholds\n", 
+           bestfacet->id, bestangle));
+      return;
+    }
+  }
+  qh num_good= numgood;
+  trace0((qh ferr, "qh_findgood_all: %d good facets remain out of %d facets\n",
+        numgood, startgood));
+} /* findgood_all */
+
+/*---------------------------------
+  
+  qh_furthestnext()
+    set qh.facet_next to facet with furthest of all furthest points
+    searches all facets on qh.facet_list
+
+  notes:
+    this may help avoid precision problems
+*/
+void qh_furthestnext (void /* qh facet_list */) {
+  facetT *facet, *bestfacet= NULL;
+  realT dist, bestdist= -REALmax;
+
+  FORALLfacets {
+    if (facet->outsideset) {
+#if qh_COMPUTEfurthest
+      pointT *furthest;
+      furthest= (pointT*)qh_setlast (facet->outsideset);
+      zinc_(Zcomputefurthest);
+      qh_distplane (furthest, facet, &dist);
+#else
+      dist= facet->furthestdist;
+#endif
+      if (dist > bestdist) {
+	bestfacet= facet;
+	bestdist= dist;
+      }
+    }
+  }
+  if (bestfacet) {
+    qh_removefacet (bestfacet);
+    qh_prependfacet (bestfacet, &qh facet_next);
+    trace1((qh ferr, "qh_furthestnext: made f%d next facet (dist %.2g)\n",
+	    bestfacet->id, bestdist));
+  }
+} /* furthestnext */
+
+/*---------------------------------
+  
+  qh_furthestout( facet )
+    make furthest outside point the last point of outsideset
+
+  returns:
+    updates facet->outsideset
+    clears facet->notfurthest
+    sets facet->furthestdist
+
+  design:
+    determine best point of outsideset
+    make it the last point of outsideset
+*/
+void qh_furthestout (facetT *facet) {
+  pointT *point, **pointp, *bestpoint= NULL;
+  realT dist, bestdist= -REALmax;
+
+  FOREACHpoint_(facet->outsideset) {
+    qh_distplane (point, facet, &dist);
+    zinc_(Zcomputefurthest);
+    if (dist > bestdist) {
+      bestpoint= point;
+      bestdist= dist;
+    }
+  }
+  if (bestpoint) {
+    qh_setdel (facet->outsideset, point);
+    qh_setappend (&facet->outsideset, point);
+#if !qh_COMPUTEfurthest
+    facet->furthestdist= bestdist;
+#endif
+  }
+  facet->notfurthest= False;
+  trace3((qh ferr, "qh_furthestout: p%d is furthest outside point of f%d\n",
+	  qh_pointid (point), facet->id));
+} /* furthestout */
+
+
+/*---------------------------------
+  
+  qh_infiniteloop( facet )
+    report infinite loop error due to facet
+*/
+void qh_infiniteloop (facetT *facet) {
+
+  fprintf (qh ferr, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n");
+  qh_errexit (qh_ERRqhull, facet, NULL);
+} /* qh_infiniteloop */
+
+/*---------------------------------
+  
+  qh_initbuild()
+    initialize hull and outside sets with point array
+    qh.FIRSTpoint/qh.NUMpoints is point array
+    if qh.GOODpoint
+      adds qh.GOODpoint to initial hull
+
+  returns:
+    qh_facetlist with initial hull
+    points partioned into outside sets, coplanar sets, or inside
+    initializes qh.GOODpointp, qh.GOODvertexp,
+
+  design:
+    initialize global variables used during qh_buildhull
+    determine precision constants and points with max/min coordinate values
+      if qh.SCALElast, scale last coordinate (for 'd')
+    build initial simplex
+    partition input points into facets of initial simplex
+    set up lists
+    if qh.ONLYgood
+      check consistency  
+      add qh.GOODvertex if defined
+*/
+void qh_initbuild( void) {
+  setT *maxpoints, *vertices;
+  facetT *facet;
+  int i, numpart;
+  realT dist;
+  boolT isoutside;
+
+  qh furthest_id= -1;
+  qh lastreport= 0;
+  qh facet_id= qh vertex_id= qh ridge_id= 0;
+  qh visit_id= qh vertex_visit= 0;
+  qh maxoutdone= False;
+
+  if (qh GOODpoint > 0) 
+    qh GOODpointp= qh_point (qh GOODpoint-1);
+  else if (qh GOODpoint < 0) 
+    qh GOODpointp= qh_point (-qh GOODpoint-1);
+  if (qh GOODvertex > 0)
+    qh GOODvertexp= qh_point (qh GOODvertex-1);
+  else if (qh GOODvertex < 0) 
+    qh GOODvertexp= qh_point (-qh GOODvertex-1);
+  if ((qh GOODpoint  
+       && (qh GOODpointp < qh first_point  /* also catches !GOODpointp */
+	   || qh GOODpointp > qh_point (qh num_points-1)))
+    || (qh GOODvertex
+	&& (qh GOODvertexp < qh first_point  /* also catches !GOODvertexp */
+	    || qh GOODvertexp > qh_point (qh num_points-1)))) {
+    fprintf (qh ferr, "qhull input error: either QGn or QVn point is > p%d\n",
+	     qh num_points-1);
+    qh_errexit (qh_ERRinput, NULL, NULL);
+  }
+  maxpoints= qh_maxmin(qh first_point, qh num_points, qh hull_dim);
+  if (qh SCALElast)
+    qh_scalelast (qh first_point, qh num_points, qh hull_dim,
+               qh MINlastcoord, qh MAXlastcoord, qh MAXwidth);
+  qh_detroundoff();
+  if (qh DELAUNAY && qh upper_threshold[qh hull_dim-1] > REALmax/2
+                  && qh lower_threshold[qh hull_dim-1] < -REALmax/2) {
+    for (i= qh_PRINTEND; i--; ) {
+      if (qh PRINTout[i] == qh_PRINTgeom && qh DROPdim < 0 
+ 	  && !qh GOODthreshold && !qh SPLITthresholds)
+	break;  /* in this case, don't set upper_threshold */
+    }
+    if (i < 0) {
+      if (qh UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */
+	qh lower_threshold[qh hull_dim-1]= qh ANGLEround * qh_ZEROdelaunay;
+	qh GOODthreshold= True;
+      }else { 
+	qh upper_threshold[qh hull_dim-1]= -qh ANGLEround * qh_ZEROdelaunay;
+        if (!qh GOODthreshold) 
+	  qh SPLITthresholds= True; /* build upper-convex hull even if Qg */
+          /* qh_initqhull_globals errors if Qg without Pdk/etc. */
+      }
+    }
+  }
+  vertices= qh_initialvertices(qh hull_dim, maxpoints, qh first_point, qh num_points); 
+  qh_initialhull (vertices);  /* initial qh facet_list */
+  qh_partitionall (vertices, qh first_point, qh num_points);
+  if (qh PRINToptions1st || qh TRACElevel || qh IStracing) {
+    if (qh TRACElevel || qh IStracing)
+      fprintf (qh ferr, "\nTrace level %d for %s | %s\n", 
+         qh IStracing ? qh IStracing : qh TRACElevel, qh rbox_command, qh qhull_command);
+    fprintf (qh ferr, "Options selected for Qhull %s:\n%s\n", qh_VERSION, qh qhull_options);
+  }
+  qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+  qh facet_next= qh facet_list;
+  qh_furthestnext (/* qh facet_list */);
+  if (qh PREmerge) {
+    qh cos_max= qh premerge_cos;
+    qh centrum_radius= qh premerge_centrum;
+  }
+  if (qh ONLYgood) {
+    if (qh GOODvertex > 0 && qh MERGING) {
+      fprintf (qh ferr, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    if (!(qh GOODthreshold || qh GOODpoint
+         || (!qh MERGEexact && !qh PREmerge && qh GOODvertexp))) {
+      fprintf (qh ferr, "qhull input error: 'Qg' (ONLYgood) needs a good threshold ('Pd0D0'), a\n\
+good point (QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n");
+      qh_errexit (qh_ERRinput, NULL, NULL);
+    }
+    if (qh GOODvertex > 0  && !qh MERGING  /* matches qh_partitionall */
+	&& !qh_isvertex (qh GOODvertexp, vertices)) {
+      facet= qh_findbestnew (qh GOODvertexp, qh facet_list, 
+			  &dist, !qh_ALL, &isoutside, &numpart);
+      zadd_(Zdistgood, numpart);
+      if (!isoutside) {
+        fprintf (qh ferr, "qhull input error: point for QV%d is inside initial simplex.  It can not be made a vertex.\n",
+	       qh_pointid(qh GOODvertexp));
+        qh_errexit (qh_ERRinput, NULL, NULL);
+      }
+      if (!qh_addpoint (qh GOODvertexp, facet, False)) {
+	qh_settempfree(&vertices);
+	qh_settempfree(&maxpoints);
+	return;
+      }
+    }
+    qh_findgood (qh facet_list, 0);
+  }
+  qh_settempfree(&vertices);
+  qh_settempfree(&maxpoints);
+  trace1((qh ferr, "qh_initbuild: initial hull created and points partitioned\n"));
+} /* initbuild */
+
+/*---------------------------------
+  
+  qh_initialhull( vertices )
+    constructs the initial hull as a DIM3 simplex of vertices
+
+  design:
+    creates a simplex (initializes lists)
+    determines orientation of simplex
+    sets hyperplanes for facets
+    doubles checks orientation (in case of axis-parallel facets with Gaussian elimination)
+    checks for flipped facets and qh.NARROWhull
+    checks the result   
+*/
+void qh_initialhull(setT *vertices) {
+  facetT *facet, *firstfacet, *neighbor, **neighborp;
+  realT dist, angle, minangle= REALmax;
+#ifndef qh_NOtrace
+  int k;
+#endif
+
+  qh_createsimplex(vertices);  /* qh facet_list */
+  qh_resetlists (False, qh_RESETvisible);
+  qh facet_next= qh facet_list;      /* advance facet when processed */
+  qh interior_point= qh_getcenter(vertices);
+  firstfacet= qh facet_list;
+  qh_setfacetplane(firstfacet);
+  zinc_(Znumvisibility); /* needs to be in printsummary */
+  qh_distplane(qh interior_point, firstfacet, &dist);
+  if (dist > 0) {  
+    FORALLfacets
+      facet->toporient ^= True;
+  }
+  FORALLfacets
+    qh_setfacetplane(facet);
+  FORALLfacets {
+    if (!qh_checkflipped (facet, NULL, qh_ALL)) {/* due to axis-parallel facet */
+      trace1((qh ferr, "qh_initialhull: initial orientation incorrect.  Correct all facets\n"));
+      facet->flipped= False;
+      FORALLfacets {
+	facet->toporient ^= True;
+	qh_orientoutside (facet);
+      }
+      break;
+    }
+  }
+  FORALLfacets {
+    if (!qh_checkflipped (facet, NULL, !qh_ALL)) {  /* can happen with 'R0.1' */
+      qh_precision ("initial facet is coplanar with interior point");
+      fprintf (qh ferr, "qhull precision error: initial facet %d is coplanar with the interior point\n",
+                   facet->id);
+      qh_errexit (qh_ERRsingular, facet, NULL);
+    }
+    FOREACHneighbor_(facet) {
+      angle= qh_getangle (facet->normal, neighbor->normal);
+      minimize_( minangle, angle);
+    }
+  }
+  if (minangle < qh_MAXnarrow && !qh NOnarrow) { 
+    realT diff= 1.0 + minangle;
+
+    qh NARROWhull= True;
+    qh_option ("_narrow-hull", NULL, &diff);
+    if (minangle < qh_WARNnarrow && !qh RERUN && qh PRINTprecision)
+      fprintf (qh ferr, "qhull precision warning: \n\
+The initial hull is narrow (cosine of min. angle is %.16f).\n\
+A coplanar point may lead to a wide facet.  Options 'QbB' (scale to unit box)\n\
+or 'Qbb' (scale last coordinate) may remove this warning.  Use 'Pp' to skip\n\
+this warning.  See 'Limitations' in qh-impre.htm.\n",
+          -minangle);   /* convert from angle between normals to angle between facets */
+  }
+  zzval_(Zprocessed)= qh hull_dim+1;
+  qh_checkpolygon (qh facet_list);
+  qh_checkconvex(qh facet_list,   qh_DATAfault);
+#ifndef qh_NOtrace
+  if (qh IStracing >= 1) {
+    fprintf(qh ferr, "qh_initialhull: simplex constructed, interior point:");
+    for (k=0; k < qh hull_dim; k++) 
+      fprintf (qh ferr, " %6.4g", qh interior_point[k]);
+    fprintf (qh ferr, "\n");
+  }
+#endif
+} /* initialhull */
+
+/*---------------------------------
+  
+  qh_initialvertices( dim, maxpoints, points, numpoints )
+    determines a non-singular set of initial vertices
+    maxpoints may include duplicate points
+
+  returns:
+    temporary set of dim+1 vertices in descending order by vertex id
+    if qh.RANDOMoutside && !qh.ALLpoints
+      picks random points
+    if dim >= qh_INITIALmax, 
+      uses min/max x and max points with non-zero determinants
+
+  notes:
+    unless qh.ALLpoints, 
+      uses maxpoints as long as determinate is non-zero
+*/
+setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints) {
+  pointT *point, **pointp;
+  setT *vertices, *simplex, *tested;
+  realT randr;
+  int index, point_i, point_n, k;
+  boolT nearzero= False;
+  
+  vertices= qh_settemp (dim + 1);
+  simplex= qh_settemp (dim+1);
+  if (qh ALLpoints) 
+    qh_maxsimplex (dim, NULL, points, numpoints, &simplex);
+  else if (qh RANDOMoutside) {
+    while (qh_setsize (simplex) != dim+1) {
+      randr= qh_RANDOMint;
+      randr= randr/(qh_RANDOMmax+1);
+      index= (int)floor(qh num_points * randr);
+      while (qh_setin (simplex, qh_point (index))) {
+	index++; /* in case qh_RANDOMint always returns the same value */
+        index= index < qh num_points ? index : 0;
+      }
+      qh_setappend (&simplex, qh_point (index));
+    }
+  }else if (qh hull_dim >= qh_INITIALmax) {
+    tested= qh_settemp (dim+1);
+    qh_setappend (&simplex, SETfirst_(maxpoints));   /* max and min X coord */
+    qh_setappend (&simplex, SETsecond_(maxpoints));
+    qh_maxsimplex (fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex);
+    k= qh_setsize (simplex);
+    FOREACHpoint_i_(maxpoints) { 
+      if (point_i & 0x1) {     /* first pick up max. coord. points */
+      	if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
+	  qh_detsimplex(point, simplex, k, &nearzero);
+          if (nearzero)
+            qh_setappend (&tested, point);
+          else {
+            qh_setappend (&simplex, point);
+            if (++k == dim)  /* use search for last point */
+	      break;
+	  }
+	}
+      }
+    }
+    while (k != dim && (point= (pointT*)qh_setdellast (maxpoints))) {
+      if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
+        qh_detsimplex (point, simplex, k, &nearzero);
+        if (nearzero)
+          qh_setappend (&tested, point);
+        else {
+          qh_setappend (&simplex, point);
+          k++;
+	}
+      }
+    }
+    index= 0;
+    while (k != dim && (point= qh_point (index++))) {
+      if (!qh_setin (simplex, point) && !qh_setin (tested, point)){
+        qh_detsimplex (point, simplex, k, &nearzero);
+        if (!nearzero){
+          qh_setappend (&simplex, point);
+          k++;
+	}
+      }
+    }
+    qh_settempfree (&tested);
+    qh_maxsimplex (dim, maxpoints, points, numpoints, &simplex);
+  }else
+    qh_maxsimplex (dim, maxpoints, points, numpoints, &simplex);
+  FOREACHpoint_(simplex) 
+    qh_setaddnth (&vertices, 0, qh_newvertex(point)); /* descending order */
+  qh_settempfree (&simplex);
+  return vertices;
+} /* initialvertices */
+
+
+/*---------------------------------
+  
+  qh_isvertex(  )
+    returns vertex if point is in vertex set, else returns NULL
+
+  notes:
+    for qh.GOODvertex
+*/
+vertexT *qh_isvertex (pointT *point, setT *vertices) {
+  vertexT *vertex, **vertexp;
+
+  FOREACHvertex_(vertices) {
+    if (vertex->point == point)
+      return vertex;
+  }
+  return NULL;
+} /* isvertex */
+
+/*---------------------------------
+  
+  qh_makenewfacets( point )
+    make new facets from point and qh.visible_list
+
+  returns:
+    qh.newfacet_list= list of new facets with hyperplanes and ->newfacet
+    qh.newvertex_list= list of vertices in new facets with ->newlist set
+    
+    if (qh.ONLYgood)
+      newfacets reference horizon facets, but not vice versa
+      ridges reference non-simplicial horizon ridges, but not vice versa
+      does not change existing facets
+    else
+      sets qh.NEWfacets
+      new facets attached to horizon facets and ridges
+      for visible facets, 
+        visible->r.replace is corresponding new facet
+
+  see also: 
+    qh_makenewplanes() -- make hyperplanes for facets
+    qh_attachnewfacets() -- attachnewfacets if not done here (qh ONLYgood)
+    qh_matchnewfacets() -- match up neighbors
+    qh_updatevertices() -- update vertex neighbors and delvertices
+    qh_deletevisible() -- delete visible facets
+    qh_checkpolygon() --check the result
+    qh_triangulate() -- triangulate a non-simplicial facet
+
+  design:
+    for each visible facet
+      make new facets to its horizon facets
+      update its f.replace 
+      clear its neighbor set
+*/
+vertexT *qh_makenewfacets (pointT *point /*visible_list*/) {
+  facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
+  vertexT *apex;
+  int numnew=0;
+
+  qh newfacet_list= qh facet_tail;
+  qh newvertex_list= qh vertex_tail;
+  apex= qh_newvertex(point);
+  qh_appendvertex (apex);  
+  qh visit_id++;
+  if (!qh ONLYgood)
+    qh NEWfacets= True;
+  FORALLvisible_facets {
+    FOREACHneighbor_(visible) 
+      neighbor->seen= False;
+    if (visible->ridges) {
+      visible->visitid= qh visit_id;
+      newfacet2= qh_makenew_nonsimplicial (visible, apex, &numnew);
+    }
+    if (visible->simplicial)
+      newfacet= qh_makenew_simplicial (visible, apex, &numnew);
+    if (!qh ONLYgood) {
+      if (newfacet2)  /* newfacet is null if all ridges defined */
+        newfacet= newfacet2;
+      if (newfacet)
+      	visible->f.replace= newfacet;
+      else
+        zinc_(Zinsidevisible);
+      SETfirst_(visible->neighbors)= NULL;
+    }
+  }
+  trace1((qh ferr, "qh_makenewfacets: created %d new facets from point p%d to horizon\n",
+	  numnew, qh_pointid(point)));
+  if (qh IStracing >= 4)
+    qh_printfacetlist (qh newfacet_list, NULL, qh_ALL);
+  return apex;
+} /* makenewfacets */
+
+/*---------------------------------
+  
+  qh_matchduplicates( atfacet, atskip, hashsize, hashcount )
+    match duplicate ridges in qh.hash_table for atfacet/atskip
+    duplicates marked with ->dupridge and qh_DUPLICATEridge
+
+  returns:
+    picks match with worst merge (min distance apart)
+    updates hashcount
+  
+  see also:
+    qh_matchneighbor
+
+  notes:
+
+  design:
+    compute hash value for atfacet and atskip
+    repeat twice -- once to make best matches, once to match the rest
+      for each possible facet in qh.hash_table
+        if it is a matching facet and pass 2
+          make match 
+	  unless tricoplanar, mark match for merging (qh_MERGEridge)
+          [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt]
+        if it is a matching facet and pass 1
+          test if this is a better match
+      if pass 1,
+        make best match (it will not be merged)
+*/
+#ifndef qh_NOmerge
+void qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount) {
+  boolT same, ismatch;
+  int hash, scan;
+  facetT *facet, *newfacet, *maxmatch= NULL, *maxmatch2= NULL, *nextfacet;
+  int skip, newskip, nextskip= 0, maxskip= 0, maxskip2= 0, makematch;
+  realT maxdist= -REALmax, mindist, dist2, low, high;
+
+  hash= (int)qh_gethash (hashsize, atfacet->vertices, qh hull_dim, 1, 
+                     SETelem_(atfacet->vertices, atskip));
+  trace2((qh ferr, "qh_matchduplicates: find duplicate matches for f%d skip %d hash %d hashcount %d\n",
+	  atfacet->id, atskip, hash, *hashcount));
+  for (makematch= 0; makematch < 2; makematch++) {
+    qh visit_id++;
+    for (newfacet= atfacet, newskip= atskip; newfacet; newfacet= nextfacet, newskip= nextskip) {
+      zinc_(Zhashlookup);
+      nextfacet= NULL;
+      newfacet->visitid= qh visit_id;
+      for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT)); 
+	   scan= (++scan >= hashsize ? 0 : scan)) {
+	if (!facet->dupridge || facet->visitid == qh visit_id)
+	  continue;
+	zinc_(Zhashtests);
+	if (qh_matchvertices (1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
+	  ismatch= (same == (newfacet->toporient ^ facet->toporient));
+	  if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) {
+	    if (!makematch) {
+	      fprintf (qh ferr, "qhull internal error (qh_matchduplicates): missing dupridge at f%d skip %d for new f%d skip %d hash %d\n",
+		     facet->id, skip, newfacet->id, newskip, hash);
+	      qh_errexit2 (qh_ERRqhull, facet, newfacet);
+	    }
+	  }else if (ismatch && makematch) {
+	    if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) {
+	      SETelem_(facet->neighbors, skip)= newfacet;
+	      if (newfacet->tricoplanar)
+  		SETelem_(newfacet->neighbors, newskip)= facet;
+	      else
+		SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
+	      *hashcount -= 2; /* removed two unmatched facets */
+	      trace4((qh ferr, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d merge\n",
+		    facet->id, skip, newfacet->id, newskip));
+	    }
+	  }else if (ismatch) {
+	    mindist= qh_getdistance (facet, newfacet, &low, &high);
+	    dist2= qh_getdistance (newfacet, facet, &low, &high);
+	    minimize_(mindist, dist2);
+	    if (mindist > maxdist) {
+	      maxdist= mindist;
+	      maxmatch= facet;
+	      maxskip= skip;
+	      maxmatch2= newfacet;
+	      maxskip2= newskip;
+	    }
+	    trace3((qh ferr, "qh_matchduplicates: duplicate f%d skip %d new f%d skip %d at dist %2.2g, max is now f%d f%d\n",
+		    facet->id, skip, newfacet->id, newskip, mindist, 
+		    maxmatch->id, maxmatch2->id));
+	  }else { /* !ismatch */
+	    nextfacet= facet;
+	    nextskip= skip;
+	  }
+	}
+	if (makematch && !facet 
+        && SETelemt_(facet->neighbors, skip, facetT) == qh_DUPLICATEridge) {
+	  fprintf (qh ferr, "qhull internal error (qh_matchduplicates): no MERGEridge match for duplicate f%d skip %d at hash %d\n",
+		     newfacet->id, newskip, hash);
+	  qh_errexit (qh_ERRqhull, newfacet, NULL);
+	}
+      }
+    } /* end of for each new facet at hash */
+    if (!makematch) {
+      if (!maxmatch) {
+	fprintf (qh ferr, "qhull internal error (qh_matchduplicates): no maximum match at duplicate f%d skip %d at hash %d\n",
+		     atfacet->id, atskip, hash);
+	qh_errexit (qh_ERRqhull, atfacet, NULL);
+      }
+      SETelem_(maxmatch->neighbors, maxskip)= maxmatch2;
+      SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch;
+      *hashcount -= 2; /* removed two unmatched facets */
+      zzinc_(Zmultiridge);
+      trace0((qh ferr, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d keep\n",
+	      maxmatch->id, maxskip, maxmatch2->id, maxskip2));
+      qh_precision ("ridge with multiple neighbors");
+      if (qh IStracing >= 4)
+	qh_errprint ("DUPLICATED/MATCH", maxmatch, maxmatch2, NULL, NULL);
+    }
+  }
+} /* matchduplicates */
+
+/*---------------------------------
+  
+  qh_nearcoplanar()
+    for all facets, remove near-inside points from facet->coplanarset
+    coplanar points defined by innerplane from qh_outerinner()
+
+  returns:
+    if qh KEEPcoplanar && !qh KEEPinside
+      facet->coplanarset only contains coplanar points
+    if qh.JOGGLEmax
+      drops inner plane by another qh.JOGGLEmax diagonal since a
+        vertex could shift out while a coplanar point shifts in
+  
+  notes:
+    used for qh.PREmerge and qh.JOGGLEmax
+    must agree with computation of qh.NEARcoplanar in qh_detroundoff()
+  design:
+    if not keeping coplanar or inside points
+      free all coplanar sets
+    else if not keeping both coplanar and inside points
+      remove !coplanar or !inside points from coplanar sets
+*/
+void qh_nearcoplanar ( void /* qh.facet_list */) {
+  facetT *facet;
+  pointT *point, **pointp;
+  int numpart;
+  realT dist, innerplane;
+
+  if (!qh KEEPcoplanar && !qh KEEPinside) {
+    FORALLfacets {
+      if (facet->coplanarset) 
+        qh_setfree( &facet->coplanarset);
+    }
+  }else if (!qh KEEPcoplanar || !qh KEEPinside) {
+    qh_outerinner (NULL, NULL, &innerplane);
+    if (qh JOGGLEmax < REALmax/2)
+      innerplane -= qh JOGGLEmax * sqrt (qh hull_dim);
+    numpart= 0;
+    FORALLfacets { 
+      if (facet->coplanarset) {
+        FOREACHpoint_(facet->coplanarset) {
+          numpart++;
+	  qh_distplane (point, facet, &dist); 
+  	  if (dist < innerplane) {
+	    if (!qh KEEPinside)
+              SETref_(point)= NULL;
+          }else if (!qh KEEPcoplanar)
+            SETref_(point)= NULL;
+        }
+	qh_setcompact (facet->coplanarset);
+      }
+    }
+    zzadd_(Zcheckpart, numpart);
+  }
+} /* nearcoplanar */
+
+/*---------------------------------
+  
+  qh_nearvertex( facet, point, bestdist )
+    return nearest vertex in facet to point
+
+  returns:
+    vertex and its distance
+    
+  notes:
+    if qh.DELAUNAY
+      distance is measured in the input set
+    searches neighboring tricoplanar facets (requires vertexneighbors)
+      Slow implementation.  Recomputes vertex set for each point.
+    The vertex set could be stored in the qh.keepcentrum facet.
+*/
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp) {
+  realT bestdist= REALmax, dist;
+  vertexT *bestvertex= NULL, *vertex, **vertexp, *apex;
+  coordT *center;
+  facetT *neighbor, **neighborp;
+  setT *vertices;
+  int dim= qh hull_dim;
+
+  if (qh DELAUNAY)
+    dim--;
+  if (facet->tricoplanar) {
+    if (!qh VERTEXneighbors || !facet->center) {
+      fprintf(qh ferr, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n");
+      qh_errexit(qh_ERRqhull, NULL, NULL);
+    }
+    vertices= qh_settemp (qh TEMPsize);
+    apex= SETfirst_(facet->vertices);
+    center= facet->center;
+    FOREACHneighbor_(apex) {
+      if (neighbor->center == center) {
+	FOREACHvertex_(neighbor->vertices) 
+	  qh_setappend(&vertices, vertex);
+      }
+    }
+  }else 
+    vertices= facet->vertices;
+  FOREACHvertex_(vertices) {
+    dist= qh_pointdist (vertex->point, point, -dim);
+    if (dist < bestdist) {
+      bestdist= dist;
+      bestvertex= vertex;
+    }
+  }
+  if (facet->tricoplanar)
+    qh_settempfree (&vertices);
+  *bestdistp= sqrt (bestdist);
+  return bestvertex;
+} /* nearvertex */
+
+/*---------------------------------
+  
+  qh_newhashtable( newsize )
+    returns size of qh.hash_table of at least newsize slots
+
+  notes:
+    assumes qh.hash_table is NULL
+    qh_HASHfactor determines the number of extra slots
+    size is not divisible by 2, 3, or 5
+*/
+int qh_newhashtable(int newsize) {
+  int size;
+
+  size= ((newsize+1)*qh_HASHfactor) | 0x1;  /* odd number */
+  while (True) { 
+    if ((size%3) && (size%5))
+      break;
+    size += 2;
+    /* loop terminates because there is an infinite number of primes */
+  }
+  qh hash_table= qh_setnew (size);
+  qh_setzero (qh hash_table, 0, size);
+  return size;
+} /* newhashtable */
+
+/*---------------------------------
+  
+  qh_newvertex( point )
+    returns a new vertex for point
+*/
+vertexT *qh_newvertex(pointT *point) {
+  vertexT *vertex;
+
+  zinc_(Ztotvertices);
+  vertex= (vertexT *)qh_memalloc(sizeof(vertexT));
+  memset ((char *) vertex, 0, sizeof (vertexT));
+  if (qh vertex_id == 0xFFFFFF) {
+    fprintf(qh ferr, "qhull input error: more than %d vertices.  ID field overflows and two vertices\n\
+may have the same identifier.  Vertices not sorted correctly.\n", 0xFFFFFF);
+    qh_errexit(qh_ERRinput, NULL, NULL);
+  }
+  if (qh vertex_id == qh tracevertex_id)
+    qh tracevertex= vertex;
+  vertex->id= qh vertex_id++;
+  vertex->point= point;
+  trace4((qh ferr, "qh_newvertex: vertex p%d (v%d) created\n", qh_pointid(vertex->point), 
+	  vertex->id));
+  return (vertex);
+} /* newvertex */
+
+/*---------------------------------
+  
+  qh_nextridge3d( atridge, facet, vertex )
+    return next ridge and vertex for a 3d facet
+
+  notes:
+    in qh_ORIENTclock order
+    this is a O(n^2) implementation to trace all ridges
+    be sure to stop on any 2nd visit
+  
+  design:
+    for each ridge
+      exit if it is the ridge after atridge
+*/
+ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp) {
+  vertexT *atvertex, *vertex, *othervertex;
+  ridgeT *ridge, **ridgep;
+
+  if ((atridge->top == facet) ^ qh_ORIENTclock)
+    atvertex= SETsecondt_(atridge->vertices, vertexT);
+  else
+    atvertex= SETfirstt_(atridge->vertices, vertexT);
+  FOREACHridge_(facet->ridges) {
+    if (ridge == atridge)
+      continue;
+    if ((ridge->top == facet) ^ qh_ORIENTclock) {
+      othervertex= SETsecondt_(ridge->vertices, vertexT);
+      vertex= SETfirstt_(ridge->vertices, vertexT);
+    }else {
+      vertex= SETsecondt_(ridge->vertices, vertexT);
+      othervertex= SETfirstt_(ridge->vertices, vertexT);
+    }
+    if (vertex == atvertex) {
+      if (vertexp)
+        *vertexp= othervertex;
+      return ridge;
+    }
+  }
+  return NULL;
+} /* nextridge3d */
+#else /* qh_NOmerge */
+void qh_matchduplicates (facetT *atfacet, int atskip, int hashsize, int *hashcount) {
+}
+ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp) {
+
+  return NULL;
+}
+#endif /* qh_NOmerge */
+  
+/*---------------------------------
+  
+  qh_outcoplanar()
+    move points from all facets' outsidesets to their coplanarsets
+
+  notes:
+    for post-processing under qh.NARROWhull
+
+  design:
+    for each facet
+      for each outside point for facet
+        partition point into coplanar set
+*/
+void qh_outcoplanar (void /* facet_list */) {
+  pointT *point, **pointp;
+  facetT *facet;
+  realT dist;
+
+  trace1((qh ferr, "qh_outcoplanar: move outsideset to coplanarset for qh NARROWhull\n"));
+  FORALLfacets {
+    FOREACHpoint_(facet->outsideset) {
+      qh num_outside--;
+      if (qh KEEPcoplanar || qh KEEPnearinside) {
+	qh_distplane (point, facet, &dist);
+        zinc_(Zpartition);
+	qh_partitioncoplanar (point, facet, &dist);
+      }
+    }
+    qh_setfree (&facet->outsideset);
+  }
+} /* outcoplanar */
+
+/*---------------------------------
+  
+  qh_point( id )
+    return point for a point id, or NULL if unknown
+
+  alternative code:
+    return ((pointT *)((unsigned   long)qh.first_point
+           + (unsigned long)((id)*qh.normal_size)));
+*/
+pointT *qh_point (int id) {
+
+  if (id < 0)
+    return NULL;
+  if (id < qh num_points)
+    return qh first_point + id * qh hull_dim;
+  id -= qh num_points;
+  if (id < qh_setsize (qh other_points))
+    return SETelemt_(qh other_points, id, pointT);
+  return NULL;
+} /* point */
+  
+/*---------------------------------
+  
+  qh_point_add( set, point, elem )
+    stores elem at set[point.id]
+  
+  returns:
+    access function for qh_pointfacet and qh_pointvertex
+
+  notes:
+    checks point.id
+*/
+void qh_point_add (setT *set, pointT *point, void *elem) {
+  int id, size;
+
+  SETreturnsize_(set, size);
+  if ((id= qh_pointid(point)) < 0)
+    fprintf (qh ferr, "qhull internal warning (point_add): unknown point %p id %d\n", 
+      point, id);
+  else if (id >= size) {
+    fprintf (qh ferr, "qhull internal errror (point_add): point p%d is out of bounds (%d)\n",
+	     id, size);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }else
+    SETelem_(set, id)= elem;
+} /* point_add */
+
+
+/*---------------------------------
+  
+  qh_pointfacet()
+    return temporary set of facet for each point
+    the set is indexed by point id
+
+  notes:
+    vertices assigned to one of the facets
+    coplanarset assigned to the facet
+    outside set assigned to the facet
+    NULL if no facet for point (inside)
+      includes qh.GOODpointp
+
+  access:
+    FOREACHfacet_i_(facets) { ... }
+    SETelem_(facets, i)
+  
+  design:
+    for each facet
+      add each vertex
+      add each coplanar point
+      add each outside point
+*/
+setT *qh_pointfacet (void /*qh facet_list*/) {
+  int numpoints= qh num_points + qh_setsize (qh other_points);
+  setT *facets;
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+  pointT *point, **pointp;
+  
+  facets= qh_settemp (numpoints);
+  qh_setzero (facets, 0, numpoints);
+  qh vertex_visit++;
+  FORALLfacets {
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh vertex_visit) {
+        vertex->visitid= qh vertex_visit;
+        qh_point_add (facets, vertex->point, facet);
+      }
+    }
+    FOREACHpoint_(facet->coplanarset) 
+      qh_point_add (facets, point, facet);
+    FOREACHpoint_(facet->outsideset) 
+      qh_point_add (facets, point, facet);
+  }
+  return facets;
+} /* pointfacet */
+
+/*---------------------------------
+  
+  qh_pointvertex(  )
+    return temporary set of vertices indexed by point id
+    entry is NULL if no vertex for a point
+      this will include qh.GOODpointp
+
+  access:
+    FOREACHvertex_i_(vertices) { ... }
+    SETelem_(vertices, i)
+*/
+setT *qh_pointvertex (void /*qh facet_list*/) {
+  int numpoints= qh num_points + qh_setsize (qh other_points);
+  setT *vertices;
+  vertexT *vertex;
+  
+  vertices= qh_settemp (numpoints);
+  qh_setzero (vertices, 0, numpoints);
+  FORALLvertices 
+    qh_point_add (vertices, vertex->point, vertex);
+  return vertices;
+} /* pointvertex */
+
+
+/*---------------------------------
+  
+  qh_prependfacet( facet, facetlist )
+    prepend facet to the start of a facetlist
+
+  returns:
+    increments qh.numfacets
+    updates facetlist, qh.facet_list, facet_next
+  
+  notes:
+    be careful of prepending since it can lose a pointer.
+      e.g., can lose _next by deleting and then prepending before _next
+*/
+void qh_prependfacet(facetT *facet, facetT **facetlist) {
+  facetT *prevfacet, *list;
+  
+
+  trace4((qh ferr, "qh_prependfacet: prepend f%d before f%d\n",
+	  facet->id, getid_(*facetlist)));
+  if (!*facetlist)
+    (*facetlist)= qh facet_tail;
+  list= *facetlist;
+  prevfacet= list->previous;
+  facet->previous= prevfacet;
+  if (prevfacet)
+    prevfacet->next= facet;
+  list->previous= facet;
+  facet->next= *facetlist;
+  if (qh facet_list == list)  /* this may change *facetlist */
+    qh facet_list= facet;
+  if (qh facet_next == list)
+    qh facet_next= facet;
+  *facetlist= facet;
+  qh num_facets++;
+} /* prependfacet */
+
+
+/*---------------------------------
+  
+  qh_printhashtable( fp )
+    print hash table to fp
+
+  notes:
+    not in I/O to avoid bringing io.c in
+  
+  design:
+    for each hash entry
+      if defined
+        if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge)
+          print entry and neighbors
+*/
+void qh_printhashtable(FILE *fp) {
+  facetT *facet, *neighbor;
+  int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
+  vertexT *vertex, **vertexp;
+
+  FOREACHfacet_i_(qh hash_table) {
+    if (facet) {
+      FOREACHneighbor_i_(facet) {
+        if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) 
+          break;
+      }
+      if (neighbor_i == neighbor_n)
+        continue;
+      fprintf (fp, "hash %d f%d ", facet_i, facet->id);
+      FOREACHvertex_(facet->vertices)
+        fprintf (fp, "v%d ", vertex->id);
+      fprintf (fp, "\n neighbors:");
+      FOREACHneighbor_i_(facet) {
+	if (neighbor == qh_MERGEridge)
+	  id= -3;
+	else if (neighbor == qh_DUPLICATEridge)
+	  id= -2;
+	else
+	  id= getid_(neighbor);
+        fprintf (fp, " %d", id);
+      }
+      fprintf (fp, "\n");
+    }
+  }
+} /* printhashtable */
+     
+
+/*---------------------------------
+  
+  qh_printlists( fp )
+    print out facet and vertex list for debugging (without 'f/v' tags)
+*/
+void qh_printlists (void) {
+  facetT *facet;
+  vertexT *vertex;
+  int count= 0;
+  
+  fprintf (qh ferr, "qh_printlists: facets:");
+  FORALLfacets {
+    if (++count % 100 == 0)
+      fprintf (qh ferr, "\n     ");
+    fprintf (qh ferr, " %d", facet->id);
+  }
+  fprintf (qh ferr, "\n  new facets %d visible facets %d next facet for qh_addpoint %d\n  vertices (new %d):",
+     getid_(qh newfacet_list), getid_(qh visible_list), getid_(qh facet_next),
+     getid_(qh newvertex_list));
+  count = 0;
+  FORALLvertices {
+    if (++count % 100 == 0)
+      fprintf (qh ferr, "\n     ");
+    fprintf (qh ferr, " %d", vertex->id);
+  }
+  fprintf (qh ferr, "\n");
+} /* printlists */
+  
+/*---------------------------------
+  
+  qh_resetlists( stats, qh_RESETvisible )
+    reset newvertex_list, newfacet_list, visible_list
+    if stats, 
+      maintains statistics
+
+  returns:
+    visible_list is empty if qh_deletevisible was called
+*/
+void qh_resetlists (boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/) {
+  vertexT *vertex;
+  facetT *newfacet, *visible;
+  int totnew=0, totver=0;
+  
+  if (stats) {
+    FORALLvertex_(qh newvertex_list)
+      totver++;
+    FORALLnew_facets 
+      totnew++;
+    zadd_(Zvisvertextot, totver);
+    zmax_(Zvisvertexmax, totver);
+    zadd_(Znewfacettot, totnew);
+    zmax_(Znewfacetmax, totnew);
+  }
+  FORALLvertex_(qh newvertex_list)
+    vertex->newlist= False;
+  qh newvertex_list= NULL;
+  FORALLnew_facets
+    newfacet->newfacet= False;
+  qh newfacet_list= NULL;
+  if (resetVisible) {
+    FORALLvisible_facets {
+      visible->f.replace= NULL;
+      visible->visible= False;
+    }
+    qh num_visible= 0;
+  }
+  qh visible_list= NULL; /* may still have visible facets via qh_triangulate */
+  qh NEWfacets= False;
+} /* resetlists */
+
+/*---------------------------------
+  
+  qh_setvoronoi_all()
+    compute Voronoi centers for all facets
+    includes upperDelaunay facets if qh.UPPERdelaunay ('Qu')
+
+  returns:
+    facet->center is the Voronoi center
+    
+  notes:
+    this is unused/untested code
+      please email bradb@shore.net if this works ok for you
+  
+  use:
+    FORALLvertices {...} to locate the vertex for a point.  
+    FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell.
+*/
+void qh_setvoronoi_all (void) {
+  facetT *facet;
+
+  qh_clearcenters (qh_ASvoronoi);
+  qh_vertexneighbors();
+  
+  FORALLfacets {
+    if (!facet->normal || !facet->upperdelaunay || qh UPPERdelaunay) {
+      if (!facet->center)
+        facet->center= qh_facetcenter (facet->vertices);
+    }
+  }
+} /* setvoronoi_all */
+
+#ifndef qh_NOmerge
+
+/*---------------------------------
+  
+  qh_triangulate()
+    triangulate non-simplicial facets on qh.facet_list, 
+    if qh.CENTERtype=qh_ASvoronoi, sets Voronoi centers of non-simplicial facets
+
+  returns:
+    all facets simplicial
+    each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc.
+
+  notes:
+    call after qh_check_output since may switch to Voronoi centers
+    Output may overwrite ->f.triowner with ->f.area
+*/
+void qh_triangulate (void /*qh facet_list*/) {
+  facetT *facet, *nextfacet, *owner;
+  int onlygood= qh ONLYgood;
+  facetT *neighbor, *visible= NULL, *facet1, *facet2, *new_facet_list= NULL;
+  facetT *orig_neighbor= NULL, *otherfacet;
+  vertexT *new_vertex_list= NULL;
+  mergeT *merge; 
+  mergeType mergetype;
+  int neighbor_i, neighbor_n;
+
+  trace1((qh ferr, "qh_triangulate: triangulate non-simplicial facets\n"));
+  if (qh hull_dim == 2)
+    return;
+  if (qh VORONOI) {  /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */
+    qh_clearcenters (qh_ASvoronoi);
+    qh_vertexneighbors();
+  }
+  qh ONLYgood= False; /* for makenew_nonsimplicial */
+  qh visit_id++;
+  qh NEWfacets= True;
+  qh degen_mergeset= qh_settemp (qh TEMPsize);
+  qh newvertex_list= qh vertex_tail;
+  for (facet= qh facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */
+    nextfacet= facet->next;
+    if (facet->visible || facet->simplicial)
+      continue;
+    /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */
+    if (!new_facet_list)
+      new_facet_list= facet;  /* will be moved to end */
+    qh_triangulate_facet (facet, &new_vertex_list);
+  }
+  trace2((qh ferr, "qh_triangulate: delete null facets from f%d -- apex same as second vertex\n", getid_(new_facet_list)));
+  for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* null facets moved to end */
+    nextfacet= facet->next;
+    if (facet->visible) 
+      continue;
+    if (facet->ridges) {
+      if (qh_setsize(facet->ridges) > 0) {
+	fprintf( qh ferr, "qhull error (qh_triangulate): ridges still defined for f%d\n", facet->id);
+	qh_errexit (qh_ERRqhull, facet, NULL);
+      }
+      qh_setfree (&facet->ridges);
+    }
+    if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) {
+      zinc_(Ztrinull);
+      qh_triangulate_null (facet);
+    }
+  }
+  trace2((qh ferr, "qh_triangulate: delete %d or more mirror facets -- same vertices and neighbors\n", qh_setsize(qh degen_mergeset)));
+  qh visible_list= qh facet_tail;
+  while ((merge= (mergeT*)qh_setdellast (qh degen_mergeset))) {
+    facet1= merge->facet1;
+    facet2= merge->facet2;
+    mergetype= merge->type;
+    qh_memfree (merge, sizeof(mergeT));
+    if (mergetype == MRGmirror) {
+      zinc_(Ztrimirror);
+      qh_triangulate_mirror (facet1, facet2);
+    }
+  }
+  qh_settempfree(&qh degen_mergeset);
+  trace2((qh ferr, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(new_vertex_list)));
+  qh newvertex_list= new_vertex_list;  /* all vertices of new facets */
+  qh visible_list= NULL;
+  qh_updatevertices(/*qh newvertex_list, empty newfacet_list and visible_list*/);
+  qh_resetlists (False, !qh_RESETvisible /*qh newvertex_list, empty newfacet_list and visible_list*/);
+
+  trace2((qh ferr, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list)));
+  trace2((qh ferr, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n"));
+  FORALLfacet_(new_facet_list) {
+    if (facet->tricoplanar && !facet->visible) {
+      FOREACHneighbor_i_(facet) {
+	if (neighbor_i == 0) {  /* first iteration */
+	  if (neighbor->tricoplanar)
+            orig_neighbor= neighbor->f.triowner;
+	  else
+	    orig_neighbor= neighbor;
+	}else {
+	  if (neighbor->tricoplanar)
+  	    otherfacet= neighbor->f.triowner;
+	  else
+	    otherfacet= neighbor;
+	  if (orig_neighbor == otherfacet) {
+	    zinc_(Ztridegen);
+	    facet->degenerate= True;
+	    break;
+	  }
+	}
+      }
+    }
+  }
+
+  trace2((qh ferr, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n"));
+  owner= NULL;
+  visible= NULL;
+  for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* may delete facet */
+    nextfacet= facet->next;
+    if (facet->visible) {
+      if (facet->tricoplanar) { /* a null or mirrored facet */
+	qh_delfacet(facet);
+	qh num_visible--;
+      }else {  /* a non-simplicial facet followed by its tricoplanars */
+	if (visible && !owner) {
+	  /*  RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */
+	  trace2((qh ferr, "qh_triangulate: all tricoplanar facets degenerate for non-simplicial facet f%d\n",
+		       visible->id));
+	  qh_delfacet(visible);
+	  qh num_visible--;
+	}
+	visible= facet;
+	owner= NULL;
+      }
+    }else if (facet->tricoplanar) {
+      if (facet->f.triowner != visible) { 
+	fprintf( qh ferr, "qhull error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible));
+	qh_errexit2 (qh_ERRqhull, facet, visible);
+      }
+      if (owner) 
+	facet->f.triowner= owner;
+      else if (!facet->degenerate) {
+	owner= facet;
+	nextfacet= visible->next; /* rescan tricoplanar facets with owner */
+	facet->keepcentrum= True;  /* one facet owns ->normal, etc. */
+	facet->coplanarset= visible->coplanarset;
+	facet->outsideset= visible->outsideset;
+  	visible->coplanarset= NULL;
+	visible->outsideset= NULL;
+        if (!qh TRInormals) { /* center and normal copied to tricoplanar facets */
+	  visible->center= NULL;
+	  visible->normal= NULL;
+	}
+	qh_delfacet(visible);
+	qh num_visible--;
+      }
+    }
+  }
+  if (visible && !owner) {
+    trace2((qh ferr, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n",
+	         visible->id));
+    qh_delfacet(visible);
+    qh num_visible--;
+  }
+  qh NEWfacets= False;
+  qh ONLYgood= onlygood; /* restore value */
+  if (qh CHECKfrequently) 
+    qh_checkpolygon (qh facet_list);
+} /* triangulate */
+
+
+/*---------------------------------
+  
+  qh_triangulate_facet (facetA)
+    triangulate a non-simplicial facet
+      if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center
+  returns:
+    qh.newfacet_list == simplicial facets
+      facet->tricoplanar set and ->keepcentrum false
+      facet->degenerate set if duplicated apex
+      facet->f.trivisible set to facetA
+      facet->center copied from facetA (created if qh_ASvoronoi)
+	qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied
+      facet->normal,offset,maxoutside copied from facetA
+
+  notes:
+      qh_makenew_nonsimplicial uses neighbor->seen for the same
+
+  see also:
+      qh_addpoint() -- add a point
+      qh_makenewfacets() -- construct a cone of facets for a new vertex
+
+  design:
+      if qh_ASvoronoi, 
+	 compute Voronoi center (facet->center)
+      select first vertex (highest ID to preserve ID ordering of ->vertices)
+      triangulate from vertex to ridges
+      copy facet->center, normal, offset
+      update vertex neighbors
+*/
+void qh_triangulate_facet (facetT *facetA, vertexT **first_vertex) {
+  facetT *newfacet;
+  facetT *neighbor, **neighborp;
+  vertexT *apex;
+  int numnew=0;
+
+  trace3((qh ferr, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id));
+
+  if (qh IStracing >= 4)
+    qh_printfacet (qh ferr, facetA);
+  FOREACHneighbor_(facetA) {
+    neighbor->seen= False;
+    neighbor->coplanar= False;
+  }
+  if (qh CENTERtype == qh_ASvoronoi && !facetA->center  /* matches upperdelaunay in qh_setfacetplane() */
+        && fabs_(facetA->normal[qh hull_dim -1]) >= qh ANGLEround * qh_ZEROdelaunay) {
+    facetA->center= qh_facetcenter (facetA->vertices);
+  }
+  qh_willdelete (facetA, NULL);
+  qh newfacet_list= qh facet_tail;
+  facetA->visitid= qh visit_id;
+  apex= SETfirst_(facetA->vertices);
+  qh_makenew_nonsimplicial (facetA, apex, &numnew);
+  SETfirst_(facetA->neighbors)= NULL;
+  FORALLnew_facets {
+    newfacet->tricoplanar= True;
+    newfacet->f.trivisible= facetA;
+    newfacet->degenerate= False;
+    newfacet->upperdelaunay= facetA->upperdelaunay;
+    newfacet->good= facetA->good;
+    if (qh TRInormals) { 
+      newfacet->keepcentrum= True;
+      newfacet->normal= qh_copypoints (facetA->normal, 1, qh hull_dim);
+      if (qh CENTERtype == qh_AScentrum) 
+	newfacet->center= qh_getcentrum (newfacet);
+      else
+	newfacet->center= qh_copypoints (facetA->center, 1, qh hull_dim);
+    }else {
+      newfacet->keepcentrum= False;
+      newfacet->normal= facetA->normal;
+      newfacet->center= facetA->center;
+    }
+    newfacet->offset= facetA->offset;
+#if qh_MAXoutside
+    newfacet->maxoutside= facetA->maxoutside;
+#endif
+  }
+  qh_matchnewfacets(/*qh newfacet_list*/);
+  zinc_(Ztricoplanar);
+  zadd_(Ztricoplanartot, numnew);
+  zmax_(Ztricoplanarmax, numnew);
+  qh visible_list= NULL;
+  if (!(*first_vertex))
+    (*first_vertex)= qh newvertex_list;
+  qh newvertex_list= NULL;
+  qh_updatevertices(/*qh newfacet_list, empty visible_list and newvertex_list*/);
+  qh_resetlists (False, !qh_RESETvisible /*qh newfacet_list, empty visible_list and newvertex_list*/);
+} /* triangulate_facet */
+
+/*---------------------------------
+  
+  qh_triangulate_link (oldfacetA, facetA, oldfacetB, facetB)
+    relink facetA to facetB via oldfacets
+  returns:
+    adds mirror facets to qh degen_mergeset (4-d and up only)
+  design:
+    if they are already neighbors, the opposing neighbors become MRGmirror facets
+*/
+void qh_triangulate_link (facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) {
+  int errmirror= False;
+
+  trace3((qh ferr, "qh_triangulate_link: relink old facets f%d and f%d between neighbors f%d and f%d\n", 
+         oldfacetA->id, oldfacetB->id, facetA->id, facetB->id));
+  if (qh_setin (facetA->neighbors, facetB)) {
+    if (!qh_setin (facetB->neighbors, facetA)) 
+      errmirror= True;
+    else
+      qh_appendmergeset (facetA, facetB, MRGmirror, NULL);
+  }else if (qh_setin (facetB->neighbors, facetA)) 
+    errmirror= True;
+  if (errmirror) {
+    fprintf( qh ferr, "qhull error (qh_triangulate_link): mirror facets f%d and f%d do not match for old facets f%d and f%d\n",
+       facetA->id, facetB->id, oldfacetA->id, oldfacetB->id);
+    qh_errexit2 (qh_ERRqhull, facetA, facetB);
+  }
+  qh_setreplace (facetB->neighbors, oldfacetB, facetA);
+  qh_setreplace (facetA->neighbors, oldfacetA, facetB);
+} /* triangulate_link */
+
+/*---------------------------------
+  
+  qh_triangulate_mirror (facetA, facetB)
+    delete mirrored facets from qh_triangulate_null() and qh_triangulate_mirror
+      a mirrored facet shares the same vertices of a logical ridge
+  design:
+    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
+    if they are already neighbors, the opposing neighbors become MRGmirror facets
+*/
+void qh_triangulate_mirror (facetT *facetA, facetT *facetB) {
+  facetT *neighbor, *neighborB;
+  int neighbor_i, neighbor_n;
+
+  trace3((qh ferr, "qh_triangulate_mirror: delete mirrored facets f%d and f%d\n", 
+         facetA->id, facetB->id));
+  FOREACHneighbor_i_(facetA) {
+    neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT);
+    if (neighbor == neighborB)
+      continue; /* occurs twice */
+    qh_triangulate_link (facetA, neighbor, facetB, neighborB);
+  }
+  qh_willdelete (facetA, NULL);
+  qh_willdelete (facetB, NULL);
+} /* triangulate_mirror */
+
+/*---------------------------------
+  
+  qh_triangulate_null (facetA)
+    remove null facetA from qh_triangulate_facet()
+      a null facet has vertex #1 (apex) == vertex #2
+  returns:
+    adds facetA to ->visible for deletion after qh_updatevertices
+    qh degen_mergeset contains mirror facets (4-d and up only)
+  design:
+    since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet
+    if they are already neighbors, the opposing neighbors become MRGmirror facets
+*/
+void qh_triangulate_null (facetT *facetA) {
+  facetT *neighbor, *otherfacet;
+
+  trace3((qh ferr, "qh_triangulate_null: delete null facet f%d\n", facetA->id));
+  neighbor= SETfirst_(facetA->neighbors);
+  otherfacet= SETsecond_(facetA->neighbors);
+  qh_triangulate_link (facetA, neighbor, facetA, otherfacet);
+  qh_willdelete (facetA, NULL);
+} /* triangulate_null */
+
+#else /* qh_NOmerge */
+void qh_triangulate (void) {
+}
+#endif /* qh_NOmerge */
+
+   /*---------------------------------
+  
+  qh_vertexintersect( vertexsetA, vertexsetB )
+    intersects two vertex sets (inverse id ordered)
+    vertexsetA is a temporary set at the top of qhmem.tempstack
+
+  returns:
+    replaces vertexsetA with the intersection
+  
+  notes:
+    could overwrite vertexsetA if currently too slow
+*/
+void qh_vertexintersect(setT **vertexsetA,setT *vertexsetB) {
+  setT *intersection;
+
+  intersection= qh_vertexintersect_new (*vertexsetA, vertexsetB);
+  qh_settempfree (vertexsetA);
+  *vertexsetA= intersection;
+  qh_settemppush (intersection);
+} /* vertexintersect */
+
+/*---------------------------------
+  
+  qh_vertexintersect_new(  )
+    intersects two vertex sets (inverse id ordered)
+
+  returns:
+    a new set
+*/
+setT *qh_vertexintersect_new (setT *vertexsetA,setT *vertexsetB) {
+  setT *intersection= qh_setnew (qh hull_dim - 1);
+  vertexT **vertexA= SETaddr_(vertexsetA, vertexT); 
+  vertexT **vertexB= SETaddr_(vertexsetB, vertexT); 
+
+  while (*vertexA && *vertexB) {
+    if (*vertexA  == *vertexB) {
+      qh_setappend(&intersection, *vertexA);
+      vertexA++; vertexB++;
+    }else {
+      if ((*vertexA)->id > (*vertexB)->id)
+        vertexA++;
+      else
+        vertexB++;
+    }
+  }
+  return intersection;
+} /* vertexintersect_new */
+
+/*---------------------------------
+  
+  qh_vertexneighbors()
+    for each vertex in qh.facet_list, 
+      determine its neighboring facets 
+
+  returns:
+    sets qh.VERTEXneighbors
+      nop if qh.VERTEXneighbors already set
+      qh_addpoint() will maintain them
+
+  notes:
+    assumes all vertex->neighbors are NULL
+
+  design:
+    for each facet
+      for each vertex
+        append facet to vertex->neighbors
+*/
+void qh_vertexneighbors (void /*qh facet_list*/) {
+  facetT *facet;
+  vertexT *vertex, **vertexp;
+
+  if (qh VERTEXneighbors)
+    return;
+  trace1((qh ferr, "qh_vertexneighbors: determing neighboring facets for each vertex\n"));
+  qh vertex_visit++;
+  FORALLfacets {
+    if (facet->visible)
+      continue;
+    FOREACHvertex_(facet->vertices) {
+      if (vertex->visitid != qh vertex_visit) {
+        vertex->visitid= qh vertex_visit;
+        vertex->neighbors= qh_setnew (qh hull_dim);
+      }
+      qh_setappend (&vertex->neighbors, facet);
+    }
+  }
+  qh VERTEXneighbors= True;
+} /* vertexneighbors */
+
+/*---------------------------------
+  
+  qh_vertexsubset( vertexsetA, vertexsetB )
+    returns True if vertexsetA is a subset of vertexsetB
+    assumes vertexsets are sorted
+
+  note:    
+    empty set is a subset of any other set
+*/
+boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {
+  vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
+  vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);
+
+  while (True) {
+    if (!*vertexA)
+      return True;
+    if (!*vertexB)
+      return False;
+    if ((*vertexA)->id > (*vertexB)->id)
+      return False;
+    if (*vertexA  == *vertexB)
+      vertexA++;
+    vertexB++; 
+  }
+  return False; /* avoid warnings */
+} /* vertexsubset */
diff --git a/extern/qhull/src/qconvex.c b/extern/qhull/src/qconvex.c
new file mode 100644
index 00000000000..67b78646e50
--- /dev/null
+++ b/extern/qhull/src/qconvex.c
@@ -0,0 +1,334 @@
+/*
  ---------------------------------
+
+   qconvex.c
+      compute convex hulls using qhull
+
+   see unix.c for full interface
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt
+    long prompt for qconvex
+    
+  notes:
+    restricted version of qhull.c
+
+  see:
+    concise prompt below
+*/  
+
+/* duplicated in qconvex.htm */
+char hidden_options[]=" d v H Qbb Qf Qg Qm Qr Qu Qv Qx Qz TR E V Fp Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
+	       
+char qh_prompta[]= "\n\
+qconvex- compute the convex hull\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    first lines: dimension and number of points (or vice-versa).\n\
+    other lines: point coordinates, best if one point per line\n\
+    comments:    start with a non-numeric character\n\
+\n\
+options:\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Qc   - keep coplanar points with nearest facet\n\
+    Qi   - keep interior points with nearest facet\n\
+\n\
+Qhull control options:\n\
+    Qbk:n   - scale coord k so that low bound is n\n\
+      QBk:n - scale coord k so that upper bound is n (QBk is %2.2g)\n\
+    QbB  - scale input to unit cube centered at the origin\n\
+    Qbk:0Bk:0 - remove k-th coordinate from input\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qs   - search all points for the initial simplex\n\
+    QGn  - good facet if visible from point n, -n for not visible\n\
+    QVn  - good facet if it includes point n, -n if not\n\
+\n\
+";
+char qh_promptc[]= "\
+Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - print statistics\n\
+    Tv   - verify result: structure, convexity, and point inclusion\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when point n added to hull\n\
+     TMn - turn on tracing at merge n\n\
+     TWn - trace merge facets when width > n\n\
+    TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
+     TCn - stop qhull after building cone for point n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Un   - max distance below plane for a new, coplanar point\n\
+    Wn   - min facet width for outside point (before roundoff)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    f    - facet dump\n\
+    G    - Geomview output (see below)\n\
+    i    - vertices incident to each facet\n\
+    m    - Mathematica output (2-d and 3-d)\n\
+    n    - normals with offsets\n\
+    o    - OFF file format (dim, points and facets; Voronoi regions)\n\
+    p    - point coordinates \n\
+    s    - summary (stderr)\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fa   - area for each facet\n\
+    FA   - compute total area and volume for option 's'\n\
+    Fc   - count plus coplanar points for each facet\n\
+           use 'Qc' (default) for coplanar and 'Qi' for interior\n\
+    FC   - centrum for each facet\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FD   - use cdd format for numeric output (offset first)\n\
+    FF   - facet dump without ridges\n\
+    Fi   - inner plane for each facet\n\
+    FI   - ID for each facet\n\
+    Fm   - merge count for each facet (511 max)\n\
+    Fn   - count plus neighboring facets for each facet\n\
+    FN   - count plus neighboring facets for each point\n\
+    Fo   - outer plane (or max_outside) for each facet\n\
+    FO   - options and precision constants\n\
+    FP   - nearest vertex for each coplanar point\n\
+    FQ   - command used for qconvex\n\
+    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
+                      for output: #vertices, #facets,\n\
+                                  #coplanar points, #non-simplicial facets\n\
+                    #real (2), max outer plane, min vertex\n\
+    FS   - sizes:   #int (0) \n\
+                    #real(2) tot area, tot volume\n\
+    Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
+    Fv   - count plus vertices for each facet\n\
+    FV   - average of vertices (a feasible point for 'H')\n\
+    Fx   - extreme points (in order for 2-d)\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview output (2-d, 3-d, and 4-d)\n\
+    Ga   - all points as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices as spheres\n\
+    Gi   - inner planes only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc   - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest facets by area\n\
+    Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n - drop facet if normal[k] >= n\n\
+    Pg   - print good facets (needs 'QGn' or 'QVn')\n\
+    PFn  - keep facets whose area is at least n\n\
+    PG   - print neighbors of good facets\n\
+    PMn  - keep n facets with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull 
+*/  
+char qh_prompt2[]= "\n\
+qconvex- compute the convex hull.  Qhull %s\n\
+    input (stdin): dimension, number of points, point coordinates\n\
+    comments start with a non-numeric character\n\
+\n\
+options (qconvex.htm):\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and point inclusion\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+output options (subset):\n\
+    s    - summary of results (default)\n\
+    i    - vertices incident to each facet\n\
+    n    - normals with offsets\n\
+    p    - vertex coordinates (includes coplanar points if 'Qc')\n\
+    Fx   - extreme points (convex hull vertices)\n\
+    FA   - compute total area and volume\n\
+    o    - OFF format (dim, n, points, facets)\n\
+    G    - Geomview output (2-d, 3-d, and 4-d)\n\
+    m    - Mathematica output (2-d and 3-d)\n\
+    QVn  - print facets that include point n, -n if not\n\
+    TO file- output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+    rbox c D2 | qconvex s n                    rbox c D2 | qconvex i\n\
+    rbox c D2 | qconvex o                      rbox 1000 s | qconvex s Tv FA\n\
+    rbox c d D2 | qconvex s Qc Fx              rbox y 1000 W0 | qconvex s n\n\
+    rbox y 1000 W0 | qconvex s QJ              rbox d G1 D12 | qconvex QR0 FA Pp\n\
+    rbox c D7 | qconvex FA TF1000\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull 
+*/  
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper-case options take an argument.\n\
+\n\
+ incidences     mathematica    normals        OFF_format     points\n\
+ summary        facet_dump\n\
+\n\
+ Farea          FArea_total    Fcoplanars     FCentrums      Fd_cdd_in\n\
+ FD_cdd_out     FFacet_xridge  Finner         FIDs           Fmerges\n\
+ Fneighbors     FNeigh_vertex  Fouter         FOptions       FPoint_near\n\
+ FQhull         Fsummary       FSize          Fvertices      FVertex_ave\n\
+ Fxtremes\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+\n\
+ PArea_keep     Pdrop d0:0D0   PFacet_area_keep Pgood        PGood_neighbors\n\
+ PMerge_keep    Poutput_forced Pprecision_not\n\
+\n\
+ QbBound 0:0.5  QbB_scale_box  Qcoplanar      QGood_point    Qinterior\n\
+ QJoggle        Qrandom        QRotate        Qsearch_1st    Qtriangulate\n\
+ QVertex_good\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Random_dist    Ucoplanar_max  Wide_outside\n\
+";
+
+/*---------------------------------
+  
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+  
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {      
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION, qh_DEFAULTbox, 
+		qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_checkflags (qh qhull_command, hidden_options);
+    qh_initflags (qh qhull_command);
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    if (dim >= 5) {
+      qh_option ("Qxact_merge", NULL, NULL);
+      qh MERGEexact= True; /* 'Qx' always */
+    }
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/qdelaun.c b/extern/qhull/src/qdelaun.c
new file mode 100644
index 00000000000..0e49d9c381e
--- /dev/null
+++ b/extern/qhull/src/qdelaun.c
@@ -0,0 +1,323 @@
+/*
  ---------------------------------
+
+   qdelaun.c
+     compute Delaunay triangulations and furthest-point Delaunay
+     triangulations using qhull
+
+   see unix.c for full interface
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt 
+    long prompt for qhull
+    
+  notes:
+    restricted version of qhull.c
+ 
+  see:
+    concise prompt below
+*/  
+
+/* duplicated in qdelau_f.htm and qdelaun.htm */
+char hidden_options[]=" d n v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V FC Fi Fo Ft Fp FV Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
+
+char qh_prompta[]= "\n\
+qdelaunay- compute the Delaunay triangulation\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    first lines: dimension and number of points (or vice-versa).\n\
+    other lines: point coordinates, best if one point per line\n\
+    comments:    start with a non-numeric character\n\
+\n\
+options:\n\
+    Qu   - compute furthest-site Delaunay triangulation\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+\n\
+Qhull control options:\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qs   - search all points for the initial simplex\n\
+    Qz   - add point-at-infinity to Delaunay triangulation\n\
+    QGn  - print Delaunay region if visible from point n, -n if not\n\
+    QVn  - print Delaunay regions that include point n, -n if not\n\
+\n\
+";
+char qh_promptc[]= "\
+Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - print statistics\n\
+    Tv   - verify result: structure, convexity, and in-circle test\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when point n added to hull\n\
+     TMn - turn on tracing at merge n\n\
+     TWn - trace merge facets when width > n\n\
+    TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
+     TCn - stop qhull after building cone for point n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Wn   - min facet width for outside point (before roundoff)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    f    - facet dump\n\
+    G    - Geomview output (see below)\n\
+    i    - vertices incident to each Delaunay region\n\
+    m    - Mathematica output (2-d only, lifted to a paraboloid)\n\
+    o    - OFF format (dim, points, and facets as a paraboloid)\n\
+    p    - point coordinates (lifted to a paraboloid)\n\
+    s    - summary (stderr)\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fa   - area for each Delaunay region\n\
+    FA   - compute total area for option 's'\n\
+    Fc   - count plus coincident points for each Delaunay region\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FD   - use cdd format for numeric output (offset first)\n\
+    FF   - facet dump without ridges\n\
+    FI   - ID of each Delaunay region\n\
+    Fm   - merge count for each Delaunay region (511 max)\n\
+    Fn   - count plus neighboring region for each Delaunay region\n\
+    FN   - count plus neighboring region for each point\n\
+    FO   - options and precision constants\n\
+    FP   - nearest point and distance for each coincident point\n\
+    FQ   - command used for qdelaunay\n\
+    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
+                    for output: #vertices, #Delaunay regions,\n\
+                                #coincident points, #non-simplicial regions\n\
+                    #real (2), max outer plane, min vertex\n\
+    FS   - sizes:   #int (0)\n\
+                    #real(2) tot area, 0\n\
+    Fv   - count plus vertices for each Delaunay region\n\
+    Fx   - extreme points of Delaunay triangulation (on convex hull)\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview options (2-d and 3-d)\n\
+    Ga   - all points as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices as spheres\n\
+    Gi   - inner planes only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc	   - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+    Gt   - transparent outer ridges to view 3-d Delaunay\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest Delaunay regions by area\n\
+    Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n - drop facet if normal[k] >= n\n\
+    Pg   - print good Delaunay regions (needs 'QGn' or 'QVn')\n\
+    PFn  - keep Delaunay regions whose area is at least n\n\
+    PG   - print neighbors of good regions (needs 'QGn' or 'QVn')\n\
+    PMn  - keep n Delaunay regions with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull 
+*/  
+char qh_prompt2[]= "\n\
+qdelaunay- compute the Delaunay triangulation. Qhull %s\n\
+    input (stdin): dimension, number of points, point coordinates\n\
+    comments start with a non-numeric character\n\
+\n\
+options (qdelaun.htm):\n\
+    Qu   - furthest-site Delaunay triangulation\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and in-circle test\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+output options (subset):\n\
+    s    - summary of results (default)\n\
+    i    - vertices incident to each Delaunay region\n\
+    Fx   - extreme points (vertices of the convex hull)\n\
+    o    - OFF format (shows the points lifted to a paraboloid)\n\
+    G    - Geomview output (2-d and 3-d points lifted to a paraboloid)\n\
+    m    - Mathematica output (2-d inputs lifted to a paraboloid)\n\
+    QVn  - print Delaunay regions that include point n, -n if not\n\
+    TO file- output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+    rbox c P0 D2 | qdelaunay s o          rbox c P0 D2 | qdelaunay i\n\
+    rbox c P0 D2 | qdelaunay Fv           rbox c P0 D2 | qdelaunay s Qu Fv\n\
+    rbox c G1 d D2 | qdelaunay s i        rbox c G1 d D2 | qdelaunay Qt\n\
+    rbox M3,4 z 100 D2 | qdelaunay s      rbox M3,4 z 100 D2 | qdelaunay s Qt\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull 
+*/  
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper-case options take an argument.\n\
+\n\
+ incidences     mathematica    OFF_format     points_lifted  summary\n\
+ facet_dump\n\
+\n\
+ Farea          FArea_total    Fcoincident    Fd_cdd_in      FD_cdd_out\n\
+ FF_dump_xridge FIDs           Fmerges        Fneighbors     FNeigh_vertex\n\
+ FOptions       FPoint_near    FQdelaun       Fsummary       FSize\n\
+ Fvertices      Fxtremes\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+ Gtransparent\n\
+\n\
+ PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
+ PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
+\n\
+ QGood_point    QJoggle        Qsearch_1st    Qtriangulate   QupperDelaunay\n\
+ QVertex_good   Qzinfinite\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Random_dist    Wide_outside\n\
+";
+
+/*---------------------------------
+  
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+  
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {      
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION,  
+		qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_option ("delaunay  Qbbound-last", NULL, NULL);
+    qh DELAUNAY= True;     /* 'd'   */
+    qh SCALElast= True;    /* 'Qbb' */
+    qh KEEPcoplanar= True; /* 'Qc', to keep coplanars in 'p' */
+    qh_checkflags (qh qhull_command, hidden_options);
+    qh_initflags (qh qhull_command);
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    if (dim >= 5) {
+      qh_option ("Qxact_merge", NULL, NULL);
+      qh MERGEexact= True; /* 'Qx' always */
+    }
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/qhalf.c b/extern/qhull/src/qhalf.c
new file mode 100644
index 00000000000..a2b3875dd7f
--- /dev/null
+++ b/extern/qhull/src/qhalf.c
@@ -0,0 +1,324 @@
+/*
  ---------------------------------
+
+   qhalf.c
+     compute the intersection of halfspaces about a point
+
+   see unix.c for full interface
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt 
+    long prompt for qhull
+    
+  notes:
+    restricted version of qhull.c
+ 
+  see:
+    concise prompt below
+*/  
+
+/* duplicated in qhalf.htm */
+char hidden_options[]=" d n v Qbb QbB Qf Qg Qm Qr QR Qv Qx Qz TR E V Fa FA FC FD FS Ft FV Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
+
+char qh_prompta[]= "\n\
+qhalf- compute the intersection of halfspaces about a point\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    optional interior point: dimension, 1, coordinates\n\
+    first lines: dimension+1 and number of halfspaces\n\
+    other lines: halfspace coefficients followed by offset\n\
+    comments:    start with a non-numeric character\n\
+\n\
+options:\n\
+    Hn,n - specify coordinates of interior point\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Qc   - keep coplanar halfspaces\n\
+    Qi   - keep other redundant halfspaces\n\
+\n\
+Qhull control options:\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qbk:0Bk:0 - remove k-th coordinate from input\n\
+    Qs   - search all halfspaces for the initial simplex\n\
+    QGn  - print intersection if visible to halfspace n, -n for not\n\
+    QVn  - print intersections for halfspace n, -n if not\n\
+\n\
+";
+char qh_promptc[]= "\
+Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - print statistics\n\
+    Tv   - verify result: structure, convexity, and redundancy\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when halfspace n added to intersection\n\
+    TMn  - turn on tracing at merge n\n\
+    TWn  - trace merge facets when width > n\n\
+    TVn  - stop qhull after adding halfspace n, -n for before (see TCn)\n\
+    TCn  - stop qhull after building cone for halfspace n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Un   - max distance below plane for a new, coplanar halfspace\n\
+    Wn   - min facet width for outside halfspace (before roundoff)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    f    - facet dump\n\
+    G    - Geomview output (dual convex hull)\n\
+    i    - non-redundant halfspaces incident to each intersection\n\
+    m    - Mathematica output (dual convex hull)\n\
+    o    - OFF format (dual convex hull: dimension, points, and facets)\n\
+    p    - vertex coordinates of dual convex hull (coplanars if 'Qc' or 'Qi')\n\
+    s    - summary (stderr)\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fc   - count plus redundant halfspaces for each intersection\n\
+         -   Qc (default) for coplanar and Qi for other redundant\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FF   - facet dump without ridges\n\
+    FI   - ID of each intersection\n\
+    Fm   - merge count for each intersection (511 max)\n\
+    Fn   - count plus neighboring intersections for each intersection\n\
+    FN   - count plus intersections for each non-redundant halfspace\n\
+    FO   - options and precision constants\n\
+    Fp   - dim, count, and intersection coordinates\n\
+    FP   - nearest halfspace and distance for each redundant halfspace\n\
+    FQ   - command used for qhalf\n\
+    Fs   - summary: #int (8), dim, #halfspaces, #non-redundant, #intersections\n\
+                      for output: #non-redundant, #intersections, #coplanar\n\
+                                  halfspaces, #non-simplicial intersections\n\
+                    #real (2), max outer plane, min vertex\n\
+    Fv   - count plus non-redundant halfspaces for each intersection\n\
+    Fx   - non-redundant halfspaces\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview output (2-d, 3-d and 4-d; dual convex hull)\n\
+    Ga   - all points (i.e., transformed halfspaces) as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices (i.e., non-redundant halfspaces) as spheres\n\
+    Gi   - inner planes (i.e., halfspace intersections) only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc	 - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest facets (i.e., intersections) by area\n\
+    Pdk:n- drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n- drop facet if normal[k] >= n\n\
+    Pg   - print good facets (needs 'QGn' or 'QVn')\n\
+    PFn  - keep facets whose area is at least n\n\
+    PG   - print neighbors of good facets\n\
+    PMn  - keep n facets with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull 
+*/  
+char qh_prompt2[]= "\n\
+qhalf- halfspace intersection about a point. Qhull %s\n\
+    input (stdin): [dim, 1, interior point], dim+1, n, coefficients+offset\n\
+    comments start with a non-numeric character\n\
+\n\
+options (qhalf.htm):\n\
+    Hn,n - specify coordinates of interior point\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and redundancy\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+output options (subset):\n\
+    s    - summary of results (default)\n\
+    Fp   - intersection coordinates\n\
+    Fv   - non-redundant halfspaces incident to each intersection\n\
+    Fx   - non-redundant halfspaces\n\
+    o    - OFF file format (dual convex hull)\n\
+    G    - Geomview output (dual convex hull)\n\
+    m    - Mathematica output (dual convex hull)\n\
+    QVn  - print intersections for halfspace n, -n if not\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+    rbox d | qconvex FQ n | qhalf s H0,0,0 Fp\n\
+    rbox c | qconvex FQ FV n | qhalf s i\n\
+    rbox c | qconvex FQ FV n | qhalf s o\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull 
+*/  
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper_case options take an argument.\n\
+\n\
+ incidences     Geomview       mathematica    OFF_format     point_dual\n\
+ summary        facet_dump\n\
+\n\
+ Fc_redundant   Fd_cdd_in      FF_dump_xridge FIDs           Fmerges\n\
+ Fneighbors     FN_intersect   FOptions       Fp_coordinates FP_nearest\n\
+ FQhalf         Fsummary       Fv_halfspace   Fx_non_redundant\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+\n\
+ PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
+ PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
+\n\
+ Qbk:0Bk:0_drop Qcoplanar      QG_half_good   Qi_redundant   QJoggle\n\
+ Qsearch_1st    Qtriangulate   QVertex_good\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Random_dist    Ucoplanar_max  Wide_outside\n\
+";
+
+/*---------------------------------
+  
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+  
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {      
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION, 
+        qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_option ("Halfspace", NULL, NULL);
+    qh HALFspace= True;    /* 'H'   */
+    qh_checkflags (qh qhull_command, hidden_options);
+    qh_initflags (qh qhull_command);
+    if (qh SCALEinput) {
+      fprintf(qh ferr, "\
+qhull error: options 'Qbk:n' and 'QBk:n' are not used with qhalf.\n\
+             Use 'Qbk:0Bk:0 to drop dimension k.\n");
+      qh_errexit(qh_ERRinput, NULL, NULL);
+    }
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    if (dim >= 5) {
+      qh_option ("Qxact_merge", NULL, NULL);
+      qh MERGEexact= True; /* 'Qx' always */
+    }
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/qhull.c b/extern/qhull/src/qhull.c
new file mode 100644
index 00000000000..dc835bb4f28
--- /dev/null
+++ b/extern/qhull/src/qhull.c
@@ -0,0 +1,1395 @@
+/*
  ---------------------------------
+
+   qhull.c
+   Quickhull algorithm for convex hulls
+
+   qhull() and top-level routines
+
+   see qh-qhull.htm, qhull.h, unix.c
+
+   see qhull_a.h for internal functions
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#include "qhull_a.h" 
+
+/*============= functions in alphabetic order after qhull() =======*/
+
+/*---------------------------------
+  
+  qh_qhull()
+    compute DIM3 convex hull of qh.num_points starting at qh.first_point
+    qh contains all global options and variables
+
+  returns:
+    returns polyhedron
+      qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,
+    
+    returns global variables
+      qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex
+    
+    returns precision constants
+      qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge
+
+  notes:
+    unless needed for output
+      qh.max_vertex and qh.min_vertex are max/min due to merges
+      
+  see:
+    to add individual points to either qh.num_points
+      use qh_addpoint()
+      
+    if qh.GETarea
+      qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()
+
+  design:
+    record starting time
+    initialize hull and partition points
+    build convex hull
+    unless early termination
+      update facet->maxoutside for vertices, coplanar, and near-inside points
+    error if temporary sets exist
+    record end time
+*/
+void qh_qhull (void) {
+  int numoutside;
+
+  qh hulltime= qh_CPUclock;
+  if (qh RERUN || qh JOGGLEmax < REALmax/2) 
+    qh_build_withrestart();
+  else {
+    qh_initbuild();
+    qh_buildhull();
+  }
+  if (!qh STOPpoint && !qh STOPcone) {
+    if (qh ZEROall_ok && !qh TESTvneighbors && qh MERGEexact)
+      qh_checkzero( qh_ALL);
+    if (qh ZEROall_ok && !qh TESTvneighbors && !qh WAScoplanar) {
+      trace2((qh ferr, "qh_qhull: all facets are clearly convex and no coplanar points.  Post-merging and check of maxout not needed.\n"));
+      qh DOcheckmax= False;
+    }else {
+      if (qh MERGEexact || (qh hull_dim > qh_DIMreduceBuild && qh PREmerge))
+        qh_postmerge ("First post-merge", qh premerge_centrum, qh premerge_cos, 
+             (qh POSTmerge ? False : qh TESTvneighbors));
+      else if (!qh POSTmerge && qh TESTvneighbors) 
+        qh_postmerge ("For testing vertex neighbors", qh premerge_centrum,
+             qh premerge_cos, True); 
+      if (qh POSTmerge)
+        qh_postmerge ("For post-merging", qh postmerge_centrum, 
+             qh postmerge_cos, qh TESTvneighbors);
+      if (qh visible_list == qh facet_list) { /* i.e., merging done */
+        qh findbestnew= True;
+        qh_partitionvisible (/*visible_list, newfacet_list*/ !qh_ALL, &numoutside);
+        qh findbestnew= False;
+        qh_deletevisible (/*qh visible_list*/);
+        qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+      }
+    }
+    if (qh DOcheckmax){
+      if (qh REPORTfreq) {
+	qh_buildtracing (NULL, NULL); 
+	fprintf (qh ferr, "\nTesting all coplanar points.\n");
+      }
+      qh_check_maxout();
+    }
+    if (qh KEEPnearinside && !qh maxoutdone)  
+      qh_nearcoplanar();
+  }
+  if (qh_setsize ((setT*)qhmem.tempstack) != 0) {
+    fprintf (qh ferr, "qhull internal error (qh_qhull): temporary sets not empty (%d)\n",
+	     qh_setsize ((setT*)qhmem.tempstack));
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  qh hulltime= qh_CPUclock - qh hulltime;
+  qh QHULLfinished= True;
+  trace1((qh ferr, "qh_qhull: algorithm completed\n"));
+} /* qhull */
+
+/*---------------------------------
+  
+  qh_addpoint( furthest, facet, checkdist )
+    add point (usually furthest point) above facet to hull 
+    if checkdist, 
+      check that point is above facet.
+      if point is not outside of the hull, uses qh_partitioncoplanar()
+      assumes that facet is defined by qh_findbestfacet()
+    else if facet specified,
+      assumes that point is above facet (major damage if below)
+    for Delaunay triangulations, 
+      Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
+      Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. 
+
+  returns:
+    returns False if user requested an early termination
+     qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
+    updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
+    clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
+    if unknown point, adds a pointer to qh.other_points
+      do not deallocate the point's coordinates
+  
+  notes:
+    assumes point is near its best facet and not at a local minimum of a lens
+      distributions.  Use qh_findbestfacet to avoid this case.
+    uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets
+
+  see also:
+    qh_triangulate() -- triangulate non-simplicial facets
+
+  design:
+    check point in qh.first_point/.num_points
+    if checkdist
+      if point not above facet
+        partition coplanar point 
+        exit
+    exit if pre STOPpoint requested
+    find horizon and visible facets for point
+    make new facets for point to horizon
+    make hyperplanes for point
+    compute balance statistics
+    match neighboring new facets
+    update vertex neighbors and delete interior vertices
+    exit if STOPcone requested
+    merge non-convex new facets
+    if merge found, many merges, or 'Qf'
+       use qh_findbestnew() instead of qh_findbest()
+    partition outside points from visible facets
+    delete visible facets
+    check polyhedron if requested
+    exit if post STOPpoint requested
+    reset working lists of facets and vertices
+*/
+boolT qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist) {
+  int goodvisible, goodhorizon;
+  vertexT *vertex;
+  facetT *newfacet;
+  realT dist, newbalance, pbalance;
+  boolT isoutside= False;
+  int numpart, numpoints, numnew, firstnew;
+
+  qh maxoutdone= False;
+  if (qh_pointid (furthest) == -1)
+    qh_setappend (&qh other_points, furthest);
+  if (!facet) {
+    fprintf (qh ferr, "qh_addpoint: NULL facet.  Need to call qh_findbestfacet first\n");
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  if (checkdist) {
+    facet= qh_findbest (furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,
+			&dist, &isoutside, &numpart);
+    zzadd_(Zpartition, numpart);
+    if (!isoutside) {
+      zinc_(Znotmax);  /* last point of outsideset is no longer furthest. */
+      facet->notfurthest= True;
+      qh_partitioncoplanar (furthest, facet, &dist);
+      return True;
+    }
+  }
+  qh_buildtracing (furthest, facet);
+  if (qh STOPpoint < 0 && qh furthest_id == -qh STOPpoint-1) {
+    facet->notfurthest= True;
+    return False;
+  }
+  qh_findhorizon (furthest, facet, &goodvisible, &goodhorizon); 
+  if (qh ONLYgood && !(goodvisible+goodhorizon) && !qh GOODclosest) {
+    zinc_(Znotgood);  
+    facet->notfurthest= True;
+    /* last point of outsideset is no longer furthest.  This is ok
+       since all points of the outside are likely to be bad */
+    qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+    return True;
+  }
+  zzinc_(Zprocessed);
+  firstnew= qh facet_id;
+  vertex= qh_makenewfacets (furthest /*visible_list, attaches if !ONLYgood */);
+  qh_makenewplanes (/* newfacet_list */);
+  numnew= qh facet_id - firstnew;
+  newbalance= numnew - (realT) (qh num_facets-qh num_visible)
+                         * qh hull_dim/qh num_vertices;
+  wadd_(Wnewbalance, newbalance);
+  wadd_(Wnewbalance2, newbalance * newbalance);
+  if (qh ONLYgood 
+  && !qh_findgood (qh newfacet_list, goodhorizon) && !qh GOODclosest) {
+    FORALLnew_facets 
+      qh_delfacet (newfacet);
+    qh_delvertex (vertex);
+    qh_resetlists (True, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+    zinc_(Znotgoodnew);
+    facet->notfurthest= True;
+    return True;
+  }
+  if (qh ONLYgood)
+    qh_attachnewfacets(/*visible_list*/);
+  qh_matchnewfacets();
+  qh_updatevertices();
+  if (qh STOPcone && qh furthest_id == qh STOPcone-1) {
+    facet->notfurthest= True;
+    return False;  /* visible_list etc. still defined */
+  }
+  qh findbestnew= False;
+  if (qh PREmerge || qh MERGEexact) {
+    qh_premerge (vertex, qh premerge_centrum, qh premerge_cos);
+    if (qh_USEfindbestnew)
+      qh findbestnew= True;
+    else {
+      FORALLnew_facets {
+	if (!newfacet->simplicial) {
+	  qh findbestnew= True;  /* use qh_findbestnew instead of qh_findbest*/
+	  break;
+	}
+      }
+    }
+  }else if (qh BESToutside)
+    qh findbestnew= True;
+  qh_partitionvisible (/*visible_list, newfacet_list*/ !qh_ALL, &numpoints);
+  qh findbestnew= False;
+  qh findbest_notsharp= False;
+  zinc_(Zpbalance);
+  pbalance= numpoints - (realT) qh hull_dim /* assumes all points extreme */
+                * (qh num_points - qh num_vertices)/qh num_vertices;
+  wadd_(Wpbalance, pbalance);
+  wadd_(Wpbalance2, pbalance * pbalance);
+  qh_deletevisible (/*qh visible_list*/);
+  zmax_(Zmaxvertex, qh num_vertices);
+  qh NEWfacets= False;
+  if (qh IStracing >= 4) {
+    if (qh num_facets < 2000)
+      qh_printlists();
+    qh_printfacetlist (qh newfacet_list, NULL, True);
+    qh_checkpolygon (qh facet_list);
+  }else if (qh CHECKfrequently) {
+    if (qh num_facets < 50)
+      qh_checkpolygon (qh facet_list);
+    else
+      qh_checkpolygon (qh newfacet_list);
+  }
+  if (qh STOPpoint > 0 && qh furthest_id == qh STOPpoint-1) 
+    return False; 
+  qh_resetlists (True, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
+  /* qh_triangulate(); to test qh.TRInormals */
+  trace2((qh ferr, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n",
+    qh_pointid (furthest), numnew, newbalance, pbalance));
+  return True;
+} /* addpoint */
+
+/*---------------------------------
+  
+  qh_build_withrestart()
+    allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
+    qh.FIRSTpoint/qh.NUMpoints is point array
+        it may be moved by qh_joggleinput()
+*/
+void qh_build_withrestart (void) {
+  int restart;
+
+  qh ALLOWrestart= True;
+  while (True) {
+    restart= setjmp (qh restartexit); /* simple statement for CRAY J916 */
+    if (restart) {       /* only from qh_precision() */
+      zzinc_(Zretry);
+      wmax_(Wretrymax, qh JOGGLEmax);
+      qh ERREXITcalled= False;
+      qh STOPcone= True; /* if break, prevents normal output */
+    }
+    if (!qh RERUN && qh JOGGLEmax < REALmax/2) {
+      if (qh build_cnt > qh_JOGGLEmaxretry) {
+	fprintf(qh ferr, "\n\
+qhull precision error: %d attempts to construct a convex hull\n\
+        with joggled input.  Increase joggle above 'QJ%2.2g'\n\
+	or modify qh_JOGGLE... parameters in user.h\n",
+	   qh build_cnt, qh JOGGLEmax);
+	qh_errexit (qh_ERRqhull, NULL, NULL);
+      }
+      if (qh build_cnt && !restart)
+	break;
+    }else if (qh build_cnt && qh build_cnt >= qh RERUN)
+      break;
+    qh STOPcone= False;
+    qh_freebuild (True);  /* first call is a nop */
+    qh build_cnt++;
+    if (!qh qhull_optionsiz)
+      qh qhull_optionsiz= strlen (qh qhull_options);
+    else { 
+      qh qhull_options [qh qhull_optionsiz]= '\0';
+      qh qhull_optionlen= 80;
+    }
+    qh_option("_run", &qh build_cnt, NULL);
+    if (qh build_cnt == qh RERUN) {
+      qh IStracing= qh TRACElastrun;  /* duplicated from qh_initqhull_globals */
+      if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
+        qh TRACElevel= (qh IStracing? qh IStracing : 3);
+        qh IStracing= 0;
+      }
+      qhmem.IStracing= qh IStracing;
+    }
+    if (qh JOGGLEmax < REALmax/2)
+      qh_joggleinput();
+    qh_initbuild();
+    qh_buildhull();
+    if (qh JOGGLEmax < REALmax/2 && !qh MERGING)
+      qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
+  }
+  qh ALLOWrestart= False;
+} /* qh_build_withrestart */
+
+/*---------------------------------
+  
+  qh_buildhull()
+    construct a convex hull by adding outside points one at a time
+
+  returns:
+  
+  notes:
+    may be called multiple times
+    checks facet and vertex lists for incorrect flags
+    to recover from STOPcone, call qh_deletevisible and qh_resetlists
+
+  design:
+    check visible facet and newfacet flags
+    check newlist vertex flags and qh.STOPcone/STOPpoint
+    for each facet with a furthest outside point
+      add point to facet
+      exit if qh.STOPcone or qh.STOPpoint requested
+    if qh.NARROWhull for initial simplex
+      partition remaining outside points to coplanar sets
+*/
+void qh_buildhull(void) {
+  facetT *facet;
+  pointT *furthest;
+  vertexT *vertex;
+  int id;
+  
+  trace1((qh ferr, "qh_buildhull: start build hull\n"));
+  FORALLfacets {
+    if (facet->visible || facet->newfacet) {
+      fprintf (qh ferr, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
+                   facet->id);    
+      qh_errexit (qh_ERRqhull, facet, NULL);
+    }
+  }
+  FORALLvertices {
+    if (vertex->newlist) {
+      fprintf (qh ferr, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
+                   vertex->id);
+      qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }
+    id= qh_pointid (vertex->point);
+    if ((qh STOPpoint>0 && id == qh STOPpoint-1) ||
+	(qh STOPpoint<0 && id == -qh STOPpoint-1) ||
+	(qh STOPcone>0 && id == qh STOPcone-1)) {
+      trace1((qh ferr,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
+      return;
+    }
+  }
+  qh facet_next= qh facet_list;      /* advance facet when processed */
+  while ((furthest= qh_nextfurthest (&facet))) {
+    qh num_outside--;  /* if ONLYmax, furthest may not be outside */
+    if (!qh_addpoint (furthest, facet, qh ONLYmax))
+      break;
+  }
+  if (qh NARROWhull) /* move points from outsideset to coplanarset */
+    qh_outcoplanar( /* facet_list */ );
+  if (qh num_outside && !furthest) {
+    fprintf (qh ferr, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh num_outside);
+    qh_errexit (qh_ERRqhull, NULL, NULL);
+  }
+  trace1((qh ferr, "qh_buildhull: completed the hull construction\n"));
+} /* buildhull */
+  
+
+/*---------------------------------
+  
+  qh_buildtracing( furthest, facet )
+    trace an iteration of qh_buildhull() for furthest point and facet
+    if !furthest, prints progress message
+
+  returns:
+    tracks progress with qh.lastreport
+    updates qh.furthest_id (-3 if furthest is NULL)
+    also resets visit_id, vertext_visit on wrap around
+
+  see:
+    qh_tracemerging()
+
+  design:
+    if !furthest
+      print progress message
+      exit
+    if 'TFn' iteration
+      print progress message
+    else if tracing
+      trace furthest point and facet
+    reset qh.visit_id and qh.vertex_visit if overflow may occur
+    set qh.furthest_id for tracing
+*/
+void qh_buildtracing (pointT *furthest, facetT *facet) {
+  realT dist= 0;
+  float cpu;
+  int total, furthestid;
+  time_t timedata;
+  struct tm *tp;
+  vertexT *vertex;
+
+  qh old_randomdist= qh RANDOMdist;
+  qh RANDOMdist= False;
+  if (!furthest) {
+    time (&timedata);
+    tp= localtime (&timedata);
+    cpu= qh_CPUclock - qh hulltime;
+    cpu /= qh_SECticks;
+    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+    fprintf (qh ferr, "\n\
+At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
+ The current hull contains %d facets and %d vertices.  Last point was p%d\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
+      total, qh num_facets, qh num_vertices, qh furthest_id);
+    return;
+  }
+  furthestid= qh_pointid (furthest);
+  if (qh TRACEpoint == furthestid) {
+    qh IStracing= qh TRACElevel;
+    qhmem.IStracing= qh TRACElevel;
+  }else if (qh TRACEpoint != -1 && qh TRACEdist < REALmax/2) {
+    qh IStracing= 0;
+    qhmem.IStracing= 0;
+  }
+  if (qh REPORTfreq && (qh facet_id-1 > qh lastreport+qh REPORTfreq)) {
+    qh lastreport= qh facet_id-1;
+    time (&timedata);
+    tp= localtime (&timedata);
+    cpu= qh_CPUclock - qh hulltime;
+    cpu /= qh_SECticks;
+    total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+    zinc_(Zdistio);
+    qh_distplane (furthest, facet, &dist);
+    fprintf (qh ferr, "\n\
+At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
+ The current hull contains %d facets and %d vertices.  There are %d\n\
+ outside points.  Next is point p%d (v%d), %2.2g above f%d.\n",
+      tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
+      total, qh num_facets, qh num_vertices, qh num_outside+1,
+      furthestid, qh vertex_id, dist, getid_(facet));
+  }else if (qh IStracing >=1) {
+    cpu= qh_CPUclock - qh hulltime;
+    cpu /= qh_SECticks;
+    qh_distplane (furthest, facet, &dist);
+    fprintf (qh ferr, "qh_addpoint: add p%d (v%d) to hull of %d facets (%2.2g above f%d) and %d outside at %4.4g CPU secs.  Previous was p%d.\n",
+      furthestid, qh vertex_id, qh num_facets, dist,
+      getid_(facet), qh num_outside+1, cpu, qh furthest_id);
+  }
+  if (qh visit_id > (unsigned) INT_MAX) {
+    qh visit_id= 0;
+    FORALLfacets
+      facet->visitid= qh visit_id;
+  }
+  if (qh vertex_visit > (unsigned) INT_MAX) {
+    qh vertex_visit= 0;
+    FORALLvertices
+      vertex->visitid= qh vertex_visit;
+  }
+  qh furthest_id= furthestid;
+  qh RANDOMdist= qh old_randomdist;
+} /* buildtracing */
+
+/*---------------------------------
+  
+  qh_errexit2( exitcode, facet, otherfacet )
+    return exitcode to system after an error
+    report two facets
+
+  returns:
+    assumes exitcode non-zero
+
+  see:
+    normally use qh_errexit() in user.c (reports a facet and a ridge)
+*/
+void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet) {
+  
+  qh_errprint("ERRONEOUS", facet, otherfacet, NULL, NULL);
+  qh_errexit (exitcode, NULL, NULL);
+} /* errexit2 */
+
+
+/*---------------------------------
+  
+  qh_findhorizon( point, facet, goodvisible, goodhorizon )
+    given a visible facet, find the point's horizon and visible facets
+    for all facets, !facet-visible
+
+  returns:
+    returns qh.visible_list/num_visible with all visible facets 
+      marks visible facets with ->visible 
+    updates count of good visible and good horizon facets
+    updates qh.max_outside, qh.max_vertex, facet->maxoutside
+
+  see:
+    similar to qh_delpoint()
+
+  design:
+    move facet to qh.visible_list at end of qh.facet_list
+    for all visible facets
+     for each unvisited neighbor of a visible facet
+       compute distance of point to neighbor
+       if point above neighbor
+         move neighbor to end of qh.visible_list
+       else if point is coplanar with neighbor
+         update qh.max_outside, qh.max_vertex, neighbor->maxoutside
+         mark neighbor coplanar (will create a samecycle later)
+         update horizon statistics         
+*/
+void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
+  facetT *neighbor, **neighborp, *visible;
+  int numhorizon= 0, coplanar= 0;
+  realT dist;
+  
+  trace1((qh ferr,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(point),facet->id));
+  *goodvisible= *goodhorizon= 0;
+  zinc_(Ztotvisible);
+  qh_removefacet(facet);  /* visible_list at end of qh facet_list */
+  qh_appendfacet(facet);
+  qh num_visible= 1;
+  if (facet->good)
+    (*goodvisible)++;
+  qh visible_list= facet;
+  facet->visible= True;
+  facet->f.replace= NULL;
+  if (qh IStracing >=4)
+    qh_errprint ("visible", facet, NULL, NULL, NULL);
+  qh visit_id++;
+  FORALLvisible_facets {
+    if (visible->tricoplanar && !qh TRInormals) {
+      fprintf (qh ferr, "qh_findhorizon: does not work for tricoplanar facets.  Use option 'Q11'\n");
+      qh_errexit (qh_ERRqhull, visible, NULL);
+    }
+    visible->visitid= qh visit_id;
+    FOREACHneighbor_(visible) {
+      if (neighbor->visitid == qh visit_id) 
+        continue;
+      neighbor->visitid= qh visit_id;
+      zzinc_(Znumvisibility);
+      qh_distplane(point, neighbor, &dist);
+      if (dist > qh MINvisible) {
+        zinc_(Ztotvisible);
+	qh_removefacet(neighbor);  /* append to end of qh visible_list */
+	qh_appendfacet(neighbor);
+	neighbor->visible= True;
+        neighbor->f.replace= NULL;
+	qh num_visible++;
+	if (neighbor->good)
+	  (*goodvisible)++;
+        if (qh IStracing >=4)
+          qh_errprint ("visible", neighbor, NULL, NULL, NULL);
+      }else {
+ 	if (dist > - qh MAXcoplanar) {
+    	  neighbor->coplanar= True;
+          zzinc_(Zcoplanarhorizon);
+          qh_precision ("coplanar horizon");
+	  coplanar++;
+	  if (qh MERGING) {
+	    if (dist > 0) {
+	      maximize_(qh max_outside, dist);
+	      maximize_(qh max_vertex, dist);
+#if qh_MAXoutside
+	      maximize_(neighbor->maxoutside, dist);
+#endif
+	    }else
+	      minimize_(qh min_vertex, dist);  /* due to merge later */
+	  }
+      	  trace2((qh ferr, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh MINvisible (%2.7g)\n",
+	      qh_pointid(point), neighbor->id, dist, qh MINvisible));
+	}else
+    	  neighbor->coplanar= False;
+    	zinc_(Ztothorizon);
+        numhorizon++;
+	if (neighbor->good)
+	  (*goodhorizon)++;
+        if (qh IStracing >=4)
+          qh_errprint ("horizon", neighbor, NULL, NULL, NULL);
+      }
+    }
+  }
+  if (!numhorizon) {
+    qh_precision ("empty horizon");
+    fprintf(qh ferr, "qhull precision error (qh_findhorizon): empty horizon\n\
+Point p%d was above all facets.\n", qh_pointid(point));
+    qh_printfacetlist (qh facet_list, NULL, True);
+    qh_errexit(qh_ERRprec, NULL, NULL);
+  }
+  trace1((qh ferr, "qh_findhorizon: %d horizon facets (good %d), %d visible (good %d), %d coplanar\n", 
+       numhorizon, *goodhorizon, qh num_visible, *goodvisible, coplanar));
+  if (qh IStracing >= 4 && qh num_facets < 50) 
+    qh_printlists ();
+} /* findhorizon */
+
+/*---------------------------------
+  
+  qh_nextfurthest( visible )
+    returns next furthest point and visible facet for qh_addpoint()
+    starts search at qh.facet_next
+
+  returns:
+    removes furthest point from outside set
+    NULL if none available
+    advances qh.facet_next over facets with empty outside sets  
+
+  design:
+    for each facet from qh.facet_next
+      if empty outside set
+        advance qh.facet_next
+      else if qh.NARROWhull
+        determine furthest outside point
+        if furthest point is not outside
+          advance qh.facet_next (point will be coplanar)
+    remove furthest point from outside set
+*/
+pointT *qh_nextfurthest (facetT **visible) {
+  facetT *facet;
+  int size, index;
+  realT randr, dist;
+  pointT *furthest;
+
+  while ((facet= qh facet_next) != qh facet_tail) {
+    if (!facet->outsideset) {
+      qh facet_next= facet->next;
+      continue;
+    }
+    SETreturnsize_(facet->outsideset, size);
+    if (!size) {
+      qh_setfree (&facet->outsideset);
+      qh facet_next= facet->next;
+      continue;
+    }
+    if (qh NARROWhull) {
+      if (facet->notfurthest) 
+	qh_furthestout (facet);
+      furthest= (pointT*)qh_setlast (facet->outsideset);
+#if qh_COMPUTEfurthest
+      qh_distplane (furthest, facet, &dist);
+      zinc_(Zcomputefurthest);
+#else
+      dist= facet->furthestdist;
+#endif
+      if (dist < qh MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */
+	qh facet_next= facet->next;
+	continue;
+      }
+    }
+    if (!qh RANDOMoutside && !qh VIRTUALmemory) {
+      if (qh PICKfurthest) {
+	qh_furthestnext (/* qh facet_list */);
+	facet= qh facet_next;
+      }
+      *visible= facet;
+      return ((pointT*)qh_setdellast (facet->outsideset));
+    }
+    if (qh RANDOMoutside) {
+      int outcoplanar = 0;
+      if (qh NARROWhull) {
+        FORALLfacets {
+	  if (facet == qh facet_next)
+	    break;
+	  if (facet->outsideset)
+  	    outcoplanar += qh_setsize( facet->outsideset);
+	}
+      }
+      randr= qh_RANDOMint;
+      randr= randr/(qh_RANDOMmax+1);
+      index= (int)floor((qh num_outside - outcoplanar) * randr);
+      FORALLfacet_(qh facet_next) {
+        if (facet->outsideset) {
+          SETreturnsize_(facet->outsideset, size);
+          if (!size)
+            qh_setfree (&facet->outsideset);
+          else if (size > index) {
+            *visible= facet;
+            return ((pointT*)qh_setdelnth (facet->outsideset, index));
+          }else
+            index -= size;
+        }
+      }
+      fprintf (qh ferr, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",
+              qh num_outside, index+1, randr);
+      qh_errexit (qh_ERRqhull, NULL, NULL);
+    }else { /* VIRTUALmemory */
+      facet= qh facet_tail->previous;
+      if (!(furthest= (pointT*)qh_setdellast(facet->outsideset))) {
+        if (facet->outsideset)
+          qh_setfree (&facet->outsideset);
+        qh_removefacet (facet);
+        qh_prependfacet (facet, &qh facet_list);
+        continue;
+      }
+      *visible= facet;
+      return furthest;
+    }
+  }
+  return NULL;
+} /* nextfurthest */
+
+/*---------------------------------
+  
+  qh_partitionall( vertices, points, numpoints )
+    partitions all points in points/numpoints to the outsidesets of facets
+    vertices= vertices in qh.facet_list (not partitioned)
+
+  returns:
+    builds facet->outsideset
+    does not partition qh.GOODpoint
+    if qh.ONLYgood && !qh.MERGING, 
+      does not partition qh.GOODvertex
+
+  notes:
+    faster if qh.facet_list sorted by anticipated size of outside set
+
+  design:
+    initialize pointset with all points
+    remove vertices from pointset
+    remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
+    for all facets
+      for all remaining points in pointset
+        compute distance from point to facet
+        if point is outside facet
+          remove point from pointset (by not reappending)
+          update bestpoint
+          append point or old bestpoint to facet's outside set
+      append bestpoint to facet's outside set (furthest)
+    for all points remaining in pointset
+      partition point into facets' outside sets and coplanar sets
+*/
+void qh_partitionall(setT *vertices, pointT *points, int numpoints){
+  setT *pointset;
+  vertexT *vertex, **vertexp;
+  pointT *point, **pointp, *bestpoint;
+  int size, point_i, point_n, point_end, remaining, i, id;
+  facetT *facet;
+  realT bestdist= -REALmax, dist, distoutside;
+    
+  trace1((qh ferr, "qh_partitionall: partition all points into outside sets\n"));
+  pointset= qh_settemp (numpoints);
+  qh num_outside= 0;
+  pointp= SETaddr_(pointset, pointT);
+  for (i=numpoints, point= points; i--; point += qh hull_dim)
+    *(pointp++)= point;
+  qh_settruncate (pointset, numpoints);
+  FOREACHvertex_(vertices) {
+    if ((id= qh_pointid(vertex->point)) >= 0)
+      SETelem_(pointset, id)= NULL;
+  }
+  id= qh_pointid (qh GOODpointp);
+  if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
+    SETelem_(pointset, id)= NULL;
+  if (qh GOODvertexp && qh ONLYgood && !qh MERGING) { /* matches qhull()*/
+    if ((id= qh_pointid(qh GOODvertexp)) >= 0)
+      SETelem_(pointset, id)= NULL;
+  }
+  if (!qh BESToutside) {  /* matches conditional for qh_partitionpoint below */
+    distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
+    zval_(Ztotpartition)= qh num_points - qh hull_dim - 1; /*misses GOOD... */
+    remaining= qh num_facets;
+    point_end= numpoints;
+    FORALLfacets {
+      size= point_end/(remaining--) + 100;
+      facet->outsideset= qh_setnew (size);
+      bestpoint= NULL;
+      point_end= 0;
+      FOREACHpoint_i_(pointset) {
+        if (point) {
+          zzinc_(Zpartitionall);
+          qh_distplane (point, facet, &dist);
+          if (dist < distoutside)
+            SETelem_(pointset, point_end++)= point;
+          else {
+	    qh num_outside++;
+            if (!bestpoint) {
+              bestpoint= point;
+              bestdist= dist;
+            }else if (dist > bestdist) {
+              qh_setappend (&facet->outsideset, bestpoint);
+              bestpoint= point;
+              bestdist= dist;
+            }else 
+              qh_setappend (&facet->outsideset, point);
+          }
+        }
+      }
+      if (bestpoint) {
+        qh_setappend (&facet->outsideset, bestpoint);
+#if !qh_COMPUTEfurthest
+	facet->furthestdist= bestdist;
+#endif
+      }else
+        qh_setfree (&facet->outsideset);
+      qh_settruncate (pointset, point_end);
+    }
+  }
+  /* if !qh BESToutside, pointset contains points not assigned to outsideset */
+  if (qh BESToutside || qh MERGING || qh KEEPcoplanar || qh KEEPinside) {
+    qh findbestnew= True;
+    FOREACHpoint_i_(pointset) { 
+      if (point)
+        qh_partitionpoint(point, qh facet_list);
+    }
+    qh findbestnew= False;
+  }
+  zzadd_(Zpartitionall, zzval_(Zpartition));
+  zzval_(Zpartition)= 0;
+  qh_settempfree(&pointset);
+  if (qh IStracing >= 4)
+    qh_printfacetlist (qh facet_list, NULL, True);
+} /* partitionall */
+
+
+/*---------------------------------
+  
+  qh_partitioncoplanar( point, facet, dist )
+    partition coplanar point to a facet
+    dist is distance from point to facet
+    if dist NULL, 
+      searches for bestfacet and does nothing if inside
+    if qh.findbestnew set, 
+      searches new facets instead of using qh_findbest()
+
+  returns:
+    qh.max_ouside updated
+    if qh.KEEPcoplanar or qh.KEEPinside
+      point assigned to best coplanarset
+  
+  notes:
+    facet->maxoutside is updated at end by qh_check_maxout
+
+  design:
+    if dist undefined
+      find best facet for point
+      if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)
+        exit
+    if keeping coplanar/nearinside/inside points
+      if point is above furthest coplanar point
+        append point to coplanar set (it is the new furthest)
+        update qh.max_outside
+      else
+        append point one before end of coplanar set
+    else if point is clearly outside of qh.max_outside and bestfacet->coplanarset
+    and bestfacet is more than perpendicular to facet
+      repartition the point using qh_findbest() -- it may be put on an outsideset
+    else
+      update qh.max_outside
+*/
+void qh_partitioncoplanar (pointT *point, facetT *facet, realT *dist) {
+  facetT *bestfacet;
+  pointT *oldfurthest;
+  realT bestdist, dist2, angle;
+  int numpart= 0, oldfindbest;
+  boolT isoutside;
+
+  qh WAScoplanar= True;
+  if (!dist) {
+    if (qh findbestnew)
+      bestfacet= qh_findbestnew (point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
+    else
+      bestfacet= qh_findbest (point, facet, qh_ALL, !qh_ISnewfacets, qh DELAUNAY, 
+                          &bestdist, &isoutside, &numpart);
+    zinc_(Ztotpartcoplanar);
+    zzadd_(Zpartcoplanar, numpart);
+    if (!qh DELAUNAY && !qh KEEPinside) { /*  for 'd', bestdist skips upperDelaunay facets */
+      if (qh KEEPnearinside) {
+        if (bestdist < -qh NEARinside) { 
+          zinc_(Zcoplanarinside);
+	  trace4((qh ferr, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g findbestnew %d\n",
+		  qh_pointid(point), bestfacet->id, bestdist, qh findbestnew));
+          return;
+        }
+      }else if (bestdist < -qh MAXcoplanar) {
+	  trace4((qh ferr, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g findbestnew %d\n",
+		  qh_pointid(point), bestfacet->id, bestdist, qh findbestnew));
+        zinc_(Zcoplanarinside);
+        return;
+      }
+    }
+  }else {
+    bestfacet= facet;
+    bestdist= *dist;
+  }
+  if (bestdist > qh max_outside) {
+    if (!dist && facet != bestfacet) { 
+      zinc_(Zpartangle);
+      angle= qh_getangle(facet->normal, bestfacet->normal);
+      if (angle < 0) {
+	/* typically due to deleted vertex and coplanar facets, e.g.,
+	     RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
+	zinc_(Zpartflip);
+	trace2((qh ferr, "qh_partitioncoplanar: repartition point p%d from f%d.  It is above flipped facet f%d dist %2.2g\n",
+		qh_pointid(point), facet->id, bestfacet->id, bestdist));
+	oldfindbest= qh findbestnew;
+        qh findbestnew= False;
+	qh_partitionpoint(point, bestfacet);
+        qh findbestnew= oldfindbest;
+	return;
+      }
+    }
+    qh max_outside= bestdist;
+    if (bestdist > qh TRACEdist) {
+      fprintf (qh ferr, "qh_partitioncoplanar: ====== p%d from f%d increases max_outside to %2.2g of f%d last p%d\n",
+		     qh_pointid(point), facet->id, bestdist, bestfacet->id, qh furthest_id);
+      qh_errprint ("DISTANT", facet, bestfacet, NULL, NULL);
+    }
+  }
+  if (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside) {
+    oldfurthest= (pointT*)qh_setlast (bestfacet->coplanarset);
+    if (oldfurthest) {
+      zinc_(Zcomputefurthest);
+      qh_distplane (oldfurthest, bestfacet, &dist2);
+    }
+    if (!oldfurthest || dist2 < bestdist) 
+      qh_setappend(&bestfacet->coplanarset, point);
+    else 
+      qh_setappend2ndlast(&bestfacet->coplanarset, point);
+  }
+  trace4((qh ferr, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n",
+	  qh_pointid(point), bestfacet->id, bestdist));
+} /* partitioncoplanar */
+
+/*---------------------------------
+  
+  qh_partitionpoint( point, facet )
+    assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
+    if qh.findbestnew
+      uses qh_findbestnew() to search all new facets
+    else
+      uses qh_findbest()
+  
+  notes:
+    after qh_distplane(), this and qh_findbest() are most expensive in 3-d
+
+  design:
+    find best facet for point 
+      (either exhaustive search of new facets or directed search from facet)
+    if qh.NARROWhull
+      retain coplanar and nearinside points as outside points
+    if point is outside bestfacet
+      if point above furthest point for bestfacet
+        append point to outside set (it becomes the new furthest)
+        if outside set was empty
+          move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
+        update bestfacet->furthestdist
+      else
+        append point one before end of outside set
+    else if point is coplanar to bestfacet
+      if keeping coplanar points or need to update qh.max_outside
+        partition coplanar point into bestfacet
+    else if near-inside point        
+      partition as coplanar point into bestfacet
+    else is an inside point
+      if keeping inside points 
+        partition as coplanar point into bestfacet
+*/
+void qh_partitionpoint (pointT *point, facetT *facet) {
+  realT bestdist;
+  boolT isoutside;
+  facetT *bestfacet;
+  int numpart;
+#if qh_COMPUTEfurthest
+  realT dist;
+#endif
+
+  if (qh findbestnew)
+    bestfacet= qh_findbestnew (point, facet, &bestdist, qh BESToutside, &isoutside, &numpart);
+  else
+    bestfacet= qh_findbest (point, facet, qh BESToutside, qh_ISnewfacets, !qh_NOupper,
+			  &bestdist, &isoutside, &numpart);
+  zinc_(Ztotpartition);
+  zzadd_(Zpartition, numpart);
+  if (qh NARROWhull) {
+    if (qh DELAUNAY && !isoutside && bestdist >= -qh MAXcoplanar)
+      qh_precision ("nearly incident point (narrow hull)");
+    if (qh KEEPnearinside) {
+      if (bestdist >= -qh NEARinside)
+	isoutside= True;
+    }else if (bestdist >= -qh MAXcoplanar)
+      isoutside= True;
+  }
+
+  if (isoutside) {
+    if (!bestfacet->outsideset 
+    || !qh_setlast (bestfacet->outsideset)) {
+      qh_setappend(&(bestfacet->outsideset), point);
+      if (!bestfacet->newfacet) {
+        qh_removefacet (bestfacet);  /* make sure it's after qh facet_next */
+        qh_appendfacet (bestfacet);
+      }
+#if !qh_COMPUTEfurthest
+      bestfacet->furthestdist= bestdist;
+#endif
+    }else {
+#if qh_COMPUTEfurthest
+      zinc_(Zcomputefurthest);
+      qh_distplane (oldfurthest, bestfacet, &dist);
+      if (dist < bestdist) 
+	qh_setappend(&(bestfacet->outsideset), point);
+      else
+	qh_setappend2ndlast(&(bestfacet->outsideset), point);
+#else
+      if (bestfacet->furthestdist < bestdist) {
+	qh_setappend(&(bestfacet->outsideset), point);
+	bestfacet->furthestdist= bestdist;
+      }else
+	qh_setappend2ndlast(&(bestfacet->outsideset), point);
+#endif
+    }
+    qh num_outside++;
+    trace4((qh ferr, "qh_partitionpoint: point p%d is outside facet f%d new? %d(or narrowhull)\n",
+	  qh_pointid(point), bestfacet->id, bestfacet->newfacet));
+  }else if (qh DELAUNAY || bestdist >= -qh MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
+    zzinc_(Zcoplanarpart);
+    if (qh DELAUNAY)
+      qh_precision ("nearly incident point");
+    if ((qh KEEPcoplanar + qh KEEPnearinside) || bestdist > qh max_outside) 
+      qh_partitioncoplanar (point, bestfacet, &bestdist);
+    else {
+      trace4((qh ferr, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",
+	  qh_pointid(point), bestfacet->id));
+    }
+  }else if (qh KEEPnearinside && bestdist > -qh NEARinside) {
+    zinc_(Zpartnear);
+    qh_partitioncoplanar (point, bestfacet, &bestdist);
+  }else {
+    zinc_(Zpartinside);
+    trace4((qh ferr, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
+	  qh_pointid(point), bestfacet->id, bestdist));
+    if (qh KEEPinside)
+      qh_partitioncoplanar (point, bestfacet, &bestdist);
+  }
+} /* partitionpoint */
+
+/*---------------------------------
+  
+  qh_partitionvisible( allpoints, numoutside )
+    partitions points in visible facets to qh.newfacet_list
+    qh.visible_list= visible facets
+    for visible facets
+      1st neighbor (if any) points to a horizon facet or a new facet
+    if allpoints (not used),
+      repartitions coplanar points
+
+  returns:
+    updates outside sets and coplanar sets of qh.newfacet_list
+    updates qh.num_outside (count of outside points)
+  
+  notes:
+    qh.findbest_notsharp should be clear (extra work if set)
+
+  design:
+    for all visible facets with outside set or coplanar set
+      select a newfacet for visible facet
+      if outside set
+        partition outside set into new facets
+      if coplanar set and keeping coplanar/near-inside/inside points
+        if allpoints
+          partition coplanar set into new facets, may be assigned outside
+        else
+          partition coplanar set into coplanar sets of new facets
+    for each deleted vertex
+      if allpoints
+        partition vertex into new facets, may be assigned outside
+      else
+        partition vertex into coplanar sets of new facets
+*/
+void qh_partitionvisible(/*visible_list*/ boolT allpoints, int *numoutside) {
+  facetT *visible, *newfacet;
+  pointT *point, **pointp;
+  int coplanar=0, size;
+  unsigned count;
+  vertexT *vertex, **vertexp;
+  
+  if (qh ONLYmax)
+    maximize_(qh MINoutside, qh max_vertex);
+  *numoutside= 0;
+  FORALLvisible_facets {
+    if (!visible->outsideset && !visible->coplanarset)
+      continue;
+    newfacet= visible->f.replace;
+    count= 0;
+    while (newfacet && newfacet->visible) {
+      newfacet= newfacet->f.replace;
+      if (count++ > qh facet_id)
+	qh_infiniteloop (visible);
+    }
+    if (!newfacet)
+      newfacet= qh newfacet_list;
+    if (newfacet == qh facet_tail) {
+      fprintf (qh ferr, "qhull precision error (qh_partitionvisible): all new facets deleted as\n        degenerate facets. Can not continue.\n");
+      qh_errexit (qh_ERRprec, NULL, NULL);
+    }
+    if (visible->outsideset) {
+      size= qh_setsize (visible->outsideset);
+      *numoutside += size;
+      qh num_outside -= size;
+      FOREACHpoint_(visible->outsideset) 
+        qh_partitionpoint (point, newfacet);
+    }
+    if (visible->coplanarset && (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside)) {
+      size= qh_setsize (visible->coplanarset);
+      coplanar += size;
+      FOREACHpoint_(visible->coplanarset) {
+        if (allpoints) /* not used */
+          qh_partitionpoint (point, newfacet);
+        else
+          qh_partitioncoplanar (point, newfacet, NULL);
+      }
+    }
+  }
+  FOREACHvertex_(qh del_vertices) {
+    if (vertex->point) {
+      if (allpoints) /* not used */
+        qh_partitionpoint (vertex->point, qh newfacet_list);
+      else
+        qh_partitioncoplanar (vertex->point, qh newfacet_list, NULL);
+    }
+  }
+  trace1((qh ferr,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));
+} /* partitionvisible */
+
+
+
+/*---------------------------------
+  
+  qh_precision( reason )
+    restart on precision errors if not merging and if 'QJn'
+*/
+void qh_precision (char *reason) {
+
+  if (qh ALLOWrestart && !qh PREmerge && !qh MERGEexact) {
+    if (qh JOGGLEmax < REALmax/2) {
+      trace0((qh ferr, "qh_precision: qhull restart because of %s\n", reason));
+      longjmp(qh restartexit, qh_ERRprec);
+    }
+  }
+} /* qh_precision */
+
+/*---------------------------------
+  
+  qh_printsummary( fp )
+    prints summary to fp
+
+  notes:
+    not in io.c so that user_eg.c can prevent io.c from loading
+    qh_printsummary and qh_countfacets must match counts
+
+  design:
+    determine number of points, vertices, and coplanar points
+    print summary
+*/
+void qh_printsummary(FILE *fp) {
+  realT ratio, outerplane, innerplane;
+  float cpu;
+  int size, id, nummerged, numvertices, numcoplanars= 0, nonsimplicial=0;
+  int goodused;
+  facetT *facet;
+  char *s;
+  int numdel= zzval_(Zdelvertextot);
+  int numtricoplanars= 0;
+
+  size= qh num_points + qh_setsize (qh other_points);
+  numvertices= qh num_vertices - qh_setsize (qh del_vertices);
+  id= qh_pointid (qh GOODpointp);
+  FORALLfacets {
+    if (facet->coplanarset)
+      numcoplanars += qh_setsize( facet->coplanarset);
+    if (facet->good) {
+      if (facet->simplicial) {
+	if (facet->keepcentrum && facet->tricoplanar)
+	  numtricoplanars++;
+      }else if (qh_setsize(facet->vertices) != qh hull_dim)
+	nonsimplicial++;
+    }
+  }
+  if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
+    size--;
+  if (qh STOPcone || qh STOPpoint)
+      fprintf (fp, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error.");
+  if (qh UPPERdelaunay)
+    goodused= qh GOODvertex + qh GOODpoint + qh SPLITthresholds;
+  else if (qh DELAUNAY)
+    goodused= qh GOODvertex + qh GOODpoint + qh GOODthreshold;
+  else
+    goodused= qh num_good;
+  nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
+  if (qh VORONOI) {
+    if (qh UPPERdelaunay)
+      fprintf (fp, "\n\
+Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    else
+      fprintf (fp, "\n\
+Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    fprintf(fp, "  Number of Voronoi regions%s: %d\n",
+              qh ATinfinity ? " and at-infinity" : "", numvertices);
+    if (numdel)
+      fprintf(fp, "  Total number of deleted points due to merging: %d\n", numdel); 
+    if (numcoplanars - numdel > 0) 
+      fprintf(fp, "  Number of nearly incident points: %d\n", numcoplanars - numdel); 
+    else if (size - numvertices - numdel > 0) 
+      fprintf(fp, "  Total number of nearly incident points: %d\n", size - numvertices - numdel); 
+    fprintf(fp, "  Number of%s Voronoi vertices: %d\n", 
+              goodused ? " 'good'" : "", qh num_good);
+    if (nonsimplicial) 
+      fprintf(fp, "  Number of%s non-simplicial Voronoi vertices: %d\n", 
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else if (qh DELAUNAY) {
+    if (qh UPPERdelaunay)
+      fprintf (fp, "\n\
+Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    else
+      fprintf (fp, "\n\
+Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    fprintf(fp, "  Number of input sites%s: %d\n", 
+              qh ATinfinity ? " and at-infinity" : "", numvertices);
+    if (numdel)
+      fprintf(fp, "  Total number of deleted points due to merging: %d\n", numdel); 
+    if (numcoplanars - numdel > 0) 
+      fprintf(fp, "  Number of nearly incident points: %d\n", numcoplanars - numdel); 
+    else if (size - numvertices - numdel > 0)
+      fprintf(fp, "  Total number of nearly incident points: %d\n", size - numvertices - numdel); 
+    fprintf(fp, "  Number of%s Delaunay regions: %d\n", 
+              goodused ? " 'good'" : "", qh num_good);
+    if (nonsimplicial) 
+      fprintf(fp, "  Number of%s non-simplicial Delaunay regions: %d\n", 
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else if (qh HALFspace) {
+    fprintf (fp, "\n\
+Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    fprintf(fp, "  Number of halfspaces: %d\n", size);
+    fprintf(fp, "  Number of non-redundant halfspaces: %d\n", numvertices);
+    if (numcoplanars) {
+      if (qh KEEPinside && qh KEEPcoplanar)
+      	s= "similar and redundant";
+      else if (qh KEEPinside)
+        s= "redundant";
+      else
+        s= "similar"; 
+      fprintf(fp, "  Number of %s halfspaces: %d\n", s, numcoplanars);
+    } 
+    fprintf(fp, "  Number of intersection points: %d\n", qh num_facets - qh num_visible);
+    if (goodused)
+      fprintf(fp, "  Number of 'good' intersection points: %d\n", qh num_good);
+    if (nonsimplicial) 
+      fprintf(fp, "  Number of%s non-simplicial intersection points: %d\n", 
+              goodused ? " 'good'" : "", nonsimplicial);
+  }else {
+    fprintf (fp, "\n\
+Convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
+    fprintf(fp, "  Number of vertices: %d\n", numvertices);
+    if (numcoplanars) {
+      if (qh KEEPinside && qh KEEPcoplanar)
+      	s= "coplanar and interior";
+      else if (qh KEEPinside)
+        s= "interior";
+      else
+        s= "coplanar"; 
+      fprintf(fp, "  Number of %s points: %d\n", s, numcoplanars);
+    } 
+    fprintf(fp, "  Number of facets: %d\n", qh num_facets - qh num_visible);
+    if (goodused)
+      fprintf(fp, "  Number of 'good' facets: %d\n", qh num_good);
+    if (nonsimplicial) 
+      fprintf(fp, "  Number of%s non-simplicial facets: %d\n", 
+              goodused ? " 'good'" : "", nonsimplicial);
+  }
+  if (numtricoplanars)
+      fprintf(fp, "  Number of triangulated facets: %d\n", numtricoplanars);
+  fprintf(fp, "\nStatistics for: %s | %s", 
+                      qh rbox_command, qh qhull_command);
+  if (qh ROTATErandom != INT_MIN)
+    fprintf(fp, " QR%d\n\n", qh ROTATErandom);
+  else
+    fprintf(fp, "\n\n");
+  fprintf(fp, "  Number of points processed: %d\n", zzval_(Zprocessed));
+  fprintf(fp, "  Number of hyperplanes created: %d\n", zzval_(Zsetplane));
+  if (qh DELAUNAY)
+    fprintf(fp, "  Number of facets in hull: %d\n", qh num_facets - qh num_visible);
+  fprintf(fp, "  Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
+      zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
+#if 0  /* NOTE: must print before printstatistics() */
+  {realT stddev, ave;
+  fprintf(fp, "  average new facet balance: %2.2g\n",
+	  wval_(Wnewbalance)/zval_(Zprocessed));
+  stddev= qh_stddev (zval_(Zprocessed), wval_(Wnewbalance), 
+                                 wval_(Wnewbalance2), &ave);
+  fprintf(fp, "  new facet standard deviation: %2.2g\n", stddev);
+  fprintf(fp, "  average partition balance: %2.2g\n",
+	  wval_(Wpbalance)/zval_(Zpbalance));
+  stddev= qh_stddev (zval_(Zpbalance), wval_(Wpbalance), 
+                                 wval_(Wpbalance2), &ave);
+  fprintf(fp, "  partition standard deviation: %2.2g\n", stddev);
+  }
+#endif
+  if (nummerged) {
+    fprintf(fp,"  Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
+          zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)+
+          zzval_(Zdistzero));
+    fprintf(fp,"  Number of distance tests for checking: %d\n",zzval_(Zcheckpart));
+    fprintf(fp,"  Number of merged facets: %d\n", nummerged);
+  }
+  if (!qh RANDOMoutside && qh QHULLfinished) {
+    cpu= qh hulltime;
+    cpu /= qh_SECticks;
+    wval_(Wcpu)= cpu;
+    fprintf (fp, "  CPU seconds to compute hull (after input): %2.4g\n", cpu);
+  }
+  if (qh RERUN) {
+    if (!qh PREmerge && !qh MERGEexact)
+      fprintf(fp, "  Percentage of runs with precision errors: %4.1f\n",
+	   zzval_(Zretry)*100.0/qh build_cnt);  /* careful of order */
+  }else if (qh JOGGLEmax < REALmax/2) {
+    if (zzval_(Zretry))
+      fprintf(fp, "  After %d retries, input joggled by: %2.2g\n",
+         zzval_(Zretry), qh JOGGLEmax);
+    else
+      fprintf(fp, "  Input joggled by: %2.2g\n", qh JOGGLEmax);
+  }
+  if (qh totarea != 0.0) 
+    fprintf(fp, "  %s facet area:   %2.8g\n", 
+	    zzval_(Ztotmerge) ? "Approximate" : "Total", qh totarea);
+  if (qh totvol != 0.0) 
+    fprintf(fp, "  %s volume:       %2.8g\n", 
+	    zzval_(Ztotmerge) ? "Approximate" : "Total", qh totvol);
+  if (qh MERGING) {
+    qh_outerinner (NULL, &outerplane, &innerplane);
+    if (outerplane > 2 * qh DISTround) {
+      fprintf(fp, "  Maximum distance of %spoint above facet: %2.2g", 
+	    (qh QHULLfinished ? "" : "merged "), outerplane);
+      ratio= outerplane/(qh ONEmerge + qh DISTround);
+      /* don't report ratio if MINoutside is large */
+      if (ratio > 0.05 && 2* qh ONEmerge > qh MINoutside && qh JOGGLEmax > REALmax/2)
+        fprintf (fp, " (%.1fx)\n", ratio);
+      else
+        fprintf (fp, "\n");
+    }
+    if (innerplane < -2 * qh DISTround) {
+      fprintf(fp, "  Maximum distance of %svertex below facet: %2.2g", 
+	    (qh QHULLfinished ? "" : "merged "), innerplane);
+      ratio= -innerplane/(qh ONEmerge+qh DISTround);
+      if (ratio > 0.05 && qh JOGGLEmax > REALmax/2)
+        fprintf (fp, " (%.1fx)\n", ratio);
+      else
+        fprintf (fp, "\n");
+    }
+  }
+  fprintf(fp, "\n");
+} /* printsummary */
+
+
diff --git a/extern/qhull/src/qhull.h b/extern/qhull/src/qhull.h
new file mode 100644
index 00000000000..896ec1e9c18
--- /dev/null
+++ b/extern/qhull/src/qhull.h
@@ -0,0 +1,1048 @@
+/*
  ---------------------------------
+
+   qhull.h
+   user-level header file for using qhull.a library
+
+   see qh-qhull.htm, qhull_a.h
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   NOTE: access to qh_qh is via the 'qh' macro.  This allows
+   qh_qh to be either a pointer or a structure.  An example
+   of using qh is "qh DROPdim" which accesses the DROPdim
+   field of qh_qh.  Similarly, access to qh_qhstat is via
+   the 'qhstat' macro.
+
+   includes function prototypes for qhull.c, geom.c, global.c, io.c, user.c
+
+   use mem.h for mem.c
+   use qset.h for qset.c
+
+   see unix.c for an example of using qhull.h
+
+   recompile qhull if you change this file
+*/
+
+#ifndef qhDEFqhull
+#define qhDEFqhull 1
+
+/*=========================== -included files ==============*/
+
+#include 
+#include 
+#include 
+
+#if __MWERKS__ && __POWERPC__
+#include  
+#include  
+#include	
+#endif
+
+#ifndef __STDC__
+#ifndef __cplusplus
+#if     !_MSC_VER
+#error  Neither __STDC__ nor __cplusplus is defined.  Please use strict ANSI C or C++ to compile
+#error  Qhull.  You may need to turn off compiler extensions in your project configuration.  If
+#error  your compiler is a standard C compiler, you can delete this warning from qhull.h
+#endif
+#endif
+#endif
+
+#include "user.h"      /* user defineable constants */
+
+/*============ constants and basic types ====================*/
+
+/*----------------------------------
+
+  qh_VERSION
+    version string by year and date
+
+    the revision increases on code changes only
+
+  notes:
+    change date:    Changes.txt, Announce.txt, README.txt, qhull.man
+                    qhull-news.html, Eudora signatures, 
+    change version: README.txt, qhull.html, file_id.diz, Makefile
+    change year:    Copying.txt
+    check download size
+    recompile user_eg.c, rbox.c, qhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c
+    make copy of qhull-news.html as qh-news.htm
+*/
+
+#define qh_VERSION "2002.1 2002/8/20"
+
+/*----------------------------------
+
+  coordT
+    coordinates and coefficients are stored as realT (i.e., double)
+
+  notes:
+    could use 'float' for data and 'double' for calculations (realT vs. coordT)
+      This requires many type casts, and adjusted error bounds.
+      Also C compilers may do expressions in double anyway.
+*/
+#define coordT realT
+
+/*----------------------------------
+
+  pointT
+    a point is an array of DIM3 coordinates
+*/
+#define pointT coordT
+
+/*----------------------------------
+
+  flagT
+    Boolean flag as a bit
+*/
+#define flagT unsigned int
+
+/*----------------------------------
+
+  boolT
+    boolean value, either True or False
+
+  notes:
+    needed for portability
+*/
+#define boolT unsigned int
+#ifdef False
+#undef False
+#endif
+#ifdef True
+#undef True
+#endif
+#define False 0
+#define True 1
+
+/*----------------------------------
+
+  qh_CENTER
+    to distinguish facet->center
+*/
+typedef enum
+{
+    qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum
+}
+qh_CENTER;
+
+/*----------------------------------
+
+  qh_PRINT
+    output formats for printing (qh.PRINTout).
+    'Fa' 'FV' 'Fc' 'FC' 
+       
+
+   notes:
+   some of these names are similar to qh names.  The similar names are only
+   used in switch statements in qh_printbegin() etc.
+*/
+typedef enum {qh_PRINTnone= 0, 
+  qh_PRINTarea, qh_PRINTaverage,           /* 'Fa' 'FV' 'Fc' 'FC' */
+  qh_PRINTcoplanars, qh_PRINTcentrums, 
+  qh_PRINTfacets, qh_PRINTfacets_xridge,   /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */
+  qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors, 
+  qh_PRINTnormals, qh_PRINTouter,          /* 'n' 'Fo' 'i' 'm' 'Fm' 'o' */
+  qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff, 
+  qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */
+  qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize, 
+  qh_PRINTsummary, qh_PRINTtriangles,      /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */
+  qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes,
+  qh_PRINTEND} qh_PRINT;
+
+/*----------------------------------
+
+  qh_ALL
+    argument flag for selecting everything
+*/
+#define qh_ALL      True
+#define qh_NOupper  True     /* argument for qh_findbest */
+#define qh_IScheckmax  True     /* argument for qh_findbesthorizon */
+#define qh_ISnewfacets  True     /* argument for qh_findbest */
+#define qh_RESETvisible  True     /* argument for qh_resetlists */
+
+/*----------------------------------
+
+  qh_ERR
+    Qhull exit codes, for indicating errors
+*/
+#define qh_ERRnone  0    /* no error occurred during qhull */
+#define qh_ERRinput 1    /* input inconsistency */
+#define qh_ERRsingular 2 /* singular input data */
+#define qh_ERRprec  3    /* precision error */
+#define qh_ERRmem   4    /* insufficient memory, matches mem.h */
+#define qh_ERRqhull 5    /* internal error detected, matches mem.h */
+
+/* ============ -structures- ====================
+   each of the following structures is defined by a typedef
+   all realT and coordT fields occur at the beginning of a structure
+        (otherwise space may be wasted due to alignment)
+   define all flags together and pack into 32-bit number
+*/
+
+typedef struct vertexT vertexT;
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;          /* defined in qset.h */
+#endif
+
+/*----------------------------------
+
+  facetT
+    defines a facet
+
+  notes:
+   qhull() generates the hull as a list of facets.
+
+  topological information:
+    f.previous,next     doubly-linked list of facets
+    f.vertices          set of vertices
+    f.ridges            set of ridges
+    f.neighbors         set of neighbors
+    f.toporient         True if facet has top-orientation (else bottom)
+
+  geometric information:
+    f.offset,normal     hyperplane equation
+    f.maxoutside        offset to outer plane -- all points inside
+    f.center            centrum for testing convexity
+    f.simplicial        True if facet is simplicial
+    f.flipped           True if facet does not include qh.interior_point
+
+  for constructing hull:
+    f.visible           True if facet on list of visible facets (will be deleted)
+    f.newfacet          True if facet on list of newly created facets
+    f.coplanarset       set of points coplanar with this facet
+                        (includes near-inside points for later testing)
+    f.outsideset        set of points outside of this facet
+    f.furthestdist      distance to furthest point of outside set
+    f.visitid           marks visited facets during a loop
+    f.replace           replacement facet for to-be-deleted, visible facets
+    f.samecycle,newcycle cycle of facets for merging into horizon facet
+
+  see below for other flags and fields
+*/
+struct facetT {
+#if !qh_COMPUTEfurthest
+  coordT   furthestdist;/* distance to furthest point of outsideset */
+#endif
+#if qh_MAXoutside
+  coordT   maxoutside;  /* max computed distance of point to facet
+  			Before QHULLfinished this is an approximation
+  			since maxdist not always set for mergefacet
+			Actual outer plane is +DISTround and
+			computed outer plane is +2*DISTround */
+#endif
+  coordT   offset;      /* exact offset of hyperplane from origin */
+  coordT  *normal;      /* normal of hyperplane, hull_dim coefficients */
+			/*   if tricoplanar, shared with a neighbor */
+  union {               /* in order of testing */
+   realT   area;        /* area of facet, only in io.c if  ->isarea */
+   facetT *replace;	/*  replacement facet if ->visible and NEWfacets
+  			     is NULL only if qh_mergedegen_redundant or interior */
+   facetT *samecycle;   /*  cycle of facets from the same visible/horizon intersection,
+   			     if ->newfacet */
+   facetT *newcycle;    /*  in horizon facet, current samecycle of new facets */ 
+   facetT *trivisible;  /* visible facet for ->tricoplanar facets during qh_triangulate() */
+   facetT *triowner;    /* owner facet for ->tricoplanar, !isarea facets w/ ->keepcentrum */
+  }f;
+  coordT  *center;      /*  centrum for convexity, qh CENTERtype == qh_AScentrum */
+      			/*  Voronoi center, qh CENTERtype == qh_ASvoronoi */
+			/*   if tricoplanar, shared with a neighbor */
+  facetT  *previous;    /* previous facet in the facet_list */
+  facetT  *next;        /* next facet in the facet_list */
+  setT    *vertices;    /* vertices for this facet, inverse sorted by ID 
+                           if simplicial, 1st vertex was apex/furthest */
+  setT    *ridges;      /* explicit ridges for nonsimplicial facets.
+  			   for simplicial facets, neighbors defines ridge */
+  setT    *neighbors;   /* neighbors of the facet.  If simplicial, the kth
+			   neighbor is opposite the kth vertex, and the first
+			   neighbor is the horizon facet for the first vertex*/
+  setT    *outsideset;  /* set of points outside this facet
+		           if non-empty, last point is furthest
+			   if NARROWhull, includes coplanars for partitioning*/
+  setT    *coplanarset; /* set of points coplanar with this facet
+  			   > qh.min_vertex and <= facet->max_outside
+                           a point is assigned to the furthest facet
+		           if non-empty, last point is furthest away */
+  unsigned visitid;     /* visit_id, for visiting all neighbors,
+			   all uses are independent */
+  unsigned id;	        /* unique identifier from qh facet_id */
+  unsigned nummerge:9;  /* number of merges */
+#define qh_MAXnummerge 511 /*     2^9-1, 32 flags total, see "flags:" in io.c */
+  flagT    tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */
+			  /*   all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */
+			  /*   all tricoplanars share the same apex */
+                          /*   if ->degenerate, does not span facet (one logical ridge) */
+                          /*   one tricoplanar has ->keepcentrum and ->coplanarset */
+                          /*   during qh_triangulate, f.trivisible points to original facet */
+  flagT	   newfacet:1;  /* True if facet on qh newfacet_list (new or merged) */
+  flagT	   visible:1;   /* True if visible facet (will be deleted) */
+  flagT    toporient:1; /* True if created with top orientation
+			   after merging, use ridge orientation */
+  flagT    simplicial:1;/* True if simplicial facet, ->ridges may be implicit */
+  flagT    seen:1;      /* used to perform operations only once, like visitid */
+  flagT    seen2:1;     /* used to perform operations only once, like visitid */
+  flagT	   flipped:1;   /* True if facet is flipped */
+  flagT    upperdelaunay:1; /* True if facet is upper envelope of Delaunay triangulation */
+  flagT    notfurthest:1; /* True if last point of outsideset is not furthest*/
+
+/*-------- flags primarily for output ---------*/
+  flagT	   good:1;      /* True if a facet marked good for output */
+  flagT    isarea:1;    /* True if facet->f.area is defined */
+
+/*-------- flags for merging ------------------*/
+  flagT    dupridge:1;  /* True if duplicate ridge in facet */
+  flagT    mergeridge:1; /* True if facet or neighbor contains a qh_MERGEridge
+                            ->normal defined (also defined for mergeridge2) */
+  flagT    mergeridge2:1; /* True if neighbor contains a qh_MERGEridge (mark_dupridges */
+  flagT    coplanar:1;  /* True if horizon facet is coplanar at last use */
+  flagT     mergehorizon:1; /* True if will merge into horizon (->coplanar) */
+  flagT	    cycledone:1;/* True if mergecycle_all already done */
+  flagT    tested:1;    /* True if facet convexity has been tested (false after merge */
+  flagT    keepcentrum:1; /* True if keep old centrum after a merge, or marks owner for ->tricoplanar */
+  flagT	   newmerge:1;  /* True if facet is newly merged for reducevertices */
+  flagT	   degenerate:1; /* True if facet is degenerate (degen_mergeset or ->tricoplanar) */
+  flagT	   redundant:1;  /* True if facet is redundant (degen_mergeset) */
+};
+
+
+/*----------------------------------
+
+  ridgeT
+    defines a ridge
+
+  notes:
+  a ridge is DIM3-1 simplex between two neighboring facets.  If the
+  facets are non-simplicial, there may be more than one ridge between
+  two facets.  E.G. a 4-d hypercube has two triangles between each pair
+  of neighboring facets.
+
+  topological information:
+    vertices            a set of vertices
+    top,bottom          neighboring facets with orientation
+
+  geometric information:
+    tested              True if ridge is clearly convex
+    nonconvex           True if ridge is non-convex
+*/
+struct ridgeT {
+  setT    *vertices;    /* vertices belonging to this ridge, inverse sorted by ID 
+                           NULL if a degen ridge (matchsame) */
+  facetT  *top;         /* top facet this ridge is part of */
+  facetT  *bottom;      /* bottom facet this ridge is part of */
+  unsigned id:24;       /* unique identifier, =>room for 8 flags */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    tested:1;    /* True when ridge is tested for convexity */
+  flagT    nonconvex:1; /* True if getmergeset detected a non-convex neighbor
+			   only one ridge between neighbors may have nonconvex */
+};
+
+/*----------------------------------
+
+  vertexT
+     defines a vertex
+
+  topological information:
+    next,previous       doubly-linked list of all vertices
+    neighbors           set of adjacent facets (only if qh.VERTEXneighbors)
+
+  geometric information:
+    point               array of DIM3 coordinates
+*/
+struct vertexT {
+  vertexT *next;        /* next vertex in vertex_list */
+  vertexT *previous;    /* previous vertex in vertex_list */
+  pointT  *point;       /* hull_dim coordinates (coordT) */
+  setT    *neighbors;   /* neighboring facets of vertex, qh_vertexneighbors()
+			   inits in io.c or after first merge */
+  unsigned visitid; /* for use with qh vertex_visit */
+  unsigned id:24;   /* unique identifier, =>room for 8 flags */
+  flagT    seen:1;      /* used to perform operations only once */
+  flagT    seen2:1;     /* another seen flag */
+  flagT    delridge:1;  /* vertex was part of a deleted ridge */
+  flagT	   deleted:1;   /* true if vertex on qh del_vertices */
+  flagT    newlist:1;   /* true if vertex on qh newvertex_list */
+};
+
+/*======= -global variables -qh ============================*/
+
+/*----------------------------------
+
+  qh
+   all global variables for qhull are in qh, qhmem, and qhstat
+
+  notes:
+   qhmem is defined in mem.h and qhstat is defined in stat.h
+   access to qh_qh is via the "qh" macro.  See qh_QHpointer in user.h
+*/
+typedef struct qhT qhT;
+#if qh_QHpointer
+#define qh qh_qh->
+extern qhT *qh_qh;     /* allocated in global.c */
+#else
+#define qh qh_qh.
+extern qhT qh_qh;
+#endif
+
+struct qhT {
+
+/*----------------------------------
+
+  qh constants
+    configuration flags and constants for Qhull
+
+  notes:
+    The user configures Qhull by defining flags.  They are
+    copied into qh by qh_setflags().  qh-quick.htm#options defines the flags.
+*/
+  boolT ALLpoints;        /* true 'Qs' if search all points for initial simplex */
+  boolT ANGLEmerge;	  /* true 'Qa' if sort potential merges by angle */
+  boolT APPROXhull;       /* true 'Wn' if MINoutside set */
+  realT MINoutside;       /*   'Wn' min. distance for an outside point */
+  boolT ATinfinity;       /* true 'Qz' if point num_points-1 is "at-infinity"
+                             for improving precision in Delaunay triangulations */
+  boolT AVOIDold;         /* true 'Q4' if avoid old->new merges */
+  boolT BESToutside;      /* true 'Qf' if partition points into best outsideset */
+  boolT CDDinput;         /* true 'Pc' if input uses CDD format (1.0/offset first) */
+  boolT CDDoutput;        /* true 'PC' if print normals in CDD format (offset first) */
+  boolT CHECKfrequently;  /* true 'Tc' if checking frequently */
+  realT premerge_cos;     /*   'A-n'   cos_max when pre merging */
+  realT postmerge_cos;    /*   'An'    cos_max when post merging */
+  boolT DELAUNAY;         /* true 'd' if computing DELAUNAY triangulation */
+  boolT DOintersections;  /* true 'Gh' if print hyperplane intersections */
+  int   DROPdim;          /* drops dim 'GDn' for 4-d -> 3-d output */
+  boolT FORCEoutput;      /* true 'Po' if forcing output despite degeneracies */
+  int   GOODpoint;        /* 1+n for 'QGn', good facet if visible/not(-) from point n*/
+  pointT *GOODpointp;     /*   the actual point */
+  boolT GOODthreshold;    /* true if qh lower_threshold/upper_threshold defined
+  			     false if qh SPLITthreshold */
+  int   GOODvertex;       /* 1+n, good facet if vertex for point n */
+  pointT *GOODvertexp;     /*   the actual point */
+  boolT HALFspace;        /* true 'Hn,n,n' if halfspace intersection */
+  int   IStracing;        /* trace execution, 0=none, 1=least, 4=most, -1=events */
+  int   KEEParea;         /* 'PAn' number of largest facets to keep */
+  boolT KEEPcoplanar;     /* true 'Qc' if keeping nearest facet for coplanar points */
+  boolT KEEPinside;       /* true 'Qi' if keeping nearest facet for inside points
+			      set automatically if 'd Qc' */
+  int   KEEPmerge;        /* 'PMn' number of facets to keep with most merges */
+  realT KEEPminArea;      /* 'PFn' minimum facet area to keep */
+  realT MAXcoplanar;      /* 'Un' max distance below a facet to be coplanar*/
+  boolT MERGEexact;	  /* true 'Qx' if exact merges (coplanar, degen, dupridge, flipped) */
+  boolT MERGEindependent; /* true 'Q2' if merging independent sets */
+  boolT MERGING;          /* true if exact-, pre- or post-merging, with angle and centrum tests */
+  realT   premerge_centrum;  /*   'C-n' centrum_radius when pre merging.  Default is round-off */
+  realT   postmerge_centrum; /*   'Cn' centrum_radius when post merging.  Default is round-off */
+  boolT MERGEvertices;	  /* true 'Q3' if merging redundant vertices */
+  realT MINvisible;       /* 'Vn' min. distance for a facet to be visible */
+  boolT NOnarrow;         /* true 'Q10' if no special processing for narrow distributions */
+  boolT NOnearinside;     /* true 'Q8' if ignore near-inside points when partitioning */
+  boolT NOpremerge;       /* true 'Q0' if no defaults for C-0 or Qx */
+  boolT ONLYgood; 	  /* true 'Qg' if process points with good visible or horizon facets */
+  boolT ONLYmax; 	  /* true 'Qm' if only process points that increase max_outside */
+  boolT PICKfurthest;     /* true 'Q9' if process furthest of furthest points*/
+  boolT POSTmerge;        /* true if merging after buildhull (Cn or An) */
+  boolT PREmerge;         /* true if merging during buildhull (C-n or A-n) */
+  			/* NOTE: some of these names are similar to qh_PRINT names */
+  boolT PRINTcentrums;	  /* true 'Gc' if printing centrums */
+  boolT PRINTcoplanar;    /* true 'Gp' if printing coplanar points */
+  int	PRINTdim;      	  /* print dimension for Geomview output */
+  boolT PRINTdots;        /* true 'Ga' if printing all points as dots */
+  boolT PRINTgood;        /* true 'Pg' if printing good facets */
+  boolT PRINTinner;	  /* true 'Gi' if printing inner planes */
+  boolT PRINTneighbors;	  /* true 'PG' if printing neighbors of good facets */
+  boolT PRINTnoplanes;	  /* true 'Gn' if printing no planes */
+  boolT PRINToptions1st;  /* true 'FO' if printing options to stderr */
+  boolT PRINTouter;	  /* true 'Go' if printing outer planes */
+  boolT PRINTprecision;   /* false 'Pp' if not reporting precision problems */
+  qh_PRINT PRINTout[qh_PRINTEND]; /* list of output formats to print */
+  boolT PRINTridges;      /* true 'Gr' if print ridges */
+  boolT PRINTspheres;     /* true 'Gv' if print vertices as spheres */
+  boolT PRINTstatistics;  /* true 'Ts' if printing statistics to stderr */
+  boolT PRINTsummary;     /* true 's' if printing summary to stderr */
+  boolT PRINTtransparent; /* true 'Gt' if print transparent outer ridges */
+  boolT PROJECTdelaunay;  /* true if DELAUNAY, no readpoints() and
+			     need projectinput() for Delaunay in qh_init_B */
+  int   PROJECTinput;     /* number of projected dimensions 'bn:0Bn:0' */
+  boolT QUICKhelp;	  /* true if quick help message for degen input */
+  boolT RANDOMdist;       /* true if randomly change distplane and setfacetplane */
+  realT RANDOMfactor;     /*    maximum random perturbation */
+  realT RANDOMa;         /*  qh_randomfactor is randr * RANDOMa + RANDOMb */
+  realT RANDOMb;
+  boolT RANDOMoutside;    /* true if select a random outside point */
+  int	REPORTfreq;       /* buildtracing reports every n facets */
+  int   REPORTfreq2;	  /* tracemerging reports every REPORTfreq/2 facets */
+  int	RERUN;            /* 'TRn' rerun qhull n times (qh.build_cnt) */
+  int	ROTATErandom;	  /* 'QRn' seed, 0 time, >= rotate input */
+  boolT SCALEinput;       /* true 'Qbk' if scaling input */
+  boolT SCALElast;        /* true 'Qbb' if scale last coord to max prev coord */
+  boolT SETroundoff;      /* true 'E' if qh DISTround is predefined */
+  boolT SKIPcheckmax;	  /* true 'Q5' if skip qh_check_maxout */
+  boolT SKIPconvex;       /* true 'Q6' if skip convexity testing during pre-merge */
+  boolT SPLITthresholds;  /* true if upper_/lower_threshold defines a region
+                               used only for printing (not for qh ONLYgood) */
+  int	STOPcone;         /* 'TCn' 1+n for stopping after cone for point n*/
+			  /*       also used by qh_build_withresart for err exit*/
+  int	STOPpoint;        /* 'TVn' 'TV-n' 1+n for stopping after/before(-)
+			                adding point n */
+  int	TESTpoints;	  /* 'QTn' num of test points after qh.num_points.  Test points always coplanar. */
+  boolT TESTvneighbors;   /*  true 'Qv' if test vertex neighbors at end */
+  int   TRACElevel;       /* 'Tn' conditional IStracing level */
+  int	TRACElastrun;	  /*  qh.TRACElevel applies to last qh.RERUN */
+  int   TRACEpoint;       /* 'TPn' start tracing when point n is a vertex */
+  realT TRACEdist;        /* 'TWn' start tracing when merge distance too big */
+  int   TRACEmerge;       /* 'TMn' start tracing before this merge */
+  boolT TRIangulate;	  /* true 'Qt' if triangulate non-simplicial facets */
+  boolT TRInormals;	  /* true 'Q11' if triangulate duplicates normals (sets Qt) */
+  boolT UPPERdelaunay;    /* true 'Qu' if computing furthest-site Delaunay */
+  boolT VERIFYoutput;     /* true 'Tv' if verify output at end of qhull */
+  boolT VIRTUALmemory;    /* true 'Q7' if depth-first processing in buildhull */
+  boolT VORONOI;	  /* true 'v' if computing Voronoi diagram */
+
+  /*--------input constants ---------*/
+  realT AREAfactor;       /* 1/(hull_dim-1)! for converting det's to area */
+  boolT DOcheckmax;       /* true if calling qh_check_maxout (qh_initqhull_globals) */
+  char	*feasible_string;  /* feasible point 'Hn,n,n' for halfspace intersection */
+  coordT *feasible_point;  /*    as coordinates, both malloc'd */
+  boolT GETarea;          /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io.c */
+  boolT KEEPnearinside;   /* true if near-inside points in coplanarset */
+  int 	hull_dim;         /* dimension of hull, set by initbuffers */
+  int 	input_dim;	  /* dimension of input, set by initbuffers */
+  int 	num_points;       /* number of input points */
+  pointT *first_point;    /* array of input points, see POINTSmalloc */
+  boolT POINTSmalloc;     /*   true if qh first_point/num_points allocated */
+  pointT *input_points;   /* copy of original qh.first_point for input points for qh_joggleinput */
+  boolT input_malloc;     /* true if qh input_points malloc'd */
+  char 	qhull_command[256];/* command line that invoked this program */
+  char 	rbox_command[256]; /* command line that produced the input points */
+  char  qhull_options[512];/* descriptive list of options */
+  int   qhull_optionlen;  /*    length of last line */
+  int   qhull_optionsiz;  /*     size of qhull_options before qh_initbuild */
+  boolT VERTEXneighbors;  /* true if maintaining vertex neighbors */
+  boolT ZEROcentrum;      /* true if 'C-0' or 'C-0 Qx'.  sets ZEROall_ok */
+  realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k]
+                             must set either GOODthreshold or SPLITthreshold
+  			     if Delaunay, default is 0.0 for upper envelope */
+  realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */
+  realT *upper_bound;     /* scale point[k] to new upper bound */
+  realT *lower_bound;     /* scale point[k] to new lower bound
+  			     project if both upper_ and lower_bound == 0 */
+
+/*----------------------------------
+
+  qh precision constants
+    precision constants for Qhull
+
+  notes:
+    qh_detroundoff() computes the maximum roundoff error for distance
+    and other computations.  It also sets default values for the
+    qh constants above.
+*/
+  realT ANGLEround;       /* max round off error for angles */
+  realT centrum_radius;   /* max centrum radius for convexity (roundoff added) */
+  realT cos_max;	  /* max cosine for convexity (roundoff added) */
+  realT DISTround;        /* max round off error for distances, 'E' overrides */
+  realT MAXabs_coord;     /* max absolute coordinate */
+  realT MAXlastcoord;     /* max last coordinate for qh_scalelast */
+  realT MAXsumcoord;      /* max sum of coordinates */
+  realT MAXwidth;         /* max rectilinear width of point coordinates */
+  realT MINdenom_1;       /* min. abs. value for 1/x */
+  realT MINdenom;         /*    use divzero if denominator < MINdenom */
+  realT MINdenom_1_2;     /* min. abs. val for 1/x that allows normalization */
+  realT MINdenom_2;       /*    use divzero if denominator < MINdenom_2 */
+  realT MINlastcoord;     /* min. last coordinate for qh_scalelast */
+  boolT NARROWhull;       /* set in qh_initialhull if angle < qh_MAXnarrow */
+  realT *NEARzero;        /* hull_dim array for near zero in gausselim */
+  realT NEARinside;       /* keep points for qh_check_maxout if close to facet */
+  realT ONEmerge;         /* max distance for merging simplicial facets */
+  realT outside_err;      /* application's epsilon for coplanar points
+                             qh_check_bestdist() qh_check_points() reports error if point outside */
+  realT WIDEfacet;        /* size of wide facet for skipping ridge in
+			     area computation and locking centrum */
+  
+/*----------------------------------
+
+  qh internal constants
+    internal constants for Qhull
+*/
+  char qhull[sizeof("qhull")]; /* for checking ownership */
+  void *old_stat;         /* pointer to saved qh_qhstat, qh_save_qhull */
+  jmp_buf errexit;        /* exit label for qh_errexit, defined by setjmp() */
+  char jmpXtra[40];       /* extra bytes in case jmp_buf is defined wrong by compiler */
+  jmp_buf restartexit;    /* restart label for qh_errexit, defined by setjmp() */
+  char jmpXtra2[40];      /* extra bytes in case jmp_buf is defined wrong by compiler*/
+  FILE *fin;              /* pointer to input file, init by qh_meminit */
+  FILE *fout;             /* pointer to output file */
+  FILE *ferr;             /* pointer to error file */
+  pointT *interior_point; /* center point of the initial simplex*/
+  int   normal_size;      /* size in bytes for facet normals and point coords*/
+  int   center_size;      /* size in bytes for Voronoi centers */
+  int   TEMPsize;         /* size for small, temporary sets (in quick mem) */
+
+/*----------------------------------
+
+  qh facet and vertex lists
+    defines lists of facets, new facets, visible facets, vertices, and
+    new vertices.  Includes counts, next ids, and trace ids.
+  see:
+    qh_resetlists()
+*/
+  facetT *facet_list;     /* first facet */
+  facetT  *facet_tail;     /* end of facet_list (dummy facet) */
+  facetT *facet_next;     /* next facet for buildhull()
+    			     previous facets do not have outside sets
+                             NARROWhull: previous facets may have coplanar outside sets for qh_outcoplanar */
+  facetT *newfacet_list;  /* list of new facets to end of facet_list */
+  facetT *visible_list;   /* list of visible facets preceeding newfacet_list,
+                             facet->visible set */
+  int       num_visible;  /* current number of visible facets */
+  unsigned tracefacet_id;  /* set at init, then can print whenever */
+  facetT *tracefacet;     /*   set in newfacet/mergefacet, undone in delfacet*/
+  unsigned tracevertex_id;  /* set at buildtracing, can print whenever */
+  vertexT *tracevertex;     /*   set in newvertex, undone in delvertex*/
+  vertexT *vertex_list;     /* list of all vertices, to vertex_tail */
+  vertexT  *vertex_tail;    /*      end of vertex_list (dummy vertex) */
+  vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail
+                             all vertices have 'newlist' set */
+  int 	num_facets;	  /* number of facets in facet_list
+			     includes visble faces (num_visible) */
+  int 	num_vertices;     /* number of vertices in facet_list */
+  int   num_outside;      /* number of points in outsidesets (for tracing and RANDOMoutside)
+                               includes coplanar outsideset points for NARROWhull/qh_outcoplanar() */
+  int   num_good;         /* number of good facets (after findgood_all) */
+  unsigned facet_id;      /* ID of next, new facet from newfacet() */
+  unsigned ridge_id;      /* ID of next, new ridge from newridge() */
+  unsigned vertex_id;     /* ID of next, new vertex from newvertex() */
+
+/*----------------------------------
+
+  qh global variables
+    defines minimum and maximum distances, next visit ids, several flags,
+    and other global variables.
+    initialize in qh_initbuild or qh_maxmin if used in qh_buildhull
+*/
+  unsigned long hulltime; /* ignore time to set up input and randomize */
+                          /*   use unsigned to avoid wrap-around errors */
+  boolT ALLOWrestart;     /* true if qh_precision can use qh.restartexit */
+  int   build_cnt;        /* number of calls to qh_initbuild */
+  qh_CENTER CENTERtype;   /* current type of facet->center, qh_CENTER */
+  int 	furthest_id;      /* pointid of furthest point, for tracing */
+  facetT *GOODclosest;    /* closest facet to GOODthreshold in qh_findgood */
+  realT JOGGLEmax;        /* set 'QJn' if randomly joggle input */
+  boolT maxoutdone;       /* set qh_check_maxout(), cleared by qh_addpoint() */
+  realT max_outside;      /* maximum distance from a point to a facet,
+			       before roundoff, not simplicial vertices
+			       actual outer plane is +DISTround and
+			       computed outer plane is +2*DISTround */
+  realT max_vertex;       /* maximum distance (>0) from vertex to a facet,
+			       before roundoff, due to a merge */
+  realT min_vertex;       /* minimum distance (<0) from vertex to a facet,
+			       before roundoff, due to a merge
+			       if qh.JOGGLEmax, qh_makenewplanes sets it
+  			       recomputed if qh.DOcheckmax, default -qh.DISTround */
+  boolT NEWfacets;        /* true while visible facets invalid due to new or merge
+			      from makecone/attachnewfacets to deletevisible */
+  boolT findbestnew;	  /* true if partitioning calls qh_findbestnew */
+  boolT findbest_notsharp; /* true if new facets are at least 90 degrees */
+  boolT NOerrexit;        /* true if qh.errexit is not available */
+  realT PRINTcradius;     /* radius for printing centrums */
+  realT PRINTradius;      /* radius for printing vertex spheres and points */
+  boolT POSTmerging;      /* true when post merging */
+  int 	printoutvar;	  /* temporary variable for qh_printbegin, etc. */
+  int 	printoutnum;	  /* number of facets printed */
+  boolT QHULLfinished;    /* True after qhull() is finished */
+  realT totarea;          /* 'FA': total facet area computed by qh_getarea */
+  realT totvol;           /* 'FA': total volume computed by qh_getarea */
+  unsigned int visit_id;  /* unique ID for searching neighborhoods, */
+  unsigned int vertex_visit; /* unique ID for searching vertices */
+  boolT ZEROall_ok;       /* True if qh_checkzero always succeeds */
+  boolT WAScoplanar;      /* True if qh_partitioncoplanar (qh_check_maxout) */
+  
+/*----------------------------------
+
+  qh global sets
+    defines sets for merging, initial simplex, hashing, extra input points,
+    and deleted vertices
+*/
+  setT *facet_mergeset;   /* temporary set of merges to be done */
+  setT *degen_mergeset;   /* temporary set of degenerate and redundant merges */
+  setT *hash_table;	  /* hash table for matching ridges in qh_matchfacets
+                             size is setsize() */
+  setT *other_points;     /* additional points (first is qh interior_point) */
+  setT *del_vertices;     /* vertices to partition and delete with visible
+                             facets.  Have deleted set for checkfacet */
+
+/*----------------------------------
+
+  qh global buffers
+    defines buffers for maxtrix operations, input, and error messages
+*/
+  coordT *gm_matrix;      /* (dim+1)Xdim matrix for geom.c */
+  coordT **gm_row;        /* array of gm_matrix rows */
+  char* line;             /* malloc'd input line of maxline+1 chars */
+  int maxline;
+  coordT *half_space;     /* malloc'd input array for halfspace (qh normal_size+coordT) */
+  coordT *temp_malloc;    /* malloc'd input array for points */
+  
+/*----------------------------------
+
+  qh static variables
+    defines static variables for individual functions
+
+  notes:
+    do not use 'static' within a function.  Multiple instances of qhull
+    may exist.
+
+    do not assume zero initialization, 'QPn' may cause a restart
+*/
+  boolT ERREXITcalled;    /* true during errexit (prevents duplicate calls */
+  boolT firstcentrum; 	  /* for qh_printcentrum */
+  realT last_low;         /* qh_scalelast parameters for qh_setdelaunay */
+  realT last_high;
+  realT last_newhigh;
+  unsigned lastreport;    /* for qh_buildtracing */
+  int mergereport;        /* for qh_tracemerging */
+  boolT old_randomdist;   /* save RANDOMdist when io, tracing, or statistics */
+  int   ridgeoutnum;      /* number of ridges in 4OFF output */
+  void *old_qhstat;       /* for saving qh_qhstat in save_qhull() */
+  setT *old_tempstack;     /* for saving qhmem.tempstack in save_qhull */
+  setT *coplanarset;      /* set of coplanar facets for searching qh_findbesthorizon() */
+};
+
+/*=========== -macros- =========================*/
+
+/*----------------------------------
+
+  otherfacet_(ridge, facet)
+    return neighboring facet for a ridge in facet
+*/
+#define otherfacet_(ridge, facet) \
+                        (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top)
+
+/*----------------------------------
+
+  getid_(p)
+    return ID for facet, ridge, or vertex
+    return MAXINT if NULL (-1 causes type conversion error )
+*/
+#define getid_(p)       ((p) ? (p)->id : -1)
+
+/*============== FORALL macros ===================*/
+
+/*----------------------------------
+
+  FORALLfacets { ... }
+    assign 'facet' to each facet in qh.facet_list
+
+  notes:
+    uses 'facetT *facet;'
+    assumes last facet is a sentinel
+
+  see:
+    FORALLfacet_( facetlist )
+*/
+#define FORALLfacets for (facet=qh facet_list;facet && facet->next;facet=facet->next)
+
+/*----------------------------------
+
+  FORALLpoints { ... }
+    assign 'point' to each point in qh.first_point, qh.num_points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoints FORALLpoint_(qh first_point, qh num_points)
+
+/*----------------------------------
+
+  FORALLpoint_( points, num) { ... }
+    assign 'point' to each point in points array of num points
+
+  declare:
+    coordT *point, *pointtemp;
+*/
+#define FORALLpoint_(points, num) for(point= (points), \
+      pointtemp= (points)+qh hull_dim*(num); point < pointtemp; point += qh hull_dim)
+
+/*----------------------------------
+
+  FORALLvertices { ... }
+    assign 'vertex' to each vertex in qh.vertex_list
+
+  declare:
+    vertexT *vertex;
+
+  notes:
+    assumes qh.vertex_list terminated with a sentinel
+*/
+#define FORALLvertices for (vertex=qh vertex_list;vertex && vertex->next;vertex= vertex->next)
+
+/*----------------------------------
+
+  FOREACHfacet_( facets ) { ... }
+    assign 'facet' to each facet in facets
+
+  declare:
+    facetT *facet, **facetp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHfacet_(facets)    FOREACHsetelement_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_( facet ) { ... }
+    assign 'neighbor' to each neighbor in facet->neighbors
+
+  FOREACHneighbor_( vertex ) { ... }
+    assign 'neighbor' to each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor, **neighborp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHneighbor_(facet)  FOREACHsetelement_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_( points ) { ... }
+    assign 'point' to each point in points set
+
+  declare:
+    pointT *point, **pointp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHpoint_(points)    FOREACHsetelement_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_( ridges ) { ... }
+    assign 'ridge' to each ridge in ridges set
+
+  declare:
+    ridgeT *ridge, **ridgep;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHridge_(ridges)    FOREACHsetelement_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_( vertices ) { ... }
+    assign 'vertex' to each vertex in vertices set
+
+  declare:
+    vertexT *vertex, **vertexp;
+
+  see:
+    FOREACHsetelement_
+*/
+#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex)
+
+/*----------------------------------
+
+  FOREACHfacet_i_( facets ) { ... }
+    assign 'facet' and 'facet_i' for each facet in facets set
+
+  declare:
+    facetT *facet;
+    int     facet_n, facet_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHfacet_i_(facets)    FOREACHsetelement_i_(facetT, facets, facet)
+
+/*----------------------------------
+
+  FOREACHneighbor_i_( facet ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors
+
+  FOREACHneighbor_i_( vertex ) { ... }
+    assign 'neighbor' and 'neighbor_i' for each neighbor in vertex->neighbors
+
+  declare:
+    facetT *neighbor;
+    int     neighbor_n, neighbor_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHneighbor_i_(facet)  FOREACHsetelement_i_(facetT, facet->neighbors, neighbor)
+
+/*----------------------------------
+
+  FOREACHpoint_i_( points ) { ... }
+    assign 'point' and 'point_i' for each point in points set
+
+  declare:
+    pointT *point;
+    int     point_n, point_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHpoint_i_(points)    FOREACHsetelement_i_(pointT, points, point)
+
+/*----------------------------------
+
+  FOREACHridge_i_( ridges ) { ... }
+    assign 'ridge' and 'ridge_i' for each ridge in ridges set
+
+  declare:
+    ridgeT *ridge;
+    int     ridge_n, ridge_i;
+
+  see:
+    FOREACHsetelement_i_
+*/
+#define FOREACHridge_i_(ridges)    FOREACHsetelement_i_(ridgeT, ridges, ridge)
+
+/*----------------------------------
+
+  FOREACHvertex_i_( vertices ) { ... }
+    assign 'vertex' and 'vertex_i' for each vertex in vertices set
+
+  declare:
+    vertexT *vertex;
+    int     vertex_n, vertex_i;
+
+  see:
+    FOREACHsetelement_i_
+ */
+#define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices,vertex)
+
+/********* -qhull.c prototypes (duplicated from qhull_a.h) **********************/
+
+void    qh_qhull (void);
+boolT   qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist);
+void	qh_printsummary(FILE *fp);
+
+/********* -user.c prototypes (alphabetical) **********************/
+
+void 	qh_errexit(int exitcode, facetT *facet, ridgeT *ridge);
+void 	qh_errprint(char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex);
+int     qh_new_qhull (int dim, int numpoints, coordT *points, boolT ismalloc,
+		char *qhull_cmd, FILE *outfile, FILE *errfile);
+void    qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall);
+void 	qh_user_memsizes (void);
+
+/***** -geom.c/geom2.c prototypes (duplicated from geom.h) ****************/
+
+facetT *qh_findbest (pointT *point, facetT *startfacet,
+		     boolT bestoutside, boolT newfacets, boolT noupper,
+		     realT *dist, boolT *isoutside, int *numpart);
+facetT *qh_findbestnew (pointT *point, facetT *startfacet,
+                     realT *dist, boolT bestoutside, boolT *isoutside, int *numpart);
+boolT   qh_gram_schmidt(int dim, realT **rows);
+void    qh_outerinner (facetT *facet, realT *outerplane, realT *innerplane);
+void	qh_printsummary(FILE *fp);
+void    qh_projectinput (void);
+void    qh_randommatrix (realT *buffer, int dim, realT **row);
+void    qh_rotateinput (realT **rows);
+void    qh_scaleinput (void);
+void    qh_setdelaunay (int dim, int count, pointT *points);
+coordT  *qh_sethalfspace_all (int dim, int count, coordT *halfspaces, pointT *feasible);
+
+/***** -global.c prototypes (alphabetical) ***********************/
+
+unsigned long qh_clock (void);
+void 	qh_checkflags (char *command, char *hiddenflags);
+void 	qh_freebuffers (void);
+void    qh_freeqhull (boolT allmem);
+void    qh_init_A (FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]);
+void    qh_init_B (coordT *points, int numpoints, int dim, boolT ismalloc);
+void 	qh_init_qhull_command (int argc, char *argv[]);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+void 	qh_initflags (char *command);
+void 	qh_initqhull_buffers (void);
+void 	qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc);
+void    qh_initqhull_mem (void);
+void 	qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile);
+void 	qh_initthresholds (char *command);
+void    qh_option (char *option, int *i, realT *r);
+#if qh_QHpointer
+void 	qh_restore_qhull (qhT **oldqh);
+qhT    *qh_save_qhull (void);
+#endif
+
+/***** -io.c prototypes (duplicated from io.h) ***********************/
+
+void    dfacet( unsigned id);
+void    dvertex( unsigned id);
+void	qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall);
+void	qh_produce_output(void);
+coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
+
+
+/********* -mem.c prototypes (duplicated from mem.h) **********************/
+
+void qh_meminit (FILE *ferr);
+void qh_memfreeshort (int *curlong, int *totlong);
+
+/********* -poly.c/poly2.c prototypes (duplicated from poly.h) **********************/
+
+void    qh_check_output (void);
+void    qh_check_points (void);
+setT   *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets);
+facetT *qh_findbestfacet (pointT *point, boolT bestoutside,
+           realT *bestdist, boolT *isoutside);
+vertexT *qh_nearvertex (facetT *facet, pointT *point, realT *bestdistp);
+pointT *qh_point (int id);
+setT   *qh_pointfacet (void /*qh.facet_list*/);
+int     qh_pointid (pointT *point);
+setT   *qh_pointvertex (void /*qh.facet_list*/);
+void    qh_setvoronoi_all (void);
+void	qh_triangulate (void /*qh facet_list*/);
+
+/********* -stat.c prototypes (duplicated from stat.h) **********************/
+
+void    qh_collectstatistics (void);
+void    qh_printallstatistics (FILE *fp, char *string);
+
+#endif /* qhDEFqhull */
diff --git a/extern/qhull/src/qhull_a.h b/extern/qhull/src/qhull_a.h
new file mode 100644
index 00000000000..d4e69b071be
--- /dev/null
+++ b/extern/qhull/src/qhull_a.h
@@ -0,0 +1,127 @@
+/*
  ---------------------------------
+
+   qhull_a.h 
+   all header files for compiling qhull
+
+   see qh-qhull.htm
+
+   see qhull.h for user-level definitions
+   
+   see user.h for user-defineable constants
+   
+   defines internal functions for qhull.c global.c
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   Notes:  grep for ((" and (" to catch fprintf("lkasdjf");
+           full parens around (x?y:z)
+	   use '#include qhull/qhull_a.h' to avoid name clashes
+*/
+
+#ifndef qhDEFqhulla
+#define qhDEFqhulla
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include     /* some compilers will not need float.h */
+#include 
+#include 
+#include 
+/*** uncomment here and qset.c
+     if string.h does not define memcpy()
+#include 
+*/
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+#include "geom.h"
+#include "merge.h"
+#include "poly.h"
+#include "io.h"
+#include "stat.h"
+
+#if qh_CLOCKtype == 2  /* defined in user.h from qhull.h */
+#include 
+#include 
+#include 
+#endif
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ */
+#pragma warning( disable : 4056)  /* float constant expression.  Looks like a compiler bug */
+#pragma warning( disable : 4146)  /* unary minus applied to unsigned type */
+#pragma warning( disable : 4244)  /* conversion from 'unsigned long' to 'real' */
+#pragma warning( disable : 4305)  /* conversion from 'const double' to 'float' */
+#endif
+
+/* ======= -macros- =========== */
+
+/*----------------------------------
+  
+  traceN((fp.ferr, "format\n", vars));  
+    calls fprintf if qh.IStracing >= N
+  
+  notes:
+    removing tracing reduces code size but doesn't change execution speed
+*/
+#ifndef qh_NOtrace
+#define trace0(args) {if (qh IStracing) fprintf args;}
+#define trace1(args) {if (qh IStracing >= 1) fprintf args;}
+#define trace2(args) {if (qh IStracing >= 2) fprintf args;}
+#define trace3(args) {if (qh IStracing >= 3) fprintf args;}
+#define trace4(args) {if (qh IStracing >= 4) fprintf args;}
+#define trace5(args) {if (qh IStracing >= 5) fprintf args;}
+#else /* qh_NOtrace */
+#define trace0(args) {}
+#define trace1(args) {}
+#define trace2(args) {}
+#define trace3(args) {}
+#define trace4(args) {}
+#define trace5(args) {}
+#endif /* qh_NOtrace */
+
+/***** -qhull.c prototypes (alphabetical after qhull) ********************/
+
+void 	qh_qhull (void);
+boolT   qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist);
+void 	qh_buildhull(void);
+void    qh_buildtracing (pointT *furthest, facetT *facet);
+void    qh_build_withrestart (void);
+void 	qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet);
+void    qh_findhorizon(pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
+pointT *qh_nextfurthest (facetT **visible);
+void 	qh_partitionall(setT *vertices, pointT *points,int npoints);
+void    qh_partitioncoplanar (pointT *point, facetT *facet, realT *dist);
+void    qh_partitionpoint (pointT *point, facetT *facet);
+void 	qh_partitionvisible(boolT allpoints, int *numpoints);
+void    qh_precision (char *reason);
+void	qh_printsummary(FILE *fp);
+
+/***** -global.c internal prototypes (alphabetical) ***********************/
+
+void    qh_appendprint (qh_PRINT format);
+void 	qh_freebuild (boolT allmem);
+void 	qh_freebuffers (void);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+int     qh_strtol (const char *s, char **endp);
+double  qh_strtod (const char *s, char **endp);
+
+/***** -stat.c internal prototypes (alphabetical) ***********************/
+
+void	qh_allstatA (void);
+void	qh_allstatB (void);
+void	qh_allstatC (void);
+void	qh_allstatD (void);
+void	qh_allstatE (void);
+void	qh_allstatE2 (void);
+void	qh_allstatF (void);
+void	qh_allstatG (void);
+void	qh_allstatH (void);
+void 	qh_freebuffers (void);
+void    qh_initbuffers (coordT *points, int numpoints, int dim, boolT ismalloc);
+
+#endif /* qhDEFqhulla */
diff --git a/extern/qhull/src/qhull_interface.cpp b/extern/qhull/src/qhull_interface.cpp
new file mode 100644
index 00000000000..6ecc640e82b
--- /dev/null
+++ b/extern/qhull/src/qhull_interface.cpp
@@ -0,0 +1,96 @@
+/*
  ---------------------------------
+*/
+
+#include 
+#include 
+
+//--- Include qhull, so it works from with in a C++ source file
+//---
+//--- In MVC one cannot just do:
+//---
+//---    extern "C"
+//---    {
+//---      #include "qhull_a.h"
+//---    }
+//---
+//--- Because qhull_a.h includes math.h, which can not appear
+//--- inside a extern "C" declaration.
+//---
+//--- Maybe that why Numerical recipes in C avoid this problem, by removing
+//--- standard include headers from its header files and add them in the
+//--- respective source files instead.
+//---
+//--- [K. Erleben]
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#if defined(__cplusplus)
+}
+#endif
+
+/*********************************************************************/
+/*                                                                   */
+/*                                                                   */
+/*                                                                   */
+/*                                                                   */
+/*********************************************************************/
+
+void compute_convex_hull(void)
+{  
+	int dim;  	              /* dimension of points */
+	int numpoints;            /* number of points */
+	coordT *points;           /* array of coordinates for each point */ 
+	boolT ismalloc;           /* True if qhull should free points in qh_freeqhull() or reallocation */ 
+	char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */
+	FILE *outfile= stdout;    /* output from qh_produce_output()			
+	                             use NULL to skip qh_produce_output() */ 
+	FILE *errfile= stderr;    /* error messages from qhull code */ 
+	int exitcode;             /* 0 if no error from qhull */
+	facetT *facet;	          /* set by FORALLfacets */
+	int curlong, totlong;	  /* memory remaining after qh_memfreeshort */
+
+   	/* initialize dim, numpoints, points[], ismalloc here */
+	exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+							flags, outfile, errfile);
+	if (!exitcode) { /* if no error */ 
+		/* 'qh facet_list' contains the convex hull */
+		FORALLfacets {
+			/* ... your code ... */ 
+		}
+	}
+	qh_freeqhull(!qh_ALL);  
+	qh_memfreeshort (&curlong, &totlong);
+	if (curlong || totlong)
+		fprintf (errfile, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n", 
+		             totlong, curlong);
+};
+
+/*********************************************************************/
+/*                                                                   */
+/*                                                                   */
+/*                                                                   */
+/*                                                                   */
+/*********************************************************************/
+
+void main() 
+{ 
+	cout << "Hello world" << endl;
+	
+	cout << "Press any key..." << endl;  
+	
+	while(!_kbhit());
+
+};
diff --git a/extern/qhull/src/qset.c b/extern/qhull/src/qset.c
new file mode 100644
index 00000000000..9e78464c07e
--- /dev/null
+++ b/extern/qhull/src/qset.c
@@ -0,0 +1,1301 @@
+/*
  ---------------------------------
+
+   qset.c 
+   implements set manipulations needed for quickhull 
+
+   see qh-set.htm and qset.h
+
+   copyright (c) 1993-2002 The Geometry Center        
+*/
+
+#include 
+#include 
+/*** uncomment here and qhull_a.h 
+     if string.h does not define memcpy()
+#include 
+*/
+#include "qset.h"
+#include "mem.h"
+
+#ifndef qhDEFqhull
+typedef struct ridgeT ridgeT;
+typedef struct facetT facetT;
+void    qh_errexit(int exitcode, facetT *, ridgeT *);
+#endif
+
+/*=============== internal macros ===========================*/
+
+/*---------------------------------
+   
+  SETsizeaddr_(set) 
+    return pointer to actual size+1 of set (set CANNOT be NULL!!)
+      
+  notes:
+    *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
+*/
+#define SETsizeaddr_(set) (&((set)->e[(set)->maxsize].i))
+
+/*============ functions in alphabetical order ===================*/
+  
+/*----------------------------------
+   
+  qh_setaddnth( setp, nth, newelem)
+    adds newelem as n'th element of sorted or unsorted *setp
+      
+  notes:
+    *setp and newelem must be defined
+    *setp may be a temp set
+    nth=0 is first element
+    errors if nth is out of bounds
+   
+  design:
+    expand *setp if empty or full
+    move tail of *setp up one
+    insert newelem
+*/
+void qh_setaddnth(setT **setp, int nth, void *newelem) {
+  int *sizep, oldsize, i;
+  void **oldp, **newp;
+
+  if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+    qh_setlarger(setp);
+    sizep= SETsizeaddr_(*setp);
+  }
+  oldsize= *sizep - 1;
+  if (nth < 0 || nth > oldsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint (qhmem.ferr, "", *setp);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  (*sizep)++;
+  oldp= SETelemaddr_(*setp, oldsize, void);   /* NULL */
+  newp= oldp+1;
+  for (i= oldsize-nth+1; i--; )  /* move at least NULL  */
+    *(newp--)= *(oldp--);       /* may overwrite *sizep */
+  *newp= newelem;
+} /* setaddnth */
+
+
+/*----------------------------------
+   
+  setaddsorted( setp, newelem )
+    adds an newelem into sorted *setp
+      
+  notes:
+    *setp and newelem must be defined
+    *setp may be a temp set
+    nop if newelem already in set
+  
+  design:
+    find newelem's position in *setp
+    insert newelem
+*/
+void qh_setaddsorted(setT **setp, void *newelem) {
+  int newindex=0;
+  void *elem, **elemp;
+
+  FOREACHelem_(*setp) {          /* could use binary search instead */
+    if (elem < newelem)
+      newindex++;
+    else if (elem == newelem)
+      return;
+    else
+      break;
+  }
+  qh_setaddnth(setp, newindex, newelem);
+} /* setaddsorted */
+
+
+/*---------------------------------
+  
+  qh_setappend( setp, newelem)
+    append newelem to *setp
+
+  notes:
+    *setp may be a temp set
+    *setp and newelem may be NULL
+
+  design:
+    expand *setp if empty or full
+    append newelem to *setp
+    
+*/
+void qh_setappend(setT **setp, void *newelem) {
+  int *sizep;
+  void **endp;
+
+  if (!newelem)
+    return;
+  if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+    qh_setlarger(setp);
+    sizep= SETsizeaddr_(*setp);
+  }
+  *(endp= &((*setp)->e[(*sizep)++ - 1].p))= newelem;
+  *(++endp)= NULL;
+} /* setappend */
+
+/*---------------------------------
+  
+  qh_setappend_set( setp, setA) 
+    appends setA to *setp
+
+  notes:
+    *setp can not be a temp set
+    *setp and setA may be NULL
+
+  design:
+    setup for copy
+    expand *setp if it is too small
+    append all elements of setA to *setp 
+*/
+void qh_setappend_set(setT **setp, setT *setA) {
+  int *sizep, sizeA, size;
+  setT *oldset;
+
+  if (!setA)
+    return;
+  SETreturnsize_(setA, sizeA);
+  if (!*setp)
+    *setp= qh_setnew (sizeA);
+  sizep= SETsizeaddr_(*setp);
+  if (!(size= *sizep))
+    size= (*setp)->maxsize;
+  else
+    size--;
+  if (size + sizeA > (*setp)->maxsize) {
+    oldset= *setp;
+    *setp= qh_setcopy (oldset, sizeA);
+    qh_setfree (&oldset);
+    sizep= SETsizeaddr_(*setp);
+  }
+  *sizep= size+sizeA+1;   /* memcpy may overwrite */
+  if (sizeA > 0) 
+    memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), SETelemsize *(sizeA+1));
+} /* setappend_set */
+
+
+/*---------------------------------
+  
+  qh_setappend2ndlast( setp, newelem )
+    makes newelem the next to the last element in *setp
+
+  notes:
+    *setp must have at least one element
+    newelem must be defined
+    *setp may be a temp set
+
+  design:
+    expand *setp if empty or full
+    move last element of *setp up one
+    insert newelem
+*/
+void qh_setappend2ndlast(setT **setp, void *newelem) {
+  int *sizep;
+  void **endp, **lastp;
+  
+  if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
+    qh_setlarger(setp);
+    sizep= SETsizeaddr_(*setp);
+  }
+  endp= SETelemaddr_(*setp, (*sizep)++ -1, void); /* NULL */
+  lastp= endp-1;
+  *(endp++)= *lastp;
+  *endp= NULL;    /* may overwrite *sizep */
+  *lastp= newelem;
+} /* setappend2ndlast */
+
+
+/*---------------------------------
+  
+  qh_setcheck( set, typename, id ) 
+    check set for validity
+    report errors with typename and id
+
+  design:
+    checks that maxsize, actual size, and NULL terminator agree
+*/
+void qh_setcheck(setT *set, char *tname, int id) {
+  int maxsize, size;
+  int waserr= 0;
+
+  if (!set)
+    return;
+  SETreturnsize_(set, size);
+  maxsize= set->maxsize;
+  if (size > maxsize || !maxsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
+	     size, tname, id, maxsize);
+    waserr= 1;
+  }else if (set->e[size].p) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setcheck): %s%d (size %d max %d) is not null terminated.\n",
+	     tname, id, maxsize, size-1);
+    waserr= 1;
+  }
+  if (waserr) {
+    qh_setprint (qhmem.ferr, "ERRONEOUS", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+} /* setcheck */
+
+
+/*---------------------------------
+  
+  qh_setcompact( set )
+    remove internal NULLs from an unsorted set
+
+  returns:
+    updated set
+
+  notes:
+    set may be NULL
+    it would be faster to swap tail of set into holes, like qh_setdel
+
+  design:
+    setup pointers into set
+    skip NULLs while copying elements to start of set 
+    update the actual size
+*/
+void qh_setcompact(setT *set) {
+  int size;
+  void **destp, **elemp, **endp, **firstp;
+
+  if (!set)
+    return;
+  SETreturnsize_(set, size);
+  destp= elemp= firstp= SETaddr_(set, void);
+  endp= destp + size;
+  while (1) {
+    if (!(*destp++ = *elemp++)) {
+      destp--;
+      if (elemp > endp)
+	break;
+    }
+  }
+  qh_settruncate (set, destp-firstp);
+} /* setcompact */
+
+
+/*---------------------------------
+  
+  qh_setcopy( set, extra )
+    make a copy of a sorted or unsorted set with extra slots
+
+  returns:
+    new set
+
+  design:
+    create a newset with extra slots
+    copy the elements to the newset
+    
+*/
+setT *qh_setcopy(setT *set, int extra) {
+  setT *newset;
+  int size;
+
+  if (extra < 0)
+    extra= 0;
+  SETreturnsize_(set, size);
+  newset= qh_setnew(size+extra);
+  *SETsizeaddr_(newset)= size+1;    /* memcpy may overwrite */
+  memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), SETelemsize *(size+1));
+  return (newset);
+} /* setcopy */
+
+
+/*---------------------------------
+  
+  qh_setdel( set, oldelem )
+    delete oldelem from an unsorted set
+
+  returns:
+    returns oldelem if found
+    returns NULL otherwise
+    
+  notes:
+    set may be NULL
+    oldelem must not be NULL;
+    only deletes one copy of oldelem in set
+     
+  design:
+    locate oldelem
+    update actual size if it was full
+    move the last element to the oldelem's location
+*/
+void *qh_setdel(setT *set, void *oldelem) {
+  void **elemp, **lastp;
+  int *sizep;
+
+  if (!set)
+    return NULL;
+  elemp= SETaddr_(set, void);
+  while (*elemp != oldelem && *elemp)
+    elemp++;
+  if (*elemp) {
+    sizep= SETsizeaddr_(set);
+    if (!(*sizep)--)         /*  if was a full set */
+      *sizep= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
+    lastp= SETelemaddr_(set, *sizep-1, void);
+    *elemp= *lastp;      /* may overwrite itself */
+    *lastp= NULL;
+    return oldelem;
+  }
+  return NULL;
+} /* setdel */
+
+
+/*---------------------------------
+  
+  qh_setdellast( set) 
+    return last element of set or NULL
+
+  notes:
+    deletes element from set
+    set may be NULL
+
+  design:
+    return NULL if empty
+    if full set
+      delete last element and set actual size
+    else
+      delete last element and update actual size 
+*/
+void *qh_setdellast(setT *set) {
+  int setsize;  /* actually, actual_size + 1 */
+  int maxsize;
+  int *sizep;
+  void *returnvalue;
+  
+  if (!set || !(set->e[0].p))
+    return NULL;
+  sizep= SETsizeaddr_(set);
+  if ((setsize= *sizep)) {
+    returnvalue= set->e[setsize - 2].p;
+    set->e[setsize - 2].p= NULL;
+    (*sizep)--;
+  }else {
+    maxsize= set->maxsize;
+    returnvalue= set->e[maxsize - 1].p;
+    set->e[maxsize - 1].p= NULL;
+    *sizep= maxsize;
+  }
+  return returnvalue;
+} /* setdellast */
+
+
+/*---------------------------------
+  
+  qh_setdelnth( set, nth )
+    deletes nth element from unsorted set 
+    0 is first element
+
+  returns:
+    returns the element (needs type conversion)
+
+  notes:
+    errors if nth invalid
+
+  design:
+    setup points and check nth
+    delete nth element and overwrite with last element
+*/
+void *qh_setdelnth(setT *set, int nth) {
+  void **elemp, **lastp, *elem;
+  int *sizep;
+
+
+  elemp= SETelemaddr_(set, nth, void);
+  sizep= SETsizeaddr_(set);
+  if (!(*sizep)--)         /*  if was a full set */
+    *sizep= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
+  if (nth < 0 || nth >= *sizep) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  lastp= SETelemaddr_(set, *sizep-1, void);
+  elem= *elemp;
+  *elemp= *lastp;      /* may overwrite itself */
+  *lastp= NULL;
+  return elem;
+} /* setdelnth */
+
+/*---------------------------------
+  
+  qh_setdelnthsorted( set, nth )
+    deletes nth element from sorted set
+
+  returns:
+    returns the element (use type conversion)
+  
+  notes:
+    errors if nth invalid
+    
+  see also: 
+    setnew_delnthsorted
+
+  design:
+    setup points and check nth
+    copy remaining elements down one
+    update actual size  
+*/
+void *qh_setdelnthsorted(setT *set, int nth) {
+  void **newp, **oldp, *elem;
+  int *sizep;
+
+  sizep= SETsizeaddr_(set);
+  if (nth < 0 || (*sizep && nth >= *sizep-1) || nth >= set->maxsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  newp= SETelemaddr_(set, nth, void);
+  elem= *newp;
+  oldp= newp+1;
+  while ((*(newp++)= *(oldp++)))
+    ; /* copy remaining elements and NULL */
+  if (!(*sizep)--)         /*  if was a full set */
+    *sizep= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
+  return elem;
+} /* setdelnthsorted */
+
+
+/*---------------------------------
+  
+  qh_setdelsorted( set, oldelem )
+    deletes oldelem from sorted set
+
+  returns:
+    returns oldelem if it was deleted
+  
+  notes:
+    set may be NULL
+
+  design:
+    locate oldelem in set
+    copy remaining elements down one
+    update actual size  
+*/
+void *qh_setdelsorted(setT *set, void *oldelem) {
+  void **newp, **oldp;
+  int *sizep;
+
+  if (!set)
+    return NULL;
+  newp= SETaddr_(set, void);
+  while(*newp != oldelem && *newp)
+    newp++;
+  if (*newp) {
+    oldp= newp+1;
+    while ((*(newp++)= *(oldp++)))
+      ; /* copy remaining elements */
+    sizep= SETsizeaddr_(set);
+    if (!(*sizep)--)    /*  if was a full set */
+      *sizep= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
+    return oldelem;
+  }
+  return NULL;
+} /* setdelsorted */
+
+
+/*---------------------------------
+  
+  qh_setduplicate( set, elemsize )
+    duplicate a set of elemsize elements
+
+  notes:
+    use setcopy if retaining old elements
+
+  design:
+    create a new set
+    for each elem of the old set
+      create a newelem
+      append newelem to newset
+*/
+setT *qh_setduplicate (setT *set, int elemsize) {
+  void		*elem, **elemp, *newElem;
+  setT		*newSet;
+  int		size;
+  
+  if (!(size= qh_setsize (set)))
+    return NULL;
+  newSet= qh_setnew (size);
+  FOREACHelem_(set) {
+    newElem= qh_memalloc (elemsize);
+    memcpy (newElem, elem, elemsize);
+    qh_setappend (&newSet, newElem);
+  }
+  return newSet;
+} /* setduplicate */
+
+
+/*---------------------------------
+  
+  qh_setequal(  )
+    returns 1 if two sorted sets are equal, otherwise returns 0
+
+  notes:
+    either set may be NULL
+
+  design:
+    check size of each set
+    setup pointers
+    compare elements of each set
+*/
+int qh_setequal(setT *setA, setT *setB) {
+  void **elemAp, **elemBp;
+  int sizeA, sizeB;
+  
+  SETreturnsize_(setA, sizeA);
+  SETreturnsize_(setB, sizeB);
+  if (sizeA != sizeB)
+    return 0;
+  if (!sizeA)
+    return 1;
+  elemAp= SETaddr_(setA, void);
+  elemBp= SETaddr_(setB, void);
+  if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))
+    return 1;
+  return 0;
+} /* setequal */
+
+
+/*---------------------------------
+  
+  qh_setequal_except( setA, skipelemA, setB, skipelemB )
+    returns 1 if sorted setA and setB are equal except for skipelemA & B
+
+  returns:
+    false if either skipelemA or skipelemB are missing
+  
+  notes:
+    neither set may be NULL
+
+    if skipelemB is NULL, 
+      can skip any one element of setB
+
+  design:
+    setup pointers
+    search for skipelemA, skipelemB, and mismatches
+    check results
+*/
+int qh_setequal_except (setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
+  void **elemA, **elemB;
+  int skip=0;
+
+  elemA= SETaddr_(setA, void);
+  elemB= SETaddr_(setB, void);
+  while (1) {
+    if (*elemA == skipelemA) {
+      skip++;
+      elemA++;
+    }
+    if (skipelemB) {
+      if (*elemB == skipelemB) {
+        skip++;
+        elemB++;
+      }
+    }else if (*elemA != *elemB) {
+      skip++;
+      if (!(skipelemB= *elemB++))
+        return 0;
+    }
+    if (!*elemA)
+      break;
+    if (*elemA++ != *elemB++) 
+      return 0;
+  }
+  if (skip != 2 || *elemB)
+    return 0;
+  return 1;
+} /* setequal_except */
+  
+
+/*---------------------------------
+  
+  qh_setequal_skip( setA, skipA, setB, skipB )
+    returns 1 if sorted setA and setB are equal except for elements skipA & B
+
+  returns:
+    false if different size
+
+  notes:
+    neither set may be NULL
+
+  design:
+    setup pointers
+    search for mismatches while skipping skipA and skipB
+*/
+int qh_setequal_skip (setT *setA, int skipA, setT *setB, int skipB) {
+  void **elemA, **elemB, **skipAp, **skipBp;
+
+  elemA= SETaddr_(setA, void);
+  elemB= SETaddr_(setB, void);
+  skipAp= SETelemaddr_(setA, skipA, void);
+  skipBp= SETelemaddr_(setB, skipB, void);
+  while (1) {
+    if (elemA == skipAp)
+      elemA++;
+    if (elemB == skipBp)
+      elemB++;
+    if (!*elemA)
+      break;
+    if (*elemA++ != *elemB++) 
+      return 0;
+  }
+  if (*elemB)
+    return 0;
+  return 1;
+} /* setequal_skip */
+  
+
+/*---------------------------------
+  
+  qh_setfree( setp )
+    frees the space occupied by a sorted or unsorted set
+
+  returns:
+    sets setp to NULL
+    
+  notes:
+    set may be NULL
+
+  design:
+    free array
+    free set
+*/
+void qh_setfree(setT **setp) {
+  int size;
+  void **freelistp;  /* used !qh_NOmem */
+  
+  if (*setp) {
+    size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize; 
+    if (size <= qhmem.LASTsize) {
+      qh_memfree_(*setp, size, freelistp);
+    }else
+      qh_memfree (*setp, size);
+    *setp= NULL;
+  }
+} /* setfree */
+
+
+/*---------------------------------
+  
+  qh_setfree2( setp, elemsize )
+    frees the space occupied by a set and its elements
+
+  notes:
+    set may be NULL
+
+  design:
+    free each element
+    free set 
+*/
+void qh_setfree2 (setT **setp, int elemsize) {
+  void		*elem, **elemp;
+  
+  FOREACHelem_(*setp)
+    qh_memfree (elem, elemsize);
+  qh_setfree (setp);
+} /* setfree2 */
+
+
+      
+/*---------------------------------
+  
+  qh_setfreelong( setp )
+    frees a set only if it's in long memory
+
+  returns:
+    sets setp to NULL if it is freed
+    
+  notes:
+    set may be NULL
+
+  design:
+    if set is large
+      free it    
+*/
+void qh_setfreelong(setT **setp) {
+  int size;
+  
+  if (*setp) {
+    size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize; 
+    if (size > qhmem.LASTsize) {
+      qh_memfree (*setp, size);
+      *setp= NULL;
+    }
+  }
+} /* setfreelong */
+
+
+/*---------------------------------
+  
+  qh_setin( set, setelem )
+    returns 1 if setelem is in a set, 0 otherwise
+
+  notes:
+    set may be NULL or unsorted
+
+  design:
+    scans set for setelem
+*/
+int qh_setin(setT *set, void *setelem) {
+  void *elem, **elemp;
+
+  FOREACHelem_(set) {
+    if (elem == setelem)
+      return 1;
+  }
+  return 0;
+} /* setin */
+
+
+/*---------------------------------
+  
+  qh_setindex( set, atelem )
+    returns the index of atelem in set.   
+    returns -1, if not in set or maxsize wrong
+
+  notes:
+    set may be NULL and may contain nulls.
+
+  design:
+    checks maxsize
+    scans set for atelem
+*/
+int qh_setindex(setT *set, void *atelem) {
+  void **elem;
+  int size, i;
+
+  SETreturnsize_(set, size);
+  if (size > set->maxsize)
+    return -1;
+  elem= SETaddr_(set, void);
+  for (i=0; i < size; i++) {
+    if (*elem++ == atelem)
+      return i;
+  }
+  return -1;
+} /* setindex */
+
+
+/*---------------------------------
+  
+  qh_setlarger( oldsetp )
+    returns a larger set that contains all elements of *oldsetp
+
+  notes:
+    the set is at least twice as large
+    if temp set, updates qhmem.tempstack
+
+  design:
+    creates a new set
+    copies the old set to the new set
+    updates pointers in tempstack
+    deletes the old set
+*/
+void qh_setlarger(setT **oldsetp) {
+  int size= 1, *sizep;
+  setT *newset, *set, **setp, *oldset;
+  void **oldp, **newp;
+
+  if (*oldsetp) {
+    oldset= *oldsetp;
+    SETreturnsize_(oldset, size);
+    qhmem.cntlarger++;
+    qhmem.totlarger += size+1;
+    newset= qh_setnew(2 * size);
+    oldp= SETaddr_(oldset, void);
+    newp= SETaddr_(newset, void);
+    memcpy((char *)newp, (char *)oldp, (size+1) * SETelemsize);
+    sizep= SETsizeaddr_(newset);
+    *sizep= size+1;
+    FOREACHset_((setT *)qhmem.tempstack) {
+      if (set == oldset)
+	*(setp-1)= newset;
+    }
+    qh_setfree(oldsetp);
+  }else 
+    newset= qh_setnew(3);
+  *oldsetp= newset;
+} /* setlarger */
+
+
+/*---------------------------------
+  
+  qh_setlast(  )
+    return last element of set or NULL (use type conversion)
+
+  notes:
+    set may be NULL
+
+  design:
+    return last element  
+*/
+void *qh_setlast(setT *set) {
+  int size;
+
+  if (set) {
+    size= *SETsizeaddr_(set);
+    if (!size) 
+      return SETelem_(set, set->maxsize - 1);
+    else if (size > 1)
+      return SETelem_(set, size - 2);
+  }
+  return NULL;
+} /* setlast */
+
+
+/*---------------------------------
+  
+  qh_setnew( setsize )
+    creates and allocates space for a set
+
+  notes:
+    setsize means the number of elements (NOT including the NULL terminator)
+    use qh_settemp/qh_setfreetemp if set is temporary
+
+  design:
+    allocate memory for set
+    roundup memory if small set
+    initialize as empty set
+*/
+setT *qh_setnew(int setsize) {
+  setT *set;
+  int sizereceived; /* used !qh_NOmem */
+  int size;
+  void **freelistp; /* used !qh_NOmem */
+
+  if (!setsize)
+    setsize++;
+  size= sizeof(setT) + setsize * SETelemsize;
+  if ((unsigned) size <= (unsigned) qhmem.LASTsize) {
+    qh_memalloc_(size, freelistp, set, setT);
+#ifndef qh_NOmem
+    sizereceived= qhmem.sizetable[ qhmem.indextable[size]];
+    if (sizereceived > size) 
+      setsize += (sizereceived - size)/SETelemsize;
+#endif
+  }else
+    set= (setT*)qh_memalloc (size);
+  set->maxsize= setsize;
+  set->e[setsize].i= 1;
+  set->e[0].p= NULL;
+  return (set);
+} /* setnew */
+
+
+/*---------------------------------
+  
+  qh_setnew_delnthsorted( set, size, nth, prepend )
+    creates a sorted set not containing nth element
+    if prepend, the first prepend elements are undefined
+
+  notes:
+    set must be defined
+    checks nth
+    see also: setdelnthsorted
+
+  design:
+    create new set
+    setup pointers and allocate room for prepend'ed entries
+    append head of old set to new set
+    append tail of old set to new set
+*/
+setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend) {
+  setT *newset;
+  void **oldp, **newp;
+  int tailsize= size - nth -1, newsize;
+
+  if (tailsize < 0) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  newsize= size-1 + prepend;
+  newset= qh_setnew(newsize);
+  newset->e[newset->maxsize].i= newsize+1;  /* may be overwritten */
+  oldp= SETaddr_(set, void);
+  newp= SETaddr_(newset, void) + prepend;
+  switch (nth) {
+  case 0:
+    break;
+  case 1:
+    *(newp++)= *oldp++;
+    break;
+  case 2:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 3:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 4:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  default:
+    memcpy((char *)newp, (char *)oldp, nth * SETelemsize);
+    newp += nth;
+    oldp += nth;
+    break;
+  }
+  oldp++;
+  switch (tailsize) {
+  case 0:
+    break;
+  case 1:
+    *(newp++)= *oldp++;
+    break;
+  case 2:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 3:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  case 4:
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    *(newp++)= *oldp++;
+    break;
+  default:
+    memcpy((char *)newp, (char *)oldp, tailsize * SETelemsize);
+    newp += tailsize;
+  }
+  *newp= NULL;
+  return(newset);
+} /* setnew_delnthsorted */
+
+
+/*---------------------------------
+  
+  qh_setprint( fp, string, set )
+    print set elements to fp with identifying string
+
+  notes:
+    never errors
+*/
+void qh_setprint(FILE *fp, char* string, setT *set) {
+  int size, k;
+
+  if (!set)
+    fprintf (fp, "%s set is null\n", string);
+  else {
+    SETreturnsize_(set, size);
+    fprintf (fp, "%s set=%p maxsize=%d size=%d elems=",
+	     string, set, set->maxsize, size);
+    if (size > set->maxsize)
+      size= set->maxsize+1;
+    for (k=0; k < size; k++)
+      fprintf(fp, " %p", set->e[k].p);
+    fprintf(fp, "\n");
+  }
+} /* setprint */
+
+/*---------------------------------
+  
+  qh_setreplace( set, oldelem, newelem )
+    replaces oldelem in set with newelem
+
+  notes:
+    errors if oldelem not in the set
+    newelem may be NULL, but it turns the set into an indexed set (no FOREACH)
+
+  design:
+    find oldelem
+    replace with newelem
+*/
+void qh_setreplace(setT *set, void *oldelem, void *newelem) {
+  void **elemp;
+  
+  elemp= SETaddr_(set, void);
+  while(*elemp != oldelem && *elemp)
+    elemp++;
+  if (*elemp)
+    *elemp= newelem;
+  else {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setreplace): elem %p not found in set\n",
+       oldelem);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+} /* setreplace */
+
+
+/*---------------------------------
+  
+  qh_setsize( set )
+    returns the size of a set
+
+  notes:
+    errors if set's maxsize is incorrect
+    same as SETreturnsize_(set)
+
+  design:
+    determine actual size of set from maxsize
+*/
+int qh_setsize(setT *set) {
+  int size, *sizep;
+  
+  if (!set)
+    return (0);
+  sizep= SETsizeaddr_(set);
+  if ((size= *sizep)) {
+    size--;
+    if (size > set->maxsize) {
+      fprintf (qhmem.ferr, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
+	       size, set->maxsize);
+      qh_setprint (qhmem.ferr, "set: ", set);
+      qh_errexit (qhmem_ERRqhull, NULL, NULL);
+    }
+  }else
+    size= set->maxsize;
+  return size;
+} /* setsize */
+
+/*---------------------------------
+  
+  qh_settemp( setsize )
+    return a stacked, temporary set of upto setsize elements
+
+  notes:
+    use settempfree or settempfree_all to release from qhmem.tempstack
+    see also qh_setnew
+
+  design:
+    allocate set
+    append to qhmem.tempstack
+    
+*/
+setT *qh_settemp(int setsize) {
+  setT *newset;
+  
+  newset= qh_setnew (setsize);
+  qh_setappend ((setT **)&qhmem.tempstack, newset);
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_settemp: temp set %p of %d elements, depth %d\n",
+       newset, newset->maxsize, qh_setsize ((setT*)qhmem.tempstack));
+  return newset;
+} /* settemp */
+
+/*---------------------------------
+  
+  qh_settempfree( set )
+    free temporary set at top of qhmem.tempstack
+
+  notes:
+    nop if set is NULL
+    errors if set not from previous   qh_settemp
+  
+  to locate errors:
+    use 'T2' to find source and then find mis-matching qh_settemp
+
+  design:
+    check top of qhmem.tempstack
+    free it
+*/
+void qh_settempfree(setT **set) {
+  setT *stackedset;
+
+  if (!*set)
+    return;
+  stackedset= qh_settemppop ();
+  if (stackedset != *set) {
+    qh_settemppush(stackedset);
+    fprintf (qhmem.ferr, "qhull internal error (qh_settempfree): set %p (size %d) was not last temporary allocated (depth %d, set %p, size %d)\n",
+	     *set, qh_setsize(*set), qh_setsize((setT*)qhmem.tempstack)+1,
+	     stackedset, qh_setsize(stackedset));
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  qh_setfree (set);
+} /* settempfree */
+
+/*---------------------------------
+  
+  qh_settempfree_all(  )
+    free all temporary sets in qhmem.tempstack
+
+  design:
+    for each set in tempstack
+      free set
+    free qhmem.tempstack
+*/
+void qh_settempfree_all(void) {
+  setT *set, **setp;
+
+  FOREACHset_((setT *)qhmem.tempstack) 
+    qh_setfree(&set);
+  qh_setfree((setT **)&qhmem.tempstack);
+} /* settempfree_all */
+
+/*---------------------------------
+  
+  qh_settemppop(  )
+    pop and return temporary set from qhmem.tempstack 
+
+  notes:
+    the returned set is permanent
+    
+  design:
+    pop and check top of qhmem.tempstack
+*/
+setT *qh_settemppop(void) {
+  setT *stackedset;
+  
+  stackedset= (setT*)qh_setdellast((setT *)qhmem.tempstack);
+  if (!stackedset) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_settemppop: depth %d temp set %p of %d elements\n",
+       qh_setsize((setT*)qhmem.tempstack)+1, stackedset, qh_setsize(stackedset));
+  return stackedset;
+} /* settemppop */
+
+/*---------------------------------
+  
+  qh_settemppush( set )
+    push temporary set unto qhmem.tempstack (makes it temporary)
+
+  notes:
+    duplicates settemp() for tracing
+
+  design:
+    append set to tempstack  
+*/
+void qh_settemppush(setT *set) {
+  
+  qh_setappend ((setT**)&qhmem.tempstack, set);
+  if (qhmem.IStracing >= 5)
+    fprintf (qhmem.ferr, "qh_settemppush: depth %d temp set %p of %d elements\n",
+    qh_setsize((setT*)qhmem.tempstack), set, qh_setsize(set));
+} /* settemppush */
+
+ 
+/*---------------------------------
+  
+  qh_settruncate( set, size )
+    truncate set to size elements
+
+  notes:
+    set must be defined
+  
+  see:
+    SETtruncate_
+
+  design:
+    check size
+    update actual size of set
+*/
+void qh_settruncate (setT *set, int size) {
+
+  if (size < 0 || size > set->maxsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  set->e[set->maxsize].i= size+1;   /* maybe overwritten */
+  set->e[size].p= NULL;
+} /* settruncate */
+    
+/*---------------------------------
+  
+  qh_setunique( set, elem )
+    add elem to unsorted set unless it is already in set
+
+  notes:
+    returns 1 if it is appended
+
+  design:
+    if elem not in set
+      append elem to set
+*/
+int qh_setunique (setT **set, void *elem) {
+
+  if (!qh_setin (*set, elem)) {
+    qh_setappend (set, elem);
+    return 1;
+  }
+  return 0;
+} /* setunique */
+    
+/*---------------------------------
+  
+  qh_setzero( set, index, size )
+    zero elements from index on
+    set actual size of set to size
+
+  notes:
+    set must be defined
+    the set becomes an indexed set (can not use FOREACH...)
+  
+  see also:
+    qh_settruncate
+    
+  design:
+    check index and size
+    update actual size
+    zero elements starting at e[index]   
+*/
+void qh_setzero (setT *set, int index, int size) {
+  int count;
+
+  if (index < 0 || index >= size || size > set->maxsize) {
+    fprintf (qhmem.ferr, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", index, size);
+    qh_setprint (qhmem.ferr, "", set);
+    qh_errexit (qhmem_ERRqhull, NULL, NULL);
+  }
+  set->e[set->maxsize].i=  size+1;  /* may be overwritten */
+  count= size - index + 1;   /* +1 for NULL terminator */
+  memset ((char *)SETelemaddr_(set, index, void), 0, count * SETelemsize);
+} /* setzero */
+
+    
diff --git a/extern/qhull/src/qset.h b/extern/qhull/src/qset.h
new file mode 100644
index 00000000000..6c0ff758de4
--- /dev/null
+++ b/extern/qhull/src/qset.h
@@ -0,0 +1,468 @@
+/*
  ---------------------------------
+
+   qset.h
+     header file for qset.c that implements set
+
+   see qh-set.htm and qset.c
+   
+   only uses mem.c, malloc/free
+
+   for error handling, writes message and calls
+      qh_errexit (qhmem_ERRqhull, NULL, NULL);
+   
+   set operations satisfy the following properties:
+    - sets have a max size, the actual size (if different) is stored at the end
+    - every set is NULL terminated
+    - sets may be sorted or unsorted, the caller must distinguish this
+   
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#ifndef qhDEFset
+#define qhDEFset 1
+
+/*================= -structures- ===============*/
+
+#ifndef DEFsetT
+#define DEFsetT 1
+typedef struct setT setT;   /* a set is a sorted or unsorted array of pointers */
+#endif
+
+/*------------------------------------------
+   
+setT
+  a set or list of pointers with maximum size and actual size.
+
+variations:
+  unsorted, unique   -- a list of unique pointers with NULL terminator
+  			   user guarantees uniqueness
+  sorted	     -- a sorted list of unique pointers with NULL terminator
+  			   qset.c guarantees uniqueness
+  unsorted           -- a list of pointers terminated with NULL
+  indexed  	     -- an array of pointers with NULL elements 
+
+structure for set of n elements:
+
+	--------------
+	|  maxsize 
+	--------------
+	|  e[0] - a pointer, may be NULL for indexed sets
+	--------------
+	|  e[1]
+	
+	--------------
+	|  ...
+	--------------
+	|  e[n-1]
+	--------------
+	|  e[n] = NULL
+	--------------
+	|  ...
+	--------------
+	|  e[maxsize] - n+1 or NULL (determines actual size of set)
+	--------------
+
+*/
+
+/*-- setelemT -- internal type to allow both pointers and indices
+*/
+typedef union setelemT setelemT;
+union setelemT {
+  void    *p;
+  int      i;         /* integer used for e[maxSize] */
+};
+
+struct setT {
+  int maxsize;          /* maximum number of elements (except NULL) */
+  setelemT e[1];        /* array of pointers, tail is NULL */
+                        /* last slot (unless NULL) is actual size+1 
+                           e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
+                        /* this may generate a warning since e[] contains
+			   maxsize elements */
+};
+
+/*=========== -constants- =========================*/
+
+/*-------------------------------------
+   
+  SETelemsize
+    size of a set element in bytes
+*/
+#define SETelemsize sizeof(setelemT) 
+
+
+/*=========== -macros- =========================*/
+
+/*-------------------------------------
+   
+   FOREACHsetelement_(type, set, variable)
+     define FOREACH iterator
+
+   declare:  
+     assumes *variable and **variablep are declared
+     no space in "variable)" [DEC Alpha cc compiler]
+
+   each iteration:
+     variable is set element
+     variablep is one beyond variable.  
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+
+   example:  
+     #define FOREACHfacet_( facets ) FOREACHsetelement_( facetT, facets, facet )
+
+   notes:
+     use FOREACHsetelement_i_() if need index or include NULLs
+
+   WARNING: 
+     nested loops can't use the same variable (define another FOREACH)
+   
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+          variable##p= (type **)&((set)->e[0].p); \
+	  (variable= *variable##p++);)
+
+/*------------------------------------------
+
+   FOREACHsetelement_i_(type, set, variable)
+     define indexed FOREACH iterator
+
+   declare:  
+     type *variable, variable_n, variable_i;
+
+   each iteration:
+     variable is set element, may be NULL
+     variable_i is index, variable_n is qh_setsize()
+
+   to repeat an element:
+     variable_i--; variable_n-- repeats for deleted element
+
+   at exit:
+     variable==NULL and variable_i==variable_n
+
+   example:
+     #define FOREACHfacet_i_( facets ) FOREACHsetelement_i_( facetT, facets, facet )
+   
+   WARNING: 
+     nested loops can't use the same variable (define another FOREACH)
+   
+     needs braces if nested inside another FOREACH
+     this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
+*/
+#define FOREACHsetelement_i_(type, set, variable) \
+        if (((variable= NULL), set)) for (\
+          variable##_i= 0, variable= (type *)((set)->e[0].p), \
+                   variable##_n= qh_setsize(set);\
+          variable##_i < variable##_n;\
+          variable= (type *)((set)->e[++variable##_i].p) )
+
+/*----------------------------------------
+
+   FOREACHsetelementreverse_(type, set, variable)- 
+     define FOREACH iterator in reverse order
+
+   declare:  
+     assumes *variable and **variablep are declared
+     also declare 'int variabletemp'
+
+   each iteration:
+     variable is set element
+
+   to repeat an element:
+     variabletemp++; / *repeat* /
+
+   at exit:
+     variable is NULL
+
+   example:
+     #define FOREACHvertexreverse_( vertices ) FOREACHsetelementreverse_( vertexT, vertices, vertex )
+  
+   notes:
+     use FOREACHsetelementreverse12_() to reverse first two elements
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+	   variable##temp= qh_setsize(set)-1, variable= qh_setlast(set);\
+	   variable; variable= \
+	   ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))
+
+/*-------------------------------------
+
+   FOREACHsetelementreverse12_(type, set, variable)- 
+     define FOREACH iterator with e[1] and e[0] reversed
+
+   declare:  
+     assumes *variable and **variablep are declared
+
+   each iteration:
+     variable is set element
+     variablep is one after variable.  
+
+   to repeat an element:
+     variablep--; / *repeat* /
+
+   at exit:
+     variable is NULL at end of loop
+  
+   example
+     #define FOREACHvertexreverse12_( vertices ) FOREACHsetelementreverse12_( vertexT, vertices, vertex )
+
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHsetelementreverse12_(type, set, variable) \
+        if (((variable= NULL), set)) for(\
+          variable##p= (type **)&((set)->e[1].p); \
+	  (variable= *variable##p); \
+          variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
+	      (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))
+
+/*-------------------------------------
+
+   FOREACHelem_( set )- 
+     iterate elements in a set
+
+   declare:  
+     void *elem, *elemp;
+
+   each iteration:
+     elem is set element
+     elemp is one beyond
+
+   to repeat an element:
+     elemp--; / *repeat* /
+
+   at exit:
+     elem == NULL at end of loop
+  
+   example:
+     FOREACHelem_(set) {
+     
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)
+
+/*-------------------------------------
+
+   FOREACHset_( set )- 
+     iterate a set of sets
+
+   declare:  
+     setT *set, **setp;
+
+   each iteration:
+     set is set element
+     setp is one beyond
+
+   to repeat an element:
+     setp--; / *repeat* /
+
+   at exit:
+     set == NULL at end of loop
+  
+   example
+     FOREACHset_(sets) {
+     
+   notes:
+     WARNING: needs braces if nested inside another FOREACH
+*/
+#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)
+
+/*-------------------------------------------
+
+   SETindex_( set, elem )
+     return index of elem in set
+
+   notes:   
+     for use with FOREACH iteration
+
+   example:
+     i= SETindex_(ridges, ridge)
+*/
+#define SETindex_(set, elem) ((void **)elem##p - (void **)&(set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETref_( elem )
+     l.h.s. for modifying the current element in a FOREACH iteration
+
+   example:
+     SETref_(ridge)= anotherridge;
+*/
+#define SETref_(elem) (elem##p[-1])
+
+/*-----------------------------------------
+
+   SETelem_(set, n)
+     return the n'th element of set
+   
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+      use SETelemt_() for type cast
+*/
+#define SETelem_(set, n)           ((set)->e[n].p)
+
+/*-----------------------------------------
+
+   SETelemt_(set, n, type)
+     return the n'th element of set as a type
+   
+   notes:
+      assumes that n is valid [0..size] and that set is defined
+*/
+#define SETelemt_(set, n, type)    ((type*)((set)->e[n].p))
+
+/*-----------------------------------------
+
+   SETelemaddr_(set, n, type)
+     return address of the n'th element of a set
+   
+   notes:
+      assumes that n is valid [0..size] and set is defined 
+*/
+#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))
+
+/*-----------------------------------------
+
+   SETfirst_(set)
+     return first element of set
+   
+*/
+#define SETfirst_(set)             ((set)->e[0].p)
+
+/*-----------------------------------------
+
+   SETfirstt_(set, type)
+     return first element of set as a type
+   
+*/
+#define SETfirstt_(set, type)      ((type*)((set)->e[0].p))
+
+/*-----------------------------------------
+
+   SETsecond_(set)
+     return second element of set
+   
+*/
+#define SETsecond_(set)            ((set)->e[1].p)
+
+/*-----------------------------------------
+
+   SETsecondt_(set, type)
+     return second element of set as a type
+*/
+#define SETsecondt_(set, type)     ((type*)((set)->e[1].p))
+
+/*-----------------------------------------
+
+   SETaddr_(set, type)
+       return address of set's elements
+*/
+#define SETaddr_(set,type)	   ((type **)(&((set)->e[0].p)))
+
+/*-----------------------------------------
+
+   SETreturnsize_(set, size) 
+     return size of a set
+   
+   notes:
+      set must be defined
+      use qh_setsize(set) unless speed is critical
+*/
+#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))
+
+/*-----------------------------------------
+
+   SETempty_(set) 
+     return true (1) if set is empty
+   
+   notes:
+      set may be NULL
+*/
+#define SETempty_(set) 	          (!set || (SETfirst_(set) ? 0:1))
+
+/*-----------------------------------------
+
+   SETtruncate_(set)
+     return first element of set
+
+   see:
+     qh_settruncate()
+   
+*/
+#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
+      set->e[size].p= NULL;}
+
+/*======= prototypes in alphabetical order ============*/
+
+void  qh_setaddsorted(setT **setp, void *elem);
+void  qh_setaddnth(setT **setp, int nth, void *newelem);
+void  qh_setappend(setT **setp, void *elem);
+void  qh_setappend_set(setT **setp, setT *setA);
+void  qh_setappend2ndlast(setT **setp, void *elem);
+void  qh_setcheck(setT *set, char *tname, int id);
+void  qh_setcompact(setT *set);
+setT *qh_setcopy(setT *set, int extra);
+void *qh_setdel(setT *set, void *elem);
+void *qh_setdellast(setT *set);
+void *qh_setdelnth(setT *set, int nth);
+void *qh_setdelnthsorted(setT *set, int nth);
+void *qh_setdelsorted(setT *set, void *newelem);
+setT *qh_setduplicate( setT *set, int elemsize);
+int   qh_setequal(setT *setA, setT *setB);
+int   qh_setequal_except (setT *setA, void *skipelemA, setT *setB, void *skipelemB);
+int   qh_setequal_skip (setT *setA, int skipA, setT *setB, int skipB);
+void  qh_setfree(setT **set);
+void  qh_setfree2( setT **setp, int elemsize);
+void  qh_setfreelong(setT **set);
+int   qh_setin(setT *set, void *setelem);
+int   qh_setindex(setT *set, void *setelem);
+void  qh_setlarger(setT **setp);
+void *qh_setlast(setT *set);
+setT *qh_setnew(int size);
+setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend);
+void  qh_setprint(FILE *fp, char* string, setT *set);
+void  qh_setreplace(setT *set, void *oldelem, void *newelem);
+int   qh_setsize(setT *set);
+setT *qh_settemp(int setsize);
+void  qh_settempfree(setT **set);
+void  qh_settempfree_all(void);
+setT *qh_settemppop(void);
+void  qh_settemppush(setT *set);
+void  qh_settruncate (setT *set, int size);
+int   qh_setunique (setT **set, void *elem);
+void  qh_setzero (setT *set, int index, int size);
+
+
+#endif /* qhDEFset */
diff --git a/extern/qhull/src/qvoronoi.c b/extern/qhull/src/qvoronoi.c
new file mode 100644
index 00000000000..ebeb7367b87
--- /dev/null
+++ b/extern/qhull/src/qvoronoi.c
@@ -0,0 +1,318 @@
+/*
  ---------------------------------
+
+   qvoronoi.c
+     compute Voronoi diagrams and furthest-point Voronoi
+     diagrams using qhull
+
+   see unix.c for full interface
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt 
+    long prompt for qhull
+    
+  notes:
+    restricted version of qhull.c
+ 
+  see:
+    concise prompt below
+*/  
+
+/* duplicated in qvoron_f.htm and qvoronoi.htm */
+char hidden_options[]=" d n m v H U Qb QB Qc Qf Qg Qi Qm Qr QR Qv Qx TR E V Fa FA FC Fp FS Ft FV Pv Gt Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 ";
+
+char qh_prompta[]= "\n\
+qvoronoi- compute the Voronoi diagram\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    first lines: dimension and number of points (or vice-versa).\n\
+    other lines: point coordinates, best if one point per line\n\
+    comments:    start with a non-numeric character\n\
+\n\
+options:\n\
+    Qu   - compute furthest-site Voronoi diagram\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+\n\
+Qhull control options:\n\
+    Qz   - add point-at-infinity to Voronoi diagram\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qs   - search all points for the initial simplex\n\
+    QGn  - Voronoi vertices if visible from point n, -n if not\n\
+    QVn  - Voronoi vertices for input point n, -n if not\n\
+\n\
+";
+char qh_promptc[]= "\
+Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - statistics\n\
+    Tv   - verify result: structure, convexity, and in-circle test\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when point n added to hull\n\
+     TMn - turn on tracing at merge n\n\
+     TWn - trace merge facets when width > n\n\
+    TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
+     TCn - stop qhull after building cone for point n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Wn   - min facet width for non-coincident point (before roundoff)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    s    - summary to stderr\n\
+    p    - Voronoi vertices\n\
+    o    - OFF format (dim, Voronoi vertices, and Voronoi regions)\n\
+    i    - Delaunay regions (use 'Pp' to avoid warning)\n\
+    f    - facet dump\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fc   - count plus coincident points (by Voronoi vertex)\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FD   - use cdd format for output (offset first)\n\
+    FF   - facet dump without ridges\n\
+    Fi   - separating hyperplanes for bounded Voronoi regions\n\
+    FI   - ID for each Voronoi vertex\n\
+    Fm   - merge count for each Voronoi vertex (511 max)\n\
+    Fn   - count plus neighboring Voronoi vertices for each Voronoi vertex\n\
+    FN   - count and Voronoi vertices for each Voronoi region\n\
+    Fo   - separating hyperplanes for unbounded Voronoi regions\n\
+    FO   - options and precision constants\n\
+    FP   - nearest point and distance for each coincident point\n\
+    FQ   - command used for qvoronoi\n\
+    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
+                    for output: #Voronoi regions, #Voronoi vertices,\n\
+                                #coincident points, #non-simplicial regions\n\
+                    #real (2), max outer plane and min vertex\n\
+    Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites\n\
+    Fx   - extreme points of Delaunay triangulation (on convex hull)\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview options (2-d only)\n\
+    Ga   - all points as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices as spheres\n\
+    Gi   - inner planes only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc	 - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest Voronoi vertices by 'area'\n\
+    Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n - drop facet if normal[k] >= n\n\
+    Pg   - print good Voronoi vertices (needs 'QGn' or 'QVn')\n\
+    PFn  - keep Voronoi vertices whose 'area' is at least n\n\
+    PG   - print neighbors of good Voronoi vertices\n\
+    PMn  - keep n Voronoi vertices with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull 
+*/  
+char qh_prompt2[]= "\n\
+qvoronoi- compute the Voronoi diagram. Qhull %s\n\
+    input (stdin): dimension, number of points, point coordinates\n\
+    comments start with a non-numeric character\n\
+\n\
+options (qvoronoi.htm):\n\
+    Qu   - compute furthest-site Voronoi diagram\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and in-circle test\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+output options (subset):\n\
+    s    - summary of results (default)\n\
+    p    - Voronoi vertices\n\
+    o    - OFF file format (dim, Voronoi vertices, and Voronoi regions)\n\
+    FN   - count and Voronoi vertices for each Voronoi region\n\
+    Fv   - Voronoi diagram as Voronoi vertices between adjacent input sites\n\
+    Fi   - separating hyperplanes for bounded regions, 'Fo' for unbounded\n\
+    G    - Geomview output (2-d only)\n\
+    QVn  - Voronoi vertices for input point n, -n if not\n\
+    TO file- output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+rbox c P0 D2 | qvoronoi s o         rbox c P0 D2 | qvoronoi Fi\n\
+rbox c P0 D2 | qvoronoi Fo          rbox c P0 D2 | qvoronoi Fv\n\
+rbox c P0 D2 | qvoronoi s Qu Fv     rbox c P0 D2 | qvoronoi Qu Fo\n\
+rbox c G1 d D2 | qvoronoi s p       rbox c G1 d D2 | qvoronoi QJ s p\n\
+rbox c P0 D2 | qvoronoi s Fv QV0\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull 
+*/  
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper-case options take an argument.\n\
+\n\
+ OFF_format     p_vertices     i_delaunay     summary        facet_dump\n\
+\n\
+ Fcoincident    Fd_cdd_in      FD_cdd_out     FF-dump-xridge Fi_bounded\n\
+ Fxtremes       Fmerges        Fneighbors     FNeigh_region  FOptions\n\
+ Fo_unbounded   FPoint_near    FQvoronoi      Fsummary       Fvoronoi\n\
+ FIDs\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+\n\
+ PArea_keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
+ PGood_neighbors PMerge_keep   Poutput_forced Pprecision_not\n\
+\n\
+ QG_vertex_good QJoggle        Qsearch_1st    Qtriangulate   Qupper_voronoi\n\
+ QV_point_good  Qzinfinite\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Random_dist    Wide_outside\n\
+";
+
+/*---------------------------------
+  
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+  
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {      
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION,  
+		qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_option ("voronoi  _bbound-last  _coplanar-keep", NULL, NULL);
+    qh DELAUNAY= True;     /* 'v'   */
+    qh VORONOI= True; 
+    qh SCALElast= True;    /* 'Qbb' */
+    qh_checkflags (qh qhull_command, hidden_options);
+    qh_initflags (qh qhull_command);
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    if (dim >= 5) {
+      qh_option ("_merge-exact", NULL, NULL);
+      qh MERGEexact= True; /* 'Qx' always */
+    }
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/rbox.c b/extern/qhull/src/rbox.c
new file mode 100644
index 00000000000..1c288bddc96
--- /dev/null
+++ b/extern/qhull/src/rbox.c
@@ -0,0 +1,788 @@
+/*
  ---------------------------------
+
+   rbox.c
+     Generate input points for qhull.
+   
+   notes:
+     50 points generated for 'rbox D4'
+
+     This code needs a full rewrite.  It needs separate procedures for each 
+     distribution with common, helper procedures.
+   
+   WARNING: 
+     incorrect range if qh_RANDOMmax is defined wrong (user.h)
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "user.h"
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+#endif
+
+#ifdef _MSC_VER  /* Microsoft Visual C++ */
+#pragma warning( disable : 4244)  /* conversion from double to int */
+#endif
+
+#define MINVALUE 0.8
+#define MAXdim 200
+#define PI 3.1415926535897932384
+#define DEFAULTzbox 1e6
+
+char prompt[]= "\n\
+-rbox- generate various point distributions.  Default is random in cube.\n\
+\n\
+args (any order, space separated):                    Version: 2001/06/24\n\
+  3000    number of random points in cube, lens, spiral, sphere or grid\n\
+  D3      dimension 3-d\n\
+  c       add a unit cube to the output ('c G2.0' sets size)\n\
+  d       add a unit diamond to the output ('d G2.0' sets size)\n\
+  l       generate a regular 3-d spiral\n\
+  r       generate a regular polygon, ('r s Z1 G0.1' makes a cone)\n\
+  s       generate cospherical points\n\
+  x       generate random points in simplex, may use 'r' or 'Wn'\n\
+  y       same as 'x', plus simplex\n\
+  Pn,m,r  add point [n,m,r] first, pads with 0\n\
+\n\
+  Ln      lens distribution of radius n.  Also 's', 'r', 'G', 'W'.\n\
+  Mn,m,r  lattice (Mesh) rotated by [n,-m,0], [m,n,0], [0,0,r], ...\n\
+          '27 M1,0,1' is {0,1,2} x {0,1,2} x {0,1,2}.  Try 'M3,4 z'.\n\
+  W0.1    random distribution within 0.1 of the cube's or sphere's surface\n\
+  Z0.5 s  random points in a 0.5 disk projected to a sphere\n\
+  Z0.5 s G0.6 same as Z0.5 within a 0.6 gap\n\
+\n\
+  Bn      bounding box coordinates, default %2.2g\n\
+  h       output as homogeneous coordinates for cdd\n\
+  n       remove command line from the first line of output\n\
+  On      offset coordinates by n\n\
+  t       use time as the random number seed (default is command line)\n\
+  tn      use n as the random number seed\n\
+  z       print integer coordinates, default 'Bn' is %2.2g\n\
+";
+
+/* ------------------------------ prototypes ----------------*/
+int roundi( double a);
+void out1( double a);
+void out2n( double a, double b);
+void out3n( double a, double b, double c);
+int     qh_rand( void);
+void    qh_srand( int seed);
+
+
+/* ------------------------------ globals -------------------*/
+
+    FILE *fp;
+    int isinteger= 0;
+    double out_offset= 0.0;
+
+
+/*--------------------------------------------
+-rbox-  main procedure of rbox application
+*/
+int main(int argc, char **argv) {
+    int i,j,k;
+    int gendim;
+    int cubesize, diamondsize, seed=0, count, apex;
+    int dim=3 , numpoints= 0, totpoints, addpoints=0;
+    int issphere=0, isaxis=0,  iscdd= 0, islens= 0, isregular=0, iswidth=0, addcube=0;
+    int isgap=0, isspiral=0, NOcommand= 0, adddiamond=0, istime=0;
+    int isbox=0, issimplex=0, issimplex2=0, ismesh=0;
+    double width=0.0, gap=0.0, radius= 0.0;
+    double coord[MAXdim], offset, meshm=3.0, meshn=4.0, meshr=5.0;
+    double *simplex, *simplexp;
+    int nthroot, mult[MAXdim];
+    double norm, factor, randr, rangap, lensangle= 0, lensbase= 1;
+    double anglediff, angle, x, y, cube= 0.0, diamond= 0.0;
+    double box= qh_DEFAULTbox; /* scale all numbers before output */
+    double randmax= qh_RANDOMmax;
+    char command[200], *s, seedbuf[200];    
+    time_t timedata;
+
+#if __MWERKS__ && __POWERPC__
+    char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+    SIOUXSettings.showstatusline= False;
+    SIOUXSettings.tabspaces= 1;
+    SIOUXSettings.rows= 40;
+    if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+    || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+    || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0)) 
+      	fprintf ( stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+    argc= ccommand(&argv);
+#endif
+    if (argc == 1) {
+ 	printf (prompt, box, DEFAULTzbox);
+    	exit(1);
+    }
+    if ((s = strrchr( argv[0], '\\'))) /* Borland gives full path */
+      strcpy (command, s+1);
+    else
+      strcpy (command, argv[0]);
+    if ((s= strstr (command, ".EXE"))
+    ||  (s= strstr (command, ".exe")))
+      *s= '\0';
+    /* ============= read flags =============== */
+    for (i=1; i < argc; i++) {
+  	if (strlen (command) + strlen(argv[i]) + 1 < sizeof(command) ) {
+	    strcat (command, " ");
+	    strcat (command, argv[i]);
+	}
+        if (isdigit (argv[i][0])) {
+      	    numpoints= atoi (argv[i]);
+      	    continue;
+	}
+	if (argv[i][0] == '-')
+	  (argv[i])++;
+        switch (argv[i][0]) {
+	  case 'c':
+	    addcube= 1;
+	    if (i+1 < argc && argv[i+1][0] == 'G')
+	      cube= (double) atof (&argv[++i][1]);
+	    break;
+	  case 'd':
+	    adddiamond= 1;
+	    if (i+1 < argc && argv[i+1][0] == 'G')
+	      diamond= (double) atof (&argv[++i][1]);
+	    break;
+	  case 'h':
+	    iscdd= 1;
+            break;
+	  case 'l':
+	    isspiral= 1;
+            break;
+	  case 'n':
+	    NOcommand= 1;
+	    break;
+	  case 'r':
+	    isregular= 1;
+	    break;
+	  case 's':
+	    issphere= 1;
+            break;
+	  case 't':
+	    istime= 1;
+	    if (isdigit (argv[i][1]))
+	      seed= atoi (&argv[i][1]);
+	    else {
+	      seed= time (&timedata);
+	      sprintf (seedbuf, "%d", seed);
+	      strcat (command, seedbuf);
+	    }
+            break;
+	  case 'x':
+	    issimplex= 1;
+	    break;
+	  case 'y':
+	    issimplex2= 1;
+	    break;
+	  case 'z':
+	    isinteger= 1;
+	    break;
+	  case 'B':
+	    box= (double) atof (&argv[i][1]);
+	    isbox= 1;
+	    break;
+	  case 'D':
+	    dim= atoi (&argv[i][1]);
+	    if (dim < 1
+	    || dim > MAXdim) {
+		fprintf (stderr, "rbox error: dim %d too large or too small\n", dim);
+		exit (1);
+	    }
+            break;
+	  case 'G':
+	    if (argv[i][1])
+	      gap= (double) atof (&argv[i][1]);
+	    else
+	      gap= 0.5;
+	    isgap= 1;
+	    break;
+	  case 'L':
+	    if (argv[i][1])
+	      radius= (double) atof (&argv[i][1]);
+	    else
+	      radius= 10;
+	    islens= 1;
+	    break;
+	  case 'M':
+	    ismesh= 1;
+    	    s= argv[i]+1;
+	    if (*s)
+	      meshn= strtod (s, &s);
+	    if (*s == ',')
+	      meshm= strtod (++s, &s);
+	    else
+	      meshm= 0.0;
+	    if (*s == ',')
+	      meshr= strtod (++s, &s);
+	    else
+	      meshr= sqrt (meshn*meshn + meshm*meshm);
+	    if (*s) {
+	      fprintf (stderr, "rbox warning: assuming 'M3,4,5' since mesh args are not integers or reals\n");
+	      meshn= 3.0, meshm=4.0, meshr=5.0;
+	    }
+	    break;
+	  case 'O':
+	    out_offset= (double) atof (&argv[i][1]);
+	    break;
+	  case 'P':
+	    addpoints++;
+	    break;
+	  case 'W':
+	    width= (double) atof (&argv[i][1]);
+	    iswidth= 1;
+	    break;
+	  case 'Z':
+	    if (argv[i][1])
+	      radius= (double) atof (&argv[i][1]);
+	    else
+	      radius= 1.0;
+	    isaxis= 1;
+	    break;
+	  default:
+            fprintf (stderr, "rbox warning: unknown flag %s.\nExecute 'rbox' without arguments for documentation.\n", argv[i]);
+	}
+    }
+    /* ============= defaults, constants, and sizes =============== */
+    if (isinteger && !isbox)
+      box= DEFAULTzbox;
+    if (addcube) {
+      cubesize= floor(ldexp(1.0,dim)+0.5);
+      if (cube == 0.0)
+        cube= box;
+    }else
+      cubesize= 0;
+    if (adddiamond) {
+      diamondsize= 2*dim;
+      if (diamond == 0.0)
+        diamond= box;
+    }else
+      diamondsize= 0;
+    if (islens) {
+      if (isaxis) {
+  	fprintf (stderr, "rbox error: can not combine 'Ln' with 'Zn'\n");
+  	exit(1);
+      }
+      if (radius <= 1.0) {
+  	fprintf (stderr, "rbox error: lens radius %.2g should be greater than 1.0\n",
+  	       radius);
+  	exit(1);
+      }
+      lensangle= asin (1.0/radius);
+      lensbase= radius * cos (lensangle);
+    }
+    if (!numpoints) {
+      if (issimplex2)
+	; /* ok */
+      else if (isregular + issimplex + islens + issphere + isaxis + isspiral + iswidth + ismesh) {
+	fprintf (stderr, "rbox error: missing count\n");
+	exit(1);
+      }else if (adddiamond + addcube + addpoints)
+	; /* ok */
+      else { 
+	numpoints= 50;  /* ./rbox D4 is the test case */
+	issphere= 1;
+      }
+    }
+    if ((issimplex + islens + isspiral + ismesh > 1) 
+    || (issimplex + issphere + isspiral + ismesh > 1)) {
+      fprintf (stderr, "rbox error: can only specify one of 'l', 's', 'x', 'Ln', or 'Mn,m,r' ('Ln s' is ok).\n");
+      exit(1);
+    }
+    fp= stdout;
+    /* ============= print header with total points =============== */
+    if (issimplex || ismesh)
+      totpoints= numpoints;
+    else if (issimplex2)
+      totpoints= numpoints+dim+1;
+    else if (isregular) {
+      totpoints= numpoints;
+      if (dim == 2) {
+      	if (islens)
+      	  totpoints += numpoints - 2;
+      }else if (dim == 3) {
+      	if (islens)
+      	  totpoints += 2 * numpoints;
+        else if (isgap)
+          totpoints += 1 + numpoints;
+        else
+          totpoints += 2;
+      }
+    }else
+      totpoints= numpoints + isaxis;
+    totpoints += cubesize + diamondsize + addpoints;
+    if (iscdd) 
+      fprintf(fp, "%s\nbegin\n        %d %d %s\n", 
+            NOcommand ? "" : command, 
+            totpoints, dim+1,
+            isinteger ? "integer" : "real");
+    else if (NOcommand)
+      fprintf(fp,  "%d\n%d\n", dim, totpoints);
+    else
+      fprintf(fp,  "%d %s\n%d\n", dim, command, totpoints);
+    /* ============= seed randoms =============== */
+    if (istime == 0) {
+      for (s=command; *s; s++) {
+	if (issimplex2 && *s == 'y') /* make 'y' same seed as 'x' */
+	  i= 'x';
+	else
+	  i= *s;
+	seed= 11*seed + i;
+      }
+    } /* else, seed explicitly set to n or to time */
+    qh_RANDOMseed_(seed);
+    /* ============= explicit points =============== */
+    for (i=1; i < argc; i++) {
+      if (argv[i][0] == 'P') {
+	s= argv[i]+1;
+	count= 0;
+	if (iscdd)
+	  out1( 1.0);
+	while (*s) {
+	  out1( strtod (s, &s));
+	  count++;
+	  if (*s) { 
+	    if (*s++ != ',') {
+	      fprintf (stderr, "rbox error: missing comma after coordinate in %s\n\n", argv[i]);
+	      exit (1);
+	    }
+          }
+	}
+	if (count < dim) {
+	  for (k= dim-count; k--; )
+	    out1( 0.0);
+	}else if (count > dim) {
+	  fprintf (stderr, "rbox error: %d coordinates instead of %d coordinates in %s\n\n", 
+                 count, dim, argv[i]);
+	  exit (1);
+	}
+	fprintf (fp, "\n");
+      }
+    }
+    /* ============= simplex distribution =============== */
+    if (issimplex+issimplex2) {
+      if (!(simplex= malloc( dim * (dim+1) * sizeof(double)))) {
+	fprintf (stderr, "insufficient memory for simplex\n");
+	exit(0);
+      }
+      simplexp= simplex;
+      if (isregular) {
+        for (i= 0; i randmax/2)
+	    coord[dim-1]= -coord[dim-1];
+	/* ============= project 'Wn' point toward boundary =============== */
+	}else if (iswidth && !issphere) {
+	  j= qh_RANDOMint % gendim;
+	  if (coord[j] < 0)
+	    coord[j]= -1.0 - coord[j] * width;
+	  else
+	    coord[j]= 1.0 - coord[j] * width;
+	}
+	/* ============= write point =============== */
+	if (iscdd)
+	  out1( 1.0);
+	for (k=0; k < dim; k++) 
+	  out1( coord[k] * box);
+	fprintf (fp, "\n");
+      }
+    }
+    /* ============= write cube vertices =============== */
+    if (addcube) {
+      for (j=0; j=0; k--) {
+	  if (j & ( 1 << k))
+	    out1( cube);
+	  else
+	    out1( -cube);
+	}
+	fprintf (fp, "\n");
+      }
+    }
+    /* ============= write diamond vertices =============== */
+    if (adddiamond) {
+      for (j=0; j=0; k--) {
+	  if (j/2 != k)
+	    out1( 0.0);
+	  else if (j & 0x1)
+	    out1( diamond);
+	  else
+	    out1( -diamond);
+	}
+	fprintf (fp, "\n");
+      }
+    }
+    if (iscdd)
+      fprintf (fp, "end\nhull\n");
+    return 0;
+  } /* rbox */
+
+/*------------------------------------------------
+-outxxx - output functions
+*/
+int roundi( double a) {
+  if (a < 0.0) {
+    if (a - 0.5 < INT_MIN) {
+      fprintf(stderr, "rbox input error: coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
+      exit (1);
+    }
+    return a - 0.5;
+  }else {
+    if (a + 0.5 > INT_MAX) {
+      fprintf(stderr, "rbox input error: coordinate %2.2g is too large.  Reduce 'Bn'\n", a);
+      exit (1);
+    }
+    return a + 0.5;
+  }
+} /* roundi */
+
+void out1(double a) {
+
+  if (isinteger) 
+    fprintf(fp, "%d ", roundi( a+out_offset));
+  else
+    fprintf(fp, qh_REAL_1, a+out_offset);
+} /* out1 */
+
+void out2n( double a, double b) {
+
+  if (isinteger)
+    fprintf(fp, "%d %d\n", roundi(a+out_offset), roundi(b+out_offset));
+  else
+    fprintf(fp, qh_REAL_2n, a+out_offset, b+out_offset);
+} /* out2n */
+
+void out3n( double a, double b, double c) { 
+
+  if (isinteger)
+    fprintf(fp, "%d %d %d\n", roundi(a+out_offset), roundi(b+out_offset), roundi(c+out_offset));
+  else
+    fprintf(fp, qh_REAL_3n, a+out_offset, b+out_offset, c+out_offset);
+} /* out3n */
+
+/*-------------------------------------------------
+-rand & srand- generate pseudo-random number between 1 and 2^31 -2
+  from Park & Miller's minimimal standard random number generator
+  Communications of the ACM, 31:1192-1201, 1988.
+notes:
+  does not use 0 or 2^31 -1
+  this is silently enforced by qh_srand()
+  copied from geom2.c
+*/
+static int seed = 1;  /* global static */
+
+int qh_rand( void) {
+#define qh_rand_a 16807
+#define qh_rand_m 2147483647
+#define qh_rand_q 127773  /* m div a */
+#define qh_rand_r 2836    /* m mod a */
+  int lo, hi, test;
+
+  hi = seed / qh_rand_q;  /* seed div q */
+  lo = seed % qh_rand_q;  /* seed mod q */
+  test = qh_rand_a * lo - qh_rand_r * hi;
+  if (test > 0)
+    seed= test;
+  else
+    seed= test + qh_rand_m;
+  return seed;
+} /* rand */
+
+void qh_srand( int newseed) {
+  if (newseed < 1)
+    seed= 1;
+  else if (newseed >= qh_rand_m)
+    seed= qh_rand_m - 1;
+  else
+    seed= newseed;
+} /* qh_srand */
+
diff --git a/extern/qhull/src/stat.c b/extern/qhull/src/stat.c
new file mode 100644
index 00000000000..ede0323cb88
--- /dev/null
+++ b/extern/qhull/src/stat.c
@@ -0,0 +1,700 @@
+/*
  ---------------------------------
+
+   stat.c 
+   contains all statistics that are collected for qhull
+
+   see qh-stat.htm and stat.h
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include "qhull_a.h"
+
+/*============ global data structure ==========*/
+
+#if qh_QHpointer
+qhstatT *qh_qhstat=NULL;  /* global data structure */
+#else
+qhstatT qh_qhstat;   /* add "={0}" if this causes a compiler error */
+#endif
+
+/*========== functions in alphabetic order ================*/
+
+/*---------------------------------
+  
+  qh_allstatA()
+    define statistics in groups of 20
+
+  notes:
+    (otherwise, 'gcc -O2' uses too much memory)
+    uses qhstat.next
+*/
+void qh_allstatA (void) {
+  
+   /* zdef_(type,name,doc,average) */
+  zzdef_(zdoc, Zdoc2, "precision statistics", -1);
+  zdef_(zinc, Znewvertex, NULL, -1);
+  zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet (not 0s)", Znewvertex);
+  zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);
+  zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);
+  zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);
+  zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);
+
+  qhstat precision= qhstat next;  /* call qh_precision for each of these */
+  zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1);
+  zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);
+  zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);
+  zzdef_(zinc, Zflippedfacets, "flipped facets", -1);
+  zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);
+  zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);
+  zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1);
+  zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);
+  zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);
+  zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);
+  zzdef_(zinc, Zmultiridge, "ridges with multiple neighbors", -1);
+}
+void qh_allstatB (void) {
+  zzdef_(zdoc, Zdoc1, "summary information", -1);
+  zdef_(zinc, Zvertices, "number of vertices in output", -1);
+  zdef_(zinc, Znumfacets, "number of facets in output", -1);
+  zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);
+  zdef_(zinc, Znowsimplicial, "number of simplicial facets that were merged", -1);
+  zdef_(zinc, Znumridges, "number of ridges in output", -1);
+  zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);
+  zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);
+  zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);
+  zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);
+  zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);
+  zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);
+  zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);
+  zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);
+  zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);
+  zdef_(zinc, Ztotvertices, "vertices created altogether", -1);
+  zzdef_(zinc, Zsetplane, "facets created altogether", -1);
+  zdef_(zinc, Ztotridges, "ridges created altogether", -1);
+  zdef_(zinc, Zpostfacets, "facets before post merge", -1);
+  zdef_(zadd, Znummergetot, "average merges per facet (at most 511)", Znumfacets);
+  zdef_(zmax, Znummergemax, "  maximum merges for a facet (at most 511)", -1);
+  zdef_(zinc, Zangle, NULL, -1);
+  zdef_(wadd, Wangle, "average angle (cosine) of facet normals for all ridges", Zangle);
+  zdef_(wmax, Wanglemax, "  maximum angle (cosine) of facet normals across a ridge", -1);
+  zdef_(wmin, Wanglemin, "  minimum angle (cosine) of facet normals across a ridge", -1);
+  zdef_(wadd, Wareatot, "total area of facets", -1);
+  zdef_(wmax, Wareamax, "  maximum facet area", -1);
+  zdef_(wmin, Wareamin, "  minimum facet area", -1);
+}  
+void qh_allstatC (void) {
+  zdef_(zdoc, Zdoc9, "build hull statistics", -1);
+  zzdef_(zinc, Zprocessed, "points processed", -1);
+  zzdef_(zinc, Zretry, "retries due to precision problems", -1);
+  zdef_(wmax, Wretrymax, "  max. random joggle", -1);
+  zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);
+  zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);
+  zdef_(zinc, Zinsidevisible, "  ave. visible facets without an horizon neighbor", Zprocessed);
+  zdef_(zadd, Zvisfacettot,  "  ave. facets deleted per iteration", Zprocessed);
+  zdef_(zmax, Zvisfacetmax,  "    maximum", -1);
+  zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);
+  zdef_(zmax, Zvisvertexmax, "    maximum", -1);
+  zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);
+  zdef_(zadd, Znewfacettot,  "ave. new or merged facets per iteration", Zprocessed);
+  zdef_(zmax, Znewfacetmax,  "    maximum (includes initial simplex)", -1);
+  zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);
+  zdef_(wadd, Wnewbalance2, "  standard deviation", -1);
+  zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);
+  zdef_(wadd, Wpbalance2, "  standard deviation", -1);
+  zdef_(zinc, Zpbalance, "  number of trials", -1);
+  zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
+  zdef_(zinc, Zdetsimplex, "determinants computed (area & initial hull)", -1);
+  zdef_(zinc, Znoarea, "determinants not computed because vertex too low", -1);
+  zdef_(zinc, Znotmax, "points ignored (not above max_outside)", -1);
+  zdef_(zinc, Znotgood, "points ignored (not above a good facet)", -1);
+  zdef_(zinc, Znotgoodnew, "points ignored (didn't create a good new facet)", -1);
+  zdef_(zinc, Zgoodfacet, "good facets found", -1);
+  zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
+  zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);
+  zdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
+  zzdef_(zinc, Zcheckpart, "  ave. distance tests per check", Ztotcheck);
+}
+void qh_allstatD(void) {
+  zdef_(zdoc, Zdoc4, "partitioning statistics (see previous for outer planes)", -1);
+  zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);
+  zdef_(zmax, Zdelvertexmax, "    maximum vertices deleted per iteration", -1);
+  zdef_(zinc, Zfindbest, "calls to findbest", -1);
+  zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);
+  zdef_(zmax, Zfindbestmax, " max. facets tested", -1);
+  zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);
+  zdef_(zinc, Zfindnew, "calls to findbestnew", -1);
+  zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);
+  zdef_(zmax, Zfindnewmax, " max. facets tested", -1);
+  zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);
+  zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);
+  zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);
+  zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);
+  zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);
+  zdef_(zinc, Zfindjump,       " ave. clearly better", Zfindhorizon);
+  zdef_(zinc, Zparthorizon, " horizon facets better than bestfacet", -1);
+  zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);
+  zdef_(zinc, Zpartflip, "  repartitioned coplanar points for flipped orientation", -1);
+  zdef_(zinc, Zpartinside, "inside points", -1);
+  zdef_(zinc, Zpartnear, "  inside points kept with a facet", -1);
+  zdef_(zinc, Zcoplanarinside, "  inside points that were coplanar with a facet", -1);
+  zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);
+}
+void qh_allstatE(void) {
+  zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
+  zdef_(zinc, Ztotpartition, "partitions of a point", -1);
+  zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);
+  zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1); 
+  zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1); 
+  zdef_(zinc, Zdistgood, "distance tests for checking good point", -1); 
+  zdef_(zinc, Zdistio, "distance tests for output", -1); 
+  zdef_(zinc, Zdiststat, "distance tests for statistics", -1); 
+  zdef_(zinc, Zdistplane, "total number of distance tests", -1);
+  zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);
+  zzdef_(zinc, Zpartcoplanar, "   distance tests for these partitions", -1);
+  zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);
+}
+void qh_allstatE2(void) {
+  zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);
+  zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);
+  zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);
+  zdef_(zinc, Zhashridge, "total lookups of subridges (duplicates and boundary)", -1);
+  zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);
+  zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);
+  zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);
+
+  zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);
+  zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);
+  zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);
+  zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);
+  zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);
+  zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1);
+  zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);
+  zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1);
+  zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
+}
+void qh_allstatF(void) {
+  zdef_(zdoc, Zdoc7, "statistics for merging", -1);
+  zdef_(zinc, Zpremergetot, "merge iterations", -1);
+  zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);
+  zdef_(zadd, Zmergeinitmax, "  maximum", -1);
+  zdef_(zadd, Zmergesettot, "  ave. additional non-convex ridges per iteration", Zpremergetot);
+  zdef_(zadd, Zmergesetmax, "  maximum additional in one pass", -1);
+  zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);
+  zdef_(zadd, Zmergesettot2, "  additional non-convex ridges", -1);
+  zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet (w/roundoff)", -1);
+  zdef_(wmin, Wminvertex, "max distance of merged vertex below facet (or roundoff)", -1);
+  zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1);
+  zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1);
+  zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1);
+  zdef_(zinc, Zmergesimplex, "merged a simplex", -1);
+  zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1);
+  zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1);
+  zzdef_(zadd, Zcyclefacettot, "  ave. facets per cycle", Zcyclehorizon);
+  zdef_(zmax, Zcyclefacetmax, "  max. facets", -1);
+  zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);
+  zdef_(zinc, Zmergenew, "new facets merged", -1);
+  zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);
+  zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);
+  zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1);
+  zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);
+  zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);
+  zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1);
+  zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1); 
+}
+void qh_allstatG(void) {
+  zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);
+  zdef_(wadd, Wacoplanartot, "  average merge distance", Zacoplanar);
+  zdef_(wmax, Wacoplanarmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);
+  zdef_(wadd, Wcoplanartot, "  average merge distance", Zcoplanar);
+  zdef_(wmax, Wcoplanarmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zconcave, "merges due to concave facets", -1);
+  zdef_(wadd, Wconcavetot, "  average merge distance", Zconcave);
+  zdef_(wmax, Wconcavemax, "  maximum merge distance", -1);
+  zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);
+  zdef_(wadd, Wavoidoldtot, "  average merge distance", Zavoidold);
+  zdef_(wmax, Wavoidoldmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);
+  zdef_(wadd, Wdegentot, "  average merge distance", Zdegen);
+  zdef_(wmax, Wdegenmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);
+  zdef_(wadd, Wflippedtot, "  average merge distance", Zflipped);
+  zdef_(wmax, Wflippedmax, "  maximum merge distance", -1);
+  zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1);
+  zdef_(wadd, Wduplicatetot, "  average merge distance", Zduplicate);
+  zdef_(wmax, Wduplicatemax, "  maximum merge distance", -1);
+}
+void qh_allstatH(void) {
+  zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1);
+  zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);
+  zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);
+  zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);
+  zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);
+  zdef_(zinc, Zdupridge, "  duplicate ridges detected", -1);
+  zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
+  zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
+  zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1);
+  zdef_(zinc, Zdelfacetdup, "  facets deleted because of no neighbors", -1);
+  zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);
+  zdef_(zinc, Zremvertexdel, "  deleted", -1);
+  zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);
+  zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);
+  zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);
+  zdef_(zadd, Zintersecttot, "   ave. number found per vertex", Zintersect);
+  zdef_(zmax, Zintersectmax, "   max. found for a vertex", -1);
+  zdef_(zinc, Zvertexridge, NULL, -1);
+  zdef_(zadd, Zvertexridgetot, "  ave. number of ridges per tested vertex", Zvertexridge);
+  zdef_(zmax, Zvertexridgemax, "  max. number of ridges per tested vertex", -1);
+
+  zdef_(zdoc, Zdoc10, "memory usage statistics (in bytes)", -1);
+  zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);
+  zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);
+  zdef_(zadd, Zmempoints, "for input points and outside and coplanar sets",-1);
+  zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
+} /* allstat */
+
+void qh_allstatI(void) {
+  qhstat vridges= qhstat next;
+  zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);
+  zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);
+  zzdef_(wadd, Wridge, "  ave. distance to ridge", Zridge);
+  zzdef_(wmax, Wridgemax, "  max. distance to ridge", -1);
+  zzdef_(zinc, Zridgemid, "bounded ridges", -1);
+  zzdef_(wadd, Wridgemid, "  ave. distance of midpoint to ridge", Zridgemid);
+  zzdef_(wmax, Wridgemidmax, "  max. distance of midpoint to ridge", -1);
+  zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);
+  zzdef_(wadd, Wridgeok, "  ave. angle to ridge", Zridgeok);
+  zzdef_(wmax, Wridgeokmax, "  max. angle to ridge", -1);
+  zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);
+  zzdef_(wadd, Wridge0, "  ave. angle to ridge", Zridge0);
+  zzdef_(wmax, Wridge0max, "  max. angle to ridge", -1);
+
+  zdef_(zdoc, Zdoc12, "Triangulation statistics (Qt)", -1);
+  zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);
+  zdef_(zadd, Ztricoplanartot, "  ave. new facets created (may be deleted)", Ztricoplanar);
+  zdef_(zmax, Ztricoplanarmax, "  max. new facets created", -1);
+  zdef_(zinc, Ztrinull, "null new facets deleted (duplicated vertex)", -1);
+  zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted (same vertices)", -1);
+  zdef_(zinc, Ztridegen, "degenerate new facets in output (same ridge)", -1);
+} /* allstat */
+
+/*---------------------------------
+  
+  qh_allstatistics()
+    reset printed flag for all statistics
+*/
+void qh_allstatistics (void) {
+  int i;
+  
+  for (i=ZEND; i--; ) 
+    qhstat printed[i]= False;
+} /* allstatistics */
+
+#if qh_KEEPstatistics
+/*---------------------------------
+  
+  qh_collectstatistics()
+    collect statistics for qh.facet_list
+
+*/
+void qh_collectstatistics (void) {
+  facetT *facet, *neighbor, **neighborp;
+  vertexT *vertex, **vertexp;
+  realT dotproduct, dist;
+  int sizneighbors, sizridges, sizvertices, i;
+  
+  qh old_randomdist= qh RANDOMdist;
+  qh RANDOMdist= False;
+  zval_(Zmempoints)= qh num_points * qh normal_size + 
+                             sizeof (qhT) + sizeof (qhstatT);
+  zval_(Zmemfacets)= 0;
+  zval_(Zmemridges)= 0;
+  zval_(Zmemvertices)= 0;
+  zval_(Zangle)= 0;
+  wval_(Wangle)= 0.0;
+  zval_(Znumridges)= 0;
+  zval_(Znumfacets)= 0;
+  zval_(Znumneighbors)= 0;
+  zval_(Znumvertices)= 0;
+  zval_(Znumvneighbors)= 0;
+  zval_(Znummergetot)= 0;
+  zval_(Znummergemax)= 0;
+  zval_(Zvertices)= qh num_vertices - qh_setsize (qh del_vertices);
+  if (qh MERGING || qh APPROXhull || qh JOGGLEmax < REALmax/2)
+    wmax_(Wmaxoutside, qh max_outside);
+  if (qh MERGING)
+    wmin_(Wminvertex, qh min_vertex);
+  FORALLfacets
+    facet->seen= False;
+  if (qh DELAUNAY) {
+    FORALLfacets {
+      if (facet->upperdelaunay != qh UPPERdelaunay)
+        facet->seen= True; /* remove from angle statistics */
+    }
+  }
+  FORALLfacets {
+    if (facet->visible && qh NEWfacets)
+      continue;
+    sizvertices= qh_setsize (facet->vertices);
+    sizneighbors= qh_setsize (facet->neighbors);
+    sizridges= qh_setsize (facet->ridges);
+    zinc_(Znumfacets);
+    zadd_(Znumvertices, sizvertices);
+    zmax_(Zmaxvertices, sizvertices);
+    zadd_(Znumneighbors, sizneighbors);
+    zmax_(Zmaxneighbors, sizneighbors);
+    zadd_(Znummergetot, facet->nummerge);
+    i= facet->nummerge; /* avoid warnings */
+    zmax_(Znummergemax, i); 
+    if (!facet->simplicial) {
+      if (sizvertices == qh hull_dim) {
+	zinc_(Znowsimplicial);
+      }else {
+        zinc_(Znonsimplicial);
+      }
+    }
+    if (sizridges) {
+      zadd_(Znumridges, sizridges);
+      zmax_(Zmaxridges, sizridges);
+    }
+    zadd_(Zmemfacets, sizeof (facetT) + qh normal_size + 2*sizeof (setT) 
+       + SETelemsize * (sizneighbors + sizvertices));
+    if (facet->ridges) {
+      zadd_(Zmemridges,
+	 sizeof (setT) + SETelemsize * sizridges + sizridges * 
+         (sizeof (ridgeT) + sizeof (setT) + SETelemsize * (qh hull_dim-1))/2);
+    }
+    if (facet->outsideset)
+      zadd_(Zmempoints, sizeof (setT) + SETelemsize * qh_setsize (facet->outsideset));
+    if (facet->coplanarset)
+      zadd_(Zmempoints, sizeof (setT) + SETelemsize * qh_setsize (facet->coplanarset));
+    if (facet->seen) /* Delaunay upper envelope */
+      continue;
+    facet->seen= True;
+    FOREACHneighbor_(facet) {
+      if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge
+	  || neighbor->seen || !facet->normal || !neighbor->normal)
+	continue;
+      dotproduct= qh_getangle(facet->normal, neighbor->normal);
+      zinc_(Zangle);
+      wadd_(Wangle, dotproduct);
+      wmax_(Wanglemax, dotproduct)
+      wmin_(Wanglemin, dotproduct)
+    }
+    if (facet->normal) {
+      FOREACHvertex_(facet->vertices) {
+        zinc_(Zdiststat);
+        qh_distplane(vertex->point, facet, &dist);
+        wmax_(Wvertexmax, dist);
+        wmin_(Wvertexmin, dist);
+      }
+    }
+  }
+  FORALLvertices {
+    if (vertex->deleted)
+      continue;
+    zadd_(Zmemvertices, sizeof (vertexT));
+    if (vertex->neighbors) {
+      sizneighbors= qh_setsize (vertex->neighbors);
+      zadd_(Znumvneighbors, sizneighbors);
+      zmax_(Zmaxvneighbors, sizneighbors);
+      zadd_(Zmemvertices, sizeof (vertexT) + SETelemsize * sizneighbors);
+    }
+  }
+  qh RANDOMdist= qh old_randomdist;
+} /* collectstatistics */
+#endif /* qh_KEEPstatistics */
+
+/*---------------------------------
+  
+  qh_freestatistics(  )
+    free memory used for statistics
+*/
+void qh_freestatistics (void) {
+
+#if qh_QHpointer
+  free (qh_qhstat);
+  qh_qhstat= NULL;
+#endif
+} /* freestatistics */
+
+/*---------------------------------
+  
+  qh_initstatistics(  )
+    allocate and initialize statistics
+
+  notes:
+    uses malloc() instead of qh_memalloc() since mem.c not set up yet
+*/
+void qh_initstatistics (void) {
+  int i;
+  realT realx;
+  int intx;
+
+#if qh_QHpointer
+  if (!(qh_qhstat= (qhstatT *)malloc (sizeof(qhstatT)))) {
+    fprintf (qhmem.ferr, "qhull error (qh_initstatistics): insufficient memory\n");
+    exit (1);  /* can not use qh_errexit() */
+  }
+#endif
+  
+  qhstat next= 0;
+  qh_allstatA();
+  qh_allstatB();
+  qh_allstatC();
+  qh_allstatD();
+  qh_allstatE();
+  qh_allstatE2();
+  qh_allstatF();
+  qh_allstatG();
+  qh_allstatH();
+  qh_allstatI();
+  if (qhstat next > sizeof(qhstat id)) {
+    fprintf (qhmem.ferr, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\
+      qhstat.next %d should be <= sizeof(qhstat id) %ld\n", qhstat next, sizeof(qhstat id));
+#if 0 /* for locating error, Znumridges should be duplicated */
+    for (i=0; i < ZEND; i++) {
+      int j;
+      for (j=i+1; j < ZEND; j++) {
+	if (qhstat id[i] == qhstat id[j]) {
+          fprintf (qhmem.ferr, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n", 
+	      qhstat id[i], i, j);
+	}
+      }
+    }
+#endif 
+    exit (1);  /* can not use qh_errexit() */
+  }
+  qhstat init[zinc].i= 0;
+  qhstat init[zadd].i= 0;
+  qhstat init[zmin].i= INT_MAX;
+  qhstat init[zmax].i= INT_MIN;
+  qhstat init[wadd].r= 0;
+  qhstat init[wmin].r= REALmax;
+  qhstat init[wmax].r= -REALmax;
+  for (i=0; i < ZEND; i++) {
+    if (qhstat type[i] > ZTYPEreal) {
+      realx= qhstat init[(unsigned char)(qhstat type[i])].r;
+      qhstat stats[i].r= realx;
+    }else if (qhstat type[i] != zdoc) {
+      intx= qhstat init[(unsigned char)(qhstat type[i])].i;
+      qhstat stats[i].i= intx;
+    }
+  }
+} /* initstatistics */
+
+/*---------------------------------
+  
+  qh_newstats(  )
+    returns True if statistics for zdoc
+
+  returns:
+    next zdoc
+*/
+boolT qh_newstats (int index, int *nextindex) {
+  boolT isnew= False;
+  int start, i;
+
+  if (qhstat type[qhstat id[index]] == zdoc) 
+    start= index+1;
+  else
+    start= index;
+  for (i= start; i < qhstat next && qhstat type[qhstat id[i]] != zdoc; i++) {
+    if (!qh_nostatistic(qhstat id[i]) && !qhstat printed[qhstat id[i]])
+	isnew= True;
+  }
+  *nextindex= i;
+  return isnew;
+} /* newstats */
+
+/*---------------------------------
+  
+  qh_nostatistic( index )
+    true if no statistic to print
+*/
+boolT qh_nostatistic (int i) {
+  
+  if ((qhstat type[i] > ZTYPEreal
+       &&qhstat stats[i].r == qhstat init[(unsigned char)(qhstat type[i])].r)
+      || (qhstat type[i] < ZTYPEreal
+	  &&qhstat stats[i].i == qhstat init[(unsigned char)(qhstat type[i])].i))
+    return True;
+  return False;
+} /* nostatistic */
+
+#if qh_KEEPstatistics
+/*---------------------------------
+  
+  qh_printallstatistics( fp, string )
+    print all statistics with header 'string'
+*/
+void qh_printallstatistics (FILE *fp, char *string) {
+
+  qh_allstatistics();
+  qh_collectstatistics();
+  qh_printstatistics (fp, string);
+  qh_memstatistics (fp);
+}
+
+
+/*---------------------------------
+  
+  qh_printstatistics( fp, string )
+    print statistics to a file with header 'string'
+    skips statistics with qhstat.printed[] (reset with qh_allstatistics)
+
+  see: 
+    qh_printallstatistics()
+*/
+void qh_printstatistics (FILE *fp, char *string) {
+  int i, k;
+  realT ave;
+  
+  if (qh num_points != qh num_vertices) {
+    wval_(Wpbalance)= 0;
+    wval_(Wpbalance2)= 0;
+  }else
+    wval_(Wpbalance2)= qh_stddev (zval_(Zpbalance), wval_(Wpbalance), 
+                                 wval_(Wpbalance2), &ave);
+  wval_(Wnewbalance2)= qh_stddev (zval_(Zprocessed), wval_(Wnewbalance), 
+                                 wval_(Wnewbalance2), &ave);
+  fprintf (fp, "\n\
+%s\n\
+ qhull invoked by: %s | %s\n%s with options:\n%s\n", string, qh rbox_command, 
+     qh qhull_command, qh_VERSION, qh qhull_options);
+  fprintf (fp, "\nprecision constants:\n\
+ %6.2g max. abs. coordinate in the (transformed) input ('Qbd:n')\n\
+ %6.2g max. roundoff error for distance computation ('En')\n\
+ %6.2g max. roundoff error for angle computations\n\
+ %6.2g min. distance for outside points ('Wn')\n\
+ %6.2g min. distance for visible facets ('Vn')\n\
+ %6.2g max. distance for coplanar facets ('Un')\n\
+ %6.2g max. facet width for recomputing centrum and area\n\
+", 
+  qh MAXabs_coord, qh DISTround, qh ANGLEround, qh MINoutside, 
+        qh MINvisible, qh MAXcoplanar, qh WIDEfacet);
+  if (qh KEEPnearinside)
+    fprintf(fp, "\
+ %6.2g max. distance for near-inside points\n", qh NEARinside);
+  if (qh premerge_cos < REALmax/2) fprintf (fp, "\
+ %6.2g max. cosine for pre-merge angle\n", qh premerge_cos);
+  if (qh PREmerge) fprintf (fp, "\
+ %6.2g radius of pre-merge centrum\n", qh premerge_centrum);
+  if (qh postmerge_cos < REALmax/2) fprintf (fp, "\
+ %6.2g max. cosine for post-merge angle\n", qh postmerge_cos);
+  if (qh POSTmerge) fprintf (fp, "\
+ %6.2g radius of post-merge centrum\n", qh postmerge_centrum);
+  fprintf (fp, "\
+ %6.2g max. distance for merging two simplicial facets\n\
+ %6.2g max. roundoff error for arithmetic operations\n\
+ %6.2g min. denominator for divisions\n\
+  zero diagonal for Gauss: ", qh ONEmerge, REALepsilon, qh MINdenom);
+  for (k=0; k < qh hull_dim; k++)
+    fprintf (fp, "%6.2e ", qh NEARzero[k]);
+  fprintf (fp, "\n\n");
+  for (i=0 ; i < qhstat next; ) 
+    qh_printstats (fp, i, &i);
+} /* printstatistics */
+#endif /* qh_KEEPstatistics */
+
+/*---------------------------------
+  
+  qh_printstatlevel( fp, id )
+    print level information for a statistic
+
+  notes:
+    nop if id >= ZEND, printed, or same as initial value
+*/
+void qh_printstatlevel (FILE *fp, int id, int start) {
+#define NULLfield "       "
+
+  if (id >= ZEND || qhstat printed[id])
+    return;
+  if (qhstat type[id] == zdoc) {
+    fprintf (fp, "%s\n", qhstat doc[id]);
+    return;
+  }
+  start= 0; /* not used */
+  if (qh_nostatistic(id) || !qhstat doc[id])
+    return;
+  qhstat printed[id]= True;
+  if (qhstat count[id] != -1 
+      && qhstat stats[(unsigned char)(qhstat count[id])].i == 0)
+    fprintf (fp, " *0 cnt*");
+  else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] == -1)
+    fprintf (fp, "%7.2g", qhstat stats[id].r);
+  else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] != -1)
+    fprintf (fp, "%7.2g", qhstat stats[id].r/ qhstat stats[(unsigned char)(qhstat count[id])].i);
+  else if (qhstat type[id] < ZTYPEreal && qhstat count[id] == -1)
+    fprintf (fp, "%7d", qhstat stats[id].i);
+  else if (qhstat type[id] < ZTYPEreal && qhstat count[id] != -1)
+    fprintf (fp, "%7.3g", (realT) qhstat stats[id].i / qhstat stats[(unsigned char)(qhstat count[id])].i);
+  fprintf (fp, " %s\n", qhstat doc[id]);
+} /* printstatlevel */
+
+
+/*---------------------------------
+  
+  qh_printstats( fp, index, nextindex )
+    print statistics for a zdoc group
+
+  returns:
+    next zdoc if non-null
+*/
+void qh_printstats (FILE *fp, int index, int *nextindex) {
+  int j, nexti;
+
+  if (qh_newstats (index, &nexti)) {
+    fprintf (fp, "\n");
+    for (j=index; j--------------------------------
+  
+  qh_stddev( num, tot, tot2, ave )
+    compute the standard deviation and average from statistics
+
+    tot2 is the sum of the squares
+  notes:
+    computes r.m.s.: 
+      (x-ave)^2 
+      == x^2 - 2x tot/num +   (tot/num)^2
+      == tot2 - 2 tot tot/num + tot tot/num 
+      == tot2 - tot ave
+*/
+realT qh_stddev (int num, realT tot, realT tot2, realT *ave) {
+  realT stddev;
+
+  *ave= tot/num;
+  stddev= sqrt (tot2/num - *ave * *ave);
+  return stddev;
+} /* stddev */
+
+#endif /* qh_KEEPstatistics */ 
+
+#if !qh_KEEPstatistics
+void    qh_collectstatistics (void) {}
+void    qh_printallstatistics (FILE *fp, char *string) {};
+void    qh_printstatistics (FILE *fp, char *string) {}
+#endif
+
diff --git a/extern/qhull/src/stat.h b/extern/qhull/src/stat.h
new file mode 100644
index 00000000000..1dae54ed21d
--- /dev/null
+++ b/extern/qhull/src/stat.h
@@ -0,0 +1,520 @@
+  /*
  ---------------------------------
+
+   stat.h 
+     contains all statistics that are collected for qhull
+
+   see qh-stat.htm and stat.c
+
+   copyright (c) 1993-2002, The Geometry Center
+
+   recompile qhull if you change this file
+
+   Integer statistics are Z* while real statistics are W*.  
+
+   define maydebugx to call a routine at every statistic event
+
+*/
+
+#ifndef qhDEFstat
+#define qhDEFstat 1
+
+
+/*---------------------------------
+
+  qh_KEEPstatistics
+    0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
+*/
+#ifndef qh_KEEPstatistics
+#define qh_KEEPstatistics 1
+#endif
+
+/*---------------------------------
+
+  Zxxx for integers, Wxxx for reals
+
+  notes:
+    be sure that all statistics are defined in stat.c
+      otherwise initialization may core dump
+    can pick up all statistics by:
+      grep '[zw].*_[(][ZW]' *.c >z.x
+    remove trailers with query">-
+    remove leaders with  query-replace-regexp [ ^I]+  (
+*/
+#if qh_KEEPstatistics
+enum statistics {     /* alphabetical after Z/W */
+    Zacoplanar,
+    Wacoplanarmax,
+    Wacoplanartot,
+    Zangle,
+    Wangle,
+    Wanglemax,
+    Wanglemin,
+    Zangletests,
+    Wareatot,
+    Wareamax,
+    Wareamin,
+    Zavoidold,
+    Wavoidoldmax,
+    Wavoidoldtot,
+    Zback0,
+    Zbestcentrum,
+    Zbestdist,
+    Zcentrumtests,
+    Zcheckpart,
+    Zcomputefurthest,
+    Zconcave,
+    Wconcavemax,
+    Wconcavetot,
+    Zconcaveridges,
+    Zconcaveridge,
+    Zcoplanar,
+    Wcoplanarmax,
+    Wcoplanartot,
+    Zcoplanarangle,
+    Zcoplanarcentrum,
+    Zcoplanarhorizon,
+    Zcoplanarinside,
+    Zcoplanarpart,
+    Zcoplanarridges,
+    Wcpu,
+    Zcyclefacetmax,
+    Zcyclefacettot,
+    Zcyclehorizon,
+    Zcyclevertex,
+    Zdegen,
+    Wdegenmax,
+    Wdegentot,
+    Zdegenvertex,
+    Zdelfacetdup, 
+    Zdelridge,
+    Zdelvertextot,
+    Zdelvertexmax,
+    Zdetsimplex,
+    Zdistcheck,
+    Zdistconvex,
+    Zdistgood,
+    Zdistio,
+    Zdistplane,
+    Zdiststat,
+    Zdistvertex,
+    Zdistzero,
+    Zdoc1,
+    Zdoc2,
+    Zdoc3,
+    Zdoc4,
+    Zdoc5,
+    Zdoc6,
+    Zdoc7,
+    Zdoc8,
+    Zdoc9,
+    Zdoc10,
+    Zdoc11,
+    Zdoc12,
+    Zdropdegen,
+    Zdropneighbor,
+    Zdupflip,
+    Zduplicate,
+    Wduplicatemax,
+    Wduplicatetot,
+    Zdupridge,
+    Zdupsame,
+    Zflipped, 
+    Wflippedmax, 
+    Wflippedtot, 
+    Zflippedfacets,
+    Zfindbest,
+    Zfindbestmax,
+    Zfindbesttot,
+    Zfindcoplanar,
+    Zfindfail,
+    Zfindhorizon,
+    Zfindhorizonmax,
+    Zfindhorizontot,
+    Zfindjump,
+    Zfindnew,
+    Zfindnewmax,
+    Zfindnewtot,
+    Zfindnewjump,
+    Zfindnewsharp,
+    Zgauss0,
+    Zgoodfacet,
+    Zhashlookup,
+    Zhashridge,
+    Zhashridgetest,
+    Zhashtests,
+    Zinsidevisible,
+    Zintersect,
+    Zintersectfail,
+    Zintersectmax,
+    Zintersectnum,
+    Zintersecttot,
+    Zmaxneighbors,
+    Wmaxout,
+    Wmaxoutside,
+    Zmaxridges,
+    Zmaxvertex,
+    Zmaxvertices,
+    Zmaxvneighbors,
+    Zmemfacets,
+    Zmempoints,
+    Zmemridges,
+    Zmemvertices,
+    Zmergeflipdup,
+    Zmergehorizon,
+    Zmergeinittot,
+    Zmergeinitmax,
+    Zmergeinittot2,
+    Zmergeintohorizon,
+    Zmergenew,
+    Zmergesettot,
+    Zmergesetmax,
+    Zmergesettot2,
+    Zmergesimplex,
+    Zmergevertex,
+    Wmindenom,
+    Wminvertex,
+    Zminnorm,
+    Zmultiridge,
+    Znearlysingular,
+    Zneighbor,
+    Wnewbalance,
+    Wnewbalance2,
+    Znewfacettot,
+    Znewfacetmax,
+    Znewvertex,
+    Wnewvertex,
+    Wnewvertexmax,
+    Znoarea,
+    Znonsimplicial,
+    Znowsimplicial,
+    Znotgood,
+    Znotgoodnew,
+    Znotmax,
+    Znumfacets,
+    Znummergemax,
+    Znummergetot,
+    Znumneighbors,
+    Znumridges,
+    Znumvertices,
+    Znumvisibility,
+    Znumvneighbors,
+    Zonehorizon,
+    Zpartangle,
+    Zpartcoplanar,
+    Zpartflip,
+    Zparthorizon,
+    Zpartinside,
+    Zpartition, 
+    Zpartitionall,
+    Zpartnear,
+    Zpbalance,
+    Wpbalance,
+    Wpbalance2, 
+    Zpostfacets, 
+    Zpremergetot,
+    Zprocessed,
+    Zremvertex,
+    Zremvertexdel,
+    Zrenameall,
+    Zrenamepinch,
+    Zrenameshare,
+    Zretry,
+    Wretrymax,
+    Zridge,
+    Wridge,
+    Wridgemax,
+    Zridge0,
+    Wridge0,
+    Wridge0max,
+    Zridgemid,
+    Wridgemid,
+    Wridgemidmax,
+    Zridgeok,
+    Wridgeok,
+    Wridgeokmax,
+    Zsearchpoints,
+    Zsetplane,
+    Ztestvneighbor,
+    Ztotcheck,
+    Ztothorizon,
+    Ztotmerge,
+    Ztotpartcoplanar,
+    Ztotpartition,
+    Ztotridges,
+    Ztotvertices,
+    Ztotvisible,
+    Ztricoplanar,
+    Ztricoplanarmax,
+    Ztricoplanartot,
+    Ztridegen,
+    Ztrimirror,
+    Ztrinull,
+    Wvertexmax,
+    Wvertexmin,
+    Zvertexridge,
+    Zvertexridgetot,
+    Zvertexridgemax,
+    Zvertices,
+    Zvisfacettot,
+    Zvisfacetmax,
+    Zvisvertextot,
+    Zvisvertexmax,
+    Zwidefacet,
+    Zwidevertices,
+    ZEND};
+
+/*---------------------------------
+
+  Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0
+
+  notes:
+    be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
+*/
+#else
+enum statistics {     /* for zzdef etc. macros */
+  Zback0,
+  Zbestdist,
+  Zcentrumtests,
+  Zcheckpart,
+  Zconcaveridges,
+  Zcoplanarhorizon,
+  Zcoplanarpart,
+  Zcoplanarridges,
+  Zcyclefacettot,
+  Zcyclehorizon,
+  Zdelvertextot,
+  Zdistcheck,
+  Zdistconvex,
+  Zdistzero,
+  Zdoc1,
+  Zdoc2,
+  Zdoc3,
+  Zdoc11,
+  Zflippedfacets,
+  Zgauss0,
+  Zminnorm,
+  Zmultiridge,
+  Znearlysingular,
+  Wnewvertexmax,
+  Znumvisibility,
+  Zpartcoplanar,
+  Zpartition,
+  Zpartitionall,
+  Zprocessed,
+  Zretry,
+  Zridge,
+  Wridge,
+  Wridgemax,
+  Zridge0,
+  Wridge0,
+  Wridge0max,
+  Zridgemid,
+  Wridgemid,
+  Wridgemidmax,
+  Zridgeok,
+  Wridgeok,
+  Wridgeokmax,
+  Zsetplane,
+  Ztotmerge,
+    ZEND};
+#endif
+
+/*---------------------------------
+  
+  ztype
+    the type of a statistic sets its initial value.  
+
+  notes:
+    The type should be the same as the macro for collecting the statistic
+*/
+enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};
+
+/*========== macros and constants =============*/
+
+/*----------------------------------
+  
+  MAYdebugx
+    define as maydebug() to be called frequently for error trapping
+*/
+#define MAYdebugx 
+
+/*----------------------------------
+  
+  zzdef_, zdef_( type, name, doc, -1)
+    define a statistic (assumes 'qhstat.next= 0;')
+
+  zdef_( type, name, doc, count)
+    define an averaged statistic
+    printed as name/count
+*/
+#define zzdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
+   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
+#if qh_KEEPstatistics
+#define zdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
+   qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
+#else
+#define zdef_(type,name,doc,count)
+#endif
+
+/*----------------------------------
+  
+  zzinc_( name ), zinc_( name)
+    increment an integer statistic
+*/
+#define zzinc_(id) {MAYdebugx; qhstat stats[id].i++;}
+#if qh_KEEPstatistics
+#define zinc_(id) {MAYdebugx; qhstat stats[id].i++;}
+#else
+#define zinc_(id) {}
+#endif
+
+/*----------------------------------
+  
+  zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
+    add value to an integer or real statistic
+*/
+#define zzadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
+#define wwadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
+#if qh_KEEPstatistics
+#define zadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
+#define wadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
+#else
+#define zadd_(id, val) {}
+#define wadd_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zzval_( name ), zval_( name ), wwval_( name )
+    set or return value of a statistic
+*/
+#define zzval_(id) ((qhstat stats[id]).i)
+#define wwval_(id) ((qhstat stats[id]).r)
+#if qh_KEEPstatistics
+#define zval_(id) ((qhstat stats[id]).i)
+#define wval_(id) ((qhstat stats[id]).r)
+#else
+#define zval_(id) qhstat tempi
+#define wval_(id) qhstat tempr
+#endif
+
+/*----------------------------------
+
+  zmax_( id, val ), wmax_( id, value )
+    maximize id with val
+*/
+#define wwmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
+#if qh_KEEPstatistics
+#define zmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].i,(val));}
+#define wmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
+#else
+#define zmax_(id, val) {}
+#define wmax_(id, val) {}
+#endif
+
+/*----------------------------------
+
+  zmin_( id, val ), wmin_( id, value )
+    minimize id with val
+*/
+#if qh_KEEPstatistics
+#define zmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].i,(val));}
+#define wmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].r,(val));}
+#else
+#define zmin_(id, val) {}
+#define wmin_(id, val) {}
+#endif
+
+/*================== stat.h types ==============*/
+
+
+/*----------------------------------
+ 
+  intrealT
+    union of integer and real, used for statistics
+*/
+typedef union intrealT intrealT;    /* union of int and realT */
+union intrealT {
+    int i;
+    realT r;
+};
+
+/*----------------------------------
+  
+  qhstat
+    global data structure for statistics
+  
+  notes:
+   access to qh_qhstat is via the "qhstat" macro.  There are two choices
+   qh_QHpointer = 1     access globals via a pointer
+                        enables qh_saveqhull() and qh_restoreqhull()
+		= 0     qh_qhstat is a static data structure
+		        only one instance of qhull() can be active at a time
+			default value
+   qh_QHpointer is defined in qhull.h
+
+   allocated in stat.c
+*/
+typedef struct qhstatT qhstatT; 
+#if qh_QHpointer
+#define qhstat qh_qhstat->
+extern qhstatT *qh_qhstat;
+#else
+#define qhstat qh_qhstat.
+extern qhstatT qh_qhstat; 
+#endif
+struct qhstatT {  
+  intrealT   stats[ZEND];     /* integer and real statistics */
+  unsigned   char id[ZEND+10]; /* id's in print order */
+  char      *doc[ZEND];       /* array of documentation strings */
+  short int  count[ZEND];     /* -1 if none, else index of count to use */
+  char       type[ZEND];      /* type, see ztypes above */
+  char       printed[ZEND];   /* true, if statistic has been printed */
+  intrealT   init[ZTYPEend];  /* initial values by types, set initstatistics */
+
+  int        next;            /* next index for zdef_ */
+  int        precision;       /* index for precision problems */
+  int        vridges;         /* index for Voronoi ridges */
+  int        tempi;
+  realT      tempr;
+};
+
+/*========== function prototypes ===========*/
+
+void    qh_allstatA(void);
+void    qh_allstatB(void);
+void    qh_allstatC(void);
+void    qh_allstatD(void);
+void    qh_allstatE(void);
+void    qh_allstatE2(void);
+void    qh_allstatF(void);
+void    qh_allstatG(void);
+void    qh_allstatH(void);
+void    qh_allstatI(void);
+void    qh_allstatistics (void);
+void    qh_collectstatistics (void);
+void	qh_freestatistics (void);
+void    qh_initstatistics (void);
+boolT 	qh_newstats (int index, int *nextindex);
+boolT 	qh_nostatistic (int i);
+void    qh_printallstatistics (FILE *fp, char *string);
+void    qh_printstatistics (FILE *fp, char *string);
+void  	qh_printstatlevel (FILE *fp, int id, int start);
+void  	qh_printstats (FILE *fp, int index, int *nextindex);
+realT   qh_stddev (int num, realT tot, realT tot2, realT *ave);
+
+#endif   /* qhDEFstat */
diff --git a/extern/qhull/src/unix.c b/extern/qhull/src/unix.c
new file mode 100644
index 00000000000..5ec5feab16c
--- /dev/null
+++ b/extern/qhull/src/unix.c
@@ -0,0 +1,376 @@
+/*
  ---------------------------------
+
+   unix.c
+     command line interface to qhull
+	 includes SIOUX interface for Macintoshes
+
+   see qh-qhull.htm
+
+   copyright (c) 1993-2002, The Geometry Center
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "qhull.h"
+#include "mem.h"
+#include "qset.h"
+
+#if __MWERKS__ && __POWERPC__
+#include 
+#include 
+#include 
+#include 
+
+#elif __cplusplus
+extern "C" {
+  int isatty (int);
+}
+
+#elif _MSC_VER
+#include 
+#define isatty _isatty
+
+#else
+int isatty (int);  /* returns 1 if stdin is a tty
+		   if "Undefined symbol" this can be deleted along with call in main() */
+#endif
+
+/*---------------------------------
+
+  qh_prompt 
+    long prompt for qhull
+    
+  see:
+    concise prompt below
+*/  
+char qh_prompta[]= "\n\
+qhull- compute convex hulls and related structures.\n\
+    http://www.geom.umn.edu/software/qhull  %s\n\
+\n\
+input (stdin):\n\
+    first lines: dimension and number of points (or vice-versa).\n\
+    other lines: point coordinates, best if one point per line\n\
+    comments:    start with a non-numeric character\n\
+    halfspaces:  use dim plus one and put offset after coefficients.\n\
+                 May be preceeded by a single interior point ('H').\n\
+\n\
+options:\n\
+    d    - Delaunay triangulation by lifting points to a paraboloid\n\
+    d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
+    v    - Voronoi diagram (dual of the Delaunay triangulation)\n\
+    v Qu - furthest-site Voronoi diagram\n\
+    Hn,n,... - halfspace intersection about point [n,n,0,...]\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Qc   - keep coplanar points with nearest facet\n\
+    Qi   - keep interior points with nearest facet\n\
+\n\
+Qhull control options:\n\
+    Qbk:n   - scale coord k so that low bound is n\n\
+      QBk:n - scale coord k so that upper bound is n (QBk is %2.2g)\n\
+    QbB  - scale input to unit cube centered at the origin\n\
+    Qbb  - scale last coordinate to [0,m] for Delaunay triangulations\n\
+    Qbk:0Bk:0 - remove k-th coordinate from input\n\
+    QJn  - randomly joggle input in range [-n,n]\n\
+    QRn  - random rotation (n=seed, n=0 time, n=-1 time/no rotate)\n\
+%s%s%s%s";  /* split up qh_prompt for Visual C++ */
+char qh_promptb[]= "\
+    Qf   - partition point to furthest outside facet\n\
+    Qg   - only build good facets (needs 'QGn', 'QVn', or 'PdD')\n\
+    Qm   - only process points that would increase max_outside\n\
+    Qr   - process random outside points instead of furthest ones\n\
+    Qs   - search all points for the initial simplex\n\
+    Qu   - for 'd' or 'v', compute upper hull without point at-infinity\n\
+              returns furthest-site Delaunay triangulation\n\
+    Qv   - test vertex neighbors for convexity\n\
+    Qx   - exact pre-merges (skips coplanar and angle-coplanar facets)\n\
+    Qz   - add point-at-infinity to Delaunay triangulation\n\
+    QGn  - good facet if visible from point n, -n for not visible\n\
+    QVn  - good facet if it includes point n, -n if not\n\
+    Q0   - turn off default premerge with 'C-0'/'Qx'\n\
+    Q1	   - sort merges by type instead of angle\n\
+    Q2   - merge all non-convex at once instead of independent sets\n\
+    Q3   - do not merge redundant vertices\n\
+    Q4   - avoid old->new merges\n\
+    Q5   - do not correct outer planes at end of qhull\n\
+    Q6   - do not pre-merge concave or coplanar facets\n\
+    Q7   - depth-first processing instead of breadth-first\n\
+    Q8   - do not process near-inside points\n\
+    Q9   - process furthest of furthest points\n\
+    Q10  - no special processing for narrow distributions\n\
+    Q11  - copy normals and recompute centrums for tricoplanar facets\n\
+\n\
+";
+char qh_promptc[]= "\
+Topts- Trace options:\n\
+    T4   - trace at level n, 4=all, 5=mem/gauss, -1= events\n\
+    Tc   - check frequently during execution\n\
+    Ts   - print statistics\n\
+    Tv   - verify result: structure, convexity, and point inclusion\n\
+    Tz   - send all output to stdout\n\
+    TFn  - report summary when n or more facets created\n\
+    TI file - input data from file, no spaces or single quotes\n\
+    TO file - output results to file, may be enclosed in single quotes\n\
+    TPn  - turn on tracing when point n added to hull\n\
+     TMn - turn on tracing at merge n\n\
+     TWn - trace merge facets when width > n\n\
+    TRn  - rerun qhull n times.  Use with 'QJn'\n\
+    TVn  - stop qhull after adding point n, -n for before (see TCn)\n\
+     TCn - stop qhull after building cone for point n (see TVn)\n\
+\n\
+Precision options:\n\
+    Cn   - radius of centrum (roundoff added).  Merge facets if non-convex\n\
+     An  - cosine of maximum angle.  Merge facets if cosine > n or non-convex\n\
+           C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge\n\
+    En   - max roundoff error for distance computation\n\
+    Rn   - randomly perturb computations by a factor of [1-n,1+n]\n\
+    Vn   - min distance above plane for a visible facet (default 3C-n or En)\n\
+    Un   - max distance below plane for a new, coplanar point (default Vn)\n\
+    Wn   - min facet width for outside point (before roundoff, default 2Vn)\n\
+\n\
+Output formats (may be combined; if none, produces a summary to stdout):\n\
+    f    - facet dump\n\
+    G    - Geomview output (see below)\n\
+    i    - vertices incident to each facet\n\
+    m    - Mathematica output (2-d and 3-d)\n\
+    o    - OFF format (dim, points and facets; Voronoi regions)\n\
+    n    - normals with offsets\n\
+    p    - vertex coordinates or Voronoi vertices (coplanar points if 'Qc')\n\
+    s    - summary (stderr)\n\
+\n\
+";
+char qh_promptd[]= "\
+More formats:\n\
+    Fa   - area for each facet\n\
+    FA   - compute total area and volume for option 's'\n\
+    Fc   - count plus coplanar points for each facet\n\
+           use 'Qc' (default) for coplanar and 'Qi' for interior\n\
+    FC   - centrum or Voronoi center for each facet\n\
+    Fd   - use cdd format for input (homogeneous with offset first)\n\
+    FD   - use cdd format for numeric output (offset first)\n\
+    FF   - facet dump without ridges\n\
+    Fi   - inner plane for each facet\n\
+           for 'v', separating hyperplanes for bounded Voronoi regions\n\
+    FI   - ID of each facet\n\
+    Fm   - merge count for each facet (511 max)\n\
+    Fn   - count plus neighboring facets for each facet\n\
+    FN   - count plus neighboring facets for each point\n\
+    Fo   - outer plane (or max_outside) for each facet\n\
+           for 'v', separating hyperplanes for unbounded Voronoi regions\n\
+    FO   - options and precision constants\n\
+    Fp   - dim, count, and intersection coordinates (halfspace only)\n\
+    FP   - nearest vertex and distance for each coplanar point\n\
+    FQ   - command used for qhull\n\
+    Fs   - summary: #int (8), dimension, #points, tot vertices, tot facets,\n\
+                      output: #vertices, #facets, #coplanars, #nonsimplicial\n\
+                    #real (2), max outer plane, min vertex\n\
+    FS   - sizes:   #int (0)\n\
+                    #real(2) tot area, tot volume\n\
+    Ft   - triangulation with centrums for non-simplicial facets (OFF format)\n\
+    Fv   - count plus vertices for each facet\n\
+           for 'v', Voronoi diagram as Voronoi vertices for pairs of sites\n\
+    FV   - average of vertices (a feasible point for 'H')\n\
+    Fx   - extreme points (in order for 2-d)\n\
+\n\
+";
+char qh_prompte[]= "\
+Geomview options (2-d, 3-d, and 4-d; 2-d Voronoi)\n\
+    Ga   - all points as dots\n\
+     Gp  -  coplanar points and vertices as radii\n\
+     Gv  -  vertices as spheres\n\
+    Gi   - inner planes only\n\
+     Gn  -  no planes\n\
+     Go  -  outer planes only\n\
+    Gc   - centrums\n\
+    Gh   - hyperplane intersections\n\
+    Gr   - ridges\n\
+    GDn  - drop dimension n in 3-d and 4-d output\n\
+    Gt   - for 3-d 'd', transparent outer ridges\n\
+\n\
+Print options:\n\
+    PAn  - keep n largest facets by area\n\
+    Pdk:n - drop facet if normal[k] <= n (default 0.0)\n\
+    PDk:n - drop facet if normal[k] >= n\n\
+    Pg   - print good facets (needs 'QGn' or 'QVn')\n\
+    PFn  - keep facets whose area is at least n\n\
+    PG   - print neighbors of good facets\n\
+    PMn  - keep n facets with most merges\n\
+    Po   - force output.  If error, output neighborhood of facet\n\
+    Pp   - do not report precision problems\n\
+\n\
+    .    - list of all options\n\
+    -    - one line descriptions of all options\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt2
+    synopsis for qhull
+*/
+char qh_prompt2[]= "\n\
+qhull- compute convex hulls and related structures.  %s\n\
+    input (stdin): dimension, n, point coordinates\n\
+    comments start with a non-numeric character\n\
+    halfspace: use dim+1 and put offsets after coefficients\n\
+\n\
+options (qh-quick.htm):\n\
+    d    - Delaunay triangulation by lifting points to a paraboloid\n\
+    d Qu - furthest-site Delaunay triangulation (upper convex hull)\n\
+    v    - Voronoi diagram as the dual of the Delaunay triangulation\n\
+    v Qu - furthest-site Voronoi diagram\n\
+    H1,1 - Halfspace intersection about [1,1,0,...] via polar duality\n\
+    Qt   - triangulated output\n\
+    QJ   - joggled input instead of merged facets\n\
+    Tv   - verify result: structure, convexity, and point inclusion\n\
+    .    - concise list of all options\n\
+    -    - one-line description of all options\n\
+\n\
+Output options (subset):\n\
+    s    - summary of results (default)\n\
+    i    - vertices incident to each facet\n\
+    n    - normals with offsets\n\
+    p    - vertex coordinates (if 'Qc', includes coplanar points)\n\
+           if 'v', Voronoi vertices\n\
+    Fp   - halfspace intersections\n\
+    Fx   - extreme points (convex hull vertices)\n\
+    FA   - compute total area and volume\n\
+    o    - OFF format (if 'v', outputs Voronoi regions)\n\
+    G    - Geomview output (2-d, 3-d and 4-d)\n\
+    m    - Mathematica output (2-d and 3-d)\n\
+    QVn  - print facets that include point n, -n if not\n\
+    TO file- output results to file, may be enclosed in single quotes\n\
+\n\
+examples:\n\
+    rbox c d D2 | qhull Qc s f Fx | more      rbox 1000 s | qhull Tv s FA\n\
+    rbox 10 D2 | qhull d QJ s i TO result     rbox 10 D2 | qhull v QJ p\n\
+    rbox 10 D2 | qhull d Qu QJ m              rbox 10 D2 | qhull v Qu QJ o\n\
+    rbox c | qhull n                          rbox c | qhull FV n | qhull H Fp\n\
+    rbox d D12 | qhull QR0 FA                 rbox c D7 | qhull FA TF1000\n\
+    rbox y 1000 W0 | qhull                    rbox 10 | qhull v QJ o Fv\n\
+\n\
+";
+/* for opts, don't assign 'e' or 'E' to a flag (already used for exponent) */
+
+/*---------------------------------
+
+  qh_prompt3
+    concise prompt for qhull
+*/
+char qh_prompt3[]= "\n\
+Qhull %s.\n\
+Except for 'F.' and 'PG', upper-case options take an argument.\n\
+\n\
+ delaunay       voronoi	       Geomview       Halfspace      facet_dump\n\
+ incidences     mathematica    normals        OFF_format     points\n\
+ summary\n\
+\n\
+ Farea          FArea-total    Fcoplanars     FCentrums      Fd-cdd-in\n\
+ FD-cdd-out     FF-dump-xridge Finner         FIDs           Fmerges\n\
+ Fneighbors     FNeigh-vertex  Fouter         FOptions       Fpoint-intersect\n\
+ FPoint_near    FQhull         Fsummary       FSize          Ftriangles\n\
+ Fvertices      Fvoronoi       FVertex-ave    Fxtremes\n\
+\n\
+ Gvertices      Gpoints        Gall_points    Gno_planes     Ginner\n\
+ Gcentrums      Ghyperplanes   Gridges        Gouter         GDrop_dim\n\
+ Gtransparent\n\
+\n\
+ PArea-keep     Pdrop d0:0D0   Pgood          PFacet_area_keep\n\
+ PGood_neighbors PMerge-keep   Poutput_forced Pprecision_not\n\
+\n\
+ QbBound 0:0.5  Qbk:0Bk:0_drop QbB-scale-box  Qbb-scale-last Qcoplanar\n\
+ Qfurthest      Qgood_only     QGood_point    Qinterior      Qmax_out\n\
+ QJoggle        Qrandom        QRotate        Qsearch_1st    Qtriangulate\n\
+ QupperDelaunay QVertex_good   Qvneighbors    Qxact_merge    Qzinfinite\n\
+\n\
+ Q0_no_premerge Q1_no_angle    Q2_no_independ Q3_no_redundant Q4_no_old\n\
+ Q5_no_check_out Q6_no_concave Q7_depth_first Q8_no_near_in  Q9_pick_furthest\n\
+ Q10_no_narrow  Q11_trinormals\n\
+\n\
+ T4_trace       Tcheck_often   Tstatistics    Tverify        Tz_stdout\n\
+ TFacet_log     TInput_file    TPoint_trace   TMerge_trace   TOutput_file\n\
+ TRerun         TWide_trace    TVertex_stop   TCone_stop\n\
+\n\
+ Angle_max      Centrum_size   Error_round    Random_dist    Visible_min\n\
+ Ucoplanar_max  Wide_outside\n\
+";
+
+/*---------------------------------
+
+  main( argc, argv )
+    processes the command line, calls qhull() to do the work, and exits
+
+  design:
+    initializes data structures
+    reads points
+    finishes initialization
+    computes convex hull and other structures
+    checks the result
+    writes the output
+    frees memory
+*/
+int main(int argc, char *argv[]) {
+  int curlong, totlong; /* used !qh_NOmem */
+  int exitcode, numpoints, dim;
+  coordT *points;
+  boolT ismalloc;
+
+#if __MWERKS__ && __POWERPC__
+  char inBuf[BUFSIZ], outBuf[BUFSIZ], errBuf[BUFSIZ];
+  SIOUXSettings.showstatusline= false;
+  SIOUXSettings.tabspaces= 1;
+  SIOUXSettings.rows= 40;
+  if (setvbuf (stdin, inBuf, _IOFBF, sizeof(inBuf)) < 0   /* w/o, SIOUX I/O is slow*/
+  || setvbuf (stdout, outBuf, _IOFBF, sizeof(outBuf)) < 0
+  || (stdout != stderr && setvbuf (stderr, errBuf, _IOFBF, sizeof(errBuf)) < 0))
+    fprintf (stderr, "qhull internal warning (main): could not change stdio to fully buffered.\n");
+  argc= ccommand(&argv);
+#endif
+
+  if ((argc == 1) && isatty( 0 /*stdin*/)) {
+    fprintf(stdout, qh_prompt2, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  if (argc > 1 && *argv[1] == '-' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompta, qh_VERSION, qh_DEFAULTbox,
+		qh_promptb, qh_promptc, qh_promptd, qh_prompte);
+    exit(qh_ERRnone);
+  }
+  if (argc >1 && *argv[1] == '.' && !*(argv[1]+1)) {
+    fprintf(stdout, qh_prompt3, qh_VERSION);
+    exit(qh_ERRnone);
+  }
+  qh_init_A (stdin, stdout, stderr, argc, argv);  /* sets qh qhull_command */
+  exitcode= setjmp (qh errexit); /* simple statement for CRAY J916 */
+  if (!exitcode) {
+    qh_initflags (qh qhull_command);
+    points= qh_readpoints (&numpoints, &dim, &ismalloc);
+    qh_init_B (points, numpoints, dim, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();
+    if (qh VERIFYoutput && !qh FORCEoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+    exitcode= qh_ERRnone;
+  }
+  qh NOerrexit= True;  /* no more setjmp */
+#ifdef qh_NOmem
+  qh_freeqhull( True);
+#else
+  qh_freeqhull( False);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong)
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+#endif
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/user.c b/extern/qhull/src/user.c
new file mode 100644
index 00000000000..94b31aaf99f
--- /dev/null
+++ b/extern/qhull/src/user.c
@@ -0,0 +1,324 @@
+/*
  ---------------------------------
+
+   user.c 
+   user redefinable functions
+
+   see README.txt  see COPYING.txt for copyright information.
+
+   see qhull.h for data structures, macros, and user-callable functions.
+
+   see user_eg.c, unix.c, and qhull_interface.cpp for examples.
+
+   see user.h for user-definable constants
+
+      use qh_NOmem in mem.h to turn off memory management
+      use qh_NOmerge in user.h to turn off facet merging
+      set qh_KEEPstatistics in user.h to 0 to turn off statistics
+
+   This is unsupported software.  You're welcome to make changes,
+   but you're on your own if something goes wrong.  Use 'Tc' to
+   check frequently.  Usually qhull will report an error if 
+   a data structure becomes inconsistent.  If so, it also reports
+   the last point added to the hull, e.g., 102.  You can then trace
+   the execution of qhull with "T4P102".  
+
+   Please report any errors that you fix to qhull@geom.umn.edu
+
+   call_qhull is a template for calling qhull from within your application
+
+   if you recompile and load this module, then user.o will not be loaded
+   from qhull.a
+
+   you can add additional quick allocation sizes in qh_user_memsizes
+
+   if the other functions here are redefined to not use qh_print...,
+   then io.o will not be loaded from qhull.a.  See user_eg.c for an
+   example.  We recommend keeping io.o for the extra debugging 
+   information it supplies.
+*/
+
+#include "qhull_a.h" 
+
+/*---------------------------------
+
+  qh_call_qhull( void )
+    template for calling qhull from inside your program
+    remove #if 0, #endif to compile
+
+  returns: 
+    exit code (see qh_ERR... in qhull.h)
+    all memory freed
+
+  notes:
+    This can be called any number of times.  
+
+  see:
+    qh_call_qhull_once()
+    
+*/
+#if 0
+{
+  int dim;	            /* dimension of points */
+  int numpoints;            /* number of points */
+  coordT *points;           /* array of coordinates for each point */
+  boolT ismalloc;           /* True if qhull should free points in qh_freeqhull() or reallocation */
+  char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */
+  FILE *outfile= stdout;    /* output from qh_produce_output()
+			       use NULL to skip qh_produce_output() */
+  FILE *errfile= stderr;    /* error messages from qhull code */
+  int exitcode;             /* 0 if no error from qhull */
+  facetT *facet;	    /* set by FORALLfacets */
+  int curlong, totlong;	    /* memory remaining after qh_memfreeshort */
+
+  /* initialize dim, numpoints, points[], ismalloc here */
+  exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+  if (!exitcode) {                  /* if no error */
+    /* 'qh facet_list' contains the convex hull */
+    FORALLfacets {
+       /* ... your code ... */
+    }
+  }
+  qh_freeqhull(!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong) 
+    fprintf (errfile, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+}
+#endif
+
+/*---------------------------------
+
+  qh_new_qhull( dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )
+    build new qhull data structure and return exitcode (0 if no errors)
+
+  notes:
+    do not modify points until finished with results.
+      The qhull data structure contains pointers into the points array.
+    do not call qhull functions before qh_new_qhull().
+      The qhull data structure is not initialized until qh_new_qhull().
+
+    outfile may be null
+    qhull_cmd must start with "qhull "
+    projects points to a new point array for Delaunay triangulations ('d' and 'v')
+    transforms points into a new point array for halfspace intersection ('H')
+       
+
+  To allow multiple, concurrent calls to qhull() 
+    - set qh_QHpointer in user.h
+    - use qh_save_qhull and qh_restore_qhull to swap the global data structure between calls.
+    - use qh_freeqhull(qh_ALL) to free intermediate convex hulls
+
+  see:
+    user_eg.c for an example
+*/
+int qh_new_qhull (int dim, int numpoints, coordT *points, boolT ismalloc, 
+		char *qhull_cmd, FILE *outfile, FILE *errfile) {
+  int exitcode, hulldim;
+  boolT new_ismalloc;
+  static boolT firstcall = True;
+  coordT *new_points;
+
+  if (firstcall) {
+    qh_meminit (errfile);
+    firstcall= False;
+  }
+  if (strncmp (qhull_cmd,"qhull ", 6)) {
+    fprintf (errfile, "qh_new_qhull: start qhull_cmd argument with \"qhull \"\n");
+    exit(1);
+  }
+  qh_initqhull_start (NULL, outfile, errfile);
+  trace1(( qh ferr, "qh_new_qhull: build new Qhull for %d %d-d points with %s\n", numpoints, dim, qhull_cmd));
+  exitcode = setjmp (qh errexit);
+  if (!exitcode)
+  {
+    qh NOerrexit = False;
+    qh_initflags (qhull_cmd);
+    if (qh DELAUNAY)
+      qh PROJECTdelaunay= True;
+    if (qh HALFspace) {
+      /* points is an array of halfspaces, 
+         the last coordinate of each halfspace is its offset */
+      hulldim= dim-1;
+      qh_setfeasible (hulldim); 
+      new_points= qh_sethalfspace_all (dim, numpoints, points, qh feasible_point);
+      new_ismalloc= True;
+      if (ismalloc)
+	free (points);
+    }else {
+      hulldim= dim;
+      new_points= points;
+      new_ismalloc= ismalloc;
+    }
+    qh_init_B (new_points, numpoints, hulldim, new_ismalloc);
+    qh_qhull();
+    qh_check_output();
+    if (outfile)
+      qh_produce_output(); 
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points();
+  }
+  qh NOerrexit = True;
+  return exitcode;
+} /* new_qhull */
+
+/*---------------------------------
+  
+  qh_errexit( exitcode, facet, ridge )
+    report and exit from an error
+    report facet and ridge if non-NULL
+    reports useful information such as last point processed
+    set qh.FORCEoutput to print neighborhood of facet
+
+  see: 
+    qh_errexit2() in qhull.c for printing 2 facets
+
+  design:
+    check for error within error processing
+    compute qh.hulltime
+    print facet and ridge (if any)
+    report commandString, options, qh.furthest_id
+    print summary and statistics (including precision statistics)
+    if qh_ERRsingular
+      print help text for singular data set
+    exit program via long jump (if defined) or exit()      
+*/
+void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) {
+
+  if (qh ERREXITcalled) {
+    fprintf (qh ferr, "\nqhull error while processing previous error.  Exit program\n");
+    exit(1);
+  }
+  qh ERREXITcalled= True;
+  if (!qh QHULLfinished)
+    qh hulltime= qh_CPUclock - qh hulltime;
+  qh_errprint("ERRONEOUS", facet, NULL, ridge, NULL);
+  fprintf (qh ferr, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command);
+  fprintf(qh ferr, "Options selected for Qhull %s:\n%s\n", qh_VERSION, qh qhull_options);
+  if (qh furthest_id >= 0) {
+    fprintf(qh ferr, "Last point added to hull was p%d.", qh furthest_id);
+    if (zzval_(Ztotmerge))
+      fprintf(qh ferr, "  Last merge was #%d.", zzval_(Ztotmerge));
+    if (qh QHULLfinished)
+      fprintf(qh ferr, "\nQhull has finished constructing the hull.");
+    else if (qh POSTmerging)
+      fprintf(qh ferr, "\nQhull has started post-merging.");
+    fprintf (qh ferr, "\n");
+  }
+  if (qh FORCEoutput && (qh QHULLfinished || (!facet && !ridge)))
+    qh_produce_output();
+  else {
+    if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh hull_dim+1) {
+      fprintf (qh ferr, "\nAt error exit:\n");
+      qh_printsummary (qh ferr);
+      if (qh PRINTstatistics) {
+	qh_collectstatistics();
+	qh_printstatistics(qh ferr, "at error exit");
+	qh_memstatistics (qh ferr);
+      }
+    }
+    if (qh PRINTprecision)
+      qh_printstats (qh ferr, qhstat precision, NULL);
+  }
+  if (!exitcode)
+    exitcode= qh_ERRqhull;
+  else if (exitcode == qh_ERRsingular)
+    qh_printhelp_singular(qh ferr);
+  else if (exitcode == qh_ERRprec && !qh PREmerge)
+    qh_printhelp_degenerate (qh ferr);
+  if (qh NOerrexit) {
+    fprintf (qh ferr, "qhull error while ending program.  Exit program\n");
+    exit(1);
+  }
+  qh NOerrexit= True;
+  longjmp(qh errexit, exitcode);
+} /* errexit */
+
+
+/*---------------------------------
+  
+  qh_errprint( fp, string, atfacet, otherfacet, atridge, atvertex )
+    prints out the information of facets and ridges to fp
+    also prints neighbors and geomview output
+    
+  notes:
+    except for string, any parameter may be NULL
+*/
+void qh_errprint(char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
+  int i;
+
+  if (atfacet) {
+    fprintf(qh ferr, "%s FACET:\n", string);
+    qh_printfacet(qh ferr, atfacet);
+  }
+  if (otherfacet) {
+    fprintf(qh ferr, "%s OTHER FACET:\n", string);
+    qh_printfacet(qh ferr, otherfacet);
+  }
+  if (atridge) {
+    fprintf(qh ferr, "%s RIDGE:\n", string);
+    qh_printridge(qh ferr, atridge);
+    if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet)
+      qh_printfacet(qh ferr, atridge->top);
+    if (atridge->bottom
+	&& atridge->bottom != atfacet && atridge->bottom != otherfacet)
+      qh_printfacet(qh ferr, atridge->bottom);
+    if (!atfacet)
+      atfacet= atridge->top;
+    if (!otherfacet)
+      otherfacet= otherfacet_(atridge, atfacet);
+  }
+  if (atvertex) {
+    fprintf(qh ferr, "%s VERTEX:\n", string);
+    qh_printvertex (qh ferr, atvertex);
+  }
+  if (qh fout && qh FORCEoutput && atfacet && !qh QHULLfinished && !qh IStracing) {
+    fprintf(qh ferr, "ERRONEOUS and NEIGHBORING FACETS to output\n");
+    for (i= 0; i < qh_PRINTEND; i++)  /* use fout for geomview output */
+      qh_printneighborhood (qh fout, qh PRINTout[i], atfacet, otherfacet,
+			    !qh_ALL);
+  }
+} /* errprint */
+
+
+/*---------------------------------
+  
+  qh_printfacetlist( fp, facetlist, facets, printall )
+    print all fields for a facet list and/or set of facets to fp
+    if !printall, 
+      only prints good facets
+
+  notes:
+    also prints all vertices
+*/
+void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall) {
+  facetT *facet, **facetp;
+
+  qh_printbegin (qh ferr, qh_PRINTfacets, facetlist, facets, printall);
+  FORALLfacet_(facetlist)
+    qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
+  FOREACHfacet_(facets)
+    qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
+  qh_printend (qh ferr, qh_PRINTfacets, facetlist, facets, printall);
+} /* printfacetlist */
+
+
+/*---------------------------------
+  
+  qh_user_memsizes()
+    allocate up to 10 additional, quick allocation sizes
+
+  notes:
+    increase maximum number of allocations in qh_initqhull_mem()
+*/
+void qh_user_memsizes (void) {
+
+  /* qh_memsize (size); */
+} /* user_memsizes */
+
diff --git a/extern/qhull/src/user.h b/extern/qhull/src/user.h
new file mode 100644
index 00000000000..79558967a52
--- /dev/null
+++ b/extern/qhull/src/user.h
@@ -0,0 +1,762 @@
+/*
  ---------------------------------
+
+   user.h
+   user redefinable constants
+
+   see qh-user.htm.  see COPYING for copyright information.
+
+   before reading any code, review qhull.h for data structure definitions and 
+   the "qh" macro.
+*/
+
+#ifndef qhDEFuser
+#define qhDEFuser 1
+
+/*============= data types and configuration macros ==========*/
+
+/*----------------------------------
+  
+  realT
+    set the size of floating point numbers
+  
+  qh_REALdigits 
+    maximimum number of significant digits
+  
+  qh_REAL_1, qh_REAL_2n, qh_REAL_3n
+    format strings for printf
+  
+  qh_REALmax, qh_REALmin
+    maximum and minimum (near zero) values  
+  
+  qh_REALepsilon
+    machine roundoff.  Maximum roundoff error for addition and multiplication.
+    
+  notes:
+   Select whether to store floating point numbers in single precision (float)
+   or double precision (double).
+   
+   Use 'float' to save about 8% in time and 25% in space.  This is particularly
+   help if high-d where convex hulls are space limited.  Using 'float' also
+   reduces the printed size of Qhull's output since numbers have 8 digits of 
+   precision.
+   
+   Use 'double' when greater arithmetic precision is needed.  This is needed
+   for Delaunay triangulations and Voronoi diagrams when you are not merging 
+   facets.
+
+   If 'double' gives insufficient precision, your data probably includes
+   degeneracies.  If so you should use facet merging (done by default)
+   or exact arithmetic (see imprecision section of manual, qh-impre.htm).  
+   You may also use option 'Po' to force output despite precision errors.
+
+   You may use 'long double', but many format statements need to be changed
+   and you may need a 'long double' square root routine.  S. Grundmann
+   (sg@eeiwzb.et.tu-dresden.de) has done this.  He reports that the code runs 
+   much slower with little gain in precision.    
+
+   WARNING: on some machines,    int f(){realT a= REALmax;return (a == REALmax);}
+      returns False.  Use (a > REALmax/2) instead of (a == REALmax).
+
+   REALfloat =   1      all numbers are 'float' type
+             =   0      all numbers are 'double' type
+*/
+#define REALfloat 0
+
+#if (REALfloat == 1)
+#define realT float
+#define REALmax FLT_MAX
+#define REALmin FLT_MIN
+#define REALepsilon FLT_EPSILON
+#define qh_REALdigits 8   /* maximum number of significant digits */
+#define qh_REAL_1 "%6.8g "
+#define qh_REAL_2n "%6.8g %6.8g\n"
+#define qh_REAL_3n "%6.8g %6.8g %6.8g\n"
+
+#elif (REALfloat == 0)
+#define realT double
+#define REALmax DBL_MAX
+#define REALmin DBL_MIN
+#define REALepsilon DBL_EPSILON
+#define qh_REALdigits 16    /* maximum number of significant digits */
+#define qh_REAL_1 "%6.16g "
+#define qh_REAL_2n "%6.16g %6.16g\n"
+#define qh_REAL_3n "%6.16g %6.16g %6.16g\n"
+
+#else
+#error unknown float option
+#endif
+
+/*----------------------------------
+  
+  qh_CPUclock
+    define the clock() function for reporting the total time spent by Qhull
+    returns CPU ticks as a 'long int'
+    qh_CPUclock is only used for reporting the total time spent by Qhull
+
+  qh_SECticks 
+    the number of clock ticks per second
+
+  notes:
+    looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds
+    to define a custom clock, set qh_CLOCKtype to 0
+
+    if your system does not use clock() to return CPU ticks, replace
+    qh_CPUclock with the corresponding function.  It is converted
+    to unsigned long to prevent wrap-around during long runs.
+   
+
+   Set qh_CLOCKtype to
+   
+     1	   	for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond
+                Note:  may fail if more than 1 hour elapsed time
+
+     2	   	use qh_clock() with POSIX times() (see global.c)
+*/
+#define qh_CLOCKtype 1  /* change to the desired number */
+
+#if (qh_CLOCKtype == 1)
+
+#if defined (CLOCKS_PER_SECOND)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SECOND
+
+#elif defined (CLOCKS_PER_SEC)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLOCKS_PER_SEC
+
+#elif defined (CLK_TCK)
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks CLK_TCK
+
+#else
+#define qh_CPUclock    ((unsigned long)clock())  /* return CPU clock */
+#define qh_SECticks 1E6
+#endif
+
+#elif (qh_CLOCKtype == 2)
+#define qh_CPUclock    qh_clock()  /* return CPU clock */
+#define qh_SECticks 100
+
+#else /* qh_CLOCKtype == ? */
+#error unknown clock option
+#endif
+
+/*----------------------------------
+  
+  qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed
+    define random number generator
+
+    qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax.  
+    qh_RANDOMseed sets the random number seed for qh_RANDOMint
+
+  Set qh_RANDOMtype (default 5) to:
+    1       for random() with 31 bits (UCB)
+    2       for rand() with RAND_MAX or 15 bits (system 5)
+    3       for rand() with 31 bits (Sun)
+    4       for lrand48() with 31 bits (Solaris)
+    5       for qh_rand() with 31 bits (included with Qhull)
+  
+  notes:
+    Random numbers are used by rbox to generate point sets.  Random
+    numbers are used by Qhull to rotate the input ('QRn' option),
+    simulate a randomized algorithm ('Qr' option), and to simulate
+    roundoff errors ('Rn' option).
+
+    Random number generators differ between systems.  Most systems provide
+    rand() but the period varies.  The period of rand() is not critical
+    since qhull does not normally use random numbers.  
+
+    The default generator is Park & Miller's minimal standard random
+    number generator [CACM 31:1195 '88].  It is included with Qhull.
+
+    If qh_RANDOMmax is wrong, qhull will report a warning and Geomview 
+    output will likely be invisible.
+*/
+#define qh_RANDOMtype 5   /* *** change to the desired number *** */
+
+#if (qh_RANDOMtype == 1)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, random()/MAX */
+#define qh_RANDOMint random()
+#define qh_RANDOMseed_(seed) srandom(seed);
+
+#elif (qh_RANDOMtype == 2)
+#ifdef RAND_MAX
+#define qh_RANDOMmax ((realT)RAND_MAX)
+#else
+#define qh_RANDOMmax ((realT)32767)   /* 15 bits (System 5) */
+#endif
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+  
+#elif (qh_RANDOMtype == 3)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, Sun */
+#define qh_RANDOMint  rand()
+#define qh_RANDOMseed_(seed) srand((unsigned)seed);
+
+#elif (qh_RANDOMtype == 4)
+#define qh_RANDOMmax ((realT)0x7fffffffUL)  /* 31 bits, lrand38()/MAX */
+#define qh_RANDOMint lrand48()
+#define qh_RANDOMseed_(seed) srand48(seed);
+
+#elif (qh_RANDOMtype == 5)
+#define qh_RANDOMmax ((realT)2147483646UL)  /* 31 bits, qh_rand/MAX */
+#define qh_RANDOMint qh_rand()
+#define qh_RANDOMseed_(seed) qh_srand(seed);
+/* unlike rand(), never returns 0 */
+
+#else
+#error: unknown random option
+#endif
+
+/*----------------------------------
+  
+  qh_ORIENTclock
+    0 for inward pointing normals by Geomview convention
+*/
+#define qh_ORIENTclock 0 
+
+
+/*========= performance related constants =========*/
+
+/*----------------------------------
+  
+  qh_HASHfactor
+    total hash slots / used hash slots.  Must be at least 1.1.
+      
+  notes:
+    =2 for at worst 50% occupancy for qh hash_table and normally 25% occupancy
+*/
+#define qh_HASHfactor 2
+
+/*----------------------------------
+  
+  qh_VERIFYdirect
+    with 'Tv' verify all points against all facets if op count is smaller
+
+  notes:
+    if greater, calls qh_check_bestdist() instead
+*/
+#define qh_VERIFYdirect 1000000 
+
+/*----------------------------------
+  
+  qh_INITIALsearch
+     if qh_INITIALmax, search points up to this dimension
+*/
+#define qh_INITIALsearch 6
+
+/*----------------------------------
+  
+  qh_INITIALmax
+    if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex
+      
+  notes:
+    from points with non-zero determinants
+    use option 'Qs' to override (much slower)
+*/
+#define qh_INITIALmax 8
+
+/*----------------------------------
+  
+  qh_JOGGLEdefault
+    default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault
+
+  notes:
+    rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16
+    rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults
+    rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults
+    rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults
+    rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults
+    rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults
+    rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults
+    rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults
+    rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults
+    the later have about 20 points per facet, each of which may interfere
+
+    pick a value large enough to avoid retries on most inputs
+*/
+#define qh_JOGGLEdefault 30000.0
+
+/*----------------------------------
+  
+  qh_JOGGLEincrease
+    factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
+*/
+#define qh_JOGGLEincrease 10.0
+
+/*----------------------------------
+  
+  qh_JOGGLEretry
+    if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax
+
+  notes:
+    try twice at the original value in case of bad luck the first time
+*/
+#define qh_JOGGLEretry 2
+
+/*----------------------------------
+  
+  qh_JOGGLEagain
+    every following qh_JOGGLEagain, increase qh.JOGGLEmax
+
+  notes:
+    1 is OK since it's already failed qh_JOGGLEretry times
+*/
+#define qh_JOGGLEagain 1
+
+/*----------------------------------
+  
+  qh_JOGGLEmaxincrease
+    maximum qh.JOGGLEmax due to qh_JOGGLEincrease
+    relative to qh.MAXwidth
+
+  notes:
+    qh.joggleinput will retry at this value until qh_JOGGLEmaxretry
+*/
+#define qh_JOGGLEmaxincrease 1e-2
+
+/*----------------------------------
+  
+  qh_JOGGLEmaxretry
+    stop after qh_JOGGLEmaxretry attempts
+*/
+#define qh_JOGGLEmaxretry 100
+
+/*========= memory constants =========*/
+
+/*----------------------------------
+  
+  qh_MEMalign
+    memory alignment for qh_meminitbuffers() in global.c
+    
+  notes:
+    to avoid bus errors, memory allocation must consider alignment requirements.
+    malloc() automatically takes care of alignment.   Since mem.c manages
+    its own memory, we need to explicitly specify alignment in
+    qh_meminitbuffers().
+
+    A safe choice is sizeof(double).  sizeof(float) may be used if doubles 
+    do not occur in data structures and pointers are the same size.  Be careful
+    of machines (e.g., DEC Alpha) with large pointers. 
+
+    If using gcc, best alignment is
+              #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
+*/
+#define qh_MEMalign fmax_(sizeof(realT), sizeof(void *))
+
+/*----------------------------------
+  
+  qh_MEMbufsize
+    size of additional memory buffers
+    
+  notes:
+    used for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMbufsize 0x10000       /* allocate 64K memory buffers */
+
+/*----------------------------------
+  
+  qh_MEMinitbuf
+    size of initial memory buffer
+    
+  notes:
+    use for qh_meminitbuffers() in global.c
+*/
+#define qh_MEMinitbuf 0x20000      /* initially allocate 128K buffer */
+
+/*----------------------------------
+  
+  qh_INFINITE
+    on output, indicates Voronoi center at infinity
+*/
+#define qh_INFINITE  -10.101
+
+/*----------------------------------
+  
+  qh_DEFAULTbox
+    default box size (Geomview expects 0.5)
+*/
+#define qh_DEFAULTbox 0.5 
+
+/*======= conditional compilation ============================*/
+
+/*----------------------------------
+
+  __cplusplus
+    defined by C++ compilers
+
+  __MSC_VER
+    defined by Microsoft Visual C++
+  
+  __MWERKS__ && __POWERPC__
+    defined by Metrowerks when compiling for the Power Macintosh
+
+  __STDC__
+    defined for strict ANSI C 
+*/
+
+/*----------------------------------
+ 
+  qh_COMPUTEfurthest 
+    compute furthest distance to an outside point instead of storing it with the facet
+    =1 to compute furthest
+  
+  notes:
+    computing furthest saves memory but costs time
+      about 40% more distance tests for partitioning
+      removes facet->furthestdist 
+*/
+#define qh_COMPUTEfurthest 0
+                         
+/*----------------------------------
+ 
+  qh_KEEPstatistics   
+    =0 removes most of statistic gathering and reporting
+
+  notes:
+    if 0, code size is reduced by about 4%.
+*/
+#define qh_KEEPstatistics 1
+                       
+/*----------------------------------
+ 
+  qh_MAXoutside 
+    record outer plane for each facet
+    =1 to record facet->maxoutside
+  
+  notes:
+    this takes a realT per facet and slightly slows down qhull
+    it produces better outer planes for geomview output 
+*/
+#define qh_MAXoutside 1
+
+/*----------------------------------
+ 
+  qh_NOmerge
+    disables facet merging if defined
+    
+  notes:
+    This saves about 10% space.
+    
+    Unless 'Q0'
+      qh_NOmerge sets 'QJ' to avoid precision errors
+
+    #define qh_NOmerge    
+
+  see:
+    qh_NOmem in mem.c
+    
+    see user.c/user_eg.c for removing io.o
+*/  
+    
+/*----------------------------------
+ 
+  qh_NOtrace
+    no tracing if defined 
+  
+  notes:
+    This saves about 5% space.
+
+    #define qh_NOtrace
+*/    
+
+/*----------------------------------
+  
+  qh_QHpointer
+    access global data with pointer or static structure
+
+  qh_QHpointer  = 1     access globals via a pointer to allocated memory
+                        enables qh_saveqhull() and qh_restoreqhull()
+			costs about 8% in time and 2% in space
+
+		= 0     qh_qh and qh_qhstat are static data structures
+		        only one instance of qhull() can be active at a time
+			default value
+
+  notes:
+    all global variables for qhull are in qh, qhmem, and qhstat
+    qh is defined in qhull.h
+    qhmem is defined in mem.h
+    qhstat is defined in stat.h
+
+  see:
+    user_eg.c for an example
+*/
+#define qh_QHpointer 0
+#if 0  /* sample code */
+    qhT *oldqhA, *oldqhB;
+
+    exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+    /* use results from first call to qh_new_qhull */
+    oldqhA= qh_save_qhull();
+    exitcode= qh_new_qhull (dimB, numpointsB, pointsB, ismalloc,
+                      flags, outfile, errfile); 
+    /* use results from second call to qh_new_qhull */
+    oldqhB= qh_save_qhull();
+    qh_restore_qhull (&oldqhA);
+    /* use results from first call to qh_new_qhull */
+    qh_freeqhull (qh_ALL);  /* frees all memory used by first call */
+    qh_restore_qhull (&oldqhB);
+    /* use results from second call to qh_new_qhull */
+    qh_freeqhull (!qh_ALL); /* frees long memory used by second call */
+    qh_memfreeshort (&curlong, &totlong);  /* frees short memory and memory allocator */
+#endif
+
+/*----------------------------------
+ 
+  qh_QUICKhelp        
+    =1 to use abbreviated help messages, e.g., for degenerate inputs
+*/
+#define qh_QUICKhelp    0  
+
+/* ============ -merge constants- ====================
+
+   These constants effect facet merging.  You probably will not need
+   to modify these.  They effect the performance of facet merging.
+*/
+
+/*----------------------------------
+  
+  qh_DIMmergeVertex
+    max dimension for vertex merging (it is not effective in high-d)
+*/
+#define qh_DIMmergeVertex 6
+
+/*----------------------------------
+  
+  qh_DIMreduceBuild
+     max dimension for vertex reduction during build (slow in high-d)
+*/
+#define qh_DIMreduceBuild 5
+
+/*----------------------------------
+     
+  qh_BESTcentrum
+     if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster)
+     else, qh_findbestneighbor() tests all vertices (much better merges)
+
+  qh_BESTcentrum2
+     if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums
+*/
+#define qh_BESTcentrum 20
+#define qh_BESTcentrum2 2
+
+/*----------------------------------
+  
+  qh_BESTnonconvex
+    if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges.
+    
+  notes:
+    It is needed because qh_findbestneighbor is slow for large facets
+*/
+#define qh_BESTnonconvex 15 
+
+/*----------------------------------
+  
+  qh_MAXnewmerges
+    if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums.
+     
+  notes:
+    It is needed because postmerge can merge many facets at once
+*/
+#define qh_MAXnewmerges 2
+
+/*----------------------------------
+  
+  qh_MAXnewcentrum
+    if <= dim+n vertices (n approximates the number of merges),
+      reset the centrum in qh_updatetested() and qh_mergecycle_facets()
+    
+  notes:
+    needed to reduce cost and because centrums may move too much if 
+    many vertices in high-d
+*/
+#define qh_MAXnewcentrum 5
+
+/*----------------------------------
+  
+  qh_COPLANARratio
+    for 3-d+ merging, qh.MINvisible is n*premerge_centrum
+
+  notes:
+    for non-merging, it's DISTround
+*/
+#define qh_COPLANARratio 3
+
+/*----------------------------------
+  
+  qh_DISToutside
+    When is a point clearly outside of a facet?  
+    Stops search in qh_findbestnew or qh_partitionall
+    qh_findbest uses qh.MINoutside since since it is only called if no merges.
+     
+  notes:
+    'Qf' always searches for best facet
+    if !qh.MERGING, same as qh.MINoutside. 
+    if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved
+      [Note: Zdelvertextot occurs normally with interior points]
+            RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv
+    When there is a sharp edge, need to move points to a
+    clearly good facet; otherwise may be lost in another partitioning.
+    if too big then O(n^2) behavior for partitioning in cone
+    if very small then important points not processed
+    Needed in qh_partitionall for
+      RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv
+    Needed in qh_findbestnew for many instances of
+      RBOX 1000 s Z1 G1e-13 t | QHULL Tv
+
+  See:  
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \
+     fmax_((qh MERGING ? 2 : 1)*qh MINoutside, qh max_outside))
+
+/*----------------------------------
+  
+  qh_RATIOnearinside
+    ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for
+    qh_check_maxout().  
+  
+  notes:
+    This is overkill since do not know the correct value.
+    It effects whether 'Qc' reports all coplanar points
+    Not used for 'd' since non-extreme points are coplanar
+*/
+#define qh_RATIOnearinside 5
+
+/*----------------------------------
+  
+  qh_SEARCHdist
+    When is a facet coplanar with the best facet?  
+    qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
+
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \
+      (qh max_outside + 2 * qh DISTround + fmax_( qh MINvisible, qh MAXcoplanar)));
+
+/*----------------------------------
+  
+  qh_USEfindbestnew
+     Always use qh_findbestnew for qh_partitionpoint, otherwise use
+     qh_findbestnew if merged new facet or sharpnewfacets.
+  
+  See:
+    qh_DISToutside -- when is a point clearly outside of a facet
+    qh_SEARCHdist -- when is facet coplanar with the best facet?
+    qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
+*/
+#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50)
+
+/*----------------------------------
+  
+  qh_WIDEcoplanar
+    n*MAXcoplanar or n*MINvisible for a WIDEfacet 
+    
+    if vertex is further than qh.WIDEfacet from the hyperplane
+    then its ridges are not counted in computing the area, and
+    the facet's centrum is frozen. 
+    
+  notes:
+   qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar,
+      qh_WIDEcoplanar * qh.MINvisible);
+*/
+#define qh_WIDEcoplanar 6
+
+/*----------------------------------
+  
+  qh_MAXnarrow
+    max. cosine in initial hull that sets qh.NARROWhull
+       
+  notes:
+    If qh.NARROWhull, the initial partition does not make 
+    coplanar points.  If narrow, a coplanar point can be 
+    coplanar to two facets of opposite orientations and
+    distant from the exact convex hull.
+
+    Conservative estimate.  Don't actually see problems until it is -1.0
+*/
+#define qh_MAXnarrow -0.99999999
+
+/*----------------------------------
+  
+  qh_WARNnarrow
+    max. cosine in initial hull to warn about qh.NARROWhull
+      
+  notes:
+    this is a conservative estimate.  
+    Don't actually see problems until it is -1.0.  See qh-impre.htm
+*/
+#define qh_WARNnarrow -0.999999999999999
+
+/*----------------------------------
+  
+  qh_ZEROdelaunay
+    a zero Delaunay facet occurs for input sites coplanar with their convex hull
+    the last normal coefficient of a zero Delaunay facet is within
+        qh_ZEROdelaunay * qh.ANGLEround of 0
+      
+  notes:
+    qh_ZEROdelaunay does not allow for joggled input ('QJ').
+
+    You can avoid zero Delaunay facets by surrounding the input with a box.
+
+    Use option 'PDk:-n' to explicitly define zero Delaunay facets
+      k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation)
+      n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12')
+*/
+#define qh_ZEROdelaunay 2
+
+#endif /* qh_DEFuser */
+
+
+
diff --git a/extern/qhull/src/user_eg.c b/extern/qhull/src/user_eg.c
new file mode 100644
index 00000000000..97e4aa7a89a
--- /dev/null
+++ b/extern/qhull/src/user_eg.c
@@ -0,0 +1,310 @@
+/*
  ---------------------------------
+
+  user_eg.c
+  sample code for calling qhull() from an application
+  
+  call with:
+
+     user_eg "cube/diamond options" "delaunay options" "halfspace options"
+
+  for example:
+
+     user_eg                             # return summaries
+
+     user_eg "n" "o" "Fp"                # return normals, OFF, points
+
+     user_eg "n Qt" "o" "Fp"             # triangulated cube
+
+     user_eg "QR0 p" "QR0 v p" "QR0 Fp"  # rotate input and return points
+                                         # 'v' returns Voronoi
+					 # transform is rotated for halfspaces
+
+   main() makes three runs of qhull.
+
+     1) compute the convex hull of a cube
+
+     2a) compute the Delaunay triangulation of random points
+
+     2b) find the Delaunay triangle closest to a point.
+
+     3) compute the halfspace intersection of a diamond
+
+ notes:
+ 
+   For another example, see main() in unix.c and user_eg2.c.
+   These examples, call qh_qhull() directly.  They allow
+   tighter control on the code loaded with Qhull.
+
+   For a simple C++ example, see qhull_interface.cpp
+
+   Summaries are sent to stderr if other output formats are used
+
+   compiled by 'make user_eg'
+
+   see qhull.h for data structures, macros, and user-callable functions.
+*/
+
+#include "qhull_a.h"
+
+/*-------------------------------------------------
+-internal function prototypes
+*/
+void print_summary (void);
+void makecube (coordT *points, int numpoints, int dim);
+void makeDelaunay (coordT *points, int numpoints, int dim, int seed);
+void findDelaunay (int dim);
+void makehalf (coordT *points, int numpoints, int dim);
+
+/*-------------------------------------------------
+-print_summary()
+*/
+void print_summary (void) {
+  facetT *facet;
+  int k;
+
+  printf ("\n%d vertices and %d facets with normals:\n", 
+                 qh num_vertices, qh num_facets);
+  FORALLfacets {
+    for (k=0; k < qh hull_dim; k++) 
+      printf ("%6.2g ", facet->normal[k]);
+    printf ("\n");
+  }
+}
+
+/*--------------------------------------------------
+-makecube- set points to vertices of cube
+  points is numpoints X dim
+*/
+void makecube (coordT *points, int numpoints, int dim) {
+  int j,k;
+  coordT *point;
+
+  for (j=0; jvertices) {
+    for (k=0; k < dim; k++)
+      printf ("%5.2f ", vertex->point[k]);
+    printf ("\n");
+  }
+} /*.findDelaunay.*/
+
+/*--------------------------------------------------
+-makehalf- set points to halfspaces for a (dim)-dimensional diamond
+  points is numpoints X dim+1
+
+  each halfspace consists of dim coefficients followed by an offset
+*/
+void makehalf (coordT *points, int numpoints, int dim) {
+  int j,k;
+  coordT *point;
+
+  for (j=0; j= 2 ? argv[1] : "");
+  numpoints= SIZEcube;
+  makecube (points, numpoints, DIM);
+  for (i=numpoints; i--; )
+    rows[i]= points+dim*i;
+  qh_printmatrix (outfile, "input", rows, numpoints, dim);
+  exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+  if (!exitcode) {                  /* if no error */
+    /* 'qh facet_list' contains the convex hull */
+    print_summary();
+    FORALLfacets {
+       /* ... your code ... */
+    }
+  }
+  qh_freeqhull(!qh_ALL);                   /* free long memory  */
+  qh_memfreeshort (&curlong, &totlong);    /* free short memory and memory allocator */
+  if (curlong || totlong) 
+    fprintf (errfile, "qhull internal warning (user_eg, #1): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+
+  /*
+    Run 2: Delaunay triangulation
+  */
+
+  printf( "\ncompute 3-d Delaunay triangulation\n");
+  sprintf (flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+  numpoints= SIZEcube;
+  makeDelaunay (points, numpoints, dim, time(NULL));
+  for (i=numpoints; i--; )
+    rows[i]= points+dim*i;
+  qh_printmatrix (outfile, "input", rows, numpoints, dim);
+  exitcode= qh_new_qhull (dim, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+  if (!exitcode) {                  /* if no error */
+    /* 'qh facet_list' contains the convex hull */
+    /* If you want a Voronoi diagram ('v') and do not request output (i.e., outfile=NULL), 
+       call qh_setvoronoi_all() after qh_new_qhull(). */
+    print_summary();
+    FORALLfacets {
+       /* ... your code ... */
+    }
+    printf( "\nfind 3-d Delaunay triangle closest to [0.5, 0.5, ...]\n");
+    exitcode= setjmp (qh errexit);  
+    if (!exitcode) {
+      /* Trap Qhull errors in findDelaunay().  Without the setjmp(), Qhull
+         will exit() after reporting an error */
+      qh NOerrexit= False;
+      findDelaunay (DIM);
+    }
+    qh NOerrexit= True;
+  }
+#if qh_QHpointer  /* see user.h */
+  {
+    qhT *oldqhA, *oldqhB;
+    coordT pointsB[DIM*TOTpoints]; /* array of coordinates for each point */
+
+
+    printf( "\nsave first triangulation and compute a new triangulation\n");
+    oldqhA= qh_save_qhull();
+    sprintf (flags, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+    numpoints= SIZEcube;
+    makeDelaunay (pointsB, numpoints, dim, time(NULL)+1);
+    for (i=numpoints; i--; )
+      rows[i]= pointsB+dim*i;
+    qh_printmatrix (outfile, "input", rows, numpoints, dim);
+    exitcode= qh_new_qhull (dim, numpoints, pointsB, ismalloc,
+                      flags, outfile, errfile); 
+    if (!exitcode)
+      print_summary();
+    printf( "\nsave second triangulation and restore first one\n");
+    oldqhB= qh_save_qhull();
+    qh_restore_qhull (&oldqhA);
+    print_summary();
+    printf( "\nfree first triangulation and restore second one.\n");
+    qh_freeqhull (qh_ALL);               /* free short and long memory used by first call */
+			                 /* do not use qh_memfreeshort */
+    qh_restore_qhull (&oldqhB);
+    print_summary();
+  }
+#endif
+  qh_freeqhull(!qh_ALL);                 /* free long memory */
+  qh_memfreeshort (&curlong, &totlong);  /* free short memory and memory allocator */
+  if (curlong || totlong) 
+    fprintf (errfile, "qhull internal warning (user_eg, #2): did not free %d bytes of long memory (%d pieces)\n", totlong, curlong);
+
+  /*
+    Run 3: halfspace intersection about the origin
+  */
+  printf( "\ncompute halfspace intersection about the origin for a diamond\n");
+  sprintf (flags, "qhull H0 s Tcv %s", argc >= 4 ? argv[3] : "Fp");
+  numpoints= SIZEcube;
+  makehalf (points, numpoints, dim);
+  for (i=numpoints; i--; )
+    rows[i]= points+(dim+1)*i;
+  qh_printmatrix (outfile, "input as halfspace coefficients + offsets", rows, numpoints, dim+1);
+  /* use qh_sethalfspace_all to transform the halfspaces yourself.  
+     If so, set 'qh feasible_point and do not use option 'Hn,...' [it would retransform the halfspaces]
+  */
+  exitcode= qh_new_qhull (dim+1, numpoints, points, ismalloc,
+                      flags, outfile, errfile); 
+  if (!exitcode) 
+    print_summary();
+  qh_freeqhull (!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong)  /* could also check previous runs */
+    fprintf (stderr, "qhull internal warning (user_eg, #3): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+  return exitcode;
+} /* main */
+
diff --git a/extern/qhull/src/user_eg2.c b/extern/qhull/src/user_eg2.c
new file mode 100644
index 00000000000..1eb42ccfe8a
--- /dev/null
+++ b/extern/qhull/src/user_eg2.c
@@ -0,0 +1,532 @@
+/*
  ---------------------------------
+
+  user_eg2.c
+
+  sample code for calling qhull() from an application.
+
+  See user_eg.c for a simpler method using qh_new_qhull().
+  The method used here and in unix.c gives you additional
+  control over Qhull. 
+  
+  call with:
+
+     user_eg2 "triangulated cube/diamond options" "delaunay options" "halfspace options"
+
+  for example:
+
+     user_eg2                             # return summaries
+
+     user_eg2 "n" "o" "Fp"                # return normals, OFF, points
+
+     user_eg2 "QR0 p" "QR0 v p" "QR0 Fp"  # rotate input and return points
+                                         # 'v' returns Voronoi
+					 # transform is rotated for halfspaces
+
+   main() makes three runs of qhull.
+
+     1) compute the convex hull of a cube, and incrementally add a diamond
+
+     2a) compute the Delaunay triangulation of random points, and add points.
+
+     2b) find the Delaunay triangle closest to a point.
+
+     3) compute the halfspace intersection of a diamond, and add a cube
+
+ notes:
+ 
+   summaries are sent to stderr if other output formats are used
+
+   derived from unix.c and compiled by 'make user_eg2'
+
+   see qhull.h for data structures, macros, and user-callable functions.
+   
+   If you want to control all output to stdio and input to stdin,
+   set the #if below to "1" and delete all lines that contain "io.c".  
+   This prevents the loading of io.o.  Qhull will
+   still write to 'qh ferr' (stderr) for error reporting and tracing.
+
+   Defining #if 1, also prevents user.o from being loaded.
+*/
+
+#include "qhull_a.h"
+
+/*-------------------------------------------------
+-internal function prototypes
+*/
+void print_summary (void);
+void makecube (coordT *points, int numpoints, int dim);
+void adddiamond (coordT *points, int numpoints, int numnew, int dim);
+void makeDelaunay (coordT *points, int numpoints, int dim);
+void addDelaunay (coordT *points, int numpoints, int numnew, int dim);
+void findDelaunay (int dim);
+void makehalf (coordT *points, int numpoints, int dim);
+void addhalf (coordT *points, int numpoints, int numnew, int dim, coordT *feasible);
+
+/*-------------------------------------------------
+-print_summary()
+*/
+void print_summary (void) {
+  facetT *facet;
+  int k;
+
+  printf ("\n%d vertices and %d facets with normals:\n", 
+                 qh num_vertices, qh num_facets);
+  FORALLfacets {
+    for (k=0; k < qh hull_dim; k++) 
+      printf ("%6.2g ", facet->normal[k]);
+    printf ("\n");
+  }
+}
+
+/*--------------------------------------------------
+-makecube- set points to vertices of cube
+  points is numpoints X dim
+*/
+void makecube (coordT *points, int numpoints, int dim) {
+  int j,k;
+  coordT *point;
+
+  for (j=0; jvertices) {
+    for (k=0; k < dim-1; k++)
+      printf ("%5.2f ", vertex->point[k]);
+    printf ("\n");
+  }
+} /*.findDelaunay.*/
+
+/*--------------------------------------------------
+-makehalf- set points to halfspaces for a (dim)-d diamond
+  points is numpoints X dim+1
+
+  each halfspace consists of dim coefficients followed by an offset
+*/
+void makehalf (coordT *points, int numpoints, int dim) {
+  int j,k;
+  coordT *point;
+
+  for (j=0; j= 2 ? argv[1] : "");
+    qh_initflags (options);
+    printf( "\ncompute triangulated convex hull of cube after rotating input\n");
+    makecube (array[0], SIZEcube, DIM);
+    qh_init_B (array[0], SIZEcube, DIM, ismalloc);
+    qh_qhull();
+    qh_check_output();
+    qh_triangulate();  /* requires option 'Q11' if want to add points */ 
+    print_summary ();
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+    printf( "\nadd points in a diamond\n");
+    adddiamond (array[0], SIZEcube, SIZEdiamond, DIM);
+    qh_check_output();
+    print_summary (); 
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+  }
+  qh NOerrexit= True;
+  qh_freeqhull (!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  /*
+    Run 2: Delaunay triangulation
+  */
+  qh_init_A (stdin, stdout, stderr, 0, NULL);
+  exitcode= setjmp (qh errexit);
+  if (!exitcode) {
+    coordT array[TOTpoints][DIM];
+
+    strcat (qh rbox_command, "user_eg Delaunay");
+    sprintf (options, "qhull s d Tcv %s", argc >= 3 ? argv[2] : "");
+    qh_initflags (options);
+    printf( "\ncompute 2-d Delaunay triangulation\n");
+    makeDelaunay (array[0], SIZEcube, DIM);
+    /* Instead of makeDelaunay with qh_setdelaunay, you may
+       produce a 2-d array of points, set DIM to 2, and set 
+       qh PROJECTdelaunay to True.  qh_init_B will call 
+       qh_projectinput to project the points to the paraboloid
+       and add a point "at-infinity".
+    */
+    qh_init_B (array[0], SIZEcube, DIM, ismalloc);
+    qh_qhull();
+    /* If you want Voronoi ('v') without qh_produce_output(), call
+       qh_setvoronoi_all() after qh_qhull() */
+    qh_check_output();
+    print_summary ();
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+    printf( "\nadd points to triangulation\n");
+    addDelaunay (array[0], SIZEcube, SIZEdiamond, DIM); 
+    qh_check_output();
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+    printf( "\nfind Delaunay triangle closest to [0.5, 0.5, ...]\n");
+    findDelaunay (DIM);
+  }
+  qh NOerrexit= True;
+  qh_freeqhull (!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  /*
+    Run 3: halfspace intersection
+  */
+  qh_init_A (stdin, stdout, stderr, 0, NULL);
+  exitcode= setjmp (qh errexit);
+  if (!exitcode) {
+    coordT array[TOTpoints][DIM+1];  /* +1 for halfspace offset */
+    pointT *points;
+
+    strcat (qh rbox_command, "user_eg halfspaces");
+    sprintf (options, "qhull H0 s Tcv %s", argc >= 4 ? argv[3] : "");
+    qh_initflags (options);
+    printf( "\ncompute halfspace intersection about the origin for a diamond\n");
+    makehalf (array[0], SIZEcube, DIM);
+    qh_setfeasible (DIM); /* from io.c, sets qh feasible_point from 'Hn,n' */
+    /* you may malloc and set qh feasible_point directly.  It is only used for
+       option 'Fp' */
+    points= qh_sethalfspace_all ( DIM+1, SIZEcube, array[0], qh feasible_point); 
+    qh_init_B (points, SIZEcube, DIM, True); /* qh_freeqhull frees points */
+    qh_qhull();
+    qh_check_output();
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+    printf( "\nadd halfspaces for cube to intersection\n");
+    addhalf (array[0], SIZEcube, SIZEdiamond, DIM, qh feasible_point); 
+    qh_check_output();
+    qh_produce_output();  /* delete this line to help avoid io.c */
+    if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
+      qh_check_points ();
+  }
+  qh NOerrexit= True;
+  qh NOerrexit= True;
+  qh_freeqhull (!qh_ALL);
+  qh_memfreeshort (&curlong, &totlong);
+  if (curlong || totlong)  /* could also check previous runs */
+    fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n",
+       totlong, curlong);
+  return exitcode;
+} /* main */
+
+#if 1    /* use 1 to prevent loading of io.o and user.o */
+/*-------------------------------------------
+-errexit- return exitcode to system after an error
+  assumes exitcode non-zero
+  prints useful information
+  see qh_errexit2() in qhull.c for 2 facets
+*/
+void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) {
+
+  if (qh ERREXITcalled) {
+    fprintf (qh ferr, "qhull error while processing previous error.  Exit program\n");
+    exit(1);
+  }
+  qh ERREXITcalled= True;
+  if (!qh QHULLfinished)
+    qh hulltime= (unsigned)clock() - qh hulltime;
+  fprintf (qh ferr, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command);
+  fprintf(qh ferr, "Options selected:\n%s\n", qh qhull_options);
+  if (qh furthest_id >= 0) {
+    fprintf(qh ferr, "\nLast point added to hull was p%d", qh furthest_id);
+    if (zzval_(Ztotmerge))
+      fprintf(qh ferr, "  Last merge was #%d.", zzval_(Ztotmerge));
+    if (qh QHULLfinished)
+      fprintf(qh ferr, "\nQhull has finished constructing the hull.");
+    else if (qh POSTmerging)
+      fprintf(qh ferr, "\nQhull has started post-merging");
+    fprintf(qh ferr, "\n\n");
+  }
+  if (qh NOerrexit) {
+    fprintf (qh ferr, "qhull error while ending program.  Exit program\n");
+    exit(1);
+  }
+  if (!exitcode)
+    exitcode= qh_ERRqhull;
+  qh NOerrexit= True;
+  longjmp(qh errexit, exitcode);
+} /* errexit */
+
+
+/*-------------------------------------------
+-errprint- prints out the information of the erroneous object
+    any parameter may be NULL, also prints neighbors and geomview output
+*/
+void qh_errprint(char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
+
+  fprintf (qh ferr, "%s facets f%d f%d ridge r%d vertex v%d\n",
+	   string, getid_(atfacet), getid_(otherfacet), getid_(atridge),
+	   getid_(atvertex));
+} /* errprint */
+
+
+void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall) {
+  facetT *facet, **facetp;
+
+  /* remove these calls to help avoid io.c */
+  qh_printbegin (qh ferr, qh_PRINTfacets, facetlist, facets, printall);/*io.c*/
+  FORALLfacet_(facetlist)                                              /*io.c*/
+    qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);          /*io.c*/
+  FOREACHfacet_(facets)                                                /*io.c*/
+    qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);          /*io.c*/
+  qh_printend (qh ferr, qh_PRINTfacets, facetlist, facets, printall);  /*io.c*/
+
+  FORALLfacet_(facetlist)
+    fprintf( qh ferr, "facet f%d\n", facet->id);
+} /* printfacetlist */
+
+
+
+/*-----------------------------------------
+-user_memsizes- allocate up to 10 additional, quick allocation sizes
+*/
+void qh_user_memsizes (void) {
+
+  /* qh_memsize (size); */
+} /* user_memsizes */
+
+#endif
diff --git a/extern/solid/CMakeLists.txt b/extern/solid/CMakeLists.txt
new file mode 100644
index 00000000000..496618c5914
--- /dev/null
+++ b/extern/solid/CMakeLists.txt
@@ -0,0 +1,37 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SET(INC include src src/broad src/complex src/convex ../qhull/include)
+
+FILE(GLOB SRC src/*.cpp src/convex/*.cpp src/complex/*.cpp src/broad/*.cpp)
+
+ADD_DEFINITIONS(-DUSE_DOUBLES -DQHULL -D_LIB)
+
+BLENDERLIB(extern_solid "${SRC}" "${INC}")
+#, libtype=['game2','player'], priority=[45, 75]
diff --git a/extern/solid/LICENSE_GPL.txt b/extern/solid/LICENSE_GPL.txt
new file mode 100644
index 00000000000..07db89585a2
--- /dev/null
+++ b/extern/solid/LICENSE_GPL.txt
@@ -0,0 +1,349 @@
+
+ The SOLID library is Copyright (C) 2001-2003  Dtecta.
+
+ You may use, distribute and copy the SOLID library under the terms of
+ GNU General Public License version 2, which is displayed below.
+
+-------------------------------------------------------------------------
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    
+    Copyright (C)   
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  , 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+-------------------------------------------------------------------------
diff --git a/extern/solid/LICENSE_QPL.txt b/extern/solid/LICENSE_QPL.txt
new file mode 100644
index 00000000000..3fca00466e2
--- /dev/null
+++ b/extern/solid/LICENSE_QPL.txt
@@ -0,0 +1,110 @@
+
+ The SOLID library is Copyright (C) 2001-2003  Dtecta.
+
+ You may use, distribute and copy the SOLID library under the terms of
+ the Q Public License, which is displayed below.
+
+-------------------------------------------------------------------------
+			     THE Q PUBLIC LICENSE
+				  version 1.0
+
+		   Copyright (C) 1999-2000 Trolltech AS, Norway.
+		       Everyone is permitted to copy and
+		       distribute this license document.
+
+The intent of this license is to establish freedom to share and change the
+software regulated by this license under the open source model.
+
+This license applies to any software containing a notice placed by the
+copyright holder saying that it may be distributed under the terms of
+the Q Public License version 1.0.  Such software is herein referred to as
+the Software.  This license covers modification and distribution of the
+Software, use of third-party application programs based on the Software,
+and development of free software which uses the Software.
+
+				 Granted Rights
+
+1. You are granted the non-exclusive rights set forth in this license
+   provided you agree to and comply with any and all conditions in this
+   license.  Whole or partial distribution of the Software, or software
+   items that link with the Software, in any form signifies acceptance of
+   this license.
+
+2. You may copy and distribute the Software in unmodified form provided
+   that the entire package, including - but not restricted to - copyright,
+   trademark notices and disclaimers, as released by the initial developer
+   of the Software, is distributed.
+
+3. You may make modifications to the Software and distribute your
+   modifications, in a form that is separate from the Software, such as
+   patches. The following restrictions apply to modifications:
+
+     a. Modifications must not alter or remove any copyright notices in
+        the Software.
+
+     b. When modifications to the Software are released under this
+        license, a non-exclusive royalty-free right is granted to the
+        initial developer of the Software to distribute your modification
+        in future versions of the Software provided such versions remain
+        available under these terms in addition to any other license(s) of
+        the initial developer.
+
+4. You may distribute machine-executable forms of the Software or
+   machine-executable forms of modified versions of the Software, provided
+   that you meet these restrictions:
+
+     a. You must include this license document in the distribution.
+
+     b. You must ensure that all recipients of the machine-executable forms
+        are also able to receive the complete machine-readable source code
+        to the distributed Software, including all modifications, without
+        any charge beyond the costs of data transfer, and place prominent
+        notices in the distribution explaining this.
+
+     c. You must ensure that all modifications included in the
+        machine-executable forms are available under the terms of this
+        license.
+
+5. You may use the original or modified versions of the Software to
+   compile, link and run application programs legally developed by you
+   or by others.
+
+6. You may develop application programs, reusable components and other
+   software items that link with the original or modified versions of the
+   Software.  These items, when distributed, are subject to the following
+   requirements:
+
+     a. You must ensure that all recipients of machine-executable forms of
+        these items are also able to receive and use the complete
+        machine-readable source code to the items without any charge
+        beyond the costs of data transfer.
+
+     b. You must explicitly license all recipients of your items to use
+        and re-distribute original and modified versions of the items in
+        both machine-executable and source code forms. The recipients must
+        be able to do so without any charges whatsoever, and they must be
+        able to re-distribute to anyone they choose.
+
+
+     c. If the items are not available to the general public, and the
+        initial developer of the Software requests a copy of the items,
+        then you must supply one.
+
+			    Limitations of Liability
+
+In no event shall the initial developers or copyright holders be liable
+for any damages whatsoever, including - but not restricted to - lost
+revenue or profits or other direct, indirect, special, incidental or
+consequential damages, even if they have been advised of the possibility
+of such damages, except to the extent invariable law, if any, provides
+otherwise.
+
+			          No Warranty
+
+The Software and this license document are provided AS IS with NO WARRANTY
+OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE.
+                                 Choice of Law
+
+This license is governed by the Laws of Norway. Disputes shall be settled
+by Oslo City Court.
diff --git a/extern/solid/Makefile b/extern/solid/Makefile
new file mode 100644
index 00000000000..ed5a1359cf4
--- /dev/null
+++ b/extern/solid/Makefile
@@ -0,0 +1,60 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+include nan_definitions.mk
+
+SOURCEDIR = extern/solid
+LIBNAMES = solid solid_broad solid_convex solid_complex
+DIR = $(OCGDIR)/extern/
+DIRS = src
+
+include nan_subdirs.mk
+
+install: all debug
+	@[ -d $(NAN_SOLID) ] || mkdir -p $(NAN_SOLID)
+	@[ -d $(NAN_SOLID)/include/SOLID ] || mkdir -p $(NAN_SOLID)/include/SOLID
+	@[ -d $(NAN_SOLID)/include/SOLID/MT ] || mkdir -p $(NAN_SOLID)/include/SOLID/MT
+	@[ -d $(NAN_SOLID)/lib ] || mkdir -p $(NAN_SOLID)/lib
+	@[ -d $(NAN_SOLID)/lib/debug ] || mkdir -p $(NAN_SOLID)/lib/debug
+	@for i in $(LIBNAMES); do \
+	    $(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/$$i/lib$$i.a $(NAN_SOLID)/lib/ ; \
+	    $(NANBLENDERHOME)/intern/tools/cpifdiff.sh $(DIR)/$$i/debug/lib$$i.a $(NAN_SOLID)/lib/debug/ ; \
+	    if [ $(OS) = darwin ] ; then \
+            ranlib $(NAN_SOLID)/lib/lib$$i.a ; \
+            ranlib $(NAN_SOLID)/lib/debug/lib$$i.a ; \
+        fi ; \
+	done
+	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh include/*.h $(NAN_SOLID)/include/SOLID
+	@$(NANBLENDERHOME)/intern/tools/cpifdiff.sh include/MT/*.h $(NAN_SOLID)/include/SOLID/MT
+
+
diff --git a/extern/solid/README.txt b/extern/solid/README.txt
new file mode 100644
index 00000000000..348d92b35cb
--- /dev/null
+++ b/extern/solid/README.txt
@@ -0,0 +1,55 @@
+
+		 SOLID - Software Library for Interference Detection
+
+SOLID is a software library containing functions for performing
+intersection tests and proximity queries that are useful in the context
+of collision detection. Collision detection is the process of detecting
+pairs of geometric objects that are intersecting or are within a given
+proximity of each other. In particular, SOLID is useful for detecting
+collisions between objects that are moving relatively of each other over
+time. The motions of objects are controlled by the client application,
+and are not determined or affected by SOLID. 
+
+This open-source edition of SOLID version 3 is released under the terms of
+either the GNU Public License (GPL) or the Q Public License (QPL). This means
+that for software created with SOLID version 3 you must comply with the terms
+of one of these licenses. You may choose wich of these licenses best suits
+your purpose. See the following files contained in this distribution for a
+complete list of terms and conditions of these licenses:  
+
+		 LICENSE_QPL.txt	 The Q Public License 
+		 LICENSE_GPL.txt	 The GNU General Public License
+
+These licenses do not permit the use of SOLID 3 in closed-source software
+products. For enquiries about commercial use of SOLID, please contact
+info@dtecta.com.    
+
+SOLID 3 uses Qhull from The Geometry Center of the University of Minnesota.
+Qhull is copyrighted as noted below.  Qhull is free software and may be
+obtained via anonymous ftp from geom.umn.edu.   
+        
+                    Qhull, Copyright (c) 1993-2002
+
+       The National Science and Technology Research Center for
+        Computation and Visualization of Geometric Structures
+                        (The Geometry Center)
+                       University of Minnesota
+                            400 Lind Hall
+                        207 Church Street S.E.
+                      Minneapolis, MN 55455  USA
+
+                       email: qhull@geom.umn.edu
+
+Installation
+
+For details on how to install SOLID see the documention in the 'doc' directory.
+
+Platforms
+
+SOLID 3 has been tested on the following platforms:
+
+    Linux IA32  gcc 2.95.3, gcc 3.3
+	Win32		MSVC++ 6.0 SP4, MSVC++ 7.1 
+
+  
+
diff --git a/extern/solid/SConscript b/extern/solid/SConscript
new file mode 100644
index 00000000000..7482014c0a4
--- /dev/null
+++ b/extern/solid/SConscript
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+import sys
+
+Import('env')
+
+defs = 'USE_DOUBLES QHULL _LIB'
+cflags = []
+
+if env['OURPLATFORM']=='win32-vc':
+    defs += ' WIN32 NDEBUG _WINDOWS _LIB'
+    cflags += ['/MT', '/W3', '/GX', '/Og', '/Ot', '/Ob1', '/Op', '/G6']
+elif env['OURPLATFORM']=='win32-mingw':
+    defs += ' NDEBUG'
+    cflags += ['-O2']
+elif sys.platform=='linux2' or sys.platform=='linux-i386' or sys.platform=='freebsd4' or sys.platform=='freebsd5' or sys.platform=='openbsd3' or sys.platform=='sunos5':
+    defs += ' NDEBUG'
+    cflags += ['-O2']
+elif sys.platform=='darwin' :
+    defs += ' NDEBUG'
+    cflags += ['-O2','-pipe', '-fPIC', '-funsigned-char', '-ffast-math']
+
+else:
+    print "################################################"
+    print 
+    print "Check if solid builds on your platform correctly"
+    print "Add your platform specific defines"
+    print "and cflags / cxxflags to the"
+    print "extern/solid/SConscript file"
+
+sources = env.Glob('src/*.cpp') + env.Glob('src/convex/*.cpp') + env.Glob('src/complex/*.cpp') + env.Glob('src/broad/*.cpp')
+
+incs = 'include src src/broad src/complex src/convex ../qhull/include'
+
+env.BlenderLib ( libname='extern_solid', sources=sources, includes=Split(incs), defines=Split(defs), libtype=['game2','player'], priority=[45, 75] , compileflags = cflags)
diff --git a/extern/solid/SOLID/SOLID.h b/extern/solid/SOLID/SOLID.h
new file mode 100644
index 00000000000..37d74340f8c
--- /dev/null
+++ b/extern/solid/SOLID/SOLID.h
@@ -0,0 +1,279 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_H
+#define SOLID_H
+
+#include "SOLID_types.h"
+
+#ifdef __cplusplus
+extern "C" { 
+#endif
+    
+	DT_DECLARE_HANDLE(DT_ObjectHandle);
+	DT_DECLARE_HANDLE(DT_SceneHandle);
+	DT_DECLARE_HANDLE(DT_ShapeHandle);
+	DT_DECLARE_HANDLE(DT_VertexBaseHandle);
+	DT_DECLARE_HANDLE(DT_RespTableHandle);
+	DT_DECLARE_HANDLE(DT_ArchiveHandle);
+
+	typedef unsigned int DT_ResponseClass;
+
+	typedef enum DT_ResponseType { 
+		DT_NO_RESPONSE,                  /* No response (obsolete) */        
+		DT_BROAD_RESPONSE,      
+		DT_SIMPLE_RESPONSE,              /* No collision data */
+		DT_WITNESSED_RESPONSE,           /* A point common to both objects
+											is returned as collision data
+										 */
+		DT_DEPTH_RESPONSE                /* The penetration depth is returned
+											as collision data. The penetration depth
+											is the shortest vector over which one 
+											object needs to be translated in order
+											to bring the objects in touching contact. 
+										 */ 
+	} DT_ResponseType;
+    
+/* For witnessed response, the following structure represents a common point. The world 
+   coordinates of 'point1' and 'point2' coincide. 'normal' is the zero vector.
+   
+   For depth response, the following structure represents the penetration depth. 
+   'point1' en 'point2' are the witness points of the penetration depth in world coordinates.
+   The penetration depth vector in world coordinates is represented by 'normal'.
+*/
+
+	typedef struct DT_CollData {
+		DT_Vector3 point1;               /* Point in object1 in world coordinates */ 
+		DT_Vector3 point2;               /* Point in object2 in world coordinates */
+		DT_Vector3 normal;               /* point2 - point1 */ 
+	} DT_CollData;
+
+/* A response callback is called by SOLID for each pair of collding objects. 'client-data'
+   is a pointer to an arbitrary structure in the client application. The client objects are
+   pointers to structures in the client application associated with the coliding objects.
+   'coll_data' is the collision data computed by SOLID.
+*/
+
+	typedef DT_Bool (*DT_ResponseCallback)(void *client_data,
+										   void *client_object1,
+										   void *client_object2,
+										   const DT_CollData *coll_data);
+										
+/* Shape definition */
+
+
+	extern DECLSPEC DT_ShapeHandle DT_NewBox(DT_Scalar x, DT_Scalar y, DT_Scalar z);
+	extern DECLSPEC DT_ShapeHandle DT_NewCone(DT_Scalar radius, DT_Scalar height);
+	extern DECLSPEC DT_ShapeHandle DT_NewCylinder(DT_Scalar radius, DT_Scalar height);
+	extern DECLSPEC DT_ShapeHandle DT_NewSphere(DT_Scalar radius);
+	extern DECLSPEC DT_ShapeHandle DT_NewPoint(const DT_Vector3 point);
+	extern DECLSPEC DT_ShapeHandle DT_NewLineSegment(const DT_Vector3 source, const DT_Vector3 target);
+	extern DECLSPEC DT_ShapeHandle DT_NewMinkowski(DT_ShapeHandle shape1, DT_ShapeHandle shape2);
+	extern DECLSPEC DT_ShapeHandle DT_NewHull(DT_ShapeHandle shape1, DT_ShapeHandle shape2);
+
+	extern DECLSPEC DT_VertexBaseHandle DT_NewVertexBase(const void *pointer, DT_Size stride);
+	extern DECLSPEC void DT_DeleteVertexBase(DT_VertexBaseHandle vertexBase);	
+	extern DECLSPEC void DT_ChangeVertexBase(DT_VertexBaseHandle vertexBase, const void *pointer);
+
+	extern DECLSPEC DT_ShapeHandle DT_NewComplexShape(DT_VertexBaseHandle vertexBase);
+	extern DECLSPEC void           DT_EndComplexShape();
+
+	extern DECLSPEC DT_ShapeHandle DT_NewPolytope(DT_VertexBaseHandle vertexBase);
+	extern DECLSPEC void           DT_EndPolytope();
+
+	extern DECLSPEC void DT_Begin();
+	extern DECLSPEC void DT_End();
+
+	extern DECLSPEC void DT_Vertex(const DT_Vector3 vertex);
+	extern DECLSPEC void DT_VertexIndex(DT_Index index);
+
+	extern DECLSPEC void DT_VertexIndices(DT_Count count, const DT_Index *indices);
+	extern DECLSPEC void DT_VertexRange(DT_Index first, DT_Count count); 
+
+	extern DECLSPEC void DT_DeleteShape(DT_ShapeHandle shape);
+
+/* Object  */
+
+	extern DECLSPEC DT_ObjectHandle DT_CreateObject(
+		void *client_object,      /* pointer to object in client memory */
+		DT_ShapeHandle shape  /* the shape or geometry of the object */
+		);
+
+	extern DECLSPEC void DT_DestroyObject(DT_ObjectHandle object);
+
+
+
+	extern DECLSPEC void DT_SetPosition(DT_ObjectHandle object, const DT_Vector3 position);
+	extern DECLSPEC void DT_SetOrientation(DT_ObjectHandle object, const DT_Quaternion orientation);
+	extern DECLSPEC void DT_SetScaling(DT_ObjectHandle object, const DT_Vector3 scaling);
+
+/* The margin is an offset from the actual shape. The actual geometry of an
+   object is the set of points whose distance to the transformed shape is at 
+   most the  margin. During the lifetime of an object the margin can be 
+   modified. 
+*/
+   
+	extern DECLSPEC void DT_SetMargin(DT_ObjectHandle object, DT_Scalar margin);
+
+
+/* These commands assume a column-major 4x4 OpenGL matrix representation */
+
+	extern DECLSPEC void DT_SetMatrixf(DT_ObjectHandle object, const float *m); 
+	extern DECLSPEC void DT_GetMatrixf(DT_ObjectHandle object, float *m); 
+
+	extern DECLSPEC void DT_SetMatrixd(DT_ObjectHandle object, const double *m); 
+	extern DECLSPEC void DT_GetMatrixd(DT_ObjectHandle object, double *m); 
+
+	extern DECLSPEC void DT_GetBBox(DT_ObjectHandle object, DT_Vector3 min, DT_Vector3 max);
+
+
+	extern DECLSPEC DT_Bool  DT_GetIntersect(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 v);
+/* This next command returns the distance between the objects. De returned
+   closest points are given in world coordinates.
+*/
+	extern DECLSPEC DT_Scalar DT_GetClosestPair(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 point1, DT_Vector3 point2);  
+
+	extern DECLSPEC DT_Bool   DT_GetCommonPoint(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 point);
+
+	extern DECLSPEC DT_Bool   DT_GetPenDepth(DT_ObjectHandle object1, DT_ObjectHandle object2,
+											 DT_Vector3 point1, DT_Vector3 point2);  
+
+/* Scene */
+
+	extern DECLSPEC DT_SceneHandle DT_CreateScene(); 
+	extern DECLSPEC void           DT_DestroyScene(DT_SceneHandle scene);
+
+	extern DECLSPEC void DT_AddObject(DT_SceneHandle scene, DT_ObjectHandle object);
+	extern DECLSPEC void DT_RemoveObject(DT_SceneHandle scene, DT_ObjectHandle object);
+
+/* Note that objects can be assigned to multiple scenes! */
+
+/* Response */
+
+/* Response tables are defined independent of the scenes in which they are used.
+   Multiple response tables can be used in one scene, and a response table
+   can be shared among scenes.
+*/
+	extern DECLSPEC DT_RespTableHandle DT_CreateRespTable(); 
+	extern DECLSPEC void               DT_DestroyRespTable(DT_RespTableHandle respTable); 
+
+/* Responses are defined on (pairs of) response classes. Each response table 
+   maintains its set of response classes.
+*/
+	extern DECLSPEC DT_ResponseClass DT_GenResponseClass(DT_RespTableHandle respTable);
+
+/* To each object for which a response is defined in the response table a
+   response class needs to be assigned. 
+*/
+
+	extern DECLSPEC void DT_SetResponseClass(DT_RespTableHandle respTable,
+											 DT_ObjectHandle object,
+											 DT_ResponseClass responseClass);
+
+	extern DECLSPEC void DT_ClearResponseClass(DT_RespTableHandle respTable, 
+											   DT_ObjectHandle object);
+
+	extern DECLSPEC void DT_CallResponse(DT_RespTableHandle respTable,
+										 DT_ObjectHandle object1,
+										 DT_ObjectHandle object2,
+										 const DT_CollData *coll_data);
+
+/* For each pair of objects multiple responses can be defined. A response is a callback
+   together with its response type and client data. */
+    
+/* Responses can be defined for all pairs of response classes... */
+	extern DECLSPEC void DT_AddDefaultResponse(DT_RespTableHandle respTable,
+											   DT_ResponseCallback response, 
+											   DT_ResponseType type, void *client_data);
+
+	extern DECLSPEC void DT_RemoveDefaultResponse(DT_RespTableHandle respTable,
+												  DT_ResponseCallback response);
+/* ...per response class... */
+	extern DECLSPEC void DT_AddClassResponse(DT_RespTableHandle respTable,
+											 DT_ResponseClass responseClass,
+											 DT_ResponseCallback response,
+											 DT_ResponseType type, void *client_data);
+
+	extern DECLSPEC void DT_RemoveClassResponse(DT_RespTableHandle respTable,
+												DT_ResponseClass responseClass,
+												DT_ResponseCallback response);
+
+/* ... and per pair of response classes...*/
+	extern DECLSPEC void DT_AddPairResponse(DT_RespTableHandle respTable,
+											DT_ResponseClass responseClass1,
+											DT_ResponseClass responseClass2, 
+											DT_ResponseCallback response,
+											DT_ResponseType type, void *client_data);
+	extern DECLSPEC void DT_RemovePairResponse(DT_RespTableHandle respTable,
+											   DT_ResponseClass responseClass1,
+											   DT_ResponseClass responseClass2,
+											   DT_ResponseCallback response);
+
+/* The next command calls the response callbacks for all intersecting pairs of objects in a scene. 
+   'DT_Test' returns the number of pairs of objects for which callbacks have been called. 
+*/
+ 
+	extern DECLSPEC DT_Count DT_Test(DT_SceneHandle scene, DT_RespTableHandle respTable);
+
+/* Set the maximum relative error in the closest points and penetration depth
+   computation. The default for `max_error' is 1.0e-3. Larger errors result
+   in better performance. Non-positive error tolerances are ignored.
+*/ 
+
+	extern DECLSPEC void DT_SetAccuracy(DT_Scalar max_error);
+
+/* Set the maximum tolerance on relative errors due to rounding.  The default for `tol_error' 
+   is the machine epsilon. Very large tolerances result in false collisions. Setting tol_error too small 
+   results in missed collisions. Non-positive error tolerances are ignored. 
+*/ 
+    
+	extern DECLSPEC void DT_SetTolerance(DT_Scalar tol_error);
+
+
+/* This function returns the client pointer to the first object in a scene hit by the ray 
+   (actually a line segment) defined by the points 'from' en 'to'. The spot is the hit point 
+   on the object in local coordinates. 'normal' is the normal to the surface of the object in
+   world coordinates. The ignore_client pointer is used to make one of the objects transparent.
+
+   NB: Currently ray tests are implemented for spheres, boxes, and meshes only!!
+*/   
+
+	extern DECLSPEC void *DT_RayCast(DT_SceneHandle scene, void *ignore_client,
+									 const DT_Vector3 source, const DT_Vector3 target,
+									 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal);
+
+/* Similar, only here a single object is tested and a boolean is returned */
+
+	extern DECLSPEC DT_Bool DT_ObjectRayCast(DT_ObjectHandle object,
+											 const DT_Vector3 source, const DT_Vector3 target,
+											 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/solid/SOLID/SOLID_broad.h b/extern/solid/SOLID/SOLID_broad.h
new file mode 100644
index 00000000000..74e4214fa67
--- /dev/null
+++ b/extern/solid/SOLID/SOLID_broad.h
@@ -0,0 +1,75 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_BROAD_H
+#define SOLID_BROAD_H
+
+#include "SOLID_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+	DT_DECLARE_HANDLE(BP_SceneHandle);
+	DT_DECLARE_HANDLE(BP_ProxyHandle);
+	
+	typedef void (*BP_Callback)(void *client_data,
+								void *object1,
+								void *object2);
+
+	typedef bool (*BP_RayCastCallback)(void *client_data,
+									   void *object,
+									   const DT_Vector3 source,
+									   const DT_Vector3 target,
+									   DT_Scalar *lambda);
+	
+	extern DECLSPEC BP_SceneHandle BP_CreateScene(void *client_data,
+												  BP_Callback beginOverlap,
+												  BP_Callback endOverlap);
+	
+	extern DECLSPEC void           BP_DestroyScene(BP_SceneHandle scene);
+	
+	extern DECLSPEC BP_ProxyHandle BP_CreateProxy(BP_SceneHandle scene, 
+												  void *object,
+												  const DT_Vector3 min, 
+												  const DT_Vector3 max);
+	
+	extern DECLSPEC void           BP_DestroyProxy(BP_SceneHandle scene, 
+												  BP_ProxyHandle proxy);
+	
+	extern DECLSPEC void BP_SetBBox(BP_ProxyHandle proxy, 
+									const DT_Vector3 min, 
+									const DT_Vector3 max);
+	
+	extern DECLSPEC void *BP_RayCast(BP_SceneHandle scene, 
+									 BP_RayCastCallback objectRayCast, 
+									 void *client_data,
+									 const DT_Vector3 source,
+									 const DT_Vector3 target,
+									 DT_Scalar *lambda);		
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/solid/SOLID/SOLID_types.h b/extern/solid/SOLID/SOLID_types.h
new file mode 100644
index 00000000000..630594e447f
--- /dev/null
+++ b/extern/solid/SOLID/SOLID_types.h
@@ -0,0 +1,53 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_TYPES_H
+#define SOLID_TYPES_H
+
+#ifndef DECLSPEC
+# ifdef WIN32
+#  define DECLSPEC __declspec(dllexport)
+# else
+#  define DECLSPEC
+# endif
+#endif
+
+#define DT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
+    
+
+typedef unsigned short DT_Index;
+typedef unsigned short DT_Count;
+typedef unsigned int   DT_Size;
+typedef float          DT_Scalar; 
+typedef int            DT_Bool;
+
+#define DT_FALSE 0
+#define DT_TRUE  1
+
+#define DT_CONTINUE 0
+#define DT_DONE 1
+
+typedef DT_Scalar DT_Vector3[3]; 
+typedef DT_Scalar DT_Quaternion[4]; 
+
+#endif
diff --git a/extern/solid/VisualC6/broad/broad.dsp b/extern/solid/VisualC6/broad/broad.dsp
new file mode 100644
index 00000000000..1161d68fcd6
--- /dev/null
+++ b/extern/solid/VisualC6/broad/broad.dsp
@@ -0,0 +1,132 @@
+# Microsoft Developer Studio Project File - Name="broad" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=broad - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "broad.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "broad.mak" CFG="broad - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "broad - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "broad - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "broad - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "broad - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "broad - Win32 Release"
+# Name "broad - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\src\broad\BP_C-api.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_EndpointList.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Proxy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Scene.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Endpoint.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_EndpointList.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Proxy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_ProxyList.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\broad\BP_Scene.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/complex/complex.dsp b/extern/solid/VisualC6/complex/complex.dsp
new file mode 100644
index 00000000000..74ea67b9e23
--- /dev/null
+++ b/extern/solid/VisualC6/complex/complex.dsp
@@ -0,0 +1,116 @@
+# Microsoft Developer Studio Project File - Name="complex" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=complex - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "complex.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "complex.mak" CFG="complex - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "complex - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "complex - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "complex - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /I "../../src/convex" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "complex - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /Od /I "../../include" /I "../../src/convex" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "complex - Win32 Release"
+# Name "complex - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_BBoxTree.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_Complex.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_BBoxTree.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_CBox.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\complex\DT_Complex.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/convex/convex.dsp b/extern/solid/VisualC6/convex/convex.dsp
new file mode 100644
index 00000000000..ec9caace9d9
--- /dev/null
+++ b/extern/solid/VisualC6/convex/convex.dsp
@@ -0,0 +1,232 @@
+# Microsoft Developer Studio Project File - Name="convex" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=convex - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "convex.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "convex.mak" CFG="convex - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "convex - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "convex - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "convex - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /I "../../../qhull/include" /D "NDEBUG" /D "QHULL" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "convex - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /Od /I "../../include" /I "../../../qhull/include" /D "_DEBUG" /D "QHULL" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "convex - Win32 Release"
+# Name "convex - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Accuracy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Box.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Cone.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Convex.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Cylinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Facet.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_LineSegment.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_PenDepth.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Point.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Polyhedron.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Polytope.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Sphere.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Triangle.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Accuracy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Array.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Box.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Cone.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Convex.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Cylinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Facet.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_GJK.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Hull.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_IndexArray.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_LineSegment.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Minkowski.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_PenDepth.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Point.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Polyhedron.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Polytope.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Shape.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Sphere.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Transform.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_Triangle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\convex\DT_VertexBase.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/dynamics/dynamics.dsp b/extern/solid/VisualC6/dynamics/dynamics.dsp
new file mode 100644
index 00000000000..9659cbf8a56
--- /dev/null
+++ b/extern/solid/VisualC6/dynamics/dynamics.dsp
@@ -0,0 +1,120 @@
+# Microsoft Developer Studio Project File - Name="dynamics" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=dynamics - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "dynamics.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "dynamics.mak" CFG="dynamics - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "dynamics - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "dynamics - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "dynamics - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "dynamics - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "dynamics - Win32 Release"
+# Name "dynamics - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\Dynamic.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\Kinetic.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\RigidBody.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\Dynamic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\Kinetic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\examples\dynamics\RigidBody.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/gldemo/gldemo.dsp b/extern/solid/VisualC6/gldemo/gldemo.dsp
new file mode 100644
index 00000000000..f3cde286161
--- /dev/null
+++ b/extern/solid/VisualC6/gldemo/gldemo.dsp
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="gldemo" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=gldemo - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "gldemo.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "gldemo.mak" CFG="gldemo - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "gldemo - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "gldemo - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "gldemo - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "gldemo - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "gldemo - Win32 Release"
+# Name "gldemo - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\gldemo.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/mnm/mnm.dsp b/extern/solid/VisualC6/mnm/mnm.dsp
new file mode 100644
index 00000000000..2df6d951794
--- /dev/null
+++ b/extern/solid/VisualC6/mnm/mnm.dsp
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="mnm" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mnm - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mnm.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mnm.mak" CFG="mnm - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mnm - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mnm - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mnm - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../examples/dynamics" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "mnm - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /I "../../examples/dynamics" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mnm - Win32 Release"
+# Name "mnm - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\mnm.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/physics/physics.dsp b/extern/solid/VisualC6/physics/physics.dsp
new file mode 100644
index 00000000000..dd69b6a35b2
--- /dev/null
+++ b/extern/solid/VisualC6/physics/physics.dsp
@@ -0,0 +1,100 @@
+# Microsoft Developer Studio Project File - Name="physics" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=physics - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "physics.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "physics.mak" CFG="physics - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "physics - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "physics - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "physics - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../examples/dynamics" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "physics - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /I "../../examples/dynamics" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "physics - Win32 Release"
+# Name "physics - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\physics.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/sample/sample.dsp b/extern/solid/VisualC6/sample/sample.dsp
new file mode 100644
index 00000000000..c6e0423cd04
--- /dev/null
+++ b/extern/solid/VisualC6/sample/sample.dsp
@@ -0,0 +1,102 @@
+# Microsoft Developer Studio Project File - Name="sample" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=sample - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "sample.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "sample.mak" CFG="sample - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "sample - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "sample - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "sample - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "sample - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "sample - Win32 Release"
+# Name "sample - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\examples\sample.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/solid.dsw b/extern/solid/VisualC6/solid.dsw
new file mode 100644
index 00000000000..397cc4bf371
--- /dev/null
+++ b/extern/solid/VisualC6/solid.dsw
@@ -0,0 +1,89 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "broad"=".\broad\broad.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "complex"=".\complex\complex.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "convex"=".\convex\convex.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name qhull
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "qhull"="..\..\qhull\VisualC6\qhull\qhull.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "solid"=".\solid\solid.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name broad
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name complex
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name convex
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/extern/solid/VisualC6/solid/solid.dsp b/extern/solid/VisualC6/solid/solid.dsp
new file mode 100644
index 00000000000..4ac7459c2f9
--- /dev/null
+++ b/extern/solid/VisualC6/solid/solid.dsp
@@ -0,0 +1,148 @@
+# Microsoft Developer Studio Project File - Name="solid" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=solid - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "solid.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "solid.mak" CFG="solid - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "solid - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "solid - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "solid - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /I "../../src/convex" /I "../../src/complex" /D "NDEBUG" /D "QHULL" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Cmds=XCOPY   /Y   ..\..\include\SOLID*.h   ..\..\..\..\..\lib\windows\solid\include\solid\  	XCOPY   /Y   Release\*.lib   ..\..\..\..\..\lib\windows\solid\lib\ 
+# End Special Build Tool
+
+!ELSEIF  "$(CFG)" == "solid - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+LINK32=cwlink.exe
+MTL=midl.exe
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MT /W3 /GX /Zd /Od /I "../../include" /I "../../src/convex" /I "../../src/complex" /D "_DEBUG" /D "QHULL" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Cmds=XCOPY   /Y   ..\..\include\SOLID*.h   ..\..\..\..\..\lib\windows\solid\include\solid\  	XCOPY   /Y   Debug\*.lib   ..\..\..\..\..\lib\windows\solid\lib\Debug\ 
+# End Special Build Tool
+
+!ENDIF 
+
+# Begin Target
+
+# Name "solid - Win32 Release"
+# Name "solid - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\src\DT_C-api.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Encounter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Object.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_RespTable.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Scene.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\DT_AlgoTable.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Encounter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Object.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Response.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_RespTable.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Scene.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/VisualC6/solid_dll/solid_dll.dsp b/extern/solid/VisualC6/solid_dll/solid_dll.dsp
new file mode 100644
index 00000000000..eed092502e0
--- /dev/null
+++ b/extern/solid/VisualC6/solid_dll/solid_dll.dsp
@@ -0,0 +1,147 @@
+# Microsoft Developer Studio Project File - Name="solid_dll" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=solid_dll - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "solid_dll.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "solid_dll.mak" CFG="solid_dll - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "solid_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "solid_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "solid_dll - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "../../lib/win32/vc6"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOLID_DLL_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../include" /I "../../src/convex" /I "../../src/complex" /D "NDEBUG" /D "USE_DOUBLES" /D "QHULL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOLID_DLL_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../lib/win32/vc6/solid.dll"
+
+!ELSEIF  "$(CFG)" == "solid_dll - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "../../lib/win32/vc6"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOLID_DLL_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MD /W3 /GX /Zd /Od /I "../../include" /I "../../src/convex" /I "../../src/complex" /D "_DEBUG" /D "QHULL" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOLID_DLL_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"../../lib/win32/vc6/solidd.dll" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "solid_dll - Win32 Release"
+# Name "solid_dll - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\src\DT_C-api.cpp"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Encounter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Object.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_RespTable.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Scene.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\src\DT_AlgoTable.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Encounter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Object.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Response.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_RespTable.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\src\DT_Scene.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/extern/solid/include/GEN_MinMax.h b/extern/solid/include/GEN_MinMax.h
new file mode 100644
index 00000000000..9ea961cfe4f
--- /dev/null
+++ b/extern/solid/include/GEN_MinMax.h
@@ -0,0 +1,76 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef GEN_MINMAX_H
+#define GEN_MINMAX_H
+
+template 
+inline const T& GEN_min(const T& a, const T& b) 
+{
+  return b < a ? b : a;
+}
+
+template 
+inline const T& GEN_max(const T& a, const T& b) 
+{
+  return  a < b ? b : a;
+}
+
+template 
+inline const T& GEN_clamped(const T& a, const T& lb, const T& ub) 
+{
+	return a < lb ? lb : (ub < a ? ub : a); 
+}
+
+template 
+inline void GEN_set_min(T& a, const T& b) 
+{
+    if (b < a) 
+	{
+		a = b;
+	}
+}
+
+template 
+inline void GEN_set_max(T& a, const T& b) 
+{
+    if (a < b) 
+	{
+		a = b;
+	}
+}
+
+template 
+inline void GEN_clamp(T& a, const T& lb, const T& ub) 
+{
+	if (a < lb) 
+	{
+		a = lb; 
+	}
+	else if (ub < a) 
+	{
+		a = ub;
+	}
+}
+
+#endif
diff --git a/extern/solid/include/GEN_random.h b/extern/solid/include/GEN_random.h
new file mode 100644
index 00000000000..4690a05511a
--- /dev/null
+++ b/extern/solid/include/GEN_random.h
@@ -0,0 +1,49 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef GEN_RANDOM_H
+#define GEN_RANDOM_H
+
+#ifdef MT19937
+
+#include 
+#include 
+
+#define GEN_RAND_MAX UINT_MAX
+
+inline void         GEN_srand(unsigned int seed) { init_genrand(seed); }
+inline unsigned int GEN_rand()                   { return genrand_int32(); }
+
+#else
+
+#include 
+
+#define GEN_RAND_MAX RAND_MAX
+
+inline void         GEN_srand(unsigned int seed) { srand(seed); } 
+inline unsigned int GEN_rand()                   { return rand(); }
+
+#endif
+
+#endif
+
diff --git a/extern/solid/include/MT/Interval.h b/extern/solid/include/MT/Interval.h
new file mode 100644
index 00000000000..c6ba2fc1681
--- /dev/null
+++ b/extern/solid/include/MT/Interval.h
@@ -0,0 +1,180 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef INTERVAL_H
+#define INTERVAL_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include 
+#include 
+
+namespace MT {
+
+	template 
+	class Interval {
+	public:
+		Interval() {}
+		
+
+#if _MSC_VER <= 1200
+        explicit Interval(const Scalar& x) 
+		    : m_lb(x), m_ub(x)
+	    {}
+        
+ 
+		Interval(const Scalar& lb, const Scalar& ub) 
+			: m_lb(lb), m_ub(ub)
+		{
+			assert(lb <= ub);
+		}
+#else
+		template 
+		explicit Interval(const Scalar2& x) 
+			: m_lb(x), m_ub(x)
+		{}
+		
+		template 
+		Interval(const Scalar2& lb, const Scalar2& ub) 
+			: m_lb(lb), m_ub(ub)
+		{
+			assert(lb <= ub);
+		}
+		
+		template 
+		Interval(const Interval& z) 
+		{ 
+			*this = z; 
+		}
+		
+		template 
+		Interval& operator=(const Interval& z) 
+		{ 
+			m_lb = Scalar(z.lower()); 
+			m_ub = Scalar(z.upper()); 
+			return *this;
+		}
+#endif
+      
+		
+
+		Scalar&       lower()       { return m_lb; }
+		const Scalar& lower() const { return m_lb; }
+		
+		Scalar&       upper()       { return m_ub; }
+		const Scalar& upper() const { return m_ub; }
+		 
+		Scalar center() const { return (m_lb + m_ub) * Scalar(0.5); } 
+		Scalar extent() const { return (m_ub - m_lb) * Scalar(0.5); } 
+
+	
+	protected:
+		Scalar m_lb, m_ub;
+	};
+
+	template 
+	inline Interval 
+	operator+(const Interval& z1, const Interval& z2)
+	{
+		return Interval(z1.lower() + z2.lower(), 
+								z1.upper() + z2.upper());
+	}
+
+	template 
+	inline Interval 
+	operator-(const Interval& z1, const Interval& z2)
+	{
+		return Interval(z1.lower() - z2.upper(), 
+								z1.upper() - z2.lower());
+	}
+	
+	template 
+	inline std::ostream& 
+	operator<<(std::ostream& os, const Interval& z)
+	{
+		return os << '[' << z.lower() << ", " << z.upper() << ']';
+	}
+
+	template 
+	inline Scalar 
+	median(const Interval& z) 
+	{
+		return (z.lower() + z.upper()) * Scalar(0.5);
+	}
+	
+	template 
+	inline Scalar 
+	width(const Interval& z) 
+	{
+		return z.upper() - z.lower();
+	}
+	
+	template 
+	inline bool 
+	overlap(const Interval& z1, const Interval& z2) 
+	{
+		return z1.lower() <= z2.upper() && z2.lower() <= z1.upper();
+	}
+
+	template 
+	inline bool 
+	in(const Interval& z1, const Interval& z2) 
+	{
+		return z2.lower() <= z1.lower() && z1.upper() <= z2.upper();
+	}
+
+	template 
+	inline bool 
+	in(Scalar x, const Interval& z) 
+	{
+		return z.lower() <= x && x <= z.upper();
+	}
+	
+	template 
+	inline Interval 
+	widen(const Interval& z, const Scalar& x) 
+	{
+		return Interval(z.lower() - x, z.upper() + x);
+	}	
+		
+	template
+	inline Interval
+	hull(const Interval& z1, const Interval& z2)
+	{
+		return Interval(GEN_min(z1.lower(), z2.lower()), 
+								GEN_max(z1.upper(), z2.upper()));
+	}	
+   
+   template
+	inline Interval
+	operator+(Scalar x, const Interval& z)
+	{
+		return Interval(x + z.lower(), x + z.upper());
+	}
+}
+
+#endif
diff --git a/extern/solid/include/MT/Matrix3x3.h b/extern/solid/include/MT/Matrix3x3.h
new file mode 100644
index 00000000000..85e0d4cac84
--- /dev/null
+++ b/extern/solid/include/MT/Matrix3x3.h
@@ -0,0 +1,380 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MATRIX3X3_H
+#define MATRIX3X3_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include "Vector3.h"
+#include "Quaternion.h"
+
+namespace MT {
+
+  // Row-major 3x3 matrix
+  
+	template 
+	class Matrix3x3 {
+	public:
+		Matrix3x3() {}
+		
+		template 
+		explicit Matrix3x3(const Scalar2 *m) { setValue(m); }
+		
+		explicit Matrix3x3(const Quaternion& q) { setRotation(q); }
+		
+		template 
+		Matrix3x3(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll)
+		{ 
+			setEuler(yaw, pitch, roll);
+		}
+		
+		template 
+		Matrix3x3(const Scalar2& xx, const Scalar2& xy, const Scalar2& xz,
+				  const Scalar2& yx, const Scalar2& yy, const Scalar2& yz,
+				  const Scalar2& zx, const Scalar2& zy, const Scalar2& zz)
+		{ 
+			setValue(xx, xy, xz, 
+					 yx, yy, yz, 
+					 zx, zy, zz);
+		}
+		
+		Vector3&  operator[](int i)
+		{ 
+			assert(0 <= i && i < 3);
+			return m_el[i]; 
+		}
+		
+		const Vector3& operator[](int i) const
+		{
+			assert(0 <= i && i < 3);
+			return m_el[i]; 
+		}
+		
+		Matrix3x3& operator*=(const Matrix3x3& m); 
+		
+		template 
+		void setValue(const Scalar2 *m)
+		{
+			m_el[0][0] = Scalar(m[0]); 
+			m_el[1][0] = Scalar(m[1]); 
+			m_el[2][0] = Scalar(m[2]);
+			m_el[0][1] = Scalar(m[4]); 
+			m_el[1][1] = Scalar(m[5]); 
+			m_el[2][1] = Scalar(m[6]);
+			m_el[0][2] = Scalar(m[8]); 
+			m_el[1][2] = Scalar(m[9]); 
+			m_el[2][2] = Scalar(m[10]);
+		}
+
+		template 
+		void setValue(const Scalar2& xx, const Scalar2& xy, const Scalar2& xz, 
+					  const Scalar2& yx, const Scalar2& yy, const Scalar2& yz, 
+					  const Scalar2& zx, const Scalar2& zy, const Scalar2& zz)
+		{
+			m_el[0][0] = Scalar(xx); 
+			m_el[0][1] = Scalar(xy); 
+			m_el[0][2] = Scalar(xz);
+			m_el[1][0] = Scalar(yx); 
+			m_el[1][1] = Scalar(yy); 
+			m_el[1][2] = Scalar(yz);
+			m_el[2][0] = Scalar(zx); 
+			m_el[2][1] = Scalar(zy); 
+			m_el[2][2] = Scalar(zz);
+		}
+  
+		void setRotation(const Quaternion& q) 
+		{
+			Scalar d = q.length2();
+			assert(d != Scalar(0.0));
+			Scalar s = Scalar(2.0) / d;
+			Scalar xs = q[0] * s,   ys = q[1] * s,   zs = q[2] * s;
+			Scalar wx = q[3] * xs,  wy = q[3] * ys,  wz = q[3] * zs;
+			Scalar xx = q[0] * xs,  xy = q[0] * ys,  xz = q[0] * zs;
+			Scalar yy = q[1] * ys,  yz = q[1] * zs,  zz = q[2] * zs;
+			setValue(Scalar(1.0) - (yy + zz), xy - wz, xz + wy,
+					 xy + wz, Scalar(1.0) - (xx + zz), yz - wx,
+					 xz - wy, yz + wx, Scalar(1.0) - (xx + yy));
+		}
+		
+		template  
+		void setEuler(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll) 
+		{
+			Scalar cy(Scalar_traits::cos(yaw)); 
+			Scalar sy(Scalar_traits::sin(yaw)); 
+			Scalar cp(Scalar_traits::cos(pitch)); 
+			Scalar sp(Scalar_traits::sin(pitch)); 
+			Scalar cr(Scalar_traits::cos(roll));
+			Scalar sr(Scalar_traits::sin(roll));
+			Scalar cc = cy * cr; 
+			Scalar cs = cy * sr; 
+			Scalar sc = sy * cr; 
+			Scalar ss = sy * sr;
+			setValue(cy * cp, -sc + sp * cs,  ss - sp * cc,
+					 sy * cp,  cc + sp * ss, -cs + sp * sc,
+					     -sp,       cp * sr,       cp * cr);
+		}
+		void setIdentity()
+		{ 
+			setValue(Scalar(1.0), Scalar(0.0), Scalar(0.0), 
+					 Scalar(0.0), Scalar(1.0), Scalar(0.0), 
+					 Scalar(0.0), Scalar(0.0), Scalar(1.0)); 
+		}
+    
+		template 
+		void getValue(Scalar2 *m) const 
+		{
+			m[0]  = Scalar2(m_el[0][0]); 
+			m[1]  = Scalar2(m_el[1][0]);
+			m[2]  = Scalar2(m_el[2][0]);
+			m[3]  = Scalar2(0.0); 
+			m[4]  = Scalar2(m_el[0][1]);
+			m[5]  = Scalar2(m_el[1][1]);
+			m[6]  = Scalar2(m_el[2][1]);
+			m[7]  = Scalar2(0.0); 
+			m[8]  = Scalar2(m_el[0][2]); 
+			m[9]  = Scalar2(m_el[1][2]);
+			m[10] = Scalar2(m_el[2][2]);
+			m[11] = Scalar2(0.0); 
+		}
+		
+		void getRotation(Quaternion& q) const
+		{
+			Scalar trace = m_el[0][0] + m_el[1][1] + m_el[2][2];
+			
+			if (trace > Scalar(0.0)) 
+			{
+				Scalar s = Scalar_traits::sqrt(trace + Scalar(1.0));
+				q[3] = s * Scalar(0.5);
+				s = Scalar(0.5) / s;
+				
+				q[0] = (m_el[2][1] - m_el[1][2]) * s;
+				q[1] = (m_el[0][2] - m_el[2][0]) * s;
+				q[2] = (m_el[1][0] - m_el[0][1]) * s;
+			} 
+			else 
+			{
+				int i = m_el[0][0] < m_el[1][1] ? 
+					(m_el[1][1] < m_el[2][2] ? 2 : 1) :
+					(m_el[0][0] < m_el[2][2] ? 2 : 0); 
+				int j = (i + 1) % 3;  
+				int k = (i + 2) % 3;
+				
+				Scalar s = Scalar_traits::sqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + Scalar(1.0));
+				q[i] = s * Scalar(0.5);
+				s = Scalar(0.5) / s;
+				
+				q[3] = (m_el[k][j] - m_el[j][k]) * s;
+				q[j] = (m_el[j][i] + m_el[i][j]) * s;
+				q[k] = (m_el[k][i] + m_el[i][k]) * s;
+			}
+		}
+
+
+		
+		template 
+		void getEuler(Scalar2& yaw, Scalar2& pitch, Scalar2& roll) const
+		{
+			pitch = Scalar2(Scalar_traits::asin(-m_el[2][0]));
+			if (pitch < Scalar_traits::TwoTimesPi())
+			{
+				if (pitch > Scalar_traits::TwoTimesPi())
+				{
+					yaw = Scalar2(Scalar_traits::atan2(m_el[1][0], m_el[0][0]));
+					roll = Scalar2(Scalar_traits::atan2(m_el[2][1], m_el[2][2]));
+				}
+				else 
+				{
+					yaw = Scalar2(-Scalar_traits::atan2(-m_el[0][1], m_el[0][2]));
+					roll = Scalar2(0.0);
+				}
+			}
+			else
+			{
+				yaw = Scalar2(Scalar_traits::atan2(-m_el[0][1], m_el[0][2]));
+				roll = Scalar2(0.0);
+			}
+		}
+
+		Vector3 getScaling() const
+		{
+			return Vector3(m_el[0][0] * m_el[0][0] + m_el[1][0] * m_el[1][0] + m_el[2][0] * m_el[2][0],
+								   m_el[0][1] * m_el[0][1] + m_el[1][1] * m_el[1][1] + m_el[2][1] * m_el[2][1],
+								   m_el[0][2] * m_el[0][2] + m_el[1][2] * m_el[1][2] + m_el[2][2] * m_el[2][2]);
+		}
+		
+		
+		Matrix3x3 scaled(const Vector3& s) const
+		{
+			return Matrix3x3(m_el[0][0] * s[0], m_el[0][1] * s[1], m_el[0][2] * s[2],
+									 m_el[1][0] * s[0], m_el[1][1] * s[1], m_el[1][2] * s[2],
+									 m_el[2][0] * s[0], m_el[2][1] * s[1], m_el[2][2] * s[2]);
+		}
+
+		Scalar            determinant() const;
+		Matrix3x3 adjoint() const;
+		Matrix3x3 absolute() const;
+		Matrix3x3 transpose() const;
+		Matrix3x3 inverse() const; 
+		
+		Matrix3x3 transposeTimes(const Matrix3x3& m) const;
+		Matrix3x3 timesTranspose(const Matrix3x3& m) const;
+		
+		Scalar tdot(int c, const Vector3& v) const 
+		{
+			return m_el[0][c] * v[0] + m_el[1][c] * v[1] + m_el[2][c] * v[2];
+		}
+		
+	protected:
+		Scalar cofac(int r1, int c1, int r2, int c2) const 
+		{
+			return m_el[r1][c1] * m_el[r2][c2] - m_el[r1][c2] * m_el[r2][c1];
+		}
+
+		Vector3 m_el[3];
+	};
+	
+	template 
+	inline std::ostream& 
+	operator<<(std::ostream& os, const Matrix3x3& m)
+	{
+		return os << m[0] << std::endl << m[1] << std::endl << m[2] << std::endl;
+	}
+	
+	template 
+	inline Matrix3x3& 
+	Matrix3x3::operator*=(const Matrix3x3& m)
+	{
+		setValue(m.tdot(0, m_el[0]), m.tdot(1, m_el[0]), m.tdot(2, m_el[0]),
+				 m.tdot(0, m_el[1]), m.tdot(1, m_el[1]), m.tdot(2, m_el[1]),
+				 m.tdot(0, m_el[2]), m.tdot(1, m_el[2]), m.tdot(2, m_el[2]));
+		return *this;
+	}
+	
+	template 
+	inline Scalar 
+	Matrix3x3::determinant() const
+	{ 
+		return triple((*this)[0], (*this)[1], (*this)[2]);
+	}
+	
+
+	template 
+	inline Matrix3x3 
+	Matrix3x3::absolute() const
+	{
+		return Matrix3x3(
+			Scalar_traits::abs(m_el[0][0]), Scalar_traits::abs(m_el[0][1]), Scalar_traits::abs(m_el[0][2]),
+			Scalar_traits::abs(m_el[1][0]), Scalar_traits::abs(m_el[1][1]), Scalar_traits::abs(m_el[1][2]),
+			Scalar_traits::abs(m_el[2][0]), Scalar_traits::abs(m_el[2][1]), Scalar_traits::abs(m_el[2][2]));
+	}
+
+	template 
+	inline Matrix3x3 
+	Matrix3x3::transpose() const 
+	{
+		return Matrix3x3(m_el[0][0], m_el[1][0], m_el[2][0],
+								 m_el[0][1], m_el[1][1], m_el[2][1],
+								 m_el[0][2], m_el[1][2], m_el[2][2]);
+	}
+	
+	template 
+	inline Matrix3x3 
+	Matrix3x3::adjoint() const 
+	{
+		return Matrix3x3(cofac(1, 1, 2, 2), cofac(0, 2, 2, 1), cofac(0, 1, 1, 2),
+								 cofac(1, 2, 2, 0), cofac(0, 0, 2, 2), cofac(0, 2, 1, 0),
+								 cofac(1, 0, 2, 1), cofac(0, 1, 2, 0), cofac(0, 0, 1, 1));
+	}
+	
+	template 
+	inline Matrix3x3 
+	Matrix3x3::inverse() const
+	{
+		Vector3 co(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1));
+		Scalar det = (*this)[0].dot(co);
+		assert(det != Scalar(0.0));
+		Scalar s = Scalar(1.0) / det;
+		return Matrix3x3(co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s,
+								 co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s,
+								 co[2] * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s);
+	}
+	
+	template 
+	inline Matrix3x3 
+	Matrix3x3::transposeTimes(const Matrix3x3& m) const
+	{
+		return Matrix3x3(
+			m_el[0][0] * m[0][0] + m_el[1][0] * m[1][0] + m_el[2][0] * m[2][0],
+			m_el[0][0] * m[0][1] + m_el[1][0] * m[1][1] + m_el[2][0] * m[2][1],
+			m_el[0][0] * m[0][2] + m_el[1][0] * m[1][2] + m_el[2][0] * m[2][2],
+			m_el[0][1] * m[0][0] + m_el[1][1] * m[1][0] + m_el[2][1] * m[2][0],
+			m_el[0][1] * m[0][1] + m_el[1][1] * m[1][1] + m_el[2][1] * m[2][1],
+			m_el[0][1] * m[0][2] + m_el[1][1] * m[1][2] + m_el[2][1] * m[2][2],
+			m_el[0][2] * m[0][0] + m_el[1][2] * m[1][0] + m_el[2][2] * m[2][0],
+			m_el[0][2] * m[0][1] + m_el[1][2] * m[1][1] + m_el[2][2] * m[2][1],
+			m_el[0][2] * m[0][2] + m_el[1][2] * m[1][2] + m_el[2][2] * m[2][2]);
+	}
+	
+	template 
+	inline Matrix3x3 
+	Matrix3x3::timesTranspose(const Matrix3x3& m) const
+	{
+		return Matrix3x3(
+			m_el[0].dot(m[0]), m_el[0].dot(m[1]), m_el[0].dot(m[2]),
+			m_el[1].dot(m[0]), m_el[1].dot(m[1]), m_el[1].dot(m[2]),
+			m_el[2].dot(m[0]), m_el[2].dot(m[1]), m_el[2].dot(m[2]));
+		
+	}
+
+	template 
+	inline Vector3 
+	operator*(const Matrix3x3& m, const Vector3& v) 
+	{
+		return Vector3(m[0].dot(v), m[1].dot(v), m[2].dot(v));
+	}
+	
+
+	template 
+	inline Vector3
+	operator*(const Vector3& v, const Matrix3x3& m)
+	{
+		return Vector3(m.tdot(0, v), m.tdot(1, v), m.tdot(2, v));
+	}
+
+	template 
+	inline Matrix3x3 
+	operator*(const Matrix3x3& m1, const Matrix3x3& m2)
+	{
+		return Matrix3x3(
+			m2.tdot(0, m1[0]), m2.tdot(1, m1[0]), m2.tdot(2, m1[0]),
+			m2.tdot(0, m1[1]), m2.tdot(1, m1[1]), m2.tdot(2, m1[1]),
+			m2.tdot(0, m1[2]), m2.tdot(1, m1[2]), m2.tdot(2, m1[2]));
+	}
+}
+
+#endif
diff --git a/extern/solid/include/MT/Quaternion.h b/extern/solid/include/MT/Quaternion.h
new file mode 100644
index 00000000000..a925f21cd5d
--- /dev/null
+++ b/extern/solid/include/MT/Quaternion.h
@@ -0,0 +1,316 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef QUATERNION_H
+#define QUATERNION_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include "Tuple4.h"
+#include "Vector3.h"
+
+namespace MT {
+
+	template 	
+	class Quaternion : public Tuple4 {
+	public:
+		Quaternion() {}
+		
+		template 
+		explicit Quaternion(const Scalar2 *v) : Tuple4(v) {}
+		
+		template 
+		Quaternion(const Scalar2& x, const Scalar2& y, const Scalar2& z, const Scalar2& w) 
+			: Tuple4(x, y, z, w) 
+		{}
+		
+		Quaternion(const Vector3& axis, const Scalar& angle) 
+		{ 
+			setRotation(axis, angle); 
+		}
+
+		template 
+		Quaternion(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll)
+		{ 
+			setEuler(yaw, pitch, roll); 
+		}
+
+		void setRotation(const Vector3& axis, const Scalar& angle)
+		{
+			Scalar d = axis.length();
+			assert(d != Scalar(0.0));
+			Scalar s = Scalar_traits::sin(angle * Scalar(0.5)) / d;
+			setValue(axis[0] * s, axis[1] * s, axis[2] * s, 
+					 Scalar_traits::cos(angle * Scalar(0.5)));
+		}
+
+		template 
+		void setEuler(const Scalar2& yaw, const Scalar2& pitch, const Scalar2& roll)
+		{
+			Scalar halfYaw = Scalar(yaw) * Scalar(0.5);  
+			Scalar halfPitch = Scalar(pitch) * Scalar(0.5);  
+			Scalar halfRoll = Scalar(roll) * Scalar(0.5);  
+			Scalar cosYaw = Scalar_traits::cos(halfYaw);
+			Scalar sinYaw = Scalar_traits::sin(halfYaw);
+			Scalar cosPitch = Scalar_traits::cos(halfPitch);
+			Scalar sinPitch = Scalar_traits::sin(halfPitch);
+			Scalar cosRoll = Scalar_traits::cos(halfRoll);
+			Scalar sinRoll = Scalar_traits::sin(halfRoll);
+			setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw,
+					 cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw,
+					 sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw,
+					 cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw);
+		}
+  
+		Quaternion& operator+=(const Quaternion& q)
+		{
+			this->m_co[0] += q[0]; this->m_co[1] += q[1]; this->m_co[2] += q[2]; this->m_co[3] += q[3];
+			return *this;
+		}
+		
+		Quaternion& operator-=(const Quaternion& q) 
+		{
+			this->m_co[0] -= q[0]; this->m_co[1] -= q[1]; this->m_co[2] -= q[2]; this->m_co[3] -= q[3];
+			return *this;
+		}
+
+		Quaternion& operator*=(const Scalar& s)
+		{
+			this->m_co[0] *= s; this->m_co[1] *= s; this->m_co[2] *= s; this->m_co[3] *= s;
+			return *this;
+		}
+		
+		Quaternion& operator/=(const Scalar& s) 
+		{
+			assert(s != Scalar(0.0));
+			return *this *= Scalar(1.0) / s;
+		}
+  
+		Quaternion& operator*=(const Quaternion& q)
+		{
+			setValue(this->m_co[3] * q[0] + this->m_co[0] * q[3] + this->m_co[1] * q[2] - this->m_co[2] * q[1],
+					 this->m_co[3] * q[1] + this->m_co[1] * q[3] + this->m_co[2] * q[0] - this->m_co[0] * q[2],
+					 this->m_co[3] * q[2] + this->m_co[2] * q[3] + this->m_co[0] * q[1] - this->m_co[1] * q[0],
+					 this->m_co[3] * q[3] - this->m_co[0] * q[0] - this->m_co[1] * q[1] - this->m_co[2] * q[2]);
+			return *this;
+		}
+	
+		Scalar dot(const Quaternion& q) const
+		{
+			return this->m_co[0] * q[0] + this->m_co[1] * q[1] + this->m_co[2] * q[2] + this->m_co[3] * q[3];
+		}
+
+		Scalar length2() const
+		{
+			return dot(*this);
+		}
+
+		Scalar length() const
+		{
+			return Scalar_traits::sqrt(length2());
+		}
+
+		Quaternion& normalize() 
+		{
+			return *this /= length();
+		}
+		
+		Quaternion normalized() const 
+		{
+			return *this / length();
+		} 
+
+		Scalar angle(const Quaternion& q) const 
+		{
+			Scalar s = Scalar_traits::sqrt(length2() * q.length2());
+			assert(s != Scalar(0.0));
+			return Scalar_traits::acos(dot(q) / s);
+		}
+   
+		Quaternion conjugate() const 
+		{
+			return Quaternion(-this->m_co[0], -this->m_co[1], -this->m_co[2], this->m_co[3]);
+		}
+
+		Quaternion inverse() const
+		{
+			return conjugate / length2();
+		}
+		
+		Quaternion slerp(const Quaternion& q, const Scalar& t) const
+		{
+			Scalar theta = angle(q);
+			if (theta != Scalar(0.0))
+			{
+				Scalar d = Scalar(1.0) / Scalar_traits::sin(theta);
+				Scalar s0 = Scalar_traits::sin((Scalar(1.0) - t) * theta);
+				Scalar s1 = Scalar_traits::sin(t * theta);   
+				return Quaternion((this->m_co[0] * s0 + q[0] * s1) * d,
+										  (this->m_co[1] * s0 + q[1] * s1) * d,
+										  (this->m_co[2] * s0 + q[2] * s1) * d,
+										  (this->m_co[3] * s0 + q[3] * s1) * d);
+			}
+			else
+			{
+				return *this;
+			}
+		}
+
+		static Quaternion random() 
+		{
+			// From: "Uniform Random Rotations", Ken Shoemake, Graphics Gems III, 
+            //       pg. 124-132
+			Scalar x0 = Scalar_traits::random();
+			Scalar r1 = Scalar_traits::sqrt(Scalar(1.0) - x0);
+			Scalar r2 = Scalar_traits::sqrt(x0);
+			Scalar t1 = Scalar_traits::TwoTimesPi() * Scalar_traits::random();
+			Scalar t2 = Scalar_traits::TwoTimesPi() * Scalar_traits::random();
+			Scalar c1 = Scalar_traits::cos(t1);
+			Scalar s1 = Scalar_traits::sin(t1);
+			Scalar c2 = Scalar_traits::cos(t2);
+			Scalar s2 = Scalar_traits::sin(t2);
+			return Quaternion(s1 * r1, c1 * r1, s2 * r2, c2 * r2);
+		}
+
+	};
+
+	template 
+	inline Quaternion
+	operator+(const Quaternion& q1, const Quaternion& q2)
+	{
+		return Quaternion(q1[0] + q2[0], q1[1] + q2[1], q1[2] + q2[2], q1[3] + q2[3]);
+	}
+	
+	template 
+	inline Quaternion
+	operator-(const Quaternion& q1, const Quaternion& q2)
+	{
+		return Quaternion(q1[0] - q2[0], q1[1] - q2[1], q1[2] - q2[2], q1[3] - q2[3]);
+	}
+	
+	template 
+	inline Quaternion
+	operator-(const Quaternion& q)
+	{
+		return Quaternion(-q[0], -q[1], -q[2], -q[3]);
+	}
+
+	template 
+	inline Quaternion
+	operator*(const Quaternion& q, const Scalar& s)
+	{
+		return Quaternion(q[0] * s, q[1] * s, q[2] * s, q[3] * s);
+	}
+	
+	template 
+	inline Quaternion
+	operator*(const Scalar& s, const Quaternion& q)
+	{
+		return q * s;
+	}
+	
+	template 
+	inline Quaternion
+	operator*(const Quaternion& q1, const Quaternion& q2) {
+		return Quaternion(q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1],
+								  q1[3] * q2[1] + q1[1] * q2[3] + q1[2] * q2[0] - q1[0] * q2[2],
+								  q1[3] * q2[2] + q1[2] * q2[3] + q1[0] * q2[1] - q1[1] * q2[0],
+								  q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2]); 
+	}
+	
+	template 
+	inline Quaternion
+	operator*(const Quaternion& q, const Vector3& w)
+	{
+		return Quaternion( q[3] * w[0] + q[1] * w[2] - q[2] * w[1],
+								   q[3] * w[1] + q[2] * w[0] - q[0] * w[2],
+								   q[3] * w[2] + q[0] * w[1] - q[1] * w[0],
+								  -q[0] * w[0] - q[1] * w[1] - q[2] * w[2]); 
+	}
+	
+	template 
+	inline Quaternion
+	operator*(const Vector3& w, const Quaternion& q)
+	{
+		return Quaternion( w[0] * q[3] + w[1] * q[2] - w[2] * q[1],
+								   w[1] * q[3] + w[2] * q[0] - w[0] * q[2],
+								   w[2] * q[3] + w[0] * q[1] - w[1] * q[0],
+								  -w[0] * q[0] - w[1] * q[1] - w[2] * q[2]); 
+	}
+	
+	template 
+	inline Scalar 
+	dot(const Quaternion& q1, const Quaternion& q2) 
+	{ 
+		return q1.dot(q2); 
+	}
+
+	template 
+	inline Scalar
+	length2(const Quaternion& q) 
+	{ 
+		return q.length2(); 
+	}
+
+	template 
+	inline Scalar
+	length(const Quaternion& q) 
+	{ 
+		return q.length(); 
+	}
+
+	template 
+	inline Scalar
+	angle(const Quaternion& q1, const Quaternion& q2) 
+	{ 
+		return q1.angle(q2); 
+	}
+
+	template 
+	inline Quaternion
+	conjugate(const Quaternion& q) 
+	{
+		return q.conjugate();
+	}
+
+	template 
+	inline Quaternion
+	inverse(const Quaternion& q) 
+	{
+		return q.inverse();
+	}
+
+	template 
+	inline Quaternion
+	slerp(const Quaternion& q1, const Quaternion& q2, const Scalar& t) 
+	{
+		return q1.slerp(q2, t);
+	}
+	
+}
+
+#endif
diff --git a/extern/solid/include/MT/Transform.h b/extern/solid/include/MT/Transform.h
new file mode 100644
index 00000000000..b80dc1bc18b
--- /dev/null
+++ b/extern/solid/include/MT/Transform.h
@@ -0,0 +1,189 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef TRANSFORM_H
+#define TRANSFORM_H
+
+#include "Vector3.h"
+#include "Matrix3x3.h"
+
+namespace MT {
+
+	template 
+	class Transform {
+		enum { 
+			TRANSLATION = 0x01,
+			ROTATION    = 0x02,
+			RIGID       = TRANSLATION | ROTATION,  
+			SCALING     = 0x04,
+			LINEAR      = ROTATION | SCALING,
+			AFFINE      = TRANSLATION | LINEAR
+		};
+    
+	public:
+		Transform() {}
+		
+		template 
+		explicit Transform(const Scalar2 *m) { setValue(m); }
+
+		explicit Transform(const Quaternion& q, 
+						   const Vector3& c = Vector3(Scalar(0), Scalar(0), Scalar(0))) 
+			: m_basis(q),
+			  m_origin(c),
+			  m_type(RIGID)
+		{}
+
+		explicit Transform(const Matrix3x3& b, 
+						   const Vector3& c = Vector3(Scalar(0), Scalar(0), Scalar(0)), 
+						   unsigned int type = AFFINE)
+			: m_basis(b),
+			  m_origin(c),
+			  m_type(type)
+		{}
+
+		Vector3 operator()(const Vector3& x) const
+		{
+			return Vector3(m_basis[0].dot(x) + m_origin[0], 
+								   m_basis[1].dot(x) + m_origin[1], 
+								   m_basis[2].dot(x) + m_origin[2]);
+		}
+    
+		Vector3 operator*(const Vector3& x) const
+		{
+			return (*this)(x);
+		}
+
+		Matrix3x3&       getBasis()          { return m_basis; }
+		const Matrix3x3& getBasis()    const { return m_basis; }
+
+		Vector3&         getOrigin()         { return m_origin; }
+		const Vector3&   getOrigin()   const { return m_origin; }
+
+		Quaternion getRotation() const { return m_basis.getRotation(); }
+		template 
+		void setValue(const Scalar2 *m) 
+		{
+			m_basis.setValue(m);
+			m_origin.setValue(&m[12]);
+			m_type = AFFINE;
+		}
+
+		template 
+		void getValue(Scalar2 *m) const 
+		{
+			m_basis.getValue(m);
+			m_origin.getValue(&m[12]);
+			m[15] = Scalar2(1.0);
+		}
+
+		void setOrigin(const Vector3& origin) 
+		{ 
+			m_origin = origin;
+			m_type |= TRANSLATION;
+		}
+
+		void setBasis(const Matrix3x3& basis)
+		{ 
+			m_basis = basis;
+			m_type |= LINEAR;
+		}
+
+		void setRotation(const Quaternion& q)
+		{
+			m_basis.setRotation(q);
+			m_type = (m_type & ~LINEAR) | ROTATION;
+		}
+
+    	void scale(const Vector3& scaling)
+		{
+			m_basis = m_basis.scaled(scaling);
+			m_type |= SCALING;
+		}
+    
+		void setIdentity()
+		{
+			m_basis.setIdentity();
+			m_origin.setValue(Scalar(0.0), Scalar(0.0), Scalar(0.0));
+			m_type = 0x0;
+		}
+		
+		bool isIdentity() const { return m_type == 0x0; }
+    
+		Transform& operator*=(const Transform& t) 
+		{
+			m_origin += m_basis * t.m_origin;
+			m_basis *= t.m_basis;
+			m_type |= t.m_type; 
+			return *this;
+		}
+
+		Transform inverse() const
+		{ 
+			Matrix3x3 inv = (m_type & SCALING) ? 
+				                    m_basis.inverse() : 
+				                    m_basis.transpose();
+			
+			return Transform(inv, inv * -m_origin, m_type);
+		}
+
+		Transform inverseTimes(const Transform& t) const;  
+
+		Transform operator*(const Transform& t) const;
+
+	private:
+		
+		Matrix3x3 m_basis;
+		Vector3   m_origin;
+		unsigned int      m_type;
+	};
+
+
+	template 
+	inline Transform 
+	Transform::inverseTimes(const Transform& t) const  
+	{
+		Vector3 v = t.getOrigin() - m_origin;
+		if (m_type & SCALING) 
+		{
+			Matrix3x3 inv = m_basis.inverse();
+			return Transform(inv * t.getBasis(), inv * v, 
+									 m_type | t.m_type);
+		}
+		else 
+		{
+			return Transform(m_basis.transposeTimes(t.m_basis),
+									 v * m_basis, m_type | t.m_type);
+		}
+	}
+
+	template 
+	inline Transform 
+	Transform::operator*(const Transform& t) const
+	{
+		return Transform(m_basis * t.m_basis, 
+								 (*this)(t.m_origin), 
+								 m_type | t.m_type);
+	}	
+}
+
+#endif
diff --git a/extern/solid/include/MT/Tuple3.h b/extern/solid/include/MT/Tuple3.h
new file mode 100644
index 00000000000..52ea33b7f58
--- /dev/null
+++ b/extern/solid/include/MT/Tuple3.h
@@ -0,0 +1,120 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef TUPLE3_H
+#define TUPLE3_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include 
+
+namespace MT {
+
+	template 
+	class Tuple3 {
+	public:
+		Tuple3() {}
+		
+		template 
+		explicit Tuple3(const Scalar2 *v) 
+		{ 
+			setValue(v);
+		}
+		
+		template 
+		Tuple3(const Scalar2& x, const Scalar2& y, const Scalar2& z) 
+		{ 
+			setValue(x, y, z); 
+		}
+		
+		template 
+		Tuple3(const Tuple3& t) 
+		{ 
+			*this = t; 
+		}
+		
+		template 
+		Tuple3& operator=(const Tuple3& t) 
+		{ 
+			m_co[0] = Scalar(t[0]); 
+			m_co[1] = Scalar(t[1]); 
+			m_co[2] = Scalar(t[2]);
+			return *this;
+		}
+		
+		operator       Scalar *()       { return m_co; }
+		operator const Scalar *() const { return m_co; }
+
+		Scalar&       operator[](int i)       { return m_co[i];	}      
+		const Scalar& operator[](int i) const { return m_co[i]; }
+
+		Scalar&       x()       { return m_co[0]; }
+		const Scalar& x() const { return m_co[0]; }
+		
+		Scalar&       y()       { return m_co[1]; }
+		const Scalar& y() const { return m_co[1]; }
+		
+		Scalar&       z()       { return m_co[2]; }
+		const Scalar& z() const { return m_co[2]; }
+
+		template 
+		void setValue(const Scalar2 *v) 
+		{
+			m_co[0] = Scalar(v[0]); 
+			m_co[1] = Scalar(v[1]); 
+			m_co[2] = Scalar(v[2]);
+		}
+
+		template 
+		void setValue(const Scalar2& x, const Scalar2& y, const Scalar2& z)
+		{
+			m_co[0] = Scalar(x); 
+			m_co[1] = Scalar(y); 
+			m_co[2] = Scalar(z);
+		}
+
+		template 
+		void getValue(Scalar2 *v) const 
+		{
+			v[0] = Scalar2(m_co[0]);
+			v[1] = Scalar2(m_co[1]);
+			v[2] = Scalar2(m_co[2]);
+		}
+    
+	protected:
+		Scalar m_co[3];                            
+	};
+
+	template 
+	inline std::ostream& 
+	operator<<(std::ostream& os, const Tuple3& t)
+	{
+		return os << t[0] << ' ' << t[1] << ' ' << t[2];
+	}
+}
+
+#endif
diff --git a/extern/solid/include/MT/Tuple4.h b/extern/solid/include/MT/Tuple4.h
new file mode 100644
index 00000000000..6930541271e
--- /dev/null
+++ b/extern/solid/include/MT/Tuple4.h
@@ -0,0 +1,112 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef TUPLE4_H
+#define TUPLE4_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include 
+
+namespace MT {
+
+	template 
+	class Tuple4 {
+	public:
+		Tuple4() {}
+		
+		template 
+		explicit Tuple4(const Scalar2 *v) 
+		{ 
+			setValue(v);
+		}
+		
+		template 
+		Tuple4(const Scalar2& x, const Scalar2& y, const Scalar2& z, const Scalar2& w) 
+		{ 
+			setValue(x, y, z, w); 
+		}
+		
+		operator       Scalar *()       { return m_co; }
+		operator const Scalar *() const { return m_co; }
+
+		Scalar&       operator[](int i)       { return m_co[i]; }      
+		const Scalar& operator[](int i) const {	return m_co[i];	}
+		
+		Scalar&       x()       { return m_co[0]; }
+		const Scalar& x() const { return m_co[0]; }
+		
+		Scalar&       y()       { return m_co[1]; }
+		const Scalar& y() const { return m_co[1]; }
+		
+		Scalar&       z()       { return m_co[2]; }
+		const Scalar& z() const { return m_co[2]; }
+
+		Scalar&       w()       { return m_co[3]; }
+		const Scalar& w() const { return m_co[3]; }
+    
+		template 
+		void setValue(const Scalar2 *v) 
+		{
+			m_co[0] = Scalar(v[0]); 
+			m_co[1] = Scalar(v[1]); 
+			m_co[2] = Scalar(v[2]);
+			m_co[3] = Scalar(v[3]);
+		}
+
+		template 
+		void setValue(const Scalar2& x, const Scalar2& y, const Scalar2& z, const Scalar2& w)
+		{
+			m_co[0] = Scalar(x); 
+			m_co[1] = Scalar(y); 
+			m_co[2] = Scalar(z);
+			m_co[3] = Scalar(w);
+		}
+
+		template 
+		void getValue(Scalar2 *v) const 
+		{
+			v[0] = Scalar2(m_co[0]);
+			v[1] = Scalar2(m_co[1]);
+			v[2] = Scalar2(m_co[2]);
+			v[3] = Scalar2(m_co[3]);
+		}
+
+	protected:
+		Scalar m_co[4];
+	};
+
+	template 
+	inline std::ostream&
+	operator<<(std::ostream& os, const Tuple4& t)
+	{
+		return os << t[0] << ' ' << t[1] << ' ' << t[2] << ' ' << t[3];
+	}
+
+}
+
+#endif
diff --git a/extern/solid/include/MT/Vector3.h b/extern/solid/include/MT/Vector3.h
new file mode 100644
index 00000000000..b569c003f59
--- /dev/null
+++ b/extern/solid/include/MT/Vector3.h
@@ -0,0 +1,283 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef VECTOR3_H
+#define VECTOR3_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+#include "Tuple3.h"
+
+namespace MT {
+
+	template 	
+	class Vector3 : public Tuple3 {
+	public:
+		Vector3() {}
+	
+		template 
+		explicit Vector3(const Scalar2 *v) : Tuple3(v) {}
+		
+		template 
+		Vector3(const Scalar2& x, const Scalar2& y, const Scalar2& z) 
+			: Tuple3(x, y, z) 
+		{}
+		
+		Vector3& operator+=(const Vector3& v)
+		{
+			this->m_co[0] += v[0]; this->m_co[1] += v[1]; this->m_co[2] += v[2];
+			return *this;
+		}
+		
+		Vector3& operator-=(const Vector3& v) 
+		{
+			this->m_co[0] -= v[0]; this->m_co[1] -= v[1]; this->m_co[2] -= v[2];
+			return *this;
+		}
+
+		Vector3& operator*=(const Scalar& s)
+		{
+			this->m_co[0] *= s; this->m_co[1] *= s; this->m_co[2] *= s;
+			return *this;
+		}
+		
+		Vector3& operator/=(const Scalar& s) 
+		{
+			assert(s != Scalar(0.0));
+			return *this *= Scalar(1.0) / s;
+		}
+  
+		Scalar dot(const Vector3& v) const
+		{
+			return this->m_co[0] * v[0] + this->m_co[1] * v[1] + this->m_co[2] * v[2];
+		}
+
+		Scalar length2() const
+		{
+			return dot(*this);
+		}
+
+		Scalar length() const
+		{
+			return Scalar_traits::sqrt(length2());
+		}
+
+		Scalar distance2(const Vector3& v) const 
+		{
+			return (v - *this).length2();
+		}
+
+		Scalar distance(const Vector3& v) const 
+		{
+			return (v - *this).length();
+		}
+		
+		Vector3& normalize() 
+		{
+			return *this /= length();
+		}
+		
+		Vector3 normalized() const 
+		{
+			return *this / length();
+		} 
+
+		Scalar angle(const Vector3& v) const 
+		{
+			Scalar s = Scalar_traits::sqrt(length2() * v.length2());
+			assert(s != Scalar(0.0));
+			return Scalar_traits::acos(dot(v) / s);
+		}
+   
+		Vector3 absolute() const 
+		{
+			return Vector3(Scalar_traits::abs(this->m_co[0]), 
+								   Scalar_traits::abs(this->m_co[1]), 
+								   Scalar_traits::abs(this->m_co[2]));
+		}
+
+		Vector3 cross(const Vector3& v) const
+		{
+			return Vector3(this->m_co[1] * v[2] - this->m_co[2] * v[1],
+								   this->m_co[2] * v[0] - this->m_co[0] * v[2],
+								   this->m_co[0] * v[1] - this->m_co[1] * v[0]);
+		}
+		
+		Scalar triple(const Vector3& v1, const Vector3& v2) const
+		{
+			return this->m_co[0] * (v1[1] * v2[2] - v1[2] * v2[1]) + 
+				   this->m_co[1] * (v1[2] * v2[0] - v1[0] * v2[2]) + 
+				   this->m_co[2] * (v1[0] * v2[1] - v1[1] * v2[0]);
+		}
+
+		int minAxis() const
+		{
+			return this->m_co[0] < this->m_co[1] ? (this->m_co[0] < this->m_co[2] ? 0 : 2) : (this->m_co[1] < this->m_co[2] ? 1 : 2);
+		}
+
+		int maxAxis() const 
+		{
+			return this->m_co[0] < this->m_co[1] ? (this->m_co[1] < this->m_co[2] ? 2 : 1) : (this->m_co[0] < this->m_co[2] ? 2 : 0);
+		}
+
+		int furthestAxis() const
+		{
+			return absolute().minAxis();
+		}
+
+		int closestAxis() const 
+		{
+			return absolute().maxAxis();
+		}
+
+		Vector3 lerp(const Vector3& v, const Scalar& t) const 
+		{
+			return Vector3(this->m_co[0] + (v[0] - this->m_co[0]) * t,
+								   this->m_co[1] + (v[1] - this->m_co[1]) * t,
+								   this->m_co[2] + (v[2] - this->m_co[2]) * t);
+		}
+    
+		static Vector3 random() 
+		{
+			Scalar z = Scalar(2.0) * Scalar_traits::random() - Scalar(1.0);
+			Scalar r = Scalar_traits::sqrt(Scalar(1.0) - z * z);
+			Scalar t = Scalar_traits::TwoTimesPi() * Scalar_traits::random();
+			return Vector3(r * Scalar_traits::cos(t), 
+								   r * Scalar_traits::sin(t), 
+								   z);
+		}
+	};
+
+	template 
+	inline Vector3 
+	operator+(const Vector3& v1, const Vector3& v2) 
+	{
+		return Vector3(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]);
+	}
+
+	template 
+	inline Vector3 
+	operator-(const Vector3& v1, const Vector3& v2)
+	{
+		return Vector3(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]);
+	}
+	
+	template 
+	inline Vector3 
+	operator-(const Vector3& v)
+	{
+		return Vector3(-v[0], -v[1], -v[2]);
+	}
+	
+	template 
+	inline Vector3 
+	operator*(const Vector3& v, const Scalar& s)
+	{
+		return Vector3(v[0] * s, v[1] * s, v[2] * s);
+	}
+	
+	template 
+	inline Vector3 
+	operator*(const Scalar& s, const Vector3& v)
+	{ 
+		return v * s; 
+	}
+	
+	template 
+	inline Vector3
+	operator/(const Vector3& v, const Scalar& s)
+	{
+		assert(s != Scalar(0.0));
+		return v * (Scalar(1.0) / s);
+	}
+	
+	template 
+	inline Scalar 
+	dot(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.dot(v2); 
+	}
+	
+	template 
+	inline Scalar
+	length2(const Vector3& v) 
+	{ 
+		return v.length2(); 
+	}
+
+	template 
+	inline Scalar
+	length(const Vector3& v) 
+	{ 
+		return v.length(); 
+	}
+
+	template 
+	inline Scalar
+	distance2(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.distance2(v2); 
+	}
+
+	template 
+	inline Scalar
+	distance(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.distance(v2); 
+	}
+
+	template 
+	inline Scalar
+	angle(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.angle(v2); 
+	}
+
+	template 
+	inline Vector3 
+	cross(const Vector3& v1, const Vector3& v2) 
+	{ 
+		return v1.cross(v2); 
+	}
+
+	template 
+	inline Scalar
+	triple(const Vector3& v1, const Vector3& v2, const Vector3& v3)
+	{
+		return v1.triple(v2, v3);
+	}
+
+	template 
+	inline Vector3 
+	lerp(const Vector3& v1, const Vector3& v2, const Scalar& t)
+	{
+		return v1.lerp(v2, t);
+	}
+
+}
+
+#endif
diff --git a/extern/solid/include/MT_BBox.h b/extern/solid/include/MT_BBox.h
new file mode 100644
index 00000000000..b5dc537e0d9
--- /dev/null
+++ b/extern/solid/include/MT_BBox.h
@@ -0,0 +1,119 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_BBOX_H
+#define MT_BBOX_H
+
+#include "MT_Scalar.h"
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+
+#include  
+#include "MT_Interval.h" 
+
+
+
+class MT_BBox : public MT::Tuple3 {
+public:
+    MT_BBox() {}
+	MT_BBox(const MT_Point3& p)
+		: MT::Tuple3(MT_Interval(p[0]), 
+				                  MT_Interval(p[1]), 
+				                  MT_Interval(p[2]))
+	{}
+	MT_BBox(const MT_Point3& lb, const MT_Point3& ub)
+		: MT::Tuple3(MT_Interval(lb[0], ub[0]),
+				                  MT_Interval(lb[1], ub[1]),
+				                  MT_Interval(lb[2], ub[2]))
+	{}
+	MT_BBox(const MT_Interval& x, const MT_Interval& y, const MT_Interval& z) 
+		: MT::Tuple3(x, y, z) 
+	{}
+
+	MT_Point3 getMin() const 
+	{ 
+		return MT_Point3(m_co[0].lower(), m_co[1].lower(), m_co[2].lower());
+	}
+
+	MT_Point3 getMax() const 
+	{ 
+		return MT_Point3(m_co[0].upper(), m_co[1].upper(), m_co[2].upper());
+	}
+	
+	MT_Point3 getCenter() const
+	{
+		return MT_Point3(MT::median(m_co[0]), MT::median(m_co[1]), MT::median(m_co[2]));
+	}
+
+	MT_Vector3 getExtent() const
+	{
+		return MT_Vector3(MT::width(m_co[0]) * MT_Scalar(0.5), MT::width(m_co[1]) * MT_Scalar(0.5), MT::width(m_co[2]) * MT_Scalar(0.5));
+	}
+
+	void extend(const MT_Vector3& v) 
+	{
+		m_co[0] = MT::widen(m_co[0], v[0]);
+		m_co[1] = MT::widen(m_co[1], v[1]);
+		m_co[2] = MT::widen(m_co[2], v[2]);
+	}
+
+    bool overlaps(const MT_BBox& b) const 
+	{
+        return MT::overlap(m_co[0], b[0]) &&
+			   MT::overlap(m_co[1], b[1]) &&
+			   MT::overlap(m_co[2], b[2]);
+    }
+
+	bool inside(const MT_BBox& b) const 
+	{
+        return MT::in(m_co[0], b[0]) &&
+			   MT::in(m_co[1], b[1]) &&
+			   MT::in(m_co[2], b[2]);
+    }
+
+	MT_BBox hull(const MT_BBox& b) const 
+	{
+		return MT_BBox(MT::hull(m_co[0], b[0]), 
+					   MT::hull(m_co[1], b[1]), 
+					   MT::hull(m_co[2], b[2])); 
+	}
+
+	bool contains(const MT_Point3& p) const 
+	{
+		return MT::in(p[0], m_co[0]) && MT::in(p[1], m_co[1]) && MT::in(p[2], m_co[2]);
+	}
+};
+
+inline MT_BBox operator+(const MT_BBox& b1, const MT_BBox& b2) 
+{
+	return MT_BBox(b1[0] + b2[0], b1[1] + b2[1], b1[2] + b2[2]);
+}
+
+inline MT_BBox operator-(const MT_BBox& b1, const MT_BBox& b2) 
+{
+	return MT_BBox(b1[0] - b2[0], b1[1] - b2[1], b1[2] - b2[2]);
+}
+
+#endif
+
+
diff --git a/extern/solid/include/MT_Interval.h b/extern/solid/include/MT_Interval.h
new file mode 100644
index 00000000000..25ebfd0a67d
--- /dev/null
+++ b/extern/solid/include/MT_Interval.h
@@ -0,0 +1,33 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_INTERVAL_H
+#define MT_INTERVAL_H
+
+#include 
+
+#include "MT_Scalar.h"
+
+typedef MT::Interval MT_Interval;
+
+#endif
diff --git a/extern/solid/include/MT_Matrix3x3.h b/extern/solid/include/MT_Matrix3x3.h
new file mode 100644
index 00000000000..f7572f90fa2
--- /dev/null
+++ b/extern/solid/include/MT_Matrix3x3.h
@@ -0,0 +1,34 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_MATRIX3X3_H
+#define MT_MATRIX3X3_H
+
+#include "MT_Scalar.h"
+#include 
+
+typedef MT::Matrix3x3 MT_Matrix3x3;
+
+
+
+#endif
diff --git a/extern/solid/include/MT_Point3.h b/extern/solid/include/MT_Point3.h
new file mode 100644
index 00000000000..ca84f652b65
--- /dev/null
+++ b/extern/solid/include/MT_Point3.h
@@ -0,0 +1,31 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_POINT3_H
+#define MT_POINT3_H
+
+#include "MT_Vector3.h"
+
+typedef MT_Vector3 MT_Point3;
+
+#endif
diff --git a/extern/solid/include/MT_Quaternion.h b/extern/solid/include/MT_Quaternion.h
new file mode 100644
index 00000000000..ca860db711c
--- /dev/null
+++ b/extern/solid/include/MT_Quaternion.h
@@ -0,0 +1,35 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_QUATERNION_H
+#define MT_QUATERNION_H
+
+#include "MT_Scalar.h"
+#include 
+
+typedef MT::Quaternion MT_Quaternion;
+
+#endif
+
+
+
diff --git a/extern/solid/include/MT_Scalar.h b/extern/solid/include/MT_Scalar.h
new file mode 100644
index 00000000000..663a1f1839c
--- /dev/null
+++ b/extern/solid/include/MT_Scalar.h
@@ -0,0 +1,158 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_SCALAR_H
+#define MT_SCALAR_H
+
+#if defined (__sun__) || defined ( __sun ) || defined (__sparc) || defined (__sparc__) || defined (__sgi)
+#include 
+#include 
+#else
+#include 
+#include 
+#include 
+#endif
+
+#undef max
+
+#include "SOLID_types.h"
+
+#include "GEN_MinMax.h"
+#include "GEN_random.h"
+
+template 
+struct Scalar_traits {};
+
+template<>
+struct Scalar_traits {
+	static float TwoTimesPi() { return 6.283185307179586232f; }
+	static float epsilon() { return FLT_EPSILON; }
+	static float max() { return FLT_MAX; }
+	
+	static float random() { return float(GEN_rand()) / float(GEN_RAND_MAX); }
+#if defined (__sun) || defined (__sun__) || defined (__sparc) || defined (__APPLE__)
+	static float sqrt(float x) { return ::sqrt(x); } 
+	static float abs(float x) { return ::fabs(x); } 
+
+	static float cos(float x) { return ::cos(x); } 
+	static float sin(float x) { return ::sin(x); } 
+	static float tan(float x) { return ::tan(x); } 
+
+	static float acos(float x) { return ::acos(x); } 
+	static float asin(float x) { return ::asin(x); } 
+	static float atan(float x) { return ::atan(x); } 
+	static float atan2(float x, float y) { return ::atan2(x, y); } 
+
+	static float exp(float x) { return ::exp(x); } 
+	static float log(float x) { return ::log(x); } 
+	static float pow(float x, float y) { return ::pow(x, y); } 
+
+#else
+	static float sqrt(float x) { return ::sqrtf(x); } 
+	static float abs(float x) { return ::fabsf(x); } 
+
+	static float cos(float x) { return ::cosf(x); } 
+	static float sin(float x) { return ::sinf(x); } 
+	static float tan(float x) { return ::tanf(x); } 
+
+	static float acos(float x) { return ::acosf(x); } 
+	static float asin(float x) { return ::asinf(x); } 
+	static float atan(float x) { return ::atanf(x); } 
+	static float atan2(float x, float y) { return ::atan2f(x, y); } 
+
+	static float exp(float x) { return ::expf(x); } 
+	static float log(float x) { return ::logf(x); } 
+	static float pow(float x, float y) { return ::powf(x, y); } 
+#endif
+};
+
+template<>
+struct Scalar_traits {
+	static double TwoTimesPi() { return 6.283185307179586232; }
+	static double epsilon() { return DBL_EPSILON; }
+	static double max() { return DBL_MAX; }
+	
+	static double random() { return double(GEN_rand()) / double(GEN_RAND_MAX); }
+	static double sqrt(double x) { return ::sqrt(x); } 
+	static double abs(double x) { return ::fabs(x); } 
+
+	static double cos(double x) { return ::cos(x); } 
+	static double sin(double x) { return ::sin(x); } 
+	static double tan(double x) { return ::tan(x); } 
+
+	static double acos(double x) { return ::acos(x); } 
+	static double asin(double x) { return ::asin(x); } 
+	static double atan(double x) { return ::atan(x); } 
+	static double atan2(double x, double y) { return ::atan2(x, y); } 
+
+	static double exp(double x) { return ::exp(x); } 
+	static double log(double x) { return ::log(x); } 
+	static double pow(double x, double y) { return ::pow(x, y); } 
+};
+
+#ifdef USE_TRACER
+#include "MT_ScalarTracer.h"
+
+#ifdef USE_DOUBLES
+typedef MT_ScalarTracer   MT_Scalar;
+#else
+typedef MT_ScalarTracer    MT_Scalar;
+#endif
+
+#else
+
+#ifdef USE_DOUBLES
+typedef double   MT_Scalar;
+#else
+typedef float    MT_Scalar;
+#endif
+
+#endif
+
+
+const MT_Scalar  MT_2_PI         = Scalar_traits::TwoTimesPi();
+const MT_Scalar  MT_PI           = MT_2_PI * MT_Scalar(0.5);
+const MT_Scalar  MT_HALF_PI		 = MT_2_PI * MT_Scalar(0.25);
+const MT_Scalar  MT_RADS_PER_DEG = MT_2_PI / MT_Scalar(360.0);
+const MT_Scalar  MT_DEGS_PER_RAD = MT_Scalar(360.0) / MT_2_PI;
+
+const MT_Scalar  MT_EPSILON      = Scalar_traits::epsilon();
+const MT_Scalar  MT_INFINITY     = Scalar_traits::max();
+
+inline MT_Scalar MT_random() { return  Scalar_traits::random(); }
+inline MT_Scalar MT_abs(MT_Scalar x) { return Scalar_traits::abs(x); }
+inline MT_Scalar MT_sqrt(MT_Scalar x) { return Scalar_traits::sqrt(x); }
+
+inline MT_Scalar MT_cos(MT_Scalar x) { return Scalar_traits::cos(x); }
+inline MT_Scalar MT_sin(MT_Scalar x) { return Scalar_traits::sin(x); }
+inline MT_Scalar MT_tan(MT_Scalar x) { return Scalar_traits::tan(x); }
+
+inline MT_Scalar MT_acos(MT_Scalar x) { return Scalar_traits::acos(x); }
+inline MT_Scalar MT_asin(MT_Scalar x) { return Scalar_traits::asin(x); }
+inline MT_Scalar MT_atan(MT_Scalar x) { return Scalar_traits::atan(x); }
+inline MT_Scalar MT_atan2(MT_Scalar x, MT_Scalar y) { return Scalar_traits::atan2(x, y); }
+
+inline MT_Scalar MT_radians(MT_Scalar x) { return x * MT_RADS_PER_DEG; }
+inline MT_Scalar MT_degrees(MT_Scalar x) { return x * MT_DEGS_PER_RAD; }
+
+#endif
diff --git a/extern/solid/include/MT_Transform.h b/extern/solid/include/MT_Transform.h
new file mode 100644
index 00000000000..66f92428054
--- /dev/null
+++ b/extern/solid/include/MT_Transform.h
@@ -0,0 +1,38 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_TRANSFORM_H
+#define MT_TRANSFORM_H
+
+#include "MT_Scalar.h"
+#include 
+
+typedef MT::Matrix3x3 MT_Matrix3x3;
+typedef MT::Transform MT_Transform;
+
+#endif
+
+
+
+
+
diff --git a/extern/solid/include/MT_Vector3.h b/extern/solid/include/MT_Vector3.h
new file mode 100644
index 00000000000..d50e80dc287
--- /dev/null
+++ b/extern/solid/include/MT_Vector3.h
@@ -0,0 +1,50 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef MT_VECTOR3_H
+#define MT_VECTOR3_H
+
+#include "MT_Scalar.h"
+#include 
+
+typedef MT::Vector3 MT_Vector3;
+
+#ifdef CPU_CMP
+
+inline bool operator==(const MT_Vector3& p1, const MT_Vector3& p2) 
+{
+	const unsigned int *i1 = (const unsigned int *)&p1;
+	const unsigned int *i2 = (const unsigned int *)&p2;
+    return i1[0] == i2[0] && i1[1] == i2[1] && i1[2] == i2[2];
+}
+
+#else
+
+inline bool operator==(const MT_Vector3& p1, const MT_Vector3& p2) 
+{
+	return p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2];
+}
+
+#endif
+
+#endif
diff --git a/extern/solid/include/SOLID.h b/extern/solid/include/SOLID.h
new file mode 100644
index 00000000000..96d40f1ea6b
--- /dev/null
+++ b/extern/solid/include/SOLID.h
@@ -0,0 +1,279 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_H
+#define SOLID_H
+
+#include "SOLID_types.h"
+
+#ifdef __cplusplus
+extern "C" { 
+#endif
+    
+	DT_DECLARE_HANDLE(DT_ObjectHandle);
+	DT_DECLARE_HANDLE(DT_SceneHandle);
+	DT_DECLARE_HANDLE(DT_ShapeHandle);
+	DT_DECLARE_HANDLE(DT_VertexBaseHandle);
+	DT_DECLARE_HANDLE(DT_RespTableHandle);
+	DT_DECLARE_HANDLE(DT_ArchiveHandle);
+
+	typedef unsigned int DT_ResponseClass;
+
+	typedef enum DT_ResponseType { 
+		DT_NO_RESPONSE,                  /* No response (obsolete) */
+		DT_BROAD_RESPONSE,               /* Broad phase response is returned. */
+		DT_SIMPLE_RESPONSE,              /* No collision data */
+		DT_WITNESSED_RESPONSE,           /* A point common to both objects
+											is returned as collision data
+										 */
+		DT_DEPTH_RESPONSE                /* The penetration depth is returned
+											as collision data. The penetration depth
+											is the shortest vector over which one 
+											object needs to be translated in order
+											to bring the objects in touching contact. 
+										 */ 
+	} DT_ResponseType;
+    
+/* For witnessed response, the following structure represents a common point. The world 
+   coordinates of 'point1' and 'point2' coincide. 'normal' is the zero vector.
+   
+   For depth response, the following structure represents the penetration depth. 
+   'point1' en 'point2' are the witness points of the penetration depth in world coordinates.
+   The penetration depth vector in world coordinates is represented by 'normal'.
+*/
+
+	typedef struct DT_CollData {
+		DT_Vector3 point1;               /* Point in object1 in world coordinates */ 
+		DT_Vector3 point2;               /* Point in object2 in world coordinates */
+		DT_Vector3 normal;               /* point2 - point1 */ 
+	} DT_CollData;
+
+/* A response callback is called by SOLID for each pair of collding objects. 'client-data'
+   is a pointer to an arbitrary structure in the client application. The client objects are
+   pointers to structures in the client application associated with the coliding objects.
+   'coll_data' is the collision data computed by SOLID.
+*/
+
+	typedef DT_Bool (*DT_ResponseCallback)(void *client_data,
+										   void *client_object1,
+										   void *client_object2,
+										   const DT_CollData *coll_data);
+										
+/* Shape definition */
+
+
+	extern DECLSPEC DT_ShapeHandle DT_NewBox(DT_Scalar x, DT_Scalar y, DT_Scalar z);
+	extern DECLSPEC DT_ShapeHandle DT_NewCone(DT_Scalar radius, DT_Scalar height);
+	extern DECLSPEC DT_ShapeHandle DT_NewCylinder(DT_Scalar radius, DT_Scalar height);
+	extern DECLSPEC DT_ShapeHandle DT_NewSphere(DT_Scalar radius);
+	extern DECLSPEC DT_ShapeHandle DT_NewPoint(const DT_Vector3 point);
+	extern DECLSPEC DT_ShapeHandle DT_NewLineSegment(const DT_Vector3 source, const DT_Vector3 target);
+	extern DECLSPEC DT_ShapeHandle DT_NewMinkowski(DT_ShapeHandle shape1, DT_ShapeHandle shape2);
+	extern DECLSPEC DT_ShapeHandle DT_NewHull(DT_ShapeHandle shape1, DT_ShapeHandle shape2);
+
+	extern DECLSPEC DT_VertexBaseHandle DT_NewVertexBase(const void *pointer, DT_Size stride);
+	extern DECLSPEC void DT_DeleteVertexBase(DT_VertexBaseHandle vertexBase);	
+	extern DECLSPEC void DT_ChangeVertexBase(DT_VertexBaseHandle vertexBase, const void *pointer);
+
+	extern DECLSPEC DT_ShapeHandle DT_NewComplexShape(DT_VertexBaseHandle vertexBase);
+	extern DECLSPEC void           DT_EndComplexShape();
+
+	extern DECLSPEC DT_ShapeHandle DT_NewPolytope(DT_VertexBaseHandle vertexBase);
+	extern DECLSPEC void           DT_EndPolytope();
+
+	extern DECLSPEC void DT_Begin();
+	extern DECLSPEC void DT_End();
+
+	extern DECLSPEC void DT_Vertex(const DT_Vector3 vertex);
+	extern DECLSPEC void DT_VertexIndex(DT_Index index);
+
+	extern DECLSPEC void DT_VertexIndices(DT_Count count, const DT_Index *indices);
+	extern DECLSPEC void DT_VertexRange(DT_Index first, DT_Count count); 
+
+	extern DECLSPEC void DT_DeleteShape(DT_ShapeHandle shape);
+
+/* Object  */
+
+	extern DECLSPEC DT_ObjectHandle DT_CreateObject(
+		void *client_object,      /* pointer to object in client memory */
+		DT_ShapeHandle shape  /* the shape or geometry of the object */
+		);
+
+	extern DECLSPEC void DT_DestroyObject(DT_ObjectHandle object);
+
+
+
+	extern DECLSPEC void DT_SetPosition(DT_ObjectHandle object, const DT_Vector3 position);
+	extern DECLSPEC void DT_SetOrientation(DT_ObjectHandle object, const DT_Quaternion orientation);
+	extern DECLSPEC void DT_SetScaling(DT_ObjectHandle object, const DT_Vector3 scaling);
+
+/* The margin is an offset from the actual shape. The actual geometry of an
+   object is the set of points whose distance to the transformed shape is at 
+   most the  margin. During the lifetime of an object the margin can be 
+   modified. 
+*/
+   
+	extern DECLSPEC void DT_SetMargin(DT_ObjectHandle object, DT_Scalar margin);
+
+
+/* These commands assume a column-major 4x4 OpenGL matrix representation */
+
+	extern DECLSPEC void DT_SetMatrixf(DT_ObjectHandle object, const float *m); 
+	extern DECLSPEC void DT_GetMatrixf(DT_ObjectHandle object, float *m); 
+
+	extern DECLSPEC void DT_SetMatrixd(DT_ObjectHandle object, const double *m); 
+	extern DECLSPEC void DT_GetMatrixd(DT_ObjectHandle object, double *m); 
+
+	extern DECLSPEC void DT_GetBBox(DT_ObjectHandle object, DT_Vector3 min, DT_Vector3 max);
+
+	
+	extern DECLSPEC DT_Bool  DT_GetIntersect(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 v);
+/* This next command returns the distance between the objects. De returned
+   closest points are given in world coordinates.
+*/
+	extern DECLSPEC DT_Scalar DT_GetClosestPair(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 point1, DT_Vector3 point2);  
+
+	extern DECLSPEC DT_Bool   DT_GetCommonPoint(DT_ObjectHandle object1, DT_ObjectHandle object2,
+												DT_Vector3 point);
+
+	extern DECLSPEC DT_Bool   DT_GetPenDepth(DT_ObjectHandle object1, DT_ObjectHandle object2,
+											 DT_Vector3 point1, DT_Vector3 point2);  
+
+/* Scene */
+
+	extern DECLSPEC DT_SceneHandle DT_CreateScene(); 
+	extern DECLSPEC void           DT_DestroyScene(DT_SceneHandle scene);
+
+	extern DECLSPEC void DT_AddObject(DT_SceneHandle scene, DT_ObjectHandle object);
+	extern DECLSPEC void DT_RemoveObject(DT_SceneHandle scene, DT_ObjectHandle object);
+
+/* Note that objects can be assigned to multiple scenes! */
+
+/* Response */
+
+/* Response tables are defined independent of the scenes in which they are used.
+   Multiple response tables can be used in one scene, and a response table
+   can be shared among scenes.
+*/
+	extern DECLSPEC DT_RespTableHandle DT_CreateRespTable(); 
+	extern DECLSPEC void               DT_DestroyRespTable(DT_RespTableHandle respTable); 
+
+/* Responses are defined on (pairs of) response classes. Each response table 
+   maintains its set of response classes.
+*/
+	extern DECLSPEC DT_ResponseClass DT_GenResponseClass(DT_RespTableHandle respTable);
+
+/* To each object for which a response is defined in the response table a
+   response class needs to be assigned. 
+*/
+
+	extern DECLSPEC void DT_SetResponseClass(DT_RespTableHandle respTable,
+											 DT_ObjectHandle object,
+											 DT_ResponseClass responseClass);
+
+	extern DECLSPEC void DT_ClearResponseClass(DT_RespTableHandle respTable, 
+											   DT_ObjectHandle object);
+
+	extern DECLSPEC void DT_CallResponse(DT_RespTableHandle respTable,
+										 DT_ObjectHandle object1,
+										 DT_ObjectHandle object2,
+										 const DT_CollData *coll_data);
+
+/* For each pair of objects multiple responses can be defined. A response is a callback
+   together with its response type and client data. */
+    
+/* Responses can be defined for all pairs of response classes... */
+	extern DECLSPEC void DT_AddDefaultResponse(DT_RespTableHandle respTable,
+											   DT_ResponseCallback response, 
+											   DT_ResponseType type, void *client_data);
+
+	extern DECLSPEC void DT_RemoveDefaultResponse(DT_RespTableHandle respTable,
+												  DT_ResponseCallback response);
+/* ...per response class... */
+	extern DECLSPEC void DT_AddClassResponse(DT_RespTableHandle respTable,
+											 DT_ResponseClass responseClass,
+											 DT_ResponseCallback response,
+											 DT_ResponseType type, void *client_data);
+
+	extern DECLSPEC void DT_RemoveClassResponse(DT_RespTableHandle respTable,
+												DT_ResponseClass responseClass,
+												DT_ResponseCallback response);
+
+/* ... and per pair of response classes...*/
+	extern DECLSPEC void DT_AddPairResponse(DT_RespTableHandle respTable,
+											DT_ResponseClass responseClass1,
+											DT_ResponseClass responseClass2, 
+											DT_ResponseCallback response,
+											DT_ResponseType type, void *client_data);
+	extern DECLSPEC void DT_RemovePairResponse(DT_RespTableHandle respTable,
+											   DT_ResponseClass responseClass1,
+											   DT_ResponseClass responseClass2,
+											   DT_ResponseCallback response);
+
+/* The next command calls the response callbacks for all intersecting pairs of objects in a scene. 
+   'DT_Test' returns the number of pairs of objects for which callbacks have been called. 
+*/
+ 
+	extern DECLSPEC DT_Count DT_Test(DT_SceneHandle scene, DT_RespTableHandle respTable);
+
+/* Set the maximum relative error in the closest points and penetration depth
+   computation. The default for `max_error' is 1.0e-3. Larger errors result
+   in better performance. Non-positive error tolerances are ignored.
+*/ 
+
+	extern DECLSPEC void DT_SetAccuracy(DT_Scalar max_error);
+
+/* Set the maximum tolerance on relative errors due to rounding.  The default for `tol_error' 
+   is the machine epsilon. Very large tolerances result in false collisions. Setting tol_error too small 
+   results in missed collisions. Non-positive error tolerances are ignored. 
+*/ 
+    
+	extern DECLSPEC void DT_SetTolerance(DT_Scalar tol_error);
+
+
+/* This function returns the client pointer to the first object in a scene hit by the ray 
+   (actually a line segment) defined by the points 'from' en 'to'. The spot is the hit point 
+   on the object in local coordinates. 'normal' is the normal to the surface of the object in
+   world coordinates. The ignore_client pointer is used to make one of the objects transparent.
+
+   NB: Currently ray tests are implemented for spheres, boxes, and meshes only!!
+*/   
+
+	extern DECLSPEC void *DT_RayCast(DT_SceneHandle scene, void *ignore_client,
+									 const DT_Vector3 source, const DT_Vector3 target,
+									 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal);
+
+/* Similar, only here a single object is tested and a boolean is returned */
+
+	extern DECLSPEC DT_Bool DT_ObjectRayCast(DT_ObjectHandle object,
+											 const DT_Vector3 source, const DT_Vector3 target,
+											 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/solid/include/SOLID_broad.h b/extern/solid/include/SOLID_broad.h
new file mode 100644
index 00000000000..74e4214fa67
--- /dev/null
+++ b/extern/solid/include/SOLID_broad.h
@@ -0,0 +1,75 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_BROAD_H
+#define SOLID_BROAD_H
+
+#include "SOLID_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+	DT_DECLARE_HANDLE(BP_SceneHandle);
+	DT_DECLARE_HANDLE(BP_ProxyHandle);
+	
+	typedef void (*BP_Callback)(void *client_data,
+								void *object1,
+								void *object2);
+
+	typedef bool (*BP_RayCastCallback)(void *client_data,
+									   void *object,
+									   const DT_Vector3 source,
+									   const DT_Vector3 target,
+									   DT_Scalar *lambda);
+	
+	extern DECLSPEC BP_SceneHandle BP_CreateScene(void *client_data,
+												  BP_Callback beginOverlap,
+												  BP_Callback endOverlap);
+	
+	extern DECLSPEC void           BP_DestroyScene(BP_SceneHandle scene);
+	
+	extern DECLSPEC BP_ProxyHandle BP_CreateProxy(BP_SceneHandle scene, 
+												  void *object,
+												  const DT_Vector3 min, 
+												  const DT_Vector3 max);
+	
+	extern DECLSPEC void           BP_DestroyProxy(BP_SceneHandle scene, 
+												  BP_ProxyHandle proxy);
+	
+	extern DECLSPEC void BP_SetBBox(BP_ProxyHandle proxy, 
+									const DT_Vector3 min, 
+									const DT_Vector3 max);
+	
+	extern DECLSPEC void *BP_RayCast(BP_SceneHandle scene, 
+									 BP_RayCastCallback objectRayCast, 
+									 void *client_data,
+									 const DT_Vector3 source,
+									 const DT_Vector3 target,
+									 DT_Scalar *lambda);		
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/solid/include/SOLID_types.h b/extern/solid/include/SOLID_types.h
new file mode 100644
index 00000000000..630594e447f
--- /dev/null
+++ b/extern/solid/include/SOLID_types.h
@@ -0,0 +1,53 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef SOLID_TYPES_H
+#define SOLID_TYPES_H
+
+#ifndef DECLSPEC
+# ifdef WIN32
+#  define DECLSPEC __declspec(dllexport)
+# else
+#  define DECLSPEC
+# endif
+#endif
+
+#define DT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
+    
+
+typedef unsigned short DT_Index;
+typedef unsigned short DT_Count;
+typedef unsigned int   DT_Size;
+typedef float          DT_Scalar; 
+typedef int            DT_Bool;
+
+#define DT_FALSE 0
+#define DT_TRUE  1
+
+#define DT_CONTINUE 0
+#define DT_DONE 1
+
+typedef DT_Scalar DT_Vector3[3]; 
+typedef DT_Scalar DT_Quaternion[4]; 
+
+#endif
diff --git a/extern/solid/make/msvc_7_0/broad/broad.vcproj b/extern/solid/make/msvc_7_0/broad/broad.vcproj
new file mode 100644
index 00000000000..adb56424e60
--- /dev/null
+++ b/extern/solid/make/msvc_7_0/broad/broad.vcproj
@@ -0,0 +1,262 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/solid/make/msvc_7_0/complex/complex.vcproj b/extern/solid/make/msvc_7_0/complex/complex.vcproj
new file mode 100644
index 00000000000..2a895fa28d3
--- /dev/null
+++ b/extern/solid/make/msvc_7_0/complex/complex.vcproj
@@ -0,0 +1,252 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/solid/make/msvc_7_0/convex/convex.vcproj b/extern/solid/make/msvc_7_0/convex/convex.vcproj
new file mode 100644
index 00000000000..da088b5972f
--- /dev/null
+++ b/extern/solid/make/msvc_7_0/convex/convex.vcproj
@@ -0,0 +1,337 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/solid/make/msvc_7_0/solid.vcproj b/extern/solid/make/msvc_7_0/solid.vcproj
new file mode 100644
index 00000000000..d9e6332987c
--- /dev/null
+++ b/extern/solid/make/msvc_7_0/solid.vcproj
@@ -0,0 +1,462 @@
+
+
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+				
+					
+				
+				
+					
+				
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+
diff --git a/extern/solid/src/DT_AlgoTable.h b/extern/solid/src/DT_AlgoTable.h
new file mode 100644
index 00000000000..0749ca7fdd9
--- /dev/null
+++ b/extern/solid/src/DT_AlgoTable.h
@@ -0,0 +1,47 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_ALGOTABLE_H
+#define DT_ALGOTABLE_H
+
+#include "DT_Shape.h"
+
+template 
+class AlgoTable {
+public:
+  void addEntry(DT_ShapeType type1, DT_ShapeType type2, Function function) 
+  { 
+    table[type2][type1] = function;
+    table[type1][type2] = function;
+  }
+
+  Function lookup(DT_ShapeType type1, DT_ShapeType type2) const 
+  {
+    return table[type1][type2];
+  }
+
+private:
+  Function table[NUM_TYPES][NUM_TYPES];
+};
+
+#endif
diff --git a/extern/solid/src/DT_C-api.cpp b/extern/solid/src/DT_C-api.cpp
new file mode 100644
index 00000000000..ac16deda87d
--- /dev/null
+++ b/extern/solid/src/DT_C-api.cpp
@@ -0,0 +1,581 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+
+#include "SOLID.h"
+
+#include "DT_Box.h"
+#include "DT_Cone.h"
+#include "DT_Cylinder.h"
+#include "DT_Sphere.h"
+#include "DT_Complex.h"
+#include "DT_Polytope.h"
+#include "DT_Polyhedron.h"
+#include "DT_Point.h"
+#include "DT_LineSegment.h"
+#include "DT_Triangle.h"
+#include "DT_Minkowski.h"
+#include "DT_Hull.h"
+
+#include "DT_Response.h"
+#include "DT_RespTable.h"
+
+#include "DT_Scene.h"
+#include "DT_Object.h"
+
+#include "DT_VertexBase.h"
+
+#include "DT_Accuracy.h"
+
+typedef MT::Tuple3 T_Vertex;
+typedef std::vector T_VertexBuf;
+typedef std::vector T_IndexBuf;
+typedef std::vector T_PolyList;
+
+static T_VertexBuf vertexBuf;
+static T_IndexBuf indexBuf;
+static T_PolyList polyList; 
+
+static DT_Complex       *currentComplex    = 0;
+static DT_Polyhedron    *currentPolyhedron = 0;
+static DT_VertexBase    *currentBase = 0;
+
+
+
+
+
+		
+DT_VertexBaseHandle DT_NewVertexBase(const void *pointer, DT_Size stride) 
+{
+    return (DT_VertexBaseHandle)new DT_VertexBase(pointer, stride);
+}
+
+void DT_DeleteVertexBase(DT_VertexBaseHandle vertexBase) 
+{ 
+    delete (DT_VertexBase *)vertexBase; 
+}
+
+void DT_ChangeVertexBase(DT_VertexBaseHandle vertexBase, const void *pointer) 
+{ 
+	DT_VertexBase *base = (DT_VertexBase *)vertexBase;
+	base->setPointer(pointer);
+	const DT_ComplexList& complexList = base->getComplexList();
+	DT_ComplexList::const_iterator it;
+	for (it = complexList.begin(); it != complexList.end(); ++it)
+	{
+		(*it)->refit();
+	}
+}
+
+
+DT_ShapeHandle DT_NewBox(DT_Scalar x, DT_Scalar y, DT_Scalar z) 
+{
+    return (DT_ShapeHandle)new DT_Box(MT_Scalar(x) * MT_Scalar(0.5), 
+									  MT_Scalar(y) * MT_Scalar(0.5), 
+									  MT_Scalar(z) * MT_Scalar(0.5));
+}
+
+DT_ShapeHandle DT_NewCone(DT_Scalar radius, DT_Scalar height)
+{
+    return (DT_ShapeHandle)new DT_Cone(MT_Scalar(radius), MT_Scalar(height));
+}
+
+DT_ShapeHandle DT_NewCylinder(DT_Scalar radius, DT_Scalar height) 
+{
+    return (DT_ShapeHandle)new DT_Cylinder(MT_Scalar(radius), MT_Scalar(height));
+}
+
+DT_ShapeHandle DT_NewSphere(DT_Scalar radius) 
+{
+    return (DT_ShapeHandle)new DT_Sphere(MT_Scalar(radius));
+}
+
+DT_ShapeHandle DT_NewPoint(const DT_Vector3 point) 
+{
+	return (DT_ShapeHandle)new DT_Point(MT_Point3(point));
+}
+
+DT_ShapeHandle DT_NewLineSegment(const DT_Vector3 source, const DT_Vector3 target) 
+{
+	return (DT_ShapeHandle)new DT_LineSegment(MT_Point3(source), MT_Point3(target));
+}
+
+DT_ShapeHandle DT_NewMinkowski(DT_ShapeHandle shape1, DT_ShapeHandle shape2) 
+{
+	if (((DT_Shape *)shape1)->getType() != CONVEX ||
+		((DT_Shape *)shape2)->getType() != CONVEX) 
+	{
+		return 0;
+	}
+
+	return (DT_ShapeHandle)new DT_Minkowski(*(DT_Convex *)shape1, *(DT_Convex *)shape2);
+}
+	
+DT_ShapeHandle DT_NewHull(DT_ShapeHandle shape1, DT_ShapeHandle shape2)
+{
+	if (((DT_Shape *)shape1)->getType() != CONVEX ||
+		((DT_Shape *)shape2)->getType() != CONVEX) 
+	{
+		return 0;
+	}
+
+	return (DT_ShapeHandle)new DT_Hull(*(DT_Convex *)shape1, *(DT_Convex *)shape2);
+}
+
+DT_ShapeHandle DT_NewComplexShape(const DT_VertexBaseHandle vertexBase) 
+{
+    if (!currentComplex) 
+	{
+		currentBase = vertexBase ? (DT_VertexBase *)vertexBase : new DT_VertexBase;
+		currentComplex = new DT_Complex(currentBase);
+	}
+    return (DT_ShapeHandle)currentComplex;
+}
+
+void DT_EndComplexShape() 
+{
+    if (currentComplex) 
+	{
+        if (currentBase->getPointer() == 0) 
+		{
+            T_Vertex *vertexArray = new T_Vertex[vertexBuf.size()];   
+			assert(vertexArray);	
+            std::copy(vertexBuf.begin(), vertexBuf.end(), &vertexArray[0]);
+            currentBase->setPointer(vertexArray, true);		
+        }
+		
+		vertexBuf.clear();
+        
+        currentComplex->finish(polyList.size(), &polyList[0]);
+        polyList.clear();
+        currentComplex = 0;
+        currentBase = 0; 
+    }
+}
+
+DT_ShapeHandle DT_NewPolytope(const DT_VertexBaseHandle vertexBase) 
+{
+    if (!currentPolyhedron) 
+	{
+		currentBase = vertexBase ? (DT_VertexBase *)vertexBase : new DT_VertexBase;
+        currentPolyhedron = new DT_Polyhedron;
+		
+    }
+    return (DT_ShapeHandle)currentPolyhedron;
+}
+
+void DT_EndPolytope() 
+{
+    if (currentPolyhedron) 
+	{
+        if (currentBase->getPointer() == 0) 
+		{
+			currentBase->setPointer(&vertexBuf[0]);		
+			new (currentPolyhedron) DT_Polyhedron(currentBase, indexBuf.size(), &indexBuf[0]);
+			
+			delete currentBase;
+		}
+		else
+		{
+			new (currentPolyhedron) DT_Polyhedron(currentBase, indexBuf.size(), &indexBuf[0]);
+		}
+		vertexBuf.clear();
+        indexBuf.clear();
+        currentPolyhedron = 0;
+        currentBase = 0;
+    }
+}
+
+void DT_Begin() 
+{}
+
+void DT_End() 
+{ 
+	if (currentComplex) 
+	{
+		DT_VertexIndices(indexBuf.size(), &indexBuf[0]);
+		indexBuf.clear();
+	}
+}
+
+void DT_Vertex(const DT_Vector3 vertex)
+{
+    MT::Vector3 p(vertex);
+    int i = GEN_max((int)vertexBuf.size() - 20, 0);
+	int n = static_cast(vertexBuf.size());
+	
+    while (i != n  && !(vertexBuf[i] == p)) 
+	{
+		++i;
+	}
+
+    if (i == n) 
+	{
+		vertexBuf.push_back(p);
+	}
+    indexBuf.push_back(i);
+}
+
+
+void DT_VertexIndex(DT_Index index) { indexBuf.push_back(index); }
+
+void DT_VertexIndices(DT_Count count, const DT_Index *indices) 
+{
+    if (currentComplex) 
+	{
+		DT_Convex *poly = count == 3 ? 
+			              static_cast(new DT_Triangle(currentBase, indices[0], indices[1], indices[2])) :
+						  static_cast(new DT_Polytope(currentBase, count, indices));  
+		polyList.push_back(poly);
+      
+    }
+
+    if (currentPolyhedron) 
+	{
+		int i;
+		for (i = 0; i < count; ++i) 
+		{
+            indexBuf.push_back(indices[i]);
+        }
+    }   
+}
+
+void DT_VertexRange(DT_Index first, DT_Count count) 
+{
+    DT_Index *indices = new DT_Index[count];
+    
+	DT_Index i;
+    for (i = 0; i != count; ++i) 
+	{
+        indices[i] = first + i;
+    }
+    DT_VertexIndices(count, indices);
+
+    delete [] indices;	
+}
+
+void DT_DeleteShape(DT_ShapeHandle shape) 
+{ 
+    delete (DT_Shape *)shape; 
+}
+
+
+
+
+// Scene
+
+
+DT_SceneHandle DT_CreateScene() 
+{
+    return (DT_SceneHandle)new DT_Scene; 
+}
+
+void DT_DestroyScene(DT_SceneHandle scene) 
+{
+    delete (DT_Scene *)scene;
+}
+
+void DT_AddObject(DT_SceneHandle scene, DT_ObjectHandle object) 
+{
+    assert(scene);
+    assert(object);
+    ((DT_Scene *)scene)->addObject(*(DT_Object *)object);
+}
+
+void DT_RemoveObject(DT_SceneHandle scene, DT_ObjectHandle object) 
+{
+    assert(scene);
+    assert(object);
+    ((DT_Scene *)scene)->removeObject(*(DT_Object *)object);
+}
+
+
+// Object instantiation
+
+
+DT_ObjectHandle DT_CreateObject(void *client_object,
+                                DT_ShapeHandle shape)
+{
+	return (DT_ObjectHandle)new DT_Object(client_object, *(DT_Shape *)shape);
+}
+
+void DT_DestroyObject(DT_ObjectHandle object) 
+{
+    delete (DT_Object *)object;
+}
+
+void DT_SetMargin(DT_ObjectHandle object, DT_Scalar margin) 
+{
+    ((DT_Object *)object)->setMargin(MT_Scalar(margin));
+}
+
+
+void DT_SetScaling(DT_ObjectHandle object, const DT_Vector3 scaling) 
+{
+    ((DT_Object *)object)->setScaling(MT_Vector3(scaling));
+}
+
+void DT_SetPosition(DT_ObjectHandle object, const DT_Vector3 position) 
+{
+    ((DT_Object *)object)->setPosition(MT_Point3(position));
+}
+
+void DT_SetOrientation(DT_ObjectHandle object, const DT_Quaternion orientation) 
+{
+    ((DT_Object *)object)->setOrientation(MT_Quaternion(orientation));   
+}
+
+
+void DT_SetMatrixf(DT_ObjectHandle object, const float *m) 
+{
+    ((DT_Object *)object)->setMatrix(m);
+}
+
+void DT_GetMatrixf(DT_ObjectHandle object, float *m) 
+{
+    ((DT_Object *)object)->getMatrix(m);
+}
+
+void DT_SetMatrixd(DT_ObjectHandle object, const double *m) 
+{
+    ((DT_Object *)object)->setMatrix(m);
+}
+void DT_GetMatrixd(DT_ObjectHandle object, double *m) 
+{
+    ((DT_Object *)object)->getMatrix(m);
+}
+
+void DT_GetBBox(DT_ObjectHandle object, DT_Vector3 min, DT_Vector3 max) 
+{
+	const MT_BBox& bbox = ((DT_Object *)object)->getBBox();
+	bbox.getMin().getValue(min);
+	bbox.getMax().getValue(max);
+}
+
+DT_Bool DT_GetIntersect(DT_ObjectHandle object1, DT_ObjectHandle object2, DT_Vector3 vec)
+{
+	MT_Vector3 v;
+	DT_Bool result = intersect(*(DT_Object*)object1, *(DT_Object*)object2, v);
+	v.getValue(vec);
+	return result;
+}
+
+DT_Scalar DT_GetClosestPair(DT_ObjectHandle object1, DT_ObjectHandle object2,
+							DT_Vector3 point1, DT_Vector3 point2) 
+{
+    MT_Point3 p1, p2;
+    
+    MT_Scalar result = closest_points(*(DT_Object *)object1, 
+									  *(DT_Object *)object2,
+									  p1, p2);
+	p1.getValue(point1);
+	p2.getValue(point2);
+
+    return MT_sqrt(result);
+}
+
+DT_Bool DT_GetCommonPoint(DT_ObjectHandle object1, DT_ObjectHandle object2,
+						  DT_Vector3 point) 
+{
+    MT_Point3   p1, p2;
+	MT_Vector3  v(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)); 
+    
+    bool result = common_point(*(DT_Object *)object1, *(DT_Object *)object2, v, p1, p2);
+
+	if (result) 
+	{
+		p1.getValue(point);
+	}
+
+    return result;
+}
+
+DT_Bool DT_GetPenDepth(DT_ObjectHandle object1, DT_ObjectHandle object2,
+				    DT_Vector3 point1, DT_Vector3 point2) 
+{
+    MT_Point3   p1, p2;
+	MT_Vector3  v(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)); 
+    
+    bool result = penetration_depth(*(DT_Object *)object1, *(DT_Object *)object2, v, p1, p2);
+
+	if (result) 
+	{
+		p1.getValue(point1);
+		p2.getValue(point2);
+	}
+
+    return result;
+}
+
+// Response
+
+DT_RespTableHandle DT_CreateRespTable() 
+{
+    return (DT_RespTableHandle)new DT_RespTable;
+}    
+
+void DT_DestroyRespTable(DT_RespTableHandle respTable) 
+{
+    delete (DT_RespTable *)respTable;
+}
+
+DT_ResponseClass DT_GenResponseClass(DT_RespTableHandle respTable) 
+{
+	return ((DT_RespTable *)respTable)->genResponseClass();
+}
+
+void DT_SetResponseClass(DT_RespTableHandle respTable, DT_ObjectHandle object,
+						 DT_ResponseClass responseClass)
+{
+	((DT_RespTable *)respTable)->setResponseClass(object, responseClass);
+}
+
+void DT_ClearResponseClass(DT_RespTableHandle respTable, 
+						   DT_ObjectHandle object)
+{
+	((DT_RespTable *)respTable)->clearResponseClass(object);
+}
+
+void DT_CallResponse(DT_RespTableHandle respTable,
+					 DT_ObjectHandle object1,
+					 DT_ObjectHandle object2,
+					 const DT_CollData *coll_data)
+{
+	const DT_ResponseList& responseList =
+		((DT_RespTable *)respTable)->find(object1, object2);
+	
+	if (responseList.getType() != DT_NO_RESPONSE) 
+	{
+		responseList(((DT_Object *)object1)->getClientObject(), 
+					 ((DT_Object *)object2)->getClientObject(),
+					 coll_data);
+	}
+}
+
+
+void DT_AddDefaultResponse(DT_RespTableHandle respTable,
+                           DT_ResponseCallback response, 
+						   DT_ResponseType type, void *client_data)
+{
+    ((DT_RespTable *)respTable)->addDefault(DT_Response(response, type, client_data));
+}
+
+void DT_RemoveDefaultResponse(DT_RespTableHandle respTable,
+							  DT_ResponseCallback response)
+{
+      ((DT_RespTable *)respTable)->removeDefault(DT_Response(response));
+}
+
+void DT_AddClassResponse(DT_RespTableHandle respTable,
+						 DT_ResponseClass responseClass, 
+						 DT_ResponseCallback response, 
+						 DT_ResponseType type, void *client_data)
+{
+    ((DT_RespTable *)respTable)->addSingle(responseClass, 
+										   DT_Response(response, type, client_data));
+}
+
+void DT_RemoveClassResponse(DT_RespTableHandle respTable,
+							DT_ResponseClass responseClass, 
+							DT_ResponseCallback response) 
+{
+    ((DT_RespTable *)respTable)->removeSingle(responseClass, 
+											  DT_Response(response));
+}
+
+void DT_AddPairResponse(DT_RespTableHandle respTable,
+                        DT_ResponseClass responseClass1, 
+						DT_ResponseClass responseClass2, 
+                        DT_ResponseCallback response,
+						DT_ResponseType type, void *client_data)
+{
+    ((DT_RespTable *)respTable)->addPair(responseClass1, responseClass2, 
+										 DT_Response(response, type, client_data));
+}
+
+void DT_RemovePairResponse(DT_RespTableHandle respTable,
+						   DT_ResponseClass responseClass1, 
+						   DT_ResponseClass responseClass2, 
+						   DT_ResponseCallback response)
+{
+    ((DT_RespTable *)respTable)->removePair(responseClass1, responseClass2, 
+											DT_Response(response));
+}
+
+
+// Runtime
+
+void DT_SetAccuracy(DT_Scalar max_error) 
+{ 
+	if (max_error > MT_Scalar(0.0)) 
+	{
+		DT_Accuracy::setAccuracy(MT_Scalar(max_error)); 
+	}
+}
+
+void DT_SetTolerance(DT_Scalar tol_error) 
+{ 
+	if (tol_error > MT_Scalar(0.0)) 
+	{
+		DT_Accuracy::setTolerance(MT_Scalar(tol_error)); 
+	}
+}
+
+DT_Count DT_Test(DT_SceneHandle scene, DT_RespTableHandle respTable) 
+{ 
+    return ((DT_Scene *)scene)->handleCollisions((DT_RespTable *)respTable);
+}
+
+void *DT_RayCast(DT_SceneHandle scene, void *ignore_client,
+				 const DT_Vector3 source, const DT_Vector3 target,
+				 DT_Scalar max_param, DT_Scalar *param, DT_Vector3 normal) 
+{
+	DT_Scalar  lambda = max_param;
+
+	void *client_object = ((DT_Scene *)scene)->rayCast(ignore_client, source, target, 
+													   lambda, normal);
+   if (client_object)
+   {
+      *param = lambda;
+   }
+	return client_object;
+}
+
+DT_Bool DT_ObjectRayCast(DT_ObjectHandle object,
+	   				     const DT_Vector3 source, const DT_Vector3 target,
+					     DT_Scalar max_param, DT_Scalar *param, DT_Vector3 hit_normal) 
+{
+	MT_Scalar lambda = MT_Scalar(max_param);
+	MT_Vector3 normal;  
+
+	bool result = ((DT_Object *)object)->ray_cast(MT_Point3(source), MT_Point3(target), 
+												  lambda, normal);
+
+	if (result) 
+	{
+		*param = lambda;
+		normal.getValue(hit_normal);
+	}
+	return result;
+}
+
diff --git a/extern/solid/src/DT_Encounter.cpp b/extern/solid/src/DT_Encounter.cpp
new file mode 100644
index 00000000000..36de33154a3
--- /dev/null
+++ b/extern/solid/src/DT_Encounter.cpp
@@ -0,0 +1,111 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_RespTable.h"
+#include "DT_Encounter.h"
+#include "DT_Object.h"
+#include "GEN_MinMax.h"
+
+DT_Bool DT_Encounter::exactTest(const DT_RespTable *respTable, int& count) const 
+{
+	const DT_ResponseList& responseList = respTable->find(m_obj_ptr1, m_obj_ptr2);
+
+   switch (responseList.getType()) 
+   {
+   case DT_BROAD_RESPONSE:
+	   return (respTable->getResponseClass(m_obj_ptr1) < respTable->getResponseClass(m_obj_ptr2)) ?
+			   responseList(m_obj_ptr1->getClientObject(), m_obj_ptr2->getClientObject(), 0) :   
+			   responseList(m_obj_ptr2->getClientObject(), m_obj_ptr1->getClientObject(), 0);    
+   case DT_SIMPLE_RESPONSE: 
+	   if (intersect(*m_obj_ptr1, *m_obj_ptr2, m_sep_axis)) 
+	   {
+		   ++count;
+		   return (respTable->getResponseClass(m_obj_ptr1) < respTable->getResponseClass(m_obj_ptr2)) ?
+			   responseList(m_obj_ptr1->getClientObject(), m_obj_ptr2->getClientObject(), 0) :   
+			   responseList(m_obj_ptr2->getClientObject(), m_obj_ptr1->getClientObject(), 0);    
+ 
+	   }
+	   break;
+   case DT_WITNESSED_RESPONSE: {
+	   MT_Point3  p1, p2;
+	   
+	   if (common_point(*m_obj_ptr1, *m_obj_ptr2, m_sep_axis, p1, p2)) 
+	   { 
+		   ++count;
+           if (respTable->getResponseClass(m_obj_ptr1) < respTable->getResponseClass(m_obj_ptr2))
+           {
+			   DT_CollData coll_data;
+			   
+			   p1.getValue(coll_data.point1);
+			   p2.getValue(coll_data.point2);
+			   
+               return responseList(m_obj_ptr1->getClientObject(), m_obj_ptr2->getClientObject(), &coll_data);
+           }
+           else
+           {
+			   DT_CollData coll_data;
+			   
+			   p1.getValue(coll_data.point2);
+			   p2.getValue(coll_data.point1);
+			   
+               return responseList(m_obj_ptr2->getClientObject(), m_obj_ptr1->getClientObject(), &coll_data);
+           }
+	   }
+	   break;
+   }
+   case DT_DEPTH_RESPONSE: {
+	   MT_Point3  p1, p2;
+	   
+	   if (penetration_depth(*m_obj_ptr1, *m_obj_ptr2, m_sep_axis, p1, p2)) 
+	   { 
+		   ++count;
+           if (respTable->getResponseClass(m_obj_ptr1) < respTable->getResponseClass(m_obj_ptr2))
+           {
+			   DT_CollData coll_data;
+			   
+			   p1.getValue(coll_data.point1);
+			   p2.getValue(coll_data.point2);	
+               (p2 - p1).getValue(coll_data.normal);
+			   
+               return responseList(m_obj_ptr1->getClientObject(), m_obj_ptr2->getClientObject(), &coll_data);
+           }
+           else
+           {
+			   DT_CollData coll_data;
+			   
+			   p1.getValue(coll_data.point2);
+			   p2.getValue(coll_data.point1); 
+               (p1 - p2).getValue(coll_data.normal);
+			   
+               return responseList(m_obj_ptr2->getClientObject(), m_obj_ptr1->getClientObject(), &coll_data);
+           }
+	   }
+	   break;
+   }
+   case DT_NO_RESPONSE:
+	   break;
+   default:
+	   assert(false);
+   }
+   return DT_CONTINUE;
+}
diff --git a/extern/solid/src/DT_Encounter.h b/extern/solid/src/DT_Encounter.h
new file mode 100644
index 00000000000..f20ea3936b0
--- /dev/null
+++ b/extern/solid/src/DT_Encounter.h
@@ -0,0 +1,84 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_ENCOUNTER_H
+#define DT_ENCOUNTER_H
+
+#include 
+
+#include "MT_Vector3.h"
+#include "DT_Object.h"
+#include "DT_Shape.h"
+
+class DT_RespTable;
+
+class DT_Encounter {
+public:
+    DT_Encounter() {}
+    DT_Encounter(DT_Object *obj_ptr1, DT_Object *obj_ptr2) 
+        : m_sep_axis(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)) 
+    {
+		assert(obj_ptr1 != obj_ptr2);
+        if (obj_ptr2->getType() < obj_ptr1->getType() || 
+            (obj_ptr2->getType() == obj_ptr1->getType() &&
+             obj_ptr2 < obj_ptr1))
+        { 
+            m_obj_ptr1 = obj_ptr2; 
+            m_obj_ptr2 = obj_ptr1; 
+        }
+        else 
+        { 
+            m_obj_ptr1 = obj_ptr1; 
+            m_obj_ptr2 = obj_ptr2; 
+        }
+    }
+
+    DT_Object         *first()          const { return m_obj_ptr1; }
+    DT_Object         *second()         const { return m_obj_ptr2; }
+    const MT_Vector3&  separatingAxis() const { return m_sep_axis; }
+
+ 	DT_Bool exactTest(const DT_RespTable *respTable, int& count) const;
+
+private:
+    DT_Object          *m_obj_ptr1;
+    DT_Object          *m_obj_ptr2;
+    mutable MT_Vector3  m_sep_axis;
+};
+
+inline bool operator<(const DT_Encounter& a, const DT_Encounter& b) 
+{ 
+    return a.first() < b.first() || 
+        (a.first() == b.first() && a.second() < b.second()); 
+}
+
+
+
+inline std::ostream& operator<<(std::ostream& os, const DT_Encounter& a) {
+    return os << '(' << a.first() << ", " << a.second() << ')';
+}
+
+
+
+typedef std::set DT_EncounterTable;
+
+#endif
diff --git a/extern/solid/src/DT_Object.cpp b/extern/solid/src/DT_Object.cpp
new file mode 100644
index 00000000000..ed43a7bdaf2
--- /dev/null
+++ b/extern/solid/src/DT_Object.cpp
@@ -0,0 +1,276 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Object.h"
+#include "DT_AlgoTable.h"
+#include "DT_Convex.h" 
+#include "DT_Complex.h" 
+#include "DT_LineSegment.h" 
+#include "DT_Transform.h"
+#include "DT_Minkowski.h"
+#include "DT_Sphere.h"
+
+void DT_Object::setBBox() 
+{
+	m_bbox = m_shape.bbox(m_xform, m_margin); 
+	DT_Vector3 min, max;
+	m_bbox.getMin().getValue(min);
+	m_bbox.getMax().getValue(max);
+	
+	T_ProxyList::const_iterator it;
+	for (it = m_proxies.begin(); it != m_proxies.end(); ++it) 
+	{
+		BP_SetBBox(*it, min, max);
+	}
+}
+
+bool DT_Object::ray_cast(const MT_Point3& source, const MT_Point3& target, 
+						 MT_Scalar& lambda, MT_Vector3& normal) const 
+{	
+	MT_Transform inv_xform = m_xform.inverse();
+	MT_Point3 local_source = inv_xform(source);
+	MT_Point3 local_target = inv_xform(target);
+	MT_Vector3 local_normal;
+
+	bool result = m_shape.ray_cast(local_source, local_target, lambda, local_normal);
+    	
+	if (result) 
+	{
+		normal = local_normal * inv_xform.getBasis();
+      MT_Scalar len = normal.length();
+		if (len > MT_Scalar(0.0))
+      {
+         normal /= len;
+      }
+	}
+
+	return result;
+}
+
+
+typedef AlgoTable IntersectTable;
+typedef AlgoTable Common_pointTable;
+typedef AlgoTable Penetration_depthTable;
+typedef AlgoTable Closest_pointsTable;
+
+
+bool intersectConvexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						   const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                           MT_Vector3& v) 
+{
+	DT_Transform ta(a2w, (const DT_Convex&)a);
+	DT_Transform tb(b2w, (const DT_Convex&)b);
+    return intersect((a_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : static_cast(ta)), 
+			         (b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), v);
+}
+
+bool intersectComplexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						    const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                            MT_Vector3& v) 
+{
+	if (a.getType() == COMPLEX)
+	{
+		DT_Transform tb(b2w, (const DT_Convex&)b);
+		return intersect((const DT_Complex&)a, a2w, a_margin, 
+		             (b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), v);
+	}
+	
+	bool r = intersectComplexConvex(b, b2w, b_margin, a, a2w, a_margin, v);
+	v *= -1.;
+	return r;
+}
+
+bool intersectComplexComplex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+							 const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                             MT_Vector3& v) 
+{
+    return intersect((const DT_Complex&)a, a2w, a_margin, 
+					 (const DT_Complex&)b, b2w, b_margin, v);
+}
+
+IntersectTable *intersectInitialize() 
+{
+    IntersectTable *p = new IntersectTable;
+    p->addEntry(COMPLEX, COMPLEX, intersectComplexComplex);
+    p->addEntry(COMPLEX, CONVEX, intersectComplexConvex);
+    p->addEntry(CONVEX, CONVEX, intersectConvexConvex);
+    return p;
+}
+
+bool intersect(const DT_Object& a, const DT_Object& b, MT_Vector3& v) 
+{
+    static IntersectTable *intersectTable = intersectInitialize();
+    Intersect intersect = intersectTable->lookup(a.getType(), b.getType());
+    return intersect(a.m_shape, a.m_xform, a.m_margin, 
+		             b.m_shape, b.m_xform, b.m_margin, v);
+}
+
+bool common_pointConvexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+							  const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+							  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+	DT_Transform ta(a2w, (const DT_Convex&)a);
+	DT_Transform tb(b2w, (const DT_Convex&)b);
+    return common_point((a_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : static_cast(ta)), 
+						(b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), v, pa, pb);
+}
+
+bool common_pointComplexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+							   const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+							   MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+	if (a.getType() == COMPLEX)
+	{
+		DT_Transform tb(b2w, (const DT_Convex&)b);
+		return common_point((const DT_Complex&)a, a2w, a_margin,
+					(b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), v, pa, pb);
+	}
+	
+	bool r = common_pointComplexConvex(b, b2w, b_margin, a, a2w, a_margin, v, pb, pa);
+	v *= -1.;
+	return r;
+}
+
+bool common_pointComplexComplex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+								const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+								MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    return common_point((const DT_Complex&)a, a2w, a_margin, 
+						(const DT_Complex&)b, b2w, b_margin, v, pa, pb);
+}
+
+Common_pointTable *common_pointInitialize() 
+{
+    Common_pointTable *p = new Common_pointTable;
+    p->addEntry(COMPLEX, COMPLEX, common_pointComplexComplex);
+    p->addEntry(COMPLEX, CONVEX, common_pointComplexConvex);
+    p->addEntry(CONVEX, CONVEX, common_pointConvexConvex);
+    return p;
+}
+
+bool common_point(const DT_Object& a, const DT_Object& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    static Common_pointTable *common_pointTable = common_pointInitialize();
+    Common_point common_point = common_pointTable->lookup(a.getType(), b.getType());
+    return common_point(a.m_shape, a.m_xform, a.m_margin, 
+						b.m_shape, b.m_xform, b.m_margin, v, pa, pb);
+}
+
+
+
+bool penetration_depthConvexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+								   const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                                   MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    return hybrid_penetration_depth(DT_Transform(a2w, (const DT_Convex&)a), a_margin, 
+									DT_Transform(b2w, (const DT_Convex&)b), b_margin, v, pa, pb);
+}
+
+bool penetration_depthComplexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                                    MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    if (a.getType() == COMPLEX)
+    	return penetration_depth((const DT_Complex&)a, a2w, a_margin,
+							 DT_Transform(b2w, (const DT_Convex&)b), b_margin, v, pa, pb);
+
+    bool r = penetration_depthComplexConvex(b, b2w, b_margin, a, a2w, a_margin, v, pb, pa);
+    v *= -1.;
+    return r;
+}
+
+bool penetration_depthComplexComplex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									 const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                                     MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    return penetration_depth((const DT_Complex&)a, a2w, a_margin, (const DT_Complex&)b, b2w, b_margin, v, pa, pb);
+}
+
+Penetration_depthTable *penetration_depthInitialize() 
+{
+    Penetration_depthTable *p = new Penetration_depthTable;
+    p->addEntry(COMPLEX, COMPLEX, penetration_depthComplexComplex);
+    p->addEntry(COMPLEX, CONVEX, penetration_depthComplexConvex);
+    p->addEntry(CONVEX, CONVEX, penetration_depthConvexConvex);
+    return p;
+}
+
+bool penetration_depth(const DT_Object& a, const DT_Object& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    static Penetration_depthTable *penetration_depthTable = penetration_depthInitialize();
+    Penetration_depth penetration_depth = penetration_depthTable->lookup(a.getType(), b.getType());
+    return penetration_depth(a.m_shape, a.m_xform, a.m_margin, 
+		                     b.m_shape, b.m_xform, b.m_margin, v, pa, pb);
+}
+
+
+MT_Scalar closest_pointsConvexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									 const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									 MT_Point3& pa, MT_Point3& pb)
+{
+	DT_Transform ta(a2w, (const DT_Convex&)a);
+	DT_Transform tb(b2w, (const DT_Convex&)b);
+    return closest_points((a_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : static_cast(ta)), 
+						  (b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), MT_INFINITY, pa, pb);
+}
+
+MT_Scalar closest_pointsComplexConvex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									  const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									  MT_Point3& pa, MT_Point3& pb)
+{
+    if (a.getType() == COMPLEX)
+    {
+	DT_Transform tb(b2w, (const DT_Convex&)b);
+	return closest_points((const DT_Complex&)a, a2w, a_margin,
+							(b_margin > MT_Scalar(0.0) ? static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : static_cast(tb)), pa, pb);
+    }
+    
+    return closest_pointsComplexConvex(b, b2w, b_margin, a, a2w, a_margin, pb, pa);
+}
+
+MT_Scalar closest_pointsComplexComplex(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+									   const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									   MT_Point3& pa, MT_Point3& pb) 
+{
+    return closest_points((const DT_Complex&)a, a2w, a_margin, 
+						  (const DT_Complex&)b, b2w, b_margin, pa, pb);
+}
+
+Closest_pointsTable *closest_pointsInitialize()
+{
+    Closest_pointsTable *p = new Closest_pointsTable;
+    p->addEntry(COMPLEX, COMPLEX, closest_pointsComplexComplex);
+    p->addEntry(COMPLEX, CONVEX, closest_pointsComplexConvex);
+    p->addEntry(CONVEX, CONVEX, closest_pointsConvexConvex);
+    return p;
+}
+
+MT_Scalar closest_points(const DT_Object& a, const DT_Object& b,
+						 MT_Point3& pa, MT_Point3& pb) 
+{
+    static Closest_pointsTable *closest_pointsTable = closest_pointsInitialize();
+    Closest_points closest_points = closest_pointsTable->lookup(a.getType(), b.getType());
+    return closest_points(a.m_shape, a.m_xform, a.m_margin, 
+						  b.m_shape, b.m_xform, b.m_margin, pa, pb);
+}
+
diff --git a/extern/solid/src/DT_Object.h b/extern/solid/src/DT_Object.h
new file mode 100644
index 00000000000..78beee2ab57
--- /dev/null
+++ b/extern/solid/src/DT_Object.h
@@ -0,0 +1,157 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_OBJECT_H
+#define DT_OBJECT_H
+
+#include 
+
+#include "SOLID.h"
+#include "SOLID_broad.h"
+
+#include "MT_Transform.h"
+#include "MT_Quaternion.h"
+#include "MT_BBox.h"
+#include "DT_Shape.h"
+
+class DT_Convex;
+
+class DT_Object {
+public:
+    DT_Object(void *client_object, const DT_Shape& shape) :
+		m_client_object(client_object),
+		m_shape(shape), 
+		m_margin(MT_Scalar(0.0))
+	{
+		m_xform.setIdentity();
+		setBBox();
+	}
+
+	void setMargin(MT_Scalar margin) 
+	{ 
+		m_margin = margin; 
+		setBBox();
+	}
+
+	void setScaling(const MT_Vector3& scaling)
+	{
+        m_xform.scale(scaling);
+        setBBox();
+    }
+
+    void setPosition(const MT_Point3& pos) 
+	{ 
+        m_xform.setOrigin(pos);
+        setBBox();
+    }
+    
+    void setOrientation(const MT_Quaternion& orn)
+	{
+		m_xform.setRotation(orn);
+		setBBox();
+    }
+
+	void setMatrix(const float *m) 
+	{
+        m_xform.setValue(m);
+		assert(m_xform.getBasis().determinant() != MT_Scalar(0.0));
+        setBBox();
+    }
+
+    void setMatrix(const double *m)
+	{
+        m_xform.setValue(m);
+		assert(m_xform.getBasis().determinant() != MT_Scalar(0.0));
+        setBBox();
+    }
+
+    void getMatrix(float *m) const
+	{
+        m_xform.getValue(m);
+    }
+
+    void getMatrix(double *m) const 
+	{
+        m_xform.getValue(m);
+    }
+
+	void setBBox();
+
+	const MT_BBox& getBBox() const { return m_bbox; }	
+	
+    DT_ResponseClass getResponseClass() const { return m_responseClass; }
+    
+	void setResponseClass(DT_ResponseClass responseClass) 
+	{ 
+		m_responseClass = responseClass;
+	}
+
+    DT_ShapeType getType() const { return m_shape.getType(); }
+
+    void *getClientObject() const { return m_client_object; }
+
+	bool ray_cast(const MT_Point3& source, const MT_Point3& target, 
+				  MT_Scalar& param, MT_Vector3& normal) const; 
+
+	void addProxy(BP_ProxyHandle proxy) { m_proxies.push_back(proxy); }
+
+	void removeProxy(BP_ProxyHandle proxy) 
+	{ 
+		T_ProxyList::iterator it = std::find(m_proxies.begin(), m_proxies.end(), proxy);
+		if (it != m_proxies.end()) {
+			m_proxies.erase(it);
+		}
+	}
+
+
+	friend bool intersect(const DT_Object&, const DT_Object&, MT_Vector3& v);
+	
+	friend bool common_point(const DT_Object&, const DT_Object&, MT_Vector3&, 
+							 MT_Point3&, MT_Point3&);
+	
+	friend bool penetration_depth(const DT_Object&, const DT_Object&, 
+								  MT_Vector3&, MT_Point3&, MT_Point3&);
+	
+	friend MT_Scalar closest_points(const DT_Object&, const DT_Object&, 
+									MT_Point3&, MT_Point3&);
+
+private:
+	typedef std::vector T_ProxyList;
+
+	void              *m_client_object;
+	DT_ResponseClass   m_responseClass;
+    const DT_Shape&    m_shape;
+    MT_Scalar          m_margin;
+	MT_Transform       m_xform;
+	T_ProxyList		   m_proxies;
+	MT_BBox            m_bbox;
+};
+
+#endif
+
+
+
+
+
+
+
diff --git a/extern/solid/src/DT_RespTable.cpp b/extern/solid/src/DT_RespTable.cpp
new file mode 100644
index 00000000000..20fbfc06aac
--- /dev/null
+++ b/extern/solid/src/DT_RespTable.cpp
@@ -0,0 +1,184 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_RespTable.h"
+
+#include 
+
+DT_ResponseList DT_RespTable::g_emptyResponseList;
+
+DT_RespTable::~DT_RespTable()
+{
+	DT_ResponseClass i;
+	for (i = 0; i < m_responseClass; ++i) 
+	{
+		delete [] m_table[i];
+	}
+}
+
+DT_ResponseClass DT_RespTable::genResponseClass()
+{
+	DT_ResponseClass newClass = m_responseClass++;
+	DT_ResponseList *newList = new DT_ResponseList[m_responseClass];
+	assert(newList);
+	m_table.push_back(newList);
+	m_singleList.resize(m_responseClass);
+	DT_ResponseClass i;
+	for (i = 0; i < m_responseClass; ++i) 
+	{
+		newList[i].append(m_default);
+		newList[i].append(m_singleList[i]);
+	}
+	return newClass;
+}
+
+void DT_RespTable::setResponseClass(void *object, 
+									DT_ResponseClass responseClass) 
+{
+	assert(responseClass < m_responseClass);
+	m_objectMap[object] = responseClass;
+}
+
+DT_ResponseClass DT_RespTable::getResponseClass(void *object) const
+{
+	T_ObjectMap::const_iterator it = m_objectMap.find(object);
+	assert(it != m_objectMap.end());
+	return (*it).second;
+}
+
+void DT_RespTable::clearResponseClass(void *object) 
+{
+	m_objectMap.erase(object);
+}
+
+const DT_ResponseList& DT_RespTable::find(void *object1, void *object2) const
+{
+	T_ObjectMap::const_iterator it = m_objectMap.find(object1);
+	if (it != m_objectMap.end()) 
+	{
+		DT_ResponseClass responseClass1 = (*it).second;
+		it = m_objectMap.find(object2);
+		if (it != m_objectMap.end()) 
+		{
+			DT_ResponseClass responseClass2 = (*it).second;
+			if (responseClass1 < responseClass2) 
+			{
+				std::swap(responseClass1, responseClass2);
+			}
+			return m_table[responseClass1][responseClass2];
+		}
+	}
+	return g_emptyResponseList;
+}
+
+void DT_RespTable::addDefault(const DT_Response& response)
+{
+	m_default.addResponse(response);
+	DT_ResponseClass i;
+	for (i = 0; i < m_responseClass; ++i) 
+	{
+		DT_ResponseClass j;
+		for (j = 0; j <= i; ++j) 
+		{
+			m_table[i][j].addResponse(response);
+		}
+	}
+}
+
+void DT_RespTable::removeDefault(const DT_Response& response)
+{
+	m_default.removeResponse(response);
+	DT_ResponseClass i;
+	for (i = 0; i < m_responseClass; ++i) 
+	{
+		DT_ResponseClass j;
+		for (j = 0; j <= i; ++j) 
+		{
+			m_table[i][j].removeResponse(response);
+		}
+	}
+}
+
+void DT_RespTable::addSingle(DT_ResponseClass responseClass, 
+							 const DT_Response& response)
+{	
+	assert(responseClass < m_responseClass);
+	m_singleList[responseClass].addResponse(response);
+	DT_ResponseClass j;
+	for (j = 0; j < responseClass; ++j) 
+	{
+		m_table[responseClass][j].addResponse(response);
+	}
+	
+	DT_ResponseClass i;
+	for (i = responseClass; i < m_responseClass; ++i) 
+	{
+		m_table[i][responseClass].addResponse(response);
+	}
+}
+
+void DT_RespTable::removeSingle(DT_ResponseClass responseClass, 
+								const DT_Response& response)
+{	
+	assert(responseClass < m_responseClass);
+	m_singleList[responseClass].removeResponse(response);
+	DT_ResponseClass j;
+	for (j = 0; j < responseClass; ++j) 
+	{
+		m_table[responseClass][j].removeResponse(response);
+	}
+	
+	DT_ResponseClass i;
+	for (i = responseClass; i < m_responseClass; ++i) 
+	{
+		m_table[i][responseClass].removeResponse(response);
+	}
+}
+
+void DT_RespTable::addPair(DT_ResponseClass responseClass1,
+						   DT_ResponseClass responseClass2, 
+						   const DT_Response& response)
+{
+	assert(responseClass1 < m_responseClass);
+	assert(responseClass2 < m_responseClass);
+	if (responseClass1 < responseClass2) 
+	{
+		std::swap(responseClass1, responseClass2);
+	}
+	m_table[responseClass1][responseClass2].addResponse(response);
+}
+
+
+void DT_RespTable::removePair(DT_ResponseClass responseClass1,
+							  DT_ResponseClass responseClass2, 
+							  const DT_Response& response)
+{
+	assert(responseClass1 < m_responseClass);
+	assert(responseClass2 < m_responseClass);
+	if (responseClass1 < responseClass2) 
+	{
+		std::swap(responseClass1, responseClass2);
+	}
+	m_table[responseClass1][responseClass2].removeResponse(response);
+}
+
diff --git a/extern/solid/src/DT_RespTable.h b/extern/solid/src/DT_RespTable.h
new file mode 100644
index 00000000000..9a17f562937
--- /dev/null
+++ b/extern/solid/src/DT_RespTable.h
@@ -0,0 +1,139 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_RESPTABLE_H
+#define DT_RESPTABLE_H
+
+#include 
+#include 
+#include 
+#include 
+#include "GEN_MinMax.h"
+#include "DT_Response.h"
+
+class DT_ResponseList : public std::list {
+public:
+    DT_ResponseList() : m_type(DT_NO_RESPONSE) {}
+
+	DT_ResponseType getType() const { return m_type; }
+
+    void addResponse(const DT_Response& response) 
+	{
+        if (response.getType() != DT_NO_RESPONSE) 
+		{
+            push_back(response);
+            GEN_set_max(m_type, response.getType());
+        }
+    }
+
+    void removeResponse(const DT_Response& response) 
+	{
+		iterator it = std::find(begin(), end(), response);
+		if (it != end()) 
+		{
+			erase(it);
+			m_type = DT_NO_RESPONSE;
+			for (it = begin(); it != end(); ++it) 
+			{
+				GEN_set_max(m_type, (*it).getType());
+			}
+		}
+    }
+	
+    void append(const DT_ResponseList& responseList) 
+	{
+        if (responseList.getType() != DT_NO_RESPONSE) 
+		{
+			const_iterator it;
+			for (it = responseList.begin(); it != responseList.end(); ++it) 
+			{
+				addResponse(*it);
+			}
+		}
+	}
+
+    DT_Bool operator()(void *a, void *b, const DT_CollData *coll_data) const 
+	{
+		DT_Bool done = DT_CONTINUE;
+		const_iterator it;
+        for (it = begin(); !done && it != end(); ++it) 
+		{
+            done = (*it)(a, b, coll_data);
+        }
+		return done;
+    }
+    
+private:
+	DT_ResponseType    m_type;
+};
+
+class DT_RespTable {
+private:
+	typedef std::map T_ObjectMap; 
+	typedef std::vector T_PairTable;
+	typedef std::vector T_SingleList;
+
+public:
+	DT_RespTable() : m_responseClass(0) {}
+
+	~DT_RespTable();
+
+	DT_ResponseClass genResponseClass();
+	
+	void setResponseClass(void *object, DT_ResponseClass responseClass);
+	DT_ResponseClass getResponseClass(void *object) const;
+	
+	void clearResponseClass(void *object);
+	
+	const DT_ResponseList& find(void *object1, void *object2) const;
+
+    void addDefault(const DT_Response& response); 
+    void removeDefault(const DT_Response& response); 
+
+    void addSingle(DT_ResponseClass responseClass, 
+				   const DT_Response& response);
+    void removeSingle(DT_ResponseClass responseClass, 
+					  const DT_Response& response);
+	
+    void addPair(DT_ResponseClass responseClass1, 
+				 DT_ResponseClass responseClass2, 
+				 const DT_Response& response);
+    void removePair(DT_ResponseClass responseClass1, 
+					DT_ResponseClass responseClass2, 
+					const DT_Response& response);
+
+private:
+	static DT_ResponseList g_emptyResponseList;
+
+	T_ObjectMap      m_objectMap;
+	DT_ResponseClass m_responseClass;
+	T_PairTable      m_table;
+	T_SingleList     m_singleList;
+    DT_ResponseList  m_default;
+};
+
+#endif
+
+
+
+
diff --git a/extern/solid/src/DT_Response.h b/extern/solid/src/DT_Response.h
new file mode 100644
index 00000000000..e58d9bb9944
--- /dev/null
+++ b/extern/solid/src/DT_Response.h
@@ -0,0 +1,63 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_RESPONSE_H
+#define DT_RESPONSE_H
+
+#include "SOLID.h"
+
+class DT_Response {
+public:
+    DT_Response(DT_ResponseCallback response    = 0, 
+				DT_ResponseType     type        = DT_NO_RESPONSE, 
+				void               *client_data = 0) 
+	  : m_response(response), 
+		m_type(type), 
+		m_client_data(client_data) {}
+    
+	DT_ResponseType getType() const { return m_type; }
+
+	DT_Bool operator()(void *a, void *b, const DT_CollData *coll_data) const 
+	{  
+		return (*m_response)(m_client_data, a, b, coll_data); 
+	}
+
+	friend bool operator==(const DT_Response& a, const DT_Response& b) 
+	{
+		return a.m_response == b.m_response;
+	}
+    
+	friend bool operator!=(const DT_Response& a, const DT_Response& b) 
+	{
+		return a.m_response != b.m_response;
+	}
+    
+private:
+    DT_ResponseCallback  m_response;
+    DT_ResponseType      m_type;
+    void                *m_client_data;
+};
+
+#endif  
+
+
diff --git a/extern/solid/src/DT_Scene.cpp b/extern/solid/src/DT_Scene.cpp
new file mode 100644
index 00000000000..56cea1633ca
--- /dev/null
+++ b/extern/solid/src/DT_Scene.cpp
@@ -0,0 +1,183 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Scene.h"
+#include "DT_Object.h"
+#include "DT_Convex.h"
+
+//#define DEBUG
+
+static void beginOverlap(void *client_data, void *object1, void *object2) 
+{
+	DT_Encounter e((DT_Object *)object1, (DT_Object *)object2);
+	DT_EncounterTable *encounterTable = static_cast(client_data);
+
+#ifdef DEBUG	
+	std::cout << "Begin: " << e << std::endl; 
+#endif
+
+	encounterTable->insert(e);
+}
+
+
+static void endOverlap(void *client_data, void *object1, void *object2) 
+{
+	DT_Encounter e((DT_Object *)object1, (DT_Object *)object2);
+	DT_EncounterTable *encounterTable = static_cast(client_data);
+
+#ifdef DEBUG
+	std::cout << "End:   " << e << std::endl; 
+#endif
+	
+	assert(encounterTable->find(e) != encounterTable->end()); 
+	encounterTable->erase(e);
+}
+
+struct DT_RayCastData {
+	DT_RayCastData(const void *ignore) 
+	  : m_ignore(ignore) 
+	{}
+
+	const void  *m_ignore;
+	MT_Vector3  m_normal;
+};
+
+static bool objectRayCast(void *client_data, 
+						  void *object,  
+						  const DT_Vector3 source,
+						  const DT_Vector3 target,
+						  DT_Scalar *lambda) 
+{
+	DT_RayCastData *data = static_cast(client_data); 
+	if (((DT_Object *)object)->getClientObject() != data->m_ignore)
+	{
+		MT_Scalar param = MT_Scalar(*lambda);
+		
+		if (((DT_Object *)object)->ray_cast(MT_Point3(source), MT_Point3(target),
+											param, data->m_normal))
+		{
+			*lambda = param;
+			return true;
+		}
+	}
+	return false;
+}
+
+DT_Scene::DT_Scene() 
+  : m_broadphase(BP_CreateScene(&m_encounterTable, &beginOverlap, &endOverlap))
+{}
+
+DT_Scene::~DT_Scene()
+{
+	BP_DestroyScene(m_broadphase);
+}
+
+void DT_Scene::addObject(DT_Object &object)
+{
+	const MT_BBox& bbox = object.getBBox();
+	DT_Vector3 min, max;
+	bbox.getMin().getValue(min);
+	bbox.getMax().getValue(max);
+    BP_ProxyHandle proxy = BP_CreateProxy(m_broadphase, &object, min, max);
+	
+#ifdef DEBUG
+	DT_EncounterTable::iterator it;	
+	std::cout << "Add " << &object << ':';
+	for (it = m_encounterTable.begin(); it != m_encounterTable.end(); ++it) {
+		std::cout << ' ' << (*it);
+	}
+	std::cout << std::endl;
+#endif
+	object.addProxy(proxy);
+    m_objectList.push_back(std::make_pair(&object, proxy));
+}
+
+
+
+void DT_Scene::removeObject(DT_Object& object)
+{
+    T_ObjectList::iterator it = m_objectList.begin();
+
+    while (it != m_objectList.end() && &object != (*it).first)
+	{
+        ++it;
+    }
+
+    if (it != m_objectList.end())
+	{
+		object.removeProxy((*it).second);
+        BP_DestroyProxy(m_broadphase, (*it).second);
+		m_objectList.erase(it);
+
+#ifdef DEBUG
+		std::cout << "Remove " << &object << ':';
+		DT_EncounterTable::iterator it;	
+		for (it = m_encounterTable.begin(); it != m_encounterTable.end(); ++it)
+		{
+			std::cout << ' ' << (*it);
+			assert((*it).first() != &object &&
+				   (*it).second() != &object);
+		}
+		std::cout << std::endl;
+#endif
+    }
+}
+
+
+
+int DT_Scene::handleCollisions(const DT_RespTable *respTable)
+{
+    int count = 0;
+
+    assert(respTable);
+
+	DT_EncounterTable::iterator it;	
+	for (it = m_encounterTable.begin(); it != m_encounterTable.end(); ++it)
+	{
+		if ((*it).exactTest(respTable, count))
+		{
+			break;
+        }
+	
+    }
+    return count;
+}
+
+void *DT_Scene::rayCast(const void *ignore_client,
+						const DT_Vector3 source, const DT_Vector3 target, 
+						DT_Scalar& lambda, DT_Vector3 normal) const 
+{
+	DT_RayCastData data(ignore_client);
+	DT_Object *object = (DT_Object *)BP_RayCast(m_broadphase, 
+												&objectRayCast, 
+												&data, 
+												source, target,
+												&lambda);
+	if (object)
+	{
+		data.m_normal.getValue(normal);
+		return object->getClientObject();
+	}
+	
+	return 0;
+}
diff --git a/extern/solid/src/DT_Scene.h b/extern/solid/src/DT_Scene.h
new file mode 100644
index 00000000000..9b061910312
--- /dev/null
+++ b/extern/solid/src/DT_Scene.h
@@ -0,0 +1,57 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_SCENE_H
+#define DT_SCENE_H
+
+#include 
+
+#include "SOLID_broad.h"
+#include "DT_Encounter.h"
+
+class DT_Object;
+class DT_RespTable;
+
+class DT_Scene {
+public:
+    DT_Scene();
+    ~DT_Scene();
+
+    void addObject(DT_Object& object);
+    void removeObject(DT_Object& object);
+
+    int  handleCollisions(const DT_RespTable *respTable);
+
+	void *rayCast(const void *ignore_client, 
+				  const DT_Vector3 source, const DT_Vector3 target, 
+				  DT_Scalar& lambda, DT_Vector3 normal) const;
+
+private:
+	typedef std::vector > T_ObjectList;
+
+	BP_SceneHandle      m_broadphase;
+	T_ObjectList        m_objectList;
+    DT_EncounterTable   m_encounterTable;
+};
+
+#endif
diff --git a/extern/solid/src/Makefile b/extern/solid/src/Makefile
new file mode 100644
index 00000000000..b45a1da9cd3
--- /dev/null
+++ b/extern/solid/src/Makefile
@@ -0,0 +1,48 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+SOURCEDIR = extern/solid/src
+LIBNAME = solid
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+DIRS = broad complex convex
+
+include nan_subdirs.mk
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../include -I$(NAN_QHULL)/include
+CPPFLAGS += -Iconvex -Icomplex
+CPPFLAGS += -DQHULL -DUSE_DOUBLES
+
+include nan_compile.mk 
+
diff --git a/extern/solid/src/broad/BP_C-api.cpp b/extern/solid/src/broad/BP_C-api.cpp
new file mode 100644
index 00000000000..43e1172927b
--- /dev/null
+++ b/extern/solid/src/broad/BP_C-api.cpp
@@ -0,0 +1,77 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "SOLID_broad.h"
+
+#include "BP_Scene.h"
+#include "BP_Proxy.h"
+
+BP_SceneHandle BP_CreateScene(void *client_data,
+							  BP_Callback beginOverlap,
+							  BP_Callback endOverlap)
+{
+	return (BP_SceneHandle)new BP_Scene(client_data, 
+										beginOverlap, 
+										endOverlap);
+}
+
+ 
+void BP_DestroyScene(BP_SceneHandle scene)
+{
+	delete (BP_Scene *)scene;
+}
+	
+
+BP_ProxyHandle BP_CreateProxy(BP_SceneHandle scene, void *object,
+							  const DT_Vector3 min, const DT_Vector3 max)
+{
+	return (BP_ProxyHandle)
+		((BP_Scene *)scene)->createProxy(object, min, max);
+}
+
+
+void BP_DestroyProxy(BP_SceneHandle scene, BP_ProxyHandle proxy) 
+{
+	((BP_Scene *)scene)->destroyProxy((BP_Proxy *)proxy);
+}
+
+
+
+void BP_SetBBox(BP_ProxyHandle proxy, const DT_Vector3 min, const DT_Vector3 max)	
+{
+	((BP_Proxy *)proxy)->setBBox(min, max);
+}
+
+void *BP_RayCast(BP_SceneHandle scene, 
+				 BP_RayCastCallback objectRayCast,
+				 void *client_data,
+				 const DT_Vector3 source,
+				 const DT_Vector3 target,
+				 DT_Scalar *lambda) 
+{
+	return ((BP_Scene *)scene)->rayCast(objectRayCast,
+										client_data,
+										source,	target,
+										*lambda);
+}
+
diff --git a/extern/solid/src/broad/BP_Endpoint.h b/extern/solid/src/broad/BP_Endpoint.h
new file mode 100644
index 00000000000..8de6e67ce65
--- /dev/null
+++ b/extern/solid/src/broad/BP_Endpoint.h
@@ -0,0 +1,108 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_ENDPOINT_H
+#define BP_ENDPOINT_H
+
+#include "SOLID_types.h"
+
+class BP_Proxy;
+
+class BP_Link {
+public:
+	BP_Link() {}
+	explicit BP_Link(BP_Proxy *proxy) :
+		m_proxy(proxy)
+	{}
+
+	DT_Index  m_index;
+	DT_Count  m_count;
+	BP_Proxy *m_proxy;
+};
+
+typedef unsigned int Uint32;
+
+class BP_Endpoint {
+public:
+    enum { 
+		MINIMUM = 0x00000000, 
+		MAXIMUM = 0x80000000,	
+		TYPEBIT = 0x00000001
+	};
+
+    BP_Endpoint() {}
+    BP_Endpoint(DT_Scalar pos, Uint32 type, BP_Link *link) 
+	  :	m_link(link)
+	{
+		setPos(pos, type);
+	}
+ 
+	DT_Scalar getPos()   const { return m_pos; }
+	DT_Index&   getIndex() const { return m_link->m_index; }
+	DT_Count&   getCount() const { return m_link->m_count; }
+	BP_Proxy *getProxy() const { return m_link->m_proxy; }
+	
+	DT_Index   getEndIndex()   const { return (m_link + 1)->m_index; }
+	
+	Uint32 getType() const 
+	{ 
+		return (m_bits & TYPEBIT) ? (~m_bits & MAXIMUM) : (m_bits & MAXIMUM);
+	}
+
+	void setPos(DT_Scalar pos, Uint32 type) 
+	{
+		m_pos = pos; 
+		if ((m_bits & MAXIMUM) == type) 
+		{
+			m_bits &= ~TYPEBIT;
+		}
+		else 
+		{
+			m_bits |= TYPEBIT;
+		}
+	}
+
+private:
+	union {
+		DT_Scalar    m_pos;
+		Uint32       m_bits;
+	};
+	BP_Link        *m_link;
+};
+
+inline bool operator<(const BP_Endpoint& a, const BP_Endpoint& b) 
+{
+    return a.getPos() < b.getPos(); 
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/extern/solid/src/broad/BP_EndpointList.cpp b/extern/solid/src/broad/BP_EndpointList.cpp
new file mode 100644
index 00000000000..aa094ffeb0a
--- /dev/null
+++ b/extern/solid/src/broad/BP_EndpointList.cpp
@@ -0,0 +1,237 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include 
+#include 
+
+#include "BP_EndpointList.h"
+#include "BP_Scene.h"
+#include "BP_Proxy.h"
+#include "BP_ProxyList.h"
+
+DT_Index BP_EndpointList::stab(const BP_Endpoint& pos, BP_ProxyList& proxies) const 
+{
+	DT_Index result = std::upper_bound(begin(), end(), pos) - begin();
+	
+	if (result != 0) 
+	{
+		DT_Index i = result - 1;
+		DT_Count count = (*this)[i].getCount(); 
+		while (count) 
+		{
+			const BP_Endpoint& endpoint = (*this)[i];
+			if (endpoint.getType() == BP_Endpoint::MINIMUM &&
+				pos < (*this)[endpoint.getEndIndex()]) 
+			{
+				proxies.add(endpoint.getProxy());
+				--count;
+			}
+			assert(i != 0 || count == 0);
+			--i;
+		}											
+	}
+	return result;
+}
+
+DT_Scalar BP_EndpointList::nextLambda(DT_Index& index, 
+									  DT_Scalar source, 
+									  DT_Scalar delta) const
+{
+	if (delta != 0.0f) 
+	{
+		if (delta < 0.0f) 
+		{
+			if (index != 0) 
+			{
+				return ((*this)[--index].getPos() - source) / delta;
+			}
+		}
+		else 
+		{
+			if (index != size()) 
+			{
+				return ((*this)[index++].getPos() - source) / delta;
+			}
+		}
+	}
+	return FLT_MAX;
+}
+
+
+void BP_EndpointList::range(const BP_Endpoint& min, 
+							const BP_Endpoint& max,
+							DT_Index& first, DT_Index& last,
+							BP_ProxyList& proxies) const 
+{
+	first = stab(min, proxies);
+	last  = std::upper_bound(begin(), end(), max) - begin();
+	
+	DT_Index i;
+	for (i = first; i != last; ++i) 
+	{
+		const BP_Endpoint& endpoint = (*this)[i];
+		if (endpoint.getType() == BP_Endpoint::MINIMUM) 
+		{
+			proxies.add(endpoint.getProxy());
+		}
+	}
+}
+
+void BP_EndpointList::addInterval(const BP_Endpoint& min, 
+								  const BP_Endpoint& max,
+								  BP_ProxyList& proxies) 
+{
+	assert(invariant());
+	DT_Index first, last;
+	range(min, max, first, last, proxies);
+	insert(begin() + last, max);
+	insert(begin() + first, min);
+	++last; 
+	
+	(*this)[first].getCount() = first != 0 ? (*this)[first - 1].getCount() : 0;
+	(*this)[last].getCount() = (*this)[last - 1].getCount();
+	
+	
+	DT_Index i;
+	for (i = first; i != last; ++i) 
+	{
+		++(*this)[i].getCount();
+		(*this)[i].getIndex() = i;
+	} 
+	for (; i != size(); ++i) 
+	{
+		(*this)[i].getIndex() = i;
+	} 
+	
+	assert(invariant());
+}
+
+void BP_EndpointList::removeInterval(DT_Index first, DT_Index last,
+									 BP_ProxyList& proxies) 
+{ 
+	assert(invariant());
+	
+	BP_Endpoint min = (*this)[first];
+	BP_Endpoint max = (*this)[last]; 
+	
+	erase(begin() + last);
+	erase(begin() + first);
+	--last;
+	
+	DT_Index i;
+	for (i = first; i != last; ++i) 
+	{
+		--(*this)[i].getCount();
+		(*this)[i].getIndex() = i;
+	} 
+	for (; i != size(); ++i) 
+	{
+		(*this)[i].getIndex() = i;
+	} 
+	
+	range(min, max, first, last, proxies);
+	
+	assert(invariant());
+}
+
+void BP_EndpointList::move(DT_Index index, DT_Scalar pos, Uint32 type,  
+						   BP_Scene& scene, T_Overlap overlap)
+{
+	assert(invariant());
+	
+	BP_Endpoint endpoint = (*this)[index];
+    DT_Scalar delta = pos - endpoint.getPos();
+	
+    if (delta != DT_Scalar(0.0)) 
+	{
+		endpoint.setPos(pos, type);
+		if (delta < DT_Scalar(0.0)) 
+		{
+			while (index != 0 && endpoint < (*this)[index - 1]) 
+			{
+				(*this)[index] = (*this)[index - 1];
+				(*this)[index].getIndex() = index;
+				encounters((*this)[index], endpoint, scene, overlap);
+				--index;
+			}
+		}
+		else 
+		{
+			DT_Index last = size() - 1;
+			while (index != last && (*this)[index + 1] < endpoint) 
+			{
+				(*this)[index] = (*this)[index + 1];
+				(*this)[index].getIndex() = index;
+				encounters(endpoint, (*this)[index], scene, overlap);
+				++index;
+			}
+		}
+		(*this)[index] = endpoint;
+		(*this)[index].getIndex() = index;
+    }
+
+	assert(invariant());
+}
+
+void BP_EndpointList::encounters(const BP_Endpoint& a, const BP_Endpoint& b,
+								 BP_Scene& scene, T_Overlap overlap)
+{
+	assert(a.getProxy() != b.getProxy());
+	
+	if (a.getType() != b.getType()) 
+	{
+		if (a.getType() == BP_Endpoint::MAXIMUM) 
+		{
+			if (overlap(*a.getProxy(), *b.getProxy())) 
+			{
+				scene.callBeginOverlap(a.getProxy()->getObject(), 
+									   b.getProxy()->getObject());
+			}
+			++a.getCount();
+			++b.getCount();
+		}
+		else 
+		{
+			if (overlap(*a.getProxy(), *b.getProxy())) 
+			{
+				scene.callEndOverlap(a.getProxy()->getObject(), 
+									 b.getProxy()->getObject());
+			}
+			--a.getCount();
+			--b.getCount();
+		}
+	}
+	else 
+	{
+		if (a.getType() == BP_Endpoint::MAXIMUM) 
+		{
+			--a.getCount();
+			++b.getCount();
+		}
+		else 
+		{
+			++a.getCount();
+			--b.getCount();
+		}
+	}
+}
diff --git a/extern/solid/src/broad/BP_EndpointList.h b/extern/solid/src/broad/BP_EndpointList.h
new file mode 100644
index 00000000000..6154991ed3d
--- /dev/null
+++ b/extern/solid/src/broad/BP_EndpointList.h
@@ -0,0 +1,109 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_ENDPOINTLIST_H
+#define BP_ENDPOINTLIST_H
+
+//#define PARANOID
+
+#include 
+
+#include "BP_Endpoint.h"
+#include "BP_ProxyList.h"
+
+class BP_Scene;
+
+typedef bool (*T_Overlap)(const BP_Proxy& a, const BP_Proxy& b);
+
+class BP_EndpointList : public std::vector {
+public:
+	BP_EndpointList() {}
+	
+	DT_Index stab(const BP_Endpoint& pos, BP_ProxyList& proxies) const;
+	
+	DT_Index stab(DT_Scalar pos, BP_ProxyList& proxies) const
+	{
+		return stab(BP_Endpoint(pos, BP_Endpoint::MINIMUM, 0), proxies);
+	}
+	
+
+   void range(const BP_Endpoint& min, const BP_Endpoint& max, 
+			  DT_Index& first, DT_Index& last, BP_ProxyList& proxies) const;
+	
+	void range(DT_Scalar lb, DT_Scalar ub, DT_Index& first, DT_Index& last, BP_ProxyList& proxies) const 
+	{
+		range(BP_Endpoint(lb, BP_Endpoint::MINIMUM, 0), 
+			  BP_Endpoint(ub, BP_Endpoint::MAXIMUM, 0),
+			  first, last, proxies);
+	}
+	
+	void addInterval(const BP_Endpoint& min, const BP_Endpoint& max, BP_ProxyList& proxies);
+	void removeInterval(DT_Index first, DT_Index last, BP_ProxyList& proxies);
+
+	void move(DT_Index index, DT_Scalar pos, Uint32 type, BP_Scene& scene, T_Overlap overlap);	
+   
+   DT_Scalar nextLambda(DT_Index& index, DT_Scalar source, DT_Scalar target) const;
+	
+
+private:
+	void encounters(const BP_Endpoint& a, const BP_Endpoint& b,
+					    BP_Scene& scene, T_Overlap overlap);
+
+
+#ifdef PARANOID
+	bool invariant() const 
+	{
+		DT_Count count = 0;
+		DT_Index i;
+		for (i = 0; i != size(); ++i) 
+		{
+         const BP_Endpoint& endpoint = (*this)[i];
+
+			if (endpoint.getType() == BP_Endpoint::MINIMUM) 
+			{
+				++count;
+			}
+			else 
+			{
+				--count;
+			}
+			if (endpoint.getCount() != count)
+			{
+				return false;
+			}
+			if (endpoint.getIndex() != i) 
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+#else
+	bool invariant() const { return true; }
+#endif
+
+};
+
+
+
+#endif
diff --git a/extern/solid/src/broad/BP_Proxy.cpp b/extern/solid/src/broad/BP_Proxy.cpp
new file mode 100644
index 00000000000..e8007df240d
--- /dev/null
+++ b/extern/solid/src/broad/BP_Proxy.cpp
@@ -0,0 +1,120 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include 
+
+#include "BP_Proxy.h"
+#include "BP_Scene.h"
+
+BP_Proxy::BP_Proxy(void *object, 
+				   BP_Scene& scene) 
+  :	m_object(object),
+	m_scene(scene)
+{
+	int i;
+	for (i = 0; i < 3; ++i) 
+	{
+		new (&m_interval[i]) BP_Interval(this);
+	}
+}
+
+void BP_Proxy::add(const DT_Vector3 min,
+				   const DT_Vector3 max,
+				   BP_ProxyList& proxies) 
+{
+	int i;
+	for (i = 0; i < 3; ++i) 
+	{
+		m_scene.getList(i).addInterval(
+			BP_Endpoint(min[i], BP_Endpoint::MINIMUM, &m_interval[i].m_min), 
+			BP_Endpoint(max[i], BP_Endpoint::MAXIMUM, &m_interval[i].m_max), 
+			proxies);
+	}
+}
+
+void BP_Proxy::remove(BP_ProxyList& proxies) 
+{
+	int i;
+	for (i = 0; i < 3; ++i) 
+	{
+		m_scene.getList(i).removeInterval(
+			m_interval[i].m_min.m_index,
+			m_interval[i].m_max.m_index,
+			proxies);
+	}
+}
+
+DT_Scalar BP_Proxy::getMin(int i) const 
+{ 
+	return m_scene.getList(i)[m_interval[i].m_min.m_index].getPos(); 
+}
+
+DT_Scalar BP_Proxy::getMax(int i) const 
+{ 
+	return m_scene.getList(i)[m_interval[i].m_max.m_index].getPos(); 
+}
+
+bool overlapXY(const BP_Proxy& a, const BP_Proxy& b)
+{
+	return a.getMin(0) <= b.getMax(0) && b.getMin(0) <= a.getMax(0) && 
+		   a.getMin(1) <= b.getMax(1) && b.getMin(1) <= a.getMax(1);
+}
+
+bool overlapXZ(const BP_Proxy& a, const BP_Proxy& b)
+{
+	return a.getMin(0) <= b.getMax(0) && b.getMin(0) <= a.getMax(0) && 
+		   a.getMin(2) <= b.getMax(2) && b.getMin(2) <= a.getMax(2); 
+}
+
+bool overlapYZ(const BP_Proxy& a, const BP_Proxy& b)
+{
+	return a.getMin(1) <= b.getMax(1) && b.getMin(1) <= a.getMax(1) && 
+		   a.getMin(2) <= b.getMax(2) && b.getMin(2) <= a.getMax(2); 
+}
+
+void BP_Proxy::setBBox(const DT_Vector3 min, const DT_Vector3 max)
+{	
+	static T_Overlap overlap[3] = { overlapYZ, overlapXZ, overlapXY };
+
+	int i;
+	for (i = 0; i < 3; ++i) 
+	{
+		if (min[i] > getMax(i)) 
+		{
+			m_scene.getList(i).move(m_interval[i].m_max.m_index, max[i], 
+									BP_Endpoint::MAXIMUM, m_scene, overlap[i]);
+			m_scene.getList(i).move(m_interval[i].m_min.m_index, min[i], 
+									BP_Endpoint::MINIMUM, m_scene, overlap[i]);
+		}
+		else 
+		{
+			m_scene.getList(i).move(m_interval[i].m_min.m_index, min[i], 
+									BP_Endpoint::MINIMUM, m_scene, overlap[i]);
+			m_scene.getList(i).move(m_interval[i].m_max.m_index, max[i], 
+									BP_Endpoint::MAXIMUM, m_scene, overlap[i]);
+		}
+	}
+}
+
+
+
diff --git a/extern/solid/src/broad/BP_Proxy.h b/extern/solid/src/broad/BP_Proxy.h
new file mode 100644
index 00000000000..b4500ddca44
--- /dev/null
+++ b/extern/solid/src/broad/BP_Proxy.h
@@ -0,0 +1,78 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_PROXY_H
+#define BP_PROXY_H
+
+#include "BP_Endpoint.h"
+#include "BP_ProxyList.h"
+
+class BP_Interval {
+public:
+	BP_Interval() {}
+	BP_Interval(BP_Proxy *proxy) :
+		m_min(proxy),
+		m_max(proxy) 
+	{}
+
+	BP_Link m_min;
+	BP_Link m_max;
+};
+
+class BP_Scene;
+
+class BP_Proxy {
+public:
+    BP_Proxy(void *object, BP_Scene& scene);
+
+	void add(const DT_Vector3 min,
+			 const DT_Vector3 max,
+			 BP_ProxyList& proxies);
+	
+    void remove(BP_ProxyList& proxies);
+	
+	void setBBox(const DT_Vector3 min, const DT_Vector3 max);
+    
+    void *getObject() { return m_object; }
+
+	DT_Scalar getMin(int i) const;
+	DT_Scalar getMax(int i) const;
+
+private:
+	BP_Interval  m_interval[3];
+    void        *m_object;
+	BP_Scene&    m_scene;
+};
+
+inline bool BP_overlap(const BP_Proxy *a, const BP_Proxy *b)
+{
+	return a->getMin(0) <= b->getMax(0) && b->getMin(0) <= a->getMax(0) && 
+		   a->getMin(1) <= b->getMax(1) && b->getMin(1) <= a->getMax(1) &&
+		   a->getMin(2) <= b->getMax(2) && b->getMin(2) <= a->getMax(2);
+}
+
+#endif
+
+
+
+
diff --git a/extern/solid/src/broad/BP_ProxyList.h b/extern/solid/src/broad/BP_ProxyList.h
new file mode 100644
index 00000000000..2f449777d2d
--- /dev/null
+++ b/extern/solid/src/broad/BP_ProxyList.h
@@ -0,0 +1,69 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_PROXYLIST_H
+#define BP_PROXYLIST_H
+
+#include 
+
+#include 
+#include 
+#include 
+
+class BP_Proxy;
+
+typedef std::pair BP_ProxyEntry; 
+
+inline bool operator<(const BP_ProxyEntry& a, const BP_ProxyEntry& b) 
+{
+	return a.first < b.first;
+}
+
+class BP_ProxyList : public std::vector {
+public:
+   BP_ProxyList(size_t n = 20) : std::vector(n) {}      
+
+	iterator add(BP_Proxy *proxy) 
+	{
+		BP_ProxyEntry entry = std::make_pair(proxy, (unsigned int)0);
+		iterator it = std::lower_bound(begin(), end(), entry);
+		if (it == end() || (*it).first != proxy) 
+		{
+			it = insert(it, entry);
+		}
+		++(*it).second;
+		return it;
+	}
+
+	void remove(BP_Proxy *proxy) 
+	{
+		BP_ProxyEntry entry = std::make_pair(proxy, (unsigned int)0);
+		iterator it = std::lower_bound(begin(), end(), entry);
+		if (it != end() && (*it).first == proxy && --(*it).second == 0) 
+		{
+			erase(it);	
+		}	
+	}
+};
+
+#endif
diff --git a/extern/solid/src/broad/BP_Scene.cpp b/extern/solid/src/broad/BP_Scene.cpp
new file mode 100644
index 00000000000..c0cd83ba311
--- /dev/null
+++ b/extern/solid/src/broad/BP_Scene.cpp
@@ -0,0 +1,151 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "BP_Scene.h"
+#include "BP_Proxy.h"
+
+#include 
+
+BP_Proxy *BP_Scene::createProxy(void *object, 
+								const DT_Vector3 min,
+								const DT_Vector3 max)
+{
+	BP_Proxy *proxy = new BP_Proxy(object, *this);
+
+	proxy->add(min, max, m_proxies);
+	
+	BP_ProxyList::iterator it;
+	for (it = m_proxies.begin(); it != m_proxies.end(); ++it)
+	{
+		if ((*it).second == 3)
+		{
+			callBeginOverlap(proxy->getObject(), (*it).first->getObject());
+		}
+	}
+
+	m_proxies.clear();
+
+	return proxy;
+}
+
+void BP_Scene::destroyProxy(BP_Proxy *proxy)
+{
+	proxy->remove(m_proxies);
+	
+	BP_ProxyList::iterator it;
+	for (it = m_proxies.begin(); it != m_proxies.end(); ++it)
+	{
+		if ((*it).second == 3)
+		{
+			callEndOverlap(proxy->getObject(), (*it).first->getObject());
+		}
+	}
+	
+	m_proxies.clear();
+
+	delete proxy;
+}
+
+void *BP_Scene::rayCast(BP_RayCastCallback objectRayCast,
+						void *client_data,
+						const DT_Vector3 source, 
+						const DT_Vector3 target, 
+						DT_Scalar& lambda) const 
+{
+	void *client_object = 0;
+	
+	DT_Index index[3];
+	index[0] = m_endpointList[0].stab(source[0], m_proxies);
+	index[1] = m_endpointList[1].stab(source[1], m_proxies);
+	index[2] = m_endpointList[2].stab(source[2], m_proxies);
+
+	BP_ProxyList::iterator it;
+	for (it = m_proxies.begin(); it != m_proxies.end(); ++it) 
+	{
+		if ((*it).second == 3 &&
+            (*objectRayCast)(client_data, (*it).first->getObject(), source, target, &lambda))
+		{
+			client_object = (*it).first->getObject();
+		}
+	}
+
+	DT_Vector3 delta;
+	delta[0] = target[0] - source[0];
+	delta[1] = target[1] - source[1];
+	delta[2] = target[2] - source[2];
+	
+	DT_Vector3 lambdas;
+	lambdas[0] = m_endpointList[0].nextLambda(index[0], source[0], delta[0]);
+	lambdas[1] = m_endpointList[1].nextLambda(index[1], source[1], delta[1]);
+	lambdas[2] = m_endpointList[2].nextLambda(index[2], source[2], delta[2]);
+	int closest = lambdas[0] < lambdas[1] ? (lambdas[0] < lambdas[2] ? 0 : 2) : (lambdas[1] < lambdas[2] ? 1 : 2);
+	
+	while (lambdas[closest] < lambda)
+	{
+		if (delta[closest] < 0.0f)
+		{
+			const BP_Endpoint& endpoint = m_endpointList[closest][index[closest]];
+
+			if (endpoint.getType() == BP_Endpoint::MAXIMUM) 
+			{
+				it = m_proxies.add(endpoint.getProxy());
+				if ((*it).second == 3 &&
+					(*objectRayCast)(client_data, (*it).first->getObject(), source, target, &lambda))
+				{
+					client_object = (*it).first->getObject();
+				}
+			}
+			else
+			{
+				m_proxies.remove(endpoint.getProxy());
+			}
+		}
+		else 
+		{
+			const BP_Endpoint& endpoint = m_endpointList[closest][index[closest] - 1];
+			
+			if (endpoint.getType() == BP_Endpoint::MINIMUM) 
+			{
+				it = m_proxies.add(endpoint.getProxy());
+				if ((*it).second == 3 &&
+					(*objectRayCast)(client_data, (*it).first->getObject(), source, target, &lambda))
+				{
+					client_object = (*it).first->getObject();
+				}
+			}
+			else
+			{
+				m_proxies.remove(endpoint.getProxy());
+			}
+		}
+
+		lambdas[closest] = m_endpointList[closest].nextLambda(index[closest], source[closest], delta[closest]);
+		closest = lambdas[0] < lambdas[1] ?	(lambdas[0] < lambdas[2] ? 0 : 2) : (lambdas[1] < lambdas[2] ? 1 : 2);
+	}
+
+	m_proxies.clear();
+
+	return client_object;
+}
+
+
diff --git a/extern/solid/src/broad/BP_Scene.h b/extern/solid/src/broad/BP_Scene.h
new file mode 100644
index 00000000000..ef55374c43b
--- /dev/null
+++ b/extern/solid/src/broad/BP_Scene.h
@@ -0,0 +1,79 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef BP_SCENE_H
+#define BP_SCENE_H
+
+#include 
+
+#include "BP_EndpointList.h"
+#include "BP_ProxyList.h"
+
+class BP_Proxy;
+
+class BP_Scene {
+public:
+    BP_Scene(void *client_data,
+			 BP_Callback beginOverlap,
+			 BP_Callback endOverlap) 
+      :	m_client_data(client_data),
+		m_beginOverlap(beginOverlap),
+		m_endOverlap(endOverlap),
+		m_proxies(20)
+	{}
+
+    ~BP_Scene() {}
+
+    BP_Proxy *createProxy(void *object, 
+						  const DT_Vector3 min,
+						  const DT_Vector3 max);
+
+    void destroyProxy(BP_Proxy *proxy);
+	
+	void *rayCast(BP_RayCastCallback objectRayCast,
+				  void *client_data,
+				  const DT_Vector3 source, 
+				  const DT_Vector3 target, 
+				  DT_Scalar& lambda) const;
+	
+  	void callBeginOverlap(void *object1, void *object2) 
+	{
+		(*m_beginOverlap)(m_client_data, object1, object2);
+	}
+	
+	void callEndOverlap(void *object1, void *object2) 
+	{
+		(*m_endOverlap)(m_client_data, object1, object2);
+	}
+	
+	BP_EndpointList& getList(int i) { return m_endpointList[i]; }
+
+private:
+	void                    *m_client_data;
+	BP_Callback              m_beginOverlap; 
+	BP_Callback              m_endOverlap; 
+    BP_EndpointList          m_endpointList[3];
+	mutable BP_ProxyList     m_proxies;
+};
+
+#endif
diff --git a/extern/solid/src/broad/Makefile b/extern/solid/src/broad/Makefile
new file mode 100644
index 00000000000..90445c3cd7a
--- /dev/null
+++ b/extern/solid/src/broad/Makefile
@@ -0,0 +1,44 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = solid_broad
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../../include -I$(NAN_QHULL)/include
+CPPFLAGS += -DQHULL -DUSE_DOUBLES
+
+include nan_compile.mk 
+
+
diff --git a/extern/solid/src/complex/DT_BBoxTree.cpp b/extern/solid/src/complex/DT_BBoxTree.cpp
new file mode 100644
index 00000000000..4f10f61f2e2
--- /dev/null
+++ b/extern/solid/src/complex/DT_BBoxTree.cpp
@@ -0,0 +1,90 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_BBoxTree.h"
+
+inline DT_CBox getBBox(int first, int last, const DT_CBox *boxes, const DT_Index *indices) 
+{
+	assert(last - first >= 1);
+
+	DT_CBox bbox = boxes[indices[first]];
+	int i;
+	for (i = first; i < last; ++i) 
+	{
+		bbox = bbox.hull(boxes[indices[i]]);
+	}
+
+	return bbox;
+}
+
+DT_BBoxNode::DT_BBoxNode(int first, int last, int& node, DT_BBoxNode *free_nodes, const DT_CBox *boxes, DT_Index *indices, const DT_CBox& bbox)
+{
+	assert(last - first >= 2);
+	
+	int axis = bbox.longestAxis();
+	MT_Scalar abscissa = bbox.getCenter()[axis];
+	int i = first, mid = last;
+	while (i < mid) 
+	{
+		if (boxes[indices[i]].getCenter()[axis] < abscissa)
+		{
+			++i;
+		}
+		else
+		{
+			--mid;
+			std::swap(indices[i], indices[mid]);
+		}
+	}
+
+	if (mid == first || mid == last) 
+	{
+		mid = (first + last) / 2;
+	}
+	
+	m_lbox = getBBox(first, mid, boxes, indices);
+	m_rbox = getBBox(mid, last, boxes, indices);
+	m_flags = 0x0;
+
+	if (mid - first == 1)
+	{
+		m_flags |= LLEAF;
+		m_lchild = indices[first];
+	}
+	else 
+	{	
+		m_lchild = node++;
+		new(&free_nodes[m_lchild]) DT_BBoxNode(first, mid, node, free_nodes, boxes, indices, m_lbox);
+	}
+
+	if (last - mid == 1)
+	{
+		m_flags |= RLEAF;
+		m_rchild = indices[mid];
+	}
+	else 
+	{
+		m_rchild = node++;
+		new(&free_nodes[m_rchild]) DT_BBoxNode(mid, last, node, free_nodes, boxes, indices, m_rbox); 
+	}
+}
diff --git a/extern/solid/src/complex/DT_BBoxTree.h b/extern/solid/src/complex/DT_BBoxTree.h
new file mode 100644
index 00000000000..3d9da6e34ba
--- /dev/null
+++ b/extern/solid/src/complex/DT_BBoxTree.h
@@ -0,0 +1,540 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_BBOXTREE_H
+#define DT_BBOXTREE_H
+
+#include 
+#include 
+
+#include "DT_Convex.h"
+#include "DT_CBox.h"
+
+
+class DT_BBoxTree {
+public:
+    enum NodeType { INTERNAL = 0, LEAF = 1 };
+    
+    DT_BBoxTree() {}
+    DT_BBoxTree(const DT_CBox& cbox, DT_Index index, NodeType type) 
+      : m_cbox(cbox),
+        m_index(index),
+        m_type(type)
+    {}
+    
+    DT_CBox  m_cbox;
+    DT_Index m_index;
+    NodeType m_type;
+};
+
+
+
+class DT_BBoxNode {
+public:
+    DT_BBoxNode() {}    
+    DT_BBoxNode(int first, int last, int& node, DT_BBoxNode *free_nodes, const DT_CBox *boxes, DT_Index *indices, const DT_CBox& bbox);
+
+    void makeChildren(DT_BBoxTree& ltree, DT_BBoxTree& rtree) const;
+    void makeChildren(const DT_CBox& added, DT_BBoxTree& ltree, DT_BBoxTree& rtree) const;
+
+    DT_CBox hull() const { return m_lbox.hull(m_rbox); }  
+    
+    enum FlagType { LLEAF = 0x80, RLEAF = 0x40 };
+
+    DT_CBox              m_lbox;
+    DT_CBox              m_rbox;
+    DT_Index             m_lchild;
+    DT_Index             m_rchild;
+    unsigned char        m_flags;
+};
+
+inline void DT_BBoxNode::makeChildren(DT_BBoxTree& ltree, DT_BBoxTree& rtree) const
+{
+    new (<ree) DT_BBoxTree(m_lbox, m_lchild, (m_flags & LLEAF) ? DT_BBoxTree::LEAF : DT_BBoxTree::INTERNAL);
+    new (&rtree) DT_BBoxTree(m_rbox, m_rchild, (m_flags & RLEAF) ? DT_BBoxTree::LEAF : DT_BBoxTree::INTERNAL);
+
+}
+
+inline void DT_BBoxNode::makeChildren(const DT_CBox& added, DT_BBoxTree& ltree, DT_BBoxTree& rtree) const
+{ 
+    new (<ree) DT_BBoxTree(m_lbox + added, m_lchild, (m_flags & LLEAF) ? DT_BBoxTree::LEAF : DT_BBoxTree::INTERNAL);
+    new (&rtree) DT_BBoxTree(m_rbox + added, m_rchild, (m_flags & RLEAF) ? DT_BBoxTree::LEAF : DT_BBoxTree::INTERNAL);
+}
+
+
+template 
+class DT_RootData {
+public:
+    DT_RootData(const DT_BBoxNode *nodes, 
+                const Shape *leaves) 
+      : m_nodes(nodes),
+        m_leaves(leaves)
+    {}
+
+    const DT_BBoxNode   *m_nodes;
+    const Shape         *m_leaves;
+};
+
+template 
+class DT_ObjectData : public DT_RootData {
+public:
+    DT_ObjectData(const DT_BBoxNode *nodes, 
+                  const Shape1 *leaves, 
+                  const MT_Transform& xform, 
+                  Shape2 plus) 
+      : DT_RootData(nodes, leaves),
+        m_xform(xform),
+        m_inv_xform(xform.inverse()),   
+        m_plus(plus),
+        m_added(computeCBox(plus, m_inv_xform))
+    {}
+
+    const MT_Transform&  m_xform;
+    MT_Transform         m_inv_xform;
+    Shape2               m_plus;
+    DT_CBox              m_added;
+};
+
+template 
+class DT_Pack {
+public:
+    DT_Pack(const DT_ObjectData& a, const DT_Convex& b)
+      : m_a(a),
+        m_b(b),
+        m_b_cbox(b.bbox(m_a.m_inv_xform))
+    {}
+    
+    DT_ObjectData  m_a;
+    const DT_Convex&               m_b;
+    DT_CBox                        m_b_cbox;
+};
+
+template 
+class DT_HybridPack : public DT_Pack {
+public:
+    DT_HybridPack(const DT_ObjectData& a, const DT_Convex& b, MT_Scalar margin)
+      : DT_Pack(a, b),
+        m_margin(margin)
+    {
+        this->m_b_cbox += computeCBox(margin, this->m_a.m_inv_xform);
+    }
+    
+    MT_Scalar m_margin;
+};
+
+template 
+class DT_DuoPack {
+public:
+    DT_DuoPack(const DT_ObjectData& a, const DT_ObjectData& b) 
+      : m_a(a),
+        m_b(b)
+    {
+        m_b2a = a.m_inv_xform * b.m_xform;
+        m_a2b = b.m_inv_xform * a.m_xform;
+        m_abs_b2a = m_b2a.getBasis().absolute();
+        m_abs_a2b = m_a2b.getBasis().absolute();    
+    }
+    
+    DT_ObjectData  m_a, m_b;
+    MT_Transform                   m_b2a, m_a2b;
+    MT_Matrix3x3                   m_abs_b2a, m_abs_a2b;
+};
+
+
+template 
+inline void refit(DT_BBoxNode& node, const DT_RootData& rd)
+{
+    node.m_lbox = (node.m_flags & DT_BBoxNode::LLEAF) ? 
+                  computeCBox(rd.m_leaves[node.m_lchild]) : 
+                  rd.m_nodes[node.m_lchild].hull(); 
+    node.m_rbox = (node.m_flags & DT_BBoxNode::RLEAF) ? 
+                  computeCBox(rd.m_leaves[node.m_rchild]) : 
+                  rd.m_nodes[node.m_rchild].hull(); 
+}
+
+
+template 
+bool ray_cast(const DT_BBoxTree& a, const DT_RootData& rd,
+              const MT_Point3& source, const MT_Point3& target, 
+              MT_Scalar& lambda, MT_Vector3& normal) 
+{
+    if (!a.m_cbox.overlapsLineSegment(source, source.lerp(target, lambda))) 
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    { 
+        return ray_cast(rd, a.m_index, source, target, lambda, normal); 
+    }
+    else 
+    {
+        DT_BBoxTree ltree, rtree;
+        rd.m_nodes[a.m_index].makeChildren(ltree, rtree);
+        
+        bool lresult = ray_cast(ltree, rd, source, target, lambda, normal);
+        bool rresult = ray_cast(rtree, rd, source, target, lambda, normal);
+        return lresult || rresult;
+    }
+}
+
+
+#ifdef STATISTICS
+int num_box_tests = 0;
+#endif
+
+template 
+inline bool intersect(const DT_CBox& a, const DT_CBox& b, const DT_DuoPack& pack)
+{
+#ifdef STATISTICS
+    ++num_box_tests;
+#endif
+
+    
+    MT_Vector3 abs_pos_b2a = (pack.m_b2a(b.getCenter()) - a.getCenter()).absolute();
+    MT_Vector3 abs_pos_a2b = (pack.m_a2b(a.getCenter()) - b.getCenter()).absolute();
+    return  (a.getExtent()[0] + pack.m_abs_b2a[0].dot(b.getExtent()) >=  abs_pos_b2a[0]) && 
+            (a.getExtent()[1] + pack.m_abs_b2a[1].dot(b.getExtent()) >=  abs_pos_b2a[1]) && 
+            (a.getExtent()[2] + pack.m_abs_b2a[2].dot(b.getExtent()) >=  abs_pos_b2a[2]) && 
+            (b.getExtent()[0] + pack.m_abs_a2b[0].dot(a.getExtent()) >=  abs_pos_a2b[0]) && 
+            (b.getExtent()[1] + pack.m_abs_a2b[1].dot(a.getExtent()) >=  abs_pos_a2b[1]) &&
+            (b.getExtent()[2] + pack.m_abs_a2b[2].dot(a.getExtent()) >=  abs_pos_a2b[2]);
+}
+
+
+
+
+template 
+bool intersect(const DT_BBoxTree& a, const DT_Pack& pack, MT_Vector3& v)
+{ 
+    if (!a.m_cbox.overlaps(pack.m_b_cbox)) 
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    {
+        return intersect(pack, a.m_index, v);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        return intersect(a_ltree, pack, v) || intersect(a_rtree, pack, v);
+    }
+}
+
+template 
+bool intersect(const DT_BBoxTree& a, const DT_BBoxTree& b, const DT_DuoPack& pack, MT_Vector3& v)
+{ 
+    if (!intersect(a.m_cbox, b.m_cbox, pack)) 
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF && b.m_type == DT_BBoxTree::LEAF) 
+    {
+        return intersect(pack, a.m_index, b.m_index, v);
+    }
+    else if (a.m_type == DT_BBoxTree::LEAF || 
+             (b.m_type != DT_BBoxTree::LEAF && a.m_cbox.size() < b.m_cbox.size())) 
+    {
+        DT_BBoxTree b_ltree, b_rtree;
+        pack.m_b.m_nodes[b.m_index].makeChildren(pack.m_b.m_added, b_ltree, b_rtree);
+
+        return intersect(a, b_ltree, pack, v) || intersect(a, b_rtree, pack, v);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        return intersect(a_ltree, b, pack, v) || intersect(a_rtree, b, pack, v);
+    }
+}
+
+template 
+bool common_point(const DT_BBoxTree& a, const DT_Pack& pack,  
+                  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{ 
+    if (!a.m_cbox.overlaps(pack.m_b_cbox))
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    {
+        return common_point(pack, a.m_index, v, pa, pb);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        return common_point(a_ltree, pack, v, pa, pb) ||
+               common_point(a_rtree, pack, v, pa ,pb);
+    }
+}
+
+template 
+bool common_point(const DT_BBoxTree& a, const DT_BBoxTree& b, const DT_DuoPack& pack,  
+                  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{ 
+    if (!intersect(a.m_cbox, b.m_cbox, pack))
+    {
+        return false;
+    }
+
+    if (a.m_type == DT_BBoxTree::LEAF && b.m_type == DT_BBoxTree::LEAF) 
+    {
+        return common_point(pack, a.m_index, b.m_index, v, pa, pb);
+    }
+    else if (a.m_type == DT_BBoxTree::LEAF || 
+             (b.m_type != DT_BBoxTree::LEAF && a.m_cbox.size() < b.m_cbox.size())) 
+    {
+        DT_BBoxTree b_ltree, b_rtree;
+        pack.m_b.m_nodes[b.m_index].makeChildren(pack.m_b.m_added, b_ltree, b_rtree);
+        return common_point(a, b_ltree, pack, v, pa, pb) ||
+               common_point(a, b_rtree, pack, v, pa, pb);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        return common_point(a_ltree, b, pack, v, pa, pb) ||
+               common_point(a_rtree, b, pack, v, pa ,pb);
+    }
+}
+
+
+template 
+bool penetration_depth(const DT_BBoxTree& a, const DT_HybridPack& pack, 
+                       MT_Vector3& v, MT_Point3& pa, MT_Point3& pb, MT_Scalar& max_pen_len) 
+{ 
+    if (!a.m_cbox.overlaps(pack.m_b_cbox))
+    {
+        return false;
+    }
+    
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    {
+        if (penetration_depth(pack, a.m_index, v, pa, pb))
+        {
+            max_pen_len = pa.distance2(pb);
+            return true;
+        }
+        else 
+        {
+            return false;
+        }
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        if (penetration_depth(a_ltree, pack, v, pa, pb, max_pen_len)) 
+        {
+            MT_Vector3 rv;
+            MT_Point3 rpa, rpb;
+            MT_Scalar rmax_pen_len;
+            if (penetration_depth(a_rtree, pack, rv, rpa, rpb, rmax_pen_len) &&
+                (max_pen_len < rmax_pen_len))
+            {
+                max_pen_len = rmax_pen_len;
+                v = rv;
+                pa = rpa;
+                pb = rpb;
+            }
+            return true;
+        }
+        else 
+        {
+            return penetration_depth(a_rtree, pack, v, pa, pb, max_pen_len);
+        }
+    }
+}
+
+template 
+bool penetration_depth(const DT_BBoxTree& a, const DT_BBoxTree& b, const DT_DuoPack& pack, 
+                       MT_Vector3& v, MT_Point3& pa, MT_Point3& pb, MT_Scalar& max_pen_len) 
+{ 
+    if (!intersect(a.m_cbox, b.m_cbox, pack))
+    {
+        return false;
+    }
+  
+    if (a.m_type == DT_BBoxTree::LEAF && b.m_type == DT_BBoxTree::LEAF) 
+    {
+        if (penetration_depth(pack, a.m_index, b.m_index, v, pa, pb))
+        {
+            max_pen_len = pa.distance2(pb);
+            return true;
+        }
+        else 
+        {
+            return false;
+        }
+    }
+    else if (a.m_type == DT_BBoxTree::LEAF || 
+             (b.m_type != DT_BBoxTree::LEAF && a.m_cbox.size() < b.m_cbox.size())) 
+    {
+        DT_BBoxTree b_ltree, b_rtree;
+        pack.m_b.m_nodes[b.m_index].makeChildren(pack.m_b.m_added, b_ltree, b_rtree);
+        if (penetration_depth(a, b_ltree, pack, v, pa, pb, max_pen_len)) 
+        {
+            MT_Point3 rpa, rpb;
+            MT_Scalar rmax_pen_len;
+            if (penetration_depth(a, b_rtree, pack, v, rpa, rpb, rmax_pen_len) &&
+                (max_pen_len < rmax_pen_len))
+            {
+                max_pen_len = rmax_pen_len;
+                pa = rpa;
+                pb = rpb;
+            }
+            return true;
+        }
+        else
+        {
+            return penetration_depth(a, b_rtree, pack, v, pa, pb, max_pen_len);
+        }
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        if (penetration_depth(a_ltree, b, pack, v, pa, pb, max_pen_len)) 
+        {
+            MT_Point3 rpa, rpb;
+            MT_Scalar rmax_pen_len;
+            if (penetration_depth(a_rtree, b, pack, v, rpa, rpb, rmax_pen_len) &&
+                (max_pen_len < rmax_pen_len))
+            {
+                max_pen_len = rmax_pen_len;
+                pa = rpa;
+                pb = rpb;
+            }
+            return true;
+        }
+        else 
+        {
+            return penetration_depth(a_rtree, b, pack, v, pa, pb, max_pen_len);
+        }
+    }
+}
+
+
+// Returns a lower bound for the distance for quick rejection in closest_points
+inline MT_Scalar distance2(const DT_CBox& a, const MT_Transform& a2w,
+                           const DT_CBox& b, const MT_Transform& b2w)
+{
+    MT_Vector3 v = b2w(b.getCenter()) - a2w(a.getCenter());
+    MT_Scalar dist2 = v.length2();
+    if (dist2 > MT_Scalar(0.0))
+    {
+        MT_Vector3 w = b2w(b.support(-v * b2w.getBasis())) - a2w(a.support(v * a2w.getBasis()));
+        MT_Scalar delta = v.dot(w);
+        return delta > MT_Scalar(0.0) ? delta * delta / dist2 : MT_Scalar(0.0);
+    }
+    return MT_Scalar(0.0);
+}
+
+
+template 
+MT_Scalar closest_points(const DT_BBoxTree& a, const DT_Pack& pack, 
+                         MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb) 
+{ 
+    if (a.m_type == DT_BBoxTree::LEAF) 
+    {
+        return closest_points(pack, a.m_index, max_dist2, pa, pb);
+    }
+    else 
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        MT_Scalar ldist2 = distance2(a_ltree.m_cbox, pack.m_a.m_xform, pack.m_b_cbox, pack.m_a.m_xform);
+        MT_Scalar rdist2 = distance2(a_rtree.m_cbox, pack.m_a.m_xform, pack.m_b_cbox, pack.m_a.m_xform);
+        if (ldist2 < rdist2) 
+        {
+            MT_Scalar dist2 = ldist2 < max_dist2 ? closest_points(a_ltree, pack, max_dist2, pa, pb) : MT_INFINITY;
+            GEN_set_min(max_dist2, dist2);
+            return rdist2 < max_dist2 ? GEN_min(dist2, closest_points(a_rtree, pack, max_dist2, pa, pb)) : dist2;
+        }
+        else
+        {
+            MT_Scalar dist2 = rdist2 < max_dist2 ? closest_points(a_rtree, pack, max_dist2, pa, pb) : MT_INFINITY;
+            GEN_set_min(max_dist2, dist2);  
+            return ldist2 < max_dist2 ? GEN_min(dist2, closest_points(a_ltree, pack, max_dist2, pa, pb)) : dist2;       
+        }
+    }
+}
+
+    
+template 
+MT_Scalar closest_points(const DT_BBoxTree& a, const DT_BBoxTree& b, const DT_DuoPack& pack, 
+                         MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb) 
+{   
+    if (a.m_type == DT_BBoxTree::LEAF && b.m_type == DT_BBoxTree::LEAF) 
+    {
+        return closest_points(pack, a.m_index, b.m_index, max_dist2, pa, pb);
+    }
+    else if (a.m_type == DT_BBoxTree::LEAF || 
+             (b.m_type != DT_BBoxTree::LEAF && a.m_cbox.size() < b.m_cbox.size())) 
+    {
+        DT_BBoxTree b_ltree, b_rtree;
+        pack.m_b.m_nodes[b.m_index].makeChildren(pack.m_b.m_added, b_ltree, b_rtree);
+        MT_Scalar ldist2 = distance2(a.m_cbox, pack.m_a.m_xform, b_ltree.m_cbox, pack.m_b.m_xform);
+        MT_Scalar rdist2 = distance2(a.m_cbox, pack.m_a.m_xform, b_rtree.m_cbox, pack.m_b.m_xform);
+        if (ldist2 < rdist2)
+        {
+            MT_Scalar dist2 = ldist2 < max_dist2 ? closest_points(a, b_ltree, pack, max_dist2, pa, pb): MT_INFINITY;;
+            GEN_set_min(max_dist2, dist2);
+            return rdist2 < max_dist2 ? GEN_min(dist2, closest_points(a, b_rtree, pack, max_dist2, pa, pb)) : dist2;        
+        }
+        else
+        {
+            MT_Scalar dist2 =  rdist2 < max_dist2 ? closest_points(a, b_rtree, pack, max_dist2, pa, pb) : MT_INFINITY;;
+            GEN_set_min(max_dist2, dist2);
+            return ldist2 < max_dist2 ? GEN_min(dist2, closest_points(a, b_ltree, pack, max_dist2, pa, pb)) : dist2;
+        }
+    }
+    else
+    {
+        DT_BBoxTree a_ltree, a_rtree;
+        pack.m_a.m_nodes[a.m_index].makeChildren(pack.m_a.m_added, a_ltree, a_rtree);
+        MT_Scalar ldist2 = distance2(a_ltree.m_cbox, pack.m_a.m_xform, b.m_cbox, pack.m_b.m_xform);
+        MT_Scalar rdist2 = distance2(a_rtree.m_cbox, pack.m_a.m_xform, b.m_cbox, pack.m_b.m_xform);
+        if (ldist2 < rdist2) 
+        {
+            MT_Scalar dist2 = ldist2 < max_dist2 ? closest_points(a_ltree, b, pack, max_dist2, pa, pb) : MT_INFINITY;;
+            GEN_set_min(max_dist2, dist2);
+            return rdist2 < max_dist2 ? GEN_min(dist2,closest_points(a_rtree, b, pack, max_dist2, pa, pb)) : dist2;
+        }
+        else
+        {
+            MT_Scalar dist2 = rdist2 < max_dist2 ? closest_points(a_rtree, b, pack, max_dist2, pa, pb) : MT_INFINITY;
+            GEN_set_min(max_dist2, dist2);
+            return ldist2 < max_dist2 ? GEN_min(dist2, closest_points(a_ltree, b, pack, max_dist2, pa, pb)) : dist2;
+        }
+    }
+}
+
+#endif
+
diff --git a/extern/solid/src/complex/DT_CBox.h b/extern/solid/src/complex/DT_CBox.h
new file mode 100644
index 00000000000..7fc7c5df4db
--- /dev/null
+++ b/extern/solid/src/complex/DT_CBox.h
@@ -0,0 +1,134 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_CBOX_H
+#define DT_CBOX_H
+
+#include "MT_BBox.h"
+
+struct DT_CBox {
+    DT_CBox() {}
+    DT_CBox(const MT_Point3& center, const MT_Vector3& extent) 
+      : m_center(center),
+        m_extent(extent)
+    {}
+
+    explicit DT_CBox(const MT_BBox& bbox) { set(bbox); }
+
+    const MT_Point3& getCenter() const { return m_center; }
+    const MT_Vector3& getExtent() const { return m_extent; }
+
+    void set(const MT_BBox& bbox)
+    {
+        m_center = bbox.getCenter();
+        m_extent = bbox.getExtent();
+    }
+ 
+    MT_BBox get() const
+    {
+        return MT_BBox(m_center - m_extent, m_center + m_extent);
+    }
+
+    MT_Scalar size() const  
+    {
+        return GEN_max(GEN_max(m_extent[0], m_extent[1]), m_extent[2]);
+    }
+
+
+    DT_CBox& operator+=(const DT_CBox& box)
+    {
+        m_center += box.getCenter();
+        m_extent += box.getExtent();
+        return *this;
+    }
+    
+    int longestAxis() const { return m_extent.closestAxis(); }
+        
+    DT_CBox hull(const DT_CBox& b) const 
+    {
+        return DT_CBox(this->get().hull(b.get()));
+    }
+
+    bool overlaps(const DT_CBox& b) const 
+    {
+        return MT_abs(m_center[0] - b.m_center[0]) <= m_extent[0] + b.m_extent[0] &&
+               MT_abs(m_center[1] - b.m_center[1]) <= m_extent[1] + b.m_extent[1] &&
+               MT_abs(m_center[2] - b.m_center[2]) <= m_extent[2] + b.m_extent[2];
+    }
+    
+    bool overlapsLineSegment(const MT_Point3& p, const MT_Point3& q) const 
+    {
+        MT_Vector3 r = q - p;   
+        MT_Vector3 r_abs = r.absolute();
+        
+        if (!overlaps(DT_CBox(p + r * MT_Scalar(0.5), r_abs * MT_Scalar(0.5))))
+        {
+            return false;
+        }
+        
+        MT_Vector3 s = p - m_center;
+
+        if (MT_abs(r[2] * s[1] - r[1] * s[2]) > r_abs[2] * m_extent[1] + r_abs[1] * m_extent[2])
+        {
+            return false;
+        }
+                    
+        if (MT_abs(r[0] * s[2] - r[2] * s[0]) > r_abs[0] * m_extent[2] + r_abs[2] * m_extent[0])
+        {
+            return false;
+        }
+                    
+        if (MT_abs(r[1] * s[0] - r[0] * s[1]) > r_abs[1] * m_extent[0] + r_abs[0] * m_extent[1])
+        {
+            return false;
+        }
+            
+        return true;
+    }
+    
+    MT_Point3 support(const MT_Vector3& v) const 
+    {
+        return m_center + MT_Vector3(v[0] < MT_Scalar(0.0) ? -m_extent[0] : m_extent[0],
+                                     v[1] < MT_Scalar(0.0) ? -m_extent[1] : m_extent[1],
+                                     v[2] < MT_Scalar(0.0) ? -m_extent[2] : m_extent[2]); 
+    
+    }
+
+private:
+    MT_Point3  m_center;
+    MT_Vector3 m_extent;
+};
+
+inline DT_CBox operator+(const DT_CBox& b1, const DT_CBox& b2) 
+{
+    return DT_CBox(b1.getCenter() + b2.getCenter(), 
+                   b1.getExtent() + b2.getExtent());
+}
+
+inline DT_CBox operator-(const DT_CBox& b1, const DT_CBox& b2) 
+{
+    return DT_CBox(b1.getCenter() - b2.getCenter(), 
+                   b1.getExtent() + b2.getExtent());
+}
+
+#endif
diff --git a/extern/solid/src/complex/DT_Complex.cpp b/extern/solid/src/complex/DT_Complex.cpp
new file mode 100644
index 00000000000..023383a8427
--- /dev/null
+++ b/extern/solid/src/complex/DT_Complex.cpp
@@ -0,0 +1,327 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include 
+#include 
+
+#include "DT_Complex.h"
+#include "DT_Minkowski.h"
+#include "DT_Sphere.h"
+#include "DT_Transform.h"
+
+DT_Complex::DT_Complex(const DT_VertexBase *base) 
+  : m_base(base),
+    m_count(0),
+    m_leaves(0),
+	m_nodes(0)
+{ 
+	assert(base);
+	base->addComplex(this);
+}
+
+
+DT_Complex::~DT_Complex()
+{
+    DT_Index i;
+    for (i = 0; i != m_count; ++i) 
+    {
+        delete m_leaves[i];
+    }
+    delete [] m_leaves;
+    delete [] m_nodes;
+    
+    m_base->removeComplex(this);
+    if (m_base->isOwner()) 
+    {
+        delete m_base;
+    }
+}
+
+void DT_Complex::finish(DT_Count n, const DT_Convex *p[]) 
+{
+	m_count = n;
+
+   
+    assert(n >= 1);
+
+    m_leaves = new const DT_Convex *[n];
+    assert(m_leaves);
+
+    DT_CBox *boxes = new DT_CBox[n];
+    DT_Index *indices = new DT_Index[n];
+    assert(boxes);
+       
+    DT_Index i;
+    for (i = 0; i != n; ++i) 
+    {
+        m_leaves[i] = p[i];
+        boxes[i].set(p[i]->bbox());
+        indices[i] = i;
+    }
+
+    m_cbox = boxes[0];
+    for (i = 1; i != n; ++i) 
+    {
+        m_cbox = m_cbox.hull(boxes[i]);
+    }
+
+    if (n == 1)
+    {
+        m_nodes = 0;
+        m_type = DT_BBoxTree::LEAF;
+    }
+    else 
+    {
+        m_nodes = new DT_BBoxNode[n - 1];
+        assert(m_nodes);
+    
+        int num_nodes = 0;
+        new(&m_nodes[num_nodes++]) DT_BBoxNode(0, n, num_nodes, m_nodes, boxes, indices, m_cbox);
+
+        assert(num_nodes == n - 1);
+        
+        m_type = DT_BBoxTree::INTERNAL;
+    }
+
+    delete [] boxes;
+}
+
+
+MT_BBox DT_Complex::bbox(const MT_Transform& t, MT_Scalar margin) const 
+{
+    MT_Matrix3x3 abs_b = t.getBasis().absolute();  
+    MT_Point3 center = t(m_cbox.getCenter());
+    MT_Vector3 extent(margin + abs_b[0].dot(m_cbox.getExtent()),
+                      margin + abs_b[1].dot(m_cbox.getExtent()),
+                      margin + abs_b[2].dot(m_cbox.getExtent()));
+    
+    return MT_BBox(center - extent, center + extent);
+}
+
+inline DT_CBox computeCBox(const DT_Convex *p)
+{
+    return DT_CBox(p->bbox()); 
+}
+
+inline DT_CBox computeCBox(MT_Scalar margin, const MT_Transform& xform) 
+{
+    const MT_Matrix3x3& basis = xform.getBasis();
+    return DT_CBox(MT_Point3(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)), 
+                   MT_Vector3(basis[0].length() * margin, 
+                              basis[1].length() * margin, 
+                              basis[2].length() * margin));
+} 
+
+void DT_Complex::refit()
+{
+    DT_RootData rd(m_nodes, m_leaves);
+    DT_Index i = m_count - 1;
+    while (i--)
+    {
+        ::refit(m_nodes[i], rd);
+    }
+    m_cbox = m_type == DT_BBoxTree::LEAF ? computeCBox(m_leaves[0]) : m_nodes[0].hull();
+}
+
+inline bool ray_cast(const DT_RootData& rd, DT_Index index, const MT_Point3& source, const MT_Point3& target, 
+                     MT_Scalar& lambda, MT_Vector3& normal)
+{
+    return rd.m_leaves[index]->ray_cast(source, target, lambda, normal);
+}
+
+bool DT_Complex::ray_cast(const MT_Point3& source, const MT_Point3& target,
+                          MT_Scalar& lambda, MT_Vector3& normal) const 
+{
+    DT_RootData rd(m_nodes, m_leaves);
+
+    return ::ray_cast(DT_BBoxTree(m_cbox, 0, m_type), rd, source, target, lambda, normal);
+}
+
+inline bool intersect(const DT_Pack& pack, DT_Index a_index, MT_Vector3& v) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    return ::intersect((a_margin > MT_Scalar(0.0) ? 
+                        static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) :  
+                        static_cast(ta)), 
+                       pack.m_b, v); 
+}
+
+bool intersect(const DT_Complex& a,  const MT_Transform& a2w,  MT_Scalar a_margin, 
+               const DT_Convex& b, MT_Vector3& v) 
+{
+    DT_Pack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin), b);
+
+    return intersect(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type), pack, v);
+}
+
+inline bool intersect(const DT_DuoPack& pack, DT_Index a_index, DT_Index b_index, MT_Vector3& v) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    DT_Transform tb = DT_Transform(pack.m_b.m_xform, *pack.m_b.m_leaves[b_index]);
+    MT_Scalar b_margin = pack.m_b.m_plus;
+    return ::intersect((a_margin > MT_Scalar(0.0) ?
+                        static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : 
+                        static_cast(ta)), 
+                       (b_margin > MT_Scalar(0.0) ? 
+                        static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : 
+                        static_cast(tb)), 
+                       v);   
+}
+
+bool intersect(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+               const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin, MT_Vector3& v) 
+{
+    DT_DuoPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin),
+                                                  DT_ObjectData(b.m_nodes, b.m_leaves, b2w, b_margin));
+
+
+    return intersect(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type),
+                     DT_BBoxTree(b.m_cbox + pack.m_b.m_added, 0, b.m_type), pack, v);
+}
+
+inline bool common_point(const DT_Pack& pack, DT_Index a_index, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    return ::common_point((a_margin > MT_Scalar(0.0) ? 
+                           static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) :
+                           static_cast(ta)), 
+                          pack.m_b, v, pa, pb); 
+}
+    
+bool common_point(const DT_Complex& a,  const MT_Transform& a2w,  MT_Scalar a_margin, 
+                  const DT_Convex& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+     DT_Pack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin), b);
+
+    return common_point(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type), pack, v, pb, pa);
+}
+
+inline bool common_point(const DT_DuoPack& pack, DT_Index a_index, DT_Index b_index, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    DT_Transform tb = DT_Transform(pack.m_b.m_xform, *pack.m_b.m_leaves[b_index]);
+    MT_Scalar b_margin = pack.m_b.m_plus;
+    return ::common_point((a_margin > MT_Scalar(0.0) ? 
+                           static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : 
+                           static_cast(ta)), 
+                          (b_margin > MT_Scalar(0.0) ? 
+                           static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : 
+                           static_cast(tb)), 
+                          v, pa, pb);    
+}
+    
+bool common_point(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+                  const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin, 
+                  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_DuoPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin),
+                                                  DT_ObjectData(b.m_nodes, b.m_leaves, b2w, b_margin));
+
+    return common_point(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type),
+                        DT_BBoxTree(b.m_cbox + pack.m_b.m_added, 0, b.m_type),  pack, v, pa, pb);
+}
+
+inline bool penetration_depth(const DT_HybridPack& pack, DT_Index a_index, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    return ::hybrid_penetration_depth(ta, pack.m_a.m_plus, pack.m_b, pack.m_margin, v, pa, pb); 
+}
+
+bool penetration_depth(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+                       const DT_Convex& b, MT_Scalar b_margin, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_HybridPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin), b, b_margin);
+     
+    MT_Scalar  max_pen_len = MT_Scalar(0.0);
+    return penetration_depth(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type), pack, v, pa, pb, max_pen_len);
+}
+
+inline bool penetration_depth(const DT_DuoPack& pack, DT_Index a_index, DT_Index b_index, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    DT_Transform tb = DT_Transform(pack.m_b.m_xform, *pack.m_b.m_leaves[b_index]);
+    return ::hybrid_penetration_depth(ta, pack.m_a.m_plus, tb, pack.m_a.m_plus, v, pa, pb);  
+}
+
+bool penetration_depth(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+                       const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin, 
+                       MT_Vector3& v, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_DuoPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin),
+                                                  DT_ObjectData(b.m_nodes, b.m_leaves, b2w, b_margin));
+
+    MT_Scalar  max_pen_len = MT_Scalar(0.0);
+    return penetration_depth(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type),
+                             DT_BBoxTree(b.m_cbox + pack.m_b.m_added, 0, b.m_type), pack, v, pa, pb, max_pen_len);
+}
+
+
+
+inline MT_Scalar closest_points(const DT_Pack& pack, DT_Index a_index, MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    return ::closest_points((a_margin > MT_Scalar(0.0) ? 
+                             static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) :  
+                             static_cast(ta)), 
+                            pack.m_b, max_dist2, pa, pb); 
+}
+
+MT_Scalar closest_points(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+                         const DT_Convex& b, MT_Point3& pa, MT_Point3& pb)
+{
+    DT_Pack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin), b);
+
+    return closest_points(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type), pack, MT_INFINITY, pa, pb); 
+}
+
+inline MT_Scalar closest_points(const DT_DuoPack& pack, DT_Index a_index, DT_Index b_index, MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_Transform ta = DT_Transform(pack.m_a.m_xform, *pack.m_a.m_leaves[a_index]);
+    MT_Scalar a_margin = pack.m_a.m_plus;
+    DT_Transform tb = DT_Transform(pack.m_b.m_xform, *pack.m_b.m_leaves[b_index]);
+    MT_Scalar b_margin = pack.m_b.m_plus;
+    return ::closest_points((a_margin > MT_Scalar(0.0) ? 
+                             static_cast(DT_Minkowski(ta, DT_Sphere(a_margin))) : 
+                             static_cast(ta)), 
+                            (b_margin > MT_Scalar(0.0) ? 
+                             static_cast(DT_Minkowski(tb, DT_Sphere(b_margin))) : 
+                             static_cast(tb)), max_dist2, pa, pb);     
+}
+
+MT_Scalar closest_points(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin,
+                         const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin, 
+                         MT_Point3& pa, MT_Point3& pb) 
+{
+    DT_DuoPack pack(DT_ObjectData(a.m_nodes, a.m_leaves, a2w, a_margin),
+                               DT_ObjectData(b.m_nodes, b.m_leaves, b2w, b_margin));
+
+    return closest_points(DT_BBoxTree(a.m_cbox + pack.m_a.m_added, 0, a.m_type),
+                          DT_BBoxTree(b.m_cbox + pack.m_b.m_added, 0, b.m_type), pack, MT_INFINITY, pa, pb);
+}
+
+
diff --git a/extern/solid/src/complex/DT_Complex.h b/extern/solid/src/complex/DT_Complex.h
new file mode 100644
index 00000000000..ae08a05d4c9
--- /dev/null
+++ b/extern/solid/src/complex/DT_Complex.h
@@ -0,0 +1,94 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_COMPLEX_H
+#define DT_COMPLEX_H
+
+#include 
+
+#include "MT_Transform.h"
+#include "DT_VertexBase.h"
+
+#include "DT_Shape.h"
+#include "DT_CBox.h"
+#include "DT_BBoxTree.h"
+
+class DT_Convex;
+
+class DT_Complex : public DT_Shape  {
+public:
+	DT_Complex(const DT_VertexBase *base);
+	virtual ~DT_Complex();
+	
+	void finish(DT_Count n, const DT_Convex *p[]);
+    
+	virtual DT_ShapeType getType() const { return COMPLEX; }
+
+    virtual MT_BBox bbox(const MT_Transform& t, MT_Scalar margin) const;
+
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target, 
+						  MT_Scalar& lambda, MT_Vector3& normal) const; 
+
+	void refit();
+	
+
+    friend bool intersect(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                  const DT_Convex& b, MT_Vector3& v);
+    
+    friend bool intersect(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                  const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                          MT_Vector3& v);
+   
+    friend bool common_point(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                     const DT_Convex& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+    
+    friend bool common_point(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                     const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                             MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+    
+    friend bool penetration_depth(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+								  const DT_Convex& b, MT_Scalar b_margin, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+    
+    friend bool penetration_depth(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+								  const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin,
+								  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+    friend MT_Scalar closest_points(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                            const DT_Convex& b, MT_Point3& pa, MT_Point3& pb);
+    
+    friend MT_Scalar closest_points(const DT_Complex& a, const MT_Transform& a2w, MT_Scalar a_margin, 
+		                            const DT_Complex& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									MT_Point3& pa, MT_Point3& pb);
+
+	const DT_VertexBase   *m_base;
+	DT_Count               m_count;
+	const DT_Convex      **m_leaves;
+	DT_BBoxNode           *m_nodes;
+	DT_CBox                m_cbox;
+	DT_BBoxTree::NodeType  m_type;
+};
+
+#endif
+
+
+
diff --git a/extern/solid/src/complex/Makefile b/extern/solid/src/complex/Makefile
new file mode 100644
index 00000000000..99e786276b0
--- /dev/null
+++ b/extern/solid/src/complex/Makefile
@@ -0,0 +1,45 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = solid_complex
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../../include -I$(NAN_QHULL)/include
+CPPFLAGS += -I../convex
+CPPFLAGS += -DQHULL -DUSE_DOUBLES
+
+include nan_compile.mk 
+
+
diff --git a/extern/solid/src/convex/DT_Accuracy.cpp b/extern/solid/src/convex/DT_Accuracy.cpp
new file mode 100644
index 00000000000..113275b0dbd
--- /dev/null
+++ b/extern/solid/src/convex/DT_Accuracy.cpp
@@ -0,0 +1,30 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Accuracy.h"
+
+static const MT_Scalar rel_error = MT_Scalar(1.0e-3);
+
+MT_Scalar DT_Accuracy::rel_error2 = rel_error * rel_error;
+MT_Scalar DT_Accuracy::depth_tolerance = MT_Scalar(1.0) + MT_Scalar(2.0) * rel_error; 
+MT_Scalar DT_Accuracy::tol_error = MT_EPSILON;
diff --git a/extern/solid/src/convex/DT_Accuracy.h b/extern/solid/src/convex/DT_Accuracy.h
new file mode 100644
index 00000000000..9759a6fd4c5
--- /dev/null
+++ b/extern/solid/src/convex/DT_Accuracy.h
@@ -0,0 +1,47 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_ACCURACY_H
+#define DT_ACCURACY_H
+
+#include "MT_Scalar.h"
+
+class DT_Accuracy {
+public:
+	static MT_Scalar rel_error2; // squared relative error in the computed distance
+	static MT_Scalar depth_tolerance; // terminate EPA if upper_bound <= depth_tolerance * dist2
+	static MT_Scalar tol_error; // error tolerance if the distance is almost zero
+	
+	static void setAccuracy(MT_Scalar rel_error) 
+	{ 
+		rel_error2 = rel_error * rel_error;
+		depth_tolerance = MT_Scalar(1.0) + MT_Scalar(2.0) * rel_error;
+	}	
+   
+	static void setTolerance(MT_Scalar epsilon) 
+	{ 
+		tol_error = epsilon;
+	}
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Array.h b/extern/solid/src/convex/DT_Array.h
new file mode 100644
index 00000000000..1694f884e53
--- /dev/null
+++ b/extern/solid/src/convex/DT_Array.h
@@ -0,0 +1,75 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_ARRAY_H
+#define DT_ARRAY_H
+
+#if defined (__sgi)
+#include 
+#else
+#include 
+#endif
+
+template 
+class DT_Array {
+public:
+	DT_Array() 
+      :	m_count(0), 
+		m_data(0) 
+	{}
+
+	explicit DT_Array(Size count)
+	  :	m_count(count),
+		m_data(new Data[count]) 
+	{
+		assert(m_data);
+	}
+	
+	DT_Array(Size count, const Data *data) 
+	  :	m_count(count),
+		m_data(new Data[count]) 
+	{
+		assert(m_data);		
+		std::copy(&data[0], &data[count], m_data);
+	}
+	
+	~DT_Array() 
+	{ 
+		delete [] m_data; 
+	}
+	
+	const Data& operator[](int i) const { return m_data[i]; }
+	Data&       operator[](int i)       { return m_data[i]; }
+
+	Size size() const { return m_count; }
+	
+private:
+	DT_Array(const DT_Array&);
+	DT_Array& operator=(const DT_Array&);
+
+	Size  m_count;
+	Data *m_data;
+};
+  
+#endif
+
diff --git a/extern/solid/src/convex/DT_Box.cpp b/extern/solid/src/convex/DT_Box.cpp
new file mode 100644
index 00000000000..0b46f566fe8
--- /dev/null
+++ b/extern/solid/src/convex/DT_Box.cpp
@@ -0,0 +1,112 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Box.h"
+
+MT_Scalar DT_Box::supportH(const MT_Vector3& v) const 
+{
+    return v.absolute().dot(m_extent);
+}
+
+MT_Point3 DT_Box::support(const MT_Vector3& v) const 
+{
+    return MT_Point3(v[0] < MT_Scalar(0.0) ? -m_extent[0] : m_extent[0],
+                     v[1] < MT_Scalar(0.0) ? -m_extent[1] : m_extent[1],
+                     v[2] < MT_Scalar(0.0) ? -m_extent[2] : m_extent[2]); 
+    
+}
+
+
+bool DT_Box::ray_cast(const MT_Point3& source, const MT_Point3& target,
+					  MT_Scalar& param, MT_Vector3& normal) const 
+{
+	T_Outcode source_bits = outcode(source);
+	T_Outcode target_bits = outcode(target);
+
+	if ((source_bits & target_bits) == 0x0)
+		// None of the side planes separate the ray from the box.
+	{
+		MT_Scalar lambda_enter = MT_Scalar(0.0);
+		MT_Scalar lambda_exit  = param;
+		MT_Vector3 r = target - source;
+		T_Outcode normal_bit = 0x0; // Indicates the axis that is returned as normal.
+		T_Outcode bit = 0x01;
+		int i;
+		for (i = 0; i != 3; ++i)
+		{
+			if (source_bits & bit)
+				// Point of intersection is entering
+			{
+				MT_Scalar lambda = (-source[i] - m_extent[i]) / r[i];
+				if (lambda_enter < lambda)
+				{
+					lambda_enter = lambda;
+					normal_bit = bit;
+				}
+			}
+			else if (target_bits & bit) 
+				// Point of intersection is exiting
+			{
+				MT_Scalar lambda = (-source[i] - m_extent[i]) / r[i];
+				GEN_set_min(lambda_exit, lambda);
+			}
+			bit <<=1;
+			if (source_bits & bit)
+				// Point of intersection is entering
+			{
+				MT_Scalar lambda =  (-source[i] + m_extent[i]) / r[i];
+				if (lambda_enter < lambda)
+				{
+					lambda_enter = lambda;
+					normal_bit = bit;
+				}
+			}
+			else if (target_bits & bit) 
+				// Point of intersection is exiting
+			{
+				MT_Scalar lambda =  (-source[i] + m_extent[i]) / r[i];
+				GEN_set_min(lambda_exit, lambda);
+			}
+			bit <<=1;
+		}
+		if (lambda_enter <= lambda_exit)
+			// The ray intersects the box
+		{
+			param = lambda_enter;
+			normal.setValue(normal_bit == 0x01 ? -MT_Scalar(1.0) : 
+							normal_bit == 0x02 ?  MT_Scalar(1.0) : 
+							MT_Scalar(0.0),
+							normal_bit == 0x04 ? -MT_Scalar(1.0) : 
+							normal_bit == 0x08 ?  MT_Scalar(1.0) : 
+							MT_Scalar(0.0),
+							normal_bit == 0x10 ? -MT_Scalar(1.0) : 
+							normal_bit == 0x20 ?  MT_Scalar(1.0) : 
+							MT_Scalar(0.0));
+			return true;
+		}
+	}
+
+	return false;
+}
+
+
diff --git a/extern/solid/src/convex/DT_Box.h b/extern/solid/src/convex/DT_Box.h
new file mode 100644
index 00000000000..ace9634b5e3
--- /dev/null
+++ b/extern/solid/src/convex/DT_Box.h
@@ -0,0 +1,62 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_BOX_H
+#define DT_BOX_H
+
+#include "DT_Convex.h"
+
+class DT_Box : public DT_Convex {
+public:
+    DT_Box(MT_Scalar x, MT_Scalar y, MT_Scalar z) : 
+        m_extent(x, y, z) 
+	{}
+
+    DT_Box(const MT_Vector3& e) : 
+		m_extent(e) 
+	{}
+
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target,
+						  MT_Scalar& param, MT_Vector3& normal) const;
+    
+    const MT_Vector3& getExtent() const { return m_extent; }
+	
+protected:
+	typedef unsigned int T_Outcode;
+	
+	T_Outcode outcode(const MT_Point3& p) const
+	{
+		return (p[0] < -m_extent[0] ? 0x01 : 0x0) |    
+			   (p[0] >  m_extent[0] ? 0x02 : 0x0) |
+			   (p[1] < -m_extent[1] ? 0x04 : 0x0) |    
+			   (p[1] >  m_extent[1] ? 0x08 : 0x0) |
+			   (p[2] < -m_extent[2] ? 0x10 : 0x0) |    
+			   (p[2] >  m_extent[2] ? 0x20 : 0x0);
+	}
+    
+    MT_Vector3 m_extent;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Cone.cpp b/extern/solid/src/convex/DT_Cone.cpp
new file mode 100644
index 00000000000..1dd6a7ddbbe
--- /dev/null
+++ b/extern/solid/src/convex/DT_Cone.cpp
@@ -0,0 +1,48 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Cone.h"
+
+MT_Point3 DT_Cone::support(const MT_Vector3& v) const 
+{
+    MT_Scalar v_len = v.length();
+
+    if (v[1] > v_len * sinAngle)
+	{
+		return MT_Point3(MT_Scalar(0.0), halfHeight, MT_Scalar(0.0));
+	}
+    else
+	{
+        MT_Scalar s = MT_sqrt(v[0] * v[0] + v[2] * v[2]);
+        if (s != MT_Scalar(0.0))
+		{
+            MT_Scalar d = bottomRadius / s;  
+            return MT_Point3(v[0] * d, -halfHeight, v[2] * d);
+        }
+        else
+		{
+			return MT_Point3(bottomRadius, -halfHeight, MT_Scalar(0.0));
+		}
+    }
+}
+
diff --git a/extern/solid/src/convex/DT_Cone.h b/extern/solid/src/convex/DT_Cone.h
new file mode 100644
index 00000000000..85e416877dd
--- /dev/null
+++ b/extern/solid/src/convex/DT_Cone.h
@@ -0,0 +1,45 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_CONE_H
+#define DT_CONE_H
+
+#include "DT_Convex.h"
+
+class DT_Cone : public DT_Convex {
+public:
+	DT_Cone(MT_Scalar r, MT_Scalar h) : 
+        bottomRadius(r), 
+        halfHeight(h * MT_Scalar(0.5)), 
+        sinAngle(r / MT_sqrt(r * r + h * h))
+    {} 
+  
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+  
+protected:
+    MT_Scalar bottomRadius;
+    MT_Scalar halfHeight;
+    MT_Scalar sinAngle;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Convex.cpp b/extern/solid/src/convex/DT_Convex.cpp
new file mode 100644
index 00000000000..3be47f6ed02
--- /dev/null
+++ b/extern/solid/src/convex/DT_Convex.cpp
@@ -0,0 +1,426 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Convex.h"
+#include "GEN_MinMax.h"
+
+//#define DEBUG
+#define SAFE_EXIT
+
+#include "DT_GJK.h"
+#include "DT_PenDepth.h"
+
+#include 
+#include 
+
+#include "MT_BBox.h"
+#include "DT_Sphere.h"
+#include "DT_Minkowski.h"
+
+#include "DT_Accuracy.h"
+
+#ifdef STATISTICS
+int num_iterations = 0;
+int num_irregularities = 0;
+#endif
+
+MT_BBox DT_Convex::bbox() const 
+{
+	MT_Point3 min(-supportH(MT_Vector3(-1.0f, 0.0f, 0.0f)),
+                  -supportH(MT_Vector3(0.0f, -1.0f, 0.0f)),
+				  -supportH(MT_Vector3(0.0f, 0.0f, -1.0f)));
+	MT_Point3 max( supportH(MT_Vector3(1.0f, 0.0f, 0.0f)),
+                   supportH(MT_Vector3(0.0f, 1.0f, 0.0f)),
+				   supportH(MT_Vector3(0.0f, 0.0f, 1.0f)));
+
+	
+    return MT_BBox(min, max);
+}
+
+MT_BBox DT_Convex::bbox(const MT_Matrix3x3& basis) const 
+{
+    MT_Point3 min(-supportH(-basis[0]),
+                  -supportH(-basis[1]),
+		          -supportH(-basis[2])); 
+    MT_Point3 max( supportH( basis[0]),
+                   supportH( basis[1]),
+                   supportH( basis[2])); 
+    return MT_BBox(min, max);
+}
+
+MT_BBox DT_Convex::bbox(const MT_Transform& t, MT_Scalar margin) const 
+{
+    MT_Point3 min(t.getOrigin()[0] - supportH(-t.getBasis()[0]) - margin,
+                  t.getOrigin()[1] - supportH(-t.getBasis()[1]) - margin,
+		          t.getOrigin()[2] - supportH(-t.getBasis()[2]) - margin); 
+    MT_Point3 max(t.getOrigin()[0] + supportH( t.getBasis()[0]) + margin,
+                  t.getOrigin()[1] + supportH( t.getBasis()[1]) + margin,
+                  t.getOrigin()[2] + supportH( t.getBasis()[2]) + margin); 
+    return MT_BBox(min, max);
+}
+
+bool DT_Convex::ray_cast(const MT_Point3& source, const MT_Point3& target, MT_Scalar& lambda, MT_Vector3& normal) const
+{
+	// Still working on this one...
+    return false;
+}
+
+bool intersect(const DT_Convex& a, const DT_Convex& b, MT_Vector3& v)
+{
+	DT_GJK gjk;
+
+#ifdef STATISTICS
+    num_iterations = 0;
+#endif
+	MT_Scalar dist2 = MT_INFINITY;
+
+	do
+	{
+		MT_Point3  p = a.support(-v);	
+		MT_Point3  q = b.support(v);
+		MT_Vector3 w = p - q; 
+		
+        if (v.dot(w) > MT_Scalar(0.0)) 
+		{
+			return false;
+		}
+ 
+		gjk.addVertex(w);
+
+#ifdef STATISTICS
+        ++num_iterations;
+#endif
+        if (!gjk.closest(v)) 
+		{
+#ifdef STATISTICS
+            ++num_irregularities;
+#endif
+            return false;
+        }
+
+#ifdef SAFE_EXIT
+		MT_Scalar prev_dist2 = dist2;
+#endif
+
+		dist2 = v.length2();
+
+#ifdef SAFE_EXIT
+		if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+		{
+			return false;
+		}
+#endif
+    } 
+    while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+
+    v.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+
+    return true;
+}
+
+
+
+
+bool common_point(const DT_Convex& a, const DT_Convex& b,
+                  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{
+	DT_GJK gjk;
+
+#ifdef STATISTICS
+    num_iterations = 0;
+#endif
+
+	MT_Scalar dist2 = MT_INFINITY;
+
+    do
+	{
+		MT_Point3  p = a.support(-v);	
+		MT_Point3  q = b.support(v);
+		MT_Vector3 w = p - q; 
+		
+        if (v.dot(w) > MT_Scalar(0.0)) 
+		{
+			return false;
+		}
+ 
+		gjk.addVertex(w, p, q);
+
+#ifdef STATISTICS
+        ++num_iterations;
+#endif
+        if (!gjk.closest(v)) 
+		{
+#ifdef STATISTICS
+            ++num_irregularities;
+#endif
+            return false;
+        }		
+		
+#ifdef SAFE_EXIT
+		MT_Scalar prev_dist2 = dist2;
+#endif
+
+		dist2 = v.length2();
+
+#ifdef SAFE_EXIT
+		if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+		{
+			return false;
+		}
+#endif
+    }
+    while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+    
+	gjk.compute_points(pa, pb);
+
+    v.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+
+    return true;
+}
+
+
+
+
+
+
+	
+bool penetration_depth(const DT_Convex& a, const DT_Convex& b,
+                       MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{
+	DT_GJK gjk;
+
+#ifdef STATISTICS
+    num_iterations = 0;
+#endif
+
+	MT_Scalar dist2 = MT_INFINITY;
+
+    do
+	{
+		MT_Point3  p = a.support(-v);	
+		MT_Point3  q = b.support(v);
+		MT_Vector3 w = p - q; 
+		
+        if (v.dot(w) > MT_Scalar(0.0)) 
+		{
+			return false;
+		}
+ 
+		gjk.addVertex(w, p, q);
+
+#ifdef STATISTICS
+        ++num_iterations;
+#endif
+        if (!gjk.closest(v)) 
+		{
+#ifdef STATISTICS
+            ++num_irregularities;
+#endif
+            return false;
+        }		
+		
+#ifdef SAFE_EXIT
+		MT_Scalar prev_dist2 = dist2;
+#endif
+
+		dist2 = v.length2();
+
+#ifdef SAFE_EXIT
+		if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+		{
+			return false;
+		}
+#endif
+    }
+    while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+    
+
+	return penDepth(gjk, a, b, v, pa, pb);
+
+}
+
+bool hybrid_penetration_depth(const DT_Convex& a, MT_Scalar a_margin, 
+							  const DT_Convex& b, MT_Scalar b_margin,
+                              MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{
+	MT_Scalar margin = a_margin + b_margin;
+	if (margin > MT_Scalar(0.0))
+	{
+		MT_Scalar margin2 = margin * margin;
+
+		DT_GJK gjk;
+
+#ifdef STATISTICS
+		num_iterations = 0;
+#endif
+		MT_Scalar dist2 = MT_INFINITY;
+
+		do
+		{
+			MT_Point3  p = a.support(-v);	
+			MT_Point3  q = b.support(v);
+			
+			MT_Vector3 w = p - q; 
+			
+			MT_Scalar delta = v.dot(w);
+			
+			if (delta > MT_Scalar(0.0) && delta * delta > dist2 * margin2) 
+			{
+				return false;
+			}
+			
+			if (gjk.inSimplex(w) || dist2 - delta <= dist2 * DT_Accuracy::rel_error2)
+			{
+				gjk.compute_points(pa, pb);
+				MT_Scalar s = MT_sqrt(dist2);
+				assert(s > MT_Scalar(0.0));
+				pa -= v * (a_margin / s);
+				pb += v * (b_margin / s);
+				return true;
+			}
+			
+			gjk.addVertex(w, p, q);
+			
+#ifdef STATISTICS
+			++num_iterations;
+#endif
+			if (!gjk.closest(v)) 
+			{
+#ifdef STATISTICS
+				++num_irregularities;
+#endif
+				gjk.compute_points(pa, pb);
+				MT_Scalar s = MT_sqrt(dist2);
+				assert(s > MT_Scalar(0.0));
+				pa -= v * (a_margin / s);
+				pb += v * (b_margin / s);
+				return true;
+			}
+			
+#ifdef SAFE_EXIT
+			MT_Scalar prev_dist2 = dist2;
+#endif
+			
+			dist2 = v.length2();
+			
+#ifdef SAFE_EXIT
+			if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+			{ 
+				gjk.backup_closest(v);
+				dist2 = v.length2();
+				gjk.compute_points(pa, pb);
+				MT_Scalar s = MT_sqrt(dist2);
+				assert(s > MT_Scalar(0.0));
+				pa -= v * (a_margin / s);
+				pb += v * (b_margin / s);
+				return true;
+			}
+#endif
+		}
+		while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+		
+	}
+	// Second GJK phase. compute points on the boundary of the offset object
+	
+	return penetration_depth((a_margin > MT_Scalar(0.0) ? 
+							  static_cast(DT_Minkowski(a, DT_Sphere(a_margin))) : 
+							  static_cast(a)), 
+							 (b_margin > MT_Scalar(0.0) ? 
+							  static_cast(DT_Minkowski(b, DT_Sphere(b_margin))) : 
+							  static_cast(b)), v, pa, pb);
+}
+
+
+MT_Scalar closest_points(const DT_Convex& a, const DT_Convex& b, MT_Scalar max_dist2,
+                         MT_Point3& pa, MT_Point3& pb) 
+{
+	MT_Vector3 v(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+	
+    DT_GJK gjk;
+
+#ifdef STATISTICS
+    num_iterations = 0;
+#endif
+
+	MT_Scalar dist2 = MT_INFINITY;
+
+    do
+	{
+		MT_Point3  p = a.support(-v);	
+		MT_Point3  q = b.support(v);
+		MT_Vector3 w = p - q; 
+
+		MT_Scalar delta = v.dot(w);
+		if (delta > MT_Scalar(0.0) && delta * delta > dist2 * max_dist2) 
+		{
+			return MT_INFINITY;
+		}
+
+		if (gjk.inSimplex(w) || dist2 - delta <= dist2 * DT_Accuracy::rel_error2) 
+		{
+            break;
+		}
+
+		gjk.addVertex(w, p, q);
+
+#ifdef STATISTICS
+        ++num_iterations;
+        if (num_iterations > 1000) 
+		{
+			std::cout << "v: " << v << " w: " << w << std::endl;
+		}
+#endif
+        if (!gjk.closest(v)) 
+		{
+#ifdef STATISTICS
+            ++num_irregularities;
+#endif
+            break;
+        }
+
+#ifdef SAFE_EXIT
+		MT_Scalar prev_dist2 = dist2;
+#endif
+
+		dist2 = v.length2();
+
+#ifdef SAFE_EXIT
+		if (prev_dist2 - dist2 <= MT_EPSILON * prev_dist2) 
+		{
+         gjk.backup_closest(v);
+         dist2 = v.length2();
+			break;
+		}
+#endif
+    }
+    while (!gjk.fullSimplex() && dist2 > DT_Accuracy::tol_error * gjk.maxVertex()); 
+
+	assert(!gjk.emptySimplex());
+	
+	if (dist2 <= max_dist2)
+	{
+		gjk.compute_points(pa, pb);
+	}
+	
+	return dist2;
+}
diff --git a/extern/solid/src/convex/DT_Convex.h b/extern/solid/src/convex/DT_Convex.h
new file mode 100644
index 00000000000..dd620ac8b98
--- /dev/null
+++ b/extern/solid/src/convex/DT_Convex.h
@@ -0,0 +1,64 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_CONVEX_H
+#define DT_CONVEX_H
+
+#include "DT_Shape.h"
+
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+
+#include "MT_Matrix3x3.h"
+#include "MT_Transform.h"
+
+class DT_Convex : public DT_Shape {
+public:
+    virtual ~DT_Convex() {}
+	virtual DT_ShapeType getType() const { return CONVEX; } 
+    
+	virtual MT_Scalar supportH(const MT_Vector3& v) const {	return v.dot(support(v)); }
+    virtual MT_Point3 support(const MT_Vector3& v) const = 0;
+	virtual MT_BBox bbox() const;
+    virtual MT_BBox bbox(const MT_Matrix3x3& basis) const;
+    virtual MT_BBox bbox(const MT_Transform& t, MT_Scalar margin = MT_Scalar(0.0)) const;
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target, MT_Scalar& param, MT_Vector3& normal) const;
+	
+protected:
+	DT_Convex() {}
+};
+
+
+bool intersect(const DT_Convex& a, const DT_Convex& b, MT_Vector3& v);
+
+bool common_point(const DT_Convex& a, const DT_Convex& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+MT_Scalar closest_points(const DT_Convex&, const DT_Convex&, MT_Scalar max_dist2, MT_Point3& pa, MT_Point3& pb);
+
+bool penetration_depth(const DT_Convex& a, const DT_Convex& b, MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+bool hybrid_penetration_depth(const DT_Convex& a, MT_Scalar a_margin, 
+							  const DT_Convex& b, MT_Scalar b_margin,
+                              MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+#endif
diff --git a/extern/solid/src/convex/DT_Cylinder.cpp b/extern/solid/src/convex/DT_Cylinder.cpp
new file mode 100644
index 00000000000..cff5ebcefb1
--- /dev/null
+++ b/extern/solid/src/convex/DT_Cylinder.cpp
@@ -0,0 +1,39 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Cylinder.h"
+
+MT_Point3 DT_Cylinder::support(const MT_Vector3& v) const 
+{
+    MT_Scalar s = MT_sqrt(v[0] * v[0] + v[2] * v[2]);
+    if (s != MT_Scalar(0.0))
+	{
+        MT_Scalar d = radius / s;  
+        return MT_Point3(v[0] * d, v[1] < 0.0 ? -halfHeight : halfHeight, v[2] * d);
+    }
+    else
+	{
+        return MT_Point3(radius, v[1] < 0.0 ? -halfHeight : halfHeight, MT_Scalar(0.0));
+    }
+}
+  
diff --git a/extern/solid/src/convex/DT_Cylinder.h b/extern/solid/src/convex/DT_Cylinder.h
new file mode 100644
index 00000000000..2a0c07fd579
--- /dev/null
+++ b/extern/solid/src/convex/DT_Cylinder.h
@@ -0,0 +1,42 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_CYLINDER_H
+#define DT_CYLINDER_H
+
+#include "DT_Convex.h"
+
+class DT_Cylinder : public DT_Convex {
+public:
+    DT_Cylinder(MT_Scalar r, MT_Scalar h) : 
+        radius(r), 
+        halfHeight(h * MT_Scalar(0.5)) {}
+    
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+    
+protected:
+    MT_Scalar radius;
+    MT_Scalar halfHeight;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Facet.cpp b/extern/solid/src/convex/DT_Facet.cpp
new file mode 100644
index 00000000000..87ae5c3e0be
--- /dev/null
+++ b/extern/solid/src/convex/DT_Facet.cpp
@@ -0,0 +1,80 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Facet.h"
+
+bool DT_Facet::link(int edge0, DT_Facet *facet, int edge1) 
+{
+    m_adjFacets[edge0] = facet;
+    m_adjEdges[edge0] = edge1;
+    facet->m_adjFacets[edge1] = this;
+    facet->m_adjEdges[edge1] = edge0;
+
+    bool b = m_indices[edge0] == facet->m_indices[incMod3(edge1)] &&
+	m_indices[incMod3(edge0)] == facet->m_indices[edge1];
+    return b;
+}
+
+bool DT_Facet::computeClosest(const MT_Vector3 *verts)
+{
+    const MT_Vector3& p0 = verts[m_indices[0]]; 
+
+    MT_Vector3 v1 = verts[m_indices[1]] - p0;
+    MT_Vector3 v2 = verts[m_indices[2]] - p0;
+    MT_Scalar v1dv1 = v1.length2();
+    MT_Scalar v1dv2 = v1.dot(v2);
+    MT_Scalar v2dv2 = v2.length2();
+    MT_Scalar p0dv1 = p0.dot(v1); 
+    MT_Scalar p0dv2 = p0.dot(v2);
+    
+    m_det = v1dv1 * v2dv2 - v1dv2 * v1dv2; // non-negative
+    m_lambda1 = p0dv2 * v1dv2 - p0dv1 * v2dv2;
+    m_lambda2 = p0dv1 * v1dv2 - p0dv2 * v1dv1; 
+    
+    if (m_det > MT_Scalar(0.0)) {	
+	m_closest = p0 + (m_lambda1 * v1 + m_lambda2 * v2) / m_det;
+	m_dist2 = m_closest.length2();
+	return true;
+    }
+    
+    return false;
+} 
+
+void DT_Facet::silhouette(int index, const MT_Vector3& w, 
+			  DT_EdgeBuffer& edgeBuffer) 
+{
+    if (!m_obsolete) {
+		if (m_closest.dot(w) < m_dist2) {
+			edgeBuffer.push_back(DT_Edge(this, index));
+		}	
+	else {
+	    m_obsolete = true; // Facet is visible 
+	    int next = incMod3(index);
+	    m_adjFacets[next]->silhouette(m_adjEdges[next], w, edgeBuffer);
+	    next = incMod3(next);
+	    m_adjFacets[next]->silhouette(m_adjEdges[next], w, edgeBuffer);
+	}
+    }
+}
+
+
diff --git a/extern/solid/src/convex/DT_Facet.h b/extern/solid/src/convex/DT_Facet.h
new file mode 100644
index 00000000000..873706346b8
--- /dev/null
+++ b/extern/solid/src/convex/DT_Facet.h
@@ -0,0 +1,134 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_FACET_H
+#define DT_FACET_H
+
+#include 
+#include 
+
+#include 
+#include 
+
+class DT_Facet;
+
+
+class DT_Edge {
+public:
+    DT_Edge() {}
+    DT_Edge(DT_Facet *facet, int index) : 
+	m_facet(facet), 
+	m_index(index) {}
+
+    DT_Facet *getFacet() const { return m_facet; }
+    int       getIndex() const { return m_index; }
+
+    int getSource() const;
+    int getTarget() const;
+
+private:    
+    DT_Facet *m_facet;
+    int       m_index;
+};
+
+typedef std::vector DT_EdgeBuffer;
+
+
+class DT_Facet {
+public:
+    DT_Facet() {}
+    DT_Facet(int i0, int i1, int i2) 
+	  :	m_obsolete(false) 
+    {
+		m_indices[0] = i0; 
+		m_indices[1] = i1; 
+		m_indices[2] = i2;
+    }
+	
+    int operator[](int i) const { return m_indices[i]; } 
+
+    bool link(int edge0, DT_Facet *facet, int edge1);
+
+    
+    bool isObsolete() const { return m_obsolete; }
+    
+
+    bool computeClosest(const MT_Vector3 *verts);
+    
+    const MT_Vector3& getClosest() const { return m_closest; } 
+    
+    bool isClosestInternal() const
+	{ 
+		return m_lambda1 >= MT_Scalar(0.0) && 
+			m_lambda2 >= MT_Scalar(0.0) && 
+			m_lambda1 + m_lambda2 <= m_det;
+    } 
+
+    MT_Scalar getDist2() const { return m_dist2; }
+	
+    MT_Point3 getClosestPoint(const MT_Point3 *points) const 
+	{
+		const MT_Point3& p0 = points[m_indices[0]];
+		
+		return p0 + (m_lambda1 * (points[m_indices[1]] - p0) + 
+					 m_lambda2 * (points[m_indices[2]] - p0)) / m_det;
+    }
+    
+    void silhouette(const MT_Vector3& w, DT_EdgeBuffer& edgeBuffer) 
+	{
+		edgeBuffer.clear();
+		m_obsolete = true;
+		m_adjFacets[0]->silhouette(m_adjEdges[0], w, edgeBuffer);
+		m_adjFacets[1]->silhouette(m_adjEdges[1], w, edgeBuffer);
+		m_adjFacets[2]->silhouette(m_adjEdges[2], w, edgeBuffer);
+    }
+	
+private:
+    void silhouette(int index, const MT_Vector3& w, DT_EdgeBuffer& edgeBuffer);
+	
+    int         m_indices[3];
+    bool        m_obsolete;
+    DT_Facet   *m_adjFacets[3];
+    int         m_adjEdges[3];
+	
+    MT_Scalar   m_det;
+    MT_Scalar   m_lambda1;
+    MT_Scalar   m_lambda2;
+    MT_Vector3  m_closest;
+    MT_Scalar   m_dist2;
+};
+
+
+inline int incMod3(int i) { return ++i % 3; } 
+
+inline int DT_Edge::getSource() const 
+{
+    return (*m_facet)[m_index];
+}
+
+inline int DT_Edge::getTarget() const 
+{
+    return (*m_facet)[incMod3(m_index)];
+}
+
+#endif
diff --git a/extern/solid/src/convex/DT_GJK.h b/extern/solid/src/convex/DT_GJK.h
new file mode 100644
index 00000000000..d8f44acf85e
--- /dev/null
+++ b/extern/solid/src/convex/DT_GJK.h
@@ -0,0 +1,438 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_GJK_H
+#define DT_GJK_H
+
+//#define USE_BACKUP_PROCEDURE
+#define JOHNSON_ROBUST
+#define FAST_CLOSEST
+
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+#include "GEN_MinMax.h"
+#include "DT_Accuracy.h"
+
+
+class DT_GJK {
+private:
+	typedef unsigned int T_Bits;
+	inline static bool subseteq(T_Bits a, T_Bits b) { return (a & b) == a; }
+	inline static bool contains(T_Bits a, T_Bits b) { return (a & b) != 0x0; }
+
+public:
+	DT_GJK() :
+		m_bits(0x0),
+		m_all_bits(0x0)
+	{}
+
+	bool emptySimplex() const { return m_bits == 0x0; }
+	bool fullSimplex() const { return m_bits == 0xf; }
+
+	void reset() 
+	{
+		m_bits = 0x0;
+		m_all_bits = 0x0;	
+	}
+
+	bool inSimplex(const MT_Vector3& w) 
+	{
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
+		{
+			if (contains(m_all_bits, bit) && w == m_y[i])
+			{
+				return true;
+			}
+		}
+		return false;
+	}
+
+	void addVertex(const MT_Vector3& w) 
+	{
+		assert(!fullSimplex());
+		m_last = 0;
+        m_last_bit = 0x1;
+        while (contains(m_bits, m_last_bit)) 
+		{ 
+			++m_last; 
+			m_last_bit <<= 1; 
+		}
+		m_y[m_last] = w;
+		m_ylen2[m_last] = w.length2();
+        m_all_bits = m_bits | m_last_bit;
+
+		update_cache();
+		compute_det();
+	}
+
+	void addVertex(const MT_Vector3& w, const MT_Point3& p, const MT_Point3& q)
+	{
+		addVertex(w);
+		m_p[m_last] = p;
+		m_q[m_last] = q;
+	}
+
+	int getSimplex(MT_Point3 *pBuf, MT_Point3 *qBuf, MT_Vector3 *yBuf) const 
+	{
+		int num_verts = 0;
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1) 
+		{
+			if (contains(m_bits, bit)) 
+			{
+				pBuf[num_verts] = m_p[i];
+				qBuf[num_verts] = m_q[i];
+				yBuf[num_verts] = m_y[i];
+				
+#ifdef DEBUG
+				std::cout << "Point " << i << " = " << m_y[i] << std::endl;
+#endif
+				
+				++num_verts;
+			}
+		}
+		return num_verts;
+    }
+
+	void compute_points(MT_Point3& p1, MT_Point3& p2) 
+	{
+		MT_Scalar sum = MT_Scalar(0.0);
+		p1.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+		p2.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1) 
+		{
+			if (contains(m_bits, bit))
+			{
+				sum += m_det[m_bits][i];
+				p1 += m_p[i] * m_det[m_bits][i];
+				p2 += m_q[i] * m_det[m_bits][i];
+			}
+		}
+
+		assert(sum > MT_Scalar(0.0));
+		MT_Scalar s = MT_Scalar(1.0) / sum;
+		p1 *= s;
+		p2 *= s;
+	}
+
+	bool closest(MT_Vector3& v) 
+	{
+#ifdef FAST_CLOSEST
+		T_Bits s;
+		for (s = m_bits; s != 0x0; --s)
+		{
+			if (subseteq(s, m_bits) && valid(s | m_last_bit)) 
+			{
+				m_bits = s | m_last_bit;
+				compute_vector(m_bits, v);
+				return true;
+			}
+		}
+		if (valid(m_last_bit)) 
+		{
+			m_bits = m_last_bit;
+			m_maxlen2 = m_ylen2[m_last];
+			v = m_y[m_last];
+			return true;
+		}
+#else
+		T_Bits s;
+		for (s = m_all_bits; s != 0x0; --s)
+		{
+			if (subseteq(s, m_all_bits) && valid(s)) 
+			{
+				m_bits = s;
+				compute_vector(m_bits, v);
+				return true;
+			}
+		}
+#endif
+		
+		// Original GJK calls the backup procedure at this point.
+#ifdef USE_BACKUP_PROCEDURE
+		backup_closest(MT_Vector3& v); 
+#endif
+		return false;  
+	}
+
+	void backup_closest(MT_Vector3& v)
+	{ 		
+		MT_Scalar min_dist2 = MT_INFINITY;
+		
+      T_Bits s;
+		for (s = m_all_bits; s != 0x0; --s) 
+		{
+			if (subseteq(s, m_all_bits) && proper(s))
+			{	
+				MT_Vector3 u;
+				compute_vector(s, u);
+				MT_Scalar dist2 = u.length2();
+				if (dist2 < min_dist2)
+				{
+					min_dist2 = dist2;
+					m_bits = s;
+					v = u;
+				}
+			}
+		}
+	}
+	
+	MT_Scalar maxVertex() { return m_maxlen2; }
+
+
+private:
+	void update_cache();
+	void compute_det();
+
+	bool valid(T_Bits s) 
+	{
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
+		{
+			if (contains(m_all_bits, bit)) 
+			{
+				if (contains(s, bit)) 
+				{
+					if (m_det[s][i] <= MT_Scalar(0.0)) 
+					{
+						return false; 
+					}
+				}
+				else if (m_det[s | bit][i] > MT_Scalar(0.0))
+				{ 
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	bool proper(T_Bits s)
+	{ 
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
+		{
+			if (contains(s, bit) && m_det[s][i] <= MT_Scalar(0.0))
+			{
+				return false; 
+			}
+		}
+		return true;
+	}
+
+	void compute_vector(T_Bits s, MT_Vector3& v) 
+	{
+		m_maxlen2 = MT_Scalar(0.0);
+		MT_Scalar sum = MT_Scalar(0.0);
+		v .setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+
+		int i;
+		T_Bits bit;
+		for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1) 
+		{
+			if (contains(s, bit))
+			{
+				sum += m_det[s][i];
+				GEN_set_max(m_maxlen2, m_ylen2[i]);
+				v += m_y[i] * m_det[s][i];
+			}
+		}
+		
+		assert(sum > MT_Scalar(0.0));
+
+		v /= sum;
+	}
+ 
+private:
+	MT_Scalar	m_det[16][4]; // cached sub-determinants
+    MT_Vector3	m_edge[4][4];
+
+#ifdef JOHNSON_ROBUST
+    MT_Scalar	m_norm[4][4];
+#endif
+
+	MT_Point3	m_p[4];    // support points of object A in local coordinates 
+	MT_Point3	m_q[4];    // support points of object B in local coordinates 
+	MT_Vector3	m_y[4];   // support points of A - B in world coordinates
+	MT_Scalar	m_ylen2[4];   // Squared lengths support points y
+
+	MT_Scalar	m_maxlen2; // Maximum squared length to a vertex of the current 
+	                      // simplex
+	T_Bits		m_bits;      // identifies current simplex
+	T_Bits		m_last;      // identifies last found support point
+	T_Bits		m_last_bit;  // m_last_bit == 0x1 << last
+	T_Bits		m_all_bits;  // m_all_bits == m_bits  | m_last_bit 
+};
+
+
+
+
+inline void DT_GJK::update_cache() 
+{
+	int i;
+	T_Bits bit;
+    for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
+	{
+        if (contains(m_bits, bit)) 
+		{
+			m_edge[i][m_last] = m_y[i] - m_y[m_last];
+			m_edge[m_last][i] = -m_edge[i][m_last];
+
+#ifdef JOHNSON_ROBUST
+			m_norm[i][m_last] = m_norm[m_last][i] = m_edge[i][m_last].length2();
+#endif
+
+		}
+	}
+}
+
+#ifdef JOHNSON_ROBUST
+
+inline void DT_GJK::compute_det() 
+{
+    m_det[m_last_bit][m_last] = 1;
+
+	int i;
+	T_Bits si;
+    for (i = 0, si = 0x1; i < 4; ++i, si <<= 1) 
+	{
+        if (contains(m_bits, si)) 
+		{
+            T_Bits s2 = si | m_last_bit;
+            m_det[s2][i] = m_edge[m_last][i].dot(m_y[m_last]); 
+            m_det[s2][m_last] = m_edge[i][m_last].dot(m_y[i]);
+
+			int j;
+			T_Bits sj;
+            for (j = 0, sj = 0x1; j < i; ++j, sj <<= 1) 
+			{
+                if (contains(m_bits, sj)) 
+				{
+					int k;
+                    T_Bits s3 = sj | s2;			
+					
+					k = m_norm[i][j] < m_norm[m_last][j] ? i : m_last;
+                    m_det[s3][j] = m_det[s2][i] * m_edge[k][j].dot(m_y[i]) + 
+                                   m_det[s2][m_last] * m_edge[k][j].dot(m_y[m_last]);
+					k = m_norm[j][i] < m_norm[m_last][i] ? j : m_last;
+                    m_det[s3][i] = m_det[sj|m_last_bit][j] * m_edge[k][i].dot(m_y[j]) +  
+                                   m_det[sj|m_last_bit][m_last] * m_edge[k][i].dot(m_y[m_last]);
+					k = m_norm[i][m_last] < m_norm[j][m_last] ? i : j;
+                    m_det[s3][m_last] = m_det[sj|si][j] * m_edge[k][m_last].dot(m_y[j]) + 
+                                        m_det[sj|si][i] * m_edge[k][m_last].dot(m_y[i]);
+                }
+            }
+        }
+    }
+
+    if (m_all_bits == 0xf) 
+	{
+		int k;
+
+		k = m_norm[1][0] < m_norm[2][0] ? (m_norm[1][0] < m_norm[3][0] ? 1 : 3) : (m_norm[2][0] < m_norm[3][0] ? 2 : 3);
+		
+        m_det[0xf][0] = m_det[0xe][1] * m_edge[k][0].dot(m_y[1]) + 
+                        m_det[0xe][2] * m_edge[k][0].dot(m_y[2]) + 
+                        m_det[0xe][3] * m_edge[k][0].dot(m_y[3]);
+
+		k = m_norm[0][1] < m_norm[2][1] ? (m_norm[0][1] < m_norm[3][1] ? 0 : 3) : (m_norm[2][1] < m_norm[3][1] ? 2 : 3);
+		
+        m_det[0xf][1] = m_det[0xd][0] * m_edge[k][1].dot(m_y[0]) + 
+                        m_det[0xd][2] * m_edge[k][1].dot(m_y[2]) +
+                        m_det[0xd][3] * m_edge[k][1].dot(m_y[3]);
+
+		k = m_norm[0][2] < m_norm[1][2] ? (m_norm[0][2] < m_norm[3][2] ? 0 : 3) : (m_norm[1][2] < m_norm[3][2] ? 1 : 3);
+		
+        m_det[0xf][2] = m_det[0xb][0] * m_edge[k][2].dot(m_y[0]) + 
+                        m_det[0xb][1] * m_edge[k][2].dot(m_y[1]) +  
+                        m_det[0xb][3] * m_edge[k][2].dot(m_y[3]);
+
+		k = m_norm[0][3] < m_norm[1][3] ? (m_norm[0][3] < m_norm[2][3] ? 0 : 2) : (m_norm[1][3] < m_norm[2][3] ? 1 : 2);
+		
+        m_det[0xf][3] = m_det[0x7][0] * m_edge[k][3].dot(m_y[0]) + 
+                        m_det[0x7][1] * m_edge[k][3].dot(m_y[1]) + 
+                        m_det[0x7][2] * m_edge[k][3].dot(m_y[2]);
+    }
+}
+
+#else
+
+inline void DT_GJK::compute_det() 
+{
+    m_det[m_last_bit][m_last] = 1;
+
+	int i;
+	T_Bits si;
+    for (i = 0, si = 0x1; i < 4; ++i, si <<= 1) 
+	{
+        if (contains(m_bits, si)) 
+		{
+            T_Bits s2 = si | m_last_bit;
+            m_det[s2][i] = m_edge[m_last][i].dot(m_y[m_last]); 
+            m_det[s2][m_last] = m_edge[i][m_last].dot(m_y[i]);
+
+			int j;
+			T_Bits sj;
+            for (j = 0, sj = 0x1; j < i; ++j, sj <<= 1)
+			{
+                if (contains(m_bits, sj)) 
+				{
+                    T_Bits s3 = sj | s2;
+                    m_det[s3][j] = m_det[s2][i] * m_edge[i][j].dot(m_y[i]) + 
+                                   m_det[s2][m_last] * m_edge[i][j].dot(m_y[m_last]);
+                    m_det[s3][i] = m_det[sj|m_last_bit][j] * m_edge[j][i].dot(m_y[j]) +  
+                                   m_det[sj|m_last_bit][m_last] * m_edge[j][i].dot(m_y[m_last]);
+                    m_det[s3][m_last] = m_det[sj|si][j] * m_edge[j][m_last].dot(m_y[j]) + 
+                                        m_det[sj|si][i] * m_edge[j][m_last].dot(m_y[i]);
+                }
+            }
+        }
+    }
+
+    if (m_all_bits == 0xf) 
+	{
+        m_det[0xf][0] = m_det[0xe][1] * m_edge[1][0].dot(m_y[1]) + 
+                        m_det[0xe][2] * m_edge[1][0].dot(m_y[2]) + 
+                        m_det[0xe][3] * m_edge[1][0].dot(m_y[3]);
+        m_det[0xf][1] = m_det[0xd][0] * m_edge[0][1].dot(m_y[0]) + 
+                        m_det[0xd][2] * m_edge[0][1].dot(m_y[2]) +
+                        m_det[0xd][3] * m_edge[0][1].dot(m_y[3]);
+        m_det[0xf][2] = m_det[0xb][0] * m_edge[0][2].dot(m_y[0]) + 
+                        m_det[0xb][1] * m_edge[0][2].dot(m_y[1]) +  
+                        m_det[0xb][3] * m_edge[0][2].dot(m_y[3]);
+        m_det[0xf][3] = m_det[0x7][0] * m_edge[0][3].dot(m_y[0]) + 
+                        m_det[0x7][1] * m_edge[0][3].dot(m_y[1]) + 
+                        m_det[0x7][2] * m_edge[0][3].dot(m_y[2]);
+    }
+}
+
+#endif
+
+#endif
diff --git a/extern/solid/src/convex/DT_Hull.h b/extern/solid/src/convex/DT_Hull.h
new file mode 100644
index 00000000000..a5bf56ae59d
--- /dev/null
+++ b/extern/solid/src/convex/DT_Hull.h
@@ -0,0 +1,53 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_HULL_H
+#define DT_HULL_H
+
+#include "DT_Convex.h"
+
+class DT_Hull : public DT_Convex {
+public:
+	DT_Hull(const DT_Convex& lchild, const DT_Convex& rchild) :
+		m_lchild(lchild), 
+		m_rchild(rchild) 
+	{}
+
+	virtual MT_Scalar supportH(const MT_Vector3& v) const 
+	{
+		return GEN_max(m_lchild.supportH(v), m_rchild.supportH(v));
+	}
+
+	virtual MT_Point3 support(const MT_Vector3& v) const 
+	{
+		MT_Point3 lpnt = m_lchild.support(v);
+		MT_Point3 rpnt = m_rchild.support(v);
+		return v.dot(lpnt) > v.dot(rpnt) ? lpnt : rpnt;
+	}
+
+private:
+	const DT_Convex& m_lchild;
+	const DT_Convex& m_rchild;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_IndexArray.h b/extern/solid/src/convex/DT_IndexArray.h
new file mode 100644
index 00000000000..95551fa8483
--- /dev/null
+++ b/extern/solid/src/convex/DT_IndexArray.h
@@ -0,0 +1,33 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_INDEXARRAY_H
+#define DT_INDEXARRAY_H
+
+#include "SOLID_types.h"
+#include "DT_Array.h"
+
+typedef DT_Array DT_IndexArray;
+
+#endif
+
diff --git a/extern/solid/src/convex/DT_LineSegment.cpp b/extern/solid/src/convex/DT_LineSegment.cpp
new file mode 100644
index 00000000000..6c7ccf6b9b7
--- /dev/null
+++ b/extern/solid/src/convex/DT_LineSegment.cpp
@@ -0,0 +1,36 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_LineSegment.h"
+
+MT_Scalar DT_LineSegment::supportH(const MT_Vector3& v) const
+{
+    return GEN_max(v.dot(m_source), v.dot(m_target));
+}
+
+MT_Point3 DT_LineSegment::support(const MT_Vector3& v) const
+{
+    return v.dot(m_source) > v.dot(m_target) ?	m_source : m_target;
+}
+
+
diff --git a/extern/solid/src/convex/DT_LineSegment.h b/extern/solid/src/convex/DT_LineSegment.h
new file mode 100644
index 00000000000..979ff8a18a9
--- /dev/null
+++ b/extern/solid/src/convex/DT_LineSegment.h
@@ -0,0 +1,52 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_LINESEGMENT_H
+#define DT_LINESEGMENT_H
+
+#include "DT_Convex.h"
+
+class DT_LineSegment : public DT_Convex {
+public:
+    DT_LineSegment(const MT_Point3& source, const MT_Point3& target) : 
+	   m_source(source), 
+	   m_target(target) {}
+
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+
+	const MT_Point3& getSource() const { return m_source; }
+	const MT_Point3& getTarget() const { return m_target; }
+
+private:
+	MT_Point3 m_source;
+	MT_Point3 m_target;
+};
+
+#endif
+
+
+
+
+
+
diff --git a/extern/solid/src/convex/DT_Minkowski.h b/extern/solid/src/convex/DT_Minkowski.h
new file mode 100644
index 00000000000..e90fed6a8e0
--- /dev/null
+++ b/extern/solid/src/convex/DT_Minkowski.h
@@ -0,0 +1,51 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_MINKOWSKI_H
+#define DT_MINKOWSKI_H
+
+#include "DT_Convex.h"
+
+class DT_Minkowski : public DT_Convex {
+public:
+	DT_Minkowski(const DT_Convex& lchild, const DT_Convex& rchild) 
+     : m_lchild(lchild), 
+       m_rchild(rchild) 
+   {}
+
+	virtual MT_Scalar supportH(const MT_Vector3& v) const 
+	{
+		return m_lchild.supportH(v) + m_rchild.supportH(v); 
+	}
+
+	virtual MT_Point3 support(const MT_Vector3& v) const 
+	{
+		return m_lchild.support(v) + (MT_Vector3)m_rchild.support(v); 
+	}
+
+private:
+	const DT_Convex& m_lchild;
+	const DT_Convex& m_rchild;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_PenDepth.cpp b/extern/solid/src/convex/DT_PenDepth.cpp
new file mode 100644
index 00000000000..e1c5c9a3949
--- /dev/null
+++ b/extern/solid/src/convex/DT_PenDepth.cpp
@@ -0,0 +1,376 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_PenDepth.h"
+
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+#include "MT_Quaternion.h"
+#include "DT_Convex.h"
+#include "DT_GJK.h"
+#include "DT_Facet.h"
+
+//#define DEBUG
+
+const int       MaxSupportPoints = 1000;
+const int       MaxFacets         = 2000;
+
+static MT_Point3  pBuf[MaxSupportPoints];
+static MT_Point3  qBuf[MaxSupportPoints];
+static MT_Vector3 yBuf[MaxSupportPoints];
+
+static DT_Facet facetBuf[MaxFacets];
+static int  freeFacet = 0;
+static DT_Facet *facetHeap[MaxFacets];
+static int  num_facets;
+
+class DT_FacetComp {
+public:
+    
+    bool operator()(const DT_Facet *face1, const DT_Facet *face2) 
+	{ 
+		return face1->getDist2() > face2->getDist2();
+    }
+    
+} facetComp;
+
+inline DT_Facet *addFacet(int i0, int i1, int i2,
+						  MT_Scalar lower2, MT_Scalar upper2) 
+{
+    assert(i0 != i1 && i0 != i2 && i1 != i2);
+    if (freeFacet < MaxFacets)
+	{
+		DT_Facet *facet = new(&facetBuf[freeFacet++]) DT_Facet(i0, i1, i2);
+#ifdef DEBUG
+		std::cout << "Facet " << i0 << ' ' << i1 << ' ' << i2;
+#endif
+		if (facet->computeClosest(yBuf)) 
+		{
+			if (facet->isClosestInternal() && 
+				lower2 <= facet->getDist2() && facet->getDist2() <= upper2) 
+			{
+				facetHeap[num_facets++] = facet;
+				std::push_heap(&facetHeap[0], &facetHeap[num_facets], facetComp);
+#ifdef DEBUG
+				std::cout << " accepted" << std::endl;
+#endif
+			}
+			else 
+			{
+#ifdef DEBUG
+				std::cout << " rejected, ";
+				if (!facet->isClosestInternal()) 
+				{
+					std::cout << "closest point not internal";
+				}
+				else if (lower2 > facet->getDist2()) 
+				{
+					std::cout << "facet is closer than orignal facet";
+				}
+				else 
+				{
+					std::cout << "facet is further than upper bound";
+				}
+				std::cout << std::endl;
+#endif
+			}
+			
+			return facet;
+		}
+    }
+    
+    return 0;
+}
+
+inline bool originInTetrahedron(const MT_Vector3& p1, const MT_Vector3& p2, 
+								const MT_Vector3& p3, const MT_Vector3& p4)
+{
+    MT_Vector3 normal1 = (p2 - p1).cross(p3 - p1);
+    MT_Vector3 normal2 = (p3 - p2).cross(p4 - p2);
+    MT_Vector3 normal3 = (p4 - p3).cross(p1 - p3);
+    MT_Vector3 normal4 = (p1 - p4).cross(p2 - p4);
+    
+    return 
+		normal1.dot(p1) > MT_Scalar(0.0) != normal1.dot(p4) > MT_Scalar(0.0) &&
+		normal2.dot(p2) > MT_Scalar(0.0) != normal2.dot(p1) > MT_Scalar(0.0) &&
+		normal3.dot(p3) > MT_Scalar(0.0) != normal3.dot(p2) > MT_Scalar(0.0) &&
+		normal4.dot(p4) > MT_Scalar(0.0) != normal4.dot(p3) > MT_Scalar(0.0);
+}
+
+
+bool penDepth(const DT_GJK& gjk, const DT_Convex& a, const DT_Convex& b,
+			  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb)
+{
+	
+    int num_verts = gjk.getSimplex(pBuf, qBuf, yBuf);
+    
+    switch (num_verts) 
+	{
+	case 1:
+	    // Touching contact. Yes, we have a collision,
+	    // but no penetration.
+	    return false;
+	case 2:	
+	{
+	    // We have a line segment inside the Minkowski sum containing the
+	    // origin. Blow it up by adding three additional support points.
+	    
+	    MT_Vector3 dir  = (yBuf[1] - yBuf[0]).normalized();
+	    int        axis = dir.furthestAxis();
+	    
+	    static MT_Scalar sin_60 = MT_sqrt(MT_Scalar(3.0)) * MT_Scalar(0.5);
+	    
+	    MT_Quaternion rot(dir[0] * sin_60, dir[1] * sin_60, dir[2] * sin_60, MT_Scalar(0.5));
+	    MT_Matrix3x3 rot_mat(rot);
+	    
+	    MT_Vector3 aux1 = dir.cross(MT_Vector3(axis == 0, axis == 1, axis == 2));
+	    MT_Vector3 aux2 = rot_mat * aux1;
+	    MT_Vector3 aux3 = rot_mat * aux2;
+	    
+	    pBuf[2] = a.support(aux1);
+	    qBuf[2] = b.support(-aux1);
+	    yBuf[2] = pBuf[2] - qBuf[2];
+	    
+	    pBuf[3] = a.support(aux2);
+	    qBuf[3] = b.support(-aux2);
+	    yBuf[3] = pBuf[3] - qBuf[3];
+	    
+	    pBuf[4] = a.support(aux3);
+	    qBuf[4] = b.support(-aux3);
+	    yBuf[4] = pBuf[4] - qBuf[4];
+	    
+	    if (originInTetrahedron(yBuf[0], yBuf[2], yBuf[3], yBuf[4])) 
+		{
+			pBuf[1] = pBuf[4];
+			qBuf[1] = qBuf[4];
+			yBuf[1] = yBuf[4];
+	    }
+	    else if (originInTetrahedron(yBuf[1], yBuf[2], yBuf[3], yBuf[4])) 
+		{
+			pBuf[0] = pBuf[4];
+			qBuf[0] = qBuf[4];
+			yBuf[0] = yBuf[4];
+	    } 
+	    else 
+		{
+			// Origin not in initial polytope
+			return false;
+	    }
+	    
+	    num_verts = 4;
+	    
+	    break;
+	}
+	case 3: 
+	{
+	    // We have a triangle inside the Minkowski sum containing
+	    // the origin. First blow it up.
+	    
+	    MT_Vector3 v1     = yBuf[1] - yBuf[0];
+	    MT_Vector3 v2     = yBuf[2] - yBuf[0];
+	    MT_Vector3 vv     = v1.cross(v2);
+	    
+	    pBuf[3] = a.support(vv);
+	    qBuf[3] = b.support(-vv);
+	    yBuf[3] = pBuf[3] - qBuf[3];
+	    pBuf[4] = a.support(-vv);
+	    qBuf[4] = b.support(vv);
+	    yBuf[4] = pBuf[4] - qBuf[4];
+	    
+	   
+	    if (originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[4])) 
+		{
+			pBuf[3] = pBuf[4];
+			qBuf[3] = qBuf[4];
+			yBuf[3] = yBuf[4];
+	    }
+	    else if (!originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[3]))
+		{ 
+			// Origin not in initial polytope
+			return false;
+	    }
+	    
+	    num_verts = 4;
+	    
+	    break;
+	}
+    }
+    
+    // We have a tetrahedron inside the Minkowski sum containing
+    // the origin (if GJK did it's job right ;-)
+      
+    
+    if (!originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[3])) 
+	{
+		//	assert(false);
+		return false;
+	}
+    
+	num_facets = 0;
+    freeFacet = 0;
+
+    DT_Facet *f0 = addFacet(0, 1, 2, MT_Scalar(0.0), MT_INFINITY);
+    DT_Facet *f1 = addFacet(0, 3, 1, MT_Scalar(0.0), MT_INFINITY);
+    DT_Facet *f2 = addFacet(0, 2, 3, MT_Scalar(0.0), MT_INFINITY);
+    DT_Facet *f3 = addFacet(1, 3, 2, MT_Scalar(0.0), MT_INFINITY);
+    
+    if (!f0 || f0->getDist2() == MT_Scalar(0.0) ||
+		!f1 || f1->getDist2() == MT_Scalar(0.0) ||
+		!f2 || f2->getDist2() == MT_Scalar(0.0) ||
+		!f3 || f3->getDist2() == MT_Scalar(0.0)) 
+	{
+		return false;
+    }
+    
+    f0->link(0, f1, 2);
+    f0->link(1, f3, 2);
+    f0->link(2, f2, 0);
+    f1->link(0, f2, 2);
+    f1->link(1, f3, 0);
+    f2->link(1, f3, 1);
+    
+    if (num_facets == 0) 
+	{
+		return false;
+    }
+    
+    // at least one facet on the heap.	
+    
+    DT_EdgeBuffer edgeBuffer(20);
+
+    DT_Facet *facet = 0;
+    
+    MT_Scalar upper_bound2 = MT_INFINITY; 	
+    
+    do {
+        facet = facetHeap[0];
+        std::pop_heap(&facetHeap[0], &facetHeap[num_facets], facetComp);
+        --num_facets;
+		
+		if (!facet->isObsolete()) 
+		{
+			assert(facet->getDist2() > MT_Scalar(0.0));
+			
+			if (num_verts == MaxSupportPoints)
+			{
+#ifdef DEBUG
+				std::cout << "Ouch, no convergence!!!" << std::endl;
+#endif 
+				assert(false);	
+				break;
+			}
+			
+			pBuf[num_verts] = a.support(facet->getClosest());
+			qBuf[num_verts] = b.support(-facet->getClosest());
+			yBuf[num_verts] = pBuf[num_verts] - qBuf[num_verts];
+			
+			int index = num_verts++;
+			MT_Scalar far_dist2 = yBuf[index].dot(facet->getClosest());
+			
+			// Make sure the support mapping is OK.
+			assert(far_dist2 > MT_Scalar(0.0));
+			
+			GEN_set_min(upper_bound2, far_dist2 * far_dist2 / facet->getDist2());
+			
+			if (upper_bound2 <= DT_Accuracy::depth_tolerance * facet->getDist2()
+#define CHECK_NEW_SUPPORT
+#ifdef CHECK_NEW_SUPPORT
+				|| yBuf[index] == yBuf[(*facet)[0]] 
+				|| yBuf[index] == yBuf[(*facet)[1]]
+				|| yBuf[index] == yBuf[(*facet)[2]]
+#endif
+				) 
+			{
+				break;
+			}
+			
+			// Compute the silhouette cast by the new vertex
+			// Note that the new vertex is on the positive side
+			// of the current facet, so the current facet is will
+			// not be in the convex hull. Start local search
+			// from this facet.
+			
+			facet->silhouette(yBuf[index], edgeBuffer);
+			
+			if (edgeBuffer.empty()) 
+			{
+				return false;
+			}
+			
+			DT_EdgeBuffer::const_iterator it = edgeBuffer.begin();
+			DT_Facet *firstFacet = 
+				addFacet((*it).getTarget(), (*it).getSource(),
+						 index, facet->getDist2(), upper_bound2);
+			
+			if (!firstFacet) 
+			{
+				break;
+			}
+			
+			firstFacet->link(0, (*it).getFacet(), (*it).getIndex());
+			DT_Facet *lastFacet = firstFacet;
+			
+			++it;
+			for (; it != edgeBuffer.end(); ++it) 
+			{
+				DT_Facet *newFacet = 
+					addFacet((*it).getTarget(), (*it).getSource(),
+							 index, facet->getDist2(), upper_bound2);
+				
+				if (!newFacet) 
+				{
+					break;
+				}
+				
+				if (!newFacet->link(0, (*it).getFacet(), (*it).getIndex())) 
+				{
+					break;
+				}
+				
+				if (!newFacet->link(2, lastFacet, 1)) 
+				{
+					break;
+				}
+				
+				lastFacet = newFacet;				
+			}
+			if (it != edgeBuffer.end()) 
+			{
+				break;
+			}
+			
+			firstFacet->link(2, lastFacet, 1);
+		}
+    }
+    while (num_facets > 0 && facetHeap[0]->getDist2() <= upper_bound2);
+	
+#ifdef DEBUG    
+    std::cout << "#facets left = " << num_facets << std::endl;
+#endif
+    
+    v = facet->getClosest();
+    pa = facet->getClosestPoint(pBuf);    
+    pb = facet->getClosestPoint(qBuf);    
+    return true;
+}
+
diff --git a/extern/solid/src/convex/DT_PenDepth.h b/extern/solid/src/convex/DT_PenDepth.h
new file mode 100644
index 00000000000..97b3c6c0e0e
--- /dev/null
+++ b/extern/solid/src/convex/DT_PenDepth.h
@@ -0,0 +1,36 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_PENDEPTH_H
+#define DT_PENDEPTH_H
+
+#include "MT_Vector3.h"
+#include "MT_Point3.h"
+
+class DT_GJK;
+class DT_Convex;
+
+bool penDepth(const DT_GJK& gjk, const DT_Convex& a, const DT_Convex& b, 
+			  MT_Vector3& v, MT_Point3& pa, MT_Point3& pb);
+
+#endif
diff --git a/extern/solid/src/convex/DT_Point.cpp b/extern/solid/src/convex/DT_Point.cpp
new file mode 100644
index 00000000000..770fe7775b7
--- /dev/null
+++ b/extern/solid/src/convex/DT_Point.cpp
@@ -0,0 +1,36 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Point.h"
+
+MT_Scalar DT_Point::supportH(const MT_Vector3& v) const
+{
+    return v.dot(m_point);
+}
+
+MT_Point3 DT_Point::support(const MT_Vector3& v) const
+{
+    return m_point;
+}
+
+
diff --git a/extern/solid/src/convex/DT_Point.h b/extern/solid/src/convex/DT_Point.h
new file mode 100644
index 00000000000..b35d158ee53
--- /dev/null
+++ b/extern/solid/src/convex/DT_Point.h
@@ -0,0 +1,46 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_POINT_H
+#define DT_POINT_H
+
+#include "DT_Convex.h"
+
+class DT_Point : public DT_Convex {
+public:
+    DT_Point(const MT_Point3& point) : m_point(point) {}
+
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+
+private:
+	MT_Point3 m_point;
+};
+
+#endif
+
+
+
+
+
+
diff --git a/extern/solid/src/convex/DT_Polyhedron.cpp b/extern/solid/src/convex/DT_Polyhedron.cpp
new file mode 100644
index 00000000000..f48ac6e4b6d
--- /dev/null
+++ b/extern/solid/src/convex/DT_Polyhedron.cpp
@@ -0,0 +1,415 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Polyhedron.h"
+
+#ifdef QHULL
+
+extern "C" {
+#include 
+}
+
+#include 
+#include   
+
+typedef std::vector T_VertexBuf;
+typedef std::vector T_IndexBuf;
+typedef std::vector T_MultiIndexBuf;
+
+static char options[] = "qhull Qts i Tv";
+
+#define DK_HIERARCHY
+
+T_IndexBuf *adjacency_graph(DT_Count count, const MT_Point3 *verts, const char *flags)
+{
+	int curlong, totlong, exitcode;
+	
+    facetT *facet;
+    vertexT *vertex;
+    vertexT **vertexp;
+    
+    std::vector > array;
+	T_IndexBuf index;
+    DT_Index i;
+    for (i = 0; i != count; ++i) 
+	{
+		if (flags == 0 || flags[i])
+		{
+            array.push_back(MT::Tuple3(verts[i]));
+			index.push_back(i);
+		}
+    }
+
+    qh_init_A(stdin, stdout, stderr, 0, NULL);
+    if ((exitcode = setjmp(qh errexit))) 
+	{
+		exit(exitcode);
+	}
+    qh_initflags(options);
+    qh_init_B(array[0], array.size(), 3, False);
+    qh_qhull();
+    qh_check_output();
+    
+    T_IndexBuf *indexBuf = new T_IndexBuf[count];
+    FORALLfacets 
+	{
+		setT *vertices = qh_facet3vertex(facet);
+		
+		T_IndexBuf  facetIndices;
+
+		FOREACHvertex_(vertices) 
+		{
+			facetIndices.push_back(index[qh_pointid(vertex->point)]);
+		}
+		int i, j;
+		for (i = 0, j = facetIndices.size()-1; i < (int)facetIndices.size(); j = i++)
+		{
+			indexBuf[facetIndices[j]].push_back(facetIndices[i]);
+		}
+    }
+
+    
+    qh NOerrexit = True;
+    qh_freeqhull(!qh_ALL);
+    qh_memfreeshort(&curlong, &totlong);
+
+	return indexBuf;
+}
+
+T_IndexBuf *simplex_adjacency_graph(DT_Count count, const char *flags)
+{
+	T_IndexBuf *indexBuf = new T_IndexBuf[count];
+
+	DT_Index index[4];
+	
+	DT_Index k = 0;
+	DT_Index i;
+	for (i = 0; i != count; ++i) 
+	{
+		if (flags == 0 || flags[i])
+		{
+			index[k++] = i;
+		}
+	}
+
+	assert(k <= 4);
+
+	for (i = 0; i != k; ++i)
+	{
+		DT_Index j;
+		for (j = 0; j != k; ++j)
+		{
+			if (i != j)
+			{
+				indexBuf[index[i]].push_back(index[j]);
+			}
+		}
+	}
+
+	return indexBuf;
+}
+
+#ifdef DK_HIERARCHY
+
+void prune(DT_Count count, T_MultiIndexBuf *cobound)
+{
+	DT_Index i;
+	for (i = 0; i != count; ++i)
+	{
+		assert(cobound[i].size());
+
+		DT_Index j;
+		for (j = 0; j != cobound[i].size() - 1; ++j)
+		{
+			T_IndexBuf::iterator it = cobound[i][j].begin();
+			while (it != cobound[i][j].end())
+			{
+				T_IndexBuf::iterator jt = 
+					std::find(cobound[i][j+1].begin(), cobound[i][j+1].end(), *it);
+
+				if (jt != cobound[i][j+1].end())
+				{
+					std::swap(*it, cobound[i][j].back());
+					cobound[i][j].pop_back();
+				}
+				else
+				{
+					++it;
+				}
+			}
+		}
+	}	
+}
+
+#endif
+
+DT_Polyhedron::DT_Polyhedron(const DT_VertexBase *base, DT_Count count, const DT_Index *indices)
+{
+	assert(count);
+
+	std::vector vertexBuf;
+	DT_Index i;
+	for (i = 0; i != count; ++i) 
+	{
+		vertexBuf.push_back((*base)[indices[i]]);
+	}
+
+	T_IndexBuf *indexBuf = count > 4 ? adjacency_graph(count, &vertexBuf[0], 0) : simplex_adjacency_graph(count, 0);
+	
+	std::vector pointBuf;
+	
+	for (i = 0; i != count; ++i) 
+	{
+		if (!indexBuf[i].empty()) 
+		{
+			pointBuf.push_back(vertexBuf[i]);
+		}
+	}
+			
+	delete [] indexBuf;
+
+	m_count = pointBuf.size();
+	m_verts = new MT_Point3[m_count];	
+	std::copy(pointBuf.begin(), pointBuf.end(), &m_verts[0]);
+
+	T_MultiIndexBuf *cobound = new T_MultiIndexBuf[m_count];
+    char *flags = new char[m_count];
+	std::fill(&flags[0], &flags[m_count], 1);
+
+	DT_Count num_layers = 0;
+	DT_Count layer_count = m_count;
+	while (layer_count > 4)
+	{
+		T_IndexBuf *indexBuf = adjacency_graph(m_count, m_verts, flags);
+		
+		DT_Index i;
+		for (i = 0; i != m_count; ++i) 
+		{
+			if (flags[i])
+			{
+				assert(!indexBuf[i].empty());
+				cobound[i].push_back(indexBuf[i]);
+			}
+		}
+			
+		++num_layers;
+
+		delete [] indexBuf;
+
+		std::fill(&flags[0], &flags[m_count], 0);
+
+		for (i = 0; i != m_count; ++i)
+		{
+			if (cobound[i].size() == num_layers) 
+			{
+				T_IndexBuf& curr_cobound = cobound[i].back();	
+				if (!flags[i] && curr_cobound.size() <= 8)
+				{	
+					DT_Index j;
+					for (j  = 0; j != curr_cobound.size(); ++j)
+					{
+						flags[curr_cobound[j]] = 1;
+					}
+				}
+			}
+		}
+		
+		layer_count = 0;
+		
+		for (i = 0; i != m_count; ++i)
+		{
+			if (flags[i])
+			{
+				++layer_count;
+			}
+		}	
+	}
+	
+	indexBuf = simplex_adjacency_graph(m_count, flags);
+		
+	for (i = 0; i != m_count; ++i) 
+	{
+		if (flags[i])
+		{
+			assert(!indexBuf[i].empty());
+			cobound[i].push_back(indexBuf[i]);
+		}
+	}
+	
+	++num_layers;
+
+	delete [] indexBuf;
+	delete [] flags;
+		
+
+
+#ifdef DK_HIERARCHY
+	prune(m_count, cobound);
+#endif
+
+	m_cobound = new T_MultiIndexArray[m_count];
+
+	for (i = 0; i != m_count; ++i)
+	{
+		new (&m_cobound[i]) T_MultiIndexArray(cobound[i].size());
+		
+		DT_Index j;
+		for (j = 0; j != cobound[i].size(); ++j)
+		{
+			new (&m_cobound[i][j]) DT_IndexArray(cobound[i][j].size(), &cobound[i][j][0]);
+		}
+	}
+		
+	delete [] cobound;
+
+	m_start_vertex = 0;
+	while (m_cobound[m_start_vertex].size() != num_layers) 
+	{
+		++m_start_vertex;
+		assert(m_start_vertex < m_count);
+	}
+
+	m_curr_vertex = m_start_vertex;
+} 
+
+
+DT_Polyhedron::~DT_Polyhedron() 
+{
+	delete [] m_verts;
+    delete [] m_cobound;
+}
+
+#ifdef DK_HIERARCHY
+
+MT_Scalar DT_Polyhedron::supportH(const MT_Vector3& v) const 
+{
+    m_curr_vertex = m_start_vertex;
+    MT_Scalar d = (*this)[m_curr_vertex].dot(v);
+    MT_Scalar h = d;
+	int curr_layer;
+	for (curr_layer = m_cobound[m_start_vertex].size(); curr_layer != 0; --curr_layer)
+	{
+		const DT_IndexArray& curr_cobound = m_cobound[m_curr_vertex][curr_layer-1];
+        DT_Index i;
+		for (i = 0; i != curr_cobound.size(); ++i) 
+		{
+			d = (*this)[curr_cobound[i]].dot(v);
+			if (d > h)
+			{
+				m_curr_vertex = curr_cobound[i];
+				h = d;
+			}
+		}
+	}
+	
+    return h;
+}
+
+MT_Point3 DT_Polyhedron::support(const MT_Vector3& v) const 
+{
+	m_curr_vertex = m_start_vertex;
+    MT_Scalar d = (*this)[m_curr_vertex].dot(v);
+    MT_Scalar h = d;
+	int curr_layer;
+	for (curr_layer = m_cobound[m_start_vertex].size(); curr_layer != 0; --curr_layer)
+	{
+		const DT_IndexArray& curr_cobound = m_cobound[m_curr_vertex][curr_layer-1];
+        DT_Index i;
+		for (i = 0; i != curr_cobound.size(); ++i) 
+		{
+			d = (*this)[curr_cobound[i]].dot(v);
+			if (d > h)
+			{
+				m_curr_vertex = curr_cobound[i];
+				h = d;
+			}
+		}
+	}
+	
+    return (*this)[m_curr_vertex];
+}
+
+#else
+
+MT_Scalar DT_Polyhedron::supportH(const MT_Vector3& v) const 
+{
+    int last_vertex = -1;
+    MT_Scalar d = (*this)[m_curr_vertex].dot(v);
+    MT_Scalar h = d;
+	
+	for (;;) 
+	{
+        DT_IndexArray& curr_cobound = m_cobound[m_curr_vertex][0];
+        int i = 0, n = curr_cobound.size(); 
+        while (i != n && 
+               (curr_cobound[i] == last_vertex || 
+				(d = (*this)[curr_cobound[i]].dot(v)) - h <= MT_abs(h) * MT_EPSILON)) 
+		{
+            ++i;
+		}
+		
+        if (i == n) 
+		{
+			break;
+		}
+		
+        last_vertex = m_curr_vertex;
+        m_curr_vertex = curr_cobound[i];
+        h = d;
+    }
+    return h;
+}
+
+MT_Point3 DT_Polyhedron::support(const MT_Vector3& v) const 
+{
+	int last_vertex = -1;
+    MT_Scalar d = (*this)[m_curr_vertex].dot(v);
+    MT_Scalar h = d;
+	
+    for (;;)
+	{
+        DT_IndexArray& curr_cobound = m_cobound[m_curr_vertex][0];
+        int i = 0, n = curr_cobound.size();
+        while (i != n && 
+               (curr_cobound[i] == last_vertex || 
+				(d = (*this)[curr_cobound[i]].dot(v)) - h <= MT_abs(h) * MT_EPSILON)) 
+		{
+            ++i;
+		}
+		
+        if (i == n)
+		{
+			break;
+		}
+		
+		last_vertex = m_curr_vertex;
+        m_curr_vertex = curr_cobound[i];
+        h = d;
+    }
+    return (*this)[m_curr_vertex];
+}
+
+#endif
+
+#endif
+
diff --git a/extern/solid/src/convex/DT_Polyhedron.h b/extern/solid/src/convex/DT_Polyhedron.h
new file mode 100644
index 00000000000..58c991bd152
--- /dev/null
+++ b/extern/solid/src/convex/DT_Polyhedron.h
@@ -0,0 +1,76 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_POLYHEDRON_H
+#define DT_POLYHEDRON_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+# if HAVE_QHULL_QHULL_A_H
+#  define QHULL
+# endif
+#endif
+
+
+#ifdef QHULL
+
+#include "DT_Convex.h"
+#include "DT_IndexArray.h"
+#include "DT_VertexBase.h"
+
+class DT_Polyhedron : public DT_Convex {
+	typedef DT_Array T_MultiIndexArray;
+public:
+	DT_Polyhedron() 
+		: m_verts(0),
+		  m_cobound(0)
+	{}
+		
+	DT_Polyhedron(const DT_VertexBase *base, DT_Count count, const DT_Index *indices);
+
+	virtual ~DT_Polyhedron();
+    
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+
+	const MT_Point3& operator[](int i) const { return m_verts[i]; }
+    DT_Count numVerts() const { return m_count; }
+
+private:
+	DT_Count              m_count;
+	MT_Point3			 *m_verts;
+	T_MultiIndexArray    *m_cobound;
+    DT_Index              m_start_vertex;
+	mutable DT_Index      m_curr_vertex;
+};
+
+#else 
+
+#include "DT_Polytope.h"
+
+typedef DT_Polytope DT_Polyhedron;
+
+#endif
+
+#endif
+
diff --git a/extern/solid/src/convex/DT_Polytope.cpp b/extern/solid/src/convex/DT_Polytope.cpp
new file mode 100644
index 00000000000..e757c3bfdb4
--- /dev/null
+++ b/extern/solid/src/convex/DT_Polytope.cpp
@@ -0,0 +1,69 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Polytope.h"
+
+MT_BBox DT_Polytope::bbox() const 
+{
+	MT_BBox bbox = (*this)[0];
+	DT_Index i;
+    for (i = 1; i < numVerts(); ++i) 
+	{
+        bbox = bbox.hull((*this)[i]);
+    }
+    return bbox;
+}
+
+MT_Scalar DT_Polytope::supportH(const MT_Vector3& v) const 
+{
+    int c = 0;
+    MT_Scalar h = (*this)[0].dot(v), d;
+	DT_Index i;
+    for (i = 1; i < numVerts(); ++i) 
+	{
+        if ((d = (*this)[i].dot(v)) > h) 
+		{ 
+			c = i; 
+			h = d; 
+		}
+    }
+    return h;
+}
+
+MT_Point3 DT_Polytope::support(const MT_Vector3& v) const 
+{
+    int c = 0;
+    MT_Scalar h = (*this)[0].dot(v), d;
+	DT_Index i;
+    for (i = 1; i < numVerts(); ++i)
+	{
+        if ((d = (*this)[i].dot(v)) > h)
+		{ 
+			c = i;
+			h = d; 
+		}
+    }
+    return (*this)[c];
+}
+
+
diff --git a/extern/solid/src/convex/DT_Polytope.h b/extern/solid/src/convex/DT_Polytope.h
new file mode 100644
index 00000000000..c715598defe
--- /dev/null
+++ b/extern/solid/src/convex/DT_Polytope.h
@@ -0,0 +1,51 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_POLYTOPE_H
+#define DT_POLYTOPE_H
+
+#include "DT_Convex.h"
+#include "DT_IndexArray.h"
+#include "DT_VertexBase.h"
+
+class DT_Polytope : public DT_Convex {
+public:	
+	DT_Polytope() {}
+    DT_Polytope(const DT_VertexBase *base, DT_Count count, const DT_Index *indices) 
+	  : m_base(base), 
+		m_index(count, indices) 
+	{}
+ 
+	virtual MT_BBox bbox() const;
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+
+	MT_Point3 operator[](int i) const { return (*m_base)[m_index[i]]; }
+    DT_Count numVerts() const { return m_index.size(); }
+
+protected:
+    const DT_VertexBase *m_base;
+    DT_IndexArray        m_index;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Shape.h b/extern/solid/src/convex/DT_Shape.h
new file mode 100644
index 00000000000..d48942fe515
--- /dev/null
+++ b/extern/solid/src/convex/DT_Shape.h
@@ -0,0 +1,72 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_SHAPE_H
+#define DT_SHAPE_H
+
+#include 
+
+#include "MT_BBox.h"
+
+#include "MT_Transform.h"
+
+class DT_Object;
+
+enum DT_ShapeType {
+    COMPLEX,
+    CONVEX
+};
+
+class DT_Shape {
+public:
+    virtual ~DT_Shape() {}
+    virtual DT_ShapeType getType() const = 0;
+	virtual MT_BBox bbox(const MT_Transform& t, MT_Scalar margin) const = 0;
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target, MT_Scalar& param, MT_Vector3& normal) const = 0;
+
+protected:
+	DT_Shape()  {}
+};
+
+typedef bool (*Intersect)(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						  const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+						  MT_Vector3&);
+
+typedef bool (*Common_point)(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						     const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+			                 MT_Vector3&, MT_Point3&, MT_Point3&);
+
+typedef bool (*Penetration_depth)(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						          const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+                                  MT_Vector3&, MT_Point3&, MT_Point3&);
+
+typedef MT_Scalar (*Closest_points)(const DT_Shape& a, const MT_Transform& a2w, MT_Scalar a_margin,
+						            const DT_Shape& b, const MT_Transform& b2w, MT_Scalar b_margin,
+									MT_Point3&, MT_Point3&);
+
+#endif
+
+
+
+
+
diff --git a/extern/solid/src/convex/DT_Sphere.cpp b/extern/solid/src/convex/DT_Sphere.cpp
new file mode 100644
index 00000000000..3f2443dcf53
--- /dev/null
+++ b/extern/solid/src/convex/DT_Sphere.cpp
@@ -0,0 +1,90 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#include "DT_Sphere.h"
+#include "GEN_MinMax.h"
+
+MT_Scalar DT_Sphere::supportH(const MT_Vector3& v) const 
+{
+	return m_radius * v.length();
+}
+
+MT_Point3 DT_Sphere::support(const MT_Vector3& v) const 
+{
+   MT_Scalar s = v.length();
+	
+	if (s > MT_Scalar(0.0))
+	{
+		s = m_radius / s;
+		return MT_Point3(v[0] * s, v[1] * s, v[2] * s);
+	}
+	else
+	{
+		return MT_Point3(m_radius, MT_Scalar(0.0), MT_Scalar(0.0));
+	}
+}
+
+bool DT_Sphere::ray_cast(const MT_Point3& source, const MT_Point3& target,
+						 MT_Scalar& param, MT_Vector3& normal) const 
+{
+	MT_Vector3 r = target - source;
+	MT_Scalar  delta = -source.dot(r);  
+	MT_Scalar  r_length2 = r.length2();
+	MT_Scalar  sigma = delta * delta - r_length2 * (source.length2() - m_radius * m_radius);
+
+	if (sigma >= MT_Scalar(0.0))
+		// The line trough source and target intersects the sphere.
+	{
+		MT_Scalar sqrt_sigma = MT_sqrt(sigma);
+		// We need only the sign of lambda2, so the division by the positive 
+		// r_length2 can be left out.
+		MT_Scalar lambda2 = (delta + sqrt_sigma) /* / r_length2 */ ;
+		if (lambda2 >= MT_Scalar(0.0))
+			// The ray points at the sphere
+		{
+			MT_Scalar lambda1 = (delta - sqrt_sigma) / r_length2;
+			if (lambda1 <= param)
+				// The ray hits the sphere, since 
+				// [lambda1, lambda2] overlaps [0, param]. 
+			{
+				if (lambda1 > MT_Scalar(0.0))
+				{
+					param = lambda1;
+					normal = (source + r * lambda1) / m_radius;
+					// NB: division by m_radius to normalize the normal.
+				}
+				else
+				{
+					param = MT_Scalar(0.0);
+					normal.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+				}
+						
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+
diff --git a/extern/solid/src/convex/DT_Sphere.h b/extern/solid/src/convex/DT_Sphere.h
new file mode 100644
index 00000000000..92386a66f3a
--- /dev/null
+++ b/extern/solid/src/convex/DT_Sphere.h
@@ -0,0 +1,43 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_SPHERE_H
+#define DT_SPHERE_H
+
+#include "DT_Convex.h"
+
+class DT_Sphere : public DT_Convex {
+public:
+   DT_Sphere(MT_Scalar radius) : m_radius(radius) {}
+	
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+	virtual MT_Point3 support(const MT_Vector3& v) const;
+	
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target,
+						  MT_Scalar& param, MT_Vector3& normal) const;
+
+protected:
+    MT_Scalar m_radius;
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_Transform.h b/extern/solid/src/convex/DT_Transform.h
new file mode 100644
index 00000000000..a976d48d22b
--- /dev/null
+++ b/extern/solid/src/convex/DT_Transform.h
@@ -0,0 +1,53 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_TRANSFORM_H
+#define DT_TRANSFORM_H
+
+#include "DT_Convex.h"
+
+class DT_Transform : public DT_Convex {
+public:
+	DT_Transform(const MT_Transform& xform, const DT_Convex& child) :
+		m_xform(xform), 
+		m_child(child)
+	{}
+
+	virtual MT_Scalar supportH(const MT_Vector3& v) const
+	{
+		return m_child.supportH(v * m_xform.getBasis()) + 
+			   v.dot(m_xform.getOrigin());
+	}
+
+	virtual MT_Point3 support(const MT_Vector3& v) const
+	{
+		return m_xform(m_child.support(v * m_xform.getBasis()));
+	}
+
+private:
+	const MT_Transform& m_xform;
+	const DT_Convex&    m_child;
+};
+
+
+#endif
diff --git a/extern/solid/src/convex/DT_Triangle.cpp b/extern/solid/src/convex/DT_Triangle.cpp
new file mode 100644
index 00000000000..1917910b39d
--- /dev/null
+++ b/extern/solid/src/convex/DT_Triangle.cpp
@@ -0,0 +1,96 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+//#define BACKFACE_CULLING
+
+#include "DT_Triangle.h"
+
+MT_BBox DT_Triangle::bbox() const 
+{
+	return MT_BBox((*this)[0]).hull((*this)[1]).hull((*this)[2]);
+}
+
+MT_Scalar DT_Triangle::supportH(const MT_Vector3& v) const
+{
+    return GEN_max(GEN_max(v.dot((*this)[0]), v.dot((*this)[1])), v.dot((*this)[2]));
+}
+
+MT_Point3 DT_Triangle::support(const MT_Vector3& v) const
+{
+    MT_Vector3 dots(v.dot((*this)[0]), v.dot((*this)[1]), v.dot((*this)[2]));
+
+	return (*this)[dots.maxAxis()];
+}
+
+bool DT_Triangle::ray_cast(const MT_Point3& source, const MT_Point3& target, 
+						   MT_Scalar& param, MT_Vector3& normal) const 
+{
+	MT_Vector3 d1 = (*this)[1] - (*this)[0];
+	MT_Vector3 d2 = (*this)[2] - (*this)[0];
+	MT_Vector3 n = d1.cross(d2);
+	MT_Vector3 r = target - source;
+	MT_Scalar delta = -r.dot(n);
+
+   MT_Scalar rounding_error = GEN_max(GEN_max(MT_abs(n[0]), MT_abs(n[1])), MT_abs(n[2])) * MT_EPSILON; 
+
+#ifdef BACKFACE_CULLING	
+   if (delta > rounding_error)
+#else
+	if (MT_abs(delta) > rounding_error)
+#endif      
+		// The ray is not parallel to the triangle's plane. 
+		// (Coplanar rays are ignored.)
+	{
+		MT_Vector3 b = source - (*this)[0];
+		MT_Scalar lambda = b.dot(n) / delta;
+
+		if (MT_Scalar(0.0) <= lambda && lambda <= param)
+			// The ray intersects the triangle's plane.
+		{
+			MT_Vector3 u = b.cross(r);
+			MT_Scalar mu1 = d2.dot(u) / delta;
+
+			if (MT_Scalar(0.0) <= mu1 && mu1 <= MT_Scalar(1.0)) 
+			{
+				MT_Scalar mu2 = -d1.dot(u) / delta;
+
+				if (MT_Scalar(0.0) <= mu2 && mu1 + mu2 <= MT_Scalar(1.0)) 
+					// The ray intersects the triangle.
+				{
+					param = lambda;
+					// Return a normal that points at the source.
+#ifdef BACKFACE_CULLING
+               normal = n;
+#else
+					normal = delta > MT_Scalar(0.0) ? n : -n;
+#endif
+					return true;
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
+
diff --git a/extern/solid/src/convex/DT_Triangle.h b/extern/solid/src/convex/DT_Triangle.h
new file mode 100644
index 00000000000..4192b5629ac
--- /dev/null
+++ b/extern/solid/src/convex/DT_Triangle.h
@@ -0,0 +1,63 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_TRIANGLE_H
+#define DT_TRIANGLE_H
+
+#include "SOLID_types.h"
+
+#include "DT_Convex.h"
+#include "DT_IndexArray.h"
+#include "DT_VertexBase.h"
+
+class DT_Triangle : public DT_Convex {
+public:
+    DT_Triangle(const DT_VertexBase *base, DT_Index i0, DT_Index i1, DT_Index i2) : 
+        m_base(base)
+	{
+		m_index[0] = i0;
+		m_index[1] = i1;
+		m_index[2] = i2;
+	}
+
+    DT_Triangle(const DT_VertexBase *base, const DT_Index *index) : 
+        m_base(base)
+	{
+		m_index[0] = index[0];
+		m_index[1] = index[1];
+		m_index[2] = index[2];
+	}
+
+	virtual MT_BBox bbox() const;
+    virtual MT_Scalar supportH(const MT_Vector3& v) const;
+    virtual MT_Point3 support(const MT_Vector3& v) const;
+	virtual bool ray_cast(const MT_Point3& source, const MT_Point3& target, MT_Scalar& lambda, MT_Vector3& normal) const;
+
+    MT_Point3 operator[](int i) const { return (*m_base)[m_index[i]]; }
+
+private:
+    const DT_VertexBase *m_base;
+    DT_Index             m_index[3];
+};
+
+#endif
diff --git a/extern/solid/src/convex/DT_VertexBase.h b/extern/solid/src/convex/DT_VertexBase.h
new file mode 100644
index 00000000000..37646fdd935
--- /dev/null
+++ b/extern/solid/src/convex/DT_VertexBase.h
@@ -0,0 +1,84 @@
+/*
+ * SOLID - Software Library for Interference Detection
+ * 
+ * Copyright (C) 2001-2003  Dtecta.  All rights reserved.
+ *
+ * This library may be distributed under the terms of the Q Public License
+ * (QPL) as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This library may be distributed and/or modified under the terms of the
+ * GNU General Public License (GPL) version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Commercial use or any other use of this library not covered by either 
+ * the QPL or the GPL requires an additional license from Dtecta. 
+ * Please contact info@dtecta.com for enquiries about the terms of commercial
+ * use of this library.
+ */
+
+#ifndef DT_VERTEXBASE_H
+#define DT_VERTEXBASE_H
+
+#include "MT_Point3.h"
+
+#include 
+
+class DT_Complex;
+
+typedef std::vectorDT_ComplexList;
+
+class DT_VertexBase {
+public:
+    explicit DT_VertexBase(const void *base = 0, DT_Size stride = 0, bool owner = false) : 
+        m_base((char *)base),
+		m_stride(stride ? stride : 3 * sizeof(DT_Scalar)),
+		m_owner(owner)
+	{}
+	
+	~DT_VertexBase()
+	{
+		if (m_owner)
+		{
+			delete [] m_base;
+		}
+	}
+    
+    MT_Point3 operator[](DT_Index i) const 
+	{ 
+        return MT_Point3(reinterpret_cast(m_base + i * m_stride));
+    }
+    
+    void setPointer(const void *base, bool owner = false)
+	{
+		m_base = (char *)base; 
+		m_owner = owner;
+	} 
+	
+    const void *getPointer() const { return m_base; }	
+	bool        isOwner() const { return m_owner; }
+    
+	void addComplex(DT_Complex *complex) const { m_complexList.push_back(complex); }
+	void removeComplex(DT_Complex *complex) const
+	{
+		DT_ComplexList::iterator it = std::find(m_complexList.begin(), m_complexList.end(), complex); 
+		if (it != m_complexList.end())
+		{
+			m_complexList.erase(it);
+		}
+	}
+	
+	const DT_ComplexList& getComplexList() const { return m_complexList; }
+	
+private:    
+    char                  *m_base;
+    DT_Size                m_stride;
+	bool                   m_owner;
+	mutable DT_ComplexList m_complexList;
+};
+
+#endif
diff --git a/extern/solid/src/convex/Makefile b/extern/solid/src/convex/Makefile
new file mode 100644
index 00000000000..406a89f2989
--- /dev/null
+++ b/extern/solid/src/convex/Makefile
@@ -0,0 +1,44 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = solid_convex
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+
+CPPFLAGS += -I../../include -I$(NAN_QHULL)/include
+CPPFLAGS += -DQHULL -DUSE_DOUBLES
+
+include nan_compile.mk 
+
+
diff --git a/extern/verse/CMakeLists.txt b/extern/verse/CMakeLists.txt
new file mode 100644
index 00000000000..409372c10f6
--- /dev/null
+++ b/extern/verse/CMakeLists.txt
@@ -0,0 +1,31 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SUBDIRS(dist)
+
diff --git a/extern/verse/Makefile b/extern/verse/Makefile
new file mode 100644
index 00000000000..2e88ee2223f
--- /dev/null
+++ b/extern/verse/Makefile
@@ -0,0 +1,58 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2002 by Hans Lambermont
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jiri Hnidek
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+LIBNAME = verse
+SOURCEDIR = extern/$(LIBNAME)
+DIR = $(OCGDIR)/$(SOURCEDIR)
+DIRS = dist
+
+include nan_subdirs.mk
+include nan_compile.mk
+include nan_link.mk
+
+DISTDIR = dist
+CP = ../../intern/tools/cpifdiff.sh
+
+ifeq ($(OS),windows)
+    EXT = .exe
+endif
+
+install: all debug
+	@[ -d $(NAN_VERSE) ] || mkdir -p $(NAN_VERSE)
+	@[ -d $(NAN_VERSE)/include ] || mkdir -p $(NAN_VERSE)/include
+	@[ -d $(NAN_VERSE)/lib ] || mkdir -p $(NAN_VERSE)/lib
+	@[ -d $(OCGDIR)/bin ] || mkdir -p $(OCGDIR)/bin
+	@$(CP) $(DISTDIR)/*.h $(NAN_VERSE)/include
+	@$(CP) $(DIR)/libverse.a $(NAN_VERSE)/lib
+ifeq ($(OS),darwin)
+	ranlib $(NAN_VERSE)/lib/libverse.a
+endif
+	$(CCC) $(LDFLAGS) -o $(DIR)/verse$(EXT) $(DIR)/libverse.a $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS)
+	@$(CP) $(DIR)/verse$(EXT) $(OCGDIR)/bin
diff --git a/extern/verse/dist/BUGS b/extern/verse/dist/BUGS
new file mode 100644
index 00000000000..8c3603a3a45
--- /dev/null
+++ b/extern/verse/dist/BUGS
@@ -0,0 +1,8 @@
+
+Known problems with Verse
+
+2004-03-03
+* The source code needs plenty of cleaning up in order to compile more
+  cleanly.
+* License information needs to be added all over the place.
+* Decent documentation is missing.
diff --git a/extern/verse/dist/CMakeLists.txt b/extern/verse/dist/CMakeLists.txt
new file mode 100644
index 00000000000..2f8fcd0b449
--- /dev/null
+++ b/extern/verse/dist/CMakeLists.txt
@@ -0,0 +1,93 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SUBDIRS(mkprot_cmd)
+
+SET(SRC_MKPROT_OUT
+  v_gen_pack_init.c
+  v_gen_pack_a_node.c
+  v_gen_pack_b_node.c
+  v_gen_pack_c_node.c
+  v_gen_pack_g_node.c
+  v_gen_pack_m_node.c
+  v_gen_pack_o_node.c
+  v_gen_pack_s_node.c
+  v_gen_pack_t_node.c
+)
+
+SET(INC .)
+
+SET(SRC
+  v_cmd_buf.c
+  v_connect.c
+  v_connection.c
+  v_encryption.c
+  v_func_storage.c
+  v_man_pack_node.c
+  v_network.c
+  v_network_in_que.c
+  v_network_out_que.c
+  v_pack.c
+  v_pack_method.c
+  v_prime.c
+  v_randgen.c
+  v_util.c
+  v_bignum.c
+  verse_ms.c
+  ${SRC_MKPROT_OUT}
+)
+
+BLENDERLIB(verse "${SRC}" "${INC}")
+ADD_DEPENDENCIES(verse mkprot)
+#verselib = env.BlenderLib(libname='verse', sources=lib_source_files, includes=[], defines=defines, libtype=['core', 'intern'], priority = [5, 5])
+
+SET(SRC_VERSE
+  vs_connection.c
+  vs_main.c
+  vs_node_audio.c
+  vs_node_bitmap.c
+  vs_node_curve.c
+  vs_node_geometry.c
+  vs_node_head.c
+  vs_node_material.c
+  vs_node_object.c
+  vs_node_particle.c
+  vs_node_storage.c
+  vs_node_text.c
+  vs_master.c  
+)
+
+ADD_EXECUTABLE(verse_server ${SRC_VERSE})
+IF(WIN32)
+TARGET_LINK_LIBRARIES(verse_server verse ws2_32)
+ELSE(WIN32)
+TARGET_LINK_LIBRARIES(verse_server verse)
+ENDIF(WIN32)
+ADD_DEPENDENCIES(verse_server mkprot)
+MESSAGE(STATUS "Configuring verse_server")
diff --git a/extern/verse/dist/MAINTAINERS b/extern/verse/dist/MAINTAINERS
new file mode 100644
index 00000000000..c467d5309b8
--- /dev/null
+++ b/extern/verse/dist/MAINTAINERS
@@ -0,0 +1,15 @@
+
+			Verse Maintainers
+
+This file tries to list credits for the various parts of the
+Verse core distribution, and also identify who maintains what.
+
+We are deeply appreciative of any contributions and thank you
+all for your time and interest in helping make Verse a better
+thing.
+
+* All code was originally written by Eskil Steenberg, and is
+  being maintained by him and Emil Brink. Contact us through
+  the project page at http://www.blender.org/modules/verse/.
+
+* SCons build file by N. Letwory, http://www.jester-depot.net/.
diff --git a/extern/verse/dist/Makefile b/extern/verse/dist/Makefile
new file mode 100644
index 00000000000..69b5590b2bc
--- /dev/null
+++ b/extern/verse/dist/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for Verse core; API and reference server.
+# This pretty much requires GNU Make, I think.
+#
+# This build is slightly complicated that part of the C code that
+# needs to go into the API implementation is generated by building
+# and running other C files (this is the protocol definition).
+#
+
+LIBNAME = verse
+DIR = $(OCGDIR)/extern/$(LIBNAME)
+
+include nan_compile.mk
+
+# TARGETS = verse
diff --git a/extern/verse/dist/Makefile.win32 b/extern/verse/dist/Makefile.win32
new file mode 100644
index 00000000000..548881c6a16
--- /dev/null
+++ b/extern/verse/dist/Makefile.win32
@@ -0,0 +1,102 @@
+#
+# Makefile for Verse core; API and reference server.
+# Written by modifying the main GNU Makefile, for nmake.
+#
+# It is more hard-coded, relying on less intelligence in
+# the make tool.
+#
+# This build is slightly complicated that part of the C code that
+# needs to go into the API implementation is generated by building
+# and running other C files (this is the protocol definition).
+#
+
+CC	= cl
+CFLAGS	= 
+LDFLAGS	= -pg
+
+AR	= ar
+ARFLAGS	= rus
+RANLIB	= ranlib
+
+TARGETS = verse.lib verse.exe
+
+# Automatically generated protocol things.
+PROT_DEF  = v_cmd_def_a.c v_cmd_def_b.c v_cmd_def_c.c v_cmd_def_g.c v_cmd_def_m.c v_cmd_def_o.c v_cmd_def_s.c v_cmd_def_t.c
+PROT_TOOL = v_cmd_gen.c $(PROT_DEF)
+PROT_OUT  = v_gen_pack_init.c v_gen_unpack_func.h verse.h \
+	    v_gen_pack_a_node.c v_gen_pack_b_node.c v_gen_pack_c_node.c v_gen_pack_g_node.c v_gen_pack_m_node.c v_gen_pack_o_node.c v_gen_pack_s_node.c v_gen_pack_t_node.c
+
+# The API implementation is the protocol code plus a few bits.
+LIBVERSE_SRC =  v_gen_pack_init.c v_gen_unpack_func.h verse.h v_gen_pack_a_node.c v_gen_pack_b_node.c v_gen_pack_c_node.c v_gen_pack_g_node.c \
+		v_gen_pack_m_node.c v_gen_pack_o_node.c v_gen_pack_s_node.c v_gen_pack_t_node.c \
+		v_bignum.c v_cmd_buf.c v_connect.c \
+		v_connection.c v_connection.h v_encryption.c \
+		v_func_storage.c v_internal_verse.h v_man_pack_node.c \
+		v_network.c v_network.h v_network_in_que.c v_network_out_que.c \
+		v_pack.c v_pack.h v_pack_method.c v_prime.c v_randgen.c v_util.c
+
+LIBVERSE_OBJ = v_gen_pack_init.obj v_gen_pack_a_node.obj v_gen_pack_b_node.obj v_gen_pack_c_node.obj v_gen_pack_g_node.obj \
+		v_gen_pack_m_node.obj v_gen_pack_o_node.obj v_gen_pack_s_node.obj v_gen_pack_t_node.obj \
+		v_bignum.obj v_cmd_buf.obj v_connect.obj \
+		v_connection.obj v_encryption.obj \
+		v_func_storage.obj v_man_pack_node.obj \
+		v_network.obj v_network_in_que.obj v_network_out_que.obj \
+		v_pack.obj v_pack_method.obj v_prime.obj v_randgen.obj v_util.obj
+
+# The server is a simple 1:1 mapping, but in Windows nmake ... That doesn't help much. :/
+VERSE_SRC = vs_connection.c vs_main.c vs_master.c vs_node_audio.c vs_node_bitmap.c vs_node_curve.c vs_node_geometry.c vs_node_head.c vs_node_material.c vs_node_object.c vs_node_particle.c vs_node_storage.c vs_node_text.c
+VERSE_OBJ = vs_connection.obj vs_main.obj vs_master.obj vs_node_audio.obj vs_node_bitmap.obj vs_node_curve.obj vs_node_geometry.obj \
+	vs_node_head.obj vs_node_material.obj vs_node_object.obj vs_node_particle.obj vs_node_storage.obj vs_node_text.obj
+
+# -----------------------------------------------------
+
+ALL:		verse.lib verse.exe
+
+verse.exe:	$(VERSE_OBJ) verse.lib resources\verse.res
+		cl /Fe$@ $** wsock32.lib
+
+verse.lib:	$(LIBVERSE_OBJ)
+		link /lib /nologo /out:$@ $**
+
+# -----------------------------------------------------
+
+# Here are the automatically generated pieces of the puzzle.	
+# Basically, we generate v_gen_pack_X_node.c files by compiling
+# the v_cmd_def_X.c files together with some driver glue and
+# running the result.
+#
+
+# The autogen outputs all depend on the tool.
+$(PROT_OUT):	mkprot.exe
+		mkprot.exe
+
+# Build the protocol maker, from the definitions themselves.
+mkprot.exe:	$(PROT_TOOL) verse_header.h
+		$(CC) /DV_GENERATE_FUNC_MODE /Fe$@ $(PROT_TOOL)
+
+# Clean away all the generated parts of the protocol implementation.
+cleanprot:	clean
+		del mkprot $(PROT_OUT) mkprot.exe
+
+# -----------------------------------------------------
+
+clean:
+	del *.obj $(TARGETS)
+
+# -----------------------------------------------------
+
+# Utter ugliness to create release archives. Needs to improve, but should work for a while.
+dist:
+	RELEASE=$$( \
+	R=`grep V_RELEASE_NUMBER verse.h | tr -s ' \t' | tr -d '"\r' | cut -d'	' -f3` ; \
+	P=`grep V_RELEASE_PATCH verse.h | tr -s ' \t' | tr -d '"\r' | cut -d'	' -f3` ; \
+	L=`grep V_RELEASE_LABEL verse.h | tr -s ' \t' | tr -d '"\r' | cut -d'	' -f3` ; echo r$${R}p$$P$$L ) ; \
+	if [ $$RELEASE ]; then ( \
+	 rm -rf  /tmp/verse; \
+	 mkdir -p /tmp/verse; \
+	 cp -a * /tmp/verse; \
+	 cd /tmp && zip verse-$$RELEASE.zip -r verse -x 'verse/*CVS*' -x 'verse/.*' ; \
+	 ); mv /tmp/verse-$$RELEASE.zip . \
+	;else \
+	  echo "Couldn't auto-set RELEASE from verse.h, something is fishy" \
+	;fi
diff --git a/extern/verse/dist/README.html b/extern/verse/dist/README.html
new file mode 100644
index 00000000000..b3b3050bf12
--- /dev/null
+++ b/extern/verse/dist/README.html
@@ -0,0 +1,173 @@
+
+
+
+
+Verse README
+
+
+
+
+

Verse

+ +

+This is the Verse protocol and sample server implementations. +

+

+For more information, see the Verse web site. +

+

Building the Verse Core

+

+Note: This section is only of interest to developers, who wish to build the Verse core themselves. +If you have chosen a binary download, you will already have the server and can skip the rest +of this section. +

+

+Running "make" here will build the API library, "libverse.a" (and its +header file, "verse.h"). These two will then be used to build the +reference Verse server binary, called "verse". +

+

+If you are more comfortable with SCons, and of course have it +installed on your system, you can type "scons" instead. +

+ +

Starting the Server

+

+The Verse server is a command-line program, without a graphical user interface. +You simply start it, and it will immediately begin listening for incoming +connections on a network socket. Here is how a typical invocation looks: +

+
~> verse
+
+

+If you don't ask it to do otherwise, the Verse server will start listening for UDP packets +on its default port. The port number currently used by Verse is 4950. +

+

+Note: This is not an official registered, port number. +It is possible that it gets assigned to someone else, in case Verse will need to change. +

+

+You can use the following command line options to control the server's operation: +

+
+
-h
+
+ Print a help text, that shows all understood options. +
+
-ms
+
+ Enables master server communications to the default, built-in address. Use the -h option to learn + what this address is. Please note that master server communication is disabled by default. +
+
-ms:ip=IP
+
+ Sets a new address to use for master server communication. This also implies -ms, i.e. the server + will try to register itself with the given master server. For details on the protocol used to do + this, please see the spec. +
+
-ms:de=DESC
+
+ Sets the description to use for this server, when registering with the the master server. This is + only used if master server communication is actually enabled. The description is expected to be a + human-readable string, like "A test server, run on a cable modem, and offline during local daytime" + or something. +
+
-ms:ta=TAGS
+
+ Sets the tags to use for this server, when registering with the the master server. This is only used + if master server communication is actually enabled. The tags consists of a comma-separated list of + single words. Each word must begin with a letter, and contain only letters, digits, or underscore + characters. For instance: home,r6p1,linux,sweden,open. +
+
-port=N
+
+ Use the indicated port number, rather than the default. Note that ports below 1024 are generally + off-limits to ordinary users. Running Verse on such a port is not recommended. +
+
-version
+
+ Prints the version string of the server to the terminal, and then exits (successfully). See + below for information how the version string is constructed. +
+
+

+For example, here is how to start the server, register it with the default master server, and run +on port number equal to 16333: +

+
~> ./server -ms -port=16333
+
+

+Here is a more complicated example, that uses an explicit master server address, and also sets both +the description and tags: +

+
~> ./server -ms:ip=master.example.net -ms:de="A test server, for the documentation" -ms:ta=example,docs
+
+

+Options can occur in any order, with later options overriding earlier ones, in case of conflicts. +

+ +

Release Labeling

+

+Verse uses a simple two-level numbering scheme to identify releases. +There is a "release number", and a "patch level" on each release. The +intent is that within a release, the API does not change and neither +should the network protocol. Between releases, we might improve the +API which will require application programmers to update their code +to stay in sync. We can do non-API-altering changes within a release +by increasing the patch level, for bug fixing and other things. +

+

+The symbols V_RELEASE_NUMBER and V_RELEASE_PATCH +are integer literals that hold the values for the API you have, and can be +used (and displayed) in application source code as you see fit. There is +also a string, V_RELEASE_LABEL, which is sometimes used. +

+

+To form a complete Verse version number, the above-mentioned symbols are +to be combined like so: +"r<V_RELEASE_NUMBER>p<V_RELEASE_PATCH><V_RELEASE_LABEL>". +So, the following variable values: +

    +
  • V_RELEASE_VERSION = 2 +
  • V_RELEASE_VERSION = 51 +
  • V_RELEASE_LABEL = "foo" +
+Would generate the version string "r2p51foo". +

+ + + diff --git a/extern/verse/dist/SConstruct b/extern/verse/dist/SConstruct new file mode 100644 index 00000000000..ecdc3178028 --- /dev/null +++ b/extern/verse/dist/SConstruct @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# +# I think it is quite straight-forward to add new platforms, +# just look at the old makefile and at the existing platforms. +# +# This SConstruct creates a configuration file which can be +# used for tweaking a build. +# +# For more about SConstruct, see . +# + +import os +import os.path +import sys +import re +import time +import string +from distutils import sysconfig + +Import('env') + +defines = [] +cflags = [] +debug_flags = [] +extra_flags = [] +release_flags = [] +warn_flags = [] +platform_libs = [] +platform_libpath = [] +platform_linkflags = [] + +ourplatform = env['OURPLATFORM'] +if ourplatform == 'win32-vc': + print "Building on win32" + defines += ['_WIN32'] + warn_flags = ['/Wall'] + platform_libs = ['ws2_32'] +elif ourplatform == 'win32-mingw': + defines += ['_WIN32', 'WIN32'] + platform_libs = ['shell32', 'kernel32', 'gdi32', 'user32', 'ws2_32'] +elif ourplatform == 'linux2': + print "Building on linux2" +elif ourplatform == 'openbsd3': + print "Building on openbsd3" + +root_build_dir = env['BF_BUILDDIR'] + +if env['VERSE_BUILD_BINARY'] == 'release': + cflags = extra_flags + release_flags + warn_flags + if ourplatform == 'win32-vc': + defines += ['NDEBUG'] +else: + cflags = extra_flags + debug_flags + warn_flags + if ourplatform == 'win32-vc': + #defines += ['_DEBUG'] specifying this makes msvc want to link to python22_d.lib?? + platform_linkflags += ['/DEBUG','/PDB:verse.pdb'] + + +verse_env = env.Copy() + +cmd_gen_files = (['v_cmd_gen.c', + 'v_cmd_def_a.c', + 'v_cmd_def_b.c', + 'v_cmd_def_c.c', + 'v_cmd_def_g.c', + 'v_cmd_def_m.c', + 'v_cmd_def_o.c', + 'v_cmd_def_s.c', + 'v_cmd_def_t.c' + ]) + +cmd_gen_deps = (['v_gen_pack_init.c']) + +proto_env = env.Copy() +proto_env.Append(CPPDEFINES=['V_GENERATE_FUNC_MODE']) +mkprot_tool = proto_env.Program(target = 'mkprot', source = cmd_gen_files) + +mkprot_re = re.compile('v_cmd_def_([a-z]{1}).c') +def mkprot_emitter(target = None, source = None, env = None): + newtargets = list() + for s in source: + p, f = os.path.split(str(s)) + m = mkprot_re.match(f) + if m: + newtargets.append("v_gen_pack_"+m.group(1)+"_node.c") + newtargets.extend(['verse.h']) + env.Depends(newtargets, mkprot_tool) + return (newtargets, source) + +mkprot_bld = Builder(action = "\"" + mkprot_tool[0].abspath + "\" -src=\""+os.getcwd()+os.sep+"extern"+os.sep+"verse"+os.sep+"dist"+os.sep+os.sep+"\" -dst=\""+os.path.abspath(env['BF_BUILDDIR'])+os.sep+"extern"+os.sep+"verse"+os.sep+"dist"+os.sep+os.sep+"\"", + emitter = mkprot_emitter) + +verse_env['BUILDERS']['Protocol'] = mkprot_bld + +cmd_gen_deps.extend(verse_env.Protocol('do_mkprot', cmd_gen_files)) + +cmd_gen_deps.pop() + +lib_source_files = (['v_cmd_buf.c', + 'v_connect.c', + 'v_connection.c', + 'v_encryption.c', + 'v_func_storage.c', + 'v_man_pack_node.c', + 'v_network.c', + 'v_network_in_que.c', + 'v_network_out_que.c', + 'v_pack.c', + 'v_pack_method.c', + 'v_prime.c', + 'v_randgen.c', + 'v_util.c', + 'v_bignum.c', + 'verse_ms.c' + ]) +lib_source_files.extend(cmd_gen_deps) + +server_source_files = (['vs_connection.c', + 'vs_main.c', + 'vs_master.c', + 'vs_node_audio.c', + 'vs_node_bitmap.c', + 'vs_node_curve.c', + 'vs_node_geometry.c', + 'vs_node_head.c', + 'vs_node_material.c', + 'vs_node_object.c', + 'vs_node_particle.c', + 'vs_node_storage.c', + 'vs_node_text.c' + ]) + +verselib_env = verse_env.Copy() +verselib_env.Append(CPPDEFINES = defines) + +verseserver_env = verse_env.Copy() +verseserver_env.Append(CPPDEFINES = defines) +verseserver_env.Append (LIBPATH = ['.']) +verseserver_env.Append (LIBS= ['verse']) +verseserver_env.Append (LIBS= platform_libs) + +verselib_env.BlenderLib(libname='verse', sources=lib_source_files, includes=["."], defines = defines, libtype=['core', 'intern', 'player'], priority = [5, 5, 100]) +verseserver_env.BlenderProg(builddir="#"+root_build_dir+os.sep, progname='verse', sources=server_source_files, libs=[], +libpath='#'+env['BF_BUILDDIR']+'/lib') + + diff --git a/extern/verse/dist/examples/list-nodes.c b/extern/verse/dist/examples/list-nodes.c new file mode 100644 index 00000000000..6c9cc000d7c --- /dev/null +++ b/extern/verse/dist/examples/list-nodes.c @@ -0,0 +1,39 @@ +/* A minimalist Verse example. Ask server for nodes, print information. */ + +#include +#include + +#include "verse.h" /* Bring in the Verse API. */ + +/* A callback for connection acception: will be called when server accepts this client. */ +static void callback_accept_connect(void *user, uint32 avatar, void *address, void *connection, uint8 *host_id) +{ + uint32 i, mask = 0; + + printf("Connected to a Verse host!\n\nListing nodes:\n"); + + /* Build node subscription mask. */ + for(i = 0; i < V_NT_NUM_TYPES; i++) + mask |= 1 << i; + verse_send_node_index_subscribe(mask); /* Request listing of all nodes. */ +} + +/* A callback for node creation: is called to report information about existing nodes, too. */ +static void callback_node_create(void *user, VNodeID node_id, VNodeType type, VNodeOwner ownership) +{ + printf(" Node #%u has type %u\n", node_id, type); +} + +int main(void) +{ + /* Register callbacks for interesting commands. */ + verse_callback_set(verse_send_connect_accept, callback_accept_connect, NULL); + verse_callback_set(verse_send_node_create, callback_node_create, NULL); + + /* Kick off program by connecting to Verse host on local machine. */ + verse_send_connect("list-nodes", "", "localhost", NULL); + while(TRUE) + verse_callback_update(10000); /* Listen to network, get callbacks. */ + + return EXIT_SUCCESS; /* This is never reached. */ +} diff --git a/extern/verse/dist/mkprot_cmd/CMakeLists.txt b/extern/verse/dist/mkprot_cmd/CMakeLists.txt new file mode 100644 index 00000000000..c4e3128b7f8 --- /dev/null +++ b/extern/verse/dist/mkprot_cmd/CMakeLists.txt @@ -0,0 +1,55 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(SRC + ../v_cmd_gen.c + ../v_cmd_def_a.c + ../v_cmd_def_b.c + ../v_cmd_def_c.c + ../v_cmd_def_g.c + ../v_cmd_def_m.c + ../v_cmd_def_o.c + ../v_cmd_def_s.c + ../v_cmd_def_t.c +) + +ADD_DEFINITIONS(-DV_GENERATE_FUNC_MODE) +ADD_EXECUTABLE(mkprot ${SRC}) + +# Uncoment the following to get verse to generate the files using dependency +# tracking without having the generated files submitted in CVS. +# +#ADD_CUSTOM_COMMAND(TARGET mkprot +# POST_BUILD +# COMMAND mkprot -src=${CMAKE_CURRENT_SOURCE_DIR}/../ -dst=${CMAKE_CURRENT_SOURCE_DIR}/../ +# MAIN_DEPENDENCY ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/mkprot +# WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR} +#) +MESSAGE(STATUS "Configuring mkprot(verse)") + diff --git a/extern/verse/dist/resources/Makefile.win32 b/extern/verse/dist/resources/Makefile.win32 new file mode 100644 index 00000000000..8e7b4a09bbd --- /dev/null +++ b/extern/verse/dist/resources/Makefile.win32 @@ -0,0 +1,11 @@ +# +# This builds a resource file for the Verse server, for the icon. +# + +ALL: verse.res + +verse.res: verse.rc + + +clean: + del *.res diff --git a/extern/verse/dist/resources/verse.ico b/extern/verse/dist/resources/verse.ico new file mode 100644 index 00000000000..b30f4c927ef Binary files /dev/null and b/extern/verse/dist/resources/verse.ico differ diff --git a/extern/verse/dist/resources/verse.rc b/extern/verse/dist/resources/verse.rc new file mode 100644 index 00000000000..a068a6f3e3e --- /dev/null +++ b/extern/verse/dist/resources/verse.rc @@ -0,0 +1 @@ +1 ICON verse.ico diff --git a/extern/verse/dist/resources/verse.res b/extern/verse/dist/resources/verse.res new file mode 100644 index 00000000000..ed4db6ca27f Binary files /dev/null and b/extern/verse/dist/resources/verse.res differ diff --git a/extern/verse/dist/v_bignum.c b/extern/verse/dist/v_bignum.c new file mode 100644 index 00000000000..3f3ea7f9ccc --- /dev/null +++ b/extern/verse/dist/v_bignum.c @@ -0,0 +1,860 @@ +/* + * Routines for big (thousands of bits) unsigned integers, and + * doing simple maths operations on them. Written by Emil Brink. + * + * Part of the Verse core, see license details elsewhere. + * + * Bignums are represented as vectors of VBigDig (unsigned short), + * where the first element holds the length of the number in such + * digits. So a 32-bit number would be { 2, low, high }; digits are + * in little-endian format. + * + * Verse's uint16 and uint32 types are *not* used, since there is no + * need to limit the bits. If your machine has 32-bit shorts and 64- + * bit ints, this code should cope. + * + * By using unsigned shorts, which are assumed to be half the size of + * an unsigned int, we can easily do intermediary steps in int-sized + * variables, and thus get space for manual carry-management. + * + * This is the second incarnation of this code, the first one used + * a fixed 2,048-bit VBigNum structure passed by value. It had to be + * replaced since it was too weak for the desired functionality. Now, + * there's roughly 1,5 weeks of time gone into this code, which still + * means it's optimized for simplicity rather than speed. + * + * There has been neither time nor interest to meditate over FFTs and + * Karatsubas. Reasonable improvements are of course welcome, although + * this code *should* not be a bottleneck. Famous last words... + * + * In general, these routines do not do a lot of error checking, they + * assume you know what you're doing. Numbers must have >0 digits. + * Shifts should not be overly large (1e3 bits: safe, ~2e9+: avoid). +*/ + +#include +#include +#include +#include + +#include "v_randgen.h" + +#include "v_bignum.h" + +#define MAX_DIG ((1UL << V_BIGBITS) - 1) + +/* ----------------------------------------------------------------------------------------- */ + +/* Some routines need temporary storage to hold a term or two (the multi- + * plier, for instance). Since we don't want to use malloc()/free(), let's + * just have a bunch of digits that it's possible to allocate from in a + * stack-like manner. +*/ +static VBigDig heap[2048 + 32]; +static unsigned int heap_pos; + +/* Allocate a number of digits, returning it un-initialized. */ +static VBigDig * bignum_alloc(unsigned int n) +{ + VBigDig *y; + + if(heap_pos + n > sizeof heap / sizeof *heap) + { + printf("Out of memory in bignum heap -- unbalanced calls?\n"); + return NULL; + } + y = heap + heap_pos; + heap_pos += n + 1; + *y = n; + return y; +} + +/* Free a number previously allocated by bignum_allow() above. MUST match in sequences. */ +static void bignum_free(const VBigDig *x) +{ + heap_pos -= *x + 1; +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Set x from bits. External representation is big-endian byte array. */ +void v_bignum_raw_import(VBigDig *x, const void *bits) +{ + const unsigned char *bytes = bits; + int i; + + for(i = *x++ - 1; i >= 0; i--) + { + x[i] = ((VBigDig) *bytes++) << 8; + x[i] |= *bytes++; + } +} + +/* Set bits to value of x. External representation is big-endian byte array. */ +void v_bignum_raw_export(const VBigDig *x, void *bits) +{ + unsigned char *bytes = bits; + int i; + + for(i = *x++ - 1; i >= 0; i--) + { + *bytes++ = x[i] >> 8; + *bytes++ = (unsigned char) x[i]; + } +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Assigns x = 0. */ +void v_bignum_set_zero(VBigDig *x) +{ + memset(x + 1, 0, *x * sizeof *x); +} + +/* Assigns x = 1. */ +void v_bignum_set_one(VBigDig *x) +{ + int i; + + for(i = *x++ - 1, *x++ = 1; i > 0; i--) + *x++ = 0; +} + +/* Assigns x = y. */ +void v_bignum_set_digit(VBigDig *x, VBigDig y) +{ + v_bignum_set_zero(x); + x[1] = y; +} + +/* Assigns x = , with string in decimal ASCII. Kind of slow. */ +void v_bignum_set_string(VBigDig *x, const char *string) +{ + unsigned int d; + + v_bignum_set_zero(x); + for(; *string && isdigit(*string); string++) + { + v_bignum_mul_digit(x, 10); + d = *string - '0'; + v_bignum_add_digit(x, d); + } +} + +/* Assigns x = , with string in hexadecimal ASCII. */ +void v_bignum_set_string_hex(VBigDig *x, const char *string) +{ + unsigned int d; + + if(string[0] == '0' && (string[1] == 'x' || string[1] == 'X')) + string += 2; + v_bignum_set_zero(x); + for(; *string && isxdigit(*string); string++) + { + v_bignum_bit_shift_left(x, 4); + d = tolower(*string) - '0'; + if(d > 9) + d -= ('a' - '0') - 10; + x[1] |= (d & 0xF); + } +} + +/* Performs x = y, taking care to handle different precisions correctly by truncating. */ +void v_bignum_set_bignum(VBigDig *x, const VBigDig *y) +{ + int xs, ys, i, s; + + xs = x[0]; + ys = y[0]; + if(xs == ys) /* For same sizes, just memcpy() and be done. */ + { + memcpy(x + 1, y + 1, xs * sizeof *x); + return; + } + else if(ys > xs) + s = xs; + else + s = ys; + /* Copy as many digits as will fit, and clear any remaining high digits. */ + for(i = 1; i <= s; i++) + x[i] = y[i]; + for(; i <= xs; i++) + x[i] = 0; +} + +/* Performs x = y[msb:msb-bits], right-adjusting the result. */ +void v_bignum_set_bignum_part(VBigDig *x, const VBigDig *y, unsigned int msb, unsigned int bits) +{ + unsigned int i, bit; + + v_bignum_set_zero(x); + if(y == NULL || msb > (y[0] * (CHAR_BIT * sizeof *x))) + return; + for(i = 0; i < bits; i++) + { + bit = msb - (bits - 1) + i; + if(v_bignum_bit_test(y, bit)) + v_bignum_bit_set(x, i); + } +} + +/* Set x to a random bunch of bits. Should use a real random source. */ +void v_bignum_set_random(VBigDig *x, VRandGen *gen) +{ + unsigned int s = *x++; + + if(gen != NULL) + v_randgen_get(gen, x, s * sizeof *x); + else + { + fprintf(stderr, "** Warning: Calling v_bignum_set_random() without VRandGen is potentially expensive\n"); + if((gen = v_randgen_new()) != NULL) + { + v_randgen_get(gen, x, s * sizeof *x); + v_randgen_destroy(gen); + } + else + fprintf(stderr, __FILE__ ": Couldn't create random number generator\n"); + } +} + +/* Print x in hexadecimal, with 0x prefix but no linefeed. */ +void v_bignum_print_hex(const VBigDig *x) +{ + int i, s = *x; + + printf("0x"); + for(i = 0; i < s; i++) + printf("%04X", x[s - i]); +} + +/* Print x in hexadecimal, with linefeed. */ +void v_bignum_print_hex_lf(const VBigDig *x) +{ + v_bignum_print_hex(x); + printf("\n"); +} + +/* ----------------------------------------------------------------------------------------- */ + +/* x = ~x. */ +void v_bignum_not(VBigDig *x) +{ + unsigned int i, s = *x++; + + for(i = 0; i < s; i++) + x[i] = ~x[i]; +} + +int v_bignum_bit_test(const VBigDig *x, unsigned int bit) +{ + unsigned int slot = bit / (CHAR_BIT * sizeof *x), m = 1 << (bit % (CHAR_BIT * sizeof *x)); + + if(slot < x[0]) + return (x[slot + 1] & m) != 0; + return 0; +} + +/* Compute x |= (1 << bit). */ +void v_bignum_bit_set(VBigDig *x, unsigned int bit) +{ + unsigned int slot, m; + + if(bit >= (*x * (CHAR_BIT * sizeof *x))) + return; + slot = bit / (CHAR_BIT * sizeof *x); + m = 1 << (bit % (CHAR_BIT * sizeof *x)); + x[1 + slot] |= m; +} + +/* Returns index of most signifant '1' bit of x, or -1 if x == 0. */ +int v_bignum_bit_msb(const VBigDig *x) +{ + int i; + unsigned int s = *x++; + + for(i = s - 1; i >= 0; i--) + { + if(x[i] != 0) + { + int bit = (i + 1) * (CHAR_BIT * sizeof *x) - 1; + VBigDig d = x[i], mask; + + for(mask = 1 << (CHAR_BIT * sizeof *x - 1); mask != 0; mask >>= 1, bit--) + { + if(d & mask) + return bit; + } + } + } + return -1; +} + +int v_bignum_bit_size(const VBigDig *x) +{ + return *x * V_BIGBITS; +} + +/* Perform x <<= count. */ +void v_bignum_bit_shift_left(VBigDig *x, unsigned int count) +{ + unsigned int t, carry, s = *x++; + register int i; + + if(count >= CHAR_BIT * sizeof *x) /* Shift whole digits. */ + { + unsigned int places = count / (CHAR_BIT * sizeof *x); + + for(i = s - 1; i >= (int) places; i--) + x[i] = x[i - places]; + for(; i >= 0; i--) /* Clear out the LSBs. */ + x[i] = 0; + count -= places * (CHAR_BIT * sizeof *x); + if(count == 0) + return; + } + /* Shift bits. */ + for(i = carry = 0; i < (int) s; i++) + { + t = (x[i] << count) | carry; + x[i] = t; + carry = t >> (CHAR_BIT * sizeof *x); + } +} + +/* Perform x <<= 1. This is a frequent operation so it can have its own function. */ +void v_bignum_bit_shift_left_1(VBigDig *x) +{ + register unsigned int t, carry, s = *x++, i; + + /* Shift bits. */ + for(i = carry = 0; i < s; i++) + { + t = (x[i] << 1) | carry; + x[i] = t; + carry = t >> (CHAR_BIT * sizeof *x); + } +} + +/* Perform x >>= count. */ +void v_bignum_bit_shift_right(VBigDig *x, unsigned int count) +{ + unsigned int t, carry, s = *x++; + int i; + + /* Shift entire digits first. */ + if(count >= CHAR_BIT * sizeof *x) + { + unsigned int places = count / (CHAR_BIT * sizeof *x); + + if(places > s) + { + memset(x, 0, s * sizeof *x); + return; + } + for(i = 0; i < (int) (s - places); i++) + x[i] = x[i + places]; + for(; i < (int) s; i++) + x[i] = 0; + count -= places * CHAR_BIT * sizeof *x; + if(count == 0) + return; + } + /* Shift any remaining bits. */ + for(i = s - 1, carry = 0; i >= 0; i--) + { + t = x[i] << (CHAR_BIT * sizeof *x); + t >>= count; + t |= carry; + carry = (t & MAX_DIG) << (CHAR_BIT * sizeof *x); + x[i] = t >> (CHAR_BIT * sizeof *x); + } +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Return x == 0. */ +int v_bignum_eq_zero(const VBigDig *x) +{ + unsigned int i, s = *x++; + + for(i = 0; i < s; i++) + if(x[i]) + return 0; + return 1; +} + +/* Return x == 1. */ +int v_bignum_eq_one(const VBigDig *x) +{ + unsigned int i, s = *x++; + + if(x[0] != 1) + return 0; + for(i = 1; i < s; i++) + if(x[i]) + return 0; + return 1; +} + +/* Returns x == y, handling different lengths properly. */ +int v_bignum_eq(const VBigDig *x, const VBigDig *y) +{ + unsigned int i, xs, ys, cs; + + if(x == y) /* Quick test thanks to pointer representation. */ + return 1; + xs = *x++; + ys = *y++; + + if(xs == ys) /* Same size? Then let's be quick about this. */ + return memcmp(x, y, xs * sizeof *x) == 0; + else + { + cs = xs < ys ? xs : ys; /* Common size. */ + if(memcmp(x, y, cs * sizeof *x) == 0) + { + const VBigDig *l; + + if(cs == xs) /* y is longer. */ + l = y, i = ys - 1; + else + l = x, i = xs - 1; + for(; i > cs; i--) + if(l[i]) + return 0; + return 1; + } + } + return 0; +} + +/* Returns x >= y. */ +int v_bignum_gte(const VBigDig *x, const VBigDig *y) +{ + unsigned int xs, ys; + int i, j, k; + + if(x == y) + return 1; + /* Find indexes of highest-most used digit in each of the numbers. */ + xs = *x++; + ys = *y++; + for(i = xs - 1; i >= 0; i--) + if(x[i] != 0) + break; + for(j = ys - 1; j >= 0; j--) + if(y[j] != 0) + break; + /* Both zero? */ + if(i < 0 && j < 0) + return 1; + /* Quick answers exists for different-sized numbers. Find them. */ + if(i < j) + return 0; + if(i > j) + return 1; + /* Compare digit by digit. */ + for(k = i; k >= 0; k--) + { + if(x[k] < y[k]) + return 0; + if(x[k] > y[k]) + return 1; + } + return x[k] >= y[k]; +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Computes x += y. */ +void v_bignum_add_digit(VBigDig *x, VBigDig y) +{ + unsigned int i, s = *x++, t; + + t = x[0] + y; + x[0] = t; + if(t > MAX_DIG) + { + for(i = 1; i < s; i++) + { + if(++x[i]) + break; + } + } +} + +/* Computes x -= y. */ +void v_bignum_sub_digit(VBigDig *x, VBigDig y) +{ + unsigned int i, s = *x++, t; + + t = x[0] - y; + x[0] = t; + if(t > MAX_DIG) + { + for(i = 1; i < s; i++) + { + x[i]--; + if(x[i] < MAX_DIG) + break; + } + } +} + +/* Computes x *= y. */ +void v_bignum_mul_digit(VBigDig *x, VBigDig y) +{ + unsigned int i, s = *x++, carry, t; + + for(i = carry = 0; i < s; i++) + { + t = x[i] * y + carry; + x[i] = t; + carry = t >> (CHAR_BIT * sizeof *x); + } +} + +/* ----------------------------------------------------------------------------------------- */ + +/* Computes x += y. */ +void v_bignum_add(VBigDig *x, const VBigDig *y) +{ + unsigned int i, xs = *x++, ys = *y++, s, carry, t; + + s = xs < ys ? xs : ys; + for(i = carry = 0; i < s; i++) + { + t = x[i] + y[i] + carry; + x[i] = t; + carry = t > MAX_DIG; + } + for(; carry && i < xs; i++) + { + t = x[i] + carry; + x[i] = t; + carry = t > MAX_DIG; + } +} + +/* Computes x -= y. */ +void v_bignum_sub(VBigDig *x, const VBigDig *y) +{ + unsigned int i, xs = *x++, ys = *y++, s, carry, t; + + if(x == y) + { + v_bignum_set_zero(x - 1); + return; + } + s = xs < ys ? xs : ys; + for(i = carry = 0; i < s; i++) + { + t = x[i] - y[i] - carry; + x[i] = t; + carry = t > MAX_DIG; + } + for(; carry && i < xs; i++) + { + t = x[i] - carry; + x[i] = t; + carry = t > MAX_DIG; + } +} + +/* Compute x *= y, using as many digits as is necessary, then truncating the + * result down. This is Algorithm 14.12 from "Handbook of Applied Cryptography". +*/ +void v_bignum_mul(VBigDig *x, const VBigDig *y) +{ + int n = *x, t = *y, i, j; + VBigDigs uv = 0, c, w[2048]; + + memset(w, 0, (n + t + 1) * sizeof *w); + for(i = 0; i < t; i++) + { + c = 0; + for(j = 0; j < n; j++) + { + uv = w[i + j] + x[1 + j] * y[1 + i] + c; + w[i + j] = uv & ((1 << V_BIGBITS) - 1); + c = uv >> V_BIGBITS; + } + w[i + n + 1] = uv >> V_BIGBITS; + } + /* Write low words of w back into x. */ + for(i = 0; i < *x; i++) + x[1 + i] = w[i]; +} + +/* Computes x /= y and remainder = x % y. */ +void v_bignum_div(VBigDig *x, const VBigDig *y, VBigDig *remainder) +{ + VBigDig *q, *work; + int msbx = v_bignum_bit_msb(x), msby = v_bignum_bit_msb(y), next; + + /* Compare magnitudes of inputs, allows quick exits. */ + if(msby > msbx) + { + if(remainder != NULL) + v_bignum_set_bignum(remainder, x); + v_bignum_set_zero(x); + return; + } + if(msby < 0) + { + v_bignum_set_zero(x); + return; + } + q = bignum_alloc(*x); + v_bignum_set_zero(q); + work = bignum_alloc(*x); + v_bignum_set_bignum_part(work, x, msbx, msby + 1); + + for(next = msbx - (msby + 1); next >= -1; next--) + { + v_bignum_bit_shift_left_1(q); + if(v_bignum_gte(work, y)) + { + q[1] |= 1; + v_bignum_sub(work, y); + } + v_bignum_bit_shift_left_1(work); + if(v_bignum_bit_test(x, next)) + work[1] |= 1; + } + v_bignum_bit_shift_right(work, 1); /* Undo the last shift (when next==-1). */ + + if(remainder != NULL) + { +/* printf("div() got remainder "); + v_bignum_print_hex_lf(work); +*/ + v_bignum_set_bignum(remainder, work); + } + bignum_free(work); + v_bignum_set_bignum(x, q); + bignum_free(q); +} + +/* Computes x %= y. */ +void v_bignum_mod(VBigDig *x, const VBigDig *y) +{ + int digs; + VBigDig *tmp; + +/* printf("computing "); + v_bignum_print_hex(x); + printf("L %% "); + v_bignum_print_hex(y); +*/ + digs = *x > *y ? *x : *y; + tmp = bignum_alloc(digs); + v_bignum_div(x, y, tmp); + v_bignum_set_bignum(x, tmp); + bignum_free(tmp); +/* printf("L = "); + v_bignum_print_hex_lf(x); +*/ +} + +/* Initialize Barrett reduction by computing the "mu" helper value. Defined in + * Handbook of Applied Cryptography algorithm 14.42 as floor(b^2k / m). +*/ +const VBigDig * v_bignum_reduce_begin(const VBigDig *m) +{ + VBigDig *mu; + int k; + + for(k = *m; m[k] == 0; k--) + ; +/* printf("k=%d -> digits are 0..%u\n", k, k - 1); + printf("computing mu=floor(65536^%d/", 2 * k); + v_bignum_print_hex(m); + printf(")\n"); +*/ mu = bignum_alloc(2 * k + 1); + /* b ^ 2k is just 65536 << 2k, i.e. set bit 16 * 2k. */ + v_bignum_set_zero(mu); + v_bignum_bit_set(mu, V_BIGBITS * 2 * k); +/* v_bignum_print_hex_lf(mu);*/ + v_bignum_div(mu, m, NULL); + + return mu; +} + +void v_bignum_reduce_end(const VBigDig *mu) +{ + bignum_free(mu); +} + +/* Compute x % m, using mu as the helper quantity mu, precomputed by the + * routine above. +*/ +void v_bignum_reduce(VBigDig *x, const VBigDig *m, const VBigDig *mu) +{ + VBigDig *q, *r1, *r2, *r; + int i, k; + + for(k = *m; m[k] == 0; k--) + ; + /* Step 1, compute the q helper. */ + q = bignum_alloc(*x + *mu - (k - 1)); /* Tighter bound number length (was 2 * *x). */ + v_bignum_set_bignum(q, x); + v_bignum_bit_shift_right(q, V_BIGBITS * (k - 1)); + v_bignum_mul(q, mu); + v_bignum_bit_shift_right(q, V_BIGBITS * (k + 1)); + + /* Step 2, initialize. */ + r1 = bignum_alloc(*x); + r2 = bignum_alloc(*x); + v_bignum_set_bignum(r1, x); + for(i = k + 1; i < *r1; i++) + r1[i + 1] = 0; + v_bignum_set_bignum(r2, q); + v_bignum_mul(r2, m); + for(i = k + 1; i < *r2; i++) + r2[i + 1] = 0; + r = x; + v_bignum_set_bignum(r, r1); + v_bignum_sub(r, r2); + /* Step 3, make sure r is positive. */ + if(v_bignum_bit_test(r, V_BIGBITS * *r - 1)) + { + VBigDig *term; + + term = bignum_alloc(k + 1 * V_BIGBITS); + v_bignum_set_zero(term); + v_bignum_bit_set(term, V_BIGBITS * (k + 1)); + v_bignum_add(r, term); + bignum_free(term); + } + /* Step 4, loop. */ + while(v_bignum_gte(r, m)) + v_bignum_sub(r, m); + + bignum_free(r2); + bignum_free(r1); + bignum_free(q); +} + +/* Compute x * x using the algorithm 14.16 from "Handbook of Applied Cryptography". + * Note that since 'w' needs to be double-precision (i.e., 32-bit), we cannot allocate + * it using bignum_alloc() cleanly. Thus the static limit, which should be enough here. + * NOTE: This very much assumes V_BIGBITS == 16. +*/ +void v_bignum_square_half(VBigDig *x) +{ + VBigDigs w[256], uv, c, ouv; + int t = *x / 2, i, j, high; + + if(t == 0) + return; + for(; x[t] == 0; t--) + ; + memset(w, 0, 2 * t * sizeof *w); /* Clear digits of w. */ +/* printf("print %lu, ", ++count); + v_bignum_print_hex(x); + printf("*"); + v_bignum_print_hex(x); +*/ for(i = 0; i < t; i++) + { +/* printf("computing w[%d]: %lX + %lX * %lX\n", 2 * i, w[2 * i], x[1 + i], x[1 + i]);*/ + uv = w[2 * i] + x[1 + i] * x[1 + i]; +/* printf("setting w[%d]=%X [before]\n", 2 * i, uv & 0xffff);*/ + w[2 * i] = uv & 0xffff; + c = uv >> V_BIGBITS; +/* printf("uv before=%X, c=%X\n", uv, c);*/ + high = 0; + for(j = i + 1; j < t; j++) + { +/* printf("computing uv=%X+2*%X*%X+%X\n", w[i + j], x[1 + j], x[1 + i], c);*/ + uv = x[1 + j] * x[1 + i]; + high = (uv & 0x80000000) != 0; + uv *= 2; + ouv = uv; /* Addition below might wrap and generate high bit. */ + uv += w[i + j] + c; +/* printf("ouv=0x%lX uv=0x%lX\n", ouv, uv);*/ + high |= uv < ouv; +/* printf("setting w[%d]=%lX [inner] uv=%lX high=%d c=%X\n", i + j, uv & 0xffff, uv, high, c);*/ + w[i + j] = uv & 0xffff; + c = (uv >> V_BIGBITS) | (high << V_BIGBITS); + } +/* printf("setting w[%d] to %X [after]\n", i + t, (uv >> 16) | (high << 16));*/ + w[i + t] = (uv >> V_BIGBITS) | (high << V_BIGBITS); + } +/* printf("w=0x"); + for(i = *x - 1; i >= 0; i--) + printf("%04X.", w[i]); + printf("\n"); +*/ /* Write low words of w back into x, trashing it with the square. */ + for(i = 0; i < 2 * t; i++) + x[1 + i] = w[i]; + for(; i < *x; i++) + x[1 + i] = 0; +/* printf("=="); + v_bignum_print_hex_lf(x); +*/ +} + +/* Computes x = (x^y) % n, where ^ denotes exponentiation. */ +void v_bignum_pow_mod(VBigDig *x, const VBigDig *y, const VBigDig *n) +{ + VBigDig *tmp; + const VBigDig *mu; + int i, k; + +/* printf("computing pow("); + v_bignum_print_hex(x); + printf("L,"); + v_bignum_print_hex(y); + printf("L,"); + v_bignum_print_hex(n); + printf("L)\n"); +*/ + tmp = bignum_alloc(2 * *x); /* Squaring needs twice the bits, or lossage occurs. */ + v_bignum_set_bignum(tmp, x); + k = v_bignum_bit_msb(y); + mu = v_bignum_reduce_begin(n); + for(i = k - 1; i >= 0; i--) + { + v_bignum_square_half(tmp); + v_bignum_reduce(tmp, n, mu); + if(v_bignum_bit_test(y, i)) + { + v_bignum_mul(tmp, x); + v_bignum_reduce(tmp, n, mu); + } + } + v_bignum_set_bignum(x, tmp); + v_bignum_reduce_end(mu); + bignum_free(tmp); +} + +/* ----------------------------------------------------------------------------------------- */ + +#if defined STANDALONE + +int main(void) +{ + VBigDig VBIGNUM(x, 3648), VBIGNUM(y, 128), VBIGNUM(z, 128); + + printf("MAX_DIG=%u\n", MAX_DIG); + + v_bignum_set_string_hex(x, "0x433864FE0F8FAC180FF1BC3A5BFD0C5566F6B11679E27294EDCC43056EB73EE118415E0CD6E6519509476EB21341ED0328BA7B14E0ED80D5E100A4549C5202B57B4CF17A74987631B6BA896C0DBA2095A7EDE5B9C4B4EEFCD1B9EF8474BCB7FBD0F64B549625D444847ED1FCB7F8050EB4F22794F694A0FAC6DFFB781C264B227966840185F9216484F6A7954741CB11FC14DEC2937EAD2CE640FD9A4339706BDB5BC355079C2F2F7994669DFA5B20C50D957A676E67C86835037078323A0BDAD3686B8E638749F327A7AD433C0D18BCD2FC970D125914C7FBEE061290A0F0F3572E207"); + v_bignum_set_bignum(y, x); + v_bignum_set_digit(z, 77); + + printf("x:"); + v_bignum_print_hex_lf(x); + printf("y:"); + v_bignum_print_hex_lf(y); + printf("r:"); + v_bignum_print_hex_lf(z); + v_bignum_pow_mod(x, y, z); + printf(" ="); + v_bignum_print_hex_lf(x); + + return 0; +} + +#endif /* STANDALONE */ diff --git a/extern/verse/dist/v_bignum.h b/extern/verse/dist/v_bignum.h new file mode 100644 index 00000000000..06e58844452 --- /dev/null +++ b/extern/verse/dist/v_bignum.h @@ -0,0 +1,89 @@ +/* + * Verse routines for big integer operations. + * Handy in heavy encryption done during connect. +*/ + +#include + +#include "v_randgen.h" + +/* ----------------------------------------------------------------------------------------- */ + +typedef unsigned short VBigDig; /* Type used to hold one digit of a bignum. */ +typedef unsigned int VBigDigs; /* Should hold precisely two digits. */ + +#define V_BIGBITS (CHAR_BIT * sizeof (VBigDig)) + +/* Use this macro to initialize big number variables, like so: + * VBigDig BIGNUM(foo, 128), BIGNUM(bar, 256); + * Creates automatic variables 'foo' of 128 bits, and 'bar' of 256. + * + * Note that 'bits' must be a multiple of V_BIGBITS, completely + * arbitrary number sizes are not supported by this module. +*/ +#define VBIGNUM(n, bits) n[1 + (bits / V_BIGBITS)] = { bits / V_BIGBITS } + +/* ----------------------------------------------------------------------------------------- */ + +/* Import/export numbers from raw bits. The number x must have been allocated + * with the desired number of bits to read/write. +*/ +extern void v_bignum_raw_import(VBigDig *x, const void *bits); +extern void v_bignum_raw_export(const VBigDig *x, void *bits); + +/* Initializers. */ +extern void v_bignum_set_zero(VBigDig *x); +extern void v_bignum_set_one(VBigDig *x); +extern void v_bignum_set_digit(VBigDig *x, VBigDig y); +extern void v_bignum_set_string(VBigDig *x, const char *string); /* Decimal. */ +extern void v_bignum_set_string_hex(VBigDig *x, const char *string); +extern void v_bignum_set_bignum(VBigDig *x, const VBigDig *y); +/* x = most significant bits of , starting at . Right- + * adjusted in x, so that e.g. y=0xcafebabec001 msb=47 bits=16 gives x=0xcafe. +*/ +extern void v_bignum_set_bignum_part(VBigDig *x, const VBigDig *y, + unsigned int msb, unsigned int bits); +extern void v_bignum_set_random(VBigDig *x, VRandGen *gen); + +/* Handy during debugging. */ +extern void v_bignum_print_hex(const VBigDig *x); +extern void v_bignum_print_hex_lf(const VBigDig *x); + +/* Bit operators. */ +extern void v_bignum_not(VBigDig *x); +extern int v_bignum_bit_test(const VBigDig *x, unsigned int bit); +extern void v_bignum_bit_set(VBigDig *x, unsigned int bit); +extern int v_bignum_bit_msb(const VBigDig *x); +extern int v_bignum_bit_size(const VBigDig *x); +extern void v_bignum_bit_shift_left(VBigDig *x, unsigned int count); +extern void v_bignum_bit_shift_left_1(VBigDig *x); +extern void v_bignum_bit_shift_right(VBigDig *x, unsigned int count); + +/* Comparators. */ +extern int v_bignum_eq_zero(const VBigDig *x); /* x == 0. */ +extern int v_bignum_eq_one(const VBigDig *x); /* x == 1. */ +extern int v_bignum_eq(const VBigDig *x, const VBigDig *y); /* x == y. */ +extern int v_bignum_gte(const VBigDig *x, const VBigDig *y); /* x >= y. */ + +/* Number vs single-digit arithmetic. */ +extern void v_bignum_add_digit(VBigDig *x, VBigDig y); /* x += y. */ +extern void v_bignum_sub_digit(VBigDig *x, VBigDig y); /* x -= y. */ +extern void v_bignum_mul_digit(VBigDig *x, VBigDig y); /* x *= y. */ + +/* Arithmetic. */ +extern void v_bignum_add(VBigDig *x, const VBigDig *y); /* x += y. */ +extern void v_bignum_sub(VBigDig *x, const VBigDig *y); /* x -= y. */ +extern void v_bignum_mul(VBigDig *x, const VBigDig *y); /* x *= y. */ +extern void v_bignum_div(VBigDig *x, const VBigDig *y, VBigDig *remainder); +extern void v_bignum_mod(VBigDig *x, const VBigDig *y); /* x %= y. */ + +/* Barrett reducer for fast x % m computation. Requires precalcing step. */ +extern const VBigDig * v_bignum_reduce_begin(const VBigDig *m); +extern void v_bignum_reduce(VBigDig *x, const VBigDig *m, const VBigDig *mu); +extern void v_bignum_reduce_end(const VBigDig *mu); + +/* Compute x *= x, assuming x only uses half of its actual size. */ +extern void v_bignum_square_half(VBigDig *x); + +/* Compute pow(x, y, n) == (x raised to the y:th power) modulo n. */ +extern void v_bignum_pow_mod(VBigDig *x, const VBigDig *y, const VBigDig *n); diff --git a/extern/verse/dist/v_cmd_buf.c b/extern/verse/dist/v_cmd_buf.c new file mode 100644 index 00000000000..b7faf227352 --- /dev/null +++ b/extern/verse/dist/v_cmd_buf.c @@ -0,0 +1,119 @@ +/* +** +*/ + +#include +#include +#include + +#include "verse_header.h" +#include "v_pack.h" +#include "v_cmd_buf.h" + +static const size_t vcmdbuf_chunk_size[] = { 10000, 10000, 10000, 10000, 8000, 5000, 500 }; /* If you think memory is cheap, set this to a high value. */ + +/* Sizes of individual command buffers, indexable by VCMDBufSize values. Switch-killer. */ +static const size_t vcmdbuf_size[] = { + sizeof (VCMDBuffer10), sizeof (VCMDBuffer20), sizeof (VCMDBuffer30), sizeof (VCMDBuffer80), + sizeof (VCMDBuffer160), sizeof (VCMDBuffer320), sizeof (VCMDBuffer1500) +}; + +#define VCMDBUF_INIT_CHUNK_FACTOR 0.5 + +static struct { + VCMDBufHead *buffers[VCMDBS_COUNT]; + unsigned int available[VCMDBS_COUNT]; +} VCMDBufData; + +static boolean v_cmd_buf_initialized = FALSE; + +void cmd_buf_init(void) +{ + unsigned int i, j; + VCMDBufHead *buf, *b; + + for(i = 0; i < VCMDBS_COUNT; i++) + { + VCMDBufData.buffers[i] = NULL; + VCMDBufData.available[i] = (unsigned int) (vcmdbuf_chunk_size[i] * VCMDBUF_INIT_CHUNK_FACTOR); + for(j = 0, buf = NULL; j < VCMDBufData.available[i]; j++, buf = b) + { + b = v_cmd_buf_allocate(i); + b->next = buf; + } + VCMDBufData.buffers[i] = buf; + } + v_cmd_buf_initialized = TRUE; +} + +VCMDBufHead * v_cmd_buf_allocate(VCMDBufSize buf_size) +{ + VCMDBufHead *output = NULL; + + if(VCMDBufData.buffers[buf_size] != NULL) + { + output = VCMDBufData.buffers[buf_size]; + VCMDBufData.buffers[buf_size] = output->next; + VCMDBufData.available[buf_size]--; + } + else + { + if(buf_size < sizeof vcmdbuf_size / sizeof *vcmdbuf_size) + output = malloc(vcmdbuf_size[buf_size]); + else + { + fprintf(stderr, "v_cmd_buf.c: Can't handle buffer size %d\n", buf_size); + return NULL; + } + output->buf_size = buf_size; + } + output->next = NULL; + output->packet = 0; + output->size = 0; + output->address_size = -1; + return output; +} + +void v_cmd_buf_free(VCMDBufHead *head) +{ + if(VCMDBufData.available[head->buf_size] < vcmdbuf_chunk_size[head->buf_size]) + { + head->next = VCMDBufData.buffers[head->buf_size]; + VCMDBufData.buffers[head->buf_size] = head; + VCMDBufData.available[head->buf_size]++; + } + else + free(head); +} + +void v_cmd_buf_set_size(VCMDBufHead *head, unsigned int size) +{ + head->size = size; +} + +void v_cmd_buf_set_address_size(VCMDBufHead *head, unsigned int size) +{ + unsigned int i; + + head->address_size = size; + head->address_sum = 0; + for(i = 1; i < size + 1; i++) + head->address_sum += i * i * (uint32)(((VCMDBuffer1500 *)head)->buf[i - 1]); +} + +void v_cmd_buf_set_unique_address_size(VCMDBufHead *head, unsigned int size) +{ + static unsigned int i = 0; + + head->address_size = size; + head->address_sum = i++; +} + +boolean v_cmd_buf_compare(VCMDBufHead *a, VCMDBufHead *b) +{ + if(a->address_sum != b->address_sum) + return FALSE; + if(a->address_size != b->address_size) + return FALSE; + return memcmp(((VCMDBuffer1500 *)a)->buf, ((VCMDBuffer1500 *)b)->buf, a->address_size) == 0; +} diff --git a/extern/verse/dist/v_cmd_buf.h b/extern/verse/dist/v_cmd_buf.h new file mode 100644 index 00000000000..6eda7640bb1 --- /dev/null +++ b/extern/verse/dist/v_cmd_buf.h @@ -0,0 +1,74 @@ +/* +** +*/ + +#include + +#include "verse_header.h" +#include "v_pack.h" + +#define V_NOQ_MAX_PACKET_SIZE 1500 + +typedef enum { + VCMDBS_10 = 0, + VCMDBS_20 = 1, + VCMDBS_30 = 2, + VCMDBS_80 = 3, + VCMDBS_160 = 4, + VCMDBS_320 = 5, + VCMDBS_1500 = 6, + VCMDBS_COUNT = 7 +} VCMDBufSize; + +typedef struct { + void *next; + uint32 packet; + unsigned int address_size; + unsigned int address_sum; + VCMDBufSize buf_size; + unsigned int size; +} VCMDBufHead; + +typedef struct { + VCMDBufHead head; + uint8 buf[10]; +} VCMDBuffer10; + +typedef struct { + VCMDBufHead head; + uint8 buf[20]; +} VCMDBuffer20; + +typedef struct { + VCMDBufHead head; + uint8 buf[30]; +} VCMDBuffer30; + +typedef struct { + VCMDBufHead head; + uint8 buf[80]; +} VCMDBuffer80; + +typedef struct { + VCMDBufHead head; + uint8 buf[160]; +} VCMDBuffer160; + +typedef struct { + VCMDBufHead head; + uint8 buf[320]; +} VCMDBuffer320; + + +typedef struct { + VCMDBufHead head; + uint8 buf[1500]; +} VCMDBuffer1500; + +extern VCMDBufHead *v_cmd_buf_allocate(VCMDBufSize buf_size); +extern void v_cmd_buf_free(VCMDBufHead *head); + +extern void v_cmd_buf_set_size(VCMDBufHead *head, unsigned int size); +extern void v_cmd_buf_set_address_size(VCMDBufHead *head, unsigned int size); +extern void v_cmd_buf_set_unique_address_size(VCMDBufHead *head, unsigned int size); +extern boolean v_cmd_buf_compare(VCMDBufHead *a, VCMDBufHead *b); diff --git a/extern/verse/dist/v_cmd_def_a.c b/extern/verse/dist/v_cmd_def_a.c new file mode 100644 index 00000000000..8557601428b --- /dev/null +++ b/extern/verse/dist/v_cmd_def_a.c @@ -0,0 +1,94 @@ +/* + * Command definitions for audio node commands. +*/ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_audio_cmd_def(void) +{ + v_cg_new_cmd(V_NT_AUDIO, "a_buffer_create", 160, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_BUFFER_ID, "buffer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_ENUM_NAME, "VNABlockType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_REAL64, "frequency"); + v_cg_alias(FALSE, "a_buffer_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_AUDIO, "a_buffer_subscribe", 161, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_BUFFER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "a_buffer_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_AUDIO, "a_block_set", 162, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "buffer_id"); + v_cg_add_param(VCGP_UINT32, "block_index"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNABlockType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNABlock"); + v_cg_add_param(VCGP_POINTER, "samples"); + + v_cg_add_param(VCGP_PACK_INLINE, "\tbuffer_pos += vnp_pack_audio_block(&buf[buffer_pos], type, samples);\n"); + + v_cg_add_param(VCGP_UNPACK_INLINE, "\tif(type <= VN_A_BLOCK_REAL64)\n\t{\n" + "\t\tVNABlock\tblock;\n" + "\t\tbuffer_pos += vnp_unpack_audio_block(&buf[buffer_pos], type, &block);\n" + "\t\tif(func_a_block_set != NULL)\n" + "\t\t\tfunc_a_block_set(v_fs_get_user_data(162), node_id, buffer_id, block_index, (VNABlockType) type, &block);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_alias(FALSE, "a_block_clear", "if(type > VN_A_BLOCK_REAL64)", 3, NULL); + v_cg_end_cmd(); + + + v_cg_new_cmd(V_NT_AUDIO, "a_stream_create", 163, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "stream_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_alias(FALSE, "a_stream_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_AUDIO, "a_stream_subscribe", 164, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "stream_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "a_stream_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_AUDIO, "a_stream", 165, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "stream_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_ENUM_NAME, "VNABlockType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_REAL64, "frequency"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNABlock"); + v_cg_add_param(VCGP_POINTER, "samples"); + + v_cg_add_param(VCGP_PACK_INLINE, "\tbuffer_pos += vnp_pack_audio_block(&buf[buffer_pos], type, samples);\n"); + + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n\t\tVNABlock\tblock;\n\tbuffer_pos += vnp_unpack_audio_block(&buf[buffer_pos], type, &block);\n" + "\t\tif(func_a_stream != NULL)\n" + "\t\t\tfunc_a_stream(v_fs_get_user_data(165), node_id, stream_id, time_s, time_f, (VNABlockType) type, frequency, &block);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_b.c b/extern/verse/dist/v_cmd_def_b.c new file mode 100644 index 00000000000..b266b03648c --- /dev/null +++ b/extern/verse/dist/v_cmd_def_b.c @@ -0,0 +1,44 @@ + +#include +#include + +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_bitmap_cmd_def(void) +{ + v_cg_new_cmd(V_NT_BITMAP, "b_dimensions_set", 80, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT16, "width"); + v_cg_add_param(VCGP_UINT16, "height"); + v_cg_add_param(VCGP_UINT16, "depth"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_BITMAP, "b_layer_create", 81, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_ENUM_NAME, "VNBLayerType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_alias(FALSE, "b_layer_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_BITMAP, "b_layer_subscribe", 82, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT8, "level"); + v_cg_alias(FALSE, "b_layer_unsubscribe", "if(level == 255)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_manual_cmd(83, "b_tile_set", "void verse_send_b_tile_set(VNodeID node_id, VLayerID layer_id, " + "uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile)", + NULL, NULL); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_c.c b/extern/verse/dist/v_cmd_def_c.c new file mode 100644 index 00000000000..317b45e1a27 --- /dev/null +++ b/extern/verse/dist/v_cmd_def_c.c @@ -0,0 +1,35 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_curve_cmd_def(void) +{ + v_cg_new_cmd(V_NT_CURVE, "c_curve_create", 128, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "curve_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_UINT8, "dimensions"); + v_cg_alias(FALSE, "c_curve_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_CURVE, "c_curve_subscribe", 129, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "curve_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "c_curve_unsubscribe", "if(!alias_bool)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_manual_cmd(130, "c_key_set", "void verse_send_c_key_set(VNodeID node_id, VLayerID curve_id, " + "uint32 key_id, uint8 dimensions, const real64 *pre_value, const uint32 *pre_pos, " + "const real64 *value, real64 pos, const real64 *post_value, const uint32 *post_pos)", + "c_key_destroy", "void verse_send_c_key_destroy(VNodeID node_id, VLayerID curve_id, " + "uint32 key_id)"); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_g.c b/extern/verse/dist/v_cmd_def_g.c new file mode 100644 index 00000000000..5a4ea7202b4 --- /dev/null +++ b/extern/verse/dist/v_cmd_def_g.c @@ -0,0 +1,183 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_geometry_cmd_def(void) +{ + unsigned int order[] = { 0, 2 }; + + v_cg_new_cmd(V_NT_GEOMETRY, "g_layer_create", 48, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_ENUM_NAME, "VNGLayerType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_UINT32, "def_uint"); + v_cg_add_param(VCGP_REAL64, "def_real"); + v_cg_alias(FALSE, "g_layer_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_layer_subscribe", 49, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNRealFormat"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_alias(FALSE, "g_layer_unsubscribe", "if(type > VN_FORMAT_REAL64)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_xyz_real32", 50, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "x"); + v_cg_add_param(VCGP_REAL32, "y"); + v_cg_add_param(VCGP_REAL32, "z"); + v_cg_alias(FALSE, "g_vertex_delete_real32", "if(x == V_REAL32_MAX || y == V_REAL32_MAX || z == V_REAL32_MAX)", 2, order); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_xyz_real64", 51, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "x"); + v_cg_add_param(VCGP_REAL64, "y"); + v_cg_add_param(VCGP_REAL64, "z"); + v_cg_alias(FALSE, "g_vertex_delete_real64", "if(x == V_REAL64_MAX || y == V_REAL64_MAX || z == V_REAL64_MAX)", 2, order); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_uint32", 52, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_real64", 53, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_set_real32", 54, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "value"); + v_cg_end_cmd(); +/* + v_cg_new_cmd(V_NT_GEOMETRY, "g_vertex_delete", VCGCT_NORMAL); + v_cg_add_param(VCGP_UINT32, "vertex_id"); + v_cg_end_cmd(); +*/ + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_corner_uint32", 55, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "v0"); + v_cg_add_param(VCGP_UINT32, "v1"); + v_cg_add_param(VCGP_UINT32, "v2"); + v_cg_add_param(VCGP_UINT32, "v3"); + v_cg_alias(FALSE, "g_polygon_delete", "if(layer_id == 1 && v0 == ~0u)", 2, order); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_corner_real64", 56, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "v0"); + v_cg_add_param(VCGP_REAL64, "v1"); + v_cg_add_param(VCGP_REAL64, "v2"); + v_cg_add_param(VCGP_REAL64, "v3"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_corner_real32", 57, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "v0"); + v_cg_add_param(VCGP_REAL32, "v1"); + v_cg_add_param(VCGP_REAL32, "v2"); + v_cg_add_param(VCGP_REAL32, "v3"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_face_uint8", 58, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT8, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_face_uint32", 59, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_face_real64", 60, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_polygon_set_face_real32", 61, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_LAYER_ID, "layer_id"); + v_cg_add_param(VCGP_UINT32, "polygon_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "value"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_crease_set_vertex", 62, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "layer"); + v_cg_add_param(VCGP_UINT32, "def_crease"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_crease_set_edge", 63, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "layer"); + v_cg_add_param(VCGP_UINT32, "def_crease"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_GEOMETRY, "g_bone_create", 64, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "bone_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "weight"); + v_cg_add_param(VCGP_NAME, "reference"); + v_cg_add_param(VCGP_UINT16, "parent"); + v_cg_add_param(VCGP_REAL64, "pos_x"); + v_cg_add_param(VCGP_REAL64, "pos_y"); + v_cg_add_param(VCGP_REAL64, "pos_z"); + v_cg_add_param(VCGP_NAME, "position_label"); + v_cg_add_param(VCGP_NAME, "rotation_label"); + v_cg_add_param(VCGP_NAME, "scale_label"); + v_cg_alias(FALSE, "g_bone_destroy", "if(weight[0] == 0)", 2, NULL); + + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_m.c b/extern/verse/dist/v_cmd_def_m.c new file mode 100644 index 00000000000..3f4b9aa7178 --- /dev/null +++ b/extern/verse/dist/v_cmd_def_m.c @@ -0,0 +1,273 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_material_cmd_def(void) +{ + v_cg_new_cmd(V_NT_MATERIAL, "m_fragment_create", 68, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_FRAGMENT_ID, "frag_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNMFragmentType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_POINTER_TYPE, "VMatFrag"); + v_cg_add_param(VCGP_POINTER, "fragment"); + + v_cg_add_param(VCGP_PACK_INLINE, "\tswitch(type)\n" + "\t{\n" + "\tcase VN_M_FT_COLOR :\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.red);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.green);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.blue);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_LIGHT :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->light.type);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->light.normal_falloff);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], fragment->light.brdf);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_r, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_g, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_b, 16);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_REFLECTION :\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->reflection.normal_falloff);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_TRANSPARENCY :\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->transparency.normal_falloff);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->transparency.refraction_index);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_GEOMETRY :\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_r, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_g, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_b, 16);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_VOLUME :\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.diffusion);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_r);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_g);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_b);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_VIEW :\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_TEXTURE :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], fragment->texture.bitmap);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_r, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_g, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_b, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->texture.filtered);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->texture.mapping);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_NOISE :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->noise.type);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->noise.mapping);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_BLENDER :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->blender.type);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.data_a);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.data_b);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.control);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_CLAMP :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->clamp.min);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.red);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.green);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.blue);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->clamp.data);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_MATRIX :\n" + "\t\t{\n" + "\t\t\tunsigned int i;\n" + "\t\t\tfor(i = 0; i < 16; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->matrix.matrix[i]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->matrix.data);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_RAMP :\n" + "\t\tif(fragment->ramp.point_count == 0)\n" + "\t\t\treturn;\n" + "\t\t{\n" + "\t\t\tunsigned int i, pos;\n" + "\t\t\tdouble last;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->ramp.type);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->ramp.channel);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->ramp.mapping);\n" + "\t\t\tpos = buffer_pos;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], fragment->ramp.point_count);\n" + "\t\t\tlast = fragment->ramp.ramp[0].pos - 1;\n" + "\t\t\tfor(i = 0; i < fragment->ramp.point_count && fragment->ramp.ramp[i].pos > last && i < 48; i++)\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].pos);\n" + "\t\t\t\tlast = fragment->ramp.ramp[i].pos;\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].red);\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].green);\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].blue);\n" + "\t\t\t}\n\t\t\tif(i != fragment->ramp.point_count)\n" + "\t\t\t\tvnp_raw_pack_uint8(&buf[pos], i);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_ANIMATION :\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->animation.label, 16);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_ALTERNATIVE :\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->alternative.alt_a);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->alternative.alt_b);\n" + "\t\tbreak;\n" + "\tcase VN_M_FT_OUTPUT :\n" + "\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->output.label, 16);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->output.front);\n" + "\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->output.back);\n" + "\t\tbreak;\n" + "\t}\n"); + + v_cg_add_param(VCGP_UNPACK_INLINE, "\tif(type <= VN_M_FT_OUTPUT)\n" + "\t{\n" + "\t\tVMatFrag frag;\n" + "\t\tuint8 temp;\n" + "\t\tswitch(type)\n" + "\t\t{\n" + "\t\tcase VN_M_FT_COLOR :\n" + "\t\t\tif(buffer_pos + 3 * 8 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.red);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.green);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.blue);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_LIGHT :\n" + "\t\t\tif(buffer_pos + 13 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.light.type = (VNMLightType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.light.normal_falloff);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &frag.light.brdf);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_r, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_g, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_b, 16, buffer_length - buffer_pos);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_REFLECTION :\n" + "\t\t\tif(buffer_pos + 8 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.reflection.normal_falloff);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_TRANSPARENCY :\n" + "\t\t\tif(buffer_pos + 16 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.transparency.normal_falloff);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.transparency.refraction_index);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_VOLUME :\n" + "\t\t\tif(buffer_pos + 32 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.diffusion);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_r);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_g);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_b);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_VIEW :\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_GEOMETRY :\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_r, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_g, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_b, 16, buffer_length - buffer_pos);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_TEXTURE :\n" + "\t\t\tif(buffer_pos + 10 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &frag.texture.bitmap);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_r, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_g, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_b, 16, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.texture.filtered = (VNMNoiseType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.texture.mapping);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_NOISE :\n" + "\t\t\tif(buffer_pos + 3 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.noise.type = (VNMNoiseType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.noise.mapping);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_BLENDER :\n" + "\t\t\tif(buffer_pos + 7 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.blender.type = (VNMBlendType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.data_a);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.data_b);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.control);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_CLAMP :\n" + "\t\t\tif(buffer_pos + 27 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\tfrag.clamp.min = (VNMBlendType)temp;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.red);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.green);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.blue);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.clamp.data);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_MATRIX :\n" + "\t\t\tif(buffer_pos + 8 * 16 + 2 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\telse\n" + "\t\t\t{\n" + "\t\t\t\tunsigned int i;\n" + "\t\t\t\tfor(i = 0; i < 16; i++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.matrix.matrix[i]);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.matrix.data);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_RAMP :\n" + "\t\t\tif(buffer_pos + 5 + 4 * 8 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\telse\n" + "\t\t\t{\n" + "\t\t\t\tunsigned int i, pos;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\t\tfrag.ramp.type = (VNMRampType)temp;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp);\n" + "\t\t\t\tfrag.ramp.channel = (VNMRampChannel)temp;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.ramp.mapping);\n" + "\t\t\t\tpos = buffer_pos;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &frag.ramp.point_count);\n" + "\t\t\t\tfor(i = 0; i < frag.ramp.point_count && buffer_pos + 8 * 4 <= buffer_length && i < 48; i++)\n" + "\t\t\t\t{\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].pos);\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].red);\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].green);\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].blue);\n" + "\t\t\t\t}if(i != frag.ramp.point_count)\n" + "\t\t\t\t\tfrag.ramp.point_count = i;\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_ANIMATION :\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.animation.label, 16, buffer_length - buffer_pos);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_ALTERNATIVE :\n" + "\t\t\tif(buffer_pos + 4 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.alternative.alt_a);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.alternative.alt_b);\n" + "\t\t\tbreak;\n" + "\t\tcase VN_M_FT_OUTPUT :\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.output.label, 16, buffer_length - buffer_pos);\n" + "\t\t\tif(buffer_pos + 4 > buffer_length)\n" + "\t\t\t\treturn -1;\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.output.front);\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.output.back);\n" + "\t\t\tbreak;\n" + "\t\t}\n" + "\t\tif(func_m_fragment_create != NULL)\n" + "\t\t\tfunc_m_fragment_create(v_fs_get_user_data(68), node_id, frag_id, type, &frag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_alias(FALSE, "m_fragment_destroy", "if(type > VN_M_FT_OUTPUT)", 2, NULL); + + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_o.c b/extern/verse/dist/v_cmd_def_o.c new file mode 100644 index 00000000000..a0135f2a4a7 --- /dev/null +++ b/extern/verse/dist/v_cmd_def_o.c @@ -0,0 +1,517 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_object_cmd_def(void) +{ + v_cg_new_cmd(V_NT_OBJECT, "o_transform_pos_real32", 32, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_POINTER_TYPE,"real32"); + v_cg_add_param(VCGP_POINTER, "pos"); + v_cg_add_param(VCGP_POINTER_TYPE,"real32"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE,"real32"); + v_cg_add_param(VCGP_POINTER, "accelerate"); + v_cg_add_param(VCGP_POINTER_TYPE,"real32"); + v_cg_add_param(VCGP_POINTER, "drag_normal"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned char mask = 0;\n" + "\t\tunsigned int cmd;\n" + "\t\tcmd = buffer_pos++;\n" + "\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[0]);\n" + "\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[1]);\n" + "\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[2]);\n" + "\t\tif(speed != NULL && (speed[0] > 0.0000001 || speed[0] < -0.0000001 || speed[1] > 0.0000001 || speed[1] < -0.0000001 || speed[2] > 0.0000001 || speed[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[2]);\n" + "\t\t}\n" + "\t\tif(accelerate != NULL && (accelerate[0] > 0.0000001 || accelerate[0] < -0.0000001 || accelerate[1] > 0.0000001 || accelerate[1] < -0.0000001 || accelerate[2] > 0.0000001 || accelerate[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[2]);\n" + "\t\t}\n" + "\t\tif(drag_normal != NULL && (drag > 0.0000001 || drag < -0.0000001) && (drag_normal[0] > 0.0000001 || drag_normal[0] < -0.0000001 || drag_normal[1] > 0.0000001 || drag_normal[1] < -0.0000001 || drag_normal[2] > 0.0000001 || drag_normal[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[2]);\n" + "\t\t}\n" + "\t\tif(drag > 0.0000001 || drag < -0.0000001)\n" + "\t\t{\n" + "\t\t\tmask |= 8;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[cmd], mask);\n" + "\t}if(FALSE)\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tfloat output[4][3];\n" + "\t\tunsigned int i, j;\n" + "\t\tchar mask, pow = 1;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &output[0][j]);\n" + "\t\tfor(i = 1; i < 4; i++)\n" + "\t\t{\n" + "\t\t\tif((mask & pow) != 0)\n" + "\t\t\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &output[i][j]);\n" + "\t\t\telse\n" + "\t\t\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\t\t\toutput[i][j] = 0;\n" + "\t\t\tpow *= 2;\n" + "\t\t}\n" + "\t\tif((mask & pow) != 0)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &drag);\n" + "\t\telse\n" + "\t\t\tdrag = 0.0f;\n" + "\t\tif(func_o_transform_pos_real32 != NULL)\n" + "\t\t\tfunc_o_transform_pos_real32(v_fs_get_user_data(32), node_id, time_s, time_f, &output[0][0], &output[1][0], &output[2][0], &output[3][0], drag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_add_param(VCGP_REAL32, "drag"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_rot_real32", 33, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNQuat32"); + v_cg_add_param(VCGP_POINTER, "rot"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNQuat32"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNQuat32"); + v_cg_add_param(VCGP_POINTER, "accelerate"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNQuat32"); + v_cg_add_param(VCGP_POINTER, "drag_normal"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tuint8 mask = 0;\n" + "\t\tunsigned int maskpos;\n" + "\t\tmaskpos = buffer_pos++;\t\t/* Remember location, and reserve a byte for the mask. */\n" + "\t\tbuffer_pos += vnp_pack_quat32(&buf[buffer_pos], rot);\n" + "\t\tif(v_quat32_valid(speed))\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tbuffer_pos += vnp_pack_quat32(&buf[buffer_pos], speed);\n" + "\t\t}\n" + "\t\tif(v_quat32_valid(accelerate))\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tbuffer_pos += vnp_pack_quat32(&buf[buffer_pos], accelerate);\n" + "\t\t}\n" + "\t\tif(v_quat32_valid(drag_normal))\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tbuffer_pos += vnp_pack_quat32(&buf[buffer_pos], drag_normal);\n" + "\t\t}\n" + "\t\tif(drag > 0.0000001 || drag < -0.0000001)\n" + "\t\t{\n" + "\t\t\tmask |= 8;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[maskpos], mask);\t/* Write the mask into start of command. */\n" + "\t}\n" + "\tif(FALSE)\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tVNQuat32 trot, temp[3], *q[3];\n" + "\t\tunsigned int i;\n" + "\t\tuint8 mask, test;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tbuffer_pos += vnp_unpack_quat32(&buf[buffer_pos], &trot);\n" + "\t\tfor(i = 0, test = 1; i < sizeof temp / sizeof *temp; i++, test <<= 1)\n" + "\t\t{\n" + "\t\t\tif(mask & test)\t\t/* Field present? */\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_unpack_quat32(&buf[buffer_pos], &temp[i]);\n" + "\t\t\t\tq[i] = &temp[i];\n" + "\t\t\t}\n" + "\t\t\telse\n" + "\t\t\t\tq[i] = NULL;\n" + "\t\t}\n" + "\t\tif(mask & test)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &drag);\n" + "\t\telse\n" + "\t\t\tdrag = 0.0;\n" + "\t\tif(func_o_transform_rot_real32 != NULL)\n" + "\t\t\tfunc_o_transform_rot_real32(v_fs_get_user_data(33), node_id, time_s, time_f, &trot, q[0], q[1], q[2], drag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_add_param(VCGP_REAL32, "drag"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_scale_real32", 34, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL32, "scale_x"); + v_cg_add_param(VCGP_REAL32, "scale_y"); + v_cg_add_param(VCGP_REAL32, "scale_z"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_pos_real64", 35, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_POINTER_TYPE,"real64"); + v_cg_add_param(VCGP_POINTER, "pos"); + v_cg_add_param(VCGP_POINTER_TYPE,"real64"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE,"real64"); + v_cg_add_param(VCGP_POINTER, "accelerate"); + v_cg_add_param(VCGP_POINTER_TYPE,"real64"); + v_cg_add_param(VCGP_POINTER, "drag_normal"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned char mask = 0;\n" + "\t\tunsigned int cmd;\n" + "\t\tcmd = buffer_pos++;\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[0]);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[1]);\n" + "\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[2]);\n" + "\t\tif(speed != NULL && (speed[0] > 0.0000001 || speed[0] < -0.0000001 || speed[1] > 0.0000001 || speed[1] < -0.0000001 || speed[2] > 0.0000001 || speed[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[2]);\n" + "\t\t}\n" + "\t\tif(accelerate != NULL && (accelerate[0] > 0.0000001 || accelerate[0] < -0.0000001 || accelerate[1] > 0.0000001 || accelerate[1] < -0.0000001 || accelerate[2] > 0.0000001 || accelerate[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[2]);\n" + "\t\t}\n" + "\t\tif(drag_normal != NULL && (drag > 0.0000001 || drag < -0.0000001) && (drag_normal[0] > 0.0000001 || drag_normal[0] < -0.0000001 || drag_normal[1] > 0.0000001 || drag_normal[1] < -0.0000001 || drag_normal[2] > 0.0000001 || drag_normal[2] < -0.0000001))\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[2]);\n" + "\t\t}\n" + "\t\tif(drag > 0.0000001 || drag < -0.0000001)\n" + "\t\t{\n" + "\t\t\tmask |= 8;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[cmd], mask);\n" + "\t}if(FALSE)\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tdouble output[4][3];\n" + "\t\tunsigned int i, j;\n" + "\t\tchar mask, pow = 1;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[0][j]);\n" + "\t\tfor(i = 1; i < 4; i++)\n" + "\t\t{\n" + "\t\t\tif((mask & pow) != 0)\n" + "\t\t\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[i][j]);\n" + "\t\t\telse\n" + "\t\t\t\tfor(j = 0; j < 3; j++)\n" + "\t\t\t\t\toutput[i][j] = 0;\n" + "\t\t\tpow *= 2;\n" + "\t\t}\n" + "\t\tif((mask & pow) != 0)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &drag);\n" + "\t\telse\n" + "\t\t\tdrag = 0.0;\n" + "\t\tif(func_o_transform_pos_real64 != NULL)\n" + "\t\t\tfunc_o_transform_pos_real64(v_fs_get_user_data(35), node_id, time_s, time_f, &output[0][0], &output[1][0], &output[2][0], &output[3][0], drag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_add_param(VCGP_REAL64, "drag"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_rot_real64", 36, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNQuat64"); + v_cg_add_param(VCGP_POINTER, "rot"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNQuat64"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNQuat64"); + v_cg_add_param(VCGP_POINTER, "accelerate"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNQuat64"); + v_cg_add_param(VCGP_POINTER, "drag_normal"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tuint8 mask = 0;\n" + "\t\tunsigned int maskpos;\n" + "\t\tmaskpos = buffer_pos++;\t\t/* Remember location, and reserve a byte for the mask. */\n" + "\t\tbuffer_pos += vnp_pack_quat64(&buf[buffer_pos], rot);\n" + "\t\tif(v_quat64_valid(speed))\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tbuffer_pos += vnp_pack_quat64(&buf[buffer_pos], speed);\n" + "\t\t}\n" + "\t\tif(v_quat64_valid(accelerate))\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tbuffer_pos += vnp_pack_quat64(&buf[buffer_pos], accelerate);\n" + "\t\t}\n" + "\t\tif(v_quat64_valid(drag_normal))\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tbuffer_pos += vnp_pack_quat64(&buf[buffer_pos], drag_normal);\n" + "\t\t}\n" + "\t\tif(drag > 0.0000001 || drag < -0.0000001)\n" + "\t\t{\n" + "\t\t\tmask |= 8;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[maskpos], mask);\t/* Write the mask into start of command. */\n" + "\t}\n" + "\tif(FALSE)\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tVNQuat64 trot, temp[3], *q[3];\n" + "\t\tunsigned int i;\n" + "\t\tuint8 mask, test;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tbuffer_pos += vnp_unpack_quat64(&buf[buffer_pos], &trot);\n" + "\t\tfor(i = 0, test = 1; i < sizeof temp / sizeof *temp; i++, test <<= 1)\n" + "\t\t{\n" + "\t\t\tif(mask & test)\t\t/* Field present? */\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_unpack_quat64(&buf[buffer_pos], &temp[i]);\n" + "\t\t\t\tq[i] = &temp[i];\n" + "\t\t\t}\n" + "\t\t\telse\n" + "\t\t\t\tq[i] = NULL;\n" + "\t\t}\n" + "\t\tif(mask & test)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &drag);\n" + "\t\telse\n" + "\t\t\tdrag = 0.0;\n" + "\t\tif(func_o_transform_rot_real64 != NULL)\n" + "\t\t\tfunc_o_transform_rot_real64(v_fs_get_user_data(36), node_id, time_s, time_f, &trot, q[0], q[1], q[2], drag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_add_param(VCGP_REAL64, "drag"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_scale_real64", 37, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "scale_x"); + v_cg_add_param(VCGP_REAL64, "scale_y"); + v_cg_add_param(VCGP_REAL64, "scale_z"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_transform_subscribe", 38, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNRealFormat"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_alias(TRUE, "o_transform_unsubscribe", NULL, 4, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_light_set", 39, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_REAL64, "light_r"); + v_cg_add_param(VCGP_REAL64, "light_g"); + v_cg_add_param(VCGP_REAL64, "light_b"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_link_set", 40, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "link_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NODE_ID, "link"); + v_cg_add_param(VCGP_NAME, "label"); + v_cg_add_param(VCGP_UINT32, "target_id"); + v_cg_alias(TRUE, "o_link_destroy", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_method_group_create", 41, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_alias(FALSE, "o_method_group_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_method_group_subscribe", 42, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "o_method_group_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_method_create", 43, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_UINT16, "method_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_LONG_NAME, "name"); + v_cg_add_param(VCGP_UINT8, "param_count"); + v_cg_add_param(VCGP_POINTER_TYPE,"VNOParamType"); + v_cg_add_param(VCGP_POINTER, "param_types"); + v_cg_add_param(VCGP_POINTER_TYPE,"char *"); + v_cg_add_param(VCGP_POINTER, "param_names"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned int i, j, sum = 1;\n" + "\t\tfor(i = 0; i < param_count; i++)\n" + "\t\t{\n" + "\t\t\tsum += 3;\n" + "\t\t\tfor(j = 0; param_names[i][j] != 0; j++);\n" + "\t\t}\n" + "\t\tif(sum + buffer_pos > 1500)\n" + "\t\t\treturn;\n" + "\t\tfor(i = 0; i < param_count; i++)\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], param_types[i]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], param_names[i], 1500 - buffer_pos);\n" + "\t\t}\n" + "\t}\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\tif(param_count != 255)\n" + "\t{\n" + "\t\tunsigned int i, size, text = 0;\n" + "\t\tVNOParamType types[256];\n" + "\t\tuint8 t;\n" + "\t\tchar name_buf[1500], *names[256];\n" + "\t\tfor(i = 0; i < param_count; i++)\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &t);\n" + "\t\t\ttypes[i] = t;\n" + "\t\t\tnames[i] = &name_buf[text];\n" + "\t\t\tsize = vnp_raw_unpack_string(&buf[buffer_pos], names[i], 1500 - buffer_pos, buffer_length - buffer_pos);\n" + "\t\t\tbuffer_pos += size;\n" + "\t\t\ttext += size;\n" + "\t\t}\n" + "\t\tif(func_o_method_create != NULL)\n" + "\t\t\tfunc_o_method_create(v_fs_get_user_data(43), node_id, group_id, method_id, name, param_count, types, (const char **) names);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_alias(FALSE, "o_method_destroy", "if(name[0] == 0)", 3, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_method_call", 44, VCGCT_UNIQUE); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_UINT16, "method_id"); + v_cg_add_param(VCGP_NODE_ID, "sender"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNOPackedParams"); + v_cg_add_param(VCGP_POINTER, "params"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned int i;\n" + "\t\tuint16 size;\n" + "\t\tvnp_raw_unpack_uint16(params, &size);\n" + "\t\tfor(i = 0; i < size; i++)\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((uint8 *)params)[i]);\n" + "\t\tfree((void *) params);\t/* Drop the const. */\n" + "\t}\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tunsigned int i;\n" + "\t\tuint8 par[1500];\n" + "\t\tuint16 size;\n" + "\t\tvnp_raw_unpack_uint16(&buf[buffer_pos], &size);\n" + "\t\tfor(i = 0; i < size; i++)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &par[i]);\n" + "\t\tif(func_o_method_call != NULL)\n" + "\t\t\tfunc_o_method_call(v_fs_get_user_data(44), node_id, group_id, method_id, sender, par);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_anim_run", 45, VCGCT_UNIQUE); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "link_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT32, "time_s"); + v_cg_add_param(VCGP_UINT32, "time_f"); + v_cg_add_param(VCGP_UINT8, "dimensions"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "pos"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "speed"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "accel"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "scale"); + v_cg_add_param(VCGP_POINTER_TYPE, "real64"); + v_cg_add_param(VCGP_POINTER, "scale_speed"); + v_cg_add_param(VCGP_PACK_INLINE, "\t{\n" + "\t\tunsigned char mask = 0;\n" + "\t\tunsigned int cmd, i;\n" + "\t\tcmd = buffer_pos++;\n" + "\t\tif(dimensions > 4)\n" + "\t\t\tdimensions = 4;\n" + "\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[i]);\n" + "\t\tif(speed != NULL)\n" + "\t\t{\n" + "\t\t\tmask |= 1;\n" + "\t\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[i]);\n" + "\t\t}\n" + "\t\tif(accel != NULL)\n" + "\t\t{\n" + "\t\t\tmask |= 2;\n" + "\t\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accel[i]);\n" + "\t\t}\n" + "\t\tif(scale != NULL)\n" + "\t\t{\n" + "\t\t\tmask |= 3;\n" + "\t\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale[i]);\n" + "\t\t}\n" + "\t\tif(scale_speed != NULL)\n" + "\t\t{\n" + "\t\t\tmask |= 4;\n" + "\t\t\tfor(i = 0; i < dimensions; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_speed[i]);\n" + "\t\t}\n" + "\t\tvnp_raw_pack_uint8(&buf[cmd], mask);\n" + "\t}\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\t{\n" + "\t\tdouble output[5][4];\n" + "\t\tunsigned int i, j;\n" + "\t\tchar mask, pow = 1;\n" + "\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask);\n" + "\t\tif(dimensions > 4)\n" + "\t\t\tdimensions = 4;\n" + "\t\tfor(j = 0; j < dimensions; j++)\n" + "\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[0][j]);\n" + "\t\tfor(i = 1; i < 5; i++)\n" + "\t\t{\n" + "\t\t\tif((mask & pow) != 0)\n" + "\t\t\t\tfor(j = 0; j < dimensions; j++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[i][j]);\n" + "\t\t\telse\n" + "\t\t\t\tfor(j = 0; j < dimensions; j++)\n" + "\t\t\t\t\toutput[i][j] = 0;\n" + "\t\t\tpow *= 2;\n" + "\t\t}\n" + "\t\tif(func_o_anim_run != NULL)\n" + "\t\t\tfunc_o_anim_run(v_fs_get_user_data(45), node_id, link_id, time_s, time_f, dimensions, &output[0][0], &output[1][0], &output[2][0], &output[3][0], &output[4][0]);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_OBJECT, "o_hide", 46, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_UINT8, "hidden"); + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_s.c b/extern/verse/dist/v_cmd_def_s.c new file mode 100644 index 00000000000..1b8b69dcd6d --- /dev/null +++ b/extern/verse/dist/v_cmd_def_s.c @@ -0,0 +1,211 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_system_cmd_def(void) +{ + v_cg_new_manual_cmd(0, "connect", "VSession verse_send_connect(const char *name, const char *pass, const char *address, const uint8 *expected_host_id)", NULL, NULL); + + v_cg_new_manual_cmd(1, "connect_accept", "VSession verse_send_connect_accept(VNodeID avatar, const char *address, uint8 *host_id)", NULL, NULL); + + v_cg_new_manual_cmd(2, "connect_terminate", "void verse_send_connect_terminate(const char *address, const char *bye)", NULL, NULL); + + v_cg_new_manual_cmd(5, "ping", "void verse_send_ping(const char *address, const char *message)", NULL, NULL); + + v_cg_new_cmd(V_NT_SYSTEM, "error_message", 6, VCGCT_UNIQUE); + v_cg_add_param(VCGP_LONG_NAME, "message"); + + v_cg_new_cmd(V_NT_SYSTEM, "packet_ack", 7, VCGCT_INVISIBLE_SYSTEM); + v_cg_add_param(VCGP_UINT32, "packet_id"); + v_cg_add_param(VCGP_PACK_INLINE, "\tv_cmd_buf_set_unique_address_size(head, buffer_pos);\n" + "\tv_cmd_buf_set_size(head, buffer_pos);\n" + "\tv_noq_send_ack_nak_buf(v_con_get_network_queue(), head);\n" + "\treturn;\n"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "packet_nak", 8, VCGCT_INVISIBLE_SYSTEM); + v_cg_add_param(VCGP_UINT32, "packet_id"); + v_cg_add_param(VCGP_PACK_INLINE, "\tv_cmd_buf_set_unique_address_size(head, buffer_pos);\n" + "\tv_cmd_buf_set_size(head, buffer_pos);\n" + "\tv_noq_send_ack_nak_buf(v_con_get_network_queue(), head);\n" + "\treturn;\n"); + v_cg_end_cmd(); + + + v_cg_new_cmd(V_NT_SYSTEM, "node_index_subscribe", 9, VCGCT_NORMAL); + v_cg_add_param(VCGP_UINT32, "mask"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "node_create", 10, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_ENUM_NAME, "VNodeType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_ENUM_NAME, "VNodeOwner"); + v_cg_add_param(VCGP_ENUM, "owner"); + v_cg_alias(FALSE, "node_destroy", "if(owner == (uint8) ~0u || type >= V_NT_NUM_TYPES)", 1, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "node_subscribe", 11, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "node_unsubscribe", NULL, 1, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "tag_group_create", 16, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_alias(FALSE, "tag_group_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "tag_group_subscribe", 17, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "tag_group_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "tag_create", 18, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_UINT16, "group_id"); + v_cg_add_param(VCGP_UINT16, "tag_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_add_param(VCGP_ENUM_NAME, "VNTagType"); + v_cg_add_param(VCGP_ENUM, "type"); + v_cg_add_param(VCGP_POINTER_TYPE, "VNTag"); + v_cg_add_param(VCGP_POINTER, "tag"); + v_cg_add_param(VCGP_PACK_INLINE, "\tif(type > VN_TAG_BLOB)\n" + "\t{\n" + "\t\tv_cmd_buf_free(head);\n" + "\t\treturn;\n" + "\t}\n" + "\tswitch(type)\n" + "\t{\n" + "\t\tcase VN_TAG_BOOLEAN :\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((VNTag *)tag)->vboolean);\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_UINT32 :\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vuint32);\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_REAL64 :\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64);\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_STRING :\n" + "\t\t{\n" + "\t\t\tunsigned int i;\n" + "\t\t\tfor(i = 0; ((VNTag *)tag)->vstring[i] != 0 && i < VN_TAG_MAX_BLOB_SIZE; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((VNTag *)tag)->vstring[i]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_REAL64_VEC3 :\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[0]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[1]);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[2]);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_LINK :\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vlink);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_ANIMATION :\n" + "\t\t{\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.curve);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.start);\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.end);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tcase VN_TAG_BLOB :\n" + "\t\t{\n" + "\t\t\tunsigned int i;\n" + "\t\t\tif(((VNTag *)tag)->vblob.size > VN_TAG_MAX_BLOB_SIZE)\n" + "\t\t\t\t((VNTag *)tag)->vblob.size = VN_TAG_MAX_BLOB_SIZE;\n" + "\t\t\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], ((VNTag *)tag)->vblob.size);\n" + "\t\t\tfor(i = 0; i < ((VNTag *)tag)->vblob.size; i++)\n" + "\t\t\t\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((uint8 *)((VNTag *)tag)->vblob.blob)[i]);\n" + "\t\t}\n" + "\t\tbreak;\n" + "\t\tdefault :\n" + "\t\t\t;\n" + "\t}\n"); + v_cg_add_param(VCGP_UNPACK_INLINE, "\tif(type < VN_TAG_TYPE_COUNT)\n" + "\t{\n" + "\t\tVNTag tag;\n" + "\t\tunsigned int i;\n" + "\t\tchar string[VN_TAG_MAX_BLOB_SIZE];\n" + "\t\tswitch(type)\n" + "\t\t{\n" + "\t\t\tcase VN_TAG_BOOLEAN :\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &tag.vboolean);\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_UINT32 :\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vuint32);\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_REAL64 :\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64);\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_STRING :\n" + "\t\t\t{\n" + "\t\t\t\ttag.vstring = string;\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], string, VN_TAG_MAX_BLOB_SIZE, buffer_length - buffer_pos);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_REAL64_VEC3 :\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[0]);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[1]);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[2]);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_LINK :\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vlink);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_ANIMATION :\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.curve);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.start);\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.end);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\t\tcase VN_TAG_BLOB :\n" + "\t\t\t{\n" + "\t\t\t\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tag.vblob.size);\n" + "\t\t\t\tif(tag.vblob.size > VN_TAG_MAX_BLOB_SIZE)\n" + "\t\t\t\t\ttag.vblob.size = VN_TAG_MAX_BLOB_SIZE;\n" + "\t\t\t\ttag.vblob.blob = string;\n" + "\t\t\t\tfor(i = 0; i < tag.vblob.size; i++)\n" + "\t\t\t\t\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &string[i]);\n" + "\t\t\t}\n" + "\t\t\tbreak;\n" + "\t\tdefault :\n" + "\t\t\t;\n" + "\t\t}\n" + "\t\tif(func_tag_create != NULL)\n" + "\t\tfunc_tag_create(v_fs_get_user_data(18), node_id, group_id, tag_id, name, type, &tag);\n" + "\t\treturn buffer_pos;\n" + "\t}\n"); + v_cg_alias(FALSE, "tag_destroy", "if(type >= VN_TAG_TYPE_COUNT)", 3, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_SYSTEM, "node_name_set", 19, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_LONG_NAME, "name"); + + v_cg_end_cmd(); +} + +#endif diff --git a/extern/verse/dist/v_cmd_def_t.c b/extern/verse/dist/v_cmd_def_t.c new file mode 100644 index 00000000000..3c568b42d7b --- /dev/null +++ b/extern/verse/dist/v_cmd_def_t.c @@ -0,0 +1,36 @@ + +#include +#include +#include "verse_header.h" +#include "v_cmd_gen.h" +#include "v_cmd_buf.h" + +#if defined(V_GENERATE_FUNC_MODE) + +void v_gen_text_cmd_def(void) +{ + v_cg_new_cmd(V_NT_TEXT, "t_language_set", 96, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_LONG_NAME, "language"); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_TEXT, "t_buffer_create", 97, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_BUFFER_ID, "buffer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_add_param(VCGP_NAME, "name"); + v_cg_alias(FALSE, "t_buffer_destroy", "if(name[0] == 0)", 2, NULL); + v_cg_end_cmd(); + + v_cg_new_cmd(V_NT_TEXT, "t_buffer_subscribe", 98, VCGCT_NORMAL); + v_cg_add_param(VCGP_NODE_ID, "node_id"); + v_cg_add_param(VCGP_BUFFER_ID, "buffer_id"); + v_cg_add_param(VCGP_END_ADDRESS, NULL); + v_cg_alias(TRUE, "t_buffer_unsubscribe", NULL, 2, NULL); + v_cg_end_cmd(); + + v_cg_new_manual_cmd(99, "t_text_set", "void verse_send_t_text_set(VNodeID node_id, VBufferID buffer_id, uint32 pos, uint32 length, const char *text)", NULL, NULL); +} + +#endif diff --git a/extern/verse/dist/v_cmd_gen.c b/extern/verse/dist/v_cmd_gen.c new file mode 100644 index 00000000000..3d18f8cf1af --- /dev/null +++ b/extern/verse/dist/v_cmd_gen.c @@ -0,0 +1,939 @@ +/* +** +*/ + +#include +#include +#include + +#include "verse_header.h" +#include "v_cmd_buf.h" + +#include "v_cmd_gen.h" + +#if defined _WIN32 +#include +#define chdir _chdir +#define snprintf _snprintf +#endif + +#if defined V_GENERATE_FUNC_MODE + +#define MAX_PARAMS_PER_CMD 32 + +static struct { + FILE *nodes[V_NT_NUM_TYPES_NETPACK]; + FILE *init; + FILE *unpack; + FILE *verse_h; + FILE *internal_verse_h; + const char *func_name; + VNodeType type; + VCGCommandType command; + unsigned int param_count; + VCGParam param_type[MAX_PARAMS_PER_CMD]; + const char *param_name[MAX_PARAMS_PER_CMD]; + unsigned int cmd_id; + const char *alias_name; + const char *alias_qualifier; + unsigned int alias_param; + unsigned int *alias_param_array; + char alias_bool_switch; +} VCGData; + +extern void v_gen_system_cmd_def(void); +extern void v_gen_object_cmd_def(void); +extern void v_gen_geometry_cmd_def(void); +extern void v_gen_material_cmd_def(void); +extern void v_gen_bitmap_cmd_def(void); +extern void v_gen_text_cmd_def(void); +extern void v_gen_curve_cmd_def(void); +extern void v_gen_audio_cmd_def(void); + +static int v_cg_init(const char *src_path) +{ + char buf[1024]; + int i; + FILE *f; + + VCGData.nodes[V_NT_OBJECT] = fopen("v_gen_pack_o_node.c", "w"); + VCGData.nodes[V_NT_GEOMETRY] = fopen("v_gen_pack_g_node.c", "w"); + VCGData.nodes[V_NT_MATERIAL] = fopen("v_gen_pack_m_node.c", "w"); + VCGData.nodes[V_NT_BITMAP] = fopen("v_gen_pack_b_node.c", "w"); + VCGData.nodes[V_NT_TEXT] = fopen("v_gen_pack_t_node.c", "w"); + VCGData.nodes[V_NT_CURVE] = fopen("v_gen_pack_c_node.c", "w"); + VCGData.nodes[V_NT_AUDIO] = fopen("v_gen_pack_a_node.c", "w"); + VCGData.nodes[V_NT_SYSTEM] = fopen("v_gen_pack_s_node.c", "w"); + VCGData.init = fopen("v_gen_pack_init.c", "w"); + VCGData.unpack = fopen("v_gen_unpack_func.h", "w"); + VCGData.verse_h = fopen("verse.h", "w"); + VCGData.internal_verse_h = fopen("v_internal_verse.h", "w"); + for(i = 0; i < V_NT_NUM_TYPES_NETPACK + 1; i++) + { + if(i == V_NT_NUM_TYPES_NETPACK) + f = VCGData.init; + else + f = VCGData.nodes[i]; + fprintf(f, + "/*\n" + "** This is automatically generated source code -- do not edit.\n" + "** Changes are affected either by editing the corresponding protocol\n" + "** definition file (v_cmd_def_X.c where X=node type), or by editing\n" + "** the code generator itself, in v_cmd_gen.c.\n" + "*/\n\n"); + fprintf(f, "#include \n"); + fprintf(f, "#include \n\n"); + fprintf(f, "#include \"v_cmd_gen.h\"\n"); + fprintf(f, "#if !defined(V_GENERATE_FUNC_MODE)\n"); + fprintf(f, "#include \"verse.h\"\n"); + fprintf(f, "#include \"v_cmd_buf.h\"\n"); + fprintf(f, "#include \"v_network_out_que.h\"\n"); + fprintf(f, "#include \"v_network.h\"\n"); + fprintf(f, "#include \"v_connection.h\"\n"); + fprintf(f, "#include \"v_util.h\"\n\n"); + } + VCGData.cmd_id = 0; + fprintf(f, "#include \"v_gen_unpack_func.h\"\n\n"); + fprintf(f, + "#include \"verse.h\"\n\n\n" + "extern void verse_send_packet_ack(uint32 packet_id);\n" + "extern void verse_send_packet_nak(uint32 packet_id);\n\n"); + + fprintf(VCGData.init, "void init_pack_and_unpack(void)\n{\n"); + fprintf(VCGData.verse_h, + "/*\n" + "** Verse API Header file (for use with libverse.a).\n" + "** This is automatically generated code; do not edit.\n" + "*/\n\n" + "\n" + "#if !defined VERSE_H\n" + "\n" + "#if defined __cplusplus\t\t/* Declare as C symbols for C++ users. */\n" + "extern \"C\" {\n" + "#endif\n\n" + "#define\tVERSE_H\n\n"); + /* Copy contents of "verse_header.h" into output "verse.h". */ + snprintf(buf, sizeof buf, "%sverse_header.h", src_path); + f = fopen(buf, "r"); + if(f != NULL) + { + while((i = fgetc(f)) != EOF) + fputc(i, VCGData.verse_h); + fclose(f); + } + else + { + fprintf(stderr, "mkprot: Couldn't find \"%s\" input file\n", buf); + return 0; + } + fprintf(VCGData.verse_h, "\n/* Command sending functions begin. ----------------------------------------- */\n\n"); + return 1; +} + +static void v_cg_close(void) +{ + unsigned int i; + for(i = 0; i < V_NT_NUM_TYPES_NETPACK; i++) + { + fprintf(VCGData.nodes[i], "#endif\n\n"); + } + fprintf(VCGData.init, "}\n#endif\n\n"); + fprintf(VCGData.verse_h, + "\n#if defined __cplusplus\n" + "}\n" + "#endif\n"); + fprintf(VCGData.verse_h, "\n#endif\t\t/* VERSE_H */\n"); +} + +void v_cg_new_cmd(VCGCommandType type, const char *name, unsigned int cmd_id, VCGCommandType command) +{ + VCGData.param_count = 0; + VCGData.func_name = name; + VCGData.type = type; + VCGData.cmd_id = cmd_id; + VCGData.command = command; +/* printf("def: %u: %s\n", cmd_id, name);*/ +} + +void v_cg_new_manual_cmd(unsigned int cmd_id, const char *name, const char *def, const char *alias_name, const char *alias_def) +{ + fprintf(VCGData.verse_h, "extern %s;\n", def); + if(alias_def != NULL) + fprintf(VCGData.verse_h, "extern %s;\n", alias_def); + fprintf(VCGData.init, "\tv_fs_add_func(%i, v_unpack_%s, (void *) verse_send_%s, ", cmd_id, name, name); + if(alias_name != NULL) + fprintf(VCGData.init, "(void *) verse_send_%s);\n", alias_name); + else + fprintf(VCGData.init, "NULL);\n"); + fprintf(VCGData.unpack, "extern unsigned int v_unpack_%s(const char *data, size_t length);\n", name); +/* printf("def: %u: %s\n", cmd_id, name);*/ +} + +void v_cg_alias(char bool_switch, const char *name, const char *qualifier, unsigned int param, unsigned int *param_array) +{ + VCGData.alias_name = name; + VCGData.alias_qualifier = qualifier; + VCGData.alias_param = param; + VCGData.alias_param_array = param_array; + VCGData.alias_bool_switch = bool_switch; +} + +void v_cg_add_param(VCGParam type, const char *name) +{ + if(VCGData.param_count == MAX_PARAMS_PER_CMD) + exit(1); + VCGData.param_type[VCGData.param_count] = type; + VCGData.param_name[VCGData.param_count] = name; + VCGData.param_count++; +} + +static void v_cg_gen_func_params(FILE *f, boolean types, boolean alias) +{ + unsigned int i; + unsigned int length, active; + length = VCGData.param_count; + if(alias) + length = VCGData.alias_param; + for(i = 0; i < length; i++) + { + if(alias && VCGData.alias_param_array != NULL) + active = VCGData.alias_param_array[i]; + else + { + for(;(VCGData.param_type[i] == VCGP_PACK_INLINE || VCGData.param_type[i] == VCGP_UNPACK_INLINE || VCGData.param_type[i] == VCGP_POINTER_TYPE || VCGData.param_type[i] == VCGP_ENUM_NAME) && i < VCGData.param_count; i++); + if(i == VCGData.param_count) + break; + active = i; + } + + if(active < VCGData.param_count && VCGData.param_type[active] != VCGP_END_ADDRESS) + { + switch(VCGData.param_type[active]) + { + case VCGP_UINT8 : + fprintf(f, "uint8 %s", VCGData.param_name[active]); + break; + case VCGP_UINT16 : + fprintf(f, "uint16 %s", VCGData.param_name[active]); + break; + case VCGP_UINT32 : + fprintf(f, "uint32 %s", VCGData.param_name[active]); + break; + case VCGP_REAL32 : + fprintf(f, "real32 %s", VCGData.param_name[active]); + break; + case VCGP_REAL64 : + fprintf(f, "real64 %s", VCGData.param_name[active]); + break; + case VCGP_POINTER : + if(active != 0 && VCGData.param_type[active - 1] == VCGP_POINTER_TYPE) + fprintf(f, "const %s *%s", VCGData.param_name[active - 1], VCGData.param_name[active]); + else + fprintf(f, "const void *%s", VCGData.param_name[active]); + break; + case VCGP_NAME : + if(types) + fprintf(f, "char %s[16]", VCGData.param_name[active]); + else + fprintf(f, "const char *%s", VCGData.param_name[active]); + break; + case VCGP_LONG_NAME : + if(types) + fprintf(f, "char %s[512]", VCGData.param_name[active]); + else + fprintf(f, "const char *%s", VCGData.param_name[active]); + break; + case VCGP_NODE_ID : + fprintf(f, "VNodeID %s", VCGData.param_name[active]); + break; + case VCGP_LAYER_ID : + fprintf(f, "VLayerID %s", VCGData.param_name[active]); + break; + case VCGP_BUFFER_ID : + fprintf(f, "VBufferID %s", VCGData.param_name[active]); + break; + case VCGP_FRAGMENT_ID : + fprintf(f, "VNMFragmentID %s", VCGData.param_name[active]); + break; + case VCGP_ENUM : +/* if(types) + fprintf(f, "uint8 %s", VCGData.param_name[active]); + else +*/ fprintf(f, "%s %s", VCGData.param_name[active - 1], VCGData.param_name[active]); + break; + } + if(types) + fprintf(f, ";\n\t"); + else + { + for(;(VCGData.param_type[active + 1] == VCGP_END_ADDRESS || VCGData.param_type[active + 1] == VCGP_PACK_INLINE || VCGData.param_type[active + 1] == VCGP_UNPACK_INLINE || VCGData.param_type[active + 1] == VCGP_POINTER_TYPE) && active < VCGData.param_count; active++); + if(active + 1 < length) + fprintf(f, ", "); + } + } + } +} + +static void v_cg_create_print(FILE *f, boolean send, boolean alias) +{ + unsigned int i, length, active; + const char *name; + if(VCGData.command == VCGCT_INVISIBLE_SYSTEM) + return; + name = VCGData.func_name; + if(alias) + name = VCGData.alias_name; + if(send) + fprintf(f, "\tprintf(\"send: verse_send_%s(", name); + else + fprintf(f, "\tprintf(\"receive: verse_send_%s(", name); + + length = VCGData.param_count; + if(alias) + length = VCGData.alias_param; + for(i = 0; i < length; i++) + { + if(alias && VCGData.alias_param_array != NULL) + active = VCGData.alias_param_array[i]; + else + active = i; + + switch(VCGData.param_type[active]) + { + case VCGP_NODE_ID : + fprintf(f, "%s = %%u ", VCGData.param_name[active]); + break; + case VCGP_UINT8 : + case VCGP_UINT16 : + case VCGP_UINT32 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_ENUM : + case VCGP_FRAGMENT_ID : + fprintf(f, "%s = %%u ", VCGData.param_name[active]); + break; + case VCGP_REAL32 : + case VCGP_REAL64 : + fprintf(f, "%s = %%f ", VCGData.param_name[active]); + break; + case VCGP_POINTER : + if(send) + fprintf(f, "%s = %%p ", VCGData.param_name[active]); + break; + case VCGP_NAME : + case VCGP_LONG_NAME : + fprintf(f, "%s = %%s ", VCGData.param_name[active]); + break; + } + } + if(send) + fprintf(f, ");\\n\""); + else + fprintf(f, "); callback = %%p\\n\""); + + for(i = 0; i < length; i++) + { + if(alias && VCGData.alias_param_array != NULL) + active = VCGData.alias_param_array[i]; + else + active = i; + switch(VCGData.param_type[active]) + { + case VCGP_NODE_ID : + fprintf(f, ", %s", VCGData.param_name[active]); + break; + case VCGP_POINTER : + if(!send) + break; + case VCGP_UINT8 : + case VCGP_UINT16 : + case VCGP_UINT32 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_ENUM : + case VCGP_FRAGMENT_ID : + case VCGP_REAL32 : + case VCGP_REAL64 : + case VCGP_NAME : + case VCGP_LONG_NAME : + fprintf(f, ", %s", VCGData.param_name[active]); + break; + } + } + if(send) + fprintf(f, ");\n"); + else if(alias) + fprintf(f, ", v_fs_get_alias_user_func(%u));\n", VCGData.cmd_id); + else + fprintf(f, ", v_fs_get_user_func(%u));\n", VCGData.cmd_id); + +} + +static unsigned int v_cg_compute_command_size(unsigned int start, boolean end) +{ + unsigned int size = 0; + for(; start < VCGData.param_count; start++) + { + switch(VCGData.param_type[start]) + { + case VCGP_UINT8 : + case VCGP_ENUM : + size++; + break; + case VCGP_UINT16 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_FRAGMENT_ID : + size += 2; + break; + case VCGP_NODE_ID : + case VCGP_UINT32 : + case VCGP_REAL32 : + size += 4; + break; + case VCGP_REAL64 : + size += 8; + break; + case VCGP_NAME : + if(end) + return size; + size += 16; + break; + case VCGP_LONG_NAME : + if(end) + return size; + size += 512; + break; + case VCGP_POINTER : + case VCGP_PACK_INLINE : + case VCGP_UNPACK_INLINE : + if(end) + return size; + size += 1500; + break; + case VCGP_END_ADDRESS : + if(end) + return size; + } + } + return size; +} + +void v_cg_set_command_address(FILE *f, boolean alias) +{ + unsigned int i, j, count = 0, length, size = 1, *param, def[] ={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + + for(i = 0; i < VCGData.param_count; i++) + if(VCGData.param_type[i] == VCGP_END_ADDRESS) + break; + if(i == VCGData.param_count) + return; + if(alias) + length = VCGData.alias_param; + else + length = VCGData.param_count; + + if(alias && VCGData.alias_param_array != 0) + param = VCGData.alias_param_array; + else + param = def; + + if(i == VCGData.param_count) + return; + fprintf(f, "\tif("); + for(i = j = 0; i < VCGData.param_count; i++) + { + switch(VCGData.param_type[i]) + { + case VCGP_UINT8 : + case VCGP_ENUM : + size++; + break; + case VCGP_UINT16 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_FRAGMENT_ID : + size += 2; + break; + case VCGP_NODE_ID : + case VCGP_UINT32 : + case VCGP_REAL32 : + size += 4; + break; + } + if(j < length && param[j] == i) + { + switch(VCGData.param_type[param[j]]) + { + case VCGP_UINT8 : + case VCGP_ENUM : + break; + case VCGP_UINT16 : + case VCGP_LAYER_ID : + case VCGP_BUFFER_ID : + case VCGP_FRAGMENT_ID : + if(count++ != 0) + fprintf(f, " || "); + fprintf(f, "%s == (uint16) ~0u", VCGData.param_name[param[j]]); + break; + case VCGP_NODE_ID : + case VCGP_UINT32 : + case VCGP_REAL32 : + if(count++ != 0) + fprintf(f, " || "); + fprintf(f, "%s == (uint32) ~0u", VCGData.param_name[param[j]]); + break; + } + j++; + } + if(VCGData.param_type[i] == VCGP_END_ADDRESS) + { + fprintf(f, ")\n"); + fprintf(f, "\t\tv_cmd_buf_set_unique_address_size(head, %u);\n", size); + fprintf(f, "\telse\n"); + fprintf(f, "\t\tv_cmd_buf_set_address_size(head, %u);\n", size); + return; + } + } + fprintf(f, ")\n"); + fprintf(f, "\t\tv_cmd_buf_set_unique_address_size(head, %u);\n", size); + fprintf(f, "\telse\n"); + fprintf(f, "\t\tv_cmd_buf_set_address_size(head, %u);\n", size); + return; +} + +static const char * v_cg_compute_buffer_size(void) +{ + unsigned int size; + size = v_cg_compute_command_size(0, FALSE) + 1; + if(size <= 10) + return "VCMDBS_10"; + else if(size <= 20) + return "VCMDBS_20"; + else if(size <= 30) + return "VCMDBS_30"; + else if(size <= 80) + return "VCMDBS_80"; + else if(size <= 160) + return "VCMDBS_160"; + else if(size <= 320) + return "VCMDBS_320"; + return "VCMDBS_1500"; +} + +static void v_cg_gen_pack(boolean alias) +{ + unsigned int i, j, size = 0, ad_size = 0; + boolean printed = FALSE; + boolean address = FALSE; + boolean no_param; + + FILE *f; + f = VCGData.nodes[VCGData.type]; + printf("generating function: verse_send_%s\n", VCGData.func_name); + if(alias) + fprintf(f, "void verse_send_%s(", VCGData.alias_name); + else + fprintf(f, "void verse_send_%s(", VCGData.func_name); + v_cg_gen_func_params(f, FALSE, alias); + fprintf(f, ")\n{\n\tuint8 *buf;\n"); + fprintf(f, "\tunsigned int buffer_pos = 0;\n"); + fprintf(f, "\tVCMDBufHead *head;\n"); + fprintf(f, "\thead = v_cmd_buf_allocate(%s);/* Allocating the buffer */\n", v_cg_compute_buffer_size()); + fprintf(f, "\tbuf = ((VCMDBuffer10 *)head)->buf;\n\n"); + + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], %u);\t/* Pack the command. */\n", VCGData.cmd_id); + + fprintf(f, "#if defined V_PRINT_SEND_COMMANDS\n"); + v_cg_create_print(f, TRUE, alias); + fprintf(f, "#endif\n"); + + for(i = 0; i < VCGData.param_count; i++) + { + const char *param = VCGData.param_name[i]; + no_param = FALSE; + if(alias) + { + if(i >= VCGData.alias_param && VCGData.alias_param_array == NULL) + no_param = TRUE; + if(VCGData.alias_param_array != NULL) + { + for(j = 0; j < VCGData.alias_param; j++) + if(VCGData.alias_param_array[j] == i) + break; + if(j == VCGData.alias_param) + no_param = TRUE; + } + } + + if(no_param) + param = "-1"; + + switch(VCGData.param_type[i]) + { + case VCGP_UINT8 : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_UINT16 : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_UINT32 : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_ENUM : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)%s);\n", param); + break; + } + if(VCGData.param_type[i] == VCGP_REAL32) + { + if(no_param) + param = "V_REAL32_MAX"; + fprintf(f, "\tbuffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], %s);\n", param); + } + if(VCGData.param_type[i] == VCGP_REAL64) + { + if(no_param) + param = "V_REAL64_MAX"; + fprintf(f, "\tbuffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], %s);\n", param); + } + if(no_param) + param = "NULL"; + switch(VCGData.param_type[i]) + { + case VCGP_NAME : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], %s, 16);\n", param); + break; + case VCGP_LONG_NAME : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_string(&buf[buffer_pos], %s, 512);\n", param); + break; + } + if(no_param) + { + /* Horrible work-around, that prevents vertex/polygon deletes from misbehaving. */ + if(strncmp(VCGData.alias_name, "g_vertex_delete_real", 20) == 0 && i == 1) + param = "0"; + else if(strncmp(VCGData.alias_name, "g_polygon_delete", 16) == 0 && i == 1) + param = "1"; + else + param = "-1"; + } + switch(VCGData.param_type[i]) + { + case VCGP_NODE_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_LAYER_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_BUFFER_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], %s);\n", param); + break; + case VCGP_FRAGMENT_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], %s);\n", param); + break; + } + if(!alias && VCGData.param_type[i] == VCGP_PACK_INLINE) + fprintf(f, "%s", VCGData.param_name[i]); + } + if(VCGData.alias_name != NULL && VCGData.alias_bool_switch) + { + if(alias) + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE);\n"); + else + fprintf(f, "\tbuffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE);\n"); + } + v_cg_set_command_address(f, alias); + fprintf(f, "\tv_cmd_buf_set_size(head, buffer_pos);\n"); + + fprintf(f, "\tv_noq_send_buf(v_con_get_network_queue(), head);\n"); + fprintf(f, "}\n\n"); +} + +static void v_cg_gen_unpack(void) +{ + FILE *f; + unsigned int i; + boolean printed = FALSE; + + f = VCGData.nodes[VCGData.type]; + printf("generating function: v_unpack_%s\n", VCGData.func_name); + fprintf(f, "unsigned int v_unpack_%s(const char *buf, size_t buffer_length)\n", VCGData.func_name); + fprintf(f, "{\n"); + for(i = 0; i < VCGData.param_count && VCGData.param_type[i] != VCGP_ENUM; i++); + if(i < VCGData.param_count) + fprintf(f, "\tuint8 enum_temp;\n"); + fprintf(f, "\tunsigned int buffer_pos = 0;\n"); + fprintf(f, "\tvoid (* func_%s)(void *user_data, ", VCGData.func_name); + v_cg_gen_func_params(f, FALSE, FALSE); + fprintf(f, ");\n\t"); + v_cg_gen_func_params(f, TRUE, FALSE); + if(VCGData.alias_name != NULL && VCGData.alias_bool_switch) + fprintf(f, "uint8\talias_bool;\n"); + fprintf(f, "\n\tfunc_%s = v_fs_get_user_func(%u);\n", VCGData.func_name, VCGData.cmd_id); + fprintf(f, "\tif(buffer_length < %u)\n\t\treturn -1;\n", v_cg_compute_command_size(0, TRUE)); + for(i = 0; i < VCGData.param_count; i++) + { + switch(VCGData.param_type[i]) + { + case VCGP_UINT8 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_UINT16 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_UINT32 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_REAL32 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_REAL64 : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_POINTER_TYPE : + break; + case VCGP_POINTER : + break; + case VCGP_NAME : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], %s, 16, buffer_length - buffer_pos);\n", VCGData.param_name[i]); + if(i + 1 < VCGData.param_count) + fprintf(f, "\tif(buffer_length < %u + buffer_pos)\n\t\treturn -1;\n", v_cg_compute_command_size(i + 1, TRUE)); + break; + case VCGP_LONG_NAME : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], %s, 512, buffer_length - buffer_pos);\n", VCGData.param_name[i]); + if(i + 1 < VCGData.param_count) + fprintf(f, "\tif(buffer_length < %u + buffer_pos)\n\t\treturn -1;\n", v_cg_compute_command_size(i + 1, TRUE)); + break; + case VCGP_NODE_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_LAYER_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_BUFFER_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_FRAGMENT_ID : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &%s);\n", VCGData.param_name[i]); + break; + case VCGP_ENUM : + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp);\n"); + fprintf(f, "\t%s = (%s)enum_temp;\n", VCGData.param_name[i], VCGData.param_name[i - 1]); + break; + case VCGP_UNPACK_INLINE : + if(!printed) + { + fprintf(f, "#if defined V_PRINT_RECEIVE_COMMANDS\n"); + if(VCGData.alias_name != NULL) + { + fprintf(f, "\t%s\n\t", VCGData.alias_qualifier); + v_cg_create_print(f, FALSE, TRUE); + fprintf(f, "\telse\n\t"); + } + v_cg_create_print(f, FALSE, FALSE); + fprintf(f, "#endif\n"); + printed = TRUE; + } + fprintf(f, "%s\n", VCGData.param_name[i++]); + break; + } + } + if(VCGData.alias_name != NULL && VCGData.alias_bool_switch) + { + fprintf(f, "\tif(buffer_length < buffer_pos + 1)\n"); + fprintf(f, "\t\treturn -1;\n"); + fprintf(f, "\tbuffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool);\n"); + } + if(!printed) + { + fprintf(f, "#if defined V_PRINT_RECEIVE_COMMANDS\n"); + if(VCGData.alias_name != NULL) + { + if(VCGData.alias_qualifier != NULL) + fprintf(f, "\t%s\n\t", VCGData.alias_qualifier); + else + fprintf(f, "\tif(!alias_bool)\n\t"); + v_cg_create_print(f, FALSE, TRUE); + fprintf(f, "\telse\n\t"); + } + v_cg_create_print(f, FALSE, FALSE); + fprintf(f, "#endif\n"); + printed = TRUE; + } + + if(VCGData.alias_name != NULL) + { + unsigned int active; + + if(VCGData.alias_bool_switch) + fprintf(f, "\tif(!alias_bool)\n"); + else + fprintf(f, "\t%s\n", VCGData.alias_qualifier); + fprintf(f, "\t{\n"); + fprintf(f, "\t\tvoid (* alias_%s)(void *user_data, ", VCGData.alias_name); + v_cg_gen_func_params(f, FALSE, TRUE); + fprintf(f, ");\n"); + fprintf(f, "\t\talias_%s = v_fs_get_alias_user_func(%u);\n", VCGData.alias_name, VCGData.cmd_id); + fprintf(f, "\t\tif(alias_%s != NULL)\n", VCGData.alias_name); + fprintf(f, "\t\t\talias_%s(v_fs_get_alias_user_data(%u)", VCGData.alias_name, VCGData.cmd_id); + for(i = 0; i < VCGData.param_count && i < VCGData.alias_param; i++) + { + if(VCGData.alias_param_array != NULL) + active = VCGData.alias_param_array[i]; + else + active = i; + + if(VCGData.param_type[active] != VCGP_PACK_INLINE && + VCGData.param_type[active] != VCGP_UNPACK_INLINE && + VCGData.param_type[active] != VCGP_END_ADDRESS && + VCGData.param_type[active] != VCGP_POINTER_TYPE) + { + if(VCGData.param_type[active] == VCGP_ENUM_NAME) + { + fprintf(f, ", (%s)%s", VCGData.param_name[active], VCGData.param_name[active + 1]); + i++; + } + else + fprintf(f, ", %s", VCGData.param_name[active]); + } + } + fprintf(f, ");\n\t\treturn buffer_pos;\n\t}\n"); + } + + fprintf(f, "\tif(func_%s != NULL)\n", VCGData.func_name); + fprintf(f, "\t\tfunc_%s(v_fs_get_user_data(%u)", VCGData.func_name, VCGData.cmd_id); + for(i = 0; i < VCGData.param_count; i++) + { + if(VCGData.param_type[i] != VCGP_PACK_INLINE && VCGData.param_type[i] != VCGP_UNPACK_INLINE && VCGData.param_type[i] != VCGP_END_ADDRESS && VCGData.param_type[i] != VCGP_POINTER_TYPE) + { + if(VCGData.param_type[i] == VCGP_ENUM_NAME) + { + fprintf(f, ", (%s) %s", VCGData.param_name[i], VCGData.param_name[i + 1]); + i++; + } + else + fprintf(f, ", %s", VCGData.param_name[i]); + } + } + fprintf(f, ");\n"); + fprintf(f, "\n\treturn buffer_pos;\n"); + fprintf(f, "}\n\n"); +} + +static void v_cg_gen_alias(void) +{ + FILE *f; + unsigned int i; + f = VCGData.nodes[VCGData.type]; + fprintf(f, "void verse_send_%s(", VCGData.alias_name); + v_cg_gen_func_params(f, FALSE, TRUE); + fprintf(f, ")\n{\n"); + fprintf(f, "\tverse_send_%s(", VCGData.func_name); + for(i = 0; i < VCGData.param_count; i++) + if(VCGData.param_type[i] != VCGP_ENUM_NAME && VCGData.param_type[i] != VCGP_PACK_INLINE && VCGData.param_type[i] != VCGP_UNPACK_INLINE && VCGData.param_type[i] != VCGP_END_ADDRESS && VCGData.param_type[i] != VCGP_POINTER_TYPE) + fprintf(f, ", %s", VCGData.param_name[i]); + fprintf(f, "}\n\n"); +} + +static void v_cg_gen_init(void) +{ + FILE *f; + f = VCGData.init; + fprintf(f, "\tv_fs_add_func(%i, v_unpack_%s, verse_send_%s, ", VCGData.cmd_id, VCGData.func_name, VCGData.func_name); + if(VCGData.alias_name != NULL) + fprintf(f, "verse_send_%s);\n", VCGData.alias_name); + else + fprintf(f, "NULL);\n"); +} + +static void v_cg_gen_verse_h(void) +{ + FILE *f; + if(VCGData.command == VCGCT_INVISIBLE_SYSTEM) + f = VCGData.internal_verse_h; + else + f = VCGData.verse_h; + fprintf(f, "extern void verse_send_%s(", VCGData.func_name); + v_cg_gen_func_params(f, FALSE, FALSE); + fprintf(f, ");\n"); + if(VCGData.alias_name != NULL) + { + fprintf(f, "extern void verse_send_%s(", VCGData.alias_name); + v_cg_gen_func_params(f, FALSE, TRUE); + fprintf(f, ");\n"); + } +} + +static void v_cg_gen_unpack_h(void) +{ + fprintf(VCGData.unpack, "extern unsigned int v_unpack_%s(const char *data, size_t length);\n", VCGData.func_name); +} + +void v_cg_end_cmd(void) +{ + v_cg_gen_pack(FALSE); + if(VCGData.alias_name != NULL) + v_cg_gen_pack(TRUE); + v_cg_gen_unpack(); + v_cg_gen_init(); + v_cg_gen_verse_h(); + v_cg_gen_unpack_h(); + VCGData.alias_name = NULL; +} + +int main(int argc, char *argv[]) +{ + const char *src = ""; + int i; + + for(i = 1; argv[i] != NULL; i++) + { + if(strcmp(argv[i], "-h") == 0) + { + printf("Verse protocol generation tool.\nUsage:\n"); + printf(" -h\t\tPrint this usage information, and exit.\n"); + printf(" -src=PATH\tSets source path prefix to PATH. It must be possible to find\n"); + printf("\t\tthe \"verse_header.h\" input file by appending that name to PATH.\n"); + printf("\t\tThus, PATH must end with a proper directory separator character.\n"); + printf(" -dst=PATH\tSets output directory, where all output files are written.\n"); + printf("\t\tIf used, use -src to point to where \"verse_header.h\" is.\n"); + printf("\nThe -src and -dst options were added to simplify building of Verse-Blender.\n"); + return EXIT_SUCCESS; + } + else if(strncmp(argv[i], "-src=", 5) == 0) + src = argv[i] + 5; + else if(strncmp(argv[i], "-dst=", 5) == 0) + { + if(chdir(argv[i] + 5) != 0) + fprintf(stderr, "%s: Couldn't set output directory to \"%s\"\n", argv[0], argv[i] + 5); + } + else + fprintf(stderr, "%s: Ignoring unknown option \"%s\"\n", argv[0], argv[i]); + } + + printf("start\n"); + if(!v_cg_init(src)) + return EXIT_FAILURE; + v_gen_system_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_object_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_geometry_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_material_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_bitmap_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_text_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_curve_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_gen_audio_cmd_def(); + fprintf(VCGData.verse_h, "\n"); + v_cg_close(); + printf("end\n"); + + return EXIT_SUCCESS; +} + +#endif diff --git a/extern/verse/dist/v_cmd_gen.h b/extern/verse/dist/v_cmd_gen.h new file mode 100644 index 00000000000..6cc19a84d19 --- /dev/null +++ b/extern/verse/dist/v_cmd_gen.h @@ -0,0 +1,42 @@ +/* +** +*/ + +/* Define this to at least build the code that regenerates the variable parts of the code. */ +/*#define V_GENERATE_FUNC_MODE*/ + +typedef enum { + VCGP_UINT8, + VCGP_UINT16, + VCGP_UINT32, + VCGP_REAL32, + VCGP_REAL64, + VCGP_POINTER_TYPE, + VCGP_POINTER, + VCGP_NAME, + VCGP_LONG_NAME, + VCGP_NODE_ID, + VCGP_LAYER_ID, + VCGP_BUFFER_ID, + VCGP_FRAGMENT_ID, + VCGP_ENUM_NAME, + VCGP_ENUM, + VCGP_PACK_INLINE, + VCGP_UNPACK_INLINE, + VCGP_END_ADDRESS +} VCGParam; + +typedef enum { + VCGCT_NORMAL, + VCGCT_UNIQUE, + VCGCT_ONCE, + VCGCT_INVISIBLE_SYSTEM, /* In the dark we are all invisible. */ + VCGCT_ORDERED +} VCGCommandType; + +extern void v_cg_new_cmd(VCGCommandType type, const char *name, unsigned int cmd_id, VCGCommandType command); +extern void v_cg_add_param(VCGParam type, const char *name); +extern void v_cg_alias(char bool_switch, const char *name, const char *qualifier, + unsigned int param, unsigned int *param_array); +extern void v_cg_end_cmd(void); +extern void v_cg_new_manual_cmd(unsigned int cmd_id, const char *name, const char *params, const char *alias_name, const char *alias_params); diff --git a/extern/verse/dist/v_connect.c b/extern/verse/dist/v_connect.c new file mode 100644 index 00000000000..31be90e2d47 --- /dev/null +++ b/extern/verse/dist/v_connect.c @@ -0,0 +1,490 @@ +/* +** +*/ + +#include +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_encryption.h" +#include "v_util.h" + +extern void verse_send_packet_ack(uint32 packet_id); + +static void v_send_hidden_connect_contact(void) /* Stage 0: Clinets inital call to connect to host */ +{ + uint8 buf[V_ENCRYPTION_LOGIN_KEY_HALF_SIZE + 4 + 1 + 1], *key; + unsigned int i, buffer_pos = 0; + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 0);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);/* Packing the command */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);/* Stage 0 */ + + key = v_con_get_my_key(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], key[V_ENCRYPTION_LOGIN_PUBLIC_START + i]);/* Packing the command */ + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], key[V_ENCRYPTION_LOGIN_N_START + i]);/* Packing the command */ + + v_n_send_data(v_con_get_network_address(), buf, buffer_pos); +} + +static void v_send_hidden_connect_send_key(void) /* Stage 1: Hosts reply to any atempt to connect */ +{ + uint8 buf[V_ENCRYPTION_LOGIN_KEY_SIZE * 3 + 4 + 1 + 1 + 1 + 4 + 4], *host_id; + unsigned int i, buffer_pos = 0, s, f; + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 0);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);/* Packing the command */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 1);/* Stage 1 */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], V_RELEASE_NUMBER);/* version */ + v_n_get_current_time(&s, &f); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], s);/* time, seconds */ + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], f);/* time, fraction */ + host_id = v_con_get_host_id(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], host_id[V_ENCRYPTION_LOGIN_PUBLIC_START + i]); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], host_id[V_ENCRYPTION_LOGIN_N_START + i]); + + v_n_send_data(v_con_get_network_address(), buf, buffer_pos); +} + +static void v_send_hidden_connect_login(void) /* Stage 2: clients sends encrypted name and password */ +{ + uint8 buf[1500], *key, name_pass[V_ENCRYPTION_LOGIN_KEY_SIZE], encrypted_key[V_ENCRYPTION_LOGIN_KEY_SIZE]; + const char *name, *pass; + unsigned int buffer_pos = 0, i; + + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 1);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0);/* Packing the command */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 2);/* Stage 2 */ + name = v_con_get_name(); + /* Pad data area with randomness. */ + for(i = 0; i < sizeof name_pass; i++) + name_pass[i] = rand() >> 13; + v_strlcpy(name_pass, name, V_ENCRYPTION_LOGIN_KEY_SIZE / 2); + pass = v_con_get_pass(); + v_strlcpy(name_pass + V_ENCRYPTION_LOGIN_KEY_SIZE / 2, pass, V_ENCRYPTION_LOGIN_KEY_SIZE / 2); + /* Make sure last (MSB) byte is clear, to guarantee that data < key for RSA math. */ + name_pass[sizeof name_pass - 1] = 0; + key = v_con_get_other_key(); + v_e_connect_encrypt(encrypted_key, name_pass, &key[V_ENCRYPTION_LOGIN_PUBLIC_START], &key[V_ENCRYPTION_LOGIN_N_START]); + + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], encrypted_key[i]); + v_n_send_data(v_con_get_network_address(), buf, buffer_pos); +} + +static void v_send_hidden_connect_accept(void) /* Host accepts Clients connectionatempt and sends over data encryption key */ +{ + uint8 buf[1500], *client_key, encrypted[V_ENCRYPTION_DATA_KEY_SIZE]; + unsigned int i, buffer_pos = 0; + + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 1);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 1);/* Packing the command */ + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], verse_session_get_avatar()); + client_key = v_con_get_other_key(); + v_e_connect_encrypt(encrypted, v_con_get_data_key(), &client_key[V_ENCRYPTION_LOGIN_PUBLIC_START], &client_key[V_ENCRYPTION_LOGIN_N_START]); + for(i = 0; i < V_ENCRYPTION_DATA_KEY_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], encrypted[i]); + v_n_send_data(v_con_get_network_address(), buf, buffer_pos); +} + +static void v_send_hidden_connect_terminate(VNetworkAddress *address, unsigned int packet_id, const char *bye) /* Host accepts Clients connectionatempt and sends over data encryption key */ +{ + uint8 buf[1500]; + unsigned int buffer_pos = 0; + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], packet_id);/* Packing the packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 2);/* Packing the command */ + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], bye, 512); /* pack message */ + v_e_data_encrypt_command(buf, sizeof (uint32), buf + sizeof (uint32), buffer_pos, v_con_get_data_key()); + v_n_send_data(address, buf, buffer_pos); +} + +VSession verse_send_connect(const char *name, const char *pass, const char *address, const uint8 *expected_key) +{ + uint8 *my_key, *key = NULL; + unsigned int i; + VNetworkAddress a; + VSession *session; + if(v_n_set_network_address(&a, address)) + { +#if defined(V_PRINT_SEND_COMMANDS) + char ip_string[32]; +#endif + session = v_con_connect(a.ip, a.port, V_CS_CONTACT); +#if defined(V_PRINT_SEND_COMMANDS) + v_n_get_address_string(&a, ip_string); + printf("send: %p = verse_send_connect(name = %s, pass = %s, address = %s (%s), expected_key = %p)\n", session, name, pass, address, ip_string, expected_key); +#endif + v_con_set_name_pass(name, pass); + if(expected_key != NULL) + { + key = malloc((sizeof *key) * V_ENCRYPTION_LOGIN_KEY_HALF_SIZE); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_HALF_SIZE; i++) + key[i] = expected_key[i]; + *v_con_get_expected_key() = key; + } + my_key = v_con_get_my_key(); + v_e_connect_create_key(&my_key[V_ENCRYPTION_LOGIN_PRIVATE_START], &my_key[V_ENCRYPTION_LOGIN_PUBLIC_START], &my_key[V_ENCRYPTION_LOGIN_N_START]); + v_send_hidden_connect_contact(); + v_con_inqueue_timer_update(); /* Reset timer in connection's in queue, above takes a while. */ + return session; + } + else + { +#if defined(V_PRINT_SEND_COMMANDS) + printf("send: NULL = verse_send_connect(name = %s, pass = %s, address = %s (Unressolved DNS), key = %p);\n", name, pass, address, key); +#endif + return NULL; + } +} + +void v_update_connection_pending(boolean resend) +{ + VSession (* func_connect)(void *user_data, const char *name, const char *pass, const char *address, const uint8 *key) = NULL; + VSession (* func_connect_accept)(void *user_data, VNodeID avatar, char *address, uint8 *host_id); + void (* func_connect_terminate)(void *user_data, char *address, const char *bye); + char address_string[32]; + + switch(v_con_get_connect_stage()) + { + case V_CS_CONTACT : /* client tries to contact host */ + if(resend) + v_send_hidden_connect_contact(); + break; + case V_CS_CONTACTED : /* Host replies with challange */ + if(resend) + v_send_hidden_connect_send_key(); + break; + case V_CS_PENDING_ACCEPT : /* Client sends login */ + if(resend) + v_send_hidden_connect_login(); + break; + case V_CS_PENDING_HOST_CALLBACK : /* Host got login waits for accept connect callback */ + v_con_set_connect_stage(V_CS_PENDING_DECISION); + func_connect = v_fs_get_user_func(0); + v_n_get_address_string(v_con_get_network_address(), address_string); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: verse_send_connect(address = %s, name = %s, pass = %s, key = NULL); callback = %p\n", address_string, v_con_get_name(), v_con_get_pass(), func_connect); +#endif + if(func_connect != 0) + func_connect(v_fs_get_user_data(0), v_con_get_name(), v_con_get_pass(), address_string, NULL); + break; + case V_CS_PENDING_CLIENT_CALLBACK_ACCEPT : /* Host got login waits for accept connect callback */ + v_con_set_connect_stage(V_CS_CONNECTED); + func_connect_accept = v_fs_get_user_func(1); + v_n_get_address_string(v_con_get_network_address(), address_string); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: func_connect_accept(avatar = %u, address = %s, name = %s, pass = %s, key = NULL); callback = %p\n", + verse_session_get_avatar(), address_string, v_con_get_name(), v_con_get_pass(), func_connect); +#endif + if(func_connect_accept != 0) + func_connect_accept(v_fs_get_user_data(1), verse_session_get_avatar(), address_string, NULL); + break; + case V_CS_PENDING_CLIENT_CALLBACK_TERMINATE : /* Host got login waits for accept connect callback */ + v_con_set_connect_stage(V_CS_CONNECTED); + func_connect_terminate = v_fs_get_user_func(2); + v_n_get_address_string(v_con_get_network_address(), address_string); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: func_connect_terminate(address = %s, bye = %s); callback = %p\n", address_string, "no message", func_connect); +#endif + if(func_connect_terminate != 0) + func_connect_terminate(v_fs_get_user_data(2), address_string, "no message"); + break; + default: + ; + } +} + +void v_unpack_connection(const char *buf, unsigned int buffer_length) /* un packing all stages of connect command */ +{ + unsigned int buffer_pos, i, pack_id; + uint32 seconds, fractions, pre; + uint8 /*key[V_ENCRYPTION_LOGIN_KEY_SIZE], */stage, cmd_id, version; + + if(buffer_length < 5) + return; + + buffer_pos = vnp_raw_unpack_uint32(buf, &pack_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &cmd_id); + pre = v_con_get_connect_stage(); + if(cmd_id == 0) + { + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &stage); + printf(" Handling connection, stage %u\n", stage); + if(stage == V_CS_IDLE && V_CS_IDLE == v_con_get_connect_stage()) /* reseved by host */ + { + uint8 *other_key, *my_key; + + verse_send_packet_ack(pack_id); + my_key = v_con_get_my_key(); + v_con_set_data_key(v_e_data_create_key()); + other_key = v_con_get_other_key(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &other_key[V_ENCRYPTION_LOGIN_PUBLIC_START + i]);/* Packing the command */ + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &other_key[V_ENCRYPTION_LOGIN_N_START + i]);/* Packing the command */ + v_con_set_connect_stage(V_CS_CONTACTED); + v_send_hidden_connect_send_key(); + return; + } + if(stage == V_CS_CONTACT && V_CS_CONTACT == v_con_get_connect_stage()) + { + uint8 *other_key; /* *host_id, *my_key, a[V_ENCRYPTION_LOGIN_KEY_SIZE], b[V_ENCRYPTION_LOGIN_KEY_SIZE];*/ + verse_send_packet_ack(pack_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &version); + if(version != V_RELEASE_NUMBER) + { + /* char error_message[128]; + func_connect_deny = v_fs_get_user_func(2); + #if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: verse_send_connect_deny(Host is running version %u you are running version %u); callback = %p\n", (uint32)version, (uint32)V_RELEASE_NUMBER func_connect_deny); + #endif + if(func_connect_deny != NULL) + { + sprintf(error_message, "Host is running version %u you are running version %u", (uint32)version, (uint32)V_RELEASE_NUMBER); + func_connect_deny(v_fs_get_user_data(2), error_message); + }*/ + return; + } + + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &seconds); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &fractions); + v_con_set_time(seconds, fractions); + + other_key = v_con_get_other_key(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &other_key[V_ENCRYPTION_LOGIN_PUBLIC_START + i]); + for(i = 0; i < V_ENCRYPTION_DATA_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &other_key[V_ENCRYPTION_LOGIN_N_START + i]); + + v_con_set_connect_stage(V_CS_PENDING_ACCEPT); + v_send_hidden_connect_login(); + return; + } +#if 0 + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_HALF_SIZE && encrypted_key[i] == 0; i++); + if(i < 0) + { + other_key = v_con_get_my_key(); + v_e_connect_encrypt(decrypted_key, encrypted_key, &other_key[V_ENCRYPTION_LOGIN_PUBLIC_START + i], &other_key[V_ENCRYPTION_LOGIN_N_START + i]); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_HALF_SIZE && my_key[V_ENCRYPTION_LOGIN_PUBLIC_START + i] == decrypted_key[i]; i++); + if(i < 0) /* Host is not who it appers top be */ + { + func_connect_deny = v_fs_get_user_func(2); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: verse_send_connect_deny(Host failed identity check); callback = %p\n", func_connect_deny); +#endif + if(func_connect_deny != NULL) + func_connect_deny(v_fs_get_user_data(2), "Host failed identity check"); + return; + } + } +#endif + if(stage == V_CS_CONTACTED && V_CS_CONTACTED == v_con_get_connect_stage()) /* reseved by host */ + { + char *host_id, unpack[V_ENCRYPTION_LOGIN_KEY_SIZE], data[V_ENCRYPTION_LOGIN_KEY_SIZE]; + VNetworkAddress *address; + verse_send_packet_ack(pack_id); + address = v_con_get_network_address(); + for(i = 0; i < V_ENCRYPTION_LOGIN_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &data[i]); + host_id = v_con_get_host_id(); + v_e_connect_encrypt(unpack, data, &host_id[V_ENCRYPTION_LOGIN_PRIVATE_START], &host_id[V_ENCRYPTION_LOGIN_N_START]); + v_con_set_name_pass(unpack, &unpack[V_ENCRYPTION_LOGIN_KEY_SIZE / 2]); + v_con_set_connect_stage(V_CS_PENDING_HOST_CALLBACK); + return; + } + } + if(cmd_id == 1 && V_CS_PENDING_ACCEPT == v_con_get_connect_stage()) /* reseved by client */ + { + uint8 *my_key, key[V_ENCRYPTION_DATA_KEY_SIZE], decrypted[V_ENCRYPTION_DATA_KEY_SIZE]; + uint32 avatar; + verse_send_packet_ack(pack_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &avatar); + v_con_set_avatar(avatar); + for(i = 0; i < V_ENCRYPTION_DATA_KEY_SIZE; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &key[i]); + my_key = v_con_get_my_key(); + v_e_connect_encrypt(decrypted, key, &my_key[V_ENCRYPTION_LOGIN_PRIVATE_START], &my_key[V_ENCRYPTION_LOGIN_N_START]); + v_con_set_data_key(decrypted); + v_con_set_connect_stage(V_CS_PENDING_CLIENT_CALLBACK_ACCEPT); + v_send_hidden_connect_send_key(); + return; + } + if(cmd_id == 2 && V_CS_PENDING_ACCEPT == v_con_get_connect_stage()) /* reseved by client */ + { + verse_send_packet_ack(pack_id); + /* buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 512, buffer_length - buffer_pos); + */ v_con_set_connect_stage(V_CS_PENDING_CLIENT_CALLBACK_TERMINATE); + return; + } +} + +VSession verse_send_connect_accept(VNodeID avatar, const char *address, uint8 *host_id) +{ + VNetworkAddress a; +#if defined(V_PRINT_SEND_COMMANDS) + printf("send: verse_send_connect_accept(avatar = %u, address = %s, host_id = NULL);\n", avatar, address); +#endif + + if(!v_n_set_network_address(&a, address)) + return NULL; + if(v_co_switch_connection(a.ip, a.port)) + { + if(v_con_get_connect_stage() != V_CS_PENDING_DECISION) + return NULL; + v_con_set_avatar(avatar); + v_con_set_connect_stage(V_CS_CONNECTED); + v_send_hidden_connect_accept(); + return v_con_get_network_queue(); + } + return NULL; +} + +void v_callback_connect_terminate(const char *bye) +{ + void (* func_connect_terminate)(void *user_data, char *address, const char *bye); + char address_string[32]; + + printf("terminate (%s)\n", bye); + func_connect_terminate = v_fs_get_user_func(2); + v_n_get_address_string(v_con_get_network_address(), address_string); +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("receive: verse_send_connect_terminate(address = %s, bye = %s); callback = %p\n", address_string, bye, func_connect_terminate); +#endif + if(func_connect_terminate != 0) + func_connect_terminate(v_fs_get_user_data(2), address_string, bye); +} + +void verse_send_connect_terminate(const char *address, const char *bye) +{ + VNetworkAddress a; +#if defined(V_PRINT_RECEIVE_COMMANDS) + printf("send: verse_send_connect_terminate(address = %s, bye = %s);\n", address, bye); +#endif + + if(address == NULL) + v_send_hidden_connect_terminate(v_con_get_network_address(), v_noq_get_next_out_packet_id(v_con_get_network_queue()), bye); + else if(!v_n_set_network_address(&a, address)) + return; + else if(v_co_switch_connection(a.ip, a.port)) + v_send_hidden_connect_terminate(v_con_get_network_address(), v_noq_get_next_out_packet_id(v_con_get_network_queue()), bye); + + if(v_con_get_connect_stage() != V_CS_PENDING_DECISION) + verse_session_destroy(v_con_get_network_queue()); +} + +void verse_send_ping(const char *address, const char *message) +{ + VNetworkAddress a; + if(v_n_set_network_address(&a, address)) + { + unsigned int buffer_pos = 0; + uint8 buf[1500]; + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], 0);/* Packing the Packet id */ + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 5);/* Packing the command */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_ping(address = %s text = %s);\n", address, message); +#endif + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], message, 1400); + v_n_send_data(&a, buf, buffer_pos); + } +#if defined V_PRINT_SEND_COMMANDS + else + printf("send: verse_send_ping(address = %s (FAULTY) message = %s);\n", address, message); +#endif +} + +unsigned int v_unpack_ping(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_ping)(void *user_data, const char *address, const char *text); + char address[64]; + char message[1400]; + + func_ping = v_fs_get_user_func(5); + v_n_get_address_string(v_con_get_network_address(), address); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], message, 1400, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_ping(address = %s message = %s ); callback = %p\n", address, message, v_fs_get_user_func(5)); +#endif + if(func_ping != NULL) + func_ping(v_fs_get_user_data(5), address, message); + return buffer_pos; +} + +typedef struct { + uint32 ip; + uint16 port; + char message[1400]; + void *next; +} VPingCommand; + +static VPingCommand *v_ping_commands = NULL; + +boolean v_connect_unpack_ping(const char *buf, size_t buffer_length, uint32 ip, uint16 port) +{ + if(buffer_length > 5) + { + unsigned int buffer_pos = 0; + uint8 cmd_id; + uint32 pack_id; + + buffer_pos = vnp_raw_unpack_uint32(&buf[buffer_pos], &pack_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &cmd_id); + if(cmd_id == 5) + { + if(NULL != v_fs_get_user_func(5)) + { + VPingCommand *pc; + + pc = malloc(sizeof *pc); + pc->ip = ip; + pc->port = port; + vnp_raw_unpack_string(&buf[buffer_pos], pc->message, + sizeof pc->message, buffer_length - buffer_pos); + pc->next = v_ping_commands; + v_ping_commands = pc; + } + return TRUE; + } + } + return FALSE; +} + +void v_ping_update(void) +{ + VPingCommand *cp; + void (* func_ping)(void *user_data, const char *address, const char *text); + VNetworkAddress a; + char address[64]; + func_ping = v_fs_get_user_func(5); + + while(v_ping_commands != NULL) + { + cp = v_ping_commands->next; + a.ip = v_ping_commands->ip; + a.port = v_ping_commands->port; + v_n_get_address_string(&a, address); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_ping(address = %s message = %s ); callback = %p\n", address, v_ping_commands->message, v_fs_get_user_func(5)); +#endif + if(func_ping != NULL) + func_ping(v_fs_get_user_data(5), address, v_ping_commands->message); + free(v_ping_commands); + v_ping_commands = cp; + } +} + +#endif diff --git a/extern/verse/dist/v_connection.c b/extern/verse/dist/v_connection.c new file mode 100644 index 00000000000..3bfafad5660 --- /dev/null +++ b/extern/verse/dist/v_connection.c @@ -0,0 +1,490 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_buf.h" +#include "v_network_in_que.h" +#include "v_network_out_que.h" +#include "v_cmd_gen.h" +#include "v_connection.h" +#include "v_encryption.h" +#include "v_util.h" + +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" + +#define CONNECTION_CHUNK_SIZE 16 +#define V_MAX_CONNECT_PACKET_SIZE 1500 +#define V_CON_MAX_MICROSECOND_BETWEEN_SENDS 100 +#define V_RE_CONNECTON_TIME_OUT 4 +#define V_CONNECTON_TIME_OUT 30 + +typedef struct { + VNetOutQueue *out_queue; + VNetInQueue in_queue; + VNetworkAddress network_address; + boolean connected; + unsigned int avatar; +/* unsigned int packet_id;*/ + int32 timedelta_s; + uint32 timedelta_f; + boolean destroy_flag; + void *ordered_storage; + char name[V_ENCRYPTION_LOGIN_KEY_SIZE / 2]; + char pass[V_ENCRYPTION_LOGIN_KEY_SIZE / 2]; + VConnectStage connect_stage; + unsigned int stage_atempts; + uint8 key_my[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE]; + uint8 key_other[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE]; + uint8 key_data[V_ENCRYPTION_DATA_KEY_SIZE]; + uint8 *expected_key; +} VConnection; + +static struct { + VConnection *con; + unsigned int con_count; + unsigned int current_connection; + VNetworkAddress *connect_address; + void *unified_func_storage; + uint16 connect_port; + unsigned int pending_packets; + uint8 host_id[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE]; +} VConData; + +extern void cmd_buf_init(void); + +void v_con_init(void) /* since verse doesnt have an init function this function is runned over an ove ard starts whit a check it it has run before */ +{ + static boolean v_con_initialized = FALSE; + + if(v_con_initialized) + return; + cmd_buf_init(); + v_con_initialized = TRUE; + VConData.con = malloc(CONNECTION_CHUNK_SIZE * sizeof *VConData.con); + memset(VConData.con, 0, CONNECTION_CHUNK_SIZE * sizeof *VConData.con); /* Clear the memory. */ + VConData.con_count = 0; + VConData.pending_packets = 0; +/* v_e_connect_create_key(&VConData.host_id[V_ENCRYPTION_LOGIN_PRIVATE_START], + &VConData.host_id[V_ENCRYPTION_LOGIN_PUBLIC_START], + &VConData.host_id[V_ENCRYPTION_LOGIN_N_START]);*/ /* default host id if none is set by user */ +} + +void verse_set_port(uint16 port) +{ + v_n_set_port(port); +} + +void verse_host_id_create(uint8 *id) +{ + v_e_connect_create_key(&id[V_ENCRYPTION_LOGIN_PRIVATE_START], + &id[V_ENCRYPTION_LOGIN_PUBLIC_START], &id[V_ENCRYPTION_LOGIN_N_START]); +} + +void verse_host_id_set(uint8 *id) +{ + memcpy(VConData.host_id, id, V_ENCRYPTION_LOGIN_KEY_FULL_SIZE); +} + +extern void *v_fs_create_func_storage(void); +extern void *v_create_ordered_storage(void); +extern void v_destroy_ordered_storage(void *data); + +void *v_con_connect(uint32 ip, uint16 port, VConnectStage stage) /* creates a new connection slot */ +{ + v_con_init(); /* init connections, if not done yet */ + if((VConData.con_count - 1) % CONNECTION_CHUNK_SIZE == 0) /* do we need more slots for connections, then reallocate more space */ + VConData.con = realloc(VConData.con, (sizeof *VConData.con) * (VConData.con_count + CONNECTION_CHUNK_SIZE)); + VConData.con[VConData.con_count].out_queue = v_noq_create_network_queue(); /* create a out queue fo all out going commands */ + v_niq_clear(&VConData.con[VConData.con_count].in_queue); /* clear and init the que of incomming packets.*/ + VConData.con[VConData.con_count].connected = FALSE; /* not yet propperly connected and should not accept commands yet */ + VConData.con[VConData.con_count].network_address.ip = ip; /* ip address of other side */ + VConData.con[VConData.con_count].network_address.port = port; /* port used by other side */ + VConData.con[VConData.con_count].avatar = 0; /* no avatar set yet*/ +/* VConData.con[VConData.con_count].packet_id = 2;*/ + VConData.con[VConData.con_count].destroy_flag = FALSE; /* this is a flag that is set once the connection is about to be destroyed.*/ + VConData.con[VConData.con_count].ordered_storage = v_create_ordered_storage(); + VConData.con[VConData.con_count].name[0] = 0; /* nouser name set yet */ + VConData.con[VConData.con_count].pass[0] = 0; /* no password set yet */ + VConData.con[VConData.con_count].connect_stage = stage; /* this is the stage of the connection, it show if the connection is ready, the init state depends if this is a client or host */ + VConData.con[VConData.con_count].stage_atempts = 0; /* each stage in the connection prosess is atempted multiple times to avoid failiure if packets get lost*/ + VConData.con[VConData.con_count].timedelta_s = 0; /* number of seconds since last incomming packet to the connection*/ + VConData.con[VConData.con_count].timedelta_f = 0; /* number of fractions of a second since last incomming packet to the connection*/ + VConData.con[VConData.con_count].expected_key = NULL; /* expected hist id if this is a client */ + VConData.current_connection = VConData.con_count; /* set the new connection to the current*/ + ++VConData.con_count; /* add one to the number of connections*/ + return VConData.con[VConData.current_connection].out_queue; +} + +void verse_session_destroy(VSession session) /* a session can not be destroyed right away, because this function might be called inside a call back from the session it tryes tpo destroy, therfor it only markes it*/ +{ + unsigned int i; + for(i = 0; i < VConData.con_count && VConData.con[i].out_queue != session; i++); + if(i < VConData.con_count) + { + VConData.con[i].destroy_flag = TRUE; + } +} + +void verse_session_set(VSession session) /* find a session and make it the current*/ +{ + unsigned int i; + for(i = 0; i < VConData.con_count && session != VConData.con[i].out_queue; i++); + if(i < VConData.con_count) + VConData.current_connection = i; +} + +VSession verse_session_get(void) +{ + if(VConData.current_connection < VConData.con_count) + return VConData.con[VConData.current_connection].out_queue; + return NULL; +} + +uint32 v_co_find_connection(uint32 ip, uint16 port) /* if a packet comes form a ip address what connection does it belong to? */ +{ + unsigned int i; + + for(i = 0; i < VConData.con_count; i++) + { + if(ip == VConData.con[i].network_address.ip && + port == VConData.con[i].network_address.port && + VConData.con[i].destroy_flag == 0) + { + return i; + } + } + return -1; +} + +boolean v_co_switch_connection(uint32 ip, uint16 port) /* switches to the current connection to one ip address if it exists */ +{ + unsigned int i; + for(i = 0; i < VConData.con_count; i++) + { + if(ip == VConData.con[i].network_address.ip && port == VConData.con[i].network_address.port) + { + VConData.current_connection = i; + return TRUE; + } + } + return FALSE; +} + +void v_con_inqueue_timer_update(void) +{ + if(VConData.current_connection < VConData.con_count) + { + v_niq_timer_update(&VConData.con[VConData.current_connection].in_queue); + } +} + +/* +extern void v_fs_buf_unpack(const uint8 *data, unsigned int length); +extern void v_fs_buf_store_pack(uint8 *data, unsigned int length); +extern boolean v_fs_buf_unpack_stored(void); +*/ +extern void v_unpack_connection(const char *buf, unsigned int buffer_length); + +extern void verse_send_packet_nak(uint32 packet_id); +extern void v_callback_connect_terminate(const char *bye); +extern boolean v_connect_unpack_ping(const char *buf, size_t buffer_length, uint32 ip, uint16 port); +extern void v_ping_update(void); +void v_fs_unpack_beginning(uint8 *data, unsigned int length); + +/* Main function that receives and distributes all incoming packets. */ +boolean v_con_network_listen(void) +{ + VNetworkAddress address; + uint8 buf[V_MAX_CONNECT_PACKET_SIZE], *store; + int size = 0; + unsigned int connection; + uint32 packet_id; + boolean ret = FALSE; + + v_con_init(); /* Init if needed. */ + connection = VConData.current_connection; /* Store current connection in a local variable so that we can restore it later. */ + size = v_n_receive_data(&address, buf, sizeof buf); /* Ask for incoming data from the network. */ + while(size != -1 && size != 0) /* Did we get any data? */ + { + VConData.current_connection = v_co_find_connection(address.ip, address.port); /* Is there a connection matching the IP and port? */ + vnp_raw_unpack_uint32(buf, &packet_id); /* Unpack the ID of the packet. */ +/* printf("got packet ID %u, %d bytes, connection %u\n", packet_id, size, VConData.current_connection);*/ + if(VConData.current_connection < VConData.con_count && + !(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED && packet_id == 0)) /* If this isn't a packet from an existing connection, disregard it. */ + { + if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) /* Is this connection initialized? */ + { + store = v_niq_store(&VConData.con[VConData.current_connection].in_queue, size, packet_id); /* Store the packet. */ + if(store != NULL) + { + VConData.pending_packets++; /* We now have one more packet pending unpack. */ + v_e_data_decrypt_packet(store, buf, size, VConData.con[VConData.current_connection].key_data); /* Decrypt the packet. */ + v_fs_unpack_beginning(store, size); + } + } + else + { + v_unpack_connection(buf, size); /* This is an ongoing connecton-attempt. */ + v_niq_timer_update(&VConData.con[VConData.current_connection].in_queue); + } + } + else if(v_connect_unpack_ping(buf, size, address.ip, address.port)) /* Ping handled. */ + ; + else if(v_fs_func_accept_connections()) /* Do we accept connection-attempts? */ + { + if(VConData.current_connection >= VConData.con_count || + V_RE_CONNECTON_TIME_OUT < v_niq_time_out(&VConData.con[VConData.current_connection].in_queue)) /* Is it a new client, or an old client that we haven't heard form in some time? */ + { + if(VConData.current_connection < VConData.con_count) + { + VConData.con[VConData.current_connection].network_address.ip = 0; + VConData.con[VConData.current_connection].destroy_flag = TRUE; /* Destroy old connection if there is one. */ + } + v_con_connect(address.ip, address.port, V_CS_IDLE); /* Create a new connection. */ + v_unpack_connection(buf, size); /* Unpack the connection-attempt. */ + } + } + else + { + fprintf(stderr, __FILE__ ": Unhandled packet--dropping\n"); + if(VConData.con_count > 0) + { + fprintf(stderr, __FILE__ ": State: connections=%u, current=%u (stage %u), packet_id=%u\n", + VConData.con_count, + VConData.current_connection, + (VConData.current_connection < VConData.con_count) ? VConData.con[VConData.current_connection].connect_stage : 0, + packet_id); + } + } + size = v_n_receive_data(&address, buf, sizeof buf); /* See if there are more incoming packets. */ + ret = TRUE; + } + VConData.current_connection = connection; /* Reset the current connection. */ + + return ret; +} + +extern void v_update_connection_pending(boolean resend); + +boolean v_con_callback_update(void) +{ + static unsigned int seconds; + boolean output = FALSE; + size_t size; + unsigned int connection, s; + VNetInPacked *p; + + v_n_get_current_time(&s, NULL); + connection = VConData.current_connection; + for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++) + if(VConData.con[VConData.current_connection].connect_stage != V_CS_CONNECTED) + v_update_connection_pending(s != seconds); + seconds = s; + VConData.current_connection = connection; + if(VConData.pending_packets == 0) + return FALSE; + if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) + { + while((p = v_niq_get(&VConData.con[VConData.current_connection].in_queue, &size)) != NULL) + { + VConData.pending_packets--; + v_fs_unpack(p->data, size); + v_niq_release(&VConData.con[VConData.current_connection].in_queue, p); + output = TRUE; + } + v_con_network_listen(); + } + return output; +} + +void verse_callback_update(unsigned int microseconds) +{ + unsigned int connection, passed; + + v_ping_update(); /* Deliver any pending pings. */ + connection = VConData.current_connection; + for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++) + { + if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) + v_noq_send_queue(VConData.con[VConData.current_connection].out_queue, &VConData.con[VConData.current_connection].network_address); + if(VConData.con[VConData.current_connection].destroy_flag == TRUE) + { + v_noq_destroy_network_queue(VConData.con[VConData.current_connection].out_queue); + VConData.pending_packets -= v_niq_free(&VConData.con[VConData.current_connection].in_queue); + v_destroy_ordered_storage(VConData.con[VConData.current_connection].ordered_storage); + if(VConData.con[VConData.current_connection].expected_key != NULL) + free(VConData.con[VConData.current_connection].expected_key); + if(VConData.con_count - 1 != VConData.current_connection) + VConData.con[VConData.current_connection] = VConData.con[VConData.con_count - 1]; + VConData.con_count--; + if(connection >= VConData.con_count) + VConData.current_connection = 0; + return; + } + } + VConData.current_connection = connection; + + if(VConData.con_count > 0) + { +/* printf("checking timeout of stage %d connection %u\n", + VConData.con[VConData.current_connection].connect_stage, VConData.current_connection); +*/ if(V_CONNECTON_TIME_OUT < v_niq_time_out(&VConData.con[VConData.current_connection].in_queue)) + { + if(VConData.con[VConData.current_connection].connect_stage != V_CS_CONNECTED) + { + VConData.con[VConData.current_connection].destroy_flag = TRUE; + } + else + v_callback_connect_terminate("connection timed out"); + } + } + + v_con_network_listen(); + if(VConData.con_count > 0) + if(v_con_callback_update()) + return; + for(passed = 0; passed < microseconds && VConData.pending_packets == 0;) + { + boolean update; + if(microseconds - passed > V_CON_MAX_MICROSECOND_BETWEEN_SENDS) /* Still a long way to go? */ + passed += v_n_wait_for_incoming(V_CON_MAX_MICROSECOND_BETWEEN_SENDS); + else + passed += v_n_wait_for_incoming(microseconds - passed); + do + { + update = v_con_network_listen(); + connection = VConData.current_connection; + for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++) + { + if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) + { + if(v_noq_send_queue(VConData.con[VConData.current_connection].out_queue, &VConData.con[VConData.current_connection].network_address)) + update = TRUE; + } + } + VConData.current_connection = connection; + } while(update); + } + if(VConData.con_count > 0) + v_con_callback_update(); +} + +void v_con_set_name_pass(const char *name, const char *pass) +{ + v_strlcpy(VConData.con[VConData.current_connection].name, name, sizeof VConData.con[VConData.current_connection].name); + v_strlcpy(VConData.con[VConData.current_connection].pass, pass, sizeof VConData.con[VConData.current_connection].pass); +} + +const char * v_con_get_name(void) +{ + return VConData.con[VConData.current_connection].name; +} + +const char * v_con_get_pass(void) +{ + return VConData.con[VConData.current_connection].pass; +} + +void v_con_set_connect_stage(VConnectStage stage) +{ + VConData.con[VConData.current_connection].connect_stage = stage; + VConData.con[VConData.current_connection].stage_atempts = 0; +} + +VConnectStage v_con_get_connect_stage(void) +{ + return VConData.con[VConData.current_connection].connect_stage; +} + +uint8 *v_con_get_my_key(void) +{ + return VConData.con[VConData.current_connection].key_my; +} + +uint8 *v_con_get_other_key(void) +{ + return VConData.con[VConData.current_connection].key_other; +} + +uint8 **v_con_get_expected_key(void) +{ + return &VConData.con[VConData.current_connection].expected_key; +} + +uint8 * v_con_get_host_id(void) +{ + return VConData.host_id; +} + +void v_con_set_data_key(const uint8 *key) +{ + memcpy(VConData.con[VConData.current_connection].key_data, key, V_ENCRYPTION_DATA_KEY_SIZE); +} + +const uint8 * v_con_get_data_key(void) +{ + return VConData.con[VConData.current_connection].key_data; +} + +void * v_con_get_network_queue(void) +{ + return VConData.con[VConData.current_connection].out_queue; +} + +VNetworkAddress * v_con_get_network_address(void) +{ + return &VConData.con[VConData.current_connection].network_address; +} + +void * v_con_get_ordered_storage(void) +{ + return VConData.con[VConData.current_connection].ordered_storage; +} + +void v_con_set_avatar(uint32 avatar) +{ + VConData.con[VConData.current_connection].avatar = avatar; +} + +uint32 verse_session_get_avatar(void) +{ + return VConData.con[VConData.current_connection].avatar; +} + +void verse_session_get_time(uint32 *seconds, uint32 *fractions) +{ + uint32 s, f; + v_n_get_current_time(&s, &f); + if((uint32)~0 - f < VConData.con[VConData.current_connection].timedelta_f) + s++; + if(seconds != NULL) + { + if(VConData.con[VConData.current_connection].timedelta_s < 0) + *seconds = s - (uint32)(-VConData.con[VConData.current_connection].timedelta_s); + else + *seconds = s + VConData.con[VConData.current_connection].timedelta_s; + } + if(fractions != NULL) + *fractions = f + VConData.con[VConData.current_connection].timedelta_f; +} + +void v_con_set_time(uint32 seconds, uint32 fractions) +{ + uint32 s, f; + v_n_get_current_time(&s, &f); + + if(f < fractions) + s--; + if (s < seconds) + VConData.con[VConData.current_connection].timedelta_s = -(int)(seconds - s); + else + VConData.con[VConData.current_connection].timedelta_s = (int)(s - seconds); + VConData.con[VConData.current_connection].timedelta_f = f - fractions; +} + +#endif diff --git a/extern/verse/dist/v_connection.h b/extern/verse/dist/v_connection.h new file mode 100644 index 00000000000..1d2ac53d597 --- /dev/null +++ b/extern/verse/dist/v_connection.h @@ -0,0 +1,73 @@ +/* +** +*/ + +#include "v_network.h" + +typedef struct{ + char name[16]; + char pass[16]; + uint8 key; + VNodeID avatar; +}VSConnectionID; + +typedef enum{ + V_CS_IDLE = 0, /* Host connection waiting for connection */ + V_CS_CONTACT = 1, /* client tryes to contact host */ + V_CS_CONTACTED = 2, /* Host replyes whit challange */ + V_CS_PENDING_ACCEPT = 3, /* Client sends login */ + V_CS_PENDING_HOST_CALLBACK = 4, /* Host got login waits for accept connect callback */ + V_CS_PENDING_CLIENT_CALLBACK_ACCEPT = 5, /* Host got login waits for accept connect callback */ + V_CS_PENDING_CLIENT_CALLBACK_TERMINATE = 6, /* Host got login waits for connect terminate callback */ + V_CS_PENDING_DECISION = 7, /* Host got has executed Callback waits for accept command */ + V_CS_CONNECTED = 8 /* Connection establiched */ +}VConnectStage; + +/* Connection related functions (v_connection.c) */ + +extern boolean v_con_network_listen(void); + +extern void v_con_set_name_pass(const char *name, const char *pass); +extern const char * v_con_get_name(void); +extern const char * v_con_get_pass(void); + +extern void v_con_set_avatar(uint32 avatar); +extern void v_con_set_time(uint32 seconds, uint32 fractions); + +extern void v_con_set_connect_stage(VConnectStage stage); +extern VConnectStage v_con_get_connect_stage(void); + + +extern uint8 *v_con_get_my_key(void); +extern uint8 *v_con_get_other_key(void); +extern uint8 *v_con_get_host_id(void); +extern uint8 **v_con_get_expected_key(void); + +extern void v_con_set_data_key(const uint8 *key); +extern const uint8 * v_con_get_data_key(void); + + +extern void * v_con_get_network_queue(void); +extern VNetworkAddress *v_con_get_network_address(void); +extern void * v_con_get_network_address_id(unsigned int id); +extern unsigned int * v_con_get_network_expected_packet(void); +extern void * v_con_get_ordered_storage(void); +extern void * v_con_get_func_storage(void); +extern void * v_con_connect(uint32 ip, uint16 port, VConnectStage stage); +extern unsigned int v_con_get_network_address_count(void); + +extern boolean v_co_switch_connection(uint32 ip, uint16 port); + +extern void v_con_inqueue_timer_update(void); + + +/* Func storage related functions (v_func_storage.c)*/ +extern void v_fs_unpack(uint8 *data, unsigned int length); + +extern boolean v_fs_func_accept_connections(void); +extern void v_fs_add_func(unsigned int cmd_id, unsigned int (*unpack_func)(const char *buf, size_t buffer_length), void *pack_func, void *alias_func); + +extern void * v_fs_get_alias_user_func(unsigned int cmd_id); +extern void * v_fs_get_alias_user_data(unsigned int cmd_id); +extern void * v_fs_get_user_func(unsigned int cmd_id); +extern void * v_fs_get_user_data(unsigned int cmd_id); diff --git a/extern/verse/dist/v_encryption.c b/extern/verse/dist/v_encryption.c new file mode 100644 index 00000000000..aea0f8e6979 --- /dev/null +++ b/extern/verse/dist/v_encryption.c @@ -0,0 +1,255 @@ +/* + * Verse encryption routines. Implements RSA encryption/decryption plus fast XORx. +*/ + +#if !defined(V_GENERATE_FUNC_MODE) + +#include +#include +#include + +#include "verse.h" +#include "v_pack.h" +#include "v_bignum.h" +#include "v_encryption.h" + +#define BITS V_ENCRYPTION_LOGIN_KEY_BITS /* Save some typing. */ + +extern void v_prime_set_random(VBigDig *x); +extern void v_prime_set_table(VBigDig *x, int i); + +const uint8 * v_e_data_create_key(void) /* possibly the worst key gen ever */ +{ + static unsigned int counter = 0; + static uint8 buffer[V_ENCRYPTION_DATA_KEY_SIZE]; + unsigned int i, temp; + + for(i = 0; i < V_ENCRYPTION_DATA_KEY_SIZE; i++) + { + counter++; + temp = (counter << 13) ^ counter; + temp = (temp * (temp * temp * 15731 + 789221) + 1376312589) & 0x7fffffff; + buffer[i] = temp; + } + /* FIXME: This really isn't very pretty. */ + buffer[0] &= 0x3f; /* Make sure top word is... Low. For RSA compatibility. */ + +/* memset(buffer, 0, sizeof buffer); + fprintf(stderr, "**WARNING: XOR data encryption disabled\n"); +*/ + return buffer; +} + +void v_e_data_encrypt_command(uint8 *packet, size_t packet_size, const uint8 *command, size_t command_size, const uint8 *key) +{ + uint32 pos, i; + + vnp_raw_unpack_uint32(packet, &pos); +/* printf("encrypting packet %u", pos);*/ + pos = key[pos % V_ENCRYPTION_DATA_KEY_SIZE] + packet_size; +/* printf(" -> pos=%u (size %u)", pos, packet_size); + printf(", key begins: ["); + for(i = 0; i < 16; i++) + printf(" %02X", key[(pos + i) % V_ENCRYPTION_DATA_KEY_SIZE]); + printf(" ]\n"); +*/ + for(i = 0; i < command_size; i++) + packet[packet_size + i] = command[i] ^ key[(i + pos) % V_ENCRYPTION_DATA_KEY_SIZE]; +} + +void v_e_data_decrypt_packet(uint8 *to, const uint8 *from, size_t size, const uint8 *key) +{ + uint32 pos, i; + + vnp_raw_unpack_uint32(from, &pos); +/* printf("decrypting packet %u", pos);*/ + pos = key[pos % V_ENCRYPTION_DATA_KEY_SIZE]; +/* printf(" -> pos=%u", pos); + printf(", key begins: ["); + for(i = 0; i < 16; i++) + printf(" %02X", key[(i + pos) % V_ENCRYPTION_DATA_KEY_SIZE]); + printf(" ]\n"); +*/ for(i = 0; i < 4; i++) + to[i] = from[i]; + for(i = 4; i < size; i++) + to[i] = from[i] ^ key[(i + pos) % V_ENCRYPTION_DATA_KEY_SIZE]; +} + +#endif + +/* From Knuth. Computes multiplicative inverse of u, modulo v. */ +void v_e_math_inv(VBigDig *inv, const VBigDig *u, const VBigDig *v) +{ + VBigDig VBIGNUM(u1, 2*BITS), VBIGNUM(u3, 2*BITS), VBIGNUM(v1, 2*BITS), VBIGNUM(v3, 2 *BITS), + VBIGNUM(t1, 2*BITS), VBIGNUM(t3, 2*BITS), VBIGNUM(q, 2*BITS), VBIGNUM(w, 2*BITS); + int iter = 1; + + v_bignum_set_one(u1); + v_bignum_set_bignum(u3, u); + v_bignum_set_zero(v1); + v_bignum_set_bignum(v3, v); + + while(!v_bignum_eq_zero(v3)) + { + v_bignum_set_bignum(q, u3); + v_bignum_div(q, v3, t3); + v_bignum_set_bignum(w, q); + v_bignum_mul(w, v1); + v_bignum_set_bignum(t1, u1); + v_bignum_add(t1, w); + + v_bignum_set_bignum(u1, v1); + v_bignum_set_bignum(v1, t1); + v_bignum_set_bignum(u3, v3); + v_bignum_set_bignum(v3, t3); + iter = -iter; + } + if(iter < 0) + { + v_bignum_set_bignum(inv, v); + v_bignum_sub(inv, u1); + } + else + v_bignum_set_bignum(inv, u1); +} + +void v_e_connect_create_key(uint8 *private_key, uint8 *public_key, uint8 *n) +{ + VBigDig VBIGNUM(p, BITS / 2), VBIGNUM(q, BITS / 2), VBIGNUM(qmo, BITS / 2), VBIGNUM(phi, BITS), + VBIGNUM(pub, BITS), VBIGNUM(priv, BITS), VBIGNUM(mod, BITS); + +#if !defined _WIN32 + /* FIXME: This is a security backdoor. Intent is simply to save time during testing. */ + if(getenv("VERSE_NORSA") != NULL) + { + printf("VERSE: Found the NORSA envvar, using constant keys\n"); + v_prime_set_table(p, 0); + v_prime_set_table(q, 1); + goto compute_phi; + } +#endif +/* printf("find prime p\n");*/ + v_prime_set_random(p); +/* printf("find prime q\n");*/ + v_prime_set_random(q); +compute_phi: +/* printf("done, computing key\n");*/ +/* printf("p="); + v_bignum_print_hex_lf(p); + printf("q="); + v_bignum_print_hex_lf(q); +*/ v_bignum_set_bignum(phi, p); + v_bignum_sub_digit(phi, 1); + v_bignum_set_bignum(qmo, q); + v_bignum_sub_digit(qmo, 1); + v_bignum_mul(phi, qmo); +/* printf("phi="); + v_bignum_print_hex_lf(phi); +*/ v_bignum_set_string_hex(pub, "0x10001"); + v_e_math_inv(priv, pub, phi); +/* printf(" pub="); + v_bignum_print_hex_lf(pub); + printf("priv="); + v_bignum_print_hex_lf(priv); +*/ + v_bignum_set_bignum(mod, p); + v_bignum_mul(mod, q); +/* printf(" mod="); + v_bignum_print_hex_lf(mod); + printf("key-creation finished\n"); +*/ /* Write out the keys. */ + v_bignum_raw_export(pub, public_key); + v_bignum_raw_export(priv, private_key); + v_bignum_raw_export(mod, n); +} + +void v_e_connect_encrypt(uint8 *output, const uint8 *data, const uint8 *key, const uint8 *key_n) +{ + VBigDig VBIGNUM(packet, BITS), VBIGNUM(expo, BITS), VBIGNUM(mod, BITS); + + v_bignum_raw_import(packet, data); + v_bignum_raw_import(expo, key); + v_bignum_raw_import(mod, key_n); + + /* Verify that data is less than the modulo, this is a prerequisite for encryption. */ + if(!v_bignum_gte(mod, packet)) + { + printf("*** WARNING. Data is not less than modulo, as it should be--encryption will break!\n"); + printf(" RSA modulo: "); + v_bignum_print_hex_lf(mod); + printf(" RSA data: "); + v_bignum_print_hex_lf(packet); + } +/* printf("RSA key: "); + v_bignum_print_hex_lf(expo); + printf("RSA mod: "); + v_bignum_print_hex_lf(mod); + printf("RSA in: "); + v_bignum_print_hex_lf(packet); + printf("bits in packet: %d, ", v_bignum_bit_msb(packet) + 1); + printf("bits in modulo: %d\n", v_bignum_bit_msb(mod) + 1); +*/ v_bignum_pow_mod(packet, expo, mod); /* Blam. */ +/* printf("RSA out: "); + v_bignum_print_hex_lf(packet); +*/ v_bignum_raw_export(packet, output); +} + +#if defined CRYPTALONE +void v_encrypt_test(void) +{ + uint8 k_priv[BITS / 8], k_pub[BITS / 8], k_n[BITS / 8], cipher[BITS / 8], plain[BITS / 8], decode[BITS / 8], i; + + printf("testing RSA-crypto\n"); + v_e_connect_create_key(k_pub, k_priv, k_n); +/* exit(0);*/ + printf("key pair generated, encrypting something\n"); + memset(plain, 0, sizeof plain); + strcpy(plain, "This is some text to encrypt, to give it something to chew on."); + printf("plain: %02X (%u)\n", plain[0], strlen(plain)); + v_e_connect_encrypt(cipher, plain, k_pub, k_n); + printf("plain: %02X, cipher: %02X\n", plain[0], cipher[0]); + v_e_connect_encrypt(decode, cipher, k_priv, k_n); + printf("decoded: %02X: '", decode[0]); + for(i = 0; decode[i] != 0; i++) + putchar(decode[i]); + printf("'\n"); +/* printf("\npublic key: "); + v_bignum_print_hex_lf(k_public); + printf("private key: "); + v_bignum_print_hex_lf(k_private); + v_bignum_set_string(msg, "123"); + gettimeofday(&t1, NULL); + v_bignum_pow_mod(msg, k_private, k_n); + gettimeofday(&t2, NULL); + printf("encrypted: "); + v_bignum_print_hex_lf(msg); + printf("encrypted %u bits in %g s\n", BITS, t2.tv_sec - t1.tv_sec + 1.0E-6 * (t2.tv_usec - t1.tv_usec)); + + gettimeofday(&t1, NULL); + v_bignum_pow_mod(msg, k_public, k_n); + gettimeofday(&t2, NULL); + printf("decrypted: "); + v_bignum_print_hex_lf(msg); + printf("decrypted %u bits in %g s\n", BITS, t2.tv_sec - t1.tv_sec + 1.0E-6 * (t2.tv_usec - t1.tv_usec)); + exit(0); +*//* v_e_encrypt(cipher, plain, &k_private, &k_n); + printf("encrypted data: "); + for(i = 0; i < sizeof cipher; i++) + printf("%c", isalnum(cipher[i]) ? cipher[i] : '?'); + printf("\n\n"); + printf("decrypting\n"); + v_e_encrypt(decode, cipher, &k_public, &k_n); + printf("decrypted data: "); + for(i = 0; i < sizeof cipher; i++) + printf("%c", isalnum(decode[i]) ? decode[i] : '?'); + printf("\n\n"); +*/ +} + +int main(void) +{ + v_encrypt_test(); + + return 0; +} +#endif diff --git a/extern/verse/dist/v_encryption.h b/extern/verse/dist/v_encryption.h new file mode 100644 index 00000000000..cbfb5ff692f --- /dev/null +++ b/extern/verse/dist/v_encryption.h @@ -0,0 +1,32 @@ +/* + * Verse encryption routines. There are two distinct flavors of encryption + * in use: one "heavy" for login/connection establishment security, and + * a far lighter symmetrical one that is applied to each data packet after + * the key has been exchanged during connection. +*/ + +#include "verse.h" + +/* Internal key size definitions. *MUST* be kept in sync with V_HOST_ID_SIZE in verse_header.h! */ +#define V_ENCRYPTION_LOGIN_KEY_BITS 512 +#define V_ENCRYPTION_LOGIN_KEY_SIZE (V_ENCRYPTION_LOGIN_KEY_BITS / 8) +#define V_ENCRYPTION_LOGIN_KEY_FULL_SIZE (3 * V_ENCRYPTION_LOGIN_KEY_SIZE) +#define V_ENCRYPTION_LOGIN_KEY_HALF_SIZE (2 * V_ENCRYPTION_LOGIN_KEY_SIZE) + +#define V_ENCRYPTION_LOGIN_PUBLIC_START (0 * V_ENCRYPTION_LOGIN_KEY_SIZE) +#define V_ENCRYPTION_LOGIN_PRIVATE_START (1 * V_ENCRYPTION_LOGIN_KEY_SIZE) +#define V_ENCRYPTION_LOGIN_N_START (2 * V_ENCRYPTION_LOGIN_KEY_SIZE) + +#define V_ENCRYPTION_DATA_KEY_SIZE (V_ENCRYPTION_LOGIN_KEY_BITS / 8) + +/* Connection encryption. Heavy, and symmetrical, so encrypt() does both encryption + * and decryption given the proper key. Current algorithm used is RSA. +*/ +extern void v_e_connect_create_key(uint8 *private_key, uint8 *public_key, uint8 *n); +extern void v_e_connect_encrypt(uint8 *output, const uint8 *data, const uint8 *key, const uint8 *key_n); + +/* Actual data traffic encryption. Also symmetrical, with a single key. Uses XOR. */ +extern const uint8 * v_e_data_create_key(void); +extern void v_e_data_encrypt_command(uint8 *packet, size_t packet_length, + const uint8 *command, size_t command_length, const uint8 *key); +extern void v_e_data_decrypt_packet(uint8 *to, const uint8 *from, size_t size, const uint8 *key); diff --git a/extern/verse/dist/v_func_storage.c b/extern/verse/dist/v_func_storage.c new file mode 100644 index 00000000000..86c7815c2af --- /dev/null +++ b/extern/verse/dist/v_func_storage.c @@ -0,0 +1,194 @@ +/* + * +*/ + +#include +#include +#include "verse_header.h" +#include "v_pack.h" +#include "v_cmd_gen.h" +#include "v_connection.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" + +#define V_FS_MAX_CMDS 256 + +extern void init_pack_and_unpack(void); + +static struct { + unsigned int (*unpack_func[V_FS_MAX_CMDS])(const char *data, size_t length); + void *pack_func[V_FS_MAX_CMDS]; + void *user_func[V_FS_MAX_CMDS]; + void *user_data[V_FS_MAX_CMDS]; + void *alias_pack_func[V_FS_MAX_CMDS]; + void *alias_user_func[V_FS_MAX_CMDS]; + void *alias_user_data[V_FS_MAX_CMDS]; + boolean call; +} VCmdData; + +static boolean v_fs_initialized = FALSE; + +extern void verse_send_packet_ack(uint32 packet_id); +extern void callback_send_packet_ack(void *user, uint32 packet_id); +extern void verse_send_packet_nak(uint32 packet_id); +extern void callback_send_packet_nak(void *user, uint32 packet_id); + +void v_fs_init(void) +{ + unsigned int i; + if(v_fs_initialized) + return; + for(i = 0; i < V_FS_MAX_CMDS; i++) + { + VCmdData.unpack_func[i] = NULL; + VCmdData.pack_func[i] = NULL; + VCmdData.user_func[i] = NULL; + VCmdData.user_data[i] = NULL; + VCmdData.alias_pack_func[i] = NULL; + VCmdData.alias_user_func[i] = NULL; + VCmdData.alias_user_data[i] = NULL; + } + #if !defined(V_GENERATE_FUNC_MODE) + init_pack_and_unpack(); + #endif + for(i = 0; i < V_FS_MAX_CMDS && VCmdData.pack_func[i] != verse_send_packet_ack; i++); + VCmdData.user_func[i] = callback_send_packet_ack; + for(i = 0; i < V_FS_MAX_CMDS && VCmdData.pack_func[i] != verse_send_packet_nak; i++); + VCmdData.user_func[i] = callback_send_packet_nak; + + v_fs_initialized = TRUE; +} + + +void v_fs_add_func(unsigned int cmd_id, unsigned int (*unpack_func)(const char *data, size_t length), void *pack_func, void *alias_func) +{ + VCmdData.unpack_func[cmd_id] = unpack_func; + VCmdData.pack_func[cmd_id] = pack_func; + VCmdData.alias_pack_func[cmd_id] = alias_func; +} + +void *v_fs_get_user_func(unsigned int cmd_id) +{ +/* if(VCmdData.call)*/ + return VCmdData.user_func[cmd_id]; + return NULL; +} + +void *v_fs_get_user_data(unsigned int cmd_id) +{ + return VCmdData.user_data[cmd_id]; +} + +void *v_fs_get_alias_user_func(unsigned int cmd_id) +{ +/* if(VCmdData.call)*/ + return VCmdData.alias_user_func[cmd_id]; + return NULL; +} + +void *v_fs_get_alias_user_data(unsigned int cmd_id) +{ + return VCmdData.alias_user_data[cmd_id]; +} + +void verse_callback_set(void *command, void *callback, void *user) +{ + unsigned int i; + if(!v_fs_initialized) + v_fs_init(); + + for(i = 0; i < V_FS_MAX_CMDS; i++) + { + if(VCmdData.pack_func[i] == command) + { + VCmdData.user_data[i] = user; + VCmdData.user_func[i] = callback; + return; + } + if(VCmdData.alias_pack_func[i] == command) + { + VCmdData.alias_user_data[i] = user; + VCmdData.alias_user_func[i] = callback; + return; + } + } +} + +/* Do we accept incoming connections, i.e. are we a host implementation? */ +boolean v_fs_func_accept_connections(void) +{ + return VCmdData.user_func[0] != NULL; +} + +/* Inspect beginning of packet, looking for ACK or NAK commands. */ +void v_fs_unpack_beginning(const uint8 *data, unsigned int length) +{ + uint32 id, i = 4; + uint8 cmd_id; + + i += vnp_raw_unpack_uint8(&data[i], &cmd_id); + while(i < length && (cmd_id == 7 || cmd_id == 8)) + { + i += vnp_raw_unpack_uint32(&data[i], &id); + if(cmd_id == 7) + callback_send_packet_ack(NULL, id); + else + callback_send_packet_nak(NULL, id); + i += vnp_raw_unpack_uint8(&data[i], &cmd_id); + } +} + +void v_fs_unpack(uint8 *data, unsigned int length) +{ + uint32 i, output, pack_id; + uint8 cmd_id, last = 255; + + i = vnp_raw_unpack_uint32(data, &pack_id); /* each packet starts with a 32 bit id */ + vnp_raw_unpack_uint8(&data[i], &cmd_id); + while(i < length && (cmd_id == 7 || cmd_id == 8)) + { + i += 5; + vnp_raw_unpack_uint8(&data[i], &cmd_id); + } + while(i < length) + { + i += vnp_raw_unpack_uint8(&data[i], &cmd_id); + if(VCmdData.unpack_func[cmd_id] != NULL) + { + VCmdData.call = TRUE; + output = VCmdData.unpack_func[cmd_id](&data[i], length - i); + if(output == (unsigned int) -1) /* Can this happen? Should be size_t or int, depending. */ + { + printf("** Aborting decode, command %u unpacker returned failure\n", cmd_id); +/* verse_send_packet_nak(pack_id);*/ + return; + } + last = cmd_id; + i += output; + } + else /* If unknown command byte was found, complain loudly and stop parsing packet. */ + { + size_t j; + + printf("\n** Unknown command ID %u (0x%02X) encountered--aborting packet decode len=%u pos=%u last=%u\n", cmd_id, cmd_id, length, i, last); + printf(" decoded %u bytes: ", --i); + for(j = 0; j < i; j++) + printf("%02X ", data[j]); + printf("\n (packet id=%u)", pack_id); + printf(" remaining %u bytes: ", length - i); + for(j = i; j < length; j++) + printf("%02X ", data[j]); + printf("\n"); +/* *(char *) 0 = 0;*/ + break; + } + } +/* if(expected != NULL) + verse_send_packet_ack(pack_id);*/ +} + +extern unsigned int v_unpack_connection(const char *data, size_t length); + +#endif diff --git a/extern/verse/dist/v_gen_pack_a_node.c b/extern/verse/dist/v_gen_pack_a_node.c new file mode 100644 index 00000000000..dc8e53e1a7f --- /dev/null +++ b/extern/verse/dist/v_gen_pack_a_node.c @@ -0,0 +1,521 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_a_buffer_create(VNodeID node_id, VBufferID buffer_id, const char *name, VNABlockType type, real64 frequency) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 160); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_buffer_create(node_id = %u buffer_id = %u name = %s type = %u frequency = %f );\n", node_id, buffer_id, name, type, frequency); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], frequency); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_buffer_destroy(VNodeID node_id, VBufferID buffer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 160); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_buffer_destroy(node_id = %u buffer_id = %u );\n", node_id, buffer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_buffer_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_a_buffer_create)(void *user_data, VNodeID node_id, VBufferID buffer_id, const char *name, VNABlockType type, real64 frequency); + VNodeID node_id; + VBufferID buffer_id; + char name[16]; + VNABlockType type; + real64 frequency; + + func_a_buffer_create = v_fs_get_user_func(160); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &buffer_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 9 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNABlockType)enum_temp; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frequency); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_a_buffer_destroy(node_id = %u buffer_id = %u ); callback = %p\n", node_id, buffer_id, v_fs_get_alias_user_func(160)); + else + printf("receive: verse_send_a_buffer_create(node_id = %u buffer_id = %u name = %s type = %u frequency = %f ); callback = %p\n", node_id, buffer_id, name, type, frequency, v_fs_get_user_func(160)); +#endif + if(name[0] == 0) + { + void (* alias_a_buffer_destroy)(void *user_data, VNodeID node_id, VBufferID buffer_id); + alias_a_buffer_destroy = v_fs_get_alias_user_func(160); + if(alias_a_buffer_destroy != NULL) + alias_a_buffer_destroy(v_fs_get_alias_user_data(160), node_id, buffer_id); + return buffer_pos; + } + if(func_a_buffer_create != NULL) + func_a_buffer_create(v_fs_get_user_data(160), node_id, buffer_id, name, (VNABlockType) type, frequency); + + return buffer_pos; +} + +void verse_send_a_buffer_subscribe(VNodeID node_id, VBufferID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 161); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_buffer_subscribe(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_buffer_unsubscribe(VNodeID node_id, VBufferID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 161); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_buffer_unsubscribe(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_buffer_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_a_buffer_subscribe)(void *user_data, VNodeID node_id, VBufferID layer_id); + VNodeID node_id; + VBufferID layer_id; + uint8 alias_bool; + + func_a_buffer_subscribe = v_fs_get_user_func(161); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_a_buffer_unsubscribe(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(161)); + else + printf("receive: verse_send_a_buffer_subscribe(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_user_func(161)); +#endif + if(!alias_bool) + { + void (* alias_a_buffer_unsubscribe)(void *user_data, VNodeID node_id, VBufferID layer_id); + alias_a_buffer_unsubscribe = v_fs_get_alias_user_func(161); + if(alias_a_buffer_unsubscribe != NULL) + alias_a_buffer_unsubscribe(v_fs_get_alias_user_data(161), node_id, layer_id); + return buffer_pos; + } + if(func_a_buffer_subscribe != NULL) + func_a_buffer_subscribe(v_fs_get_user_data(161), node_id, layer_id); + + return buffer_pos; +} + +void verse_send_a_block_set(VNodeID node_id, VLayerID buffer_id, uint32 block_index, VNABlockType type, const VNABlock *samples) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 162); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_block_set(node_id = %u buffer_id = %u block_index = %u type = %u samples = %p );\n", node_id, buffer_id, block_index, type, samples); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], block_index); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_pack_audio_block(&buf[buffer_pos], type, samples); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u || block_index == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_block_clear(VNodeID node_id, VLayerID buffer_id, uint32 block_index) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 162); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_block_clear(node_id = %u buffer_id = %u block_index = %u );\n", node_id, buffer_id, block_index); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], block_index); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u || block_index == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_block_set(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_a_block_set)(void *user_data, VNodeID node_id, VLayerID buffer_id, uint32 block_index, VNABlockType type, const VNABlock *samples); + VNodeID node_id; + VLayerID buffer_id; + uint32 block_index; + VNABlockType type; + const VNABlock *samples; + + func_a_block_set = v_fs_get_user_func(162); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &buffer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &block_index); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNABlockType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(type > VN_A_BLOCK_REAL64) + printf("receive: verse_send_a_block_clear(node_id = %u buffer_id = %u block_index = %u ); callback = %p\n", node_id, buffer_id, block_index, v_fs_get_alias_user_func(162)); + else + printf("receive: verse_send_a_block_set(node_id = %u buffer_id = %u block_index = %u type = %u ); callback = %p\n", node_id, buffer_id, block_index, type, v_fs_get_user_func(162)); +#endif + if(type <= VN_A_BLOCK_REAL64) + { + VNABlock block; + buffer_pos += vnp_unpack_audio_block(&buf[buffer_pos], type, &block); + if(func_a_block_set != NULL) + func_a_block_set(v_fs_get_user_data(162), node_id, buffer_id, block_index, (VNABlockType) type, &block); + return buffer_pos; + } + + if(type > VN_A_BLOCK_REAL64) + { + void (* alias_a_block_clear)(void *user_data, VNodeID node_id, VLayerID buffer_id, uint32 block_index); + alias_a_block_clear = v_fs_get_alias_user_func(162); + if(alias_a_block_clear != NULL) + alias_a_block_clear(v_fs_get_alias_user_data(162), node_id, buffer_id, block_index); + return buffer_pos; + } + if(func_a_block_set != NULL) + func_a_block_set(v_fs_get_user_data(162), node_id, buffer_id, block_index, (VNABlockType) type, samples); + + return buffer_pos; +} + +void verse_send_a_stream_create(VNodeID node_id, VLayerID stream_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 163); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream_create(node_id = %u stream_id = %u name = %s );\n", node_id, stream_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_stream_destroy(VNodeID node_id, VLayerID stream_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 163); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream_destroy(node_id = %u stream_id = %u );\n", node_id, stream_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_stream_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_a_stream_create)(void *user_data, VNodeID node_id, VLayerID stream_id, const char *name); + VNodeID node_id; + VLayerID stream_id; + char name[16]; + + func_a_stream_create = v_fs_get_user_func(163); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &stream_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_a_stream_destroy(node_id = %u stream_id = %u ); callback = %p\n", node_id, stream_id, v_fs_get_alias_user_func(163)); + else + printf("receive: verse_send_a_stream_create(node_id = %u stream_id = %u name = %s ); callback = %p\n", node_id, stream_id, name, v_fs_get_user_func(163)); +#endif + if(name[0] == 0) + { + void (* alias_a_stream_destroy)(void *user_data, VNodeID node_id, VLayerID stream_id); + alias_a_stream_destroy = v_fs_get_alias_user_func(163); + if(alias_a_stream_destroy != NULL) + alias_a_stream_destroy(v_fs_get_alias_user_data(163), node_id, stream_id); + return buffer_pos; + } + if(func_a_stream_create != NULL) + func_a_stream_create(v_fs_get_user_data(163), node_id, stream_id, name); + + return buffer_pos; +} + +void verse_send_a_stream_subscribe(VNodeID node_id, VLayerID stream_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 164); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream_subscribe(node_id = %u stream_id = %u );\n", node_id, stream_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_a_stream_unsubscribe(VNodeID node_id, VLayerID stream_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 164); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream_unsubscribe(node_id = %u stream_id = %u );\n", node_id, stream_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_stream_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_a_stream_subscribe)(void *user_data, VNodeID node_id, VLayerID stream_id); + VNodeID node_id; + VLayerID stream_id; + uint8 alias_bool; + + func_a_stream_subscribe = v_fs_get_user_func(164); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &stream_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_a_stream_unsubscribe(node_id = %u stream_id = %u ); callback = %p\n", node_id, stream_id, v_fs_get_alias_user_func(164)); + else + printf("receive: verse_send_a_stream_subscribe(node_id = %u stream_id = %u ); callback = %p\n", node_id, stream_id, v_fs_get_user_func(164)); +#endif + if(!alias_bool) + { + void (* alias_a_stream_unsubscribe)(void *user_data, VNodeID node_id, VLayerID stream_id); + alias_a_stream_unsubscribe = v_fs_get_alias_user_func(164); + if(alias_a_stream_unsubscribe != NULL) + alias_a_stream_unsubscribe(v_fs_get_alias_user_data(164), node_id, stream_id); + return buffer_pos; + } + if(func_a_stream_subscribe != NULL) + func_a_stream_subscribe(v_fs_get_user_data(164), node_id, stream_id); + + return buffer_pos; +} + +void verse_send_a_stream(VNodeID node_id, VLayerID stream_id, uint32 time_s, uint32 time_f, VNABlockType type, real64 frequency, const VNABlock *samples) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 165); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_a_stream(node_id = %u stream_id = %u time_s = %u time_f = %u type = %u frequency = %f samples = %p );\n", node_id, stream_id, time_s, time_f, type, frequency, samples); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], stream_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], frequency); + buffer_pos += vnp_pack_audio_block(&buf[buffer_pos], type, samples); + if(node_id == (uint32) ~0u || stream_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_a_stream(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_a_stream)(void *user_data, VNodeID node_id, VLayerID stream_id, uint32 time_s, uint32 time_f, VNABlockType type, real64 frequency, const VNABlock *samples); + VNodeID node_id; + VLayerID stream_id; + uint32 time_s; + uint32 time_f; + VNABlockType type; + real64 frequency; + const VNABlock *samples; + + func_a_stream = v_fs_get_user_func(165); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &stream_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNABlockType)enum_temp; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frequency); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_a_stream(node_id = %u stream_id = %u time_s = %u time_f = %u type = %u frequency = %f ); callback = %p\n", node_id, stream_id, time_s, time_f, type, frequency, v_fs_get_user_func(165)); +#endif + { + VNABlock block; + buffer_pos += vnp_unpack_audio_block(&buf[buffer_pos], type, &block); + if(func_a_stream != NULL) + func_a_stream(v_fs_get_user_data(165), node_id, stream_id, time_s, time_f, (VNABlockType) type, frequency, &block); + return buffer_pos; + } + + if(func_a_stream != NULL) + func_a_stream(v_fs_get_user_data(165), node_id, stream_id, time_s, time_f, (VNABlockType) type, frequency, samples); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_b_node.c b/extern/verse/dist/v_gen_pack_b_node.c new file mode 100644 index 00000000000..a4792a10fe4 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_b_node.c @@ -0,0 +1,238 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_b_dimensions_set(VNodeID node_id, uint16 width, uint16 height, uint16 depth) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 80); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_dimensions_set(node_id = %u width = %u height = %u depth = %u );\n", node_id, width, height, depth); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], width); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], height); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], depth); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_b_dimensions_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_b_dimensions_set)(void *user_data, VNodeID node_id, uint16 width, uint16 height, uint16 depth); + VNodeID node_id; + uint16 width; + uint16 height; + uint16 depth; + + func_b_dimensions_set = v_fs_get_user_func(80); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &width); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &height); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &depth); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_b_dimensions_set(node_id = %u width = %u height = %u depth = %u ); callback = %p\n", node_id, width, height, depth, v_fs_get_user_func(80)); +#endif + if(func_b_dimensions_set != NULL) + func_b_dimensions_set(v_fs_get_user_data(80), node_id, width, height, depth); + + return buffer_pos; +} + +void verse_send_b_layer_create(VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 81); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_layer_create(node_id = %u layer_id = %u name = %s type = %u );\n", node_id, layer_id, name, type); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_b_layer_destroy(VNodeID node_id, VLayerID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 81); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_layer_destroy(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_b_layer_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_b_layer_create)(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type); + VNodeID node_id; + VLayerID layer_id; + char name[16]; + VNBLayerType type; + + func_b_layer_create = v_fs_get_user_func(81); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 1 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNBLayerType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_b_layer_destroy(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(81)); + else + printf("receive: verse_send_b_layer_create(node_id = %u layer_id = %u name = %s type = %u ); callback = %p\n", node_id, layer_id, name, type, v_fs_get_user_func(81)); +#endif + if(name[0] == 0) + { + void (* alias_b_layer_destroy)(void *user_data, VNodeID node_id, VLayerID layer_id); + alias_b_layer_destroy = v_fs_get_alias_user_func(81); + if(alias_b_layer_destroy != NULL) + alias_b_layer_destroy(v_fs_get_alias_user_data(81), node_id, layer_id); + return buffer_pos; + } + if(func_b_layer_create != NULL) + func_b_layer_create(v_fs_get_user_data(81), node_id, layer_id, name, (VNBLayerType) type); + + return buffer_pos; +} + +void verse_send_b_layer_subscribe(VNodeID node_id, VLayerID layer_id, uint8 level) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 82); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_layer_subscribe(node_id = %u layer_id = %u level = %u );\n", node_id, layer_id, level); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], level); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_b_layer_unsubscribe(VNodeID node_id, VLayerID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 82); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_layer_unsubscribe(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], -1); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_b_layer_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_b_layer_subscribe)(void *user_data, VNodeID node_id, VLayerID layer_id, uint8 level); + VNodeID node_id; + VLayerID layer_id; + uint8 level; + + func_b_layer_subscribe = v_fs_get_user_func(82); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &level); +#if defined V_PRINT_RECEIVE_COMMANDS + if(level == 255) + printf("receive: verse_send_b_layer_unsubscribe(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(82)); + else + printf("receive: verse_send_b_layer_subscribe(node_id = %u layer_id = %u level = %u ); callback = %p\n", node_id, layer_id, level, v_fs_get_user_func(82)); +#endif + if(level == 255) + { + void (* alias_b_layer_unsubscribe)(void *user_data, VNodeID node_id, VLayerID layer_id); + alias_b_layer_unsubscribe = v_fs_get_alias_user_func(82); + if(alias_b_layer_unsubscribe != NULL) + alias_b_layer_unsubscribe(v_fs_get_alias_user_data(82), node_id, layer_id); + return buffer_pos; + } + if(func_b_layer_subscribe != NULL) + func_b_layer_subscribe(v_fs_get_user_data(82), node_id, layer_id, level); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_c_node.c b/extern/verse/dist/v_gen_pack_c_node.c new file mode 100644 index 00000000000..b75fa213383 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_c_node.c @@ -0,0 +1,189 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_c_curve_create(VNodeID node_id, VLayerID curve_id, const char *name, uint8 dimensions) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 128); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_curve_create(node_id = %u curve_id = %u name = %s dimensions = %u );\n", node_id, curve_id, name, dimensions); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], dimensions); + if(node_id == (uint32) ~0u || curve_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_c_curve_destroy(VNodeID node_id, VLayerID curve_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 128); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_curve_destroy(node_id = %u curve_id = %u );\n", node_id, curve_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], -1); + if(node_id == (uint32) ~0u || curve_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_c_curve_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_c_curve_create)(void *user_data, VNodeID node_id, VLayerID curve_id, const char *name, uint8 dimensions); + VNodeID node_id; + VLayerID curve_id; + char name[16]; + uint8 dimensions; + + func_c_curve_create = v_fs_get_user_func(128); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &curve_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 1 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &dimensions); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_c_curve_destroy(node_id = %u curve_id = %u ); callback = %p\n", node_id, curve_id, v_fs_get_alias_user_func(128)); + else + printf("receive: verse_send_c_curve_create(node_id = %u curve_id = %u name = %s dimensions = %u ); callback = %p\n", node_id, curve_id, name, dimensions, v_fs_get_user_func(128)); +#endif + if(name[0] == 0) + { + void (* alias_c_curve_destroy)(void *user_data, VNodeID node_id, VLayerID curve_id); + alias_c_curve_destroy = v_fs_get_alias_user_func(128); + if(alias_c_curve_destroy != NULL) + alias_c_curve_destroy(v_fs_get_alias_user_data(128), node_id, curve_id); + return buffer_pos; + } + if(func_c_curve_create != NULL) + func_c_curve_create(v_fs_get_user_data(128), node_id, curve_id, name, dimensions); + + return buffer_pos; +} + +void verse_send_c_curve_subscribe(VNodeID node_id, VLayerID curve_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 129); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_curve_subscribe(node_id = %u curve_id = %u );\n", node_id, curve_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || curve_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_c_curve_unsubscribe(VNodeID node_id, VLayerID curve_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 129); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_curve_unsubscribe(node_id = %u curve_id = %u );\n", node_id, curve_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || curve_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_c_curve_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_c_curve_subscribe)(void *user_data, VNodeID node_id, VLayerID curve_id); + VNodeID node_id; + VLayerID curve_id; + uint8 alias_bool; + + func_c_curve_subscribe = v_fs_get_user_func(129); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &curve_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_c_curve_unsubscribe(node_id = %u curve_id = %u ); callback = %p\n", node_id, curve_id, v_fs_get_alias_user_func(129)); + else + printf("receive: verse_send_c_curve_subscribe(node_id = %u curve_id = %u ); callback = %p\n", node_id, curve_id, v_fs_get_user_func(129)); +#endif + if(!alias_bool) + { + void (* alias_c_curve_unsubscribe)(void *user_data, VNodeID node_id, VLayerID curve_id); + alias_c_curve_unsubscribe = v_fs_get_alias_user_func(129); + if(alias_c_curve_unsubscribe != NULL) + alias_c_curve_unsubscribe(v_fs_get_alias_user_data(129), node_id, curve_id); + return buffer_pos; + } + if(func_c_curve_subscribe != NULL) + func_c_curve_subscribe(v_fs_get_user_data(129), node_id, curve_id); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_g_node.c b/extern/verse/dist/v_gen_pack_g_node.c new file mode 100644 index 00000000000..5a70173554d --- /dev/null +++ b/extern/verse/dist/v_gen_pack_g_node.c @@ -0,0 +1,1154 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_g_layer_create(VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_uint, real64 def_real) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 48); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_layer_create(node_id = %u layer_id = %u name = %s type = %u def_uint = %u def_real = %f );\n", node_id, layer_id, name, type, def_uint, def_real); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], def_uint); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], def_real); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_layer_destroy(VNodeID node_id, VLayerID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 48); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_layer_destroy(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_layer_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_g_layer_create)(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_uint, real64 def_real); + VNodeID node_id; + VLayerID layer_id; + char name[16]; + VNGLayerType type; + uint32 def_uint; + real64 def_real; + + func_g_layer_create = v_fs_get_user_func(48); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 13 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNGLayerType)enum_temp; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &def_uint); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &def_real); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_g_layer_destroy(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(48)); + else + printf("receive: verse_send_g_layer_create(node_id = %u layer_id = %u name = %s type = %u def_uint = %u def_real = %f ); callback = %p\n", node_id, layer_id, name, type, def_uint, def_real, v_fs_get_user_func(48)); +#endif + if(name[0] == 0) + { + void (* alias_g_layer_destroy)(void *user_data, VNodeID node_id, VLayerID layer_id); + alias_g_layer_destroy = v_fs_get_alias_user_func(48); + if(alias_g_layer_destroy != NULL) + alias_g_layer_destroy(v_fs_get_alias_user_data(48), node_id, layer_id); + return buffer_pos; + } + if(func_g_layer_create != NULL) + func_g_layer_create(v_fs_get_user_data(48), node_id, layer_id, name, (VNGLayerType) type, def_uint, def_real); + + return buffer_pos; +} + +void verse_send_g_layer_subscribe(VNodeID node_id, VLayerID layer_id, VNRealFormat type) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 49); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_layer_subscribe(node_id = %u layer_id = %u type = %u );\n", node_id, layer_id, type); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_layer_unsubscribe(VNodeID node_id, VLayerID layer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 49); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_layer_unsubscribe(node_id = %u layer_id = %u );\n", node_id, layer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_layer_subscribe(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_g_layer_subscribe)(void *user_data, VNodeID node_id, VLayerID layer_id, VNRealFormat type); + VNodeID node_id; + VLayerID layer_id; + VNRealFormat type; + + func_g_layer_subscribe = v_fs_get_user_func(49); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNRealFormat)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(type > VN_FORMAT_REAL64) + printf("receive: verse_send_g_layer_unsubscribe(node_id = %u layer_id = %u ); callback = %p\n", node_id, layer_id, v_fs_get_alias_user_func(49)); + else + printf("receive: verse_send_g_layer_subscribe(node_id = %u layer_id = %u type = %u ); callback = %p\n", node_id, layer_id, type, v_fs_get_user_func(49)); +#endif + if(type > VN_FORMAT_REAL64) + { + void (* alias_g_layer_unsubscribe)(void *user_data, VNodeID node_id, VLayerID layer_id); + alias_g_layer_unsubscribe = v_fs_get_alias_user_func(49); + if(alias_g_layer_unsubscribe != NULL) + alias_g_layer_unsubscribe(v_fs_get_alias_user_data(49), node_id, layer_id); + return buffer_pos; + } + if(func_g_layer_subscribe != NULL) + func_g_layer_subscribe(v_fs_get_user_data(49), node_id, layer_id, (VNRealFormat) type); + + return buffer_pos; +} + +void verse_send_g_vertex_set_xyz_real32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 50); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_xyz_real32(node_id = %u layer_id = %u vertex_id = %u x = %f y = %f z = %f );\n", node_id, layer_id, vertex_id, x, y, z); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], x); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], y); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], z); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_vertex_delete_real32(VNodeID node_id, uint32 vertex_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 50); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_delete_real32(node_id = %u vertex_id = %u );\n", node_id, vertex_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], 0); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], V_REAL32_MAX); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], V_REAL32_MAX); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], V_REAL32_MAX); + if(node_id == (uint32) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_xyz_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_xyz_real32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + real32 x; + real32 y; + real32 z; + + func_g_vertex_set_xyz_real32 = v_fs_get_user_func(50); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &x); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &y); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &z); +#if defined V_PRINT_RECEIVE_COMMANDS + if(x == V_REAL32_MAX || y == V_REAL32_MAX || z == V_REAL32_MAX) + printf("receive: verse_send_g_vertex_delete_real32(node_id = %u vertex_id = %u ); callback = %p\n", node_id, vertex_id, v_fs_get_alias_user_func(50)); + else + printf("receive: verse_send_g_vertex_set_xyz_real32(node_id = %u layer_id = %u vertex_id = %u x = %f y = %f z = %f ); callback = %p\n", node_id, layer_id, vertex_id, x, y, z, v_fs_get_user_func(50)); +#endif + if(x == V_REAL32_MAX || y == V_REAL32_MAX || z == V_REAL32_MAX) + { + void (* alias_g_vertex_delete_real32)(void *user_data, VNodeID node_id, uint32 vertex_id); + alias_g_vertex_delete_real32 = v_fs_get_alias_user_func(50); + if(alias_g_vertex_delete_real32 != NULL) + alias_g_vertex_delete_real32(v_fs_get_alias_user_data(50), node_id, vertex_id); + return buffer_pos; + } + if(func_g_vertex_set_xyz_real32 != NULL) + func_g_vertex_set_xyz_real32(v_fs_get_user_data(50), node_id, layer_id, vertex_id, x, y, z); + + return buffer_pos; +} + +void verse_send_g_vertex_set_xyz_real64(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 x, real64 y, real64 z) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 51); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_xyz_real64(node_id = %u layer_id = %u vertex_id = %u x = %f y = %f z = %f );\n", node_id, layer_id, vertex_id, x, y, z); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], x); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], y); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], z); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_vertex_delete_real64(VNodeID node_id, uint32 vertex_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 51); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_delete_real64(node_id = %u vertex_id = %u );\n", node_id, vertex_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], 0); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + if(node_id == (uint32) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_xyz_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_xyz_real64)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 x, real64 y, real64 z); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + real64 x; + real64 y; + real64 z; + + func_g_vertex_set_xyz_real64 = v_fs_get_user_func(51); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &x); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &y); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &z); +#if defined V_PRINT_RECEIVE_COMMANDS + if(x == V_REAL64_MAX || y == V_REAL64_MAX || z == V_REAL64_MAX) + printf("receive: verse_send_g_vertex_delete_real64(node_id = %u vertex_id = %u ); callback = %p\n", node_id, vertex_id, v_fs_get_alias_user_func(51)); + else + printf("receive: verse_send_g_vertex_set_xyz_real64(node_id = %u layer_id = %u vertex_id = %u x = %f y = %f z = %f ); callback = %p\n", node_id, layer_id, vertex_id, x, y, z, v_fs_get_user_func(51)); +#endif + if(x == V_REAL64_MAX || y == V_REAL64_MAX || z == V_REAL64_MAX) + { + void (* alias_g_vertex_delete_real64)(void *user_data, VNodeID node_id, uint32 vertex_id); + alias_g_vertex_delete_real64 = v_fs_get_alias_user_func(51); + if(alias_g_vertex_delete_real64 != NULL) + alias_g_vertex_delete_real64(v_fs_get_alias_user_data(51), node_id, vertex_id); + return buffer_pos; + } + if(func_g_vertex_set_xyz_real64 != NULL) + func_g_vertex_set_xyz_real64(v_fs_get_user_data(51), node_id, layer_id, vertex_id, x, y, z); + + return buffer_pos; +} + +void verse_send_g_vertex_set_uint32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, uint32 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 52); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_uint32(node_id = %u layer_id = %u vertex_id = %u value = %u );\n", node_id, layer_id, vertex_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_uint32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_uint32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, uint32 value); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + uint32 value; + + func_g_vertex_set_uint32 = v_fs_get_user_func(52); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_vertex_set_uint32(node_id = %u layer_id = %u vertex_id = %u value = %u ); callback = %p\n", node_id, layer_id, vertex_id, value, v_fs_get_user_func(52)); +#endif + if(func_g_vertex_set_uint32 != NULL) + func_g_vertex_set_uint32(v_fs_get_user_data(52), node_id, layer_id, vertex_id, value); + + return buffer_pos; +} + +void verse_send_g_vertex_set_real64(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 53); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_real64(node_id = %u layer_id = %u vertex_id = %u value = %f );\n", node_id, layer_id, vertex_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_real64)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 value); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + real64 value; + + func_g_vertex_set_real64 = v_fs_get_user_func(53); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_vertex_set_real64(node_id = %u layer_id = %u vertex_id = %u value = %f ); callback = %p\n", node_id, layer_id, vertex_id, value, v_fs_get_user_func(53)); +#endif + if(func_g_vertex_set_real64 != NULL) + func_g_vertex_set_real64(v_fs_get_user_data(53), node_id, layer_id, vertex_id, value); + + return buffer_pos; +} + +void verse_send_g_vertex_set_real32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 54); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_vertex_set_real32(node_id = %u layer_id = %u vertex_id = %u value = %f );\n", node_id, layer_id, vertex_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], vertex_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || vertex_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_vertex_set_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_vertex_set_real32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 value); + VNodeID node_id; + VLayerID layer_id; + uint32 vertex_id; + real32 value; + + func_g_vertex_set_real32 = v_fs_get_user_func(54); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &vertex_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_vertex_set_real32(node_id = %u layer_id = %u vertex_id = %u value = %f ); callback = %p\n", node_id, layer_id, vertex_id, value, v_fs_get_user_func(54)); +#endif + if(func_g_vertex_set_real32 != NULL) + func_g_vertex_set_real32(v_fs_get_user_data(54), node_id, layer_id, vertex_id, value); + + return buffer_pos; +} + +void verse_send_g_polygon_set_corner_uint32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 55); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_corner_uint32(node_id = %u layer_id = %u polygon_id = %u v0 = %u v1 = %u v2 = %u v3 = %u );\n", node_id, layer_id, polygon_id, v0, v1, v2, v3); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], v0); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], v1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], v2); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], v3); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_polygon_delete(VNodeID node_id, uint32 polygon_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 55); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_delete(node_id = %u polygon_id = %u );\n", node_id, polygon_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], 1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + if(node_id == (uint32) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_corner_uint32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_corner_uint32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + uint32 v0; + uint32 v1; + uint32 v2; + uint32 v3; + + func_g_polygon_set_corner_uint32 = v_fs_get_user_func(55); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &v0); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &v1); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &v2); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &v3); +#if defined V_PRINT_RECEIVE_COMMANDS + if(layer_id == 1 && v0 == ~0u) + printf("receive: verse_send_g_polygon_delete(node_id = %u polygon_id = %u ); callback = %p\n", node_id, polygon_id, v_fs_get_alias_user_func(55)); + else + printf("receive: verse_send_g_polygon_set_corner_uint32(node_id = %u layer_id = %u polygon_id = %u v0 = %u v1 = %u v2 = %u v3 = %u ); callback = %p\n", node_id, layer_id, polygon_id, v0, v1, v2, v3, v_fs_get_user_func(55)); +#endif + if(layer_id == 1 && v0 == ~0u) + { + void (* alias_g_polygon_delete)(void *user_data, VNodeID node_id, uint32 polygon_id); + alias_g_polygon_delete = v_fs_get_alias_user_func(55); + if(alias_g_polygon_delete != NULL) + alias_g_polygon_delete(v_fs_get_alias_user_data(55), node_id, polygon_id); + return buffer_pos; + } + if(func_g_polygon_set_corner_uint32 != NULL) + func_g_polygon_set_corner_uint32(v_fs_get_user_data(55), node_id, layer_id, polygon_id, v0, v1, v2, v3); + + return buffer_pos; +} + +void verse_send_g_polygon_set_corner_real64(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 v0, real64 v1, real64 v2, real64 v3) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 56); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_corner_real64(node_id = %u layer_id = %u polygon_id = %u v0 = %f v1 = %f v2 = %f v3 = %f );\n", node_id, layer_id, polygon_id, v0, v1, v2, v3); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], v0); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], v1); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], v2); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], v3); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_corner_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_corner_real64)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 v0, real64 v1, real64 v2, real64 v3); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + real64 v0; + real64 v1; + real64 v2; + real64 v3; + + func_g_polygon_set_corner_real64 = v_fs_get_user_func(56); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &v0); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &v1); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &v2); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &v3); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_corner_real64(node_id = %u layer_id = %u polygon_id = %u v0 = %f v1 = %f v2 = %f v3 = %f ); callback = %p\n", node_id, layer_id, polygon_id, v0, v1, v2, v3, v_fs_get_user_func(56)); +#endif + if(func_g_polygon_set_corner_real64 != NULL) + func_g_polygon_set_corner_real64(v_fs_get_user_data(56), node_id, layer_id, polygon_id, v0, v1, v2, v3); + + return buffer_pos; +} + +void verse_send_g_polygon_set_corner_real32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 v0, real32 v1, real32 v2, real32 v3) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 57); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_corner_real32(node_id = %u layer_id = %u polygon_id = %u v0 = %f v1 = %f v2 = %f v3 = %f );\n", node_id, layer_id, polygon_id, v0, v1, v2, v3); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], v0); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], v1); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], v2); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], v3); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_corner_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_corner_real32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 v0, real32 v1, real32 v2, real32 v3); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + real32 v0; + real32 v1; + real32 v2; + real32 v3; + + func_g_polygon_set_corner_real32 = v_fs_get_user_func(57); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &v0); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &v1); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &v2); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &v3); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_corner_real32(node_id = %u layer_id = %u polygon_id = %u v0 = %f v1 = %f v2 = %f v3 = %f ); callback = %p\n", node_id, layer_id, polygon_id, v0, v1, v2, v3, v_fs_get_user_func(57)); +#endif + if(func_g_polygon_set_corner_real32 != NULL) + func_g_polygon_set_corner_real32(v_fs_get_user_data(57), node_id, layer_id, polygon_id, v0, v1, v2, v3); + + return buffer_pos; +} + +void verse_send_g_polygon_set_face_uint8(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint8 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 58); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_face_uint8(node_id = %u layer_id = %u polygon_id = %u value = %u );\n", node_id, layer_id, polygon_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_face_uint8(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_face_uint8)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint8 value); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + uint8 value; + + func_g_polygon_set_face_uint8 = v_fs_get_user_func(58); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_face_uint8(node_id = %u layer_id = %u polygon_id = %u value = %u ); callback = %p\n", node_id, layer_id, polygon_id, value, v_fs_get_user_func(58)); +#endif + if(func_g_polygon_set_face_uint8 != NULL) + func_g_polygon_set_face_uint8(v_fs_get_user_data(58), node_id, layer_id, polygon_id, value); + + return buffer_pos; +} + +void verse_send_g_polygon_set_face_uint32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 59); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_face_uint32(node_id = %u layer_id = %u polygon_id = %u value = %u );\n", node_id, layer_id, polygon_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_face_uint32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_face_uint32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 value); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + uint32 value; + + func_g_polygon_set_face_uint32 = v_fs_get_user_func(59); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_face_uint32(node_id = %u layer_id = %u polygon_id = %u value = %u ); callback = %p\n", node_id, layer_id, polygon_id, value, v_fs_get_user_func(59)); +#endif + if(func_g_polygon_set_face_uint32 != NULL) + func_g_polygon_set_face_uint32(v_fs_get_user_data(59), node_id, layer_id, polygon_id, value); + + return buffer_pos; +} + +void verse_send_g_polygon_set_face_real64(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 60); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_face_real64(node_id = %u layer_id = %u polygon_id = %u value = %f );\n", node_id, layer_id, polygon_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_face_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_face_real64)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 value); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + real64 value; + + func_g_polygon_set_face_real64 = v_fs_get_user_func(60); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_face_real64(node_id = %u layer_id = %u polygon_id = %u value = %f ); callback = %p\n", node_id, layer_id, polygon_id, value, v_fs_get_user_func(60)); +#endif + if(func_g_polygon_set_face_real64 != NULL) + func_g_polygon_set_face_real64(v_fs_get_user_data(60), node_id, layer_id, polygon_id, value); + + return buffer_pos; +} + +void verse_send_g_polygon_set_face_real32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 value) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 61); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_polygon_set_face_real32(node_id = %u layer_id = %u polygon_id = %u value = %f );\n", node_id, layer_id, polygon_id, value); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], polygon_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], value); + if(node_id == (uint32) ~0u || layer_id == (uint16) ~0u || polygon_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_polygon_set_face_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_polygon_set_face_real32)(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 value); + VNodeID node_id; + VLayerID layer_id; + uint32 polygon_id; + real32 value; + + func_g_polygon_set_face_real32 = v_fs_get_user_func(61); + if(buffer_length < 10) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &polygon_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &value); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_polygon_set_face_real32(node_id = %u layer_id = %u polygon_id = %u value = %f ); callback = %p\n", node_id, layer_id, polygon_id, value, v_fs_get_user_func(61)); +#endif + if(func_g_polygon_set_face_real32 != NULL) + func_g_polygon_set_face_real32(v_fs_get_user_data(61), node_id, layer_id, polygon_id, value); + + return buffer_pos; +} + +void verse_send_g_crease_set_vertex(VNodeID node_id, const char *layer, uint32 def_crease) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 62); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_crease_set_vertex(node_id = %u layer = %s def_crease = %u );\n", node_id, layer, def_crease); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], layer, 16); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], def_crease); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_crease_set_vertex(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_crease_set_vertex)(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); + VNodeID node_id; + char layer[16]; + uint32 def_crease; + + func_g_crease_set_vertex = v_fs_get_user_func(62); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], layer, 16, buffer_length - buffer_pos); + if(buffer_length < 4 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &def_crease); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_crease_set_vertex(node_id = %u layer = %s def_crease = %u ); callback = %p\n", node_id, layer, def_crease, v_fs_get_user_func(62)); +#endif + if(func_g_crease_set_vertex != NULL) + func_g_crease_set_vertex(v_fs_get_user_data(62), node_id, layer, def_crease); + + return buffer_pos; +} + +void verse_send_g_crease_set_edge(VNodeID node_id, const char *layer, uint32 def_crease) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 63); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_crease_set_edge(node_id = %u layer = %s def_crease = %u );\n", node_id, layer, def_crease); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], layer, 16); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], def_crease); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_crease_set_edge(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_crease_set_edge)(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); + VNodeID node_id; + char layer[16]; + uint32 def_crease; + + func_g_crease_set_edge = v_fs_get_user_func(63); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], layer, 16, buffer_length - buffer_pos); + if(buffer_length < 4 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &def_crease); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_g_crease_set_edge(node_id = %u layer = %s def_crease = %u ); callback = %p\n", node_id, layer, def_crease, v_fs_get_user_func(63)); +#endif + if(func_g_crease_set_edge != NULL) + func_g_crease_set_edge(v_fs_get_user_data(63), node_id, layer, def_crease); + + return buffer_pos; +} + +void verse_send_g_bone_create(VNodeID node_id, uint16 bone_id, const char *weight, const char *reference, uint16 parent, real64 pos_x, real64 pos_y, real64 pos_z, const char *position_label, const char *rotation_label, const char *scale_label) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_160);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 64); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_bone_create(node_id = %u bone_id = %u weight = %s reference = %s parent = %u pos_x = %f pos_y = %f pos_z = %f position_label = %s rotation_label = %s scale_label = %s );\n", node_id, bone_id, weight, reference, parent, pos_x, pos_y, pos_z, position_label, rotation_label, scale_label); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], bone_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], weight, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], reference, 16); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], parent); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos_x); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos_y); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos_z); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], position_label, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], rotation_label, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], scale_label, 16); + if(node_id == (uint32) ~0u || bone_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_g_bone_destroy(VNodeID node_id, uint16 bone_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_160);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 64); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_g_bone_destroy(node_id = %u bone_id = %u );\n", node_id, bone_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], bone_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], V_REAL64_MAX); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || bone_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_g_bone_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_g_bone_create)(void *user_data, VNodeID node_id, uint16 bone_id, const char *weight, const char *reference, uint16 parent, real64 pos_x, real64 pos_y, real64 pos_z, const char *position_label, const char *rotation_label, const char *scale_label); + VNodeID node_id; + uint16 bone_id; + char weight[16]; + char reference[16]; + uint16 parent; + real64 pos_x; + real64 pos_y; + real64 pos_z; + char position_label[16]; + char rotation_label[16]; + char scale_label[16]; + + func_g_bone_create = v_fs_get_user_func(64); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &bone_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], weight, 16, buffer_length - buffer_pos); + if(buffer_length < 0 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], reference, 16, buffer_length - buffer_pos); + if(buffer_length < 26 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &parent); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pos_x); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pos_y); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pos_z); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], position_label, 16, buffer_length - buffer_pos); + if(buffer_length < 0 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], rotation_label, 16, buffer_length - buffer_pos); + if(buffer_length < 0 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], scale_label, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(weight[0] == 0) + printf("receive: verse_send_g_bone_destroy(node_id = %u bone_id = %u ); callback = %p\n", node_id, bone_id, v_fs_get_alias_user_func(64)); + else + printf("receive: verse_send_g_bone_create(node_id = %u bone_id = %u weight = %s reference = %s parent = %u pos_x = %f pos_y = %f pos_z = %f position_label = %s rotation_label = %s scale_label = %s ); callback = %p\n", node_id, bone_id, weight, reference, parent, pos_x, pos_y, pos_z, position_label, rotation_label, scale_label, v_fs_get_user_func(64)); +#endif + if(weight[0] == 0) + { + void (* alias_g_bone_destroy)(void *user_data, VNodeID node_id, uint16 bone_id); + alias_g_bone_destroy = v_fs_get_alias_user_func(64); + if(alias_g_bone_destroy != NULL) + alias_g_bone_destroy(v_fs_get_alias_user_data(64), node_id, bone_id); + return buffer_pos; + } + if(func_g_bone_create != NULL) + func_g_bone_create(v_fs_get_user_data(64), node_id, bone_id, weight, reference, parent, pos_x, pos_y, pos_z, position_label, rotation_label, scale_label); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_init.c b/extern/verse/dist/v_gen_pack_init.c new file mode 100644 index 00000000000..e568cb989cb --- /dev/null +++ b/extern/verse/dist/v_gen_pack_init.c @@ -0,0 +1,95 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +#include "v_gen_unpack_func.h" + +#include "verse.h" + + +extern void verse_send_packet_ack(uint32 packet_id); +extern void verse_send_packet_nak(uint32 packet_id); + +void init_pack_and_unpack(void) +{ + v_fs_add_func(0, v_unpack_connect, (void *) verse_send_connect, NULL); + v_fs_add_func(1, v_unpack_connect_accept, (void *) verse_send_connect_accept, NULL); + v_fs_add_func(2, v_unpack_connect_terminate, (void *) verse_send_connect_terminate, NULL); + v_fs_add_func(5, v_unpack_ping, (void *) verse_send_ping, NULL); + v_fs_add_func(7, v_unpack_packet_ack, verse_send_packet_ack, NULL); + v_fs_add_func(8, v_unpack_packet_nak, verse_send_packet_nak, NULL); + v_fs_add_func(9, v_unpack_node_index_subscribe, verse_send_node_index_subscribe, NULL); + v_fs_add_func(10, v_unpack_node_create, verse_send_node_create, verse_send_node_destroy); + v_fs_add_func(11, v_unpack_node_subscribe, verse_send_node_subscribe, verse_send_node_unsubscribe); + v_fs_add_func(16, v_unpack_tag_group_create, verse_send_tag_group_create, verse_send_tag_group_destroy); + v_fs_add_func(17, v_unpack_tag_group_subscribe, verse_send_tag_group_subscribe, verse_send_tag_group_unsubscribe); + v_fs_add_func(18, v_unpack_tag_create, verse_send_tag_create, verse_send_tag_destroy); + v_fs_add_func(19, v_unpack_node_name_set, verse_send_node_name_set, NULL); + v_fs_add_func(32, v_unpack_o_transform_pos_real32, verse_send_o_transform_pos_real32, NULL); + v_fs_add_func(33, v_unpack_o_transform_rot_real32, verse_send_o_transform_rot_real32, NULL); + v_fs_add_func(34, v_unpack_o_transform_scale_real32, verse_send_o_transform_scale_real32, NULL); + v_fs_add_func(35, v_unpack_o_transform_pos_real64, verse_send_o_transform_pos_real64, NULL); + v_fs_add_func(36, v_unpack_o_transform_rot_real64, verse_send_o_transform_rot_real64, NULL); + v_fs_add_func(37, v_unpack_o_transform_scale_real64, verse_send_o_transform_scale_real64, NULL); + v_fs_add_func(38, v_unpack_o_transform_subscribe, verse_send_o_transform_subscribe, verse_send_o_transform_unsubscribe); + v_fs_add_func(39, v_unpack_o_light_set, verse_send_o_light_set, NULL); + v_fs_add_func(40, v_unpack_o_link_set, verse_send_o_link_set, verse_send_o_link_destroy); + v_fs_add_func(41, v_unpack_o_method_group_create, verse_send_o_method_group_create, verse_send_o_method_group_destroy); + v_fs_add_func(42, v_unpack_o_method_group_subscribe, verse_send_o_method_group_subscribe, verse_send_o_method_group_unsubscribe); + v_fs_add_func(43, v_unpack_o_method_create, verse_send_o_method_create, verse_send_o_method_destroy); + v_fs_add_func(44, v_unpack_o_method_call, verse_send_o_method_call, NULL); + v_fs_add_func(45, v_unpack_o_anim_run, verse_send_o_anim_run, NULL); + v_fs_add_func(46, v_unpack_o_hide, verse_send_o_hide, NULL); + v_fs_add_func(48, v_unpack_g_layer_create, verse_send_g_layer_create, verse_send_g_layer_destroy); + v_fs_add_func(49, v_unpack_g_layer_subscribe, verse_send_g_layer_subscribe, verse_send_g_layer_unsubscribe); + v_fs_add_func(50, v_unpack_g_vertex_set_xyz_real32, verse_send_g_vertex_set_xyz_real32, verse_send_g_vertex_delete_real32); + v_fs_add_func(51, v_unpack_g_vertex_set_xyz_real64, verse_send_g_vertex_set_xyz_real64, verse_send_g_vertex_delete_real64); + v_fs_add_func(52, v_unpack_g_vertex_set_uint32, verse_send_g_vertex_set_uint32, NULL); + v_fs_add_func(53, v_unpack_g_vertex_set_real64, verse_send_g_vertex_set_real64, NULL); + v_fs_add_func(54, v_unpack_g_vertex_set_real32, verse_send_g_vertex_set_real32, NULL); + v_fs_add_func(55, v_unpack_g_polygon_set_corner_uint32, verse_send_g_polygon_set_corner_uint32, verse_send_g_polygon_delete); + v_fs_add_func(56, v_unpack_g_polygon_set_corner_real64, verse_send_g_polygon_set_corner_real64, NULL); + v_fs_add_func(57, v_unpack_g_polygon_set_corner_real32, verse_send_g_polygon_set_corner_real32, NULL); + v_fs_add_func(58, v_unpack_g_polygon_set_face_uint8, verse_send_g_polygon_set_face_uint8, NULL); + v_fs_add_func(59, v_unpack_g_polygon_set_face_uint32, verse_send_g_polygon_set_face_uint32, NULL); + v_fs_add_func(60, v_unpack_g_polygon_set_face_real64, verse_send_g_polygon_set_face_real64, NULL); + v_fs_add_func(61, v_unpack_g_polygon_set_face_real32, verse_send_g_polygon_set_face_real32, NULL); + v_fs_add_func(62, v_unpack_g_crease_set_vertex, verse_send_g_crease_set_vertex, NULL); + v_fs_add_func(63, v_unpack_g_crease_set_edge, verse_send_g_crease_set_edge, NULL); + v_fs_add_func(64, v_unpack_g_bone_create, verse_send_g_bone_create, verse_send_g_bone_destroy); + v_fs_add_func(68, v_unpack_m_fragment_create, verse_send_m_fragment_create, verse_send_m_fragment_destroy); + v_fs_add_func(80, v_unpack_b_dimensions_set, verse_send_b_dimensions_set, NULL); + v_fs_add_func(81, v_unpack_b_layer_create, verse_send_b_layer_create, verse_send_b_layer_destroy); + v_fs_add_func(82, v_unpack_b_layer_subscribe, verse_send_b_layer_subscribe, verse_send_b_layer_unsubscribe); + v_fs_add_func(83, v_unpack_b_tile_set, (void *) verse_send_b_tile_set, NULL); + v_fs_add_func(96, v_unpack_t_language_set, verse_send_t_language_set, NULL); + v_fs_add_func(97, v_unpack_t_buffer_create, verse_send_t_buffer_create, verse_send_t_buffer_destroy); + v_fs_add_func(98, v_unpack_t_buffer_subscribe, verse_send_t_buffer_subscribe, verse_send_t_buffer_unsubscribe); + v_fs_add_func(99, v_unpack_t_text_set, (void *) verse_send_t_text_set, NULL); + v_fs_add_func(128, v_unpack_c_curve_create, verse_send_c_curve_create, verse_send_c_curve_destroy); + v_fs_add_func(129, v_unpack_c_curve_subscribe, verse_send_c_curve_subscribe, verse_send_c_curve_unsubscribe); + v_fs_add_func(130, v_unpack_c_key_set, (void *) verse_send_c_key_set, (void *) verse_send_c_key_destroy); + v_fs_add_func(160, v_unpack_a_buffer_create, verse_send_a_buffer_create, verse_send_a_buffer_destroy); + v_fs_add_func(161, v_unpack_a_buffer_subscribe, verse_send_a_buffer_subscribe, verse_send_a_buffer_unsubscribe); + v_fs_add_func(162, v_unpack_a_block_set, verse_send_a_block_set, verse_send_a_block_clear); + v_fs_add_func(163, v_unpack_a_stream_create, verse_send_a_stream_create, verse_send_a_stream_destroy); + v_fs_add_func(164, v_unpack_a_stream_subscribe, verse_send_a_stream_subscribe, verse_send_a_stream_unsubscribe); + v_fs_add_func(165, v_unpack_a_stream, verse_send_a_stream, NULL); +} +#endif + diff --git a/extern/verse/dist/v_gen_pack_m_node.c b/extern/verse/dist/v_gen_pack_m_node.c new file mode 100644 index 00000000000..376b6c51c39 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_m_node.c @@ -0,0 +1,352 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_m_fragment_create(VNodeID node_id, VNMFragmentID frag_id, VNMFragmentType type, const VMatFrag *fragment) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 68); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_m_fragment_create(node_id = %u frag_id = %u type = %u fragment = %p );\n", node_id, frag_id, type, fragment); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], frag_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + switch(type) + { + case VN_M_FT_COLOR : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.red); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.green); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->color.blue); + break; + case VN_M_FT_LIGHT : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->light.type); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->light.normal_falloff); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], fragment->light.brdf); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_r, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_g, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->light.brdf_b, 16); + break; + case VN_M_FT_REFLECTION : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->reflection.normal_falloff); + break; + case VN_M_FT_TRANSPARENCY : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->transparency.normal_falloff); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->transparency.refraction_index); + break; + case VN_M_FT_GEOMETRY : + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_r, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_g, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->geometry.layer_b, 16); + break; + case VN_M_FT_VOLUME : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.diffusion); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_r); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_g); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->volume.col_b); + break; + case VN_M_FT_VIEW : + break; + case VN_M_FT_TEXTURE : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], fragment->texture.bitmap); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_r, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_g, 16); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->texture.layer_b, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->texture.filtered); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->texture.mapping); + break; + case VN_M_FT_NOISE : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->noise.type); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->noise.mapping); + break; + case VN_M_FT_BLENDER : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->blender.type); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.data_a); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.data_b); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->blender.control); + break; + case VN_M_FT_CLAMP : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->clamp.min); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.red); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.green); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->clamp.blue); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->clamp.data); + break; + case VN_M_FT_MATRIX : + { + unsigned int i; + for(i = 0; i < 16; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->matrix.matrix[i]); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->matrix.data); + } + break; + case VN_M_FT_RAMP : + if(fragment->ramp.point_count == 0) + return; + { + unsigned int i, pos; + double last; + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->ramp.type); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)fragment->ramp.channel); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->ramp.mapping); + pos = buffer_pos; + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], fragment->ramp.point_count); + last = fragment->ramp.ramp[0].pos - 1; + for(i = 0; i < fragment->ramp.point_count && fragment->ramp.ramp[i].pos > last && i < 48; i++) + { + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].pos); + last = fragment->ramp.ramp[i].pos; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].red); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].green); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], fragment->ramp.ramp[i].blue); + } + if(i != fragment->ramp.point_count) + vnp_raw_pack_uint8(&buf[pos], i); + } + break; + case VN_M_FT_ANIMATION : + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->animation.label, 16); + break; + case VN_M_FT_ALTERNATIVE : + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->alternative.alt_a); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->alternative.alt_b); + break; + case VN_M_FT_OUTPUT : + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], fragment->output.label, 16); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->output.front); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], fragment->output.back); + break; + } + if(node_id == (uint32) ~0u || frag_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_m_fragment_destroy(VNodeID node_id, VNMFragmentID frag_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 68); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_m_fragment_destroy(node_id = %u frag_id = %u );\n", node_id, frag_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], frag_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || frag_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_m_fragment_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_m_fragment_create)(void *user_data, VNodeID node_id, VNMFragmentID frag_id, VNMFragmentType type, const VMatFrag *fragment); + VNodeID node_id; + VNMFragmentID frag_id; + VNMFragmentType type; + const VMatFrag *fragment; + + func_m_fragment_create = v_fs_get_user_func(68); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNMFragmentType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(type > VN_M_FT_OUTPUT) + printf("receive: verse_send_m_fragment_destroy(node_id = %u frag_id = %u ); callback = %p\n", node_id, frag_id, v_fs_get_alias_user_func(68)); + else + printf("receive: verse_send_m_fragment_create(node_id = %u frag_id = %u type = %u ); callback = %p\n", node_id, frag_id, type, v_fs_get_user_func(68)); +#endif + if(type <= VN_M_FT_OUTPUT) + { + VMatFrag frag; + uint8 temp; + switch(type) + { + case VN_M_FT_COLOR : + if(buffer_pos + 3 * 8 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.red); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.green); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.color.blue); + break; + case VN_M_FT_LIGHT : + if(buffer_pos + 13 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.light.type = (VNMLightType)temp; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.light.normal_falloff); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &frag.light.brdf); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_r, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_g, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.light.brdf_b, 16, buffer_length - buffer_pos); + break; + case VN_M_FT_REFLECTION : + if(buffer_pos + 8 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.reflection.normal_falloff); + break; + case VN_M_FT_TRANSPARENCY : + if(buffer_pos + 16 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.transparency.normal_falloff); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.transparency.refraction_index); + break; + case VN_M_FT_VOLUME : + if(buffer_pos + 32 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.diffusion); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_r); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_g); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.volume.col_b); + break; + case VN_M_FT_VIEW : + break; + case VN_M_FT_GEOMETRY : + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_r, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_g, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.geometry.layer_b, 16, buffer_length - buffer_pos); + break; + case VN_M_FT_TEXTURE : + if(buffer_pos + 10 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &frag.texture.bitmap); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_r, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_g, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.texture.layer_b, 16, buffer_length - buffer_pos); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.texture.filtered = (VNMNoiseType)temp; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.texture.mapping); + break; + case VN_M_FT_NOISE : + if(buffer_pos + 3 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.noise.type = (VNMNoiseType)temp; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.noise.mapping); + break; + case VN_M_FT_BLENDER : + if(buffer_pos + 7 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.blender.type = (VNMBlendType)temp; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.data_a); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.data_b); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.blender.control); + break; + case VN_M_FT_CLAMP : + if(buffer_pos + 27 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.clamp.min = (VNMBlendType)temp; + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.red); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.green); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.clamp.blue); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.clamp.data); + break; + case VN_M_FT_MATRIX : + if(buffer_pos + 8 * 16 + 2 > buffer_length) + return -1; + else + { + unsigned int i; + for(i = 0; i < 16; i++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.matrix.matrix[i]); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.matrix.data); + } + break; + case VN_M_FT_RAMP : + if(buffer_pos + 5 + 4 * 8 > buffer_length) + return -1; + else + { + unsigned int i, pos; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.ramp.type = (VNMRampType)temp; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &temp); + frag.ramp.channel = (VNMRampChannel)temp; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.ramp.mapping); + pos = buffer_pos; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &frag.ramp.point_count); + for(i = 0; i < frag.ramp.point_count && buffer_pos + 8 * 4 <= buffer_length && i < 48; i++) + { + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].pos); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].red); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].green); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &frag.ramp.ramp[i].blue); + }if(i != frag.ramp.point_count) + frag.ramp.point_count = i; + } + break; + case VN_M_FT_ANIMATION : + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.animation.label, 16, buffer_length - buffer_pos); + break; + case VN_M_FT_ALTERNATIVE : + if(buffer_pos + 4 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.alternative.alt_a); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.alternative.alt_b); + break; + case VN_M_FT_OUTPUT : + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], frag.output.label, 16, buffer_length - buffer_pos); + if(buffer_pos + 4 > buffer_length) + return -1; + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.output.front); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &frag.output.back); + break; + } + if(func_m_fragment_create != NULL) + func_m_fragment_create(v_fs_get_user_data(68), node_id, frag_id, type, &frag); + return buffer_pos; + } + + if(type > VN_M_FT_OUTPUT) + { + void (* alias_m_fragment_destroy)(void *user_data, VNodeID node_id, VNMFragmentID frag_id); + alias_m_fragment_destroy = v_fs_get_alias_user_func(68); + if(alias_m_fragment_destroy != NULL) + alias_m_fragment_destroy(v_fs_get_alias_user_data(68), node_id, frag_id); + return buffer_pos; + } + if(func_m_fragment_create != NULL) + func_m_fragment_create(v_fs_get_user_data(68), node_id, frag_id, (VNMFragmentType) type, fragment); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_o_node.c b/extern/verse/dist/v_gen_pack_o_node.c new file mode 100644 index 00000000000..5d60bafe1d0 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_o_node.c @@ -0,0 +1,1297 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_o_transform_pos_real32(VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 32); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_pos_real32(node_id = %u time_s = %u time_f = %u pos = %p speed = %p accelerate = %p drag_normal = %p drag = %f );\n", node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + { + unsigned char mask = 0; + unsigned int cmd; + cmd = buffer_pos++; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[0]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[1]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], pos[2]); + if(speed != NULL && (speed[0] > 0.0000001 || speed[0] < -0.0000001 || speed[1] > 0.0000001 || speed[1] < -0.0000001 || speed[2] > 0.0000001 || speed[2] < -0.0000001)) + { + mask |= 1; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[0]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[1]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], speed[2]); + } + if(accelerate != NULL && (accelerate[0] > 0.0000001 || accelerate[0] < -0.0000001 || accelerate[1] > 0.0000001 || accelerate[1] < -0.0000001 || accelerate[2] > 0.0000001 || accelerate[2] < -0.0000001)) + { + mask |= 2; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[0]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[1]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], accelerate[2]); + } + if(drag_normal != NULL && (drag > 0.0000001 || drag < -0.0000001) && (drag_normal[0] > 0.0000001 || drag_normal[0] < -0.0000001 || drag_normal[1] > 0.0000001 || drag_normal[1] < -0.0000001 || drag_normal[2] > 0.0000001 || drag_normal[2] < -0.0000001)) + { + mask |= 4; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[0]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[1]); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag_normal[2]); + } + if(drag > 0.0000001 || drag < -0.0000001) + { + mask |= 8; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag); + } + vnp_raw_pack_uint8(&buf[cmd], mask); + }if(FALSE) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_pos_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_pos_real32)(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag); + VNodeID node_id; + uint32 time_s; + uint32 time_f; + const real32 *pos; + const real32 *speed; + const real32 *accelerate; + const real32 *drag_normal; + real32 drag; + + func_o_transform_pos_real32 = v_fs_get_user_func(32); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_pos_real32(node_id = %u time_s = %u time_f = %u drag = %f ); callback = %p\n", node_id, time_s, time_f, drag, v_fs_get_user_func(32)); +#endif + { + float output[4][3]; + unsigned int i, j; + char mask, pow = 1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &output[0][j]); + for(i = 1; i < 4; i++) + { + if((mask & pow) != 0) + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &output[i][j]); + else + for(j = 0; j < 3; j++) + output[i][j] = 0; + pow *= 2; + } + if((mask & pow) != 0) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &drag); + else + drag = 0.0f; + if(func_o_transform_pos_real32 != NULL) + func_o_transform_pos_real32(v_fs_get_user_data(32), node_id, time_s, time_f, &output[0][0], &output[1][0], &output[2][0], &output[3][0], drag); + return buffer_pos; + } + + if(func_o_transform_pos_real32 != NULL) + func_o_transform_pos_real32(v_fs_get_user_data(32), node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); + + return buffer_pos; +} + +void verse_send_o_transform_rot_real32(VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 33); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_rot_real32(node_id = %u time_s = %u time_f = %u rot = %p speed = %p accelerate = %p drag_normal = %p drag = %f );\n", node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + { + uint8 mask = 0; + unsigned int maskpos; + maskpos = buffer_pos++; /* Remember location, and reserve a byte for the mask. */ + buffer_pos += vnp_pack_quat32(&buf[buffer_pos], rot); + if(v_quat32_valid(speed)) + { + mask |= 1; + buffer_pos += vnp_pack_quat32(&buf[buffer_pos], speed); + } + if(v_quat32_valid(accelerate)) + { + mask |= 2; + buffer_pos += vnp_pack_quat32(&buf[buffer_pos], accelerate); + } + if(v_quat32_valid(drag_normal)) + { + mask |= 4; + buffer_pos += vnp_pack_quat32(&buf[buffer_pos], drag_normal); + } + if(drag > 0.0000001 || drag < -0.0000001) + { + mask |= 8; + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag); + } + vnp_raw_pack_uint8(&buf[maskpos], mask); /* Write the mask into start of command. */ + } + if(FALSE) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], drag); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_rot_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_rot_real32)(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag); + VNodeID node_id; + uint32 time_s; + uint32 time_f; + const VNQuat32 *rot; + const VNQuat32 *speed; + const VNQuat32 *accelerate; + const VNQuat32 *drag_normal; + real32 drag; + + func_o_transform_rot_real32 = v_fs_get_user_func(33); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_rot_real32(node_id = %u time_s = %u time_f = %u drag = %f ); callback = %p\n", node_id, time_s, time_f, drag, v_fs_get_user_func(33)); +#endif + { + VNQuat32 trot, temp[3], *q[3]; + unsigned int i; + uint8 mask, test; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + buffer_pos += vnp_unpack_quat32(&buf[buffer_pos], &trot); + for(i = 0, test = 1; i < sizeof temp / sizeof *temp; i++, test <<= 1) + { + if(mask & test) /* Field present? */ + { + buffer_pos += vnp_unpack_quat32(&buf[buffer_pos], &temp[i]); + q[i] = &temp[i]; + } + else + q[i] = NULL; + } + if(mask & test) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &drag); + else + drag = 0.0; + if(func_o_transform_rot_real32 != NULL) + func_o_transform_rot_real32(v_fs_get_user_data(33), node_id, time_s, time_f, &trot, q[0], q[1], q[2], drag); + return buffer_pos; + } + + if(func_o_transform_rot_real32 != NULL) + func_o_transform_rot_real32(v_fs_get_user_data(33), node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); + + return buffer_pos; +} + +void verse_send_o_transform_scale_real32(VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_20);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 34); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_scale_real32(node_id = %u scale_x = %f scale_y = %f scale_z = %f );\n", node_id, scale_x, scale_y, scale_z); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], scale_x); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], scale_y); + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], scale_z); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_scale_real32(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_scale_real32)(void *user_data, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z); + VNodeID node_id; + real32 scale_x; + real32 scale_y; + real32 scale_z; + + func_o_transform_scale_real32 = v_fs_get_user_func(34); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &scale_x); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &scale_y); + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], &scale_z); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_scale_real32(node_id = %u scale_x = %f scale_y = %f scale_z = %f ); callback = %p\n", node_id, scale_x, scale_y, scale_z, v_fs_get_user_func(34)); +#endif + if(func_o_transform_scale_real32 != NULL) + func_o_transform_scale_real32(v_fs_get_user_data(34), node_id, scale_x, scale_y, scale_z); + + return buffer_pos; +} + +void verse_send_o_transform_pos_real64(VNodeID node_id, uint32 time_s, uint32 time_f, const real64 *pos, const real64 *speed, const real64 *accelerate, const real64 *drag_normal, real64 drag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 35); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_pos_real64(node_id = %u time_s = %u time_f = %u pos = %p speed = %p accelerate = %p drag_normal = %p drag = %f );\n", node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + { + unsigned char mask = 0; + unsigned int cmd; + cmd = buffer_pos++; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[2]); + if(speed != NULL && (speed[0] > 0.0000001 || speed[0] < -0.0000001 || speed[1] > 0.0000001 || speed[1] < -0.0000001 || speed[2] > 0.0000001 || speed[2] < -0.0000001)) + { + mask |= 1; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[2]); + } + if(accelerate != NULL && (accelerate[0] > 0.0000001 || accelerate[0] < -0.0000001 || accelerate[1] > 0.0000001 || accelerate[1] < -0.0000001 || accelerate[2] > 0.0000001 || accelerate[2] < -0.0000001)) + { + mask |= 2; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accelerate[2]); + } + if(drag_normal != NULL && (drag > 0.0000001 || drag < -0.0000001) && (drag_normal[0] > 0.0000001 || drag_normal[0] < -0.0000001 || drag_normal[1] > 0.0000001 || drag_normal[1] < -0.0000001 || drag_normal[2] > 0.0000001 || drag_normal[2] < -0.0000001)) + { + mask |= 4; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag_normal[2]); + } + if(drag > 0.0000001 || drag < -0.0000001) + { + mask |= 8; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag); + } + vnp_raw_pack_uint8(&buf[cmd], mask); + }if(FALSE) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_pos_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_pos_real64)(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real64 *pos, const real64 *speed, const real64 *accelerate, const real64 *drag_normal, real64 drag); + VNodeID node_id; + uint32 time_s; + uint32 time_f; + const real64 *pos; + const real64 *speed; + const real64 *accelerate; + const real64 *drag_normal; + real64 drag; + + func_o_transform_pos_real64 = v_fs_get_user_func(35); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_pos_real64(node_id = %u time_s = %u time_f = %u drag = %f ); callback = %p\n", node_id, time_s, time_f, drag, v_fs_get_user_func(35)); +#endif + { + double output[4][3]; + unsigned int i, j; + char mask, pow = 1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[0][j]); + for(i = 1; i < 4; i++) + { + if((mask & pow) != 0) + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[i][j]); + else + for(j = 0; j < 3; j++) + output[i][j] = 0; + pow *= 2; + } + if((mask & pow) != 0) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &drag); + else + drag = 0.0; + if(func_o_transform_pos_real64 != NULL) + func_o_transform_pos_real64(v_fs_get_user_data(35), node_id, time_s, time_f, &output[0][0], &output[1][0], &output[2][0], &output[3][0], drag); + return buffer_pos; + } + + if(func_o_transform_pos_real64 != NULL) + func_o_transform_pos_real64(v_fs_get_user_data(35), node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); + + return buffer_pos; +} + +void verse_send_o_transform_rot_real64(VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat64 *rot, const VNQuat64 *speed, const VNQuat64 *accelerate, const VNQuat64 *drag_normal, real64 drag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 36); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_rot_real64(node_id = %u time_s = %u time_f = %u rot = %p speed = %p accelerate = %p drag_normal = %p drag = %f );\n", node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + { + uint8 mask = 0; + unsigned int maskpos; + maskpos = buffer_pos++; /* Remember location, and reserve a byte for the mask. */ + buffer_pos += vnp_pack_quat64(&buf[buffer_pos], rot); + if(v_quat64_valid(speed)) + { + mask |= 1; + buffer_pos += vnp_pack_quat64(&buf[buffer_pos], speed); + } + if(v_quat64_valid(accelerate)) + { + mask |= 2; + buffer_pos += vnp_pack_quat64(&buf[buffer_pos], accelerate); + } + if(v_quat64_valid(drag_normal)) + { + mask |= 4; + buffer_pos += vnp_pack_quat64(&buf[buffer_pos], drag_normal); + } + if(drag > 0.0000001 || drag < -0.0000001) + { + mask |= 8; + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag); + } + vnp_raw_pack_uint8(&buf[maskpos], mask); /* Write the mask into start of command. */ + } + if(FALSE) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], drag); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_rot_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_rot_real64)(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat64 *rot, const VNQuat64 *speed, const VNQuat64 *accelerate, const VNQuat64 *drag_normal, real64 drag); + VNodeID node_id; + uint32 time_s; + uint32 time_f; + const VNQuat64 *rot; + const VNQuat64 *speed; + const VNQuat64 *accelerate; + const VNQuat64 *drag_normal; + real64 drag; + + func_o_transform_rot_real64 = v_fs_get_user_func(36); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_rot_real64(node_id = %u time_s = %u time_f = %u drag = %f ); callback = %p\n", node_id, time_s, time_f, drag, v_fs_get_user_func(36)); +#endif + { + VNQuat64 trot, temp[3], *q[3]; + unsigned int i; + uint8 mask, test; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + buffer_pos += vnp_unpack_quat64(&buf[buffer_pos], &trot); + for(i = 0, test = 1; i < sizeof temp / sizeof *temp; i++, test <<= 1) + { + if(mask & test) /* Field present? */ + { + buffer_pos += vnp_unpack_quat64(&buf[buffer_pos], &temp[i]); + q[i] = &temp[i]; + } + else + q[i] = NULL; + } + if(mask & test) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &drag); + else + drag = 0.0; + if(func_o_transform_rot_real64 != NULL) + func_o_transform_rot_real64(v_fs_get_user_data(36), node_id, time_s, time_f, &trot, q[0], q[1], q[2], drag); + return buffer_pos; + } + + if(func_o_transform_rot_real64 != NULL) + func_o_transform_rot_real64(v_fs_get_user_data(36), node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); + + return buffer_pos; +} + +void verse_send_o_transform_scale_real64(VNodeID node_id, real64 scale_x, real64 scale_y, real64 scale_z) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 37); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_scale_real64(node_id = %u scale_x = %f scale_y = %f scale_z = %f );\n", node_id, scale_x, scale_y, scale_z); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_x); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_y); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_z); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_scale_real64(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_transform_scale_real64)(void *user_data, VNodeID node_id, real64 scale_x, real64 scale_y, real64 scale_z); + VNodeID node_id; + real64 scale_x; + real64 scale_y; + real64 scale_z; + + func_o_transform_scale_real64 = v_fs_get_user_func(37); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &scale_x); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &scale_y); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &scale_z); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_transform_scale_real64(node_id = %u scale_x = %f scale_y = %f scale_z = %f ); callback = %p\n", node_id, scale_x, scale_y, scale_z, v_fs_get_user_func(37)); +#endif + if(func_o_transform_scale_real64 != NULL) + func_o_transform_scale_real64(v_fs_get_user_data(37), node_id, scale_x, scale_y, scale_z); + + return buffer_pos; +} + +void verse_send_o_transform_subscribe(VNodeID node_id, VNRealFormat type) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 38); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_subscribe(node_id = %u type = %u );\n", node_id, type); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_transform_unsubscribe(VNodeID node_id, VNRealFormat type) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 38); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_transform_unsubscribe(node_id = %u type = %u );\n", node_id, type); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_transform_subscribe(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_o_transform_subscribe)(void *user_data, VNodeID node_id, VNRealFormat type); + VNodeID node_id; + VNRealFormat type; + uint8 alias_bool; + + func_o_transform_subscribe = v_fs_get_user_func(38); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNRealFormat)enum_temp; + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_o_transform_unsubscribe(node_id = %u type = %u ); callback = %p\n", node_id, type, v_fs_get_alias_user_func(38)); + else + printf("receive: verse_send_o_transform_subscribe(node_id = %u type = %u ); callback = %p\n", node_id, type, v_fs_get_user_func(38)); +#endif + if(!alias_bool) + { + void (* alias_o_transform_unsubscribe)(void *user_data, VNodeID node_id, VNRealFormat type); + alias_o_transform_unsubscribe = v_fs_get_alias_user_func(38); + if(alias_o_transform_unsubscribe != NULL) + alias_o_transform_unsubscribe(v_fs_get_alias_user_data(38), node_id, (VNRealFormat)type); + return buffer_pos; + } + if(func_o_transform_subscribe != NULL) + func_o_transform_subscribe(v_fs_get_user_data(38), node_id, (VNRealFormat) type); + + return buffer_pos; +} + +void verse_send_o_light_set(VNodeID node_id, real64 light_r, real64 light_g, real64 light_b) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 39); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_light_set(node_id = %u light_r = %f light_g = %f light_b = %f );\n", node_id, light_r, light_g, light_b); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], light_r); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], light_g); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], light_b); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_light_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_light_set)(void *user_data, VNodeID node_id, real64 light_r, real64 light_g, real64 light_b); + VNodeID node_id; + real64 light_r; + real64 light_g; + real64 light_b; + + func_o_light_set = v_fs_get_user_func(39); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &light_r); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &light_g); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &light_b); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_light_set(node_id = %u light_r = %f light_g = %f light_b = %f ); callback = %p\n", node_id, light_r, light_g, light_b, v_fs_get_user_func(39)); +#endif + if(func_o_light_set != NULL) + func_o_light_set(v_fs_get_user_data(39), node_id, light_r, light_g, light_b); + + return buffer_pos; +} + +void verse_send_o_link_set(VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 40); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_link_set(node_id = %u link_id = %u link = %u label = %s target_id = %u );\n", node_id, link_id, link, label, target_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], link_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], link); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], label, 16); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], target_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || link_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_link_destroy(VNodeID node_id, uint16 link_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 40); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_link_destroy(node_id = %u link_id = %u );\n", node_id, link_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], link_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], -1); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || link_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_link_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_link_set)(void *user_data, VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id); + VNodeID node_id; + uint16 link_id; + VNodeID link; + char label[16]; + uint32 target_id; + uint8 alias_bool; + + func_o_link_set = v_fs_get_user_func(40); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &link_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &link); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], label, 16, buffer_length - buffer_pos); + if(buffer_length < 4 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &target_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_o_link_destroy(node_id = %u link_id = %u ); callback = %p\n", node_id, link_id, v_fs_get_alias_user_func(40)); + else + printf("receive: verse_send_o_link_set(node_id = %u link_id = %u link = %u label = %s target_id = %u ); callback = %p\n", node_id, link_id, link, label, target_id, v_fs_get_user_func(40)); +#endif + if(!alias_bool) + { + void (* alias_o_link_destroy)(void *user_data, VNodeID node_id, uint16 link_id); + alias_o_link_destroy = v_fs_get_alias_user_func(40); + if(alias_o_link_destroy != NULL) + alias_o_link_destroy(v_fs_get_alias_user_data(40), node_id, link_id); + return buffer_pos; + } + if(func_o_link_set != NULL) + func_o_link_set(v_fs_get_user_data(40), node_id, link_id, link, label, target_id); + + return buffer_pos; +} + +void verse_send_o_method_group_create(VNodeID node_id, uint16 group_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 41); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_group_create(node_id = %u group_id = %u name = %s );\n", node_id, group_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_method_group_destroy(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 41); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_group_destroy(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_method_group_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_method_group_create)(void *user_data, VNodeID node_id, uint16 group_id, const char *name); + VNodeID node_id; + uint16 group_id; + char name[16]; + + func_o_method_group_create = v_fs_get_user_func(41); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_o_method_group_destroy(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_alias_user_func(41)); + else + printf("receive: verse_send_o_method_group_create(node_id = %u group_id = %u name = %s ); callback = %p\n", node_id, group_id, name, v_fs_get_user_func(41)); +#endif + if(name[0] == 0) + { + void (* alias_o_method_group_destroy)(void *user_data, VNodeID node_id, uint16 group_id); + alias_o_method_group_destroy = v_fs_get_alias_user_func(41); + if(alias_o_method_group_destroy != NULL) + alias_o_method_group_destroy(v_fs_get_alias_user_data(41), node_id, group_id); + return buffer_pos; + } + if(func_o_method_group_create != NULL) + func_o_method_group_create(v_fs_get_user_data(41), node_id, group_id, name); + + return buffer_pos; +} + +void verse_send_o_method_group_subscribe(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 42); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_group_subscribe(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_method_group_unsubscribe(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 42); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_group_unsubscribe(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_method_group_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_method_group_subscribe)(void *user_data, VNodeID node_id, uint16 group_id); + VNodeID node_id; + uint16 group_id; + uint8 alias_bool; + + func_o_method_group_subscribe = v_fs_get_user_func(42); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_o_method_group_unsubscribe(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_alias_user_func(42)); + else + printf("receive: verse_send_o_method_group_subscribe(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_user_func(42)); +#endif + if(!alias_bool) + { + void (* alias_o_method_group_unsubscribe)(void *user_data, VNodeID node_id, uint16 group_id); + alias_o_method_group_unsubscribe = v_fs_get_alias_user_func(42); + if(alias_o_method_group_unsubscribe != NULL) + alias_o_method_group_unsubscribe(v_fs_get_alias_user_data(42), node_id, group_id); + return buffer_pos; + } + if(func_o_method_group_subscribe != NULL) + func_o_method_group_subscribe(v_fs_get_user_data(42), node_id, group_id); + + return buffer_pos; +} + +void verse_send_o_method_create(VNodeID node_id, uint16 group_id, uint16 method_id, const char *name, uint8 param_count, const VNOParamType *param_types, const char * *param_names) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 43); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_create(node_id = %u group_id = %u method_id = %u name = %s param_count = %u param_types = %p param_names = %p );\n", node_id, group_id, method_id, name, param_count, param_types, param_names); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], method_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 512); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], param_count); + { + unsigned int i, j, sum = 1; + for(i = 0; i < param_count; i++) + { + sum += 3; + for(j = 0; param_names[i][j] != 0; j++); + } + if(sum + buffer_pos > 1500) + return; + for(i = 0; i < param_count; i++) + { + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], param_types[i]); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], param_names[i], 1500 - buffer_pos); + } + } + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u || method_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 9); + else + v_cmd_buf_set_address_size(head, 9); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_o_method_destroy(VNodeID node_id, uint16 group_id, uint16 method_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 43); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_destroy(node_id = %u group_id = %u method_id = %u );\n", node_id, group_id, method_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], method_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 512); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], -1); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u || method_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 9); + else + v_cmd_buf_set_address_size(head, 9); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_method_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_method_create)(void *user_data, VNodeID node_id, uint16 group_id, uint16 method_id, const char *name, uint8 param_count, const VNOParamType *param_types, const char * *param_names); + VNodeID node_id; + uint16 group_id; + uint16 method_id; + char name[512]; + uint8 param_count; + const VNOParamType *param_types; + const char * *param_names; + + func_o_method_create = v_fs_get_user_func(43); + if(buffer_length < 8) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &method_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 512, buffer_length - buffer_pos); + if(buffer_length < 1 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], ¶m_count); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_o_method_destroy(node_id = %u group_id = %u method_id = %u ); callback = %p\n", node_id, group_id, method_id, v_fs_get_alias_user_func(43)); + else + printf("receive: verse_send_o_method_create(node_id = %u group_id = %u method_id = %u name = %s param_count = %u ); callback = %p\n", node_id, group_id, method_id, name, param_count, v_fs_get_user_func(43)); +#endif + if(param_count != 255) + { + unsigned int i, size, text = 0; + VNOParamType types[256]; + uint8 t; + char name_buf[1500], *names[256]; + for(i = 0; i < param_count; i++) + { + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &t); + types[i] = t; + names[i] = &name_buf[text]; + size = vnp_raw_unpack_string(&buf[buffer_pos], names[i], 1500 - buffer_pos, buffer_length - buffer_pos); + buffer_pos += size; + text += size; + } + if(func_o_method_create != NULL) + func_o_method_create(v_fs_get_user_data(43), node_id, group_id, method_id, name, param_count, types, (const char **) names); + return buffer_pos; + } + + if(name[0] == 0) + { + void (* alias_o_method_destroy)(void *user_data, VNodeID node_id, uint16 group_id, uint16 method_id); + alias_o_method_destroy = v_fs_get_alias_user_func(43); + if(alias_o_method_destroy != NULL) + alias_o_method_destroy(v_fs_get_alias_user_data(43), node_id, group_id, method_id); + return buffer_pos; + } + if(func_o_method_create != NULL) + func_o_method_create(v_fs_get_user_data(43), node_id, group_id, method_id, name, param_count, param_types, param_names); + + return buffer_pos; +} + +void verse_send_o_method_call(VNodeID node_id, uint16 group_id, uint16 method_id, VNodeID sender, const VNOPackedParams *params) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 44); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_method_call(node_id = %u group_id = %u method_id = %u sender = %u params = %p );\n", node_id, group_id, method_id, sender, params); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], method_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], sender); + { + unsigned int i; + uint16 size; + vnp_raw_unpack_uint16(params, &size); + for(i = 0; i < size; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((uint8 *)params)[i]); + free((void *) params); /* Drop the const. */ + } + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_method_call(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_method_call)(void *user_data, VNodeID node_id, uint16 group_id, uint16 method_id, VNodeID sender, const VNOPackedParams *params); + VNodeID node_id; + uint16 group_id; + uint16 method_id; + VNodeID sender; + const VNOPackedParams *params; + + func_o_method_call = v_fs_get_user_func(44); + if(buffer_length < 12) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &method_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &sender); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_method_call(node_id = %u group_id = %u method_id = %u sender = %u ); callback = %p\n", node_id, group_id, method_id, sender, v_fs_get_user_func(44)); +#endif + { + unsigned int i; + uint8 par[1500]; + uint16 size; + vnp_raw_unpack_uint16(&buf[buffer_pos], &size); + for(i = 0; i < size; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &par[i]); + if(func_o_method_call != NULL) + func_o_method_call(v_fs_get_user_data(44), node_id, group_id, method_id, sender, par); + return buffer_pos; + } + + if(func_o_method_call != NULL) + func_o_method_call(v_fs_get_user_data(44), node_id, group_id, method_id, sender, params); + + return buffer_pos; +} + +void verse_send_o_anim_run(VNodeID node_id, uint16 link_id, uint32 time_s, uint32 time_f, uint8 dimensions, const real64 *pos, const real64 *speed, const real64 *accel, const real64 *scale, const real64 *scale_speed) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 45); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_anim_run(node_id = %u link_id = %u time_s = %u time_f = %u dimensions = %u pos = %p speed = %p accel = %p scale = %p scale_speed = %p );\n", node_id, link_id, time_s, time_f, dimensions, pos, speed, accel, scale, scale_speed); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], link_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_s); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], time_f); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], dimensions); + { + unsigned char mask = 0; + unsigned int cmd, i; + cmd = buffer_pos++; + if(dimensions > 4) + dimensions = 4; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos[i]); + if(speed != NULL) + { + mask |= 1; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], speed[i]); + } + if(accel != NULL) + { + mask |= 2; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], accel[i]); + } + if(scale != NULL) + { + mask |= 3; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale[i]); + } + if(scale_speed != NULL) + { + mask |= 4; + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], scale_speed[i]); + } + vnp_raw_pack_uint8(&buf[cmd], mask); + } + if(node_id == (uint32) ~0u || link_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_anim_run(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_anim_run)(void *user_data, VNodeID node_id, uint16 link_id, uint32 time_s, uint32 time_f, uint8 dimensions, const real64 *pos, const real64 *speed, const real64 *accel, const real64 *scale, const real64 *scale_speed); + VNodeID node_id; + uint16 link_id; + uint32 time_s; + uint32 time_f; + uint8 dimensions; + const real64 *pos; + const real64 *speed; + const real64 *accel; + const real64 *scale; + const real64 *scale_speed; + + func_o_anim_run = v_fs_get_user_func(45); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &link_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_s); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &time_f); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &dimensions); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_anim_run(node_id = %u link_id = %u time_s = %u time_f = %u dimensions = %u ); callback = %p\n", node_id, link_id, time_s, time_f, dimensions, v_fs_get_user_func(45)); +#endif + { + double output[5][4]; + unsigned int i, j; + char mask, pow = 1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &mask); + if(dimensions > 4) + dimensions = 4; + for(j = 0; j < dimensions; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[0][j]); + for(i = 1; i < 5; i++) + { + if((mask & pow) != 0) + for(j = 0; j < dimensions; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &output[i][j]); + else + for(j = 0; j < dimensions; j++) + output[i][j] = 0; + pow *= 2; + } + if(func_o_anim_run != NULL) + func_o_anim_run(v_fs_get_user_data(45), node_id, link_id, time_s, time_f, dimensions, &output[0][0], &output[1][0], &output[2][0], &output[3][0], &output[4][0]); + return buffer_pos; + } + + if(func_o_anim_run != NULL) + func_o_anim_run(v_fs_get_user_data(45), node_id, link_id, time_s, time_f, dimensions, pos, speed, accel, scale, scale_speed); + + return buffer_pos; +} + +void verse_send_o_hide(VNodeID node_id, uint8 hidden) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 46); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_o_hide(node_id = %u hidden = %u );\n", node_id, hidden); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], hidden); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_o_hide(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_o_hide)(void *user_data, VNodeID node_id, uint8 hidden); + VNodeID node_id; + uint8 hidden; + + func_o_hide = v_fs_get_user_func(46); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &hidden); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_o_hide(node_id = %u hidden = %u ); callback = %p\n", node_id, hidden, v_fs_get_user_func(46)); +#endif + if(func_o_hide != NULL) + func_o_hide(v_fs_get_user_data(46), node_id, hidden); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_s_node.c b/extern/verse/dist/v_gen_pack_s_node.c new file mode 100644 index 00000000000..6a9f4a05a0b --- /dev/null +++ b/extern/verse/dist/v_gen_pack_s_node.c @@ -0,0 +1,711 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_packet_ack(uint32 packet_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 7); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], packet_id); + v_cmd_buf_set_unique_address_size(head, buffer_pos); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_ack_nak_buf(v_con_get_network_queue(), head); + return; + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_packet_ack(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_packet_ack)(void *user_data, uint32 packet_id); + uint32 packet_id; + + func_packet_ack = v_fs_get_user_func(7); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &packet_id); +#if defined V_PRINT_RECEIVE_COMMANDS +#endif + if(func_packet_ack != NULL) + func_packet_ack(v_fs_get_user_data(7), packet_id); + + return buffer_pos; +} + +void verse_send_packet_nak(uint32 packet_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 8); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], packet_id); + v_cmd_buf_set_unique_address_size(head, buffer_pos); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_ack_nak_buf(v_con_get_network_queue(), head); + return; + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_packet_nak(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_packet_nak)(void *user_data, uint32 packet_id); + uint32 packet_id; + + func_packet_nak = v_fs_get_user_func(8); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &packet_id); +#if defined V_PRINT_RECEIVE_COMMANDS +#endif + if(func_packet_nak != NULL) + func_packet_nak(v_fs_get_user_data(8), packet_id); + + return buffer_pos; +} + +void verse_send_node_index_subscribe(uint32 mask) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 9); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_index_subscribe(mask = %u );\n", mask); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], mask); + if(mask == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_node_index_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_node_index_subscribe)(void *user_data, uint32 mask); + uint32 mask; + + func_node_index_subscribe = v_fs_get_user_func(9); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &mask); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_node_index_subscribe(mask = %u ); callback = %p\n", mask, v_fs_get_user_func(9)); +#endif + if(func_node_index_subscribe != NULL) + func_node_index_subscribe(v_fs_get_user_data(9), mask); + + return buffer_pos; +} + +void verse_send_node_create(VNodeID node_id, VNodeType type, VNodeOwner owner) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 10); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_create(node_id = %u type = %u owner = %u );\n", node_id, type, owner); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)owner); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_node_destroy(VNodeID node_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 10); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_destroy(node_id = %u );\n", node_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_node_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_node_create)(void *user_data, VNodeID node_id, VNodeType type, VNodeOwner owner); + VNodeID node_id; + VNodeType type; + VNodeOwner owner; + + func_node_create = v_fs_get_user_func(10); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNodeType)enum_temp; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + owner = (VNodeOwner)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(owner == (uint8) ~0u || type >= V_NT_NUM_TYPES) + printf("receive: verse_send_node_destroy(node_id = %u ); callback = %p\n", node_id, v_fs_get_alias_user_func(10)); + else + printf("receive: verse_send_node_create(node_id = %u type = %u owner = %u ); callback = %p\n", node_id, type, owner, v_fs_get_user_func(10)); +#endif + if(owner == (uint8) ~0u || type >= V_NT_NUM_TYPES) + { + void (* alias_node_destroy)(void *user_data, VNodeID node_id); + alias_node_destroy = v_fs_get_alias_user_func(10); + if(alias_node_destroy != NULL) + alias_node_destroy(v_fs_get_alias_user_data(10), node_id); + return buffer_pos; + } + if(func_node_create != NULL) + func_node_create(v_fs_get_user_data(10), node_id, (VNodeType) type, (VNodeOwner) owner); + + return buffer_pos; +} + +void verse_send_node_subscribe(VNodeID node_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 11); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_subscribe(node_id = %u );\n", node_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_node_unsubscribe(VNodeID node_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 11); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_unsubscribe(node_id = %u );\n", node_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_node_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_node_subscribe)(void *user_data, VNodeID node_id); + VNodeID node_id; + uint8 alias_bool; + + func_node_subscribe = v_fs_get_user_func(11); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_node_unsubscribe(node_id = %u ); callback = %p\n", node_id, v_fs_get_alias_user_func(11)); + else + printf("receive: verse_send_node_subscribe(node_id = %u ); callback = %p\n", node_id, v_fs_get_user_func(11)); +#endif + if(!alias_bool) + { + void (* alias_node_unsubscribe)(void *user_data, VNodeID node_id); + alias_node_unsubscribe = v_fs_get_alias_user_func(11); + if(alias_node_unsubscribe != NULL) + alias_node_unsubscribe(v_fs_get_alias_user_data(11), node_id); + return buffer_pos; + } + if(func_node_subscribe != NULL) + func_node_subscribe(v_fs_get_user_data(11), node_id); + + return buffer_pos; +} + +void verse_send_tag_group_create(VNodeID node_id, uint16 group_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 16); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_group_create(node_id = %u group_id = %u name = %s );\n", node_id, group_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_tag_group_destroy(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 16); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_group_destroy(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_tag_group_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_tag_group_create)(void *user_data, VNodeID node_id, uint16 group_id, const char *name); + VNodeID node_id; + uint16 group_id; + char name[16]; + + func_tag_group_create = v_fs_get_user_func(16); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_tag_group_destroy(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_alias_user_func(16)); + else + printf("receive: verse_send_tag_group_create(node_id = %u group_id = %u name = %s ); callback = %p\n", node_id, group_id, name, v_fs_get_user_func(16)); +#endif + if(name[0] == 0) + { + void (* alias_tag_group_destroy)(void *user_data, VNodeID node_id, uint16 group_id); + alias_tag_group_destroy = v_fs_get_alias_user_func(16); + if(alias_tag_group_destroy != NULL) + alias_tag_group_destroy(v_fs_get_alias_user_data(16), node_id, group_id); + return buffer_pos; + } + if(func_tag_group_create != NULL) + func_tag_group_create(v_fs_get_user_data(16), node_id, group_id, name); + + return buffer_pos; +} + +void verse_send_tag_group_subscribe(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 17); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_group_subscribe(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_tag_group_unsubscribe(VNodeID node_id, uint16 group_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 17); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_group_unsubscribe(node_id = %u group_id = %u );\n", node_id, group_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_tag_group_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_tag_group_subscribe)(void *user_data, VNodeID node_id, uint16 group_id); + VNodeID node_id; + uint16 group_id; + uint8 alias_bool; + + func_tag_group_subscribe = v_fs_get_user_func(17); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_tag_group_unsubscribe(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_alias_user_func(17)); + else + printf("receive: verse_send_tag_group_subscribe(node_id = %u group_id = %u ); callback = %p\n", node_id, group_id, v_fs_get_user_func(17)); +#endif + if(!alias_bool) + { + void (* alias_tag_group_unsubscribe)(void *user_data, VNodeID node_id, uint16 group_id); + alias_tag_group_unsubscribe = v_fs_get_alias_user_func(17); + if(alias_tag_group_unsubscribe != NULL) + alias_tag_group_unsubscribe(v_fs_get_alias_user_data(17), node_id, group_id); + return buffer_pos; + } + if(func_tag_group_subscribe != NULL) + func_tag_group_subscribe(v_fs_get_user_data(17), node_id, group_id); + + return buffer_pos; +} + +void verse_send_tag_create(VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 18); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_create(node_id = %u group_id = %u tag_id = %u name = %s type = %u tag = %p );\n", node_id, group_id, tag_id, name, type, tag); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], tag_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + if(type > VN_TAG_BLOB) + { + v_cmd_buf_free(head); + return; + } + switch(type) + { + case VN_TAG_BOOLEAN : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((VNTag *)tag)->vboolean); + break; + case VN_TAG_UINT32 : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vuint32); + break; + case VN_TAG_REAL64 : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64); + break; + case VN_TAG_STRING : + { + unsigned int i; + for(i = 0; ((VNTag *)tag)->vstring[i] != 0 && i < VN_TAG_MAX_BLOB_SIZE; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((VNTag *)tag)->vstring[i]); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0); + } + break; + case VN_TAG_REAL64_VEC3 : + { + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[0]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[1]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], ((VNTag *)tag)->vreal64_vec3[2]); + } + break; + case VN_TAG_LINK : + { + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vlink); + } + break; + case VN_TAG_ANIMATION : + { + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.curve); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.start); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], ((VNTag *)tag)->vanimation.end); + } + break; + case VN_TAG_BLOB : + { + unsigned int i; + if(((VNTag *)tag)->vblob.size > VN_TAG_MAX_BLOB_SIZE) + ((VNTag *)tag)->vblob.size = VN_TAG_MAX_BLOB_SIZE; + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], ((VNTag *)tag)->vblob.size); + for(i = 0; i < ((VNTag *)tag)->vblob.size; i++) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], ((uint8 *)((VNTag *)tag)->vblob.blob)[i]); + } + break; + default : + ; + } + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u || tag_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 9); + else + v_cmd_buf_set_address_size(head, 9); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_tag_destroy(VNodeID node_id, uint16 group_id, uint16 tag_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 18); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_tag_destroy(node_id = %u group_id = %u tag_id = %u );\n", node_id, group_id, tag_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], group_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], tag_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)-1); + if(node_id == (uint32) ~0u || group_id == (uint16) ~0u || tag_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 9); + else + v_cmd_buf_set_address_size(head, 9); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_tag_create(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_tag_create)(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); + VNodeID node_id; + uint16 group_id; + uint16 tag_id; + char name[16]; + VNTagType type; + const VNTag *tag; + + func_tag_create = v_fs_get_user_func(18); + if(buffer_length < 8) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &group_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tag_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); + if(buffer_length < 1 + buffer_pos) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNTagType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + if(type >= VN_TAG_TYPE_COUNT) + printf("receive: verse_send_tag_destroy(node_id = %u group_id = %u tag_id = %u ); callback = %p\n", node_id, group_id, tag_id, v_fs_get_alias_user_func(18)); + else + printf("receive: verse_send_tag_create(node_id = %u group_id = %u tag_id = %u name = %s type = %u ); callback = %p\n", node_id, group_id, tag_id, name, type, v_fs_get_user_func(18)); +#endif + if(type < VN_TAG_TYPE_COUNT) + { + VNTag tag; + unsigned int i; + char string[VN_TAG_MAX_BLOB_SIZE]; + switch(type) + { + case VN_TAG_BOOLEAN : + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &tag.vboolean); + break; + case VN_TAG_UINT32 : + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vuint32); + break; + case VN_TAG_REAL64 : + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64); + break; + case VN_TAG_STRING : + { + tag.vstring = string; + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], string, VN_TAG_MAX_BLOB_SIZE, buffer_length - buffer_pos); + } + break; + case VN_TAG_REAL64_VEC3 : + { + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[0]); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[1]); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &tag.vreal64_vec3[2]); + } + break; + case VN_TAG_LINK : + { + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vlink); + } + break; + case VN_TAG_ANIMATION : + { + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.curve); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.start); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &tag.vanimation.end); + } + break; + case VN_TAG_BLOB : + { + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tag.vblob.size); + if(tag.vblob.size > VN_TAG_MAX_BLOB_SIZE) + tag.vblob.size = VN_TAG_MAX_BLOB_SIZE; + tag.vblob.blob = string; + for(i = 0; i < tag.vblob.size; i++) + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &string[i]); + } + break; + default : + ; + } + if(func_tag_create != NULL) + func_tag_create(v_fs_get_user_data(18), node_id, group_id, tag_id, name, type, &tag); + return buffer_pos; + } + + if(type >= VN_TAG_TYPE_COUNT) + { + void (* alias_tag_destroy)(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id); + alias_tag_destroy = v_fs_get_alias_user_func(18); + if(alias_tag_destroy != NULL) + alias_tag_destroy(v_fs_get_alias_user_data(18), node_id, group_id, tag_id); + return buffer_pos; + } + if(func_tag_create != NULL) + func_tag_create(v_fs_get_user_data(18), node_id, group_id, tag_id, name, (VNTagType) type, tag); + + return buffer_pos; +} + +void verse_send_node_name_set(VNodeID node_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 19); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_node_name_set(node_id = %u name = %s );\n", node_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 512); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_node_name_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_node_name_set)(void *user_data, VNodeID node_id, const char *name); + VNodeID node_id; + char name[512]; + + func_node_name_set = v_fs_get_user_func(19); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 512, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_node_name_set(node_id = %u name = %s ); callback = %p\n", node_id, name, v_fs_get_user_func(19)); +#endif + if(func_node_name_set != NULL) + func_node_name_set(v_fs_get_user_data(19), node_id, name); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_pack_t_node.c b/extern/verse/dist/v_gen_pack_t_node.c new file mode 100644 index 00000000000..0cfbf8b7f21 --- /dev/null +++ b/extern/verse/dist/v_gen_pack_t_node.c @@ -0,0 +1,226 @@ +/* +** This is automatically generated source code -- do not edit. +** Changes are affected either by editing the corresponding protocol +** definition file (v_cmd_def_X.c where X=node type), or by editing +** the code generator itself, in v_cmd_gen.c. +*/ + +#include +#include + +#include "v_cmd_gen.h" +#if !defined(V_GENERATE_FUNC_MODE) +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_util.h" + +void verse_send_t_language_set(VNodeID node_id, const char *language) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 96); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_language_set(node_id = %u language = %s );\n", node_id, language); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], language, 512); + if(node_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 5); + else + v_cmd_buf_set_address_size(head, 5); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_t_language_set(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_t_language_set)(void *user_data, VNodeID node_id, const char *language); + VNodeID node_id; + char language[512]; + + func_t_language_set = v_fs_get_user_func(96); + if(buffer_length < 4) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], language, 512, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_t_language_set(node_id = %u language = %s ); callback = %p\n", node_id, language, v_fs_get_user_func(96)); +#endif + if(func_t_language_set != NULL) + func_t_language_set(v_fs_get_user_data(96), node_id, language); + + return buffer_pos; +} + +void verse_send_t_buffer_create(VNodeID node_id, VBufferID buffer_id, const char *name) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 97); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_buffer_create(node_id = %u buffer_id = %u name = %s );\n", node_id, buffer_id, name); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], name, 16); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_t_buffer_destroy(VNodeID node_id, VBufferID buffer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 97); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_buffer_destroy(node_id = %u buffer_id = %u );\n", node_id, buffer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], NULL, 16); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_t_buffer_create(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_t_buffer_create)(void *user_data, VNodeID node_id, VBufferID buffer_id, const char *name); + VNodeID node_id; + VBufferID buffer_id; + char name[16]; + + func_t_buffer_create = v_fs_get_user_func(97); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &buffer_id); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], name, 16, buffer_length - buffer_pos); +#if defined V_PRINT_RECEIVE_COMMANDS + if(name[0] == 0) + printf("receive: verse_send_t_buffer_destroy(node_id = %u buffer_id = %u ); callback = %p\n", node_id, buffer_id, v_fs_get_alias_user_func(97)); + else + printf("receive: verse_send_t_buffer_create(node_id = %u buffer_id = %u name = %s ); callback = %p\n", node_id, buffer_id, name, v_fs_get_user_func(97)); +#endif + if(name[0] == 0) + { + void (* alias_t_buffer_destroy)(void *user_data, VNodeID node_id, VBufferID buffer_id); + alias_t_buffer_destroy = v_fs_get_alias_user_func(97); + if(alias_t_buffer_destroy != NULL) + alias_t_buffer_destroy(v_fs_get_alias_user_data(97), node_id, buffer_id); + return buffer_pos; + } + if(func_t_buffer_create != NULL) + func_t_buffer_create(v_fs_get_user_data(97), node_id, buffer_id, name); + + return buffer_pos; +} + +void verse_send_t_buffer_subscribe(VNodeID node_id, VBufferID buffer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 98); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_buffer_subscribe(node_id = %u buffer_id = %u );\n", node_id, buffer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], TRUE); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_t_buffer_unsubscribe(VNodeID node_id, VBufferID buffer_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_10);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 98); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_buffer_unsubscribe(node_id = %u buffer_id = %u );\n", node_id, buffer_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], FALSE); + if(node_id == (uint32) ~0u || buffer_id == (uint16) ~0u) + v_cmd_buf_set_unique_address_size(head, 7); + else + v_cmd_buf_set_address_size(head, 7); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_t_buffer_subscribe(const char *buf, size_t buffer_length) +{ + unsigned int buffer_pos = 0; + void (* func_t_buffer_subscribe)(void *user_data, VNodeID node_id, VBufferID buffer_id); + VNodeID node_id; + VBufferID buffer_id; + uint8 alias_bool; + + func_t_buffer_subscribe = v_fs_get_user_func(98); + if(buffer_length < 6) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &buffer_id); + if(buffer_length < buffer_pos + 1) + return -1; + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &alias_bool); +#if defined V_PRINT_RECEIVE_COMMANDS + if(!alias_bool) + printf("receive: verse_send_t_buffer_unsubscribe(node_id = %u buffer_id = %u ); callback = %p\n", node_id, buffer_id, v_fs_get_alias_user_func(98)); + else + printf("receive: verse_send_t_buffer_subscribe(node_id = %u buffer_id = %u ); callback = %p\n", node_id, buffer_id, v_fs_get_user_func(98)); +#endif + if(!alias_bool) + { + void (* alias_t_buffer_unsubscribe)(void *user_data, VNodeID node_id, VBufferID buffer_id); + alias_t_buffer_unsubscribe = v_fs_get_alias_user_func(98); + if(alias_t_buffer_unsubscribe != NULL) + alias_t_buffer_unsubscribe(v_fs_get_alias_user_data(98), node_id, buffer_id); + return buffer_pos; + } + if(func_t_buffer_subscribe != NULL) + func_t_buffer_subscribe(v_fs_get_user_data(98), node_id, buffer_id); + + return buffer_pos; +} + +#endif + diff --git a/extern/verse/dist/v_gen_unpack_func.h b/extern/verse/dist/v_gen_unpack_func.h new file mode 100644 index 00000000000..462777608c7 --- /dev/null +++ b/extern/verse/dist/v_gen_unpack_func.h @@ -0,0 +1,63 @@ +extern unsigned int v_unpack_connect(const char *data, size_t length); +extern unsigned int v_unpack_connect_accept(const char *data, size_t length); +extern unsigned int v_unpack_connect_terminate(const char *data, size_t length); +extern unsigned int v_unpack_ping(const char *data, size_t length); +extern unsigned int v_unpack_packet_ack(const char *data, size_t length); +extern unsigned int v_unpack_packet_nak(const char *data, size_t length); +extern unsigned int v_unpack_node_index_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_node_create(const char *data, size_t length); +extern unsigned int v_unpack_node_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_tag_group_create(const char *data, size_t length); +extern unsigned int v_unpack_tag_group_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_tag_create(const char *data, size_t length); +extern unsigned int v_unpack_node_name_set(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_pos_real32(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_rot_real32(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_scale_real32(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_pos_real64(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_rot_real64(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_scale_real64(const char *data, size_t length); +extern unsigned int v_unpack_o_transform_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_o_light_set(const char *data, size_t length); +extern unsigned int v_unpack_o_link_set(const char *data, size_t length); +extern unsigned int v_unpack_o_method_group_create(const char *data, size_t length); +extern unsigned int v_unpack_o_method_group_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_o_method_create(const char *data, size_t length); +extern unsigned int v_unpack_o_method_call(const char *data, size_t length); +extern unsigned int v_unpack_o_anim_run(const char *data, size_t length); +extern unsigned int v_unpack_o_hide(const char *data, size_t length); +extern unsigned int v_unpack_g_layer_create(const char *data, size_t length); +extern unsigned int v_unpack_g_layer_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_xyz_real32(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_xyz_real64(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_uint32(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_real64(const char *data, size_t length); +extern unsigned int v_unpack_g_vertex_set_real32(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_corner_uint32(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_corner_real64(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_corner_real32(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_face_uint8(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_face_uint32(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_face_real64(const char *data, size_t length); +extern unsigned int v_unpack_g_polygon_set_face_real32(const char *data, size_t length); +extern unsigned int v_unpack_g_crease_set_vertex(const char *data, size_t length); +extern unsigned int v_unpack_g_crease_set_edge(const char *data, size_t length); +extern unsigned int v_unpack_g_bone_create(const char *data, size_t length); +extern unsigned int v_unpack_m_fragment_create(const char *data, size_t length); +extern unsigned int v_unpack_b_dimensions_set(const char *data, size_t length); +extern unsigned int v_unpack_b_layer_create(const char *data, size_t length); +extern unsigned int v_unpack_b_layer_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_b_tile_set(const char *data, size_t length); +extern unsigned int v_unpack_t_language_set(const char *data, size_t length); +extern unsigned int v_unpack_t_buffer_create(const char *data, size_t length); +extern unsigned int v_unpack_t_buffer_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_t_text_set(const char *data, size_t length); +extern unsigned int v_unpack_c_curve_create(const char *data, size_t length); +extern unsigned int v_unpack_c_curve_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_c_key_set(const char *data, size_t length); +extern unsigned int v_unpack_a_buffer_create(const char *data, size_t length); +extern unsigned int v_unpack_a_buffer_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_a_block_set(const char *data, size_t length); +extern unsigned int v_unpack_a_stream_create(const char *data, size_t length); +extern unsigned int v_unpack_a_stream_subscribe(const char *data, size_t length); +extern unsigned int v_unpack_a_stream(const char *data, size_t length); diff --git a/extern/verse/dist/v_gen_unpack_funcs.h b/extern/verse/dist/v_gen_unpack_funcs.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/extern/verse/dist/v_internal_verse.h b/extern/verse/dist/v_internal_verse.h new file mode 100644 index 00000000000..ce838351437 --- /dev/null +++ b/extern/verse/dist/v_internal_verse.h @@ -0,0 +1,2 @@ +extern void verse_send_packet_ack(uint32 packet_id); +extern void verse_send_packet_nak(uint32 packet_id); diff --git a/extern/verse/dist/v_man_pack_node.c b/extern/verse/dist/v_man_pack_node.c new file mode 100644 index 00000000000..cc85c4383df --- /dev/null +++ b/extern/verse/dist/v_man_pack_node.c @@ -0,0 +1,498 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_cmd_buf.h" +#include "v_network_out_que.h" +#include "v_network.h" +#include "v_connection.h" +#include "v_encryption.h" + +unsigned int v_unpack_connect(const char *buf, unsigned int buffer_length) +{ + return -1; /* this command is illegal to send */ +} + +unsigned int v_unpack_connect_accept(const char *buf, unsigned int buffer_length) +{ + return -1; /* this command is illegal to send */ +} + +extern void v_callback_connect_terminate(const char *bye); + +unsigned int v_unpack_connect_terminate(const char *buf, unsigned int buffer_length) +{ + unsigned int buffer_pos = 0; + char bye[512]; + + buffer_pos = vnp_raw_unpack_string(buf, bye, sizeof bye, buffer_length); + v_callback_connect_terminate(bye); + + return buffer_pos; +} + +static unsigned int pack_b_tile_set_head(VCMDBufHead *head, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile) +{ + unsigned int buffer_pos = 0; + uint8 *buf; + buf = ((VCMDBuffer30 *)head)->buf; + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 83); /* Pack the command. */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_b_tile_set(node_id = %u layer_id = %u tile_x = %u tile_y = %u z = %u type = %u tile = %p );\n", node_id, layer_id, tile_x, tile_y, z, type, tile); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], layer_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], tile_x); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], tile_y); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], z); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], (uint8)type); + return buffer_pos; + v_cmd_buf_set_address_size(head, 13); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_b_tile_set(VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + + switch(type) + { + case VN_B_LAYER_UINT1 : + head = v_cmd_buf_allocate(VCMDBS_30);/* Allocating the buffer */ + buf = ((VCMDBuffer30 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_uint8_vector(&buf[buffer_pos], tile->vuint1, VN_B_TILE_SIZE * VN_B_TILE_SIZE / 8); + break; + case VN_B_LAYER_UINT8 : + head = v_cmd_buf_allocate(VCMDBS_80);/* Allocating the buffer */ + buf = ((VCMDBuffer80 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_uint8_vector(&buf[buffer_pos], tile->vuint8, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_UINT16 : + head = v_cmd_buf_allocate(VCMDBS_160);/* Allocating the buffer */ + buf = ((VCMDBuffer160 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_uint16_vector(&buf[buffer_pos], tile->vuint16, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_REAL32 : + head = v_cmd_buf_allocate(VCMDBS_320);/* Allocating the buffer */ + buf = ((VCMDBuffer320 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_real32_vector(&buf[buffer_pos], tile->vreal32, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_REAL64 : + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + buffer_pos += pack_b_tile_set_head(head, node_id, layer_id, tile_x, tile_y, z, type, tile); + buffer_pos += vnp_raw_pack_real64_vector(&buf[buffer_pos], tile->vreal64, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + default: + head = NULL; + } + v_cmd_buf_set_address_size(head, 13); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_b_tile_set(const char *buf, size_t buffer_length) +{ + uint8 enum_temp; + unsigned int buffer_pos = 0; + void (* func_b_tile_set)(void *user_data, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile); + VNodeID node_id; + VLayerID layer_id; + uint16 tile_x; + uint16 tile_y; + uint16 z; + VNBLayerType type; + const VNBTile *tile; + + func_b_tile_set = v_fs_get_user_func(83); + if(buffer_length < 12) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &layer_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tile_x); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &tile_y); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &z); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &enum_temp); + type = (VNBLayerType)enum_temp; +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_b_tile_set(node_id = %u layer_id = %u tile_x = %u tile_y = %u z = %u type = %u ); callback = %p\n", node_id, layer_id, tile_x, tile_y, z, type, v_fs_get_user_func(83)); +#endif + { + VNBTile tile; + switch(type) + { + case VN_B_LAYER_UINT1 : + buffer_pos += vnp_raw_unpack_uint8_vector(&buf[buffer_pos], tile.vuint1, VN_B_TILE_SIZE * VN_B_TILE_SIZE / 8); + break; + case VN_B_LAYER_UINT8 : + buffer_pos += vnp_raw_unpack_uint8_vector(&buf[buffer_pos], tile.vuint8, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_UINT16 : + buffer_pos += vnp_raw_unpack_uint16_vector(&buf[buffer_pos], tile.vuint16, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_REAL32 : + buffer_pos += vnp_raw_unpack_real32_vector(&buf[buffer_pos], tile.vreal32, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + case VN_B_LAYER_REAL64 : + buffer_pos += vnp_raw_unpack_real64_vector(&buf[buffer_pos], tile.vreal64, VN_B_TILE_SIZE * VN_B_TILE_SIZE); + break; + } + if(func_b_tile_set != NULL && type <= VN_B_LAYER_REAL64) + func_b_tile_set(v_fs_get_user_data(83), node_id, layer_id, tile_x, tile_y, z, type, &tile); + return buffer_pos; + } + + if(func_b_tile_set != NULL) + func_b_tile_set(v_fs_get_user_data(83), node_id, layer_id, tile_x, tile_y, z, (VNBLayerType)type, tile); + + return buffer_pos; +} + +typedef struct VTempText VTempText; + +struct VTempText { + VNodeID node_id; + VBufferID buffer_id; + uint32 pos; + uint32 length; + uint16 index; + char *text; + VTempText *next; +}; + +typedef struct { + VTempText *text_temp; + uint16 text_send_id; + uint16 text_receive_id; +} VOrderedStorage; + +VOrderedStorage * v_create_ordered_storage(void) +{ + VOrderedStorage *s; + + s = malloc(sizeof *s); + s->text_temp = NULL; + s->text_send_id = 0; + s->text_receive_id = 0; + return s; +} + +void v_destroy_ordered_storage(VOrderedStorage *s) +{ + VTempText *line, *next; + + for(line = s->text_temp; line != NULL; line = next) + { + next = line->next; + if(line->text != NULL) + free(line->text); + free(line); + } + free(s); +} + +void verse_send_t_text_set(VNodeID node_id, VBufferID buffer_id, uint32 pos, uint32 length, const char *text) +{ + uint8 *buf; + VOrderedStorage *s; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 99);/* Packing the command */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_t_text_set(node_id = %u buffer_id = %u pos = %u length = %u text = %s );\n", node_id, buffer_id, pos, length, text); +#endif + s = v_con_get_ordered_storage(); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], buffer_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], pos); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], length); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], s->text_send_id++); + if(text == NULL) + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0); + else + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], text, VN_T_MAX_TEXT_CMD_SIZE); + v_cmd_buf_set_unique_address_size(head, buffer_pos); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +static void call_text_set(VTempText *line) +{ + const char *t; + void (* func_t_text_set)(void *user_data, VNodeID node_id, VBufferID buffer_id, uint32 pos, uint16 length, const char *text); + + func_t_text_set = v_fs_get_user_func(99); +#if defined V_PRINT_RECEIVE_COMMANDS + printf("receive: verse_send_t_text_set(node_id = %u buffer_id = %u pos = %u length = %u text = %s ); callback = %p\n", line->node_id, line->buffer_id, line->pos, line->length, line->text, v_fs_get_user_func(99)); +#endif + if(line->text == NULL) + t = ""; + else + t = line->text; + if(func_t_text_set != NULL) + func_t_text_set(v_fs_get_user_data(99), line->node_id, line->buffer_id, line->pos, line->length, t); +} + +unsigned int v_unpack_t_text_set(const char *buf, size_t buffer_length) +{ + unsigned int i, buffer_pos = 0; + VOrderedStorage *s; + VTempText l, *line, *past = NULL; + char text[1500]; + + if(buffer_length < 12) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &l.node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &l.buffer_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &l.pos); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &l.length); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &l.index); + buffer_pos += vnp_raw_unpack_string(&buf[buffer_pos], text, sizeof text, buffer_length - buffer_pos); + if(text[0] == 0) + l.text = NULL; + else + l.text = text; + s = v_con_get_ordered_storage(); + if(s->text_receive_id == l.index) + { + call_text_set(&l); + s->text_receive_id++; + line = s->text_temp; + while(line != NULL) + { + if(line->index == s->text_receive_id) + { + call_text_set(line); + if(past == NULL) + s->text_temp = line->next; + else + past->next = line->next; + if(line->text != NULL) + free(line->text); + past = NULL; + free(line); + line = s->text_temp; + s->text_receive_id++; + } + else + { + past = line; + line = line->next; + } + } + } + else + { + line = malloc(sizeof *line); + *line = l; + line->next = s->text_temp; + s->text_temp = line; + i = strlen(text); + if(i > 0) + { + line->text = malloc(i + 1); + strcpy(line->text, text); + } + else + line->text = NULL; + } + return buffer_pos; +} + +void verse_send_c_key_set(VNodeID node_id, VLayerID curve_id, uint32 key_id, uint8 dimensions, + const real64 *pre_value, const uint32 *pre_pos, + const real64 *value, real64 pos, + const real64 *post_value, const uint32 *post_pos) +{ + uint8 *buf; + unsigned int i, buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + if(dimensions == 0 || dimensions > 4) + return; + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 130);/* Packing the command */ +#if defined V_PRINT_SEND_COMMANDS + switch(dimensions) + { + case 1: + printf("send: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = %f pre_pos = %u value = %f pos = %f, pre_value = %f pre_pos = %u ); callback = %p\n", node_id, curve_id, key_id, dimensions, pre_value[0], pre_pos[0], value[0], pos, pre_value[0], pre_pos[0], v_fs_get_user_func(130)); + break; + case 2: + printf("sende: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f} pre_pos = {%u, %u} value = {%f, %f} pos = %f, pre_value = {%f, %f} pre_pos = {%u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], + pre_pos[0], pre_pos[1], + value[0], value[1], pos, + pre_value[0], pre_value[1], + pre_pos[0], pre_pos[1], v_fs_get_user_func(130)); + break; + case 3: + printf("send: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f, %f} pre_pos = {%u, %u, %u} value = {%f, %f, %f} pos = %f, pre_value = {%f, %f, %f} pre_pos = {%u, %u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], pre_value[2], + pre_pos[0], pre_pos[1], pre_pos[2], + value[0], value[1], value[2], pos, + pre_value[0], pre_value[1], pre_value[2], + pre_pos[0], pre_pos[1], pre_pos[2], v_fs_get_user_func(130)); + + break; + case 4: + printf("send: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f, %f, %f} pre_pos = {%u, %u, %u, %u} value = {%f, %f, %f, %f} pos = %f, pre_value = {%f, %f, %f, %f} pre_pos = {%u, %u, %u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], pre_value[2], pre_value[3], + pre_pos[0], pre_pos[1], pre_pos[2], pre_pos[3], + value[0], value[1], value[2], value[3], pos, + pre_value[0], pre_value[1], pre_value[2], pre_value[3], + pre_pos[0], pre_pos[1], pre_pos[2], pre_pos[3], v_fs_get_user_func(130)); + break; + } +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], key_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], dimensions); + + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pre_value[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], pre_pos[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], value[i]); + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], pos); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], post_value[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], post_pos[i]); + + if(key_id == (uint32) ~0u) + v_cmd_buf_set_unique_address_size(head, 11); + else + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +void verse_send_c_key_destroy(VNodeID node_id, VLayerID curve_id, uint32 key_id) +{ + uint8 *buf; + unsigned int buffer_pos = 0; + VCMDBufHead *head; + head = v_cmd_buf_allocate(VCMDBS_1500);/* Allocating the buffer */ + buf = ((VCMDBuffer10 *)head)->buf; + + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 130);/* Packing the command */ +#if defined V_PRINT_SEND_COMMANDS + printf("send: verse_send_c_key_destroy(node_id = %u curve_id = %u key_id = %u );\n", node_id, curve_id, key_id); +#endif + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], node_id); + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], curve_id); + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], key_id); + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], 0); + v_cmd_buf_set_address_size(head, 11); + v_cmd_buf_set_size(head, buffer_pos); + v_noq_send_buf(v_con_get_network_queue(), head); +} + +unsigned int v_unpack_c_key_set(const char *buf, size_t buffer_length) +{ + unsigned int i, buffer_pos = 0; + VNodeID node_id; + VLayerID curve_id; + uint32 key_id; + uint8 dimensions; + real64 pre_value[4], value[4], pos, post_value[4]; + uint32 post_pos[4], pre_pos[4]; + + if(buffer_length < 11) + return -1; + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &node_id); + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], &curve_id); + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &key_id); + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], &dimensions); + if(dimensions != 0 && dimensions < 5) + { + void (* func_c_key_set)(void *user_data, VNodeID node_id, VLayerID curve_id, uint32 key_id, uint8 dimensions, real64 *pre_value, uint32 *pre_pos, real64 *value, real64 pos, real64 *post_value, uint32 *post_pos); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pre_value[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &pre_pos[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &value[i]); + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &pos); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], &post_value[i]); + for(i = 0; i < dimensions; i++) + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], &post_pos[i]); + #if defined V_PRINT_RECEIVE_COMMANDS + switch(dimensions) + { + case 1: + printf("receive: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = %f pre_pos = %u value = %f pos = %f, pre_value = %f pre_pos = %u ); callback = %p\n", node_id, curve_id, key_id, dimensions, pre_value[0], pre_pos[0], value[0], pos, pre_value[0], pre_pos[0], v_fs_get_user_func(130)); + break; + case 2: + printf("receive: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f} pre_pos = {%u, %u} value = {%f, %f} pos = %f, pre_value = {%f, %f} pre_pos = {%u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], + pre_pos[0], pre_pos[1], + value[0], value[1], pos, + pre_value[0], pre_value[1], + pre_pos[0], pre_pos[1], v_fs_get_user_func(130)); + break; + case 3: + printf("receive: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f, %f} pre_pos = {%u, %u, %u} value = {%f, %f, %f} pos = %f, pre_value = {%f, %f, %f} pre_pos = {%u, %u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], pre_value[2], + pre_pos[0], pre_pos[1], pre_pos[2], + value[0], value[1], value[2], pos, + pre_value[0], pre_value[1], pre_value[2], + pre_pos[0], pre_pos[1], pre_pos[2], v_fs_get_user_func(130)); + + break; + case 4: + printf("receive: verse_send_c_key_set(node_id = %u curve_id = %u key_id = %u dimensions = %u pre_value = {%f, %f, %f, %f} pre_pos = {%u, %u, %u, %u} value = {%f, %f, %f, %f} pos = %f, pre_value = {%f, %f, %f, %f} pre_pos = {%u, %u, %u, %u}); callback = %p\n", + node_id, curve_id, key_id, dimensions, + pre_value[0], pre_value[1], pre_value[2], pre_value[3], + pre_pos[0], pre_pos[1], pre_pos[2], pre_pos[3], + value[0], value[1], value[2], value[3], pos, + pre_value[0], pre_value[1], pre_value[2], pre_value[3], + pre_pos[0], pre_pos[1], pre_pos[2], pre_pos[3], v_fs_get_user_func(130)); + break; + } + #endif + func_c_key_set = v_fs_get_user_func(130); + if(func_c_key_set != NULL) + func_c_key_set(v_fs_get_user_data(130), node_id, curve_id, key_id, dimensions, pre_value, pre_pos, value, pos, post_value, post_pos); + return buffer_pos; + }else + { + void (* alias_c_key_destroy)(void *user_data, VNodeID node_id, VLayerID curve_id, uint32 key_id); + alias_c_key_destroy = v_fs_get_alias_user_func(130); + printf("receive: verse_send_c_key_destroy(node_id = %u curve_id = %u key_id = %u); callback = %p\n", node_id, curve_id, key_id, alias_c_key_destroy); + if(alias_c_key_destroy != NULL) + alias_c_key_destroy(v_fs_get_alias_user_data(130), node_id, curve_id, key_id); + return buffer_pos; + } +} + +#endif diff --git a/extern/verse/dist/v_network.c b/extern/verse/dist/v_network.c new file mode 100644 index 00000000000..3d67218bb7e --- /dev/null +++ b/extern/verse/dist/v_network.c @@ -0,0 +1,274 @@ +/* +** +*/ + +#if defined _WIN32 +#include +typedef unsigned int uint; +typedef SOCKET VSocket; +#else +typedef int VSocket; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include +#include + +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned char uint8; +typedef char int8; +typedef char boolean; + +#include "v_cmd_gen.h" +#include "v_network.h" + +#if !defined socklen_t +#define socklen_t int +#endif + +#define TRUE 1 +#define FALSE 0 + +typedef struct{ + struct sockaddr_in address; + struct hostent *he; +} VNetworkConnection; + +#define VERSE_STD_CONNECT_TO_PORT 4950 + +static VSocket my_socket = -1; +static uint16 my_port = 0; + +void v_n_set_port(unsigned short port) +{ + my_port = port; +} + +VSocket v_n_socket_create(void) +{ + static boolean initialized = FALSE; + struct sockaddr_in address; + int buffer_size = 1 << 20; + + if(my_socket != -1) + return my_socket; +#if defined _WIN32 + if(!initialized) + { + WSADATA wsaData; + + if(WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) + { + fprintf(stderr, "WSAStartup failed.\n"); + exit(1); + } + + } +#endif + initialized = TRUE; + if((my_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + return -1; +#if defined _WIN32 + { + unsigned long one = 1UL; + if(ioctlsocket(my_socket, FIONBIO, &one) != 0) + return -1; + } +#else + if(fcntl(my_socket, F_SETFL, O_NONBLOCK) != 0) + { + fprintf(stderr, "v_network: Couldn't make socket non-blocking\n"); + return -1; + } +#endif + address.sin_family = AF_INET; /* host byte order */ + address.sin_port = htons(my_port); /* short, network byte order */ + address.sin_addr.s_addr = INADDR_ANY; + if(bind(my_socket, (struct sockaddr *) &address, sizeof(struct sockaddr)) != 0) + { + fprintf(stderr, "v_network: Failed to bind(), code %d (%s)\n", errno, strerror(errno)); + exit(0); /* FIX ME */ + } + if(setsockopt(my_socket, SOL_SOCKET, SO_SNDBUF, (const char *) &buffer_size, sizeof buffer_size) != 0) + fprintf(stderr, "v_network: Couldn't set send buffer size of socket to %d\n", buffer_size); + if(setsockopt(my_socket, SOL_SOCKET, SO_RCVBUF, (const char *) &buffer_size, sizeof buffer_size) != 0) + fprintf(stderr, "v_network: Couldn't set receive buffer size of socket to %d\n", buffer_size); + return my_socket; +} + +void v_n_socket_destroy(void) +{ +#if defined _WIN32 + closesocket(my_socket); +#else + close(my_socket); +#endif + my_socket = -1; +} + +boolean v_n_set_network_address(VNetworkAddress *address, const char *host_name) +{ + struct hostent *he; + char *colon = NULL, *buf = NULL; + boolean ok = FALSE; + + v_n_socket_create(); + address->port = VERSE_STD_CONNECT_TO_PORT; + /* If a port number is included, as indicated by a colon, we need to work a bit more. */ + if((colon = strchr(host_name, ':')) != NULL) + { + size_t hl = strlen(host_name); + + if((buf = malloc(hl + 1)) != NULL) + { + unsigned int tp; + + strcpy(buf, host_name); + colon = buf + (colon - host_name); + *colon = '\0'; + host_name = buf; + if(sscanf(colon + 1, "%u", &tp) == 1) + { + address->port = (unsigned short) tp; + if(address->port != tp) /* Protect against overflow. */ + host_name = NULL; + } + else + host_name = NULL; /* Protect against parse error. */ + } + else + return FALSE; + } + if(host_name != NULL && (he = gethostbyname(host_name)) != NULL) + { + memcpy(&address->ip, he->h_addr_list[0], he->h_length); + address->ip = ntohl(address->ip); + ok = TRUE; + } + if(buf != NULL) + free(buf); + + return ok; +} + +int v_n_send_data(VNetworkAddress *address, const char *data, size_t length) +{ + struct sockaddr_in address_in; + VSocket sock; + int ret; + + if((sock = v_n_socket_create()) == -1 || length == 0) + return 0; + address_in.sin_family = AF_INET; /* host byte order */ + address_in.sin_port = htons(address->port); /* short, network byte order */ + address_in.sin_addr.s_addr = htonl(address->ip); + memset(&address_in.sin_zero, 0, sizeof address_in.sin_zero); + ret = sendto(sock, data, length, 0, (struct sockaddr *) &address_in, sizeof(struct sockaddr_in)); + if(ret < 0) + fprintf(stderr, "Socket sendto() of %u bytes failed, code %d (%s)\n", (unsigned int) length, errno, strerror(errno)); + return ret; +} + +#if !defined V_GENERATE_FUNC_MODE + +extern void *v_con_get_network_address_id(unsigned int id); +extern unsigned int v_con_get_network_address_count(); + +unsigned int v_n_wait_for_incoming(unsigned int microseconds) +{ + struct timeval tv; + fd_set fd_select; + unsigned int s1, f1, s2, f2; + + if(microseconds == 0) + return 0; + v_n_socket_create(); + tv.tv_sec = microseconds / 1000000; + tv.tv_usec = microseconds % 1000000; + FD_ZERO(&fd_select); + FD_SET(my_socket, &fd_select); + v_n_get_current_time(&s1, &f1); + select(1, &fd_select, NULL, NULL, &tv); + v_n_get_current_time(&s2, &f2); + return (unsigned int) (1000000 * (s2 - s1) + (1000000.0 / 0xffffffffu) * (long) (f2 - f1)); /* Must cast to (long) for f1 > f2 case! */ +} + +#endif + +int v_n_receive_data(VNetworkAddress *address, char *data, size_t length) +{ + struct sockaddr_in address_in; + socklen_t from_length = sizeof address_in; + size_t len; + + if(v_n_socket_create() == -1) + return 0; + memset(&address_in, 0, sizeof address_in); + address_in.sin_family = AF_INET; + address_in.sin_port = htons(my_port); + address_in.sin_addr.s_addr = INADDR_ANY; + len = recvfrom(v_n_socket_create(), data, length, 0, (struct sockaddr *) &address_in, &from_length); + if(len > 0) + { + address->ip = ntohl(address_in.sin_addr.s_addr); + address->port = ntohs(address_in.sin_port); + } + return len; +} + +#if defined _WIN32 + +void v_n_get_current_time(uint32 *seconds, uint32 *fractions) +{ + static LARGE_INTEGER frequency; + static boolean init = FALSE; + LARGE_INTEGER counter; + + if(!init) + { + init = TRUE; + QueryPerformanceFrequency(&frequency); + } + + QueryPerformanceCounter(&counter); + if(seconds != NULL) + *seconds = (uint32) (counter.QuadPart / frequency.QuadPart); + if(fractions != NULL) + *fractions = (uint32) ((0xffffffffUL * (counter.QuadPart % frequency.QuadPart)) / frequency.QuadPart); +} + +#else + +void v_n_get_current_time(uint32 *seconds, uint32 *fractions) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + if(seconds != NULL) + *seconds = tv.tv_sec; + if(fractions != NULL) + *fractions = tv.tv_usec * 1E-6 * (double) (uint32)~0; +} + +#endif + +void v_n_get_address_string(const VNetworkAddress *address, char *string) +{ + sprintf(string, "%u.%u.%u.%u:%u", address->ip >> 24, (address->ip >> 16) & 0xff, + (address->ip >> 8) & 0xff, address->ip & 0xff, address->port); +} diff --git a/extern/verse/dist/v_network.h b/extern/verse/dist/v_network.h new file mode 100644 index 00000000000..52233cbe2bb --- /dev/null +++ b/extern/verse/dist/v_network.h @@ -0,0 +1,24 @@ +/* +** +*/ + +#if !defined V_NETWORK_H +#define V_NETWORK_H + +#define VERSE_STD_CONNECT_PORT 4950 + +typedef struct{ + unsigned int ip; + unsigned short port; +}VNetworkAddress; + +extern void v_n_set_port(unsigned short port); +extern unsigned int v_n_wait_for_incoming(unsigned int microseconds); +extern boolean v_n_set_network_address(VNetworkAddress *address, const char *host_name); +extern int v_n_send_data(VNetworkAddress *address, const char *data, size_t length); +extern int v_n_receive_data(VNetworkAddress *address, char *data, size_t length); +extern void v_n_get_address_string(const VNetworkAddress *address, char *string); + +extern void v_n_get_current_time(unsigned int *seconds, unsigned int *fractions); + +#endif /* V_NETWORK_H */ diff --git a/extern/verse/dist/v_network_in_que.c b/extern/verse/dist/v_network_in_que.c new file mode 100644 index 00000000000..d99a4ad11ec --- /dev/null +++ b/extern/verse/dist/v_network_in_que.c @@ -0,0 +1,140 @@ + +#include +#include +#include + +#include "verse_header.h" + +#include "v_cmd_buf.h" +#include "v_cmd_gen.h" +#include "v_connection.h" +#include "v_internal_verse.h" +#include "v_network.h" +#include "v_pack.h" + + +#if !defined(V_GENERATE_FUNC_MODE) + +#include "v_network_in_que.h" + +static VNetInPacked *v_niq_temp = NULL; + +void v_niq_clear(VNetInQueue *queue) +{ + queue->oldest = NULL; + queue->newest = NULL; + queue->packet_id = 2; + v_niq_timer_update(queue); +} + +/* Set queue's last-used timestamp to "now". */ +void v_niq_timer_update(VNetInQueue *queue) +{ + v_n_get_current_time(&queue->seconds, &queue->fractions); + queue->acc_seconds = queue->acc_fractions = 0; +} + +uint32 v_niq_time_out(VNetInQueue *queue) +{ + uint32 fractions, f; + + /* Magic code to disregard if the clock moves forward more than one second at a time. + * This should help keep Verse alive on e.g. a notebook that is suspended. + */ + v_n_get_current_time(NULL, &fractions); + if(fractions < queue->fractions) + f = 0xffffffffu - queue->fractions + fractions; + else + f = fractions - queue->fractions; +/* printf("now=%u last=%u -> f=%u\n", fractions, queue->fractions, f);*/ + if(queue->acc_fractions + f < queue->acc_fractions) + queue->acc_seconds += 1; + queue->acc_fractions += f; + queue->fractions = fractions; + +/* printf("queue at %p has seconds=%u, now=%u -> diff=%u\n", queue, queue->seconds, seconds, seconds - queue->seconds);*/ + return queue->acc_seconds; +} + +VNetInPacked * v_niq_get(VNetInQueue *queue, size_t *length) +{ + VNetInPacked *p; + + if(queue->oldest == NULL) + { + *length = 0; + return NULL; + } + /* pop oldest package */ + p = queue->oldest; + queue->oldest = p->newer; + if(queue->oldest == NULL) + queue->newest = NULL; + else + ((VNetInPacked *)queue->oldest)->older = NULL; + *length = p->size; + + return p; +} + +unsigned int v_niq_free(VNetInQueue *queue) +{ + unsigned int i; + size_t length; + + for(i = 0; v_niq_get(queue, &length) != NULL; i++) + ; + return i; +} + +void v_niq_release(VNetInQueue *queue, VNetInPacked *p) +{ + /* push on v_niq_temp for re-use */ + p->older = v_niq_temp; + v_niq_temp = p; +} + +char *v_niq_store(VNetInQueue *queue, size_t length, unsigned int packet_id) +{ + VNetInPacked *p; + + v_niq_timer_update(queue); + + if(packet_id < queue->packet_id) + return NULL; + + while(queue->packet_id != packet_id) + { + verse_send_packet_nak(queue->packet_id++); + if(queue->packet_id == 0) + queue->packet_id++; + } + queue->packet_id++; + if(queue->packet_id == 0) + queue->packet_id++; + verse_send_packet_ack(packet_id); + + if(v_niq_temp == NULL) + p = malloc(sizeof *p); + else + { + /* pop off v_niq_temp */ + p = v_niq_temp; + v_niq_temp = p->older; + } + /* push as newest */ + p->older = queue->newest; + p->newer = NULL; + + if(queue->newest == NULL) + queue->oldest = p; + else + ((VNetInPacked *)queue->newest)->newer = p; + queue->newest = p; + + p->size = length; + + return p->data; +} + +#endif diff --git a/extern/verse/dist/v_network_in_que.h b/extern/verse/dist/v_network_in_que.h new file mode 100644 index 00000000000..9241fe18fe8 --- /dev/null +++ b/extern/verse/dist/v_network_in_que.h @@ -0,0 +1,24 @@ + +typedef struct{ + void *oldest; + void *newest; + uint32 packet_id; + uint32 seconds, fractions; /* Current time. */ + uint32 acc_seconds, acc_fractions; /* Accumulated time. */ +}VNetInQueue; + +typedef struct{ + void *newer; + void *older; + char data[1500]; + size_t size; +}VNetInPacked; + +extern void v_niq_clear(VNetInQueue *queue); +extern void v_niq_timer_update(VNetInQueue *queue); + +extern VNetInPacked * v_niq_get(VNetInQueue *queue, size_t *length); +extern void v_niq_release(VNetInQueue *queue, VNetInPacked *p); +extern char * v_niq_store(VNetInQueue *queue, size_t length, unsigned int packet_id); +unsigned int v_niq_free(VNetInQueue *queue); +extern uint32 v_niq_time_out(VNetInQueue *queue); diff --git a/extern/verse/dist/v_network_out_que.c b/extern/verse/dist/v_network_out_que.c new file mode 100644 index 00000000000..10126a59779 --- /dev/null +++ b/extern/verse/dist/v_network_out_que.c @@ -0,0 +1,396 @@ +/* +** +*/ + +#include +#include +#include + +#include "verse_header.h" + +#include "v_cmd_buf.h" +#include "v_cmd_gen.h" +#include "v_connection.h" +#include "v_network.h" +#include "v_pack.h" +#include "v_encryption.h" +#include "v_network_out_que.h" +#include "v_util.h" + +#if !defined(V_GENERATE_FUNC_MODE) + +#define STD_QUE_SIZE 64 + +#define V_NOQ_OPTIMIZATION_SLOTS 2048 + +#define V_NOQ_WINDOW_SIZE 100000 +#define V_NOQ_MAX_SORTED_COMMANDS 5000 + +typedef struct{ + void *next; + char *data; + size_t size; +} NetPacked; + +struct VNetOutQueue{ + uint8 packet_buffer[V_NOQ_MAX_PACKET_SIZE]; + size_t packet_buffer_use; + NetPacked *packed; + NetPacked *last; + VCMDBufHead *unsent[V_NOQ_OPTIMIZATION_SLOTS]; + VCMDBufHead *history[V_NOQ_OPTIMIZATION_SLOTS]; + VCMDBufHead *ack_nak; + VCMDBufHead *unsorted; + VCMDBufHead *unsorted_end; + uint32 unsorted_count; /* debug only */ + uint32 unsent_comands; + size_t unsent_size; + size_t sent_size; + unsigned int packet_id; + unsigned int slot; + uint32 seconds; + uint32 fractions; +}; + +size_t verse_session_get_size(void) +{ + const VNetOutQueue *queue; + + queue = v_con_get_network_queue(); + return queue->unsent_size + queue->sent_size; +} + +VNetOutQueue * v_noq_create_network_queue(void) +{ + VNetOutQueue *queue; + unsigned int i; + + queue = malloc(sizeof *queue); + for(i = 0; i < V_NOQ_OPTIMIZATION_SLOTS; i++) + { + queue->unsent[i] = NULL; + queue->history[i] = NULL; + } + queue->unsent_comands = 0; + queue->unsent_size = 0; + queue->sent_size = 0; + queue->packet_id = 2; + queue->slot = 0; + queue->packed = NULL; + queue->last = NULL; + queue->ack_nak = NULL; + queue->unsorted = NULL; + queue->unsorted_end = NULL; + queue->unsorted_count = 0; + queue->packet_buffer_use = 0; + v_n_get_current_time(&queue->seconds, &queue->fractions); + return queue; +} + +unsigned int v_noq_get_next_out_packet_id(VNetOutQueue *queue) +{ + queue->packet_id++; + if(queue->packet_id == 0) + queue->packet_id++; + return queue->packet_id; +} + +void v_noq_destroy_network_queue(VNetOutQueue *queue) +{ + VCMDBufHead *buf, *b; + unsigned int i; + for(i = 0; i < V_NOQ_OPTIMIZATION_SLOTS; i++) + { + for(buf = queue->history[i]; buf != NULL; buf = b) + { + b = buf->next; + v_cmd_buf_free(buf); + } + for(buf = queue->unsent[i]; buf != NULL; buf = b) + { + b = buf->next; + v_cmd_buf_free(buf); + } + } + for(buf = queue->unsorted; buf != NULL; buf = b) + { + b = buf->next; + v_cmd_buf_free(buf); + } + free(queue); +} + + +void v_noq_sort_and_collapse_buf(VNetOutQueue *queue, VCMDBufHead *buf) +{ + VCMDBufHead *b, *last = NULL; + unsigned int slot; + + slot = buf->address_sum % V_NOQ_OPTIMIZATION_SLOTS; + queue->unsent_size += buf->size; + queue->unsent_comands++; + if(queue->unsent[slot] != NULL) + { + for(b = queue->unsent[slot]; !v_cmd_buf_compare(buf, b) && b->next != NULL; b = b->next) + last = b; + if(v_cmd_buf_compare(buf, b)) /* found a command to replace */ + { + queue->unsent_size -= b->size; + queue->unsent_comands--; + if(last != NULL) /* if its not the first */ + last->next = buf; + else + queue->unsent[slot] = buf; + buf->next = b->next; + v_cmd_buf_free(b); + }else /* inserting the command last in queue */ + { + buf->next = NULL; + b->next = buf; + } + }else /* inserting the first command */ + { + queue->unsent[slot] = buf; + buf->next = NULL; + } + if(queue->history[slot] != NULL) /* if there is a history clear it from any commnds with same address */ + { + last = NULL; + for(b = queue->history[slot]; b != NULL && !v_cmd_buf_compare(buf, b); b = b->next) + last = b; + if(b != NULL) /* found a command to replace */ + { + if(last == NULL) + queue->history[slot] = b->next; + else + last->next = b->next; + queue->sent_size -= b->size; + v_cmd_buf_free(b); + } + } +} + +void v_noq_send_buf(VNetOutQueue *queue, VCMDBufHead *buf) +{ + static int count = 0; +/* if(queue->unsent_comands > V_NOQ_MAX_SORTED_COMMANDS) + { + +*/ if(queue->unsorted == NULL) + { + queue->unsorted_end = buf; + queue->unsorted = buf; + }else + { + queue->unsorted_end->next = buf; + queue->unsorted_end = buf; + } + queue->unsorted_count++; +/* }else + v_noq_sort_and_colapse_buf(queue, buf); +*/ count = (count + 1) % 30; + if(count == 0) + { + v_con_network_listen(); + v_noq_send_queue(queue, v_con_get_network_address()); + } +} + +void v_noq_sort_unsorted(VNetOutQueue *queue) +{ + VCMDBufHead *buf; + + while(queue->unsent_comands < V_NOQ_MAX_SORTED_COMMANDS && queue->unsorted != NULL) + { + buf = queue->unsorted; + if(queue->unsorted == queue->unsorted_end) + { + queue->unsorted_end = NULL; + queue->unsorted = NULL; + }else + { + queue->unsorted = buf->next; + buf->next = NULL; + } + queue->unsorted_count--; + v_noq_sort_and_collapse_buf(queue, buf); + } +} + +boolean v_noq_send_queue(VNetOutQueue *queue, void *address) +{ + static unsigned int my_counter = 0; + VCMDBufHead *buf; + unsigned int size; + uint8 *data; + uint32 seconds, fractions; + double delta; + + data = queue->packet_buffer; + v_n_get_current_time(&seconds, &fractions); + delta = seconds - queue->seconds + (fractions - queue->fractions) / (double) 0xffffffff; + + if(queue->unsorted != NULL) + v_noq_sort_unsorted(queue); + + if(queue->unsent_size == 0 && delta < 1.0 && (queue->ack_nak == NULL || queue->ack_nak->next == NULL)) + return FALSE; + + if(delta > 3.0 && queue->unsent_size == 0 && queue->ack_nak == NULL && queue->packet_buffer_use != 0) + { +/* printf("A) re-sending last delta=%g\n", delta);*/ + v_n_send_data(address, data, queue->packet_buffer_use); + queue->seconds = seconds; + queue->fractions = fractions; + return TRUE; + } + + size = 4; + buf = queue->ack_nak; + while(buf != NULL && size + buf->size < V_NOQ_MAX_PACKET_SIZE) + { + vnp_raw_pack_uint32(data, queue->packet_id); + queue->ack_nak = buf->next; + buf->next = queue->history[queue->slot]; + queue->history[queue->slot] = buf; + buf->packet = queue->packet_id; + v_e_data_encrypt_command(data, size, ((VCMDBuffer1500 *)buf)->buf, buf->size, v_con_get_data_key()); + size += buf->size; + queue->sent_size += buf->size; + buf = queue->ack_nak; + } + if(queue->unsent_size == 0 || queue->sent_size >= V_NOQ_WINDOW_SIZE) + { + if(size > 5) + { +/* printf("ACK: sending actual size=%u id=%u\n", size, queue->packet_id);*/ + v_n_send_data(address, data, size); + queue->packet_buffer_use = size; + queue->seconds = seconds; + queue->fractions = fractions; + queue->packet_id++; + return TRUE; + } +/* printf("returning FALSE from send_queue()\n");*/ + return FALSE; + } +/* if(queue->sent_size < V_NOQ_WINDOW_SIZE && queue->unsent_size != 0)*/ + { + vnp_raw_pack_uint32(data, queue->packet_id); + while(queue->unsent_size != 0) + { + queue->slot = ((1 + queue->slot) % V_NOQ_OPTIMIZATION_SLOTS); + buf = queue->unsent[queue->slot]; + if(buf != NULL) + { + if(buf->size + size > V_NOQ_MAX_PACKET_SIZE) + break; + queue->unsent[queue->slot] = buf->next; + buf->next = queue->history[queue->slot]; + queue->history[queue->slot] = buf; + buf->packet = queue->packet_id; + + v_e_data_encrypt_command(data, size, ((VCMDBuffer1500 *)buf)->buf, buf->size, v_con_get_data_key()); + size += buf->size; + queue->unsent_comands--; + queue->unsent_size -= buf->size; + queue->sent_size += buf->size; + my_counter++; + } + } + v_n_send_data(address, data, size); + queue->packet_buffer_use = size; + queue->packet_id++; +/* size = vnp_raw_pack_uint32(data, queue->packet_id);*/ + queue->seconds = seconds; + queue->fractions = fractions; + } + return TRUE; +} + +void v_noq_send_ack_nak_buf(VNetOutQueue *queue, VCMDBufHead *buf) +{ + buf->next = queue->ack_nak; + queue->ack_nak = buf; +} + +void callback_send_packet_ack(void *user, uint32 packet_id) +{ + VNetOutQueue *queue; + VCMDBufHead *buf, *last; + unsigned int slot; + + queue = v_con_get_network_queue(); + for(slot = 0; slot < V_NOQ_OPTIMIZATION_SLOTS; slot++) + { + last = NULL; + for(buf = queue->history[slot]; buf != NULL && buf->packet != packet_id; buf = buf->next) + last = buf; + + if(buf != NULL) + { + if(last == NULL) + { + while(queue->history[slot] != NULL && queue->history[slot]->packet == packet_id) + { + queue->sent_size -= queue->history[slot]->size; + buf = queue->history[slot]->next; + v_cmd_buf_free(queue->history[slot]); + queue->history[slot] = buf; + } + }else + { + for(; buf != NULL && buf->packet == packet_id; buf = last->next) + { + queue->sent_size -= buf->size; + last->next = buf->next; + v_cmd_buf_free(buf); + } + } + } + } +} + +void callback_send_packet_nak(void *user, uint32 packet_id) +{ + VNetOutQueue *queue; + VCMDBufHead *buf, *last; + unsigned int slot; + + queue = v_con_get_network_queue(); + for(slot = 0; slot < V_NOQ_OPTIMIZATION_SLOTS; slot++) + { + last = NULL; + for(buf = queue->history[slot]; buf != NULL && buf->packet != packet_id; buf = buf->next) + last = buf; + if(buf != NULL) + { + if(last == NULL) + { + for(; queue->history[slot] != NULL && queue->history[slot]->packet == packet_id; queue->history[slot] = buf) + { + queue->unsent_comands++; + queue->unsent_size += queue->history[slot]->size; + queue->sent_size -= queue->history[slot]->size; + buf = queue->history[slot]->next; + queue->history[slot]->next = queue->unsent[slot]; + queue->unsent[slot] = queue->history[slot]; + } + }else + { + for(; last->next != NULL && ((VCMDBufHead *)last->next)->packet == packet_id;) + { + queue->unsent_comands++; + queue->unsent_size += ((VCMDBufHead *)last->next)->size; + queue->sent_size -= ((VCMDBufHead *)last->next)->size; + buf = last->next; + last->next = buf->next; + buf->next = queue->unsent[slot]; + queue->unsent[slot] = buf; + } + } + } + } +} + +#endif diff --git a/extern/verse/dist/v_network_out_que.h b/extern/verse/dist/v_network_out_que.h new file mode 100644 index 00000000000..6746475e84f --- /dev/null +++ b/extern/verse/dist/v_network_out_que.h @@ -0,0 +1,17 @@ +/* +** +*/ + +typedef struct VNetOutQueue VNetOutQueue; + +extern VNetOutQueue * v_noq_create_network_queue(void); +extern void v_noq_destroy_network_queue(VNetOutQueue *queue); +extern void v_noq_send_buf(VNetOutQueue *queue, VCMDBufHead *buf); +extern void v_noq_send_ack_nak_buf(VNetOutQueue *queue, VCMDBufHead *buf); + +extern void v_noq_send_ack(VNetOutQueue *queue, unsigned int id); +extern void v_noq_send_nak(VNetOutQueue *queue, unsigned int id); + +extern boolean v_noq_send_queue(VNetOutQueue *queue, void *address); + +extern unsigned int v_noq_get_next_out_packet_id(VNetOutQueue *queue); diff --git a/extern/verse/dist/v_pack.c b/extern/verse/dist/v_pack.c new file mode 100644 index 00000000000..f521360b11f --- /dev/null +++ b/extern/verse/dist/v_pack.c @@ -0,0 +1,386 @@ +/* +** v_pack.c +** +** These functions are used to pack and unpack various quantities to/from network +** packet buffers. They do not care about alignment, operating at byte level internally. +** The external byte-ordering used is big-endian (aka "network byte order") for all +** quantities larger than a single byte. +*/ + +#include +#include +#include + +#include "v_pack.h" + +size_t vnp_raw_pack_uint8(void *buffer, uint8 data) +{ + *(uint8 *) buffer = data; + + return sizeof data; +} + +size_t vnp_raw_unpack_uint8(const void *buffer, uint8 *data) +{ + *data = *(uint8 *) buffer; + + return sizeof *data; +} + +size_t vnp_raw_pack_uint8_vector(void *buffer, const uint8 *data, unsigned int length) +{ + memcpy(buffer, data, length); + return length; +} + +size_t vnp_raw_unpack_uint8_vector(const void *buffer, uint8 *data, unsigned int length) +{ + memcpy(data, buffer, length); + return length; +} + +size_t vnp_raw_pack_uint16(void *buffer, uint16 data) +{ + *(uint8 *) buffer = (data & 0xFF00) >> 8; + *((uint8 *) buffer + 1) = data & 0xFF; + return sizeof data; +} + +size_t vnp_raw_unpack_uint16(const void *buffer, uint16 *data) +{ + register const uint8 *b = buffer; + register uint16 tmp; + + tmp = ((uint16) *b++) << 8; + tmp |= (uint16) *b; + *data = tmp; + return sizeof *data; +} + +size_t vnp_raw_pack_uint16_vector(void *buffer, const uint16 *data, unsigned int length) +{ + register uint8 *b = buffer; + unsigned int i; + for(i = 0; i < length; i++) + { + *b++ = (*data & 0xFF00) >> 8; + *b++ = *data & 0xFF; + data++; + } + return length * 2; +} + +size_t vnp_raw_unpack_uint16_vector(const void *buffer, uint16 *data, unsigned int length) +{ + register const uint8 *b = buffer; + uint16 *end; + + for(end = data + length; end != data; data++) + { + *data = ((uint16) *b++) << 8; + *data |= (uint16) *b++; + } + return length * 2; +} + +size_t vnp_raw_pack_uint24(void *buffer, uint32 data) +{ + register uint8 *p = buffer; + + data >>= 8; + *(p++) = (data >> 24) & 0xFF; + *(p++) = (data >> 16) & 0xFF; + *(p++) = (data >> 8) & 0xFF; + + return 3; +} + +size_t vnp_raw_unpack_uint24(const void *buffer, uint32 *data) +{ + register const uint8 *p = buffer; + register uint32 tmp = 0; + + tmp |= ((uint32) *p++) << 24; + tmp |= ((uint32) *p++) << 16; + tmp |= ((uint32) *p++) << 8; + tmp |= tmp >> 24; + + return 3; +} + +size_t vnp_raw_pack_uint24_vector(void *buffer, const uint32 *data, unsigned int length) +{ + register uint8 *b = buffer; + unsigned int i; + + for(i = 0; i < length; i++) + { + *b++ = (*data >> 24) & 0xFF; + *b++ = (*data >> 16) & 0xFF; + *b++ = (*data >> 8) & 0xFF; + data++; + } + return length * 3; +} + +size_t vnp_raw_unpack_uint24_vector(const void *buffer, uint32 *data, unsigned int length) +{ + register const uint8 *b = buffer; + register uint32 tmp; + uint32 *end; + for(end = data + length; end != data; data++) + { + tmp = ((uint32) *b++) << 24; + tmp |= ((uint32) *b++) << 16; + tmp |= ((uint32) *b++) << 8; + tmp |= tmp >> 24; + *data = tmp; + } + return length * 3; +} + +size_t vnp_raw_pack_uint32(void *buffer, uint32 data) +{ + register uint8 *b = buffer; + + *b++ = (data >> 24) & 0xFF; + *b++ = (data >> 16) & 0xFF; + *b++ = (data >> 8) & 0xFF; + *b++ = data & 0xFF; + + return sizeof data; +} + +size_t vnp_raw_unpack_uint32(const void *buffer, uint32 *data) +{ + register const uint8 *b = buffer; + + *data = ((uint32) *b++) << 24; + *data |= ((uint32) *b++) << 16; + *data |= ((uint32) *b++) << 8; + *data |= *b; + return sizeof *data; +} + +size_t vnp_raw_pack_uint32_vector(void *buffer, const uint32 *data, unsigned int length) +{ + register uint8 *b = buffer; + unsigned int i; + + for(i = 0; i < length; i++) + { + *b++ = (*data >> 24) & 0xFF; + *b++ = (*data >> 16) & 0xFF; + *b++ = (*data >> 8) & 0xFF; + *b++ = *data & 0xFF; + data++; + } + return length * 4; +} + +size_t vnp_raw_unpack_uint32_vector(const void *buffer, uint32 *data, unsigned int length) +{ + register const uint8 *b = buffer; + uint32 *end; + for(end = data + length; end != data; data++) + { + *data = ((uint32) *b++) << 24; + *data |= ((uint32) *b++) << 16; + *data |= ((uint32) *b++) << 8; + *data |= ((uint32) *b++); + } + return length * 4; +} + +size_t vnp_raw_pack_real32(void *buffer, real32 data) +{ + union { uint32 uint; real32 real; } punt; + punt.real = data; + return vnp_raw_pack_uint32(buffer, punt.uint); +} + +size_t vnp_raw_unpack_real32(const void *buffer, real32 *data) +{ + return vnp_raw_unpack_uint32(buffer, (uint32 *) data); +} + +size_t vnp_raw_pack_real32_vector(void *buffer, const real32 *data, unsigned int length) +{ + uint32 i; + for(i = 0; i < length; i++) + vnp_raw_pack_real32(&((uint8 *)buffer)[i * 4], data[i]); + return length * 4; +} + +size_t vnp_raw_unpack_real32_vector(const void *buffer, real32 *data, unsigned int length) +{ + uint32 i; + for(i = 0; i < length; i++) + vnp_raw_unpack_real32(&((uint8 *)buffer)[i * 4], &data[i]); + return length * 4; +} + +size_t vnp_raw_pack_real64(void *buffer, real64 data) +{ + union { uint32 uint[2]; real64 real; } punt; + uint32 size; + + punt.real = data; + size = vnp_raw_pack_uint32(buffer, punt.uint[0]); + buffer = (uint8 *) buffer + size; + size += vnp_raw_pack_uint32(buffer, punt.uint[1]); + return size; +} + +size_t vnp_raw_unpack_real64(const void *buffer, real64 *data) +{ + union { uint32 uint[2]; real64 real; } punt; + uint32 size; + + size = vnp_raw_unpack_uint32(buffer, &punt.uint[0]); + size += vnp_raw_unpack_uint32(((uint8 *)buffer) + size, &punt.uint[1]); + *data = punt.real; + return size; +} + +size_t vnp_raw_pack_real64_vector(void *buffer, const real64 *data, unsigned int length) +{ + uint32 i; + for(i = 0; i < length; i++) + vnp_raw_pack_real64(&((uint8 *)buffer)[i * 8], data[i]); + return length * 8; +} + +size_t vnp_raw_unpack_real64_vector(const void *buffer, real64 *data, unsigned int length) +{ + uint32 i; + for(i = 0; i < length; i++) + vnp_raw_unpack_real64(&((uint8 *)buffer)[i * 8], &data[i]); + return length * 8; +} + +size_t vnp_raw_pack_string(void *buffer, const char *string, size_t max_size) +{ + unsigned int i = 0; + char *p = buffer; + if(string != 0) + for(; i < max_size && string[i] != 0; i++) + p[i] = string[i]; + p[i] = 0; + return ++i; +} + +size_t vnp_raw_unpack_string(const void *buffer, char *string, size_t max_size, size_t max_size2) +{ + unsigned int i; + const char *p = buffer; + + max_size--; + max_size2--; + for(i = 0; i < max_size && i < max_size2 && p[i] != 0; i++) + string[i] = p[i]; + string[i] = 0; + return ++i; +} + +/* --------------------------------------------------------------------------------------------------- */ + +size_t vnp_pack_quat32(void *buffer, const VNQuat32 *data) +{ + uint8 *out = buffer; + + if(data == NULL) + return 0; + out += vnp_raw_pack_real32(out, data->x); + out += vnp_raw_pack_real32(out, data->y); + out += vnp_raw_pack_real32(out, data->z); + out += vnp_raw_pack_real32(out, data->w); + + return out - (uint8 *) buffer; +} + +size_t vnp_unpack_quat32(const void *buffer, VNQuat32 *data) +{ + const uint8 *in = buffer; + + if(data == NULL) + return 0; + in += vnp_raw_unpack_real32(in, &data->x); + in += vnp_raw_unpack_real32(in, &data->y); + in += vnp_raw_unpack_real32(in, &data->z); + in += vnp_raw_unpack_real32(in, &data->w); + + return in - (uint8 *) buffer; +} + +size_t vnp_pack_quat64(void *buffer, const VNQuat64 *data) +{ + uint8 *out = buffer; + + if(data == NULL) + return 0; + out += vnp_raw_pack_real64(out, data->x); + out += vnp_raw_pack_real64(out, data->y); + out += vnp_raw_pack_real64(out, data->z); + out += vnp_raw_pack_real64(out, data->w); + + return out - (uint8 *) buffer; +} + +size_t vnp_unpack_quat64(const void *buffer, VNQuat64 *data) +{ + const uint8 *in = buffer; + + if(data == NULL) + return 0; + in += vnp_raw_unpack_real64(in, &data->x); + in += vnp_raw_unpack_real64(in, &data->y); + in += vnp_raw_unpack_real64(in, &data->z); + in += vnp_raw_unpack_real64(in, &data->w); + + return in - (uint8 *) buffer; +} + +size_t vnp_pack_audio_block(void *buffer, VNABlockType type, const VNABlock *block) +{ + if(block == NULL) + return 0; + switch(type) + { + case VN_A_BLOCK_INT8: + return vnp_raw_pack_uint8_vector(buffer, block->vint8, sizeof block->vint8 / sizeof *block->vint8); + case VN_A_BLOCK_INT16: + return vnp_raw_pack_uint16_vector(buffer, block->vint16, sizeof block->vint16 / sizeof *block->vint16); + case VN_A_BLOCK_INT24: + return vnp_raw_pack_uint24_vector(buffer, block->vint24, sizeof block->vint24 / sizeof *block->vint24); + case VN_A_BLOCK_INT32: + return vnp_raw_pack_uint32_vector(buffer, block->vint32, sizeof block->vint32 / sizeof *block->vint32); + case VN_A_BLOCK_REAL32: + return vnp_raw_pack_real32_vector(buffer, block->vreal32, sizeof block->vreal32 / sizeof *block->vreal32); + case VN_A_BLOCK_REAL64: + return vnp_raw_pack_real64_vector(buffer, block->vreal64, sizeof block->vreal64 / sizeof *block->vreal64); + } + return 0; +} + +size_t vnp_unpack_audio_block(const void *buffer, VNABlockType type, VNABlock *block) +{ + if(block == NULL) + return 0; + switch(type) + { + case VN_A_BLOCK_INT8: + return vnp_raw_unpack_uint8_vector(buffer, block->vint8, sizeof block->vint8 / sizeof *block->vint8); + case VN_A_BLOCK_INT16: + return vnp_raw_unpack_uint16_vector(buffer, block->vint16, sizeof block->vint16 / sizeof *block->vint16); + case VN_A_BLOCK_INT24: + return vnp_raw_unpack_uint24_vector(buffer, block->vint24, sizeof block->vint24 / sizeof *block->vint24); + case VN_A_BLOCK_INT32: + return vnp_raw_unpack_uint32_vector(buffer, block->vint32, sizeof block->vint32 / sizeof *block->vint32); + case VN_A_BLOCK_REAL32: + return vnp_raw_unpack_real32_vector(buffer, block->vreal32, sizeof block->vreal32 / sizeof *block->vreal32); + case VN_A_BLOCK_REAL64: + return vnp_raw_unpack_real64_vector(buffer, block->vreal64, sizeof block->vreal64 / sizeof *block->vreal64); + } + return 0; +} diff --git a/extern/verse/dist/v_pack.h b/extern/verse/dist/v_pack.h new file mode 100644 index 00000000000..60cb7225642 --- /dev/null +++ b/extern/verse/dist/v_pack.h @@ -0,0 +1,59 @@ +/* +** v_pack.h +** +** These functions are used to pack and unpack various quantities to/from network +** packet buffers. They do not care about alignment, operating at byte level internally. +** The external byte-ordering used is big-endian (aka "network byte order") for all +** quantities larger than a single byte. +*/ + +#include "verse_header.h" + +extern size_t vnp_raw_pack_uint8(void *buffer, uint8 data); +extern size_t vnp_raw_unpack_uint8(const void *buffer, uint8 *data); + +extern size_t vnp_raw_pack_uint16(void *buffer, uint16 data); +extern size_t vnp_raw_unpack_uint16(const void *buffer, uint16 *data); + +extern size_t vnp_raw_pack_uint24(void *buffer, uint32 data); +extern size_t vnp_raw_unpack_uint24(const void *buffer, uint32 *data); + +extern size_t vnp_raw_pack_uint32(void *buffer, uint32 data); +extern size_t vnp_raw_unpack_uint32(const void *buffer, uint32 *data); + +extern size_t vnp_raw_pack_real32(void *buffer, real32 data); +extern size_t vnp_raw_unpack_real32(const void *buffer, real32 *data); + +extern size_t vnp_raw_pack_real64(void *buffer, real64 data); +extern size_t vnp_raw_unpack_real64(const void *buffer, real64 *data); + +extern size_t vnp_raw_pack_string(void *buffer, const char *string, size_t max_size); +extern size_t vnp_raw_unpack_string(const void *buffer, char *string, size_t max_size, size_t max_size2); + +extern size_t vnp_raw_pack_uint8_vector(void *buffer, const uint8 *data, unsigned int length); +extern size_t vnp_raw_unpack_uint8_vector(const void *buffer, uint8 *data, unsigned int length); + +extern size_t vnp_raw_pack_uint16_vector(void *buffer, const uint16 *data, unsigned int length); +extern size_t vnp_raw_unpack_uint16_vector(const void *buffer, uint16 *data, unsigned int length); + +extern size_t vnp_raw_pack_uint24_vector(void *buffer, const uint32 *data, unsigned int length); +extern size_t vnp_raw_unpack_uint24_vector(const void *buffer, uint32 *data, unsigned int length); + +extern size_t vnp_raw_pack_uint32_vector(void *buffer, const uint32 *data, unsigned int length); +extern size_t vnp_raw_unpack_uint32_vector(const void *buffer, uint32 *data, unsigned int length); + +extern size_t vnp_raw_pack_real32_vector(void *buffer, const real32 *data, unsigned int length); +extern size_t vnp_raw_unpack_real32_vector(const void *buffer, real32 *data, unsigned int length); + +extern size_t vnp_raw_pack_real64_vector(void *buffer, const real64 *data, unsigned int length); +extern size_t vnp_raw_unpack_real64_vector(const void *buffer, real64 *data, unsigned int length); + +/* --------------------------------------------------------------------------------------------------- */ + +extern size_t vnp_pack_quat32(void *buffer, const VNQuat32 *data); +extern size_t vnp_unpack_quat32(const void *buffer, VNQuat32 *data); +extern size_t vnp_pack_quat64(void *buffer, const VNQuat64 *data); +extern size_t vnp_unpack_quat64(const void *buffer, VNQuat64 *data); + +extern size_t vnp_pack_audio_block(void *buffer, VNABlockType type, const VNABlock *block); +extern size_t vnp_unpack_audio_block(const void *buffer, VNABlockType type, VNABlock *block); diff --git a/extern/verse/dist/v_pack_method.c b/extern/verse/dist/v_pack_method.c new file mode 100644 index 00000000000..c79ae92ba31 --- /dev/null +++ b/extern/verse/dist/v_pack_method.c @@ -0,0 +1,219 @@ +/* +** +*/ + +#include + +#include "v_cmd_gen.h" + +#if !defined(V_GENERATE_FUNC_MODE) + +#include "verse.h" +#include "v_pack.h" + +VNOPackedParams * verse_method_call_pack(unsigned int param_count, const VNOParamType *param_type, const VNOParam *params) +{ + unsigned int i, j, buffer_pos; + uint8 *buf; + + buf = malloc(1500 + 8 * 16); + buffer_pos = vnp_raw_pack_uint16(buf, 0); + for(i = 0; i < param_count; i++) + { + switch(param_type[i]) + { + case VN_O_METHOD_PTYPE_INT8 : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], params[i].vint8); + break; + case VN_O_METHOD_PTYPE_INT16 : + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], params[i].vint16); + break; + case VN_O_METHOD_PTYPE_INT32 : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], params[i].vint32); + break; + case VN_O_METHOD_PTYPE_UINT8 : + buffer_pos += vnp_raw_pack_uint8(&buf[buffer_pos], params[i].vuint8); + break; + case VN_O_METHOD_PTYPE_UINT16 : + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], params[i].vuint16); + break; + case VN_O_METHOD_PTYPE_UINT32 : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], params[i].vuint32); + break; + case VN_O_METHOD_PTYPE_REAL32 : + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32); + break; + case VN_O_METHOD_PTYPE_REAL64 : + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64); + break; + case VN_O_METHOD_PTYPE_STRING : + buffer_pos += vnp_raw_pack_string(&buf[buffer_pos], params[i].vstring, (1500 + 8 * 16) - buffer_pos); + break; + case VN_O_METHOD_PTYPE_NODE : + buffer_pos += vnp_raw_pack_uint32(&buf[buffer_pos], params[i].vnode); + break; + case VN_O_METHOD_PTYPE_LAYER : + buffer_pos += vnp_raw_pack_uint16(&buf[buffer_pos], params[i].vlayer); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC2 : + for(j = 0; j < 2; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC3 : + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC2 : + for(j = 0; j < 2; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC3 : + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT9 : + for(j = 0; j < 9; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT16 : + for(j = 0; j < 16; j++) + buffer_pos += vnp_raw_pack_real32(&buf[buffer_pos], params[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT9 : + for(j = 0; j < 9; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT16 : + for(j = 0; j < 16; j++) + buffer_pos += vnp_raw_pack_real64(&buf[buffer_pos], params[i].vreal64_mat[j]); + break; + } + if(buffer_pos > 1500) + { + free(buf); + return NULL; + } + } + vnp_raw_pack_uint16(buf, buffer_pos); + return buf; +} + +boolean verse_method_call_unpack(const VNOPackedParams *data, unsigned int param_count, const VNOParamType *param_type, VNOParam *params) +{ + unsigned int i, j, buffer_pos = 0, len; + uint16 size; + const uint8 *buf; + static char string[2048]; + char *stringput = string; + + buf = data; + buffer_pos += vnp_raw_unpack_uint16(buf, &size); + for(i = 0; i < param_count; i++) + { + switch(param_type[i]) + { + case VN_O_METHOD_PTYPE_INT8 : + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], ¶ms[i].vint8); + break; + case VN_O_METHOD_PTYPE_INT16 : + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], ¶ms[i].vint16); + break; + case VN_O_METHOD_PTYPE_INT32 : + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], ¶ms[i].vint32); + break; + case VN_O_METHOD_PTYPE_UINT8 : + buffer_pos += vnp_raw_unpack_uint8(&buf[buffer_pos], ¶ms[i].vuint8); + break; + case VN_O_METHOD_PTYPE_UINT16 : + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], ¶ms[i].vuint16); + break; + case VN_O_METHOD_PTYPE_UINT32 : + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], ¶ms[i].vuint32); + break; + case VN_O_METHOD_PTYPE_REAL32 : + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32); + break; + case VN_O_METHOD_PTYPE_REAL64 : + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64); + break; + case VN_O_METHOD_PTYPE_STRING : + params[i].vstring = stringput; + len = vnp_raw_unpack_string(&buf[buffer_pos], stringput, (1500 + 8 * 16) - buffer_pos, -1); + stringput += len; + buffer_pos += len; + break; + case VN_O_METHOD_PTYPE_NODE : + buffer_pos += vnp_raw_unpack_uint32(&buf[buffer_pos], ¶ms[i].vnode); + break; + case VN_O_METHOD_PTYPE_LAYER : + buffer_pos += vnp_raw_unpack_uint16(&buf[buffer_pos], ¶ms[i].vlayer); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC2 : + for(j = 0; j < 2; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC3 : + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_VEC4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC2 : + for(j = 0; j < 2; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC3 : + for(j = 0; j < 3; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_VEC4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_vec[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT9 : + for(j = 0; j < 9; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL32_MAT16 : + for(j = 0; j < 16; j++) + buffer_pos += vnp_raw_unpack_real32(&buf[buffer_pos], ¶ms[i].vreal32_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT4 : + for(j = 0; j < 4; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT9 : + for(j = 0; j < 9; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_mat[j]); + break; + case VN_O_METHOD_PTYPE_REAL64_MAT16 : + for(j = 0; j < 16; j++) + buffer_pos += vnp_raw_unpack_real64(&buf[buffer_pos], ¶ms[i].vreal64_mat[j]); + break; + } + } + return TRUE; +} +#endif diff --git a/extern/verse/dist/v_prime.c b/extern/verse/dist/v_prime.c new file mode 100644 index 00000000000..cebdf4fb03d --- /dev/null +++ b/extern/verse/dist/v_prime.c @@ -0,0 +1,165 @@ +/* + * Program to generate primes of the form p = 2 * q + 1, + * where p and q are both primes. + * + * Originally written by Pontus Nyman , + * ported to Verse's bignums and rewritten from scratch by + * Emil Brink. + */ + +#include +#include +#include + +#include "v_bignum.h" +#include "v_encryption.h" +#include "verse_header.h" + +#define BITS V_ENCRYPTION_LOGIN_KEY_BITS /* Save some typing. */ + +#define CYCLES 10 /* Number of times to apply Miller-Rabin test. */ + +/* Test divisibility of against table of small known primes. Returns 1 if n looks prime, 0 if it IS not. */ +static int quick_filter(const VBigDig *n) +{ + VBigDig VBIGNUM(m, 16), VBIGNUM(tmp, BITS / 2); + const unsigned int prime[] = { 3, 5, 7, 11, 13, 17, 19, 23, 39, 31, 37, 41, 43, 47, 53 }; + unsigned int i; + + for(i = 0; i < sizeof prime / sizeof *prime; i++) + { + v_bignum_set_bignum(tmp, n); + v_bignum_set_digit(m, prime[i]); + v_bignum_mod(tmp, m); + if(v_bignum_eq_zero(tmp)) + return 0; + } + return 1; +} + +/* The Miller-Rabin primality test. Returns 1 if the candidate looks prime, 0 if + * it IS NOT prime. Assumes that n is BITS / 2 bits, so that its square fits in BITS. +*/ +static int miller_rabin(const VBigDig *n, VRandGen *gen) +{ + int i, k; + VBigDig VBIGNUM(a, BITS / 2), VBIGNUM(d, BITS), VBIGNUM(nmo, BITS / 2), VBIGNUM(x, BITS); + const VBigDig *mu; + + mu = v_bignum_reduce_begin(n); + + /* Pick a "witness", a number in the [1, n) range. */ + v_bignum_set_random(a, gen); + v_bignum_reduce(a, n, mu); + + v_bignum_set_one(d); + v_bignum_set_bignum(nmo, n); + v_bignum_sub_digit(nmo, 1); /* nmo = n - 1 (say it). */ + k = v_bignum_bit_msb(nmo); + for(i = k; i >= 0; i--) + { + v_bignum_set_bignum(x, d); + v_bignum_square_half(d); + v_bignum_reduce(d, n, mu); + if(v_bignum_eq_one(d) && !v_bignum_eq_one(x) && !v_bignum_eq(x, nmo)) + { + v_bignum_reduce_end(mu); + return 0; /* Composite found. */ + } + if(v_bignum_bit_test(nmo, i)) + { + v_bignum_mul(d, a); + v_bignum_reduce(d, n, mu); + } + } + v_bignum_reduce_end(mu); + return v_bignum_eq_one(d); /* It might be prime. */ +} + +/* Test q for primality, returning 1 if it seems prime, 0 if it certainly IS not. */ +int v_prime_test(const VBigDig *q, VRandGen *gen) +{ + int i; + + if(!quick_filter(q)) + return 0; + + for(i = 0; i < CYCLES; i++) + { + if(!miller_rabin(q, gen)) + return 0; + } + return 1; +} + +void v_prime_set_random(VBigDig *x) +{ + int bits = v_bignum_bit_size(x); + VRandGen *gen; + + gen = v_randgen_new(); + do + { + /* Create candidate, making sure it's both odd and non-zero. */ + v_bignum_set_random(x, gen); + /* Set topmost two bits, makes sure products are big. */ + v_bignum_bit_set(x, bits - 1); + v_bignum_bit_set(x, bits - 2); + /* Set lowermost bit, makes sure it is odd (better prime candidate that way). */ + v_bignum_bit_set(x, 0); + } while(!v_prime_test(x, gen)); +/* printf("Prime found after %d iterations: ", count); + v_bignum_print_hex_lf(x); +*/ + v_randgen_destroy(gen); +} + +/* Big (small?) primes from . */ +void v_prime_set_table(VBigDig *x, unsigned int i) +{ + if(i == 0) + v_bignum_set_string_hex(x, "0xCBC2C5536E3D6283FDAF36B1D0F91C3EAAB1D12892B961B866907930F6471851"); + else if(i == 1) + v_bignum_set_string_hex(x, "0xC14F93E7A1543BD57C1DFBE98C29F9E4C13077FD27A0FEC05CCBC913CD213F19"); + else + v_bignum_set_string(x, "65537"); /* It ain't big, but it's prime. */ +} + +#if PRIMEALONE +#include + +#define REPS 300 + +static double elapsed(const struct timeval *t1, const struct timeval *t2) +{ + return t2->tv_sec - t1->tv_sec + 1E-6 * (t2->tv_usec - t1->tv_usec); +} + +int main(void) +{ + struct timeval now, then; + VBigDig VBIGNUM(x, BITS / 2); + int i; + + srand(clock()); + +/* gettimeofday(&then, NULL); + for(i = 0; i < REPS; i++) + { + v_prime_set_random_incr(x); + } + gettimeofday(&now, NULL); + printf("incr: %g\n", elapsed(&then, &now)); +*/ + gettimeofday(&then, NULL); + for(i = 0; i < REPS; i++) + { + v_prime_set_random(x); + } + gettimeofday(&now, NULL); + printf("rand: %g\n", elapsed(&then, &now)); + + return EXIT_SUCCESS; +} + +#endif diff --git a/extern/verse/dist/v_randgen.c b/extern/verse/dist/v_randgen.c new file mode 100644 index 00000000000..c65b48be60b --- /dev/null +++ b/extern/verse/dist/v_randgen.c @@ -0,0 +1,101 @@ +/* + * Random number generator module. Defines a simple API to allocate, use and + * destroy a generator of randomness. Relies on platform-specific APIs. +*/ + +#include +#include + +#include "v_randgen.h" + +#if defined _WIN32 + +/* This is a fall-back to the old style of simply using rand(). It should + * be replaced by something using the proper Win32 cryptography APIs. + * The CryptAcquireContext() and CryptGenRandom() calls sound interesting. + * + * FIXME: Replace ASAP. +*/ + +VRandGen * v_randgen_new(void) +{ + return (VRandGen *) 1; /* Anything that isn't NULL. */ +} + +void v_randgen_get(VRandGen *gen, void *bytes, size_t num) +{ + if(gen != NULL && bytes != NULL) + { + unsigned char *put = bytes, *get; + size_t i; + int x; + + while(num > 0) + { + x = rand(); + get = (unsigned char *) &x; + for(i = 0; i < sizeof x && num > 0; i++, num--) + *put++ = *get++; + } + } +} + +void v_randgen_destroy(VRandGen *gen) +{ + /* Nothing to do here. */ +} + +#else + +/* On non-Win32 platforms (which is Linux and Darwin, at the moment), we + * read random data from a file, which is assumed to be one of the kernel's + * virtual files. +*/ + +#include +#include +#include +#include + +struct VRandGen { + int fd; +}; + +#define SOURCE "/dev/urandom" /* Name of file to read random bits from. */ + +VRandGen * v_randgen_new(void) +{ + VRandGen *gen; + + if((gen = malloc(sizeof *gen)) != NULL) + { + gen->fd = open(SOURCE, O_RDONLY); + if(gen->fd < 0) + { + fprintf(stderr, __FILE__ ": Couldn't open " SOURCE " for reading\n"); + free(gen); + gen = NULL; + } + } + return gen; +} + +void v_randgen_get(VRandGen *gen, void *bytes, size_t num) +{ + if(gen != NULL && bytes != NULL) + { + if(read(gen->fd, bytes, num) != (int) num) + fprintf(stderr, __FILE__ ": Failed to read %u bytes of random data from " SOURCE "\n", (unsigned int) num); + } +} + +void v_randgen_destroy(VRandGen *gen) +{ + if(gen != NULL) + { + close(gen->fd); + free(gen); + } +} + +#endif diff --git a/extern/verse/dist/v_randgen.h b/extern/verse/dist/v_randgen.h new file mode 100644 index 00000000000..ee14ce6c36f --- /dev/null +++ b/extern/verse/dist/v_randgen.h @@ -0,0 +1,14 @@ +/* + * Random number generator API. A way to improve over rand(). +*/ + +#if !defined V_RANDGEN_H +#define V_RANDGEN_H + +typedef struct VRandGen VRandGen; + +extern VRandGen * v_randgen_new(void); +extern void v_randgen_get(VRandGen *gen, void *bytes, size_t num); +extern void v_randgen_destroy(VRandGen *gen); + +#endif /* V_RANDGEN_H */ diff --git a/extern/verse/dist/v_util.c b/extern/verse/dist/v_util.c new file mode 100644 index 00000000000..a36f4c77791 --- /dev/null +++ b/extern/verse/dist/v_util.c @@ -0,0 +1,98 @@ +/* + * Utility functions. +*/ + +#include + +#include "verse_header.h" +#include "v_network.h" +#include "v_util.h" + +/* Safe string copy. Copies from to , not using more than + * bytes of destination space. Always 0-terminates the destination. Returns + * the beginning of the destination string. +*/ +char * v_strlcpy(char *dst, const char *src, size_t size) +{ + char *base = dst; + + if(size == 0) + return NULL; + for(size--; size > 0 && *src != '\0'; size--) + *dst++ = *src++; + *dst = '\0'; + + return base; +} + +void v_timer_start(VUtilTimer *timer) +{ + v_n_get_current_time(&timer->seconds, &timer->fractions); +} + +void v_timer_advance(VUtilTimer *timer, double seconds) +{ + if(timer == NULL) + return; + timer->seconds += (uint32) seconds; + timer->fractions += (uint32) ((seconds - (int) seconds) * (double) 0xffffffff); +} + +double v_timer_elapsed(const VUtilTimer *timer) +{ + uint32 cur_seconds, cur_fractions; + + v_n_get_current_time(&cur_seconds, &cur_fractions); + return (double)(cur_seconds - timer->seconds) + ((double)cur_fractions - (double)timer->fractions) / (double) 0xffffffff; +} + +void v_timer_print(const VUtilTimer *timer) +{ + uint32 cur_seconds, cur_fractions; + + v_n_get_current_time(&cur_seconds, &cur_fractions); + printf("%f", (double)(cur_seconds - timer->seconds) + ((double)cur_fractions - (double)timer->fractions) / (double) 0xffffffff); +} + +/* Compare |x| against built-in semi-magical constant, and return 1 if it's larger, 0 if not. */ +static int quat_valid(real64 x) +{ + const real64 EPSILON = 0.0000001; + return x > 0.0 ? x > EPSILON : x < -EPSILON; +} + +int v_quat32_valid(const VNQuat32 *q) +{ + if(q == NULL) + return 0; + return quat_valid(q->x) && quat_valid(q->y) && quat_valid(q->z) && quat_valid(q->w); +} + +int v_quat64_valid(const VNQuat64 *q) +{ + if(q == NULL) + return 0; + return quat_valid(q->x) && quat_valid(q->y) && quat_valid(q->z) && quat_valid(q->w); +} + +VNQuat32 * v_quat32_from_quat64(VNQuat32 *dst, const VNQuat64 *src) +{ + if(dst == NULL || src == NULL) + return NULL; + dst->x = (real32) src->x; + dst->y = (real32) src->y; + dst->z = (real32) src->z; + dst->w = (real32) src->w; + return dst; +} + +VNQuat64 * v_quat64_from_quat32(VNQuat64 *dst, const VNQuat32 *src) +{ + if(dst == NULL || src == NULL) + return NULL; + dst->x = src->x; + dst->y = src->y; + dst->z = src->z; + dst->w = src->w; + return dst; +} diff --git a/extern/verse/dist/v_util.h b/extern/verse/dist/v_util.h new file mode 100644 index 00000000000..d252d958549 --- /dev/null +++ b/extern/verse/dist/v_util.h @@ -0,0 +1,21 @@ +/* + * Miscellaneous utility routines for generic use throughout the code. +*/ + +/* Safe, buffer size limited, string copy. */ +extern char * v_strlcpy(char *dst, const char *src, size_t size); + +typedef struct { + uint32 seconds; + uint32 fractions; +} VUtilTimer; + +extern void v_timer_start(VUtilTimer *timer); +extern void v_timer_advance(VUtilTimer *timer, double seconds); +extern double v_timer_elapsed(const VUtilTimer *timer); +extern void v_timer_print(const VUtilTimer *timer); + +extern int v_quat32_valid(const VNQuat32 *q); +extern int v_quat64_valid(const VNQuat64 *q); +extern VNQuat32*v_quat32_from_quat64(VNQuat32 *dst, const VNQuat64 *src); +extern VNQuat64*v_quat64_from_quat32(VNQuat64 *dst, const VNQuat32 *src); diff --git a/extern/verse/dist/verse.h b/extern/verse/dist/verse.h new file mode 100644 index 00000000000..53ce674725a --- /dev/null +++ b/extern/verse/dist/verse.h @@ -0,0 +1,530 @@ +/* +** Verse API Header file (for use with libverse.a). +** This is automatically generated code; do not edit. +*/ + + +#if !defined VERSE_H + +#if defined __cplusplus /* Declare as C symbols for C++ users. */ +extern "C" { +#endif + +#define VERSE_H + +#if !defined VERSE_TYPES +#define VERSE_TYPES + +#include + +/* Release information. */ +#define V_RELEASE_NUMBER 6 +#define V_RELEASE_PATCH 1 +#define V_RELEASE_LABEL "" + +typedef unsigned char boolean; +typedef signed char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef float real32; +typedef double real64; + +#define V_REAL64_MAX 1.7976931348623158e+308 +#define V_REAL32_MAX 3.402823466e+38f + +#if !defined TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define V_HOST_ID_SIZE (3 * (512 / 8)) /* The size of host IDs (keys), in 8-bit bytes. */ + +typedef enum { + V_NT_OBJECT = 0, + V_NT_GEOMETRY, + V_NT_MATERIAL, + V_NT_BITMAP, + V_NT_TEXT, + V_NT_CURVE, + V_NT_AUDIO, + V_NT_NUM_TYPES, + V_NT_SYSTEM = V_NT_NUM_TYPES, + V_NT_NUM_TYPES_NETPACK +} VNodeType; + +typedef uint32 VNodeID; +typedef uint16 VLayerID; /* Commonly used to identify layers, nodes that have them. */ +typedef uint16 VBufferID; /* Commonly used to identify buffers, nodes that have them. */ +typedef uint16 VNMFragmentID; + +typedef void * VSession; + +#define V_MAX_NAME_LENGTH_SHORT 16 +#define V_MAX_NAME_LENGTH_LONG 48 +#define V_MAX_NAME_PASS_LENGTH 128 + +typedef enum { + VN_OWNER_OTHER = 0, + VN_OWNER_MINE +} VNodeOwner; + +typedef enum { + VN_O_METHOD_PTYPE_INT8 = 0, + VN_O_METHOD_PTYPE_INT16, + VN_O_METHOD_PTYPE_INT32, + + VN_O_METHOD_PTYPE_UINT8, + VN_O_METHOD_PTYPE_UINT16, + VN_O_METHOD_PTYPE_UINT32, + + VN_O_METHOD_PTYPE_REAL32, + VN_O_METHOD_PTYPE_REAL64, + + VN_O_METHOD_PTYPE_REAL32_VEC2, + VN_O_METHOD_PTYPE_REAL32_VEC3, + VN_O_METHOD_PTYPE_REAL32_VEC4, + + VN_O_METHOD_PTYPE_REAL64_VEC2, + VN_O_METHOD_PTYPE_REAL64_VEC3, + VN_O_METHOD_PTYPE_REAL64_VEC4, + + VN_O_METHOD_PTYPE_REAL32_MAT4, + VN_O_METHOD_PTYPE_REAL32_MAT9, + VN_O_METHOD_PTYPE_REAL32_MAT16, + + VN_O_METHOD_PTYPE_REAL64_MAT4, + VN_O_METHOD_PTYPE_REAL64_MAT9, + VN_O_METHOD_PTYPE_REAL64_MAT16, + + VN_O_METHOD_PTYPE_STRING, + + VN_O_METHOD_PTYPE_NODE, + VN_O_METHOD_PTYPE_LAYER +} VNOParamType; + +typedef union { + int8 vint8; + int16 vint16; + int32 vint32; + uint8 vuint8; + uint16 vuint16; + uint32 vuint32; + real32 vreal32; + real64 vreal64; + real32 vreal32_vec[4]; + real32 vreal32_mat[16]; + real64 vreal64_vec[4]; + real64 vreal64_mat[16]; + char *vstring; + VNodeID vnode; + VLayerID vlayer; +} VNOParam; + +#define VN_TAG_MAX_BLOB_SIZE 500 + +typedef enum { + VN_TAG_BOOLEAN = 0, + VN_TAG_UINT32, + VN_TAG_REAL64, + VN_TAG_STRING, + VN_TAG_REAL64_VEC3, + VN_TAG_LINK, + VN_TAG_ANIMATION, + VN_TAG_BLOB, + VN_TAG_TYPE_COUNT +} VNTagType; + +typedef enum { + VN_TAG_GROUP_SIZE = 16, + VN_TAG_NAME_SIZE = 16, + VN_TAG_FULL_NAME_SIZE = 64, + VN_TAG_STRING_SIZE = 128 +} VNTagConstants; + +typedef union { + boolean vboolean; + uint32 vuint32; + real64 vreal64; + char *vstring; + real64 vreal64_vec3[3]; + VNodeID vlink; + struct { + VNodeID curve; + uint32 start; + uint32 end; + } vanimation; + struct { + uint16 size; + void *blob; + } vblob; +} VNTag; + +typedef enum { + VN_S_CONNECT_NAME_SIZE = 32, + VN_S_CONNECT_KEY_SIZE = 4, + VN_S_CONNECT_DATA_SIZE = 32, + VS_S_CONNECT_HOSTID_PRIVATE_SIZE = 3 * 2048 / 8, + VS_S_CONNECT_HOSTID_PUBLIC_SIZE = 2 * 2048 / 8 +} VNSConnectConstants; + +typedef enum { + VN_FORMAT_REAL32, + VN_FORMAT_REAL64 +} VNRealFormat; + +typedef struct { + real32 x, y, z, w; +} VNQuat32; + +typedef struct { + real64 x, y, z, w; +} VNQuat64; + +typedef enum { + VN_O_METHOD_GROUP_NAME_SIZE = 16, + VN_O_METHOD_NAME_SIZE = 16, + VN_O_METHOD_SIG_SIZE = 256 +} VNOMethodConstants; + +typedef void VNOPackedParams; /* Opaque type. */ + +typedef enum { + VN_G_LAYER_VERTEX_XYZ = 0, + VN_G_LAYER_VERTEX_UINT32, + VN_G_LAYER_VERTEX_REAL, + VN_G_LAYER_POLYGON_CORNER_UINT32 = 128, + VN_G_LAYER_POLYGON_CORNER_REAL, + VN_G_LAYER_POLYGON_FACE_UINT8, + VN_G_LAYER_POLYGON_FACE_UINT32, + VN_G_LAYER_POLYGON_FACE_REAL +} VNGLayerType; + +typedef enum { + VN_M_LIGHT_DIRECT = 0, + VN_M_LIGHT_AMBIENT, + VN_M_LIGHT_DIRECT_AND_AMBIENT, + VN_M_LIGHT_BACK_DIRECT, + VN_M_LIGHT_BACK_AMBIENT, + VN_M_LIGHT_BACK_DIRECT_AND_AMBIENT +} VNMLightType; + +typedef enum { + VN_M_NOISE_PERLIN_ZERO_TO_ONE = 0, + VN_M_NOISE_PERLIN_MINUS_ONE_TO_ONE, + VN_M_NOISE_POINT_ZERO_TO_ONE, + VN_M_NOISE_POINT_MINUS_ONE_TO_ONE +} VNMNoiseType; + +typedef enum { + VN_M_RAMP_SQUARE = 0, + VN_M_RAMP_LINEAR, + VN_M_RAMP_SMOOTH +} VNMRampType; + +typedef enum { + VN_M_RAMP_RED = 0, + VN_M_RAMP_GREEN, + VN_M_RAMP_BLUE +} VNMRampChannel; + +typedef struct { + real64 pos; + real64 red; + real64 green; + real64 blue; +} VNMRampPoint; + +typedef enum { + VN_M_BLEND_FADE = 0, + VN_M_BLEND_ADD, + VN_M_BLEND_SUBTRACT, + VN_M_BLEND_MULTIPLY, + VN_M_BLEND_DIVIDE, +} VNMBlendType; + +typedef enum { + VN_M_FT_COLOR = 0, + VN_M_FT_LIGHT, + VN_M_FT_REFLECTION, + VN_M_FT_TRANSPARENCY, + VN_M_FT_VOLUME, + VN_M_FT_VIEW, + VN_M_FT_GEOMETRY, + VN_M_FT_TEXTURE, + VN_M_FT_NOISE, + VN_M_FT_BLENDER, + VN_M_FT_CLAMP, + VN_M_FT_MATRIX, + VN_M_FT_RAMP, + VN_M_FT_ANIMATION, + VN_M_FT_ALTERNATIVE, + VN_M_FT_OUTPUT +} VNMFragmentType; + +typedef union { + struct { + real64 red; + real64 green; + real64 blue; + } color; + struct { + uint8 type; + real64 normal_falloff; + VNodeID brdf; + char brdf_r[16]; + char brdf_g[16]; + char brdf_b[16]; + } light; + struct { + real64 normal_falloff; + } reflection; + struct { + real64 normal_falloff; + real64 refraction_index; + } transparency; + struct { + real64 diffusion; + real64 col_r; + real64 col_g; + real64 col_b; + } volume; + struct { + char layer_r[16]; + char layer_g[16]; + char layer_b[16]; + } geometry; + struct{ + VNodeID bitmap; + char layer_r[16]; + char layer_g[16]; + char layer_b[16]; + boolean filtered; + VNMFragmentID mapping; + } texture; + struct { + uint8 type; + VNMFragmentID mapping; + } noise; + struct { + uint8 type; + VNMFragmentID data_a; + VNMFragmentID data_b; + VNMFragmentID control; + } blender; + struct { + boolean min; + real64 red; + real64 green; + real64 blue; + VNMFragmentID data; + } clamp; + struct { + real64 matrix[16]; + VNMFragmentID data; + } matrix; + struct { + uint8 type; + uint8 channel; + VNMFragmentID mapping; + uint8 point_count; + VNMRampPoint ramp[48]; + } ramp; + struct { + char label[16]; + } animation; + struct { + VNMFragmentID alt_a; + VNMFragmentID alt_b; + } alternative; + struct { + char label[16]; + VNMFragmentID front; + VNMFragmentID back; + } output; +} VMatFrag; + +typedef enum { + VN_B_LAYER_UINT1 = 0, + VN_B_LAYER_UINT8, + VN_B_LAYER_UINT16, + VN_B_LAYER_REAL32, + VN_B_LAYER_REAL64 +} VNBLayerType; + +#define VN_B_TILE_SIZE 8 + +typedef union{ + uint8 vuint1[8]; + uint8 vuint8[64]; + uint16 vuint16[64]; + real32 vreal32[64]; + real64 vreal64[64]; +} VNBTile; + +typedef enum { + VN_T_CONTENT_LANGUAGE_SIZE = 32, + VN_T_CONTENT_INFO_SIZE = 256, + VN_T_BUFFER_NAME_SIZE = 16, + VN_T_MAX_TEXT_CMD_SIZE = 1450 +} VNTConstants; + +/* This is how many *samples* are included in a block of the given type. Not bytes. */ +typedef enum { + VN_A_BLOCK_SIZE_INT8 = 1024, + VN_A_BLOCK_SIZE_INT16 = 512, + VN_A_BLOCK_SIZE_INT24 = 384, + VN_A_BLOCK_SIZE_INT32 = 256, + VN_A_BLOCK_SIZE_REAL32 = 256, + VN_A_BLOCK_SIZE_REAL64 = 128 +} VNAConstants; + +typedef enum { + VN_A_BLOCK_INT8, + VN_A_BLOCK_INT16, + VN_A_BLOCK_INT24, + VN_A_BLOCK_INT32, + VN_A_BLOCK_REAL32, + VN_A_BLOCK_REAL64 +} VNABlockType; + +/* Audio commands take pointers to blocks of these. They are not packed as unions. */ +typedef union { + int8 vint8[VN_A_BLOCK_SIZE_INT8]; + int16 vint16[VN_A_BLOCK_SIZE_INT16]; + int32 vint24[VN_A_BLOCK_SIZE_INT24]; + int32 vint32[VN_A_BLOCK_SIZE_INT32]; + real32 vreal32[VN_A_BLOCK_SIZE_REAL32]; + real64 vreal64[VN_A_BLOCK_SIZE_REAL64]; +} VNABlock; + +extern void verse_set_port(uint16 port); +extern void verse_host_id_create(uint8 *id); +extern void verse_host_id_set(uint8 *id); +extern void verse_callback_set(void *send_func, void *callback, void *user_data); +extern void verse_callback_update(uint32 microseconds); +extern void verse_session_set(VSession session); +extern VSession verse_session_get(void); +extern void verse_session_destroy(VSession session); +extern size_t verse_session_get_size(void); +extern VNodeID verse_session_get_avatar(void); +extern void verse_session_get_time(uint32 *seconds, uint32 *fractions); + +extern VNOPackedParams * verse_method_call_pack(uint32 param_count, const VNOParamType *param_type, const VNOParam *params); +extern boolean verse_method_call_unpack(const VNOPackedParams *data, uint32 param_count, const VNOParamType *param_type, VNOParam *params); + +/* +#define V_PRINT_SEND_COMMANDS +#define V_PRINT_RECEIVE_COMMANDS +*/ + +#endif /* VERSE_TYPES */ + +/* Command sending functions begin. ----------------------------------------- */ + +extern VSession verse_send_connect(const char *name, const char *pass, const char *address, const uint8 *expected_host_id); +extern VSession verse_send_connect_accept(VNodeID avatar, const char *address, uint8 *host_id); +extern void verse_send_connect_terminate(const char *address, const char *bye); +extern void verse_send_ping(const char *address, const char *message); +extern void verse_send_node_index_subscribe(uint32 mask); +extern void verse_send_node_create(VNodeID node_id, VNodeType type, VNodeOwner owner); +extern void verse_send_node_destroy(VNodeID node_id); +extern void verse_send_node_subscribe(VNodeID node_id); +extern void verse_send_node_unsubscribe(VNodeID node_id); +extern void verse_send_tag_group_create(VNodeID node_id, uint16 group_id, const char *name); +extern void verse_send_tag_group_destroy(VNodeID node_id, uint16 group_id); +extern void verse_send_tag_group_subscribe(VNodeID node_id, uint16 group_id); +extern void verse_send_tag_group_unsubscribe(VNodeID node_id, uint16 group_id); +extern void verse_send_tag_create(VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); +extern void verse_send_tag_destroy(VNodeID node_id, uint16 group_id, uint16 tag_id); +extern void verse_send_node_name_set(VNodeID node_id, const char *name); + +extern void verse_send_o_transform_pos_real32(VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag); +extern void verse_send_o_transform_rot_real32(VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag); +extern void verse_send_o_transform_scale_real32(VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z); +extern void verse_send_o_transform_pos_real64(VNodeID node_id, uint32 time_s, uint32 time_f, const real64 *pos, const real64 *speed, const real64 *accelerate, const real64 *drag_normal, real64 drag); +extern void verse_send_o_transform_rot_real64(VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat64 *rot, const VNQuat64 *speed, const VNQuat64 *accelerate, const VNQuat64 *drag_normal, real64 drag); +extern void verse_send_o_transform_scale_real64(VNodeID node_id, real64 scale_x, real64 scale_y, real64 scale_z); +extern void verse_send_o_transform_subscribe(VNodeID node_id, VNRealFormat type); +extern void verse_send_o_transform_unsubscribe(VNodeID node_id, VNRealFormat type); +extern void verse_send_o_light_set(VNodeID node_id, real64 light_r, real64 light_g, real64 light_b); +extern void verse_send_o_link_set(VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id); +extern void verse_send_o_link_destroy(VNodeID node_id, uint16 link_id); +extern void verse_send_o_method_group_create(VNodeID node_id, uint16 group_id, const char *name); +extern void verse_send_o_method_group_destroy(VNodeID node_id, uint16 group_id); +extern void verse_send_o_method_group_subscribe(VNodeID node_id, uint16 group_id); +extern void verse_send_o_method_group_unsubscribe(VNodeID node_id, uint16 group_id); +extern void verse_send_o_method_create(VNodeID node_id, uint16 group_id, uint16 method_id, const char *name, uint8 param_count, const VNOParamType *param_types, const char * *param_names); +extern void verse_send_o_method_destroy(VNodeID node_id, uint16 group_id, uint16 method_id); +extern void verse_send_o_method_call(VNodeID node_id, uint16 group_id, uint16 method_id, VNodeID sender, const VNOPackedParams *params); +extern void verse_send_o_anim_run(VNodeID node_id, uint16 link_id, uint32 time_s, uint32 time_f, uint8 dimensions, const real64 *pos, const real64 *speed, const real64 *accel, const real64 *scale, const real64 *scale_speed); +extern void verse_send_o_hide(VNodeID node_id, uint8 hidden); + +extern void verse_send_g_layer_create(VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_uint, real64 def_real); +extern void verse_send_g_layer_destroy(VNodeID node_id, VLayerID layer_id); +extern void verse_send_g_layer_subscribe(VNodeID node_id, VLayerID layer_id, VNRealFormat type); +extern void verse_send_g_layer_unsubscribe(VNodeID node_id, VLayerID layer_id); +extern void verse_send_g_vertex_set_xyz_real32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z); +extern void verse_send_g_vertex_delete_real32(VNodeID node_id, uint32 vertex_id); +extern void verse_send_g_vertex_set_xyz_real64(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 x, real64 y, real64 z); +extern void verse_send_g_vertex_delete_real64(VNodeID node_id, uint32 vertex_id); +extern void verse_send_g_vertex_set_uint32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, uint32 value); +extern void verse_send_g_vertex_set_real64(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 value); +extern void verse_send_g_vertex_set_real32(VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 value); +extern void verse_send_g_polygon_set_corner_uint32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); +extern void verse_send_g_polygon_delete(VNodeID node_id, uint32 polygon_id); +extern void verse_send_g_polygon_set_corner_real64(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 v0, real64 v1, real64 v2, real64 v3); +extern void verse_send_g_polygon_set_corner_real32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 v0, real32 v1, real32 v2, real32 v3); +extern void verse_send_g_polygon_set_face_uint8(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint8 value); +extern void verse_send_g_polygon_set_face_uint32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 value); +extern void verse_send_g_polygon_set_face_real64(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 value); +extern void verse_send_g_polygon_set_face_real32(VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real32 value); +extern void verse_send_g_crease_set_vertex(VNodeID node_id, const char *layer, uint32 def_crease); +extern void verse_send_g_crease_set_edge(VNodeID node_id, const char *layer, uint32 def_crease); +extern void verse_send_g_bone_create(VNodeID node_id, uint16 bone_id, const char *weight, const char *reference, uint16 parent, real64 pos_x, real64 pos_y, real64 pos_z, const char *position_label, const char *rotation_label, const char *scale_label); +extern void verse_send_g_bone_destroy(VNodeID node_id, uint16 bone_id); + +extern void verse_send_m_fragment_create(VNodeID node_id, VNMFragmentID frag_id, VNMFragmentType type, const VMatFrag *fragment); +extern void verse_send_m_fragment_destroy(VNodeID node_id, VNMFragmentID frag_id); + +extern void verse_send_b_dimensions_set(VNodeID node_id, uint16 width, uint16 height, uint16 depth); +extern void verse_send_b_layer_create(VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type); +extern void verse_send_b_layer_destroy(VNodeID node_id, VLayerID layer_id); +extern void verse_send_b_layer_subscribe(VNodeID node_id, VLayerID layer_id, uint8 level); +extern void verse_send_b_layer_unsubscribe(VNodeID node_id, VLayerID layer_id); +extern void verse_send_b_tile_set(VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile); + +extern void verse_send_t_language_set(VNodeID node_id, const char *language); +extern void verse_send_t_buffer_create(VNodeID node_id, VBufferID buffer_id, const char *name); +extern void verse_send_t_buffer_destroy(VNodeID node_id, VBufferID buffer_id); +extern void verse_send_t_buffer_subscribe(VNodeID node_id, VBufferID buffer_id); +extern void verse_send_t_buffer_unsubscribe(VNodeID node_id, VBufferID buffer_id); +extern void verse_send_t_text_set(VNodeID node_id, VBufferID buffer_id, uint32 pos, uint32 length, const char *text); + +extern void verse_send_c_curve_create(VNodeID node_id, VLayerID curve_id, const char *name, uint8 dimensions); +extern void verse_send_c_curve_destroy(VNodeID node_id, VLayerID curve_id); +extern void verse_send_c_curve_subscribe(VNodeID node_id, VLayerID curve_id); +extern void verse_send_c_curve_unsubscribe(VNodeID node_id, VLayerID curve_id); +extern void verse_send_c_key_set(VNodeID node_id, VLayerID curve_id, uint32 key_id, uint8 dimensions, const real64 *pre_value, const uint32 *pre_pos, const real64 *value, real64 pos, const real64 *post_value, const uint32 *post_pos); +extern void verse_send_c_key_destroy(VNodeID node_id, VLayerID curve_id, uint32 key_id); + +extern void verse_send_a_buffer_create(VNodeID node_id, VBufferID buffer_id, const char *name, VNABlockType type, real64 frequency); +extern void verse_send_a_buffer_destroy(VNodeID node_id, VBufferID buffer_id); +extern void verse_send_a_buffer_subscribe(VNodeID node_id, VBufferID layer_id); +extern void verse_send_a_buffer_unsubscribe(VNodeID node_id, VBufferID layer_id); +extern void verse_send_a_block_set(VNodeID node_id, VLayerID buffer_id, uint32 block_index, VNABlockType type, const VNABlock *samples); +extern void verse_send_a_block_clear(VNodeID node_id, VLayerID buffer_id, uint32 block_index); +extern void verse_send_a_stream_create(VNodeID node_id, VLayerID stream_id, const char *name); +extern void verse_send_a_stream_destroy(VNodeID node_id, VLayerID stream_id); +extern void verse_send_a_stream_subscribe(VNodeID node_id, VLayerID stream_id); +extern void verse_send_a_stream_unsubscribe(VNodeID node_id, VLayerID stream_id); +extern void verse_send_a_stream(VNodeID node_id, VLayerID stream_id, uint32 time_s, uint32 time_f, VNABlockType type, real64 frequency, const VNABlock *samples); + + +#if defined __cplusplus +} +#endif + +#endif /* VERSE_H */ diff --git a/extern/verse/dist/verse_header.h b/extern/verse/dist/verse_header.h new file mode 100644 index 00000000000..3f3403265fd --- /dev/null +++ b/extern/verse/dist/verse_header.h @@ -0,0 +1,409 @@ +#if !defined VERSE_TYPES +#define VERSE_TYPES + +#include + +/* Release information. */ +#define V_RELEASE_NUMBER 6 +#define V_RELEASE_PATCH 1 +#define V_RELEASE_LABEL "" + +typedef unsigned char boolean; +typedef signed char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef float real32; +typedef double real64; + +#define V_REAL64_MAX 1.7976931348623158e+308 +#define V_REAL32_MAX 3.402823466e+38f + +#if !defined TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define V_HOST_ID_SIZE (3 * (512 / 8)) /* The size of host IDs (keys), in 8-bit bytes. */ + +typedef enum { + V_NT_OBJECT = 0, + V_NT_GEOMETRY, + V_NT_MATERIAL, + V_NT_BITMAP, + V_NT_TEXT, + V_NT_CURVE, + V_NT_AUDIO, + V_NT_NUM_TYPES, + V_NT_SYSTEM = V_NT_NUM_TYPES, + V_NT_NUM_TYPES_NETPACK +} VNodeType; + +typedef uint32 VNodeID; +typedef uint16 VLayerID; /* Commonly used to identify layers, nodes that have them. */ +typedef uint16 VBufferID; /* Commonly used to identify buffers, nodes that have them. */ +typedef uint16 VNMFragmentID; + +typedef void * VSession; + +#define V_MAX_NAME_LENGTH_SHORT 16 +#define V_MAX_NAME_LENGTH_LONG 48 +#define V_MAX_NAME_PASS_LENGTH 128 + +typedef enum { + VN_OWNER_OTHER = 0, + VN_OWNER_MINE +} VNodeOwner; + +typedef enum { + VN_O_METHOD_PTYPE_INT8 = 0, + VN_O_METHOD_PTYPE_INT16, + VN_O_METHOD_PTYPE_INT32, + + VN_O_METHOD_PTYPE_UINT8, + VN_O_METHOD_PTYPE_UINT16, + VN_O_METHOD_PTYPE_UINT32, + + VN_O_METHOD_PTYPE_REAL32, + VN_O_METHOD_PTYPE_REAL64, + + VN_O_METHOD_PTYPE_REAL32_VEC2, + VN_O_METHOD_PTYPE_REAL32_VEC3, + VN_O_METHOD_PTYPE_REAL32_VEC4, + + VN_O_METHOD_PTYPE_REAL64_VEC2, + VN_O_METHOD_PTYPE_REAL64_VEC3, + VN_O_METHOD_PTYPE_REAL64_VEC4, + + VN_O_METHOD_PTYPE_REAL32_MAT4, + VN_O_METHOD_PTYPE_REAL32_MAT9, + VN_O_METHOD_PTYPE_REAL32_MAT16, + + VN_O_METHOD_PTYPE_REAL64_MAT4, + VN_O_METHOD_PTYPE_REAL64_MAT9, + VN_O_METHOD_PTYPE_REAL64_MAT16, + + VN_O_METHOD_PTYPE_STRING, + + VN_O_METHOD_PTYPE_NODE, + VN_O_METHOD_PTYPE_LAYER +} VNOParamType; + +typedef union { + int8 vint8; + int16 vint16; + int32 vint32; + uint8 vuint8; + uint16 vuint16; + uint32 vuint32; + real32 vreal32; + real64 vreal64; + real32 vreal32_vec[4]; + real32 vreal32_mat[16]; + real64 vreal64_vec[4]; + real64 vreal64_mat[16]; + char *vstring; + VNodeID vnode; + VLayerID vlayer; +} VNOParam; + +#define VN_TAG_MAX_BLOB_SIZE 500 + +typedef enum { + VN_TAG_BOOLEAN = 0, + VN_TAG_UINT32, + VN_TAG_REAL64, + VN_TAG_STRING, + VN_TAG_REAL64_VEC3, + VN_TAG_LINK, + VN_TAG_ANIMATION, + VN_TAG_BLOB, + VN_TAG_TYPE_COUNT +} VNTagType; + +typedef enum { + VN_TAG_GROUP_SIZE = 16, + VN_TAG_NAME_SIZE = 16, + VN_TAG_FULL_NAME_SIZE = 64, + VN_TAG_STRING_SIZE = 128 +} VNTagConstants; + +typedef union { + boolean vboolean; + uint32 vuint32; + real64 vreal64; + char *vstring; + real64 vreal64_vec3[3]; + VNodeID vlink; + struct { + VNodeID curve; + uint32 start; + uint32 end; + } vanimation; + struct { + uint16 size; + void *blob; + } vblob; +} VNTag; + +typedef enum { + VN_S_CONNECT_NAME_SIZE = 32, + VN_S_CONNECT_KEY_SIZE = 4, + VN_S_CONNECT_DATA_SIZE = 32, + VS_S_CONNECT_HOSTID_PRIVATE_SIZE = 3 * 2048 / 8, + VS_S_CONNECT_HOSTID_PUBLIC_SIZE = 2 * 2048 / 8 +} VNSConnectConstants; + +typedef enum { + VN_FORMAT_REAL32, + VN_FORMAT_REAL64 +} VNRealFormat; + +typedef struct { + real32 x, y, z, w; +} VNQuat32; + +typedef struct { + real64 x, y, z, w; +} VNQuat64; + +typedef enum { + VN_O_METHOD_GROUP_NAME_SIZE = 16, + VN_O_METHOD_NAME_SIZE = 16, + VN_O_METHOD_SIG_SIZE = 256 +} VNOMethodConstants; + +typedef void VNOPackedParams; /* Opaque type. */ + +typedef enum { + VN_G_LAYER_VERTEX_XYZ = 0, + VN_G_LAYER_VERTEX_UINT32, + VN_G_LAYER_VERTEX_REAL, + VN_G_LAYER_POLYGON_CORNER_UINT32 = 128, + VN_G_LAYER_POLYGON_CORNER_REAL, + VN_G_LAYER_POLYGON_FACE_UINT8, + VN_G_LAYER_POLYGON_FACE_UINT32, + VN_G_LAYER_POLYGON_FACE_REAL +} VNGLayerType; + +typedef enum { + VN_M_LIGHT_DIRECT = 0, + VN_M_LIGHT_AMBIENT, + VN_M_LIGHT_DIRECT_AND_AMBIENT, + VN_M_LIGHT_BACK_DIRECT, + VN_M_LIGHT_BACK_AMBIENT, + VN_M_LIGHT_BACK_DIRECT_AND_AMBIENT +} VNMLightType; + +typedef enum { + VN_M_NOISE_PERLIN_ZERO_TO_ONE = 0, + VN_M_NOISE_PERLIN_MINUS_ONE_TO_ONE, + VN_M_NOISE_POINT_ZERO_TO_ONE, + VN_M_NOISE_POINT_MINUS_ONE_TO_ONE +} VNMNoiseType; + +typedef enum { + VN_M_RAMP_SQUARE = 0, + VN_M_RAMP_LINEAR, + VN_M_RAMP_SMOOTH +} VNMRampType; + +typedef enum { + VN_M_RAMP_RED = 0, + VN_M_RAMP_GREEN, + VN_M_RAMP_BLUE +} VNMRampChannel; + +typedef struct { + real64 pos; + real64 red; + real64 green; + real64 blue; +} VNMRampPoint; + +typedef enum { + VN_M_BLEND_FADE = 0, + VN_M_BLEND_ADD, + VN_M_BLEND_SUBTRACT, + VN_M_BLEND_MULTIPLY, + VN_M_BLEND_DIVIDE, +} VNMBlendType; + +typedef enum { + VN_M_FT_COLOR = 0, + VN_M_FT_LIGHT, + VN_M_FT_REFLECTION, + VN_M_FT_TRANSPARENCY, + VN_M_FT_VOLUME, + VN_M_FT_VIEW, + VN_M_FT_GEOMETRY, + VN_M_FT_TEXTURE, + VN_M_FT_NOISE, + VN_M_FT_BLENDER, + VN_M_FT_CLAMP, + VN_M_FT_MATRIX, + VN_M_FT_RAMP, + VN_M_FT_ANIMATION, + VN_M_FT_ALTERNATIVE, + VN_M_FT_OUTPUT +} VNMFragmentType; + +typedef union { + struct { + real64 red; + real64 green; + real64 blue; + } color; + struct { + uint8 type; + real64 normal_falloff; + VNodeID brdf; + char brdf_r[16]; + char brdf_g[16]; + char brdf_b[16]; + } light; + struct { + real64 normal_falloff; + } reflection; + struct { + real64 normal_falloff; + real64 refraction_index; + } transparency; + struct { + real64 diffusion; + real64 col_r; + real64 col_g; + real64 col_b; + } volume; + struct { + char layer_r[16]; + char layer_g[16]; + char layer_b[16]; + } geometry; + struct{ + VNodeID bitmap; + char layer_r[16]; + char layer_g[16]; + char layer_b[16]; + boolean filtered; + VNMFragmentID mapping; + } texture; + struct { + uint8 type; + VNMFragmentID mapping; + } noise; + struct { + uint8 type; + VNMFragmentID data_a; + VNMFragmentID data_b; + VNMFragmentID control; + } blender; + struct { + boolean min; + real64 red; + real64 green; + real64 blue; + VNMFragmentID data; + } clamp; + struct { + real64 matrix[16]; + VNMFragmentID data; + } matrix; + struct { + uint8 type; + uint8 channel; + VNMFragmentID mapping; + uint8 point_count; + VNMRampPoint ramp[48]; + } ramp; + struct { + char label[16]; + } animation; + struct { + VNMFragmentID alt_a; + VNMFragmentID alt_b; + } alternative; + struct { + char label[16]; + VNMFragmentID front; + VNMFragmentID back; + } output; +} VMatFrag; + +typedef enum { + VN_B_LAYER_UINT1 = 0, + VN_B_LAYER_UINT8, + VN_B_LAYER_UINT16, + VN_B_LAYER_REAL32, + VN_B_LAYER_REAL64 +} VNBLayerType; + +#define VN_B_TILE_SIZE 8 + +typedef union{ + uint8 vuint1[8]; + uint8 vuint8[64]; + uint16 vuint16[64]; + real32 vreal32[64]; + real64 vreal64[64]; +} VNBTile; + +typedef enum { + VN_T_CONTENT_LANGUAGE_SIZE = 32, + VN_T_CONTENT_INFO_SIZE = 256, + VN_T_BUFFER_NAME_SIZE = 16, + VN_T_MAX_TEXT_CMD_SIZE = 1450 +} VNTConstants; + +/* This is how many *samples* are included in a block of the given type. Not bytes. */ +typedef enum { + VN_A_BLOCK_SIZE_INT8 = 1024, + VN_A_BLOCK_SIZE_INT16 = 512, + VN_A_BLOCK_SIZE_INT24 = 384, + VN_A_BLOCK_SIZE_INT32 = 256, + VN_A_BLOCK_SIZE_REAL32 = 256, + VN_A_BLOCK_SIZE_REAL64 = 128 +} VNAConstants; + +typedef enum { + VN_A_BLOCK_INT8, + VN_A_BLOCK_INT16, + VN_A_BLOCK_INT24, + VN_A_BLOCK_INT32, + VN_A_BLOCK_REAL32, + VN_A_BLOCK_REAL64 +} VNABlockType; + +/* Audio commands take pointers to blocks of these. They are not packed as unions. */ +typedef union { + int8 vint8[VN_A_BLOCK_SIZE_INT8]; + int16 vint16[VN_A_BLOCK_SIZE_INT16]; + int32 vint24[VN_A_BLOCK_SIZE_INT24]; + int32 vint32[VN_A_BLOCK_SIZE_INT32]; + real32 vreal32[VN_A_BLOCK_SIZE_REAL32]; + real64 vreal64[VN_A_BLOCK_SIZE_REAL64]; +} VNABlock; + +extern void verse_set_port(uint16 port); +extern void verse_host_id_create(uint8 *id); +extern void verse_host_id_set(uint8 *id); +extern void verse_callback_set(void *send_func, void *callback, void *user_data); +extern void verse_callback_update(uint32 microseconds); +extern void verse_session_set(VSession session); +extern VSession verse_session_get(void); +extern void verse_session_destroy(VSession session); +extern size_t verse_session_get_size(void); +extern VNodeID verse_session_get_avatar(void); +extern void verse_session_get_time(uint32 *seconds, uint32 *fractions); + +extern VNOPackedParams * verse_method_call_pack(uint32 param_count, const VNOParamType *param_type, const VNOParam *params); +extern boolean verse_method_call_unpack(const VNOPackedParams *data, uint32 param_count, const VNOParamType *param_type, VNOParam *params); + +/* +#define V_PRINT_SEND_COMMANDS +#define V_PRINT_RECEIVE_COMMANDS +*/ + +#endif /* VERSE_TYPES */ diff --git a/extern/verse/dist/verse_ms.c b/extern/verse/dist/verse_ms.c new file mode 100644 index 00000000000..84f3fdb837b --- /dev/null +++ b/extern/verse/dist/verse_ms.c @@ -0,0 +1,286 @@ +/* + * A helper library to send and parse master server pings. See the relevant + * header for details. + * + * This code was written in 2006 by Emil Brink. It is released as public domain. +*/ + +#include +#include +#include +#include + +#include "verse.h" +#include "verse_ms.h" + +/* Build and send a MS:GET packet. */ +void verse_ms_get_send(const char *address, int fields, const char *tags) +{ + char req[128]; + + strcpy(req, "MS:GET IP="); + if(fields & VERSE_MS_FIELD_DESCRIPTION) + strcat(req, "DE"); + if(tags != NULL) + { + strcat(req, " TA="); + strcat(req, tags); + } + verse_send_ping(address, req); +} + +/* Skip assign, i.e. "NAME=" string, at . Stores name into , and then updates + * it. Returns NULL on parse error, in which case the pointer is not advanced. +*/ +static const char * skip_assign(char **put, const char *msg) +{ + if(isalpha(*msg)) + { + char *p = put != NULL ? *put : NULL; + + if(p != NULL) + *p++ = *msg; + msg++; + while(*msg && (isalnum(*msg) || *msg == '_')) + { + if(p != NULL) + *p++ = *msg; + msg++; + } + if(*msg == '=') + { + if(p != NULL) + *p++ = '\0'; + if(put != NULL) + *put = p; + return msg + 1; + } + } + return NULL; +} + +/** Skip value at , optionally storing de-quoted version through , + * which is advanced. Returns NULL on parse error, without updating . +*/ +static const char * skip_value(char **put, const char *msg) +{ + char *p = (put != NULL) ? *put : NULL; + + if(*msg == '"') + { + msg++; + while(*msg != '\0' && *msg != '"') + { + if(*msg == '\\') + { + if(msg[1] != '\0') + msg++; + else + return NULL; + } + if(p != NULL) + *p++ = *msg; + msg++; + } + if(*msg == '"') + { + if(p != NULL) + *p++ = '\0'; + if(put != NULL) + *put = p; + msg++; + if(*msg == '\0' || isspace(*msg)) + return msg; + } + return NULL; + } + while(*msg && !isspace(*msg)) + { + if(*msg == '"') + return NULL; + if(p != NULL) + *p++ = *msg; + msg++; + } + if(p != NULL) + *p++ = '\0'; + if(put != NULL) + *put = p; + return msg; +} + +static const char * put_field(VMSField *field, char **put, const char *src) +{ + const char *ptr; + char *base = *put; + + if((ptr = skip_assign(put, src)) != NULL && ptr - src > 1) + { + field->name = base; + src = ptr; + base = *put; + if((ptr = skip_value(put, src)) != NULL) + { + field->value = base; + return ptr; + } + } + return NULL; +} + +static int cmp_fields(const void *a, const void *b) +{ + return strcmp(((const VMSField *) a)->name, ((const VMSField *) b)->name); +} + +VMSServer ** verse_ms_list_parse(const char *msg) +{ + const char *word[384]; /* Takes quite a lot of stack space. */ + const char *ptr; + char *put; + size_t num_word = 0, i, j, num_ip = 0, num_field, space = 0; + VMSServer **desc, *next; + VMSField *field; + + if(strncmp(msg, "MS:LIST", 7) == 0) + msg += 7; + if(*msg != ' ') + return NULL; + + /* Step one: split the string into words, at whitespace. Split is aware + * of quoting rules for value assignment, this is crucial. This split is + * non-invasive, meaning each "word" will be a suffix. + */ + while(*msg) + { + while(isspace(*msg)) + msg++; + ptr = skip_assign(NULL, msg); + if(ptr != NULL) + { + space += ptr - msg; + word[num_word++] = msg; + msg = ptr; + ptr = skip_value(NULL, msg); + if(ptr == NULL) + { + fprintf(stderr, "Parse error\n"); + return NULL; + } + space += ptr - msg + 1; + msg = ptr; + } + else if(*msg != '\0') + { + fprintf(stderr, "Parse error\n"); + return NULL; + } + } + /* Now, count how many words begin with "IP=". */ + for(i = 0; i < num_word; i++) + { + if(strncmp(word[i], "IP=", 3) == 0) + num_ip++; + } +/* printf("found %u IPs, %u bytes\n", num_ip, space); + printf("%u IP and %u words -> %u fields total\n", num_ip, num_word, num_word - num_ip); +*/ num_field = num_word - num_ip; + /* Allocate the descriptions. */ +/* printf("allocating %u bytes\n", (num_ip + 1) * (sizeof *desc) + num_ip * sizeof **desc + num_field * sizeof (VMSField) + space); + printf(" %u for pointers, %u for structs, %u for fields, %u string\n", + (num_ip + 1) * (sizeof *desc), num_ip * sizeof **desc, num_field * sizeof (VMSField), space); +*/ desc = malloc((num_ip + 1) * (sizeof *desc) + num_ip * sizeof **desc + num_field * sizeof (VMSField) + space); + next = (VMSServer *) (desc + (num_ip + 1)); +/* printf("desc store at %u\n", (char *) next - (char *) desc);*/ + field = (VMSField *) (next + num_ip); +/* printf("field store at %u\n", (char *) field - (char *) desc);*/ + put = (char *) (field + num_field); +/* printf("string store at %u\n", put - (char *) desc);*/ + for(i = j = 0; i < num_word;) + { + if(strncmp(word[i], "IP=", 3) == 0) + { + desc[j] = next; + next->ip = put; + ptr = skip_value(&put, word[i] + 3); + next->num_fields = 0; + next->field = field; + for(i++; i < num_word && strncmp(word[i], "IP=", 3) != 0; i++, next->num_fields++, field++) + put_field(&next->field[next->num_fields], &put, word[i]); + if(next->num_fields > 0) /* Sort the fields, for binary search later. */ + qsort(next->field, next->num_fields, sizeof *next->field, cmp_fields); + j++; + next++; + } + else + i++; + } + desc[j] = NULL; + return desc; +} + +/* A binary search, exploiting that the fields are sorted. */ +static const VMSField * field_find(const VMSServer *ms, const char *name) +{ + int lo, hi, mid, rel; + + if(ms == NULL || name == NULL) + return NULL; + lo = 0; + hi = ms->num_fields; + while(lo <= hi) + { + mid = (lo + hi) / 2; + rel = strcmp(name, ms->field[mid].name); + if(rel == 0) + return &ms->field[mid]; + if(rel < 0) + hi = mid - 1; + else + lo = mid + 1; + } + return NULL; +} + +int verse_ms_field_exists(const VMSServer *ms, const char *name) +{ + if(ms == NULL || name == NULL) + return 0; + return field_find(ms, name) != NULL; +} + +const char * verse_ms_field_value(const VMSServer *ms, const char *name) +{ + const VMSField *f; + + if((f = field_find(ms, name)) != NULL) + return f->value; + return NULL; +} + +#if defined VERSE_MS_STANDALONE + +int main(void) +{ + VMSServer **servers = verse_ms_list_parse("MS:LIST IP=127.0.0.1:4951 DE=\"A test server, mainly for Eskil\" COOL=yes BACKUP=daily LANG=sv_SE " + "IP=130.237.221.74 DE=\"Test server on a puny laptop\" COOL=yes DORKY=no OPEN=absolutely " + "IP=127.0.0.1:5151 DE=\"This is a back slash: '\\\\', cool huh?\" " + "IP=127.0.0.1:6676 DE=\"a quote looks like this: \\\"\" IP=127.0.0.1:1122 "); + + if(servers != NULL) + { + int i, j; + + printf("Server info:\n"); + for(i = 0; servers[i] != NULL; i++) + { + printf("%u: IP=%s\n", i, servers[i]->ip); + for(j = 0; j < servers[i]->num_fields; j++) + printf(" %s='%s'\n", servers[i]->field[j].name, servers[i]->field[j].value); + } + free(servers); + } + return EXIT_SUCCESS; +} + +#endif /* VERSE_MS_STANDALONE */ diff --git a/extern/verse/dist/verse_ms.h b/extern/verse/dist/verse_ms.h new file mode 100644 index 00000000000..5a27d3fd446 --- /dev/null +++ b/extern/verse/dist/verse_ms.h @@ -0,0 +1,72 @@ +/* + * This is Verse Master Server, a small help library to aid application developers + * make their applications interact with a Verse master server. + * + * There are two steps to the process: + * + * 1) Send a MS:GET request to a master server. This is done by the verse_ms_get_send() + * function, which calls verse_send_ping() internally. + * + * 2) Parse any returned MS:LIST packets. This is a two-step process. The application + * still owns the ping callback, and will need to check for received pings that + * start with MS:LIST, and call the verse_ms_list_parse() function to parse those. + * + * A successfully parsed MS:LIST packet will result in an array of VMSServer pointers + * being returned. Each VMSServer instance describes one server. Use the provided + * functions to query each server structure. + * + * The application should call free() on the returned vector, whenever it is done with + * the data (perhaps after copying it into application-defined data structures). + * + * For a lot more detail about the Verse master server protocol, please see + * the spec at . + * + * This code was written in 2006 by Emil Brink. It is released as public domain. + * +*/ + +#define VERSE_MS_VERSION "1.0" + +#if defined __cplusplus +extern "C" { +#endif + +typedef struct { + const char *name; /* Field name. Upper-case. */ + const char *value; /* Field value. Fully parsed, might contain spaces. */ +} VMSField; + +typedef struct { + const char *ip; /* IP address of server, in dotted decimal:port. */ + unsigned int num_fields; /* Number of fields of extra info. */ + VMSField *field; /* Vector of fields, or NULL if none. */ +} VMSServer; + +/* Formats and sends a MS:GET ping packet to the master server. The argument + * should be a combination of VERSE_MS_FIELD_ mask values. If is set, it should + * be a comma-separated set of include/exclude tags, like "a,b,-c,d,-e". +*/ +#define VERSE_MS_FIELD_DESCRIPTION (1 << 0) +extern void verse_ms_get_send(const char *address, int fields, const char *tags); + +/* Parses a master server response. This will be a string of the form "MS:LIST IP=blah ...", + * which is split into one struct per IP, and any additional fields parsed (unquoted etc). + * Returns an array of VMSServer pointers, which is NULL-terminated. Returns NULL if there + * was a parse error somewhere in the string, no partial success is possible. +*/ +extern VMSServer ** verse_ms_list_parse(const char *list); + +/* This is the only standard field name, currently. */ +#define VERSE_MS_FIELD_DESCRIPTION_NAME "DE" /* Human-readable server description. */ + +/* Checks wether the given server has a field with the given name. */ +extern int verse_ms_field_exists(const VMSServer *ms, const char *name); + +/* Returns the value for the named field in the given server, if present. + * If not, NULL is returned. +*/ +extern const char * verse_ms_field_value(const VMSServer *ms, const char *name); + +#if defined __cplusplus +} +#endif diff --git a/extern/verse/dist/vs_connection.c b/extern/verse/dist/vs_connection.c new file mode 100644 index 00000000000..06614a5dc66 --- /dev/null +++ b/extern/verse/dist/vs_connection.c @@ -0,0 +1,179 @@ +#include + +#include "v_cmd_gen.h" + +#if !defined(V_GENERATE_FUNC_MODE) + +#include "verse.h" +#include "v_util.h" + +#define VS_CONNECTION_CHUNK_SIZE 64 + +typedef struct{ + VSession *session; + unsigned int session_count; +} VSSubscriptionList; + +typedef struct{ + VSession session; + uint32 node_id; + char name[128]; + char pass[128]; +} VSConnection; + +static struct { + VSConnection *connection; + unsigned int connection_length; + VSSubscriptionList **list; + unsigned int list_length; + unsigned int current_session; +} VSConnectionStorage; + +void vs_init_connection_storage(void) +{ + VSConnectionStorage.connection = NULL; + VSConnectionStorage.connection_length = 0; + VSConnectionStorage.list = NULL; + VSConnectionStorage.list_length = 0; + VSConnectionStorage.current_session = 0; +} + +void vs_add_new_connection(VSession session, const char *name, const char *pass, VNodeID node_id) +{ + VSConnection *conn; + + if(VSConnectionStorage.connection_length % VS_CONNECTION_CHUNK_SIZE == 0) + VSConnectionStorage.connection = realloc(VSConnectionStorage.connection, (sizeof *VSConnectionStorage.connection) * (VSConnectionStorage.connection_length + VS_CONNECTION_CHUNK_SIZE)); + conn = &VSConnectionStorage.connection[VSConnectionStorage.connection_length]; + + conn->session = session; + conn->node_id = node_id; + v_strlcpy(conn->name, name, sizeof conn->name); + v_strlcpy(conn->pass, pass, sizeof conn->pass); + + VSConnectionStorage.connection_length++; +} + +uint32 vs_get_avatar(void) +{ + return VSConnectionStorage.connection[VSConnectionStorage.current_session].node_id; +} + +VSession vs_get_session(void) +{ + return VSConnectionStorage.connection[VSConnectionStorage.current_session].session; +} + +const char * vs_get_user_name(void) +{ + return VSConnectionStorage.connection[VSConnectionStorage.current_session].name; +} + +const char * vs_get_user_pass(void) +{ + return VSConnectionStorage.connection[VSConnectionStorage.current_session].pass; +} + + +void vs_remove_connection(void) +{ + unsigned int i, j; + VSession *session; + VSSubscriptionList *list; + + session = VSConnectionStorage.connection[VSConnectionStorage.current_session].session; + for(i = 0; i < VSConnectionStorage.list_length; i++) + { + list = VSConnectionStorage.list[i]; + for(j = 0; j < list->session_count && list->session[j] != session; j++); + if(j < list->session_count) + list->session[j] = list->session[--list->session_count]; + } + j = --VSConnectionStorage.connection_length; + + if(VSConnectionStorage.current_session < j) + { + VSConnectionStorage.connection[VSConnectionStorage.current_session].session = VSConnectionStorage.connection[j].session; + VSConnectionStorage.connection[VSConnectionStorage.current_session].node_id = VSConnectionStorage.connection[j].node_id; + } + else + VSConnectionStorage.current_session = 0; +} + +void vs_set_next_session(void) +{ + if(++VSConnectionStorage.current_session >= VSConnectionStorage.connection_length) + VSConnectionStorage.current_session = 0; + if(VSConnectionStorage.connection_length != 0) + verse_session_set(VSConnectionStorage.connection[VSConnectionStorage.current_session].session); +} + +VSSubscriptionList *vs_create_subscription_list(void) +{ + VSSubscriptionList *list; + list = malloc(sizeof *list); + if(VSConnectionStorage.list_length % VS_CONNECTION_CHUNK_SIZE == 0) + VSConnectionStorage.list = realloc(VSConnectionStorage.list, (sizeof *VSConnectionStorage.list) * (VSConnectionStorage.list_length + VS_CONNECTION_CHUNK_SIZE)); + VSConnectionStorage.list[VSConnectionStorage.list_length] = list; + list->session = NULL; + list->session_count = 0; + VSConnectionStorage.list_length++; + return list; +} + +void vs_destroy_subscription_list(VSSubscriptionList *list) +{ + unsigned int i; + + if(list == NULL) + return; + if(list->session != NULL) + free(list->session); + for(i = 0; i < VSConnectionStorage.list_length && VSConnectionStorage.list[i] != list; i++) + ; + if(i < VSConnectionStorage.list_length) + VSConnectionStorage.list[i] = VSConnectionStorage.list[--VSConnectionStorage.list_length]; + free(list); +} + +/* Returns 1 if subscriber was added, 0 if not (typically meaning it was already on the list). */ +int vs_add_new_subscriptor(VSSubscriptionList *list) +{ + unsigned int i; + if(list->session_count % VS_CONNECTION_CHUNK_SIZE == 0) + list->session = realloc(list->session, (sizeof *list->session) * (list->session_count + VS_CONNECTION_CHUNK_SIZE)); + for(i = 0; i < list->session_count; i++) + if(list->session[i] == VSConnectionStorage.connection[VSConnectionStorage.current_session].session) + return 0; + list->session[list->session_count] = VSConnectionStorage.connection[VSConnectionStorage.current_session].session; + list->session_count++; + return 1; +} + + +void vs_remove_subscriptor(VSSubscriptionList *list) +{ + unsigned int i; + VSession *session; + session = VSConnectionStorage.connection[VSConnectionStorage.current_session].session; + for(i = 0; i < list->session_count && list->session[i] != session; i++); + if(i < list->session_count) + list->session[i] = list->session[--list->session_count]; +} + +size_t vs_get_subscript_count(const VSSubscriptionList *list) +{ + return list != NULL ? list->session_count : 0; +} + +void vs_set_subscript_session(VSSubscriptionList *list, unsigned int session) +{ + verse_session_set(list->session[session]); +} + +void vs_reset_subscript_session(void) +{ + verse_session_set(VSConnectionStorage.connection[VSConnectionStorage.current_session].session); +} + +#endif diff --git a/extern/verse/dist/vs_main.c b/extern/verse/dist/vs_main.c new file mode 100644 index 00000000000..3b388eecc56 --- /dev/null +++ b/extern/verse/dist/vs_main.c @@ -0,0 +1,180 @@ +/* +** A simple Verse server. +*/ + +#include +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_network.h" +#include "v_util.h" +#include "vs_server.h" + +extern VNodeID vs_node_create(VNodeID owner_id, unsigned int type); +extern void callback_send_node_destroy(void *user_data, VNodeID node_id); +extern void vs_reset_owner(VNodeID owner_id); + +static void callback_send_connect(void *user, const char *name, const char *pass, const char *address, const uint8 *host_id) +{ + VNodeID avatar; + VSession *session; + + printf("Connecting '%s'\n", name); + if(TRUE) + { + avatar = vs_node_create(~0, V_NT_OBJECT); + session = verse_send_connect_accept(avatar, address, NULL); + vs_add_new_connection(session, name, pass, avatar); +/* vs_avatar_init(avatar, name);*/ + } + else + { + verse_send_connect_terminate(address, "I'm sorry but you are not welcome here."); + } +} + +static void callback_send_connect_terminate(void *user, char *address, char *bye) +{ + printf("callback_send_connect_terminate\n"); + vs_reset_owner(vs_get_avatar()); + callback_send_node_destroy(NULL, vs_get_avatar()); + verse_session_destroy(vs_get_session()); + vs_remove_connection(); +} + +static void vs_load_host_id(const char *file_name) +{ + FILE *f; + uint8 id[V_HOST_ID_SIZE]; + size_t got; + + /* Attempt to read key from given filename. Fails silently. */ + if((f = fopen(file_name, "rb")) != NULL) + { + if((got = fread(id, 1, sizeof id, f)) > 0) + { + printf("Loaded %u-bit host ID key successfully\n", 8 * (got / 3)); + verse_host_id_set(id); + } + fclose(f); + if(got) + return; + } + /* If file didn't open, or reading failed, generate a new key and write it out. */ + verse_host_id_create(id); + verse_host_id_set(id); + if((f = fopen(file_name, "wb")) != NULL) + { + if(fwrite(id, sizeof id, 1, f) != 1) + fprintf(stderr, "Warning: Couldn't write host ID to \"%s\"\n", file_name); + fclose(f); + } + else + fprintf(stderr, "Warning: Couldn't open \"%s\" for host ID writing\n", file_name); +} + +static void cb_sigint_handler(int sig) +{ + if(sig == SIGINT) + { + printf("Verse server terminating\n"); + exit(EXIT_SUCCESS); + } +} + +static void callback_send_ping(void *user, const char *address, const char *message) +{ + if(strncmp(message, "DESCRIBE", 8) == 0 && message[8] == ' ') + vs_master_handle_describe(address, message + 9); +} + +static void usage(void) +{ + printf("Verse server usage:\n"); + printf(" -h\t\t\tShow this usage information.\n"); + printf(" -ms\t\t\tRegisters the server with a master server at the address\n"); + printf(" \t\t\tgiven with the -ms:ip= option. Off by default.\n"); + printf(" -ms:ip=IP[:PORT]\tSet master server to register with. Implies -ms.\n"); + printf(" \t\t\tThe default address is <%s>.\n", vs_master_get_address()); + printf(" -ms:de=DESC\t\tSet description, sent to master server.\n"); + printf(" -ms:ta=TAGS\t\tSet tags, sent to master server.\n"); + printf(" -port=PORT\t\tSet port to use for incoming connections.\n"); + printf(" -version\t\tPrint version information and exit.\n"); +} + +int main(int argc, char **argv) +{ + uint32 i, seconds, fractions, port = VERSE_STD_CONNECT_PORT; + + signal(SIGINT, cb_sigint_handler); + + vs_master_set_address("master.uni-verse.org"); /* The default master address. */ + vs_master_set_enabled(FALSE); /* Make sure master server support is disabled. */ + for(i = 1; i < (uint32) argc; i++) + { + if(strcmp(argv[i], "-h") == 0) + { + usage(); + return EXIT_SUCCESS; + } + else if(strcmp(argv[i], "-ms") == 0) + vs_master_set_enabled(TRUE); + else if(strncmp(argv[i], "-ms:ip=", 7) == 0) + { + vs_master_set_address(argv[i] + 7); + vs_master_set_enabled(TRUE); + } + else if(strncmp(argv[i], "-ms:de=", 7) == 0) + vs_master_set_desc(argv[i] + 7); + else if(strncmp(argv[i], "-ms:ta=", 7) == 0) + vs_master_set_tags(argv[i] + 7); + else if(strncmp(argv[i], "-port=", 6) == 0) + port = strtoul(argv[i] + 6, NULL, 0); + else if(strcmp(argv[i], "-version") == 0) + { + printf("r%up%u%s\n", V_RELEASE_NUMBER, V_RELEASE_PATCH, V_RELEASE_LABEL); + return EXIT_SUCCESS; + } + else + fprintf(stderr, "Ignoring unknown argument \"%s\", try -h for help\n", argv[i]); + } + + printf("Verse Server r%up%u%s by Eskil Steenberg \n", V_RELEASE_NUMBER, V_RELEASE_PATCH, V_RELEASE_LABEL); + verse_set_port(port); /* The Verse standard port. */ + printf(" Listening on port %d\n", port); + + /* Seed the random number generator. Still rather too weak for crypto, I guess. */ + v_n_get_current_time(&seconds, &fractions); + srand(seconds ^ fractions); + + vs_load_host_id("host_id.rsa"); + vs_init_node_storage(); + vs_o_callback_init(); + vs_g_callback_init(); + vs_m_callback_init(); + vs_b_callback_init(); + vs_t_callback_init(); + vs_c_callback_init(); + vs_a_callback_init(); + vs_h_callback_init(); + init_callback_node_storage(); + verse_callback_set(verse_send_ping, callback_send_ping, NULL); + verse_callback_set(verse_send_connect, callback_send_connect, NULL); + verse_callback_set(verse_send_connect_terminate, callback_send_connect_terminate, NULL); + + while(TRUE) + { + vs_set_next_session(); + verse_callback_update(1000000); + vs_master_update(); + } + return EXIT_SUCCESS; +} + +#endif /* V_GENERATE_FUNC_MODE */ diff --git a/extern/verse/dist/vs_master.c b/extern/verse/dist/vs_master.c new file mode 100644 index 00000000000..4fa020d58b6 --- /dev/null +++ b/extern/verse/dist/vs_master.c @@ -0,0 +1,131 @@ +/* + * Master server communication code. +*/ + +#include +#include + +#include "verse.h" +#include "v_util.h" +#include "vs_server.h" + +#define MASTER_SERVER_PERIOD (60.0) /* Period between ANNOUNCE to master server, in seconds. */ + +static struct { + boolean enabled; + boolean started; + const char *master; + char desc[64]; + const char *tags; + VUtilTimer timer; +} server_info; + +#define LEFT(d) (sizeof server_info.desc - (d - server_info.desc) - 1) + +void vs_master_set_enabled(boolean enabled) +{ + server_info.enabled = enabled; +} + +const char * vs_master_get_address(void) +{ + return server_info.master; +} + +void vs_master_set_address(const char *address) +{ + server_info.master = address; +} + +void vs_master_set_desc(const char *desc) +{ + const char *src = desc; + char *dst = server_info.desc; + + for(; *src != '\0' && LEFT(dst) > 0;) + { + if(*src == '"') + { + if(LEFT(dst) < 2) + break; + *dst++ = '\\'; + } + else if(*src == '\\') + { + if(LEFT(dst) < 2) + break; + *dst++ = '\\'; + } + *dst++ = *src++; + } + *dst = '\0'; +} + +void vs_master_set_tags(const char *tags) +{ + server_info.tags = tags; /* This needs more protection, instead of relying on the master server. */ +} + +void vs_master_update(void) +{ + if(!server_info.enabled || server_info.master == NULL) + return; + + if(!server_info.started) + { + v_timer_start(&server_info.timer); + v_timer_advance(&server_info.timer, MASTER_SERVER_PERIOD); + server_info.started = TRUE; + return; + } + if(v_timer_elapsed(&server_info.timer) < MASTER_SERVER_PERIOD) + return; + verse_send_ping(server_info.master, "MS:ANNOUNCE"); + v_timer_start(&server_info.timer); +/* printf("MS:ANNOUNCE sent to %s\n", server_info.master);*/ +} + +/* Check if a description request, of the form "A,B,C,...,D" includes the given keyword. This needs to + * do more than just a simple strstr(), since the keyword may be a prefix. Shades of OpenGL extensions. +*/ +static int desc_has_keyword(const char *desc, const char *keyword) +{ + const char *ptr; + + if(desc == NULL || *desc == '\0') /* Quick-check for empty description. */ + return 0; + + if((ptr = strstr(desc, keyword)) != NULL) + { + size_t kl = strlen(keyword); + + return ptr[kl] == ',' || ptr[kl] == '\0'; + } + return 0; +} + +static int keyword_fits(size_t used, size_t max, const char *key, const char *value) +{ + size_t vsize = 0; + + if(key != NULL && value != NULL) + vsize += 1 + strlen(key) + 1 + 1 + strlen(value) + 1; + + return max - 1 - used >= vsize; +} + +static char * append_desc(char *buf, const char *key, const char *value) +{ + return buf + sprintf(buf, " %s=\"%s\"", key, value); +} + +void vs_master_handle_describe(const char *address, const char *message) +{ + char desc[1380] = "DESCRIPTION", *put = desc + 11; + + if(desc_has_keyword(message, "DE") && server_info.desc != NULL && keyword_fits(put - desc, sizeof desc, "DE", server_info.desc)) + put = append_desc(put, "DE", server_info.desc); + if(desc_has_keyword(message, "TA") && server_info.tags != NULL && keyword_fits(put - desc, sizeof desc, "TA", server_info.tags)) + put = append_desc(put, "TA", server_info.tags); + verse_send_ping(address, desc); +} diff --git a/extern/verse/dist/vs_node_audio.c b/extern/verse/dist/vs_node_audio.c new file mode 100644 index 00000000000..e69d3d9b3ec --- /dev/null +++ b/extern/verse/dist/vs_node_audio.c @@ -0,0 +1,420 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +typedef struct { + void **data; + unsigned int length; + char name[16]; + VNABlockType type; + real64 frequency; + VSSubscriptionList *subscribers; +} VSNLayer; + +typedef struct { + char name[16]; + VSSubscriptionList *subscribers; +} VSNStream; + +typedef struct{ + VSNodeHead head; + VSNLayer *buffers; + unsigned int buffer_count; + VSNStream *streams; + unsigned int stream_count; +} VSNodeAudio; + +VSNodeAudio * vs_a_create_node(unsigned int owner) +{ + VSNodeAudio *node; + char name[48]; + unsigned int i; + + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_AUDIO); + sprintf(name, "Audio_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->buffer_count = 16; + node->buffers = malloc((sizeof *node->buffers) * node->buffer_count); + for(i = 0; i < node->buffer_count; i++) + node->buffers[i].name[0] = 0; + node->stream_count = 16; + node->streams = malloc((sizeof *node->streams) * node->stream_count); + for(i = 0; i < node->stream_count; i++) + node->streams[i].name[0] = 0; + + return node; +} + +void vs_a_destroy_node(VSNodeAudio *node) +{ + unsigned int i, j; + destroy_node_head(&node->head); + + for(i = 0; i < node->buffer_count; i++) + { + if(node->buffers[i].name[0] != 0) + { + for(j = 0; j < node->buffers[i].length; j++) + if(node->buffers[i].data[j] != NULL) + free(node->buffers[i].data[j]); + free(node->buffers[i].data); + } + } + free(node->buffers); + free(node->streams); + free(node); +} + +void vs_a_subscribe(VSNodeAudio *node) +{ + unsigned int i; + if(node == NULL) + return; + for(i = 0; i < node->buffer_count; i++) + if(node->buffers[i].name[0] != 0) + verse_send_a_buffer_create(node->head.id, i, node->buffers[i].name, node->buffers[i].type, + node->buffers[i].frequency); + for(i = 0; i < node->stream_count; i++) + if(node->streams[i].name[0] != 0) + verse_send_a_stream_create(node->head.id, i, node->streams[i].name); +} + +void vs_a_unsubscribe(VSNodeAudio *node) +{ + unsigned int i; + for(i = 0; i < node->buffer_count; i++) + if(node->buffers[i].name[0] != 0) + vs_remove_subscriptor(node->buffers[i].subscribers); + for(i = 0; i < node->stream_count; i++) + if(node->streams[i].name[0] != 0) + vs_remove_subscriptor(node->streams[i].subscribers); +} + +static void callback_send_a_stream_create(void *user, VNodeID node_id, VLayerID stream_id, const char *name) +{ + VSNodeAudio *node; + unsigned int i, j, count; + + node = (VSNodeAudio *) vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + + for(i = 0; i < node->stream_count; i++) + { + if(stream_id != i) + { + for(j = 0; name[j] == node->streams[i].name[j] && name[j] != 0; j++); + if(name[j] == node->streams[i].name[j]) + return; + } + } + if(stream_id >= node->stream_count || node->streams[stream_id].name[0] == 0) + { + for(stream_id = 0; stream_id < node->stream_count && node->streams[stream_id].name[0] != 0; stream_id++); + if(stream_id == node->stream_count) + { + stream_id = node->stream_count; + node->stream_count += 16; + node->streams = realloc(node->streams, (sizeof *node->streams) * node->stream_count); + for(i = stream_id; i < node->stream_count; i++) + node->streams[i].name[0] = 0; + } + node->streams[stream_id].subscribers = vs_create_subscription_list(); + } + for(i = 0; name[i] != 0 && i < 15; i++) + node->streams[stream_id].name[i] = name[i]; + node->streams[stream_id].name[i] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_a_stream_create(node_id, stream_id, name); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_stream_destroy(void *user, VNodeID node_id, VLayerID stream_id) +{ + VSNodeAudio *node; + unsigned int i, count; + + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL || stream_id >= node->stream_count || node->streams[stream_id].name[0] == 0) + return; + vs_remove_subscriptor(node->streams[stream_id].subscribers); + node->streams[stream_id].name[0] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_a_stream_destroy(node_id, stream_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_buffer_create(void *user, VNodeID node_id, VBufferID buffer_id, const char *name, + VNABlockType type, real64 frequency) +{ + VSNodeAudio *node; + unsigned int i, j, count; + + if(frequency < 0.0) + return; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + + for(i = 0; i < node->buffer_count; i++) + { + if(buffer_id != i) + { + for(j = 0; name[j] == node->buffers[i].name[j] && name[j] != 0; j++); + if(name[j] == node->buffers[i].name[j]) + return; + } + } + + if(buffer_id < node->buffer_count && node->buffers[buffer_id].name[0] != 0 && type != node->buffers[buffer_id].type) + { + free(node->buffers[buffer_id].data); + vs_destroy_subscription_list(node->buffers[buffer_id].subscribers); + node->buffers[buffer_id].name[0] = 0; + } + + if(buffer_id >= node->buffer_count || node->buffers[buffer_id].name[0] == 0) + { + for(buffer_id = 0; buffer_id < node->buffer_count && node->buffers[buffer_id].name[0] != 0; buffer_id++); + if(buffer_id == node->buffer_count) + { + buffer_id = node->buffer_count; + node->buffer_count += 16; + node->buffers = realloc(node->buffers, (sizeof *node->buffers) * node->buffer_count); + for(i = buffer_id; i < node->buffer_count; i++) + node->buffers[i].name[0] = 0; + } + node->buffers[buffer_id].subscribers = vs_create_subscription_list(); + node->buffers[buffer_id].type = type; + node->buffers[buffer_id].frequency = frequency; + node->buffers[buffer_id].length = 64; + node->buffers[buffer_id].data = malloc(sizeof(*node->buffers[buffer_id].data) * node->buffers[buffer_id].length); + for(i = 0; i < node->buffers[buffer_id].length; i++) + node->buffers[buffer_id].data[i] = NULL; + } + for(i = 0; name[i] != 0 && i < 15; i++) + node->buffers[buffer_id].name[i] = name[i]; + node->buffers[buffer_id].name[i] = 0; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_a_buffer_create(node_id, buffer_id, name, type, frequency); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_buffer_destroy(void *user, VNodeID node_id, VBufferID buffer_id) +{ + VSNodeAudio *node; + unsigned int i, count; + + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL || buffer_id >= node->buffer_count || node->buffers[buffer_id].name[0] == 0) + return; + vs_remove_subscriptor(node->buffers[buffer_id].subscribers); + node->buffers[buffer_id].name[0] = 0; + free(node->buffers[buffer_id].data); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_a_buffer_destroy(node_id, buffer_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_buffer_subscribe(void *user, VNodeID node_id, VLayerID buffer_id) +{ + VSNodeAudio *node; + unsigned int i; + + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->buffer_count <= buffer_id) + return; + if(node->buffers[buffer_id].name[0] == 0) + return; + vs_add_new_subscriptor(node->buffers[buffer_id].subscribers); + for(i = 0; i < node->buffers[buffer_id].length; i++) + { + if(node->buffers[buffer_id].data[i] != NULL) + verse_send_a_block_set(node_id, buffer_id, i, node->buffers[buffer_id].type, node->buffers[buffer_id].data[i]); + } +} + +static void callback_send_a_buffer_unsubscribe(void *user, VNodeID node_id, VLayerID buffer_id) +{ + VSNodeAudio *node; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->buffer_count <= buffer_id) + return; + if(node->buffers[buffer_id].name[0] == 0) + return; + vs_remove_subscriptor(node->buffers[buffer_id].subscribers); +} + +static void callback_send_a_block_set(void *user, VNodeID node_id, VLayerID buffer_id, uint32 block_index, + VNABlockType type, const VNABlock *data) +{ + static const size_t blocksize[] = { + VN_A_BLOCK_SIZE_INT8 * sizeof (int8), + VN_A_BLOCK_SIZE_INT16 * sizeof (int16), + VN_A_BLOCK_SIZE_INT24 * 3 * sizeof (int8), + VN_A_BLOCK_SIZE_INT32 * sizeof (int32), + VN_A_BLOCK_SIZE_REAL32 * sizeof (real32), + VN_A_BLOCK_SIZE_REAL64 * sizeof (real64) + }; + VSNodeAudio *node; + unsigned int i, count; + + if(type > VN_A_BLOCK_REAL64) /* Protect blocksize array. */ + return; + + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->buffers[buffer_id].name[0] == 0) + return; + if(type != node->buffers[buffer_id].type) /* Disregard attempts to set data of wrong type. */ + return; + if(block_index > node->buffers[buffer_id].length) + { + node->buffers[buffer_id].data = realloc(node->buffers[buffer_id].data, + (sizeof *node->buffers[buffer_id].data) * (block_index + 64)); + for(i = node->buffers[buffer_id].length; i < block_index + 64; i++) + node->buffers[buffer_id].data[i] = NULL; + node->buffers[buffer_id].length = block_index + 64; + } + + if(node->buffers[buffer_id].data[block_index] == NULL) + node->buffers[buffer_id].data[block_index] = malloc(blocksize[type]); + if(node->buffers[buffer_id].data[block_index] != NULL) + { + memcpy(node->buffers[buffer_id].data[block_index], data, blocksize[type]); + count = vs_get_subscript_count(node->buffers[buffer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->buffers[buffer_id].subscribers, i); + verse_send_a_block_set(node_id, buffer_id, block_index, type, data); + } + vs_reset_subscript_session(); + } +} + +static void callback_send_a_block_clear(void *user, VNodeID node_id, VLayerID buffer_id, uint32 id) +{ + VSNodeAudio *node; + unsigned int i, count; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->buffer_count <= buffer_id) + return; + if(node->buffers[buffer_id].name[0] == 0) + return; + if(id >= node->buffers[buffer_id].length) + return; + if(node->buffers[buffer_id].data[id] == NULL) + return; + free(node->buffers[buffer_id].data[id]); + node->buffers[buffer_id].data[id] = NULL; + count = vs_get_subscript_count(node->buffers[buffer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->buffers[buffer_id].subscribers, i); + verse_send_a_block_clear(node_id, buffer_id, id); + } + vs_reset_subscript_session(); +} + +static void callback_send_a_stream_subscribe(void *user, VNodeID node_id, VLayerID stream_id) +{ + VSNodeAudio *node; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->stream_count <= stream_id) + return; + if(node->streams[stream_id].name[0] == 0) + return; + vs_add_new_subscriptor(node->streams[stream_id].subscribers); +} + +static void callback_send_a_stream_unsubscribe(void *user, VNodeID node_id, VLayerID stream_id) +{ + VSNodeAudio *node; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->stream_count <= stream_id) + return; + if(node->streams[stream_id].name[0] == 0) + return; + vs_remove_subscriptor(node->streams[stream_id].subscribers); +} + +static void callback_send_a_stream(void *user, VNodeID node_id, VLayerID stream_id, uint32 time_s, uint32 time_f, + VNABlockType type, real64 frequency, const VNABlock *data) +{ + VSNodeAudio *node; + unsigned int i, count; + + if(frequency < 0) + return; + node = (VSNodeAudio *)vs_get_node(node_id, V_NT_AUDIO); + if(node == NULL) + return; + if(node->stream_count <= stream_id) + return; + if(node->streams[stream_id].name[0] == 0) + return; + count = vs_get_subscript_count(node->streams[stream_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->streams[stream_id].subscribers, i); + verse_send_a_stream(node_id, stream_id, time_s, time_f, type, frequency, data); + } + vs_reset_subscript_session(); +} + +void vs_a_callback_init(void) +{ + verse_callback_set(verse_send_a_buffer_create, callback_send_a_buffer_create, NULL); + verse_callback_set(verse_send_a_buffer_destroy, callback_send_a_buffer_destroy, NULL); + verse_callback_set(verse_send_a_buffer_subscribe, callback_send_a_buffer_subscribe, NULL); + verse_callback_set(verse_send_a_buffer_unsubscribe, callback_send_a_buffer_unsubscribe, NULL); + verse_callback_set(verse_send_a_block_set, callback_send_a_block_set, NULL); + verse_callback_set(verse_send_a_block_clear, callback_send_a_block_clear, NULL); + verse_callback_set(verse_send_a_stream_create, callback_send_a_stream_create, NULL); + verse_callback_set(verse_send_a_stream_destroy, callback_send_a_stream_destroy, NULL); + verse_callback_set(verse_send_a_stream_subscribe, callback_send_a_stream_subscribe, NULL); + verse_callback_set(verse_send_a_stream_unsubscribe, callback_send_a_stream_unsubscribe, NULL); + verse_callback_set(verse_send_a_stream, callback_send_a_stream, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_bitmap.c b/extern/verse/dist/vs_node_bitmap.c new file mode 100644 index 00000000000..566287a86d4 --- /dev/null +++ b/extern/verse/dist/vs_node_bitmap.c @@ -0,0 +1,560 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +typedef struct { + VNBLayerType type; + char name[16]; + void *layer; + VSSubscriptionList *subscribers; +} VSNBLayers; + +typedef struct { + VSNodeHead head; + uint16 size[3]; + uint32 partial_tile_col, partial_tile_row; /* These rows/columns are partial. ~0 for none. */ + VSNBLayers *layers; + unsigned int layer_count; +} VSNodeBitmap; + +static unsigned long tile_counter = 0; + +VSNodeBitmap * vs_b_create_node(unsigned int owner) +{ + VSNodeBitmap *node; + char name[48]; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_BITMAP); + sprintf(name, "Bitmap_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + + node->size[0] = 0; + node->size[1] = 0; + node->size[2] = 0; + node->partial_tile_col = ~0; + node->partial_tile_row = ~0; + node->layers = NULL; + node->layer_count = 0; + + return node; +} + +void vs_b_destroy_node(VSNodeBitmap *node) +{ + unsigned int i; + destroy_node_head(&node->head); + if(node->layers != NULL) + { + for(i = 0; i < node->layer_count; i++) + if(node->layers[i].layer != NULL) + free(node->layers[i].layer); + free(node->layers); + } + free(node); +} + +void vs_b_subscribe(VSNodeBitmap *node) +{ + unsigned int i; + verse_send_b_dimensions_set(node->head.id, node->size[0], node->size[1], node->size[2]); + for(i = 0; i < node->layer_count; i++) + if(node->layers[i].name[0] != 0) + verse_send_b_layer_create(node->head.id, (uint16)i, node->layers[i].name, (uint8)node->layers[i].type); +} + + +void vs_b_unsubscribe(VSNodeBitmap *node) +{ + unsigned int i; + for(i = 0; i < node->layer_count; i++) + if(node->layers[i].name[0] != 0) + vs_remove_subscriptor(node->layers[i].subscribers); +} + +static void callback_send_b_dimensions_set(void *user, VNodeID node_id, uint16 width, uint16 height, uint16 depth) +{ + VSNodeBitmap *node; + unsigned int i, j, k, count, tiles[2], read, write, end = 0; + + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + tiles[0] = (width + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE; + tiles[1] = (height + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE; + node->size[0] = (node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE; + node->size[1] = (node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE; + if(node->size[0] > tiles[0]) + node->size[0] = tiles[0]; + if(node->size[1] > tiles[1]) + node->size[1] = tiles[1]; + if(node->size[2] > depth) + node->size[2] = depth; + + for(i = 0; i < node->layer_count; i++) + { + if(node->layers[i].name[0] != 0) + { + switch(node->layers[i].type) + { + case VN_B_LAYER_UINT1 : + { + uint16 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]); + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]); + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]); + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]); + while(write < end) + array[write++] = 0; + } + k = depth * tiles[1] * tiles[0]; + while(write < end) + array[write++] = 0; + } + break; + case VN_B_LAYER_UINT8 : + { + uint8 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth * VN_B_TILE_SIZE * VN_B_TILE_SIZE); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = depth * tiles[1] * tiles[0] * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + break; + case VN_B_LAYER_UINT16 : + { + uint16 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth * VN_B_TILE_SIZE * VN_B_TILE_SIZE); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = depth * tiles[1] * tiles[0] * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + break; + case VN_B_LAYER_REAL32 : + { + real32 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth * VN_B_TILE_SIZE * VN_B_TILE_SIZE); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = depth * tiles[1] * tiles[0] * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + break; + case VN_B_LAYER_REAL64 : + { + real64 *array, *old; + write = 0; + old = node->layers[i].layer; + array = node->layers[i].layer = malloc((sizeof *array) * tiles[0] * tiles[1] * depth * VN_B_TILE_SIZE * VN_B_TILE_SIZE); + for(j = 0; j < node->size[2]; j++) + { + for(k = 0; k < node->size[1]; k++) + { + read = (j * node->size[1] * node->size[0] + k * node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + + end = (j * tiles[1] * tiles[0] + k * tiles[0] + node->size[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = old[read++]; + + end = (j * tiles[1] * tiles[0] + (k + 1) * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = ((j + 1) * tiles[1] * tiles[0]) * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + end = depth * tiles[1] * tiles[0] * VN_B_TILE_SIZE * VN_B_TILE_SIZE; + while(write < end) + array[write++] = 0; + } + break; + } + } + } + + node->size[0] = width; + node->size[1] = height; + node->size[2] = depth; + node->partial_tile_col = (width % VN_B_TILE_SIZE) != 0 ? (width + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE - 1 : ~0; + node->partial_tile_row = (height % VN_B_TILE_SIZE) != 0 ? (height + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE - 1 : ~0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_b_dimensions_set(node_id, width, height, depth); + } + vs_reset_subscript_session(); +} + +static void callback_send_b_layer_create(void *user, VNodeID node_id, VLayerID layer_id, char *name, uint8 type) +{ + VSNodeBitmap *node; + unsigned int i, count; + + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + if(node->layer_count <= layer_id || node->layers[layer_id].name[0] == 0) + { + for(layer_id = 0; layer_id < node->layer_count && node->layers[layer_id].name[0] != 0; layer_id++) + ; + if(layer_id == node->layer_count) + { + node->layers = realloc(node->layers, (sizeof *node->layers) * (node->layer_count + 16)); + for(i = node->layer_count; i < node->layer_count + 16; i++) + { + node->layers[i].layer = NULL; + node->layers[i].type = 0; + node->layers[i].name[0] = 0; + node->layers[i].subscribers = NULL; + } + node->layer_count += 16; + } + node->layers[layer_id].subscribers = vs_create_subscription_list(); + node->layers[layer_id].type = type + 1; + } + + if(node->layers[layer_id].type != type || node->layers[layer_id].name[0] == 0) + { + count = ((node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE) * ((node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + count *= VN_B_TILE_SIZE * VN_B_TILE_SIZE * node->size[2]; + if(node->layers[layer_id].layer != NULL) + free(node->layers[layer_id].layer); + if(count != 0) + { + switch(type) + { + case VN_B_LAYER_UINT1 : + node->layers[layer_id].layer = malloc(sizeof(uint8) * count / 8); + memset(node->layers[layer_id].layer, 0, count * sizeof(uint8) / 8); + break; + case VN_B_LAYER_UINT8 : + node->layers[layer_id].layer = malloc(sizeof(uint8) * count); + memset(node->layers[layer_id].layer, 0, count * sizeof(uint8)); + break; + case VN_B_LAYER_UINT16 : + node->layers[layer_id].layer = malloc(sizeof(uint16) * count); + memset(node->layers[layer_id].layer, 0, count * sizeof(uint16)); + break; + case VN_B_LAYER_REAL32 : + node->layers[layer_id].layer = malloc(sizeof(real32) * count); + memset(node->layers[layer_id].layer, 0, count * sizeof(real32)); + break; + case VN_B_LAYER_REAL64 : + node->layers[layer_id].layer = malloc(sizeof(real64) * count); + memset(node->layers[layer_id].layer, 0, count * sizeof(real64)); + break; + } + }else + node->layers[layer_id].layer = NULL; + } + node->layers[layer_id].type = type; + for(i = 0; i < 15 && name[i] != 0; i++) + node->layers[layer_id].name[i] = name[i]; + node->layers[layer_id].name[i] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_b_layer_create(node_id, layer_id, name, type); + } + vs_reset_subscript_session(); +} + +static void callback_send_b_layer_destroy(void *user, VNodeID node_id, VLayerID layer_id) +{ + VSNodeBitmap *node; + unsigned int i, count; + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + if(layer_id >= node->layer_count || node->layers[layer_id].layer == NULL) + return; + if(node->layers[layer_id].layer != NULL) + free(node->layers[layer_id].layer); + node->layers[layer_id].layer = NULL; + node->layers[layer_id].type = 0; + node->layers[layer_id].name[0] = 0; + vs_destroy_subscription_list(node->layers[layer_id].subscribers); + node->layers[layer_id].subscribers = NULL; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_b_layer_destroy(node_id, layer_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_b_layer_subscribe(void *user, VNodeID node_id, VLayerID layer_id, uint8 level) +{ + VSNodeBitmap *node; + const void *data; + unsigned int i, j, k, tile[3]; + + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + if(layer_id >= node->layer_count || node->layers[layer_id].layer == NULL) + return; + if(vs_add_new_subscriptor(node->layers[layer_id].subscribers) == 0) + return; + tile[0] = ((node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + tile[1] = ((node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + tile[2] = node->size[2]; + data = node->layers[layer_id].layer; + switch(node->layers[layer_id].type) + { + case VN_B_LAYER_UINT1: + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_UINT1, (VNBTile *) &((uint8*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE / 8]); + break; + case VN_B_LAYER_UINT8 : + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_UINT8, (VNBTile *) &((uint8*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]); + break; + case VN_B_LAYER_UINT16 : + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_UINT16, (VNBTile *) &((uint16*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]); + break; + case VN_B_LAYER_REAL32 : + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_REAL32, (VNBTile *) &((real32*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]); + break; + case VN_B_LAYER_REAL64 : + for(i = 0; i < tile[0]; i++) + for(j = 0; j < tile[1]; j++) + for(k = 0; k < tile[2]; k++) + verse_send_b_tile_set(node_id, layer_id, i, j, k, VN_B_LAYER_REAL64, (VNBTile *) &((real64*)data)[(tile[0] * tile[1] * k + j * tile[0] + i) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]); + break; + } +} + +static void callback_send_b_layer_unsubscribe(void *user, VNodeID node_id, VLayerID layer_id) +{ + VSNodeBitmap *node; + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + return; + if(layer_id >= node->layer_count || node->layers[layer_id].layer == NULL) + return; + vs_remove_subscriptor(node->layers[layer_id].subscribers); +} + +/* Clear any pixels that lie outside the image, so we don't violoate specs when + * sending (stored version of) the tile out to subscribers. +*/ +static void clear_outside(const VSNodeBitmap *node, uint16 tile_x, uint16 tile_y, uint8 type, VNBTile *tile) +{ + int x, y, bx, by, p; + + by = tile_y * VN_B_TILE_SIZE; + for(y = p = 0; y < VN_B_TILE_SIZE; y++, by++) + { + bx = tile_x * VN_B_TILE_SIZE; + for(x = 0; x < VN_B_TILE_SIZE; x++, bx++, p++) + { + /* Simply test current pixel against bitmap size. Not quick, but simple. */ + if(bx >= node->size[0] || by >= node->size[1]) + { + switch(type) + { + case VN_B_LAYER_UINT1: + tile->vuint1[y] &= ~(128 >> x); + break; + case VN_B_LAYER_UINT8: + tile->vuint8[p] = 0; + break; + case VN_B_LAYER_UINT16: + tile->vuint16[p] = 0; + break; + case VN_B_LAYER_REAL32: + tile->vreal32[p] = 0.0f; + break; + case VN_B_LAYER_REAL64: + tile->vreal64[p] = 0.0; + break; + } + } + } + } +} + +static void callback_send_b_tile_set(void *user, VNodeID node_id, VLayerID layer_id, + uint16 tile_x, uint16 tile_y, uint16 tile_z, uint8 type, VNBTile *data) +{ + VSNodeBitmap *node; + unsigned int i, count, tile[3]; + + if((node = (VSNodeBitmap *)vs_get_node(node_id, V_NT_BITMAP)) == NULL) + { + printf("got tile for unknown bitmpa node %u, aborting\n", node_id); + return; + } + if(layer_id >= node->layer_count || node->layers[layer_id].layer == NULL || node->layers[layer_id].type != type) + { + printf("node %u got tile for bad layer %u (have %u) %p\n", node_id, layer_id, node->layer_count, layer_id < node->layer_count ? node->layers[layer_id].layer : NULL); + return; + } + if(tile_x >= ((node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE) || tile_y >= ((node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE) || tile_z >= node->size[2]) + { + printf("got tile that is outside image, at (%u,%u,%u)\n", tile_x, tile_y, tile_z); + return; + } + + tile_counter++; + + tile[0] = ((node->size[0] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + tile[1] = ((node->size[1] + VN_B_TILE_SIZE - 1) / VN_B_TILE_SIZE); + tile[2] = node->size[2]; + + /* If tile is in a partial column or row, clear the "outside" pixels. */ + if((uint32) tile_x == node->partial_tile_col || (uint32) tile_y == node->partial_tile_row) + clear_outside(node, tile_x, tile_y, type, data); + + switch(node->layers[layer_id].type) + { + case VN_B_LAYER_UINT1 : + { + uint8 *p; + p = &((uint8 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE/8]; + memcpy(p, data->vuint1, VN_B_TILE_SIZE * sizeof(uint8)); + } + break; + case VN_B_LAYER_UINT8 : + { + uint8 *p; + p = &((uint8 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]; + memcpy(p, data->vuint8, VN_B_TILE_SIZE * VN_B_TILE_SIZE * sizeof(uint8)); + } + break; + case VN_B_LAYER_UINT16 : + { + uint16 *p; + p = &((uint16 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]; + memcpy(p, data->vuint16, VN_B_TILE_SIZE * VN_B_TILE_SIZE * sizeof(uint16)); + } + break; + case VN_B_LAYER_REAL32 : + { + real32 *p; + p = &((real32 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]; + memcpy(p, data->vreal32, VN_B_TILE_SIZE * VN_B_TILE_SIZE * sizeof(real32)); + } + break; + case VN_B_LAYER_REAL64 : + { + real64 *p; + p = &((real64 *)node->layers[layer_id].layer)[(tile[0] * tile[1] * tile_z + tile_y * tile[0] + tile_x) * VN_B_TILE_SIZE * VN_B_TILE_SIZE]; + memcpy(p, data->vreal64, VN_B_TILE_SIZE * VN_B_TILE_SIZE * sizeof(real64)); + } + break; + } + count = vs_get_subscript_count(node->layers[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layers[layer_id].subscribers, i); + verse_send_b_tile_set(node_id, layer_id, tile_x, tile_y, tile_z, type, data); + } + vs_reset_subscript_session(); +} + +void vs_b_callback_init(void) +{ + verse_callback_set(verse_send_b_dimensions_set, callback_send_b_dimensions_set, NULL); + verse_callback_set(verse_send_b_layer_create, callback_send_b_layer_create, NULL); + verse_callback_set(verse_send_b_layer_destroy, callback_send_b_layer_destroy, NULL); + verse_callback_set(verse_send_b_layer_subscribe, callback_send_b_layer_subscribe, NULL); + verse_callback_set(verse_send_b_layer_unsubscribe, callback_send_b_layer_unsubscribe, NULL); + verse_callback_set(verse_send_b_tile_set, callback_send_b_tile_set, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_curve.c b/extern/verse/dist/vs_node_curve.c new file mode 100644 index 00000000000..3787526202d --- /dev/null +++ b/extern/verse/dist/vs_node_curve.c @@ -0,0 +1,258 @@ +/* +** +*/ + +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +typedef struct { + real64 pre_value[4]; + uint32 pre_pos[4]; + real64 value[4]; + real64 pos; + real64 post_value[4]; + uint32 post_pos[4]; +} VSNKey; + +typedef struct { + VSNKey *keys; + unsigned int length; + char name[16]; + uint8 dimensions; + VSSubscriptionList *subscribers; +} VSNCurve; + +typedef struct{ + VSNodeHead head; + VSNCurve *curves; + unsigned int curve_count; +} VSNodeCurve; + +VSNodeCurve * vs_c_create_node(unsigned int owner) +{ + VSNodeCurve *node; + char name[48]; + unsigned int i; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_CURVE); + sprintf(name, "Curve_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->curves = malloc((sizeof *node->curves) * 16); + node->curve_count = 16; + for(i = 0; i < 16; i++) + node->curves[i].name[0] = 0; + return node; +} + +void vs_c_destroy_node(VSNodeCurve *node) +{ + destroy_node_head(&node->head); + free(node); +} + +void vs_c_subscribe(VSNodeCurve *node) +{ + unsigned int i; + if(node == NULL) + return; + for(i = 0; i < node->curve_count; i++) + if(node->curves[i].name[0] != 0) + verse_send_c_curve_create(node->head.id, i, node->curves[i].name, node->curves[i].dimensions); + +} + +void vs_c_unsubscribe(VSNodeCurve *node) +{ + unsigned int i; + for(i = 0; i < node->curve_count; i++) + if(node->curves[i].name[0] != 0) + vs_remove_subscriptor(node->curves[i].subscribers); +} + +static void callback_send_c_curve_create(void *user, VNodeID node_id, VLayerID curve_id, const char *name, uint8 dimensions) +{ + VSNodeCurve *node; + unsigned int i, j, count; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL) + return; + + for(i = 0; i < node->curve_count; i++) + { + if(curve_id != i) + { + for(j = 0; name[j] == node->curves[i].name[j] && name[j] != 0; j++); + if(name[j] == node->curves[i].name[j]) + return; + } + } + if(curve_id >= node->curve_count || node->curves[curve_id].name[0] == 0) + { + for(curve_id = 0; curve_id < node->curve_count && node->curves[curve_id].name[0] != 0; curve_id++); + if(curve_id == node->curve_count) + { + curve_id = node->curve_count; + node->curve_count += 16; + node->curves = realloc(node->curves, (sizeof *node->curves) * node->curve_count); + for(i = curve_id; i < node->curve_count; i++) + node->curves[i].name[0] = 0; + } + node->curves[curve_id].subscribers = vs_create_subscription_list(); + node->curves[curve_id].length = 64; + node->curves[curve_id].keys = malloc((sizeof *node->curves[curve_id].keys) * 64); + for(i = 0; i < 64; i++) + node->curves[curve_id].keys[i].pos = V_REAL64_MAX; + + }else if(node->curves[curve_id].dimensions != dimensions) + { + for(i = 0; i < node->curves[curve_id].length; i++) + { + if(node->curves[curve_id].keys[i].pos != V_REAL64_MAX) + { + for(j = node->curves[curve_id].dimensions; j < dimensions; j++) + { + node->curves[curve_id].keys[i].pre_value[j] = node->curves[curve_id].keys[i].pre_value[0]; + node->curves[curve_id].keys[i].pre_pos[j] = node->curves[curve_id].keys[i].pre_pos[0]; + node->curves[curve_id].keys[i].value[j] = node->curves[curve_id].keys[i].value[0]; + node->curves[curve_id].keys[i].post_value[j] = node->curves[curve_id].keys[i].post_value[0]; + node->curves[curve_id].keys[i].post_pos[j] = node->curves[curve_id].keys[i].post_pos[0]; + } + } + } + vs_destroy_subscription_list(node->curves[curve_id].subscribers); + node->curves[curve_id].subscribers = vs_create_subscription_list(); + } + for(i = 0; name[i] != 0 && i < 15; i++) + node->curves[curve_id].name[i] = name[i]; + node->curves[curve_id].name[i] = 0; + node->curves[curve_id].dimensions = dimensions; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_c_curve_create(node_id, curve_id, name, dimensions); + } + vs_reset_subscript_session(); +} + +static void callback_send_c_curve_destroy(void *user, VNodeID node_id, VLayerID curve_id) +{ + VSNodeCurve *node; + unsigned int i, count; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL || node->curve_count >= curve_id || node->curves[curve_id].name[0] == 0) + return; + vs_remove_subscriptor(node->curves[curve_id].subscribers); + node->curves[curve_id].name[0] = 0; + free(node->curves[curve_id].keys); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_c_curve_destroy(node_id, curve_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_c_key_set(void *user, VNodeID node_id, VLayerID curve_id, uint32 key_id, uint8 dimensions, real64 *pre_value, uint32 *pre_pos, real64 *value, real64 pos, real64 *post_value, uint32 *post_pos) +{ + VSNodeCurve *node; + unsigned int i, count; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL) + return; + if(node->curve_count <= curve_id) + return; + if(node->curves[curve_id].name[0] == 0) + return; + if(node == NULL || node->curve_count <= curve_id || node->curves[curve_id].name[0] == 0 || node->curves[curve_id].dimensions != dimensions) + return; + if(node->curves[curve_id].length <= key_id || node->curves[curve_id].keys[key_id].pos == V_REAL64_MAX) + { + for(key_id = 0; key_id < node->curves[curve_id].length && node->curves[curve_id].keys[key_id].pos != V_REAL64_MAX; key_id++); + if(key_id == node->curves[curve_id].length) + for(i = 0; i < 64; i++) + node->curves[curve_id].keys[node->curves[curve_id].length++].pos = V_REAL64_MAX; + } + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].pre_value[i] = pre_value[i]; + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].pre_pos[i] = pre_pos[i]; + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].value[i] = value[i]; + node->curves[curve_id].keys[key_id].pos = pos; + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].post_value[i] = post_value[i]; + for(i = 0; i < dimensions; i++) + node->curves[curve_id].keys[key_id].post_pos[i] = post_pos[i]; + count = vs_get_subscript_count(node->curves[curve_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->curves[curve_id].subscribers, i); + verse_send_c_key_set(node_id, curve_id, key_id, dimensions, pre_value, pre_pos, value, pos, post_value, post_pos); + } + vs_reset_subscript_session(); +} + +static void callback_send_c_key_destroy(void *user, VNodeID node_id, VLayerID curve_id, uint32 key_id) +{ + VSNodeCurve *node; + unsigned int i, count; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL || node->curve_count <= curve_id || node->curves[curve_id].name[0] == 0) + return; + if(node->curves[curve_id].length <= key_id || node->curves[curve_id].keys[key_id].pos == V_REAL64_MAX) + return; + node->curves[curve_id].keys[key_id].pos = V_REAL64_MAX; + count = vs_get_subscript_count(node->curves[curve_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->curves[curve_id].subscribers, i); + verse_send_c_key_destroy(node_id, curve_id, key_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_c_curve_subscribe(void *user, VNodeID node_id, VLayerID curve_id) +{ + VSNodeCurve *node; + unsigned int i; + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL || node->curve_count <= curve_id || node->curves[curve_id].name[0] == 0) + return; + + vs_add_new_subscriptor(node->curves[curve_id].subscribers); + + for(i = 0; i < node->curves[curve_id].length; i++) + if(node->curves[curve_id].keys[i].pos != V_REAL64_MAX) + verse_send_c_key_set(node_id, curve_id, i, node->curves[curve_id].dimensions, node->curves[curve_id].keys[i].pre_value, node->curves[curve_id].keys[i].pre_pos, node->curves[curve_id].keys[i].value, node->curves[curve_id].keys[i].pos, node->curves[curve_id].keys[i].post_value, node->curves[curve_id].keys[i].post_pos); +} + +static void callback_send_c_curve_unsubscribe(void *user, VNodeID node_id, VLayerID curve_id) +{ + VSNodeCurve *node; + + node = (VSNodeCurve *)vs_get_node(node_id, V_NT_CURVE); + if(node == NULL || curve_id >= node->curve_count || node->curves[curve_id].name[0] == 0) + return; + vs_remove_subscriptor(node->curves[curve_id].subscribers); +} + +void vs_c_callback_init(void) +{ + verse_callback_set(verse_send_c_curve_create, callback_send_c_curve_create, NULL); + verse_callback_set(verse_send_c_curve_destroy, callback_send_c_curve_destroy, NULL); + verse_callback_set(verse_send_c_curve_subscribe, callback_send_c_curve_subscribe, NULL); + verse_callback_set(verse_send_c_curve_unsubscribe, callback_send_c_curve_unsubscribe, NULL); + verse_callback_set(verse_send_c_key_set, callback_send_c_key_set, NULL); + verse_callback_set(verse_send_c_key_destroy, callback_send_c_key_destroy, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_geometry.c b/extern/verse/dist/vs_node_geometry.c new file mode 100644 index 00000000000..4b1f88c8ac2 --- /dev/null +++ b/extern/verse/dist/vs_node_geometry.c @@ -0,0 +1,1047 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_util.h" +#include "vs_server.h" + +#define VS_G_LAYER_CHUNK 32 + +typedef struct { + VNGLayerType type; + char name[16]; + void *layer; + VSSubscriptionList *subscribers; + VSSubscriptionList *subscribersd; + union{ + uint32 integer; + real64 real; + } def; +} VSNGLayer; + +typedef struct { + char weight[16]; + char reference[16]; + uint16 parent; + real64 pos_x; + real64 pos_y; + real64 pos_z; + char position_label[16]; + char rotation_label[16]; + char scale_label[16]; +} VSNGBone; + +typedef struct { + VSNodeHead head; + VSNGLayer *layer; + uint16 layer_count; + uint32 vertex_size; + uint32 poly_size; + uint32 vertex_hole; + uint32 polygon_hole; + uint32 crease_vertex; + char crease_vertex_layer[16]; + uint32 crease_edge; + char crease_edge_layer[16]; + VSNGBone *bones; + uint32 bone_count; +} VSNodeGeometry; + +VSNodeGeometry * vs_g_create_node(unsigned int owner) +{ + VSNodeGeometry *node; + unsigned int i; + char name[48]; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_GEOMETRY); + sprintf(name, "Geometry_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + + node->bones = malloc((sizeof *node->bones) * 16); + node->bone_count = 16; + for(i = 0; i < node->bone_count; i++) + node->bones[i].weight[0] = '\0'; + + node->layer = malloc((sizeof *node->layer) * 16); + node->layer_count = 16; + node->vertex_size = VS_G_LAYER_CHUNK; + node->poly_size = VS_G_LAYER_CHUNK; + + strcpy(node->layer[0].name, "vertex"); + node->layer[0].type = VN_G_LAYER_VERTEX_XYZ; + node->layer[0].layer = malloc(sizeof(real64) * VS_G_LAYER_CHUNK * 3); + for(i = 0; i < VS_G_LAYER_CHUNK * 3; i++) + ((real64 *)node->layer[0].layer)[i] = V_REAL64_MAX; + node->layer[0].subscribers = NULL;/*vs_create_subscription_list();*/ + node->layer[0].subscribersd = NULL;/*vs_create_subscription_list();*/ + node->layer[0].def.real = 0; + + strcpy(node->layer[1].name, "polygon"); + node->layer[1].type = VN_G_LAYER_POLYGON_CORNER_UINT32; + node->layer[1].layer = malloc(sizeof(uint32) * VS_G_LAYER_CHUNK * 4); + for(i = 0; i < VS_G_LAYER_CHUNK * 4; i++) + ((uint32 *)node->layer[1].layer)[i] = -1; + node->layer[1].subscribers = NULL;/*vs_create_subscription_list();*/ + node->layer[1].subscribersd = NULL; + node->layer[1].def.integer = 0; + node->layer[1].def.real = 0.0; + + for(i = 2; i < 16; i++) + { + node->layer[i].type = -1; + node->layer[i].name[0] = 0; + node->layer[i].layer = NULL; + node->layer[i].subscribers = NULL; + node->layer[i].subscribersd = NULL; + node->layer[i].def.real = 0; + } + node->crease_vertex = 0; + node->crease_vertex_layer[0] = 0; + node->crease_edge = 0; + node->crease_edge_layer[0] = 0; + node->vertex_hole = 0; + node->polygon_hole = 0; + return node; +} + +void vs_g_destroy_node(VSNodeGeometry *node) +{ + destroy_node_head(&node->head); + free(node); +} + +void vs_g_subscribe(VSNodeGeometry *node) +{ + unsigned int i; + for(i = 0; i < node->layer_count; i++) + { + if(node->layer[i].layer != NULL) + { + verse_send_g_layer_create(node->head.id, (uint16)i, node->layer[i].name, node->layer[i].type, + node->layer[i].def.integer, node->layer[i].def.real); + } + } + verse_send_g_crease_set_vertex(node->head.id, node->crease_vertex_layer, node->crease_vertex); + verse_send_g_crease_set_edge(node->head.id, node->crease_edge_layer, node->crease_edge); + for(i = 0; i < node->bone_count; i++) + { + if(node->bones[i].weight[0] != 0) + verse_send_g_bone_create(node->head.id, (uint16)i, node->bones[i].weight, node->bones[i].reference, node->bones[i].parent, + node->bones[i].pos_x, node->bones[i].pos_y, node->bones[i].pos_z, node->bones[i].position_label, + node->bones[i].rotation_label, node->bones[i].scale_label); + } +} + + +void vs_g_unsubscribe(VSNodeGeometry *node) +{ + unsigned int i; + for(i = 0; i < node->layer_count; i++) { + if(node->layer[i].layer != NULL) { + if(node->layer[i].subscribers) + vs_remove_subscriptor(node->layer[i].subscribers); + if(node->layer[i].subscribersd) + vs_remove_subscriptor(node->layer[i].subscribersd); + } + } +} + +static void callback_send_g_layer_create(void *user, VNodeID node_id, VLayerID layer_id, char *name, uint8 type, uint32 def_uint, real64 def_real) +{ + VSNodeGeometry *node; + unsigned int i, j, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + + if(node == NULL) + return; + if((type < VN_G_LAYER_POLYGON_CORNER_UINT32 && type > VN_G_LAYER_VERTEX_REAL) || + (type > VN_G_LAYER_POLYGON_FACE_REAL)) + return; + + if(layer_id < 2) + layer_id = -1; + for(i = 0; i < node->layer_count; i++) + { + if(node->layer[i].layer != NULL && i != layer_id) + { + for(j = 0; name[j] == node->layer[i].name[j] && name[j] != 0; j++); + if(name[j] == node->layer[i].name[j]) + return; + } + } + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL) + { + for(layer_id = 0; layer_id < node->layer_count && node->layer[layer_id].layer != NULL; layer_id++); + if(layer_id == node->layer_count) + { + layer_id = node->layer_count; + node->layer_count += 16; + node->layer = realloc(node->layer, (sizeof *node->layer) * node->layer_count); + for(i = layer_id; i < node->layer_count; i++) + { + node->layer[i].type = -1; + node->layer[i].name[0] = 0; + node->layer[i].layer = 0; + node->layer[i].subscribers = NULL; + node->layer[i].subscribersd = NULL; + } + } + } + for(i = 0; i < 16; i++) + node->layer[layer_id].name[i] = name[i]; + + if(node->layer[layer_id].type != type) + { + if(node->layer[layer_id].subscribers) { + vs_destroy_subscription_list(node->layer[layer_id].subscribers); + node->layer[layer_id].subscribers = NULL; + } + if(node->layer[layer_id].subscribersd) { + vs_destroy_subscription_list(node->layer[layer_id].subscribersd); + node->layer[layer_id].subscribersd = NULL; + } + node->layer[layer_id].type = type; + free(node->layer[layer_id].layer); + switch(type) + { + case VN_G_LAYER_VERTEX_XYZ : + node->layer[layer_id].layer = malloc(sizeof(real64) * node->vertex_size * 3); + for(i = 0; i < node->vertex_size * 3; i++) + ((real64 *)node->layer[layer_id].layer)[i] = ((real64 *)node->layer[0].layer)[i]; + break; + case VN_G_LAYER_VERTEX_UINT32 : + node->layer[layer_id].layer = malloc(sizeof(uint32) * node->vertex_size); + for(i = 0; i < node->vertex_size; i++) + ((uint32 *)node->layer[layer_id].layer)[i] = def_uint; + node->layer[layer_id].def.integer = def_uint; + break; + case VN_G_LAYER_VERTEX_REAL : + node->layer[layer_id].layer = malloc(sizeof(real64) * node->vertex_size); + for(i = 0; i < node->vertex_size; i++) + ((real64 *)node->layer[layer_id].layer)[i] = def_real; + node->layer[layer_id].def.real = def_real; + break; + case VN_G_LAYER_POLYGON_CORNER_UINT32 : + node->layer[layer_id].layer = malloc(sizeof(uint32) * node->poly_size * 4); + for(i = 0; i < node->poly_size * 4; i++) + ((uint32 *)node->layer[layer_id].layer)[i] = def_uint; + node->layer[layer_id].def.integer = def_uint; + break; + case VN_G_LAYER_POLYGON_CORNER_REAL : + node->layer[layer_id].layer = malloc(sizeof(real64) * node->poly_size * 4); + for(i = 0; i < node->poly_size * 4; i++) + ((real64 *)node->layer[layer_id].layer)[i] = def_real; + node->layer[layer_id].def.real = def_real; + break; + case VN_G_LAYER_POLYGON_FACE_UINT8 : + node->layer[layer_id].layer = malloc(sizeof(uint8) * node->poly_size); + for(i = 0; i < node->poly_size; i++) + ((uint8 *)node->layer[layer_id].layer)[i] = def_uint; + node->layer[layer_id].def.integer = def_uint; + break; + case VN_G_LAYER_POLYGON_FACE_UINT32 : + node->layer[layer_id].layer = malloc(sizeof(uint32) * node->poly_size); + for(i = 0; i < node->poly_size; i++) + ((uint32 *)node->layer[layer_id].layer)[i] = def_uint; + node->layer[layer_id].def.integer = def_uint; + break; + case VN_G_LAYER_POLYGON_FACE_REAL : + node->layer[layer_id].layer = malloc(sizeof(real64) * node->poly_size); + for(i = 0; i < node->poly_size; i++) + ((real64 *)node->layer[layer_id].layer)[i] = def_real; + node->layer[layer_id].def.real = def_real; + break; + } + } + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_layer_create(node_id, layer_id, name, type, def_uint, def_real); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_layer_destroy(void *user, VNodeID node_id, VLayerID layer_id) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || layer_id < 2) + return; + free(node->layer[layer_id].layer); + node->layer[layer_id].layer = NULL; + node->layer[layer_id].name[0] = 0; + node->layer[layer_id].type = -1; + if(node->layer[layer_id].subscribers) { + vs_destroy_subscription_list(node->layer[layer_id].subscribers); + node->layer[layer_id].subscribers = NULL; + } + if(node->layer[layer_id].subscribersd) { + vs_destroy_subscription_list(node->layer[layer_id].subscribersd); + node->layer[layer_id].subscribersd = NULL; + } + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_layer_destroy(node_id, layer_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_layer_subscribe(void *user, VNodeID node_id, VLayerID layer_id, uint8 type) +{ + VSNodeGeometry *node; + VSNGLayer *layer; + VSSubscriptionList **list = NULL; + unsigned int i; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL) + return; + /* Pick subscription list to add subscriber to. */ + layer = &node->layer[layer_id]; + if(type == VN_FORMAT_REAL64 && (layer->type == VN_G_LAYER_VERTEX_XYZ || layer->type == VN_G_LAYER_VERTEX_REAL || + layer->type == VN_G_LAYER_POLYGON_CORNER_REAL || layer->type == VN_G_LAYER_POLYGON_FACE_REAL)) + { + list = &node->layer[layer_id].subscribersd; + } + else + list = &node->layer[layer_id].subscribers; + + /* Add new subscriptor to whichever list was chosen by precision-test above. Create list if necessary. */ + if(list == NULL) + return; + if(*list == NULL) + *list = vs_create_subscription_list(); + vs_add_new_subscriptor(*list); + + switch(layer->type) + { + case VN_G_LAYER_VERTEX_XYZ : + if(type == VN_FORMAT_REAL64) + { + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX) + verse_send_g_vertex_set_xyz_real64(node_id, layer_id, i, ((real64 *)layer->layer)[i * 3], ((real64 *)layer->layer)[i * 3 + 1], ((real64 *)layer->layer)[i * 3 + 2]); + }else + { + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX) + verse_send_g_vertex_set_xyz_real32(node_id, layer_id, i, (float)((real64 *)layer->layer)[i * 3], (float)((real64 *)layer->layer)[i * 3 + 1], (float)((real64 *)layer->layer)[i * 3 + 2]); + } + break; + case VN_G_LAYER_VERTEX_UINT32 : + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX && ((uint32 *)layer->layer)[i] != layer->def.integer) + verse_send_g_vertex_set_uint32(node_id, layer_id, i, ((uint32 *)layer->layer)[i]); + break; + case VN_G_LAYER_VERTEX_REAL : + if(type == VN_FORMAT_REAL64) + { + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX && ((real64 *)layer->layer)[i] != layer->def.real) + verse_send_g_vertex_set_real64(node_id, layer_id, i, ((real64 *)layer->layer)[i]); + }else + { + for(i = 0; i < node->vertex_size; i++) + if(((real64 *)node->layer[0].layer)[i * 3] != V_REAL64_MAX && ((real64 *)layer->layer)[i] != layer->def.real) + verse_send_g_vertex_set_real32(node_id, layer_id, i, (float)((real64 *)layer->layer)[i]); + } + break; + case VN_G_LAYER_POLYGON_CORNER_UINT32 : + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && !(((uint32 *)layer->layer)[i * 4] == layer->def.integer && ((uint32 *)layer->layer)[i * 4 + 1] == layer->def.integer && ((uint32 *)layer->layer)[i * 4 + 2] == layer->def.integer && ((uint32 *)layer->layer)[i * 4 + 3] == layer->def.integer)) + verse_send_g_polygon_set_corner_uint32(node_id, layer_id, i, ((uint32 *)layer->layer)[i * 4], ((uint32 *)layer->layer)[i * 4 + 1], ((uint32 *)layer->layer)[i * 4 + 2], ((uint32 *)layer->layer)[i * 4 + 3]); + break; + case VN_G_LAYER_POLYGON_CORNER_REAL : + if(type == VN_FORMAT_REAL64) + { + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && !(((real64 *)layer->layer)[i * 4] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 1] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 2] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 3] == layer->def.real)) + verse_send_g_polygon_set_corner_real64(node_id, layer_id, i, ((real64 *)layer->layer)[i * 4], ((real64 *)layer->layer)[i * 4 + 1], ((real64 *)layer->layer)[i * 4 + 2], ((real64 *)layer->layer)[i * 4 + 3]); + }else + { + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && !(((real64 *)layer->layer)[i * 4] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 1] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 2] == layer->def.real && ((real64 *)layer->layer)[i * 4 + 3] == layer->def.real)) + verse_send_g_polygon_set_corner_real32(node_id, layer_id, i, (float)((real64 *)layer->layer)[i * 4], (float)((real64 *)layer->layer)[i * 4 + 1], (float)((real64 *)layer->layer)[i * 4 + 2], (float)((real64 *)layer->layer)[i * 4 + 3]); + } + break; + case VN_G_LAYER_POLYGON_FACE_UINT8 : + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && ((uint8 *)layer->layer)[i] != layer->def.integer) + verse_send_g_polygon_set_face_uint8(node_id, layer_id, i, ((uint8 *)layer->layer)[i]); + break; + case VN_G_LAYER_POLYGON_FACE_UINT32 : + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && ((uint32 *)layer->layer)[i] != layer->def.integer) + verse_send_g_polygon_set_face_uint32(node_id, layer_id, i, ((uint32 *)layer->layer)[i]); + break; + case VN_G_LAYER_POLYGON_FACE_REAL : + if(type == VN_FORMAT_REAL64) + { + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && ((real64 *)layer->layer)[i] != layer->def.real) + verse_send_g_polygon_set_face_real64(node_id, layer_id, i, ((real64 *)layer->layer)[i]); + }else + { + for(i = 0; i < node->poly_size; i++) + if(((uint32 *)node->layer[1].layer)[i * 4] != (uint32) ~0u && ((real64 *)layer->layer)[i] != layer->def.real) + verse_send_g_polygon_set_face_real32(node_id, layer_id, i, (float)((real64 *)layer->layer)[i]); + } + break; + } +} + +static void callback_send_g_layer_unsubscribe(void *user, VNodeID node_id, VLayerID layer_id) +{ + VSNodeGeometry *node; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL) + return; + if(node->layer[layer_id].subscribers) + vs_remove_subscriptor(node->layer[layer_id].subscribers); + if(node->layer[layer_id].subscribersd) + vs_remove_subscriptor(node->layer[layer_id].subscribersd); +} + + +static unsigned int vs_g_extend_arrays(VSNodeGeometry *node, boolean vertex, boolean base_layer, unsigned int id) +{ + unsigned int i, j; + + if(base_layer && id == ~0u) + { + if(vertex) + { + while(node->vertex_hole < node->vertex_size && ((real64 *)node->layer[0].layer)[node->vertex_hole * 3] != V_REAL64_MAX) + node->vertex_hole++; + id = node->vertex_hole; + }else + { + while(node->polygon_hole < node->poly_size && ((uint32 *)node->layer[1].layer)[node->polygon_hole * 4] != ~0u) + node->polygon_hole++; + id = node->polygon_hole; + } + } + + if(vertex) + { + if(node->vertex_size + 4096 < id) + return -1; + if(node->vertex_size > id) + return id; + }else + { + if(node->poly_size + 4096 < id) + return -1; + if(node->poly_size > id) + return id; + } + + for(i = 0; i < node->layer_count; i++) + { + if((vertex && node->layer[i].type < VN_G_LAYER_POLYGON_CORNER_UINT32) || (!vertex && node->layer[i].type >= VN_G_LAYER_POLYGON_CORNER_UINT32)) + { + switch(node->layer[i].type) + { + case VN_G_LAYER_VERTEX_XYZ : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(real64) * (id + VS_G_LAYER_CHUNK) * 3); + for(j = node->vertex_size * 3; j < (id + VS_G_LAYER_CHUNK) * 3; j++) + ((real64 *)node->layer[i].layer)[j] = V_REAL64_MAX; + break; + case VN_G_LAYER_VERTEX_UINT32 : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(uint32) * (id + VS_G_LAYER_CHUNK)); + for(j = node->vertex_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((uint32 *)node->layer[i].layer)[j] = node->layer[i].def.integer; + break; + case VN_G_LAYER_VERTEX_REAL : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(real64) * (id + VS_G_LAYER_CHUNK)); + for(j = node->vertex_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((real64 *)node->layer[i].layer)[j] = node->layer[i].def.real; + break; + case VN_G_LAYER_POLYGON_CORNER_UINT32 : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(uint32) * (id + VS_G_LAYER_CHUNK) * 4); + for(j = node->poly_size * 4; j < (id + VS_G_LAYER_CHUNK) * 4; j++) + ((uint32 *)node->layer[i].layer)[j] = node->layer[i].def.integer; + break; + case VN_G_LAYER_POLYGON_CORNER_REAL : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(real64) * (id + VS_G_LAYER_CHUNK) * 4); + for(j = node->poly_size * 4; j < (id + VS_G_LAYER_CHUNK) * 4; j++) + ((real64 *)node->layer[i].layer)[j] = node->layer[i].def.real; + break; + case VN_G_LAYER_POLYGON_FACE_UINT8 : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(uint8) * (id + VS_G_LAYER_CHUNK)); + for(j = node->poly_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((uint8 *)node->layer[i].layer)[j] = node->layer[i].def.integer; + break; + case VN_G_LAYER_POLYGON_FACE_UINT32 : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(uint32) * (id + VS_G_LAYER_CHUNK)); + for(j = node->poly_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((uint32 *)node->layer[i].layer)[j] = node->layer[i].def.integer; + break; + case VN_G_LAYER_POLYGON_FACE_REAL : + node->layer[i].layer = realloc(node->layer[i].layer, sizeof(real64) * (id + VS_G_LAYER_CHUNK)); + for(j = node->poly_size; j < (id + VS_G_LAYER_CHUNK); j++) + ((real64 *)node->layer[i].layer)[j] = node->layer[i].def.real; + break; + } + } + } + if(vertex) + node->vertex_size = id + VS_G_LAYER_CHUNK; + else + node->poly_size = id + VS_G_LAYER_CHUNK; + return id; +} + + +static void callback_send_g_vertex_set_xyz_real32(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, float x, float y, float z) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_XYZ) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, layer_id == 0, vertex_id)) == ~0u) + return; + if(((real64 *)node->layer[0].layer)[vertex_id * 3] == V_REAL64_MAX) + { + for(i = 0; i < node->layer_count; i++) + { + if(node->layer[i].name[0] != 0 && node->layer[i].type == VN_G_LAYER_VERTEX_XYZ && node->layer[i].layer != NULL) + { + ((real64 *)node->layer[i].layer)[vertex_id * 3] = x; + ((real64 *)node->layer[i].layer)[vertex_id * 3 + 1] = y; + ((real64 *)node->layer[i].layer)[vertex_id * 3 + 2] = z; + } + } + layer_id = 0; + }else + { + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3] = x; + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3 + 1] = y; + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3 + 2] = z; + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_vertex_set_xyz_real64(node_id, layer_id, vertex_id, (real64)x, (real64)y, (real64)z); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_xyz_real32(node_id, layer_id, vertex_id, x, y, z); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_set_xyz_real64(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 x, real64 y, real64 z) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_XYZ) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, layer_id == 0, vertex_id)) == ~0u) + return; + if(((real64 *)node->layer[0].layer)[vertex_id * 3] == V_REAL64_MAX) + { + for(i = 0; i < node->layer_count; i++) + { + if(node->layer[i].name[0] != 0 && node->layer[i].type == VN_G_LAYER_VERTEX_XYZ && node->layer[i].layer != NULL) + { + ((real64 *)node->layer[i].layer)[vertex_id * 3] = x; + ((real64 *)node->layer[i].layer)[vertex_id * 3 + 1] = y; + ((real64 *)node->layer[i].layer)[vertex_id * 3 + 2] = z; + } + } + layer_id = 0; + }else + { + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3] = x; + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3 + 1] = y; + ((real64 *)node->layer[layer_id].layer)[vertex_id * 3 + 2] = z; + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_vertex_set_xyz_real64(node_id, layer_id, vertex_id, x, y, z); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_xyz_real32(node_id, layer_id, vertex_id, (float)x, (float)y, (float)z); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_delete_real(void *user, VNodeID node_id, uint32 vertex_id) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(vertex_id >= node->vertex_size) + return; + if(vertex_id < node->vertex_hole) + node->vertex_hole = vertex_id; + for(i = 0; i < node->layer_count; i++) + if(node->layer[i].name[0] != 0 && node->layer[i].type == VN_G_LAYER_VERTEX_XYZ && node->layer[i].layer != NULL) + ((real64 *)node->layer[i].layer)[vertex_id * 3] = V_REAL64_MAX; + count = vs_get_subscript_count(node->layer[0].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[0].subscribers, i); + verse_send_g_vertex_delete_real32(node_id, vertex_id); + } + count = vs_get_subscript_count(node->layer[0].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[0].subscribersd, i); + verse_send_g_vertex_delete_real64(node_id, vertex_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_set_uint32(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, uint32 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_UINT32) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, FALSE, vertex_id)) == ~0u) + return; + ((uint32 *)node->layer[layer_id].layer)[vertex_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_uint32(node_id, layer_id, vertex_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_set_real64(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real64 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_REAL) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, FALSE, vertex_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[vertex_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_real32(node_id, layer_id, vertex_id, (float)value); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_vertex_set_real64(node_id, layer_id, vertex_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_vertex_set_real32(void *user, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, float value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_VERTEX_REAL) + return; + if((vertex_id = vs_g_extend_arrays(node, TRUE, FALSE, vertex_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[vertex_id] = (real64)value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_vertex_set_real32(node_id, layer_id, vertex_id, value); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_vertex_set_real64(node_id, layer_id, vertex_id, (real64)value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_corner_uint32(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_CORNER_UINT32) + return; + if(layer_id == 1 && (v0 == v1 || v1 == v2 || v2 == v3 || v3 == v0 || v0 == v2 || v1 == v3)) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, layer_id == 1, polygon_id)) == ~0u) + return; + ((uint32 *)node->layer[layer_id].layer)[polygon_id * 4] = v0; + ((uint32 *)node->layer[layer_id].layer)[polygon_id * 4 + 1] = v1; + ((uint32 *)node->layer[layer_id].layer)[polygon_id * 4 + 2] = v2; + ((uint32 *)node->layer[layer_id].layer)[polygon_id * 4 + 3] = v3; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_corner_uint32(node_id, layer_id, polygon_id, v0, v1, v2, v3); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_corner_real64(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 v0, real64 v1, real64 v2, real64 v3) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_CORNER_REAL) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4] = v0; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 1] = v1; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 2] = v2; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 3] = v3; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_corner_real32(node_id, layer_id, polygon_id, (float)v0, (float)v1, (float)v2, (float)v3); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_polygon_set_corner_real64(node_id, layer_id, polygon_id, v0, v1, v2, v3); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_corner_real32(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, float v0, float v1, float v2, float v3) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_CORNER_REAL) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4] = v0; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 1] = v1; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 2] = v2; + ((real64 *)node->layer[layer_id].layer)[polygon_id * 4 + 3] = v3; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_corner_real32(node_id, layer_id, polygon_id, v0, v1, v2, v3); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_polygon_set_corner_real64(node_id, layer_id, polygon_id, (real64)v0, (real64)v1, (real64)v2, (real64)v3); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_face_uint8(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint8 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_FACE_UINT8) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((uint8 *)node->layer[layer_id].layer)[polygon_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_face_uint8(node_id, layer_id, polygon_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_face_uint32(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_FACE_UINT32) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((uint32 *)node->layer[layer_id].layer)[polygon_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_face_uint32(node_id, layer_id, polygon_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_face_real64(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, real64 value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_FACE_REAL) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[polygon_id] = value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_face_real32(node_id, layer_id, polygon_id, (float)value); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_polygon_set_face_real64(node_id, layer_id, polygon_id, value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_set_face_real32(void *user, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, float value) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(layer_id >= node->layer_count || node->layer[layer_id].layer == NULL || node->layer[layer_id].type != VN_G_LAYER_POLYGON_FACE_REAL) + return; + if((polygon_id = vs_g_extend_arrays(node, FALSE, FALSE, polygon_id)) == ~0u) + return; + ((real64 *)node->layer[layer_id].layer)[polygon_id] = (real64)value; + count = vs_get_subscript_count(node->layer[layer_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribers, i); + verse_send_g_polygon_set_face_real32(node_id, layer_id, polygon_id, value); + } + count = vs_get_subscript_count(node->layer[layer_id].subscribersd); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[layer_id].subscribersd, i); + verse_send_g_polygon_set_face_real64(node_id, layer_id, polygon_id, (real64)value); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_polygon_delete(void *user, VNodeID node_id, uint32 polygon_id) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + + if(polygon_id >= node->poly_size || ((uint32 *)node->layer[1].layer)[polygon_id * 4] == ~0u) + return; + if(polygon_id < node->polygon_hole) + node->polygon_hole = polygon_id; + + ((uint32 *)node->layer[1].layer)[polygon_id * 4] = ~0u; + count = vs_get_subscript_count(node->layer[1].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->layer[1].subscribers, i); + verse_send_g_polygon_delete(node_id, polygon_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_crease_set_vertex(void *user, VNodeID node_id, const char *layer, uint32 def_crease) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + node->crease_vertex = def_crease; + v_strlcpy(node->crease_vertex_layer, layer, sizeof node->crease_vertex_layer); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_crease_set_vertex(node_id, layer, def_crease); + } + vs_reset_subscript_session(); +} + +static void callback_send_g_crease_set_edge(void *user, VNodeID node_id, const char *layer, uint32 def_crease) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + node->crease_edge = def_crease; + v_strlcpy(node->crease_edge_layer, layer, sizeof node->crease_edge_layer); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_crease_set_edge(node_id, layer, def_crease); + } + vs_reset_subscript_session(); +} + +void callback_send_g_bone_create(void *user, VNodeID node_id, uint16 bone_id, const char *weight, + const char *reference, uint16 parent, + real64 pos_x, real64 pos_y, real64 pos_z, + const char *position_label, const char *rotation_label, const char *scale_label) +{ + VSNodeGeometry *node; + unsigned int i, count; + + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(bone_id >= node->bone_count || node->bones[bone_id].weight[0] == '\0') + { + /* Find free bone to re-use, if any. */ + for(bone_id = 0; bone_id < node->bone_count && node->bones[bone_id].weight[0] != '\0'; bone_id++) + ; + if(bone_id == node->bone_count) + { + bone_id = node->bone_count; + node->bone_count += 16; + node->bones = realloc(node->bones, (sizeof *node->bones) * node->bone_count); + for(i = bone_id; i < node->bone_count; i++) + node->bones[i].weight[0] = '\0'; + } + } + v_strlcpy(node->bones[bone_id].weight, weight, sizeof node->bones[bone_id].weight); + v_strlcpy(node->bones[bone_id].reference, reference, sizeof node->bones[bone_id].reference); + node->bones[bone_id].parent = parent; + node->bones[bone_id].pos_x = pos_x; + node->bones[bone_id].pos_y = pos_y; + node->bones[bone_id].pos_z = pos_z; + v_strlcpy(node->bones[bone_id].position_label, position_label, sizeof node->bones[bone_id].position_label); + v_strlcpy(node->bones[bone_id].rotation_label, rotation_label, sizeof node->bones[bone_id].rotation_label); + v_strlcpy(node->bones[bone_id].scale_label, scale_label, sizeof node->bones[bone_id].scale_label); + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_bone_create(node_id, bone_id, weight, reference, parent, pos_x, pos_y, pos_z, position_label, rotation_label, scale_label); + } + vs_reset_subscript_session(); +} + +void callback_send_g_bone_destroy(void *user, VNodeID node_id, uint32 bone_id) +{ + VSNodeGeometry *node; + unsigned int i, count; + node = (VSNodeGeometry *)vs_get_node(node_id, V_NT_GEOMETRY); + if(node == NULL) + return; + if(bone_id >= node->bone_count || node->bones[bone_id].weight[0] == 0) + return; + node->bones[bone_id].weight[0] = 0; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_g_bone_destroy(node_id, bone_id); + } + vs_reset_subscript_session(); +} + +void vs_g_callback_init(void) +{ + verse_callback_set(verse_send_g_layer_create, callback_send_g_layer_create, NULL); + verse_callback_set(verse_send_g_layer_destroy, callback_send_g_layer_destroy, NULL); + verse_callback_set(verse_send_g_layer_subscribe, callback_send_g_layer_subscribe, NULL); + verse_callback_set(verse_send_g_layer_unsubscribe, callback_send_g_layer_unsubscribe, NULL); + verse_callback_set(verse_send_g_vertex_set_xyz_real32, callback_send_g_vertex_set_xyz_real32, NULL); + verse_callback_set(verse_send_g_vertex_set_xyz_real64, callback_send_g_vertex_set_xyz_real64, NULL); + verse_callback_set(verse_send_g_vertex_set_uint32, callback_send_g_vertex_set_uint32, NULL); + verse_callback_set(verse_send_g_vertex_set_real32, callback_send_g_vertex_set_real32, NULL); + verse_callback_set(verse_send_g_vertex_set_real64, callback_send_g_vertex_set_real64, NULL); + verse_callback_set(verse_send_g_vertex_delete_real32, callback_send_g_vertex_delete_real, NULL); + verse_callback_set(verse_send_g_vertex_delete_real64, callback_send_g_vertex_delete_real, NULL); + verse_callback_set(verse_send_g_polygon_set_corner_uint32, callback_send_g_polygon_set_corner_uint32, NULL); + verse_callback_set(verse_send_g_polygon_set_corner_real32, callback_send_g_polygon_set_corner_real32, NULL); + verse_callback_set(verse_send_g_polygon_set_corner_real64, callback_send_g_polygon_set_corner_real64, NULL); + verse_callback_set(verse_send_g_polygon_set_face_uint8, callback_send_g_polygon_set_face_uint8, NULL); + verse_callback_set(verse_send_g_polygon_set_face_uint32, callback_send_g_polygon_set_face_uint32, NULL); + verse_callback_set(verse_send_g_polygon_set_face_real32, callback_send_g_polygon_set_face_real32, NULL); + verse_callback_set(verse_send_g_polygon_set_face_real64, callback_send_g_polygon_set_face_real64, NULL); + verse_callback_set(verse_send_g_polygon_delete, callback_send_g_polygon_delete, NULL); + verse_callback_set(verse_send_g_crease_set_vertex, callback_send_g_crease_set_vertex, NULL); + verse_callback_set(verse_send_g_crease_set_edge, callback_send_g_crease_set_edge, NULL); + verse_callback_set(verse_send_g_bone_create, callback_send_g_bone_create, NULL); + verse_callback_set(verse_send_g_bone_destroy, callback_send_g_bone_destroy, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_head.c b/extern/verse/dist/vs_node_head.c new file mode 100644 index 00000000000..9e926411542 --- /dev/null +++ b/extern/verse/dist/vs_node_head.c @@ -0,0 +1,414 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined(V_GENERATE_FUNC_MODE) + +#include "verse.h" +#include "v_util.h" +#include "vs_server.h" + +typedef struct { + VNTag tag; + VNTagType type; + char tag_name[16]; +} VSTag; + +typedef struct { + VSTag *tags; + unsigned int tag_count; + char group_name[16]; + VSSubscriptionList *subscribers; +} VSTagGroup; + +void create_node_head(VSNodeHead *node, const char *name, unsigned int owner) +{ + size_t len; + + len = strlen(name) + 1; + node->name = malloc(len); + v_strlcpy(node->name, name, len); + node->owner = owner; + node->tag_groups = NULL; + node->group_count = 0; + node->subscribers = vs_create_subscription_list(); +} + +void destroy_node_head(VSNodeHead *node) +{ + unsigned int i, j; + if(node->name != NULL) + free(node->name); + if(node->tag_groups != NULL) + { + for(i = 0; i < node->group_count; i++) + { + for(j = 0; j < ((VSTagGroup *)node->tag_groups)[i].tag_count; j++) + { + if(((VSTagGroup *)node->tag_groups)[i].tags[j].type == VN_TAG_STRING) + free(((VSTagGroup *)node->tag_groups)[i].tags[j].tag.vstring); + if(((VSTagGroup *)node->tag_groups)[i].tags[j].type == VN_TAG_BLOB) + free(((VSTagGroup *)node->tag_groups)[i].tags[j].tag.vblob.blob); + } + if(((VSTagGroup *)node->tag_groups)[i].tags != NULL) + free(((VSTagGroup *)node->tag_groups)[i].tags); + } + if(node->tag_groups != NULL) + free(node->tag_groups); + } +} + + void callback_send_tag_group_create(void *user, VNodeID node_id, uint16 group_id, const char *name) +{ + VSNodeHead *node; + unsigned int count, i, j, element; + + if((node = vs_get_node_head(node_id)) == 0) + return; + if(name[0] == 0) + return; + + for(i = 0; i < node->group_count; i++) /* see if a tag group with this name alredy exists*/ + { + if(((VSTagGroup *)node->tag_groups)[i].group_name[0] != 0) + { + for(j = 0; name[j] == ((VSTagGroup *)node->tag_groups)[i].group_name[j] && name[j] != 0; j++); + if(name[j] == ((VSTagGroup *)node->tag_groups)[i].group_name[j]) + return; + } + } + if(group_id < node->group_count && ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] != 0) /* rename existing group */ + { + element = group_id; + }else /* create new game group */ + { + for(element = 0; element < node->group_count && ((VSTagGroup *)node->tag_groups)[element].group_name[0] != 0; element++); + if(element == node->group_count) + { + node->tag_groups = realloc(node->tag_groups, sizeof(VSTagGroup) * (node->group_count + 16)); + for(i = node->group_count; i < node->group_count + 16U; i++) + { + ((VSTagGroup *)node->tag_groups)[i].group_name[0] = 0; + ((VSTagGroup *)node->tag_groups)[i].tags = NULL; + ((VSTagGroup *)node->tag_groups)[i].tag_count = 0; + ((VSTagGroup *)node->tag_groups)[i].subscribers = NULL; + } + node->group_count += 16; + } + ((VSTagGroup *)node->tag_groups)[element].subscribers = vs_create_subscription_list(); + } + v_strlcpy(((VSTagGroup *)node->tag_groups)[element].group_name, name, + sizeof ((VSTagGroup *)node->tag_groups)[element].group_name); + + count = vs_get_subscript_count(node->subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->subscribers, i); + verse_send_tag_group_create(node_id, element, name); + } + vs_reset_subscript_session(); +} + +static void callback_send_tag_group_destroy(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeHead *node; + unsigned int count, i; + if((node = vs_get_node_head(node_id)) == 0) + return; + + if(node->group_count <= group_id || ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] == 0) + return; + + vs_destroy_subscription_list(((VSTagGroup *)node->tag_groups)[group_id].subscribers); + for(i = 0; i < ((VSTagGroup *)node->tag_groups)[group_id].tag_count; i++) + { + if(((VSTagGroup *)node->tag_groups)[group_id].tags[i].type == VN_TAG_STRING) + free(((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag.vstring); + if(((VSTagGroup *)node->tag_groups)[group_id].tags[i].type == VN_TAG_BLOB) + free(((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag.vblob.blob); + } + if(((VSTagGroup *)node->tag_groups)[group_id].tags != NULL) + free(((VSTagGroup *)node->tag_groups)[group_id].tags); + ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] = 0; + ((VSTagGroup *)node->tag_groups)[group_id].tags = NULL; + ((VSTagGroup *)node->tag_groups)[group_id].tag_count = 0; + + count = vs_get_subscript_count(node->subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->subscribers, i); + verse_send_tag_group_destroy(node_id, group_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_tag_group_subscribe(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeHead *node; + unsigned int i; + if((node = vs_get_node_head(node_id)) == 0) + return; + + if(group_id < node->group_count && ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] != 0) + { + vs_add_new_subscriptor(((VSTagGroup *)node->tag_groups)[group_id].subscribers); + for(i = 0; i < ((VSTagGroup *)node->tag_groups)[group_id].tag_count; i++) + { + if(((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name[0] != 0) + { + verse_send_tag_create(node_id, group_id, (uint16)i, ((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name, ((VSTagGroup *)node->tag_groups)[group_id].tags[i].type, &((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag); + } + } + } +} + +static void callback_send_tag_group_unsubscribe(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeHead *node; + if((node = vs_get_node_head(node_id)) == 0) + return; + if(group_id < node->group_count && ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] != 0) + vs_remove_subscriptor(((VSTagGroup *)node->tag_groups)[group_id].subscribers); +} + +static void callback_send_tag_create(void *user, VNodeID node_id, uint16 group_id, uint16 tag_id, char *name, uint8 type, void *tag) +{ + VSNodeHead *node; + VSTag *t = NULL; + unsigned int i, count; + + if((node = vs_get_node_head(node_id)) == 0) + return; + if(group_id >= node->group_count || ((VSTagGroup *)node->tag_groups)[group_id].group_name[0] == 0) + return; + +/* for(i = 0; i < ((VSTagGroup *)node->tag_groups)[group_id].tag_count; i++) + { + if(((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name != NULL && i != tag_id) + { + for(j = 0; name[j] == ((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name[j] && name[j] != 0; j++); + if(name[j] == ((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name[j]) + return; + } + }*/ + if(tag_id < ((VSTagGroup *)node->tag_groups)[group_id].tag_count && ((VSTagGroup *)node->tag_groups)[group_id].tags[tag_id].tag_name[0] != 0) + ; + else + { + for(tag_id = 0; tag_id < ((VSTagGroup *)node->tag_groups)[group_id].tag_count && ((VSTagGroup *)node->tag_groups)[group_id].tags[tag_id].tag_name[0] != 0; tag_id++) + ; + if(tag_id == ((VSTagGroup *)node->tag_groups)[group_id].tag_count) + { + ((VSTagGroup *)node->tag_groups)[group_id].tags = realloc(((VSTagGroup *)node->tag_groups)[group_id].tags, sizeof(VSTag) * (((VSTagGroup *)node->tag_groups)[group_id].tag_count + 16)); + for(i = tag_id; i < ((VSTagGroup *)node->tag_groups)[group_id].tag_count + 16; i++) + ((VSTagGroup *)node->tag_groups)[group_id].tags[i].tag_name[0] = 0; + ((VSTagGroup *)node->tag_groups)[group_id].tag_count += 16; + } + } + t = &((VSTagGroup *)node->tag_groups)[group_id].tags[tag_id]; + if(t->tag_name[0] != '\0') /* Old tag being re-set? */ + { + if(t->type == VN_TAG_STRING) + free(t->tag.vstring); + else if(t->type == VN_TAG_BLOB) + free(t->tag.vblob.blob); + } + t->type = type; + v_strlcpy(t->tag_name, name, sizeof t->tag_name); + switch(type) + { + case VN_TAG_BOOLEAN : + t->tag.vboolean = ((VNTag *)tag)->vboolean; + break; + case VN_TAG_UINT32 : + t->tag.vuint32 = ((VNTag *)tag)->vuint32; + break; + case VN_TAG_REAL64 : + t->tag.vreal64 = ((VNTag *)tag)->vreal64; + break; + case VN_TAG_STRING : + i = strlen(((VNTag *) tag)->vstring); + t->tag.vstring = malloc(i + 1); + strcpy(t->tag.vstring, ((VNTag *) tag)->vstring); + break; + case VN_TAG_REAL64_VEC3 : + t->tag.vreal64_vec3[0] = ((VNTag *)tag)->vreal64_vec3[0]; + t->tag.vreal64_vec3[1] = ((VNTag *)tag)->vreal64_vec3[1]; + t->tag.vreal64_vec3[2] = ((VNTag *)tag)->vreal64_vec3[2]; + break; + case VN_TAG_LINK : + t->tag.vlink = ((VNTag *)tag)->vlink; + break; + case VN_TAG_ANIMATION : + t->tag.vanimation.curve = ((VNTag *)tag)->vanimation.curve; + t->tag.vanimation.start = ((VNTag *)tag)->vanimation.start; + t->tag.vanimation.end = ((VNTag *)tag)->vanimation.end; + break; + case VN_TAG_BLOB : + t->tag.vblob.blob = malloc(((VNTag *)tag)->vblob.size); + t->tag.vblob.size = ((VNTag *)tag)->vblob.size; + memcpy(t->tag.vblob.blob, ((VNTag *)tag)->vblob.blob, ((VNTag *)tag)->vblob.size); + break; + } + + count = vs_get_subscript_count(((VSTagGroup *) node->tag_groups)[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(((VSTagGroup *) node->tag_groups)[group_id].subscribers, i); + verse_send_tag_create(node_id, group_id, tag_id, name, type, tag); + } + vs_reset_subscript_session(); +} + +static void callback_send_tag_destroy(void *user, VNodeID node_id, uint16 group_id, uint16 tag_id) +{ + VSNodeHead *node; + unsigned int count, i; + if((node = vs_get_node_head(node_id)) == 0) + return; + + count = vs_get_subscript_count(((VSTagGroup *) node->tag_groups)[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(((VSTagGroup *) node->tag_groups)[group_id].subscribers, i); + verse_send_tag_destroy(node_id, group_id, tag_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_node_name_set(void *user, VNodeID node_id, char *name) +{ + VSNodeHead *node; + unsigned int count, i; + size_t len; + + if((node = vs_get_node_head(node_id)) == 0) + return; + len = strlen(name); + if(len == 0) + return; + free(node->name); + len++; + node->name = malloc(len); + v_strlcpy(node->name, name, len); + count = vs_get_subscript_count(node->subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->subscribers, i); + verse_send_node_name_set(node_id, name); + } + vs_reset_subscript_session(); +} + +extern void vs_o_subscribe(VSNodeHead *node); +extern void vs_g_subscribe(VSNodeHead *node); +extern void vs_m_subscribe(VSNodeHead *node); +extern void vs_b_subscribe(VSNodeHead *node); +extern void vs_t_subscribe(VSNodeHead *node); +extern void vs_c_subscribe(VSNodeHead *node); +extern void vs_a_subscribe(VSNodeHead *node); + +static void callback_send_node_subscribe(void *user, VNodeID node_id) +{ + unsigned int i; + VSNodeHead *node; + + if((node = vs_get_node_head(node_id)) == NULL) + return; + switch(node->type) + { + case V_NT_OBJECT : + vs_o_subscribe(node); + break; + case V_NT_GEOMETRY : + vs_g_subscribe(node); + break; + case V_NT_MATERIAL : + vs_m_subscribe(node); + break; + case V_NT_BITMAP : + vs_b_subscribe(node); + break; + case V_NT_TEXT: + vs_t_subscribe(node); + break; + case V_NT_CURVE: + vs_c_subscribe(node); + break; + case V_NT_AUDIO: + vs_a_subscribe(node); + break; + default: + fprintf(stderr, "Not subscribing to node type %d\n", node->type); + } + verse_send_node_name_set(node->id, node->name); + for(i = 0; i < node->group_count; i++) + if(((VSTagGroup *)node->tag_groups)[i].group_name[0] != 0) + verse_send_tag_group_create(node->id, (uint16)i, ((VSTagGroup *)node->tag_groups)[i].group_name); + vs_add_new_subscriptor(node->subscribers); +} + +extern void vs_o_unsubscribe(VSNodeHead *node); +extern void vs_g_unsubscribe(VSNodeHead *node); +extern void vs_m_unsubscribe(VSNodeHead *node); +extern void vs_b_unsubscribe(VSNodeHead *node); +extern void vs_t_unsubscribe(VSNodeHead *node); +extern void vs_c_unsubscribe(VSNodeHead *node); +extern void vs_a_unsubscribe(VSNodeHead *node); + +static void callback_send_node_unsubscribe(void *user, VNodeID node_id) +{ + VSNodeHead *node; + + if((node = vs_get_node_head(node_id)) == NULL) + return; + vs_remove_subscriptor(node->subscribers); + + switch(node->type) + { + case V_NT_OBJECT : + vs_o_unsubscribe(node); + break; + case V_NT_GEOMETRY : + vs_g_unsubscribe(node); + break; + case V_NT_MATERIAL : + vs_m_unsubscribe(node); + break; + case V_NT_BITMAP : + vs_b_unsubscribe(node); + break; + case V_NT_TEXT: + vs_t_unsubscribe(node); + break; + case V_NT_CURVE: + vs_c_unsubscribe(node); + break; + case V_NT_AUDIO: + vs_a_unsubscribe(node); + break; + default: + fprintf(stderr, "Not unsubscribing from node type %d\n", node->type); + } +} + +void vs_h_callback_init(void) +{ + verse_callback_set(verse_send_tag_group_create, callback_send_tag_group_create, NULL); + verse_callback_set(verse_send_tag_group_destroy, callback_send_tag_group_destroy, NULL); + verse_callback_set(verse_send_tag_group_subscribe, callback_send_tag_group_subscribe, NULL); + verse_callback_set(verse_send_tag_group_unsubscribe, callback_send_tag_group_unsubscribe, NULL); + verse_callback_set(verse_send_tag_create, callback_send_tag_create, NULL); + verse_callback_set(verse_send_tag_destroy, callback_send_tag_destroy, NULL); + verse_callback_set(verse_send_node_name_set, callback_send_node_name_set, NULL); + verse_callback_set(verse_send_node_subscribe, callback_send_node_subscribe, NULL); + verse_callback_set(verse_send_node_unsubscribe, callback_send_node_unsubscribe, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_material.c b/extern/verse/dist/vs_node_material.c new file mode 100644 index 00000000000..b22c070e348 --- /dev/null +++ b/extern/verse/dist/vs_node_material.c @@ -0,0 +1,116 @@ +/* +** +*/ + +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +typedef struct { + VNMFragmentType type; + VMatFrag frag; +} VSMatFrag; + +typedef struct{ + VSNodeHead head; + VSMatFrag *frag; + unsigned int frag_count; +} VSNodeMaterial; + +VSNodeMaterial * vs_m_create_node(unsigned int owner) +{ + VSNodeMaterial *node; + char name[48]; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_MATERIAL); + sprintf(name, "Material_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->frag = NULL; + node->frag_count = 0; + return node; +} + +void vs_m_destroy_node(VSNodeMaterial *node) +{ + destroy_node_head(&node->head); + free(node->frag); + free(node); +} + +void vs_m_subscribe(VSNodeMaterial *node) +{ + uint16 i; + for(i = 0; i < node->frag_count; i++) + if(node->frag[i].type <= VN_M_FT_OUTPUT) + verse_send_m_fragment_create(node->head.id, (uint16)i, (uint8)node->frag[i].type, &node->frag[i].frag); +} + +void vs_m_unsubscribe(VSNodeMaterial *node) +{ +} + +static void callback_send_m_fragment_create(void *user, VNodeID node_id, VNMFragmentID frag_id, uint8 type, VMatFrag *fragment) +{ + unsigned int count; + uint16 i; + VSNodeMaterial *node; + node = (VSNodeMaterial *)vs_get_node(node_id, V_NT_MATERIAL); + if(node == NULL) + return; + if(node->frag_count + 32 < frag_id) + frag_id = (uint16)-1; + if(frag_id == (uint16) ~0u) + for(frag_id = 0; frag_id < node->frag_count && node->frag[frag_id].type < VN_M_FT_OUTPUT + 1; frag_id++) + ; + if(frag_id >= node->frag_count) + { + node->frag = realloc(node->frag, (sizeof *node->frag) * (node->frag_count + 32)); + for(i = node->frag_count; i < (node->frag_count + 32); i++) + node->frag[i].type = 255; + node->frag_count += 32; + } + node->frag[frag_id].type = type; + node->frag[frag_id].frag = *fragment; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_m_fragment_create(node_id, frag_id, type, fragment); + } + vs_reset_subscript_session(); +} + +static void callback_send_m_fragment_destroy(void *user, VNodeID node_id, VNMFragmentID frag_id) +{ + unsigned int count, i; + VSNodeMaterial *node; + node = (VSNodeMaterial *)vs_get_node(node_id, V_NT_MATERIAL); + printf("callback_send_m_fragment_destroy %p\n", node); + if(node == NULL) + return; + if(node->frag_count <= frag_id || node->frag[frag_id].type > VN_M_FT_OUTPUT) + return; + node->frag[frag_id].type = 255; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_m_fragment_destroy(node_id, frag_id); + } + vs_reset_subscript_session(); +} + +void vs_m_callback_init(void) +{ + verse_callback_set(verse_send_m_fragment_create, callback_send_m_fragment_create, NULL); + verse_callback_set(verse_send_m_fragment_destroy, callback_send_m_fragment_destroy, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_object.c b/extern/verse/dist/vs_node_object.c new file mode 100644 index 00000000000..d269a8ddb99 --- /dev/null +++ b/extern/verse/dist/vs_node_object.c @@ -0,0 +1,837 @@ +/* +** +*/ + +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "v_util.h" +#include "vs_server.h" + +extern void verse_send_o_link_set(VNodeID node_id, uint16 link_id, VNodeID link, const char *name, uint32 target_id); +extern void verse_send_o_link_destroy(VNodeID node_id, uint16 link_id); + +typedef struct { + VNodeID link; + char name[16]; + uint32 target_id; + /* Animation parameters. */ + uint32 time_s; + uint32 time_f; + uint32 dimensions; + real64 pos[4]; + real64 speed[4]; + real64 accel[4]; + real64 scale[4]; + real64 scale_speed[4]; +} VSLink; + +typedef struct { + char name[16]; + uint8 param_count; + VNOParamType *param_types; + char *param_names; +} VSMethod; + +typedef struct { + char name[VN_O_METHOD_GROUP_NAME_SIZE]; + VSMethod *methods; + unsigned int method_count; + VSSubscriptionList *subscribers; +} VSMethodGroup; + +typedef struct { + real64 position[3]; + VNQuat64 rotation; + real64 scale[3]; +/* VSSubscriptionList *subscribers;*/ +} VSTransform; + +typedef struct { + VSNodeHead head; + VSTransform transform; + VSSubscriptionList *trans_sub64; + VSSubscriptionList *trans_sub32; + real64 light[3]; + VSMethodGroup *groups; + uint16 group_count; + VSLink *links; + uint16 link_count; + boolean hidden; +} VSNodeObject; + +VSNodeObject * vs_o_create_node(unsigned int owner) +{ + VSNodeObject *node; + unsigned int i, j; + char name[48]; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_OBJECT); + sprintf(name, "Object_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->trans_sub64 = vs_create_subscription_list(); + node->trans_sub32 = vs_create_subscription_list(); + node->transform.position[0] = node->transform.position[1] = node->transform.position[2] = 0; + node->transform.rotation.x = node->transform.rotation.y = node->transform.rotation.z = 0.0; + node->transform.rotation.w = 1.0; + node->transform.scale[0] = node->transform.scale[1] = node->transform.scale[2] = 1.0; + node->light[0] = node->light[1] = node->light[2] = V_REAL64_MAX; + node->groups = malloc((sizeof *node->groups) * 16); + node->group_count = 16; + for(i = 0; i < 16; i++) + { + node->groups[i].name[0] = 0; + node->groups[i].methods = NULL; + node->groups[i].method_count = 0; + node->groups[i].subscribers = NULL; + } + + node->link_count = 16; + node->links = malloc((sizeof *node->links) * node->link_count); + for(i = 0; i < node->link_count; i++) + { + node->links[i].link = -1; + node->links[i].name[0] = 0; + node->links[i].target_id = -1; + node->links[i].dimensions = 0; + for(j = 0; j < 4; j++) + { + node->links[i].pos[j] = 0.0; + node->links[i].speed[j] = 0.0; + node->links[i].accel[j] = 0.0; + node->links[i].scale[j] = 0.0; + node->links[i].scale_speed[j] = 0.0; + } + } + node->hidden = FALSE; + return node; +} + +void vs_o_destroy_node(VSNodeObject *node) +{ + unsigned int i, j; + destroy_node_head(&node->head); + for(i = 0; i < node->group_count; i++) + { + if(node->groups[i].name[0] != 0) + { + for(j = 0; j < node->groups[i].method_count; j++) + { + if(node->groups[i].methods[j].name[0] != 0 && node->groups[i].methods[j].param_count != 0) + { + free(node->groups[i].methods[j].param_types); + free(node->groups[i].methods[j].param_names); + } + } + if(node->groups[i].methods != NULL) + free(node->groups[i].methods); + } + } + free(node->groups); + free(node); +} + +void vs_o_subscribe(VSNodeObject *node) +{ + unsigned int i; + for(i = 0; i < node->link_count; i++) + { + const VSLink *lnk = node->links + i; + + if(lnk->name[0] != 0) + { + verse_send_o_link_set(node->head.id, i, lnk->link, lnk->name, lnk->target_id); + if(lnk->dimensions != 0) + { + verse_send_o_anim_run(node->head.id, i, lnk->time_s, lnk->time_f, lnk->dimensions, + lnk->pos, lnk->speed, lnk->accel, + lnk->scale, lnk->scale_speed); + } + } + } + if(node->light[0] != V_REAL64_MAX || node->light[1] != V_REAL64_MAX || node->light[2] != V_REAL64_MAX) + verse_send_o_light_set(node->head.id, node->light[0], node->light[1], node->light[2]); + for(i = 0; i < node->group_count; i++) + { + if(node->groups[i].name[0] != 0) + verse_send_o_method_group_create(node->head.id, i, node->groups[i].name); + } + if(node->hidden) + verse_send_o_hide(node->head.id, TRUE); +} + +void vs_o_unsubscribe(VSNodeObject *node) +{ + unsigned int i; + for(i = 0; i < node->group_count; i++) + if(node->groups[i].name[0] != 0) + vs_remove_subscriptor(node->groups[i].subscribers); + vs_remove_subscriptor(node->trans_sub64); + vs_remove_subscriptor(node->trans_sub32); +} + +static void callback_send_o_transform_pos_real32(void *user, VNodeID node_id, uint32 time_s, uint32 time_f, real32 *pos, real32 *speed, real32 *accelerate, real32 *drag_normal, real32 drag) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.position[0] = pos[0]; + node->transform.position[1] = pos[1]; + node->transform.position[2] = pos[2]; + + if((count = vs_get_subscript_count(node->trans_sub64)) > 0) /* Anyone listening at 64 bits? */ + { + real64 spd[3], acc[3], drn[3], *pspd = NULL, *pacc = NULL, *pdrn = NULL; + + pspd = (speed != NULL) ? spd : NULL; + pacc = (accelerate != NULL) ? acc : NULL; + pdrn = (drag_normal != NULL) ? drn : NULL; + /* Convert non-position values to 64-bit. */ + for(i = 0; i < 3; i++) + { + if(speed != NULL) + spd[i] = speed[i]; + if(accelerate != NULL) + acc[i] = accelerate[i]; + if(drag_normal != NULL) + drn[i] = drag_normal[i]; + } + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_pos_real64(node_id, time_s, time_f, node->transform.position, pspd, pacc, pdrn, drag); + } + } + count = vs_get_subscript_count(node->trans_sub32); + for(i = 0; i < count; i++) + { + + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_pos_real32(node_id, time_s, time_f, pos, speed, accelerate, drag_normal, drag); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_rot_real32(void *user, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *rot, + const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.rotation.x = rot->x; + node->transform.rotation.y = rot->y; + node->transform.rotation.z = rot->z; + node->transform.rotation.w = rot->w; + if((count = vs_get_subscript_count(node->trans_sub64)) > 0) + { + VNQuat64 spd, acc, drn, *p[3]; + + /* Convert 32-bit quaternions to 64-bit. Converter handles NULLs, has nice return semantics. */ + p[0] = v_quat64_from_quat32(&spd, speed); + p[1] = v_quat64_from_quat32(&acc, accelerate); + p[2] = v_quat64_from_quat32(&drn, drag_normal); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_rot_real64(node_id, time_s, time_f, &node->transform.rotation, p[0], p[1], p[2], drag); + } + } + count = vs_get_subscript_count(node->trans_sub32); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_rot_real32(node_id, time_s, time_f, rot, speed, accelerate, drag_normal, drag); + } + vs_reset_subscript_session(); +} + + +static void callback_send_o_transform_scale_real32(void *user, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.scale[0] = scale_x; + node->transform.scale[1] = scale_y; + node->transform.scale[2] = scale_z; + count = vs_get_subscript_count(node->trans_sub64); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_scale_real64(node_id, scale_x, scale_y, scale_z); + } + count = vs_get_subscript_count(node->trans_sub32); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_scale_real32(node_id, scale_x, scale_y, scale_z); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_pos_real64(void *user, VNodeID node_id, uint32 time_s, uint32 time_f, const real64 *pos, + const real64 *speed, const real64 *accelerate, const real64 *drag_normal, real64 drag) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.position[0] = pos[0]; + node->transform.position[1] = pos[1]; + node->transform.position[2] = pos[2]; + count = vs_get_subscript_count(node->trans_sub64); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_pos_real64(node_id, time_s, time_f, node->transform.position, speed, accelerate, drag_normal, drag); + } + if((count = vs_get_subscript_count(node->trans_sub32)) > 0) /* Anyone listening at 32 bits? */ + { + real32 ps[3], spd[3], acc[3], drn[3], *p[] = { NULL, NULL, NULL }; + + ps[0] = pos[0]; + ps[1] = pos[1]; + ps[2] = pos[2]; + if(speed != NULL) + { + p[0] = spd; + spd[0] = speed[0]; + spd[1] = speed[1]; + spd[2] = speed[2]; + } + else + p[0] = NULL; + if(accelerate != NULL) + { + p[1] = acc; + acc[0] = accelerate[0]; + acc[1] = accelerate[1]; + acc[2] = accelerate[2]; + } + else + p[1] = NULL; + if(drag_normal != NULL) + { + p[1] = drn; + drn[0] = drag_normal[0]; + drn[1] = drag_normal[1]; + drn[2] = drag_normal[2]; + } + else + p[2] = NULL; + + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_pos_real32(node_id, time_s, time_f, ps, p[0], p[1], p[2], (real32) drag); + } + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_rot_real64(void *user, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat64 *rot, + const VNQuat64 *speed, const VNQuat64 *accelerate, const VNQuat64 *drag_normal, real64 drag) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.rotation = *rot; + count = vs_get_subscript_count(node->trans_sub64); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_rot_real64(node_id, time_s, time_f, &node->transform.rotation, speed, accelerate, drag_normal, drag); + } + if((count = vs_get_subscript_count(node->trans_sub32)) > 0) /* Anyone listening at 32 bits? */ + { + VNQuat32 rt, spd, acc, drn, *p[3]; + + v_quat32_from_quat64(&rt, rot); + p[0] = v_quat32_from_quat64(&spd, speed); + p[1] = v_quat32_from_quat64(&acc, accelerate); + p[2] = v_quat32_from_quat64(&drn, drag_normal); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_rot_real32(node_id, time_s, time_f, &rt, p[0], p[1], p[2], (real32) drag); + } + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_scale_real64(void *user, VNodeID node_id, real64 scale_x, real64 scale_y, real64 scale_z) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->transform.scale[0] = scale_x; + node->transform.scale[1] = scale_y; + node->transform.scale[2] = scale_z; + count = vs_get_subscript_count(node->trans_sub64); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub64, i); + verse_send_o_transform_scale_real64(node_id, scale_x, scale_y, scale_z); + } + count = vs_get_subscript_count(node->trans_sub32); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->trans_sub32, i); + verse_send_o_transform_scale_real32(node_id, (real32) scale_x, (real32) scale_y, (real32) scale_z); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_transform_subscribe(void *user, VNodeID node_id, VNRealFormat type) +{ + VSNodeObject *node; + uint32 time_s, time_f; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + verse_session_get_time(&time_s, &time_f); + if(type == VN_FORMAT_REAL32) + { + real32 tpos[3]; + VNQuat32 rot; + + vs_add_new_subscriptor(node->trans_sub32); + tpos[0] = node->transform.position[0]; + tpos[1] = node->transform.position[1]; + tpos[2] = node->transform.position[2]; + verse_send_o_transform_pos_real32(node_id, time_s, time_f, tpos, NULL, NULL, NULL, 0.0f); + v_quat32_from_quat64(&rot, &node->transform.rotation); + verse_send_o_transform_rot_real32(node_id, time_s, time_f, &rot, NULL, NULL, NULL, 0.0f); + verse_send_o_transform_scale_real32(node_id, (real32) node->transform.scale[0], (real32) node->transform.scale[1], (real32) node->transform.scale[2]); + } + else + { + vs_add_new_subscriptor(node->trans_sub64); + verse_send_o_transform_pos_real64(node_id, time_s, time_f, node->transform.position, NULL, NULL, NULL, 0); + verse_send_o_transform_rot_real64(node_id, time_s, time_f, &node->transform.rotation, NULL, NULL, NULL, 0); + verse_send_o_transform_scale_real64(node_id, node->transform.scale[0], node->transform.scale[1], node->transform.scale[2]); + } +} + +static void callback_send_o_transform_unsubscribe(void *user, VNodeID node_id, VNRealFormat type) +{ + VSNodeObject *node; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + if(type == VN_FORMAT_REAL32) + vs_remove_subscriptor(node->trans_sub32); + else + vs_remove_subscriptor(node->trans_sub64); +} + +static void callback_send_o_light_set(void *user, VNodeID node_id, real64 light_r, real64 light_g, real64 light_b) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + node->light[0] = light_r; + node->light[1] = light_g; + node->light[2] = light_b; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_light_set(node_id, light_r, light_g, light_b); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_link_set(void *user, VNodeID node_id, uint16 link_id, VNodeID link, const char *name, uint32 target_id) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + + if(node == NULL) + return; + + if(name[0] == 0) + return; + if(vs_get_node_head(link) == 0) + link = 0; + + if(link_id >= node->link_count || node->links[link_id].name[0] == 0) + { + for(link_id = 0; link_id < node->link_count && node->links[link_id].name[0] != 0; link_id++); + + if(link_id == node->link_count) + { + i = node->link_count; + node->link_count += 16; + node->links = realloc(node->links, (sizeof *node->links) * node->link_count); + for(; i < node->link_count; i++) + { + node->links[i].name[0] = 0; + node->links[i].dimensions = 0; + } + } + } + + node->links[link_id].link = link; + for(i = 0; i < 15 && name[i] != 0; i++) + node->links[link_id].name[i] = name[i]; + node->links[link_id].name[i] = 0; + node->links[link_id].target_id = target_id; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_link_set(node_id, link_id, link, name, target_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_link_destroy(void *user, VNodeID node_id, uint16 link_id) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + + if(link_id >= node->link_count || node->links[link_id].name[0] == 0) + return; + + node->links[link_id].name[0] = 0; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_link_destroy(node_id, link_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_group_create(void *user, VNodeID node_id, uint16 group_id, char *name) +{ + VSNodeObject *node; + unsigned int i, j, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + + for(i = 0; i < node->group_count; i++) + { + for(j = 0; node->groups[i].name[j] == name[j] && node->groups[i].name[j] != 0; j++); + if(node->groups[i].name[j] == name[j]) + return; + } + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0) + { + for(group_id = 0; group_id < node->group_count && node->groups[group_id].name[0] != 0; group_id++) + if(group_id == node->group_count) + { + node->groups = realloc(node->groups, sizeof(*node->groups) * (node->group_count + 16)); + for(i = node->group_count; i < node->group_count + 16u; i++) + { + node->groups[i].name[0] = 0; + node->groups[i].methods = NULL; + node->groups[i].method_count = 0; + } + node->group_count += 16; + } + node->groups[group_id].subscribers = vs_create_subscription_list(); + } + for(i = 0; i < 15 && name[i] != 0; i++) + node->groups[group_id].name[i] = name[i]; + node->groups[group_id].name[i] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_method_group_create(node_id, group_id, name); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_group_destroy(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0) + return; + node->groups[group_id].name[0] = 0; + for(i = 0; i < node->groups[group_id].method_count; i++) + { + if(node->groups[group_id].methods[i].name[0] != 0 && node->groups[group_id].methods[i].param_count > 0) + { + free(node->groups[group_id].methods[i].param_names); + free(node->groups[group_id].methods[i].param_types); + } + } + free(node->groups[group_id].methods); + node->groups[group_id].methods = NULL; + node->groups[group_id].method_count = 0; + vs_destroy_subscription_list(node->groups[group_id].subscribers); + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_method_group_destroy(node_id, group_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_group_subscribe(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeObject *node; + unsigned int i, j; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + if(group_id < node->group_count && node->groups[group_id].name[0] != 0) + vs_add_new_subscriptor(node->groups[group_id].subscribers); + for(i = 0; i < node->groups[group_id].method_count; i++) + { + if(node->groups[group_id].methods[i].name[0] != 0) + { + char *names[255]; + for(j = 0; j < node->groups[group_id].methods[i].param_count; j++) + names[j] = &node->groups[group_id].methods[i].param_names[j * 16]; + verse_send_o_method_create(node_id, group_id, i, node->groups[group_id].methods[i].name, node->groups[group_id].methods[i].param_count, node->groups[group_id].methods[i].param_types, (const char **) names); + } + } +} + +static void callback_send_o_method_group_unsubscribe(void *user, VNodeID node_id, uint16 group_id) +{ + VSNodeObject *node; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + if(group_id < node->group_count && node->groups[group_id].name[0] != 0) + vs_remove_subscriptor(node->groups[group_id].subscribers); +} + +static void callback_send_o_method_create(void *user, VNodeID node_id, uint16 group_id, uint16 method_id, char *name, uint8 param_count, VNOParamType *param_types, char * *param_names) +{ + VSNodeObject *node; + unsigned int i, j, count; + VSMethodGroup *group; + + node = (VSNodeObject *) vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0) + return; + group = &node->groups[group_id]; + for(i = 0; i < group->method_count; i++) + { + if(i != method_id) + { + for(j = 0; group->methods[i].name[j] == name[j] && group->methods[i].name[j] != 0; j++); + if(group->methods[i].name[j] == name[j]) + return; + } + } + if(method_id < group->method_count && group->methods[method_id].name[0] != 0) + { + for(i = 0; i < 16; i++) + group->methods[method_id].name[i] = name[i]; + if(group->methods[method_id].param_count != 0) + { + free(group->methods[method_id].param_names); + free(group->methods[method_id].param_types); + } + }else + { + for(method_id = 0; method_id < group->method_count && group->methods[method_id].name[0] != 0; method_id++); + if(method_id == group->method_count) + { + group->methods = realloc(group->methods, sizeof(*group->methods) * (group->method_count + 16)); + for(i = group->method_count; i < group->method_count + 16; i++) + group->methods[i].name[0] = 0; + group->method_count += 16; + } + } + for(i = 0; i < VN_O_METHOD_NAME_SIZE && name[i] != 0; i++) + group->methods[method_id].name[i] = name[i]; + group->methods[method_id].name[i] = '\0'; + group->methods[method_id].param_count = param_count; + if(param_count > 0) + { + group->methods[method_id].param_types = malloc((sizeof *group->methods[method_id].param_types) * param_count); + group->methods[method_id].param_names = malloc((sizeof *group->methods[method_id].param_names) * param_count * 16); + } + for(i = 0; i < param_count; i++) + { + group->methods[method_id].param_types[i] = param_types[i]; + for(j = 0; j < 15 && param_names[i][j] != 0; j++) + group->methods[method_id].param_names[i * 16 + j] = param_names[i][j]; + group->methods[method_id].param_names[i * 16 + j] = 0; + } + count = vs_get_subscript_count(node->groups[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->groups[group_id].subscribers, i); + verse_send_o_method_create(node_id, group_id, method_id, name, param_count, param_types, (const char **) param_names); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_destroy(void *user, VNodeID node_id, uint16 group_id, uint16 method_id) +{ + VSNodeObject *node; + unsigned int i, count; + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0 || method_id >= node->groups[group_id].method_count || node->groups[group_id].methods[method_id].name[0] == 0) + return; + + node->groups[group_id].methods[method_id].name[0] = 0; + if(node->groups[group_id].methods[method_id].param_count != 0) + { + free(node->groups[group_id].methods[method_id].param_names); + free(node->groups[group_id].methods[method_id].param_types); + } + count = vs_get_subscript_count(node->groups[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->groups[group_id].subscribers, i); + verse_send_o_method_destroy(node_id, group_id, method_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_method_call(void *user, VNodeID node_id, uint16 group_id, uint16 method_id, VNodeID sender, void *params) +{ + VNOParam unpacked_params[255]; + void *data; + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || vs_get_node(node_id, V_NT_OBJECT) == NULL) + return; + + if(group_id >= node->group_count || node->groups[group_id].name[0] == 0 || method_id >= node->groups[group_id].method_count || node->groups[group_id].methods[method_id].name[0] == 0) + return; + if(!verse_method_call_unpack(params, node->groups[group_id].methods[method_id].param_count, node->groups[group_id].methods[method_id].param_types, unpacked_params)) + return; + sender = vs_get_avatar(); + count = vs_get_subscript_count(node->groups[group_id].subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->groups[group_id].subscribers, i); + data = verse_method_call_pack(node->groups[group_id].methods[method_id].param_count, node->groups[group_id].methods[method_id].param_types, unpacked_params); + if(data != NULL) + verse_send_o_method_call(node_id, group_id, method_id, sender, data); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_anim_run(void *user, VNodeID node_id, uint16 link_id, uint32 time_s, uint32 time_f, uint8 dimensions, real64 *pos, + real64 *speed, real64 *accel, real64 *scale, real64 *scale_speed) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL) + return; + if(link_id >= node->link_count || node->links[link_id].name[0] == 0) + return; + if(NULL == vs_get_node(node->links[link_id].link, V_NT_CURVE)) + return; + node->links[link_id].time_s = time_s; + node->links[link_id].time_f = time_f; + node->links[link_id].dimensions = dimensions; + for(i = 0; i < dimensions && i < 4; i++) + { + node->links[link_id].pos[i] = pos[i]; + node->links[link_id].speed[i] = speed[i]; + node->links[link_id].accel[i] = accel[i]; + node->links[link_id].scale[i] = scale[i]; + node->links[link_id].scale_speed[i] = scale_speed[i]; + } + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_anim_run(node_id, link_id, time_s, time_f, dimensions, pos, speed, accel, scale, scale_speed); + } + vs_reset_subscript_session(); +} + +static void callback_send_o_hide(void *user, VNodeID node_id, uint8 hidden) +{ + VSNodeObject *node; + unsigned int i, count; + + node = (VSNodeObject *)vs_get_node(node_id, V_NT_OBJECT); + if(node == NULL || hidden == node->hidden) + return; + node->hidden = hidden; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_o_hide(node_id, hidden); + } + vs_reset_subscript_session(); +} + +void vs_o_callback_init(void) +{ + + verse_callback_set(verse_send_o_transform_pos_real32, callback_send_o_transform_pos_real32, NULL); + verse_callback_set(verse_send_o_transform_rot_real32, callback_send_o_transform_rot_real32, NULL); + verse_callback_set(verse_send_o_transform_scale_real32, callback_send_o_transform_scale_real32, NULL); + verse_callback_set(verse_send_o_transform_pos_real64, callback_send_o_transform_pos_real64, NULL); + verse_callback_set(verse_send_o_transform_rot_real64, callback_send_o_transform_rot_real64, NULL); + verse_callback_set(verse_send_o_transform_scale_real64, callback_send_o_transform_scale_real64, NULL); + verse_callback_set(verse_send_o_transform_subscribe, callback_send_o_transform_subscribe, NULL); + verse_callback_set(verse_send_o_transform_unsubscribe, callback_send_o_transform_unsubscribe, NULL); + verse_callback_set(verse_send_o_link_set, callback_send_o_link_set, NULL); + verse_callback_set(verse_send_o_light_set, callback_send_o_light_set, NULL); + verse_callback_set(verse_send_o_link_set, callback_send_o_link_set, NULL); + verse_callback_set(verse_send_o_link_destroy, callback_send_o_link_destroy, NULL); + verse_callback_set(verse_send_o_method_group_create, callback_send_o_method_group_create, NULL); + verse_callback_set(verse_send_o_method_group_destroy, callback_send_o_method_group_destroy, NULL); + verse_callback_set(verse_send_o_method_group_subscribe, callback_send_o_method_group_subscribe, NULL); + verse_callback_set(verse_send_o_method_group_unsubscribe, callback_send_o_method_group_unsubscribe, NULL); + verse_callback_set(verse_send_o_method_create, callback_send_o_method_create, NULL); + verse_callback_set(verse_send_o_method_destroy, callback_send_o_method_destroy, NULL); + verse_callback_set(verse_send_o_method_call, callback_send_o_method_call, NULL); + verse_callback_set(verse_send_o_anim_run, callback_send_o_anim_run, NULL); + verse_callback_set(verse_send_o_hide, callback_send_o_hide, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_particle.c b/extern/verse/dist/vs_node_particle.c new file mode 100644 index 00000000000..8c7b1ce3c82 --- /dev/null +++ b/extern/verse/dist/vs_node_particle.c @@ -0,0 +1,52 @@ +/* +** +*/ + +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +/* +typedef struct { + VSNodeHead head; +} VSNodeObject; + +VSNodeObject *vs_o_create_node(unsigned int owner) +{ + VSNodeObject *node; + node = malloc(sizeof *node); + create_node_head(&node->head, name, owner); + vs_add_new_node(&node->head, V_NT_OBJECT); + return node; +} + +void vs_o_destroy_node(VSNodeObject *node) +{ + destroy_node_head(&node->head); + free(node); +} + +void vs_o_subscribe(VSNodeObject *node) +{ +} + +static void callback_send_o_unsubscribe(void *user, VNodeID node_id) +{ + VSNodeObject *node; + node = (VSNodeObject *)vs_get_node(node_id); + if(node == NULL) + return; + vs_remove_subscriptor(node->head.subscribers); +} + +void vs_o_callback_init(void) +{ +} +*/ +#endif diff --git a/extern/verse/dist/vs_node_storage.c b/extern/verse/dist/vs_node_storage.c new file mode 100644 index 00000000000..480ceb1f900 --- /dev/null +++ b/extern/verse/dist/vs_node_storage.c @@ -0,0 +1,245 @@ +/* +** +*/ + +#include +#include +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +#define VS_NODE_STORAGE_CHUNK_SIZE 16 + +static struct { + VSNodeHead **nodes; + unsigned int node_length; + unsigned int node_allocated; + VSSubscriptionList *list[V_NT_NUM_TYPES]; +} VSNodeStorage; + +extern void callback_send_tag_group_create(void *user, VNodeID node_id, uint16 group_id, const char *name); + +void vs_init_node_storage(void) +{ + unsigned int i; + VSNodeStorage.nodes = malloc((sizeof *VSNodeStorage.nodes) * VS_NODE_STORAGE_CHUNK_SIZE); + VSNodeStorage.nodes[0] = NULL; + VSNodeStorage.node_length = 0; + VSNodeStorage.node_allocated = VS_NODE_STORAGE_CHUNK_SIZE; + for(i = 0; i < V_NT_NUM_TYPES; i++) + VSNodeStorage.list[i] = vs_create_subscription_list(); +} + +unsigned int vs_add_new_node(VSNodeHead *node, VNodeType type) +{ + unsigned int i, j; + for(i = 0; i < VSNodeStorage.node_length && VSNodeStorage.nodes[i] != NULL; i++); + if(i >= VSNodeStorage.node_allocated) + { + j = VSNodeStorage.node_allocated; + VSNodeStorage.node_allocated += VS_NODE_STORAGE_CHUNK_SIZE; + VSNodeStorage.nodes = realloc(VSNodeStorage.nodes, (sizeof *VSNodeStorage.nodes) * VSNodeStorage.node_allocated); + while(j < VSNodeStorage.node_allocated) + VSNodeStorage.nodes[j++] = NULL; + } + VSNodeStorage.nodes[i] = node; + if(i >= VSNodeStorage.node_length) + VSNodeStorage.node_length = i + 1; + node->id = i; + node->type = type; + + return node->id; +} + +VSNodeHead *vs_get_node(unsigned int node_id, VNodeType type) +{ + if(VSNodeStorage.node_length > node_id) + { + VSNodeHead *node = VSNodeStorage.nodes[node_id]; + + if(node != NULL && node->type == type) + return node; + } + return NULL; +} + +VSNodeHead *vs_get_node_head(unsigned int node_id) +{ + if(VSNodeStorage.node_length > node_id) + return VSNodeStorage.nodes[node_id]; + return NULL; +} + +extern VSNodeHead *vs_o_create_node(unsigned int owner); +extern VSNodeHead *vs_g_create_node(unsigned int owner); +extern VSNodeHead *vs_m_create_node(unsigned int owner); +extern VSNodeHead *vs_b_create_node(unsigned int owner); +extern VSNodeHead *vs_t_create_node(unsigned int owner); +extern VSNodeHead *vs_c_create_node(unsigned int owner); +extern VSNodeHead *vs_p_create_node(unsigned int owner); +extern VSNodeHead *vs_a_create_node(unsigned int owner); + +extern void vs_o_destroy_node(VSNodeHead *node); +extern void vs_g_destroy_node(VSNodeHead *node); +extern void vs_m_destroy_node(VSNodeHead *node); +extern void vs_b_destroy_node(VSNodeHead *node); +extern void vs_t_destroy_node(VSNodeHead *node); +extern void vs_c_destroy_node(VSNodeHead *node); +extern void vs_p_destroy_node(VSNodeHead *node); +extern void vs_a_destroy_node(VSNodeHead *node); + + +VNodeID vs_node_create(VNodeID owner_id, unsigned int type) +{ + unsigned int count, i; + VSNodeHead *node; + VNodeID node_id; + + printf("vs_node_create(%u, %u)\n", owner_id, type); + switch(type) + { + case V_NT_OBJECT : + node = vs_o_create_node(owner_id); + break; + case V_NT_GEOMETRY : + node = vs_g_create_node(owner_id); + break; + case V_NT_MATERIAL : + node = vs_m_create_node(owner_id); + break; + case V_NT_BITMAP : + node = vs_b_create_node(owner_id); + break; + case V_NT_TEXT : + node = vs_t_create_node(owner_id); + break; + case V_NT_CURVE : + node = vs_c_create_node(owner_id); + break; + case V_NT_AUDIO : + node = vs_a_create_node(owner_id); + break; + default: + fprintf(stderr, "Can't create node of unknown type %u\n", type); + return 0U; + } + node_id = node->id; + + count = vs_get_subscript_count(VSNodeStorage.list[type]); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(VSNodeStorage.list[type], i); + if(owner_id != verse_session_get_avatar()) + verse_send_node_create(node_id, type, VN_OWNER_OTHER); + else + verse_send_node_create(node_id, type, VN_OWNER_MINE); + } + if(count != 0) + vs_reset_subscript_session(); + return node_id; +} + +/* Initialize an object node into being an avatar. */ +void vs_avatar_init(VNodeID id, const char *name) +{ + callback_send_tag_group_create(NULL, id, (short) ~0u, "avatar"); + /* FIXME: Populate the group, too. */ +} + +void vs_reset_owner(VNodeID owner_id) +{ + unsigned int i; + + for(i = 0; i < VSNodeStorage.node_length; i++) + if(VSNodeStorage.nodes[i] != NULL) + if(VSNodeStorage.nodes[i]->owner == owner_id) + VSNodeStorage.nodes[i]->owner = ~0; +} + +static void callback_send_node_create(void *user_data, VNodeID node_id, uint8 type, VNodeOwner owner_id) +{ + vs_node_create(vs_get_avatar(), type); +} + +void callback_send_node_destroy(void *user_data, VNodeID node_id) +{ + unsigned int count, i; + VSNodeHead *node; + VNodeType type; + node = vs_get_node_head(node_id); + if(node == NULL) + return; + VSNodeStorage.nodes[node_id] = NULL; + type = node->type; + switch(type) + { + case V_NT_OBJECT : + vs_o_destroy_node(node); + break; + case V_NT_GEOMETRY : + vs_g_destroy_node(node); + break; + case V_NT_MATERIAL : + vs_m_destroy_node(node); + break; + case V_NT_BITMAP : + vs_b_destroy_node(node); + break; + case V_NT_TEXT : + vs_t_destroy_node(node); + break; + case V_NT_CURVE : + vs_c_destroy_node(node); + break; + case V_NT_AUDIO : + vs_c_destroy_node(node); + break; + default: + fprintf(stderr, __FILE__ " Can't handle node_destroy for type %d--not implemented", type); + return; + } + count = vs_get_subscript_count(VSNodeStorage.list[type]); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(VSNodeStorage.list[type], i); + verse_send_node_destroy(node_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_node_index_subscribe(void *user_data, uint32 mask) +{ + unsigned int i, j, pow = 1; + + for(i = 0; i < V_NT_NUM_TYPES; i++, pow <<= 1) + { + if((mask & pow) != 0) + { + for(j = 0; j < VSNodeStorage.node_length; j++) + { + if(VSNodeStorage.nodes[j] != NULL && VSNodeStorage.nodes[j]->type == (VNodeType)i) + { + if(VSNodeStorage.nodes[j]->owner == verse_session_get_avatar()) + verse_send_node_create(VSNodeStorage.nodes[j]->id, i, VN_OWNER_MINE); + else + verse_send_node_create(VSNodeStorage.nodes[j]->id, i, VN_OWNER_OTHER); + } + } + vs_add_new_subscriptor(VSNodeStorage.list[i]); + } + else + vs_remove_subscriptor(VSNodeStorage.list[i]); + } +} + +void init_callback_node_storage(void) +{ + verse_callback_set(verse_send_node_index_subscribe, callback_send_node_index_subscribe, NULL); + verse_callback_set(verse_send_node_create, callback_send_node_create, NULL); + verse_callback_set(verse_send_node_destroy, callback_send_node_destroy, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_node_text.c b/extern/verse/dist/vs_node_text.c new file mode 100644 index 00000000000..ae7c3c737c3 --- /dev/null +++ b/extern/verse/dist/vs_node_text.c @@ -0,0 +1,274 @@ +/* +** +*/ + +#include +#include +#include + +#include "v_cmd_gen.h" + +#if !defined V_GENERATE_FUNC_MODE + +#include "verse.h" +#include "vs_server.h" + +#define VS_TEXT_CHUNK_SIZE 4096 + +typedef struct { + char name[16]; + char *text; + size_t length; + size_t allocated; + VSSubscriptionList *subscribers; +} VSTextBuffer; + +typedef struct { + VSNodeHead head; + char language[512]; + VSTextBuffer *buffer; + unsigned int buffer_count; +} VSNodeText; + +VSNodeText * vs_t_create_node(unsigned int owner) +{ + VSNodeText *node; + char name[48]; + unsigned int i; + node = malloc(sizeof *node); + vs_add_new_node(&node->head, V_NT_TEXT); + sprintf(name, "Text_Node_%u", node->head.id); + create_node_head(&node->head, name, owner); + node->language[0] = 0; + node->buffer_count = 16; + node->buffer = malloc((sizeof *node->buffer) * node->buffer_count); + for(i = 0; i < node->buffer_count; i++) + node->buffer[i].name[0] = 0; + + return node; +} + +void vs_t_destroy_node(VSNodeText *node) +{ + unsigned int i; + destroy_node_head(&node->head); + for(i = 0; i < node->buffer_count; i++) + { + if(node->buffer[i].name[0] != 0) + { + free(node->buffer[i].text); + vs_destroy_subscription_list(node->buffer[i].subscribers); + } + } + free(node->buffer); + free(node); +} + +void vs_t_subscribe(VSNodeText *node) +{ + unsigned int i; + verse_send_t_language_set(node->head.id, node->language); + for(i = 0; i < node->buffer_count; i++) + if(node->buffer[i].name[0] != 0) + verse_send_t_buffer_create(node->head.id, i, node->buffer[i].name); +} + +void vs_t_unsubscribe(VSNodeText *node) +{ + unsigned int i; + for(i = 0; i < node->buffer_count; i++) + if(node->buffer[i].name[0] != 0) + vs_remove_subscriptor(node->buffer[i].subscribers); +} + +static void callback_send_t_language_set(void *user, VNodeID node_id, char *language) +{ + VSNodeText *node; + unsigned int i, count; + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + for(i = 0; i < 511 && language[i]; i++) + node->language[i] = language[i]; + node->language[i] = 0; + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_t_language_set(node_id, language); + } + vs_reset_subscript_session(); + +} + +static void callback_send_t_buffer_create(void *user, VNodeID node_id, VBufferID buffer_id, const char *name) +{ + VSNodeText *node; + unsigned int i, count; + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] != 0) + { + for(buffer_id = 0; buffer_id < node->buffer_count && node->buffer[buffer_id].name[0] != 0; buffer_id++) + ; + if(buffer_id == node->buffer_count) + { + node->buffer = realloc(node->buffer, (sizeof *node->buffer) * node->buffer_count); + for(i = node->buffer_count; i < node->buffer_count + 16; i++) + node->buffer[i].name[0] = 0; + node->buffer_count = i; + } + } + + if(node->buffer[buffer_id].name[0] == 0) + { + node->buffer[buffer_id].allocated = VS_TEXT_CHUNK_SIZE; + node->buffer[buffer_id].text = malloc(node->buffer[buffer_id].allocated); + node->buffer[buffer_id].length = 0; + node->buffer[buffer_id].subscribers = vs_create_subscription_list(); + } + for(i = 0; i < 15 && name[i] != 0; i++) + node->buffer[buffer_id].name[i] = name[i]; + node->buffer[buffer_id].name[i] = 0; + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_t_buffer_create(node_id, buffer_id, name); + } + vs_reset_subscript_session(); +} + +void callback_send_t_buffer_destroy(void *user, VNodeID node_id, VBufferID buffer_id) +{ + VSNodeText *node; + unsigned int i, count; + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] == 0) + return; + + node->buffer[buffer_id].name[0] = 0; + free(node->buffer[buffer_id].text); + vs_destroy_subscription_list(node->buffer[buffer_id].subscribers); + + count = vs_get_subscript_count(node->head.subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(node->head.subscribers, i); + verse_send_t_buffer_destroy(node_id, buffer_id); + } + vs_reset_subscript_session(); +} + +static void callback_send_t_buffer_subscribe(void *user, VNodeID node_id, VBufferID buffer_id) +{ + VSNodeText *node; + unsigned int i; + + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] == 0) + return; + if(vs_add_new_subscriptor(node->buffer[buffer_id].subscribers) == 0) + return; + for(i = 0; i < node->buffer[buffer_id].length; i += VN_T_MAX_TEXT_CMD_SIZE) + { + if(i + VN_T_MAX_TEXT_CMD_SIZE > node->buffer[buffer_id].length) + verse_send_t_text_set(node_id, buffer_id, i, node->buffer[buffer_id].length - i, &node->buffer[buffer_id].text[i]); + else + verse_send_t_text_set(node_id, buffer_id, i, VN_T_MAX_TEXT_CMD_SIZE, &node->buffer[buffer_id].text[i]); + } +} + +static void callback_send_t_buffer_unsubscribe(void *user, VNodeID node_id, VBufferID buffer_id) +{ + VSNodeText *node; + node = (VSNodeText *)vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] == 0) + return; + vs_remove_subscriptor(node->buffer[buffer_id].subscribers); +} + +static void callback_send_t_text_set(void *user, VNodeID node_id, VBufferID buffer_id, uint32 pos, uint32 length, const char *text) +{ + VSNodeText *node; + VSTextBuffer *tb; + unsigned int i, count, text_length; + char *buf; + + node = (VSNodeText *) vs_get_node(node_id, V_NT_TEXT); + if(node == NULL) + return; + if(buffer_id >= node->buffer_count || node->buffer[buffer_id].name[0] == 0) + return; + tb = &node->buffer[buffer_id]; + + text_length = strlen(text); + + /* Clamp position and length of deleted region. */ + if(pos > tb->length) + pos = tb->length; + if(pos + length > tb->length) + length = tb->length - pos; + + buf = tb->text; + + if(tb->length + text_length - length > tb->allocated) + { + buf = realloc(buf, tb->length + text_length - length + VS_TEXT_CHUNK_SIZE); + tb->allocated = tb->length + text_length - length + VS_TEXT_CHUNK_SIZE; + } + + if(text_length < length) /* Insert smaller than delete? */ + { + memmove(buf + pos + text_length, buf + pos + length, tb->length - (pos + length)); + memcpy(buf + pos, text, text_length); + } + else /* Insert is larger than delete. */ + { + memmove(buf + pos + text_length, buf + pos + length, tb->length - pos); + memcpy(buf + pos, text, text_length); + } + + tb->length += (int) text_length - length; + buf[tb->length] = '\0'; + + /* Buffer very much larger than content? Then shrink it. */ + if(tb->allocated > VS_TEXT_CHUNK_SIZE * 8 && tb->allocated * 2 > tb->length) + { + buf = realloc(buf, tb->length + VS_TEXT_CHUNK_SIZE); + tb->allocated = tb->length + VS_TEXT_CHUNK_SIZE; + } + + tb->text = buf; + + count = vs_get_subscript_count(tb->subscribers); + for(i = 0; i < count; i++) + { + vs_set_subscript_session(tb->subscribers, i); + verse_send_t_text_set(node_id, buffer_id, pos, length, text); + } + vs_reset_subscript_session(); +} + + +void vs_t_callback_init(void) +{ + verse_callback_set(verse_send_t_language_set, callback_send_t_language_set, NULL); + verse_callback_set(verse_send_t_buffer_create, callback_send_t_buffer_create, NULL); + verse_callback_set(verse_send_t_buffer_destroy, callback_send_t_buffer_destroy, NULL); + verse_callback_set(verse_send_t_buffer_subscribe, callback_send_t_buffer_subscribe, NULL); + verse_callback_set(verse_send_t_buffer_unsubscribe, callback_send_t_buffer_unsubscribe, NULL); + verse_callback_set(verse_send_t_text_set, callback_send_t_text_set, NULL); +} + +#endif diff --git a/extern/verse/dist/vs_server.h b/extern/verse/dist/vs_server.h new file mode 100644 index 00000000000..76e1b482eb9 --- /dev/null +++ b/extern/verse/dist/vs_server.h @@ -0,0 +1,62 @@ +/* +** +*/ + +#include + +extern void vs_init_connection_storage(void); +extern void vs_add_new_connection(VSession session, const char *name, const char *pass, VNodeID node_id); +extern void vs_remove_connection(void); +extern void vs_set_next_session(void); + +typedef void VSSubscriptionList; + +extern VSSubscriptionList * vs_create_subscription_list(void); +extern void vs_destroy_subscription_list(VSSubscriptionList *list); +extern int vs_add_new_subscriptor(VSSubscriptionList *list); +extern void vs_remove_subscriptor(VSSubscriptionList *list); +extern unsigned int vs_get_subscript_count(const VSSubscriptionList *list); +extern void vs_set_subscript_session(VSSubscriptionList *list, unsigned int session); +extern void vs_reset_subscript_session(void); +extern uint32 vs_get_avatar(void); +extern VSession vs_get_session(void); +extern const char * vs_get_user_name(void); +extern const char * vs_get_user_pass(void); + + +typedef struct { + VNodeID id; + VNodeType type; + VNodeID owner; + char *name; + void *tag_groups; + uint16 group_count; + VSSubscriptionList *subscribers; +} VSNodeHead; + +extern void vs_init_node_storage(void); +extern uint32 vs_add_new_node(VSNodeHead *node, VNodeType type); +extern VSNodeHead * vs_get_node(unsigned int node_id, VNodeType type); +extern VSNodeHead * vs_get_node_head(unsigned int node_id); + +extern void create_node_head(VSNodeHead *node, const char *name, unsigned int owner); +extern void destroy_node_head(VSNodeHead *node); +extern void vs_send_node_head(VSNodeHead *node); + +extern void vs_h_callback_init(void); /* "Head", not an actual node type. */ +extern void vs_o_callback_init(void); +extern void vs_g_callback_init(void); +extern void vs_m_callback_init(void); +extern void vs_b_callback_init(void); +extern void vs_t_callback_init(void); +extern void vs_c_callback_init(void); +extern void vs_a_callback_init(void); +extern void init_callback_node_storage(void); + +extern void vs_master_set_enabled(boolean enabled); +extern void vs_master_set_address(const char *address); +extern const char * vs_master_get_address(void); +extern void vs_master_set_desc(const char *desc); +extern void vs_master_set_tags(const char *tags); +extern void vs_master_update(void); +extern void vs_master_handle_describe(const char *address, const char *message); diff --git a/extern/verse/make/msvc_7_0/libverse.vcproj b/extern/verse/make/msvc_7_0/libverse.vcproj new file mode 100644 index 00000000000..1c9bfbfce33 --- /dev/null +++ b/extern/verse/make/msvc_7_0/libverse.vcproj @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/verse/make/msvc_7_0/verse.vcproj b/extern/verse/make/msvc_7_0/verse.vcproj new file mode 100644 index 00000000000..563e33e7be9 --- /dev/null +++ b/extern/verse/make/msvc_7_0/verse.vcproj @@ -0,0 +1,481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt new file mode 100644 index 00000000000..aa5b1a8531c --- /dev/null +++ b/intern/CMakeLists.txt @@ -0,0 +1,36 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SUBDIRS(SoundSystem string ghost guardedalloc bmfont moto container memutil decimation iksolver boolop opennl) + +IF(WITH_ELBEEM) + SUBDIRS(elbeem) +ENDIF(WITH_ELBEEM) + +SUBDIRS(bsp) diff --git a/intern/Makefile b/intern/Makefile new file mode 100644 index 00000000000..7eaabd5b6bb --- /dev/null +++ b/intern/Makefile @@ -0,0 +1,50 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Bounces make to subdirectories. Also installs after succesful all target. + +SOURCEDIR = intern + +# include nan_subdirs.mk + +ALLDIRS = string ghost guardedalloc bmfont moto container memutil +ALLDIRS += decimation iksolver bsp SoundSystem opennl elbeem boolop + +all:: + @for i in $(ALLDIRS); do \ + echo "====> $(MAKE) $@ in $(SOURCEDIR)/$$i" ;\ + $(MAKE) -C $$i install || exit 1; \ + done +clean test debug:: + @for i in $(ALLDIRS); do \ + echo "====> $(MAKE) $@ in $(SOURCEDIR)/$$i" ;\ + $(MAKE) -C $$i $@ || exit 1; \ + done + diff --git a/intern/SConscript b/intern/SConscript new file mode 100644 index 00000000000..f6092b7bd02 --- /dev/null +++ b/intern/SConscript @@ -0,0 +1,29 @@ +#!/usr/bin/python +Import ('env') + +SConscript(['SoundSystem/SConscript', + 'string/SConscript', + 'ghost/SConscript', + 'guardedalloc/SConscript', + 'bmfont/SConscript', + 'moto/SConscript', + 'container/SConscript', + 'memutil/SConscript/', + 'decimation/SConscript', + 'iksolver/SConscript', + 'boolop/SConscript', + 'opennl/SConscript']) + +# NEW_CSG was intended for intern/csg, but +# getting it to compile is difficult +# intern/bsp has been used anyway, so +# perhaps get rid of intern/csg? +NEW_CSG='false' + +if env['BF_NO_ELBEEM'] == 0: + SConscript(['elbeem/SConscript']) + +if NEW_CSG=='false': + SConscript(['bsp/SConscript']) +else: + SConscript(['csg/SConscript']) diff --git a/intern/SoundSystem/CMakeLists.txt b/intern/SoundSystem/CMakeLists.txt new file mode 100644 index 00000000000..428b8db01ee --- /dev/null +++ b/intern/SoundSystem/CMakeLists.txt @@ -0,0 +1,45 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . intern ../moto/include ../string dummy openal sdl) + +IF(WITH_OPENAL) + FILE(GLOB SRC dummy/*.cpp intern/*.cpp openal/*.cpp sdl/*.cpp) + INCLUDE_DIRECTORIES(${OPENAL_INC} ${SDL_INC}) + STRING(REGEX MATCH ".*ramework.*" FRAMEWORK ${OPENAL_INC}) + IF(FRAMEWORK) + ADD_DEFINITIONS(-DAPPLE_FRAMEWORK_FIX) + ENDIF(FRAMEWORK) +ELSE(WITH_OPENAL) + FILE(GLOB SRC dummy/*.cpp intern/*.cpp) + ADD_DEFINITIONS(-DNO_SOUND) +ENDIF(WITH_OPENAL) + +BLENDERLIB(bf_soundsystem "${SRC}" "${INC}") +#, libtype=['core','player'], priority = [20,140] ) diff --git a/intern/SoundSystem/Makefile b/intern/SoundSystem/Makefile new file mode 100644 index 00000000000..757301e4a35 --- /dev/null +++ b/intern/SoundSystem/Makefile @@ -0,0 +1,72 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +include nan_definitions.mk + +LIBNAME = SoundSystem +SOURCEDIR = intern/SoundSystem +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +DIRS += dummy + +ifneq ($(NAN_NO_OPENAL),true) + ifeq ($(OS),windows) + DIRS += fmod + DIRS += openal sdl + endif + ifeq ($(OS),darwin) + DIRS += openal + endif + ifeq ($(OS),$(findstring $(OS), "linux freebsd solaris")) + DIRS += openal sdl + endif +else + export CPPFLAGS += -DNO_SOUND +endif + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_SOUNDSYSTEM) ] || mkdir $(NAN_SOUNDSYSTEM) + @[ -d $(NAN_SOUNDSYSTEM)/include ] || mkdir $(NAN_SOUNDSYSTEM)/include + @[ -d $(NAN_SOUNDSYSTEM)/lib ] || mkdir $(NAN_SOUNDSYSTEM)/lib + @[ -d $(NAN_SOUNDSYSTEM)/lib/debug ] || mkdir $(NAN_SOUNDSYSTEM)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libSoundSystem.a $(NAN_SOUNDSYSTEM)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libSoundSystem.a $(NAN_SOUNDSYSTEM)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_SOUNDSYSTEM)/lib/libSoundSystem.a + ranlib $(NAN_SOUNDSYSTEM)/lib/debug/libSoundSystem.a +endif + @../tools/cpifdiff.sh *.h $(NAN_SOUNDSYSTEM)/include/ + + diff --git a/intern/SoundSystem/SConscript b/intern/SoundSystem/SConscript new file mode 100644 index 00000000000..a9c1110c09a --- /dev/null +++ b/intern/SoundSystem/SConscript @@ -0,0 +1,16 @@ +#!/usr/bin/python + +Import ('env') + +sources = env.Glob('dummy/*.cpp') + env.Glob('intern/*.cpp') + +incs = '. intern ../moto/include ../string dummy openal sdl' +defs = '' +if env['WITH_BF_OPENAL']: + sources += env.Glob('openal/*.cpp') + env.Glob('sdl/*.cpp') + incs += ' ' + env['BF_OPENAL_INC'] + incs += ' ' + env['BF_SDL_INC'] +else: + defs = 'NO_SOUND' + +env.BlenderLib ('bf_soundsystem', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [20,140] ) diff --git a/intern/SoundSystem/SND_C-api.h b/intern/SoundSystem/SND_C-api.h new file mode 100644 index 00000000000..03470f7e998 --- /dev/null +++ b/intern/SoundSystem/SND_C-api.h @@ -0,0 +1,357 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_BLENDER_H +#define SND_BLENDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SoundDefines.h" + +#define SND_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +SND_DECLARE_HANDLE(SND_AudioDeviceInterfaceHandle); +SND_DECLARE_HANDLE(SND_SceneHandle); +SND_DECLARE_HANDLE(SND_ObjectHandle); +SND_DECLARE_HANDLE(SND_ListenerHandle); + +/** + * set the specified type + */ +extern void SND_SetDeviceType(int device_type); + +/** + * get an audiodevice + */ +extern SND_AudioDeviceInterfaceHandle SND_GetAudioDevice(void); + +/** + * and let go of it + */ +extern void SND_ReleaseDevice(void); + +/** + * check if playback is desired + */ +extern int SND_IsPlaybackWanted(SND_SceneHandle scene); + +/** + * add memlocation to cache + */ +extern int SND_AddSample(SND_SceneHandle scene, + const char* filename, + void* memlocation, + int size); + +/** + * remove all samples + */ +extern void SND_RemoveAllSamples(SND_SceneHandle scene); + +/** + * forces the object to check its buffer, and fix it if it's wrong + */ +extern int SND_CheckBuffer(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Creates a scene, initializes it and returns a handle to that scene. + * + * @param audiodevice: handle to the audiodevice. + */ +extern SND_SceneHandle SND_CreateScene(SND_AudioDeviceInterfaceHandle audiodevice); + +/** + * Stops all sounds, suspends the scene (so all resources will be freed) and deletes the scene. + * + * @param scene: handle to the soundscene. + */ +extern void SND_DeleteScene(SND_SceneHandle scene); + +/** + * Adds a soundobject to the scene, gets the buffer the sample is loaded into. + * + * @param scene: handle to the soundscene. + * @param object: handle to soundobject. + */ +extern void SND_AddSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Removes a soundobject from the scene. + * + * @param scene: handle to the soundscene. + * @param object: handle to soundobject. + */ +extern void SND_RemoveSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Removes all soundobjects from the scene. + * + * @param scene: handle to the soundscene. + */ +extern void SND_RemoveAllSounds(SND_SceneHandle scene); + +/** + * Stopss all soundobjects in the scene. + * + * @param scene: handle to the soundscene. + */ +extern void SND_StopAllSounds(SND_SceneHandle scene); + +/** + * Updates the listener, checks the status of all soundobjects, builds a list of all active + * objects, updates the active objects. + * + * @param audiodevice: handle to the audiodevice. + * @param scene: handle to the soundscene. + */ +extern void SND_Proceed(SND_AudioDeviceInterfaceHandle audiodevice, SND_SceneHandle scene); + +/** + * Returns a handle to the listener. + * + * @param scene: handle to the soundscene. + */ +extern SND_ListenerHandle SND_GetListener(SND_SceneHandle scene); + +/** + * Sets the gain of the listener. + * + * @param scene: handle to the soundscene. + * @param gain: factor the gain gets multiplied with. + */ +extern void SND_SetListenerGain(SND_SceneHandle scene, double gain); + +/** + * Sets a scaling to exaggerate or deemphasize the Doppler (pitch) shift resulting from the + * calculation. + * @attention $f' = dopplerfactor * f * frac{dopplervelocity - listener_velocity}{dopplervelocity + object_velocity}$ + * @attention f: frequency in sample (soundobject) + * @attention f': effective Doppler shifted frequency + * + * @param object: handle to soundobject. + * @param dopplerfactor: the dopplerfactor. + */ +extern void SND_SetDopplerFactor(SND_SceneHandle scene, double dopplerfactor); + +/** + * Sets the value of the propagation speed relative to which the source velocities are interpreted. + * @attention $f' = dopplerfactor * f * frac{dopplervelocity - listener_velocity}{dopplervelocity + object_velocity}$ + * @attention f: frequency in sample (soundobject) + * @attention f': effective Doppler shifted frequency + * + * @param object: handle to soundobject. + * @param dopplervelocity: the dopplervelocity. + */ +extern void SND_SetDopplerVelocity(SND_SceneHandle scene, double dopplervelocity); + +/** + * Creates a new soundobject and returns a handle to it. + */ +extern SND_ObjectHandle SND_CreateSound(void); + +/** + * Deletes a soundobject. + * + * @param object: handle to soundobject. + */ +extern void SND_DeleteSound(SND_ObjectHandle object); + +/** + * Sets a soundobject to SND_MUST_PLAY, so with the next proceed it will be updated and played. + * + * @param object: handle to soundobject. + */ +extern void SND_StartSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Sets a soundobject to SND_MUST_STOP, so with the next proceed it will be stopped. + * + * @param object: handle to soundobject. + */ +extern void SND_StopSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Sets a soundobject to SND_MUST_PAUSE, so with the next proceed it will be paused. + * + * @param object: handle to soundobject. + */ +extern void SND_PauseSound(SND_SceneHandle scene, SND_ObjectHandle object); + +/** + * Sets the name of the sample to reference the soundobject to it. + * + * @param object: handle to soundobject. + * @param samplename: the name of the sample + */ +extern void SND_SetSampleName(SND_ObjectHandle object, char* samplename); + +/** + * Sets the gain of a soundobject. + * + * @param object: handle to soundobject. + * @param gain: factor the gain gets multiplied with. + */ +extern void SND_SetGain(SND_ObjectHandle object, double gain); + +/** + * Sets the minimum gain of a soundobject. + * + * @param object: handle to soundobject. + * @param minimumgain: lower threshold for the gain. + */ +extern void SND_SetMinimumGain(SND_ObjectHandle object, double minimumgain); + +/** + * Sets the maximum gain of a soundobject. + * + * @param object: handle to soundobject. + * @param maximumgain: upper threshold for the gain. + */ +extern void SND_SetMaximumGain(SND_ObjectHandle object, double maximumgain); + +/** + * Sets the rollofffactor. The rollofffactor is a per-Source parameter the application + * can use to increase or decrease the range of a source by decreasing or increasing the + * attenuation, respectively. The default value is 1. The implementation is free to optimize + * for a rollofffactor value of 0, which indicates that the application does not wish any + * distance attenuation on the respective Source. + * + * @param object: handle to soundobject. + * @param rollofffactor: the rollofffactor. + */ +extern void SND_SetRollOffFactor(SND_ObjectHandle object, double rollofffactor); + +/** + * Sets the referencedistance at which the listener will experience gain. + * @attention G_dB = gain - 20 * log10(1 + rollofffactor * (dist - referencedistance)/referencedistance); + * + * @param object: handle to soundobject. + * @param distance: the reference distance. + */ +extern void SND_SetReferenceDistance(SND_ObjectHandle object, double referencedistance); + +/** + * Sets the pitch of a soundobject. + * + * @param object: handle to soundobject. + * @param pitch: pitchingfactor: 2.0 for doubling the frequency, 0.5 for half the frequency. + */ +extern void SND_SetPitch(SND_ObjectHandle object, double pitch); + +/** + * Sets the position a soundobject. + * + * @param object: handle to soundobject. + * @param position: position[3]. + */ +extern void SND_SetPosition(SND_ObjectHandle object, double* position); + +/** + * Sets the velocity of a soundobject. + * + * @param object: handle to soundobject. + * @param velocity: velocity[3]. + */ +extern void SND_SetVelocity(SND_ObjectHandle object, double* velocity); + +/** + * Sets the orientation of a soundobject. + * + * @param object: handle to soundobject. + * @param orientation: orientation[9]. + */ +extern void SND_SetOrientation(SND_ObjectHandle object, double* orientation); + +/** + * Sets the loopmode of a soundobject. + * + * @param object: handle to soundobject. + * @param loopmode type of the loop (SND_LOOP_OFF, SND_LOOP_NORMAL, SND_LOOP_BIDIRECTIONAL); + */ +extern void SND_SetLoopMode(SND_ObjectHandle object, int loopmode); + +/** + * Sets the looppoints of a soundobject. + * + * @param object: handle to soundobject. + * @param loopstart startpoint of the loop + * @param loopend endpoint of the loop + */ +extern void SND_SetLoopPoints(SND_ObjectHandle object, unsigned int loopstart, unsigned int loopend); + +/** + * Gets the gain of a soundobject. + * + * @param object: handle to soundobject. + */ +extern float SND_GetGain(SND_ObjectHandle object); + +/** + * Gets the pitch of a soundobject. + * + * @param object: handle to soundobject. + */ +extern float SND_GetPitch(SND_ObjectHandle object); + +/** + * Gets the looping of a soundobject. + * 0: SND_LOOP_OFF + * 1: SND_LOOP_NORMAL + * 2: SND_LOOP_BIDIRECTIONAL + * + * @param object: handle to soundobject. + */ +extern int SND_GetLoopMode(SND_ObjectHandle object); + +/** + * Gets the playstate of a soundobject. + * SND_UNKNOWN = -1 + * SND_INITIAL + * SND_MUST_PLAY + * SND_PLAYING + * SND_MUST_STOP + * SND_STOPPED + * SND_MUST_PAUSE + * SND_PAUSED + * SND_MUST_BE_DELETED + * + * @param object: handle to soundobject. + */ +extern int SND_GetPlaystate(SND_ObjectHandle object); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/SoundSystem/SND_CDObject.h b/intern/SoundSystem/SND_CDObject.h new file mode 100644 index 00000000000..5af2005d34a --- /dev/null +++ b/intern/SoundSystem/SND_CDObject.h @@ -0,0 +1,86 @@ +/* + * SND_CDObject.h + * + * Implementation for CD playback + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_CDOBJECT_H +#define __SND_CDOBJECT_H + +#include "SND_Object.h" + +class SND_CDObject : public SND_Object +{ +private: + + /** + * Private to enforce singleton + */ + SND_CDObject(); + SND_CDObject(const SND_CDObject&); + + static SND_CDObject* m_instance; + MT_Scalar m_gain; /* the gain of the object */ + int m_playmode; /* the way CD is played back (all, random, track, trackloop) */ + int m_track; /* the track for 'track' and 'trackloop' */ + int m_playstate; /* flag for current state of object */ + bool m_modified; + bool m_used; /* flag for checking if we used the cd, if not don't + call the stop cd at the end */ + +public: + static bool CreateSystem(); + static bool DisposeSystem(); + static SND_CDObject* Instance(); + + ~SND_CDObject(); + + void SetGain(MT_Scalar gain); + void SetPlaymode(int playmode); + void SetTrack(int track); + void SetPlaystate(int playstate); + void SetModified(bool modified); + void SetUsed(); + bool GetUsed(); + + bool IsModified() const; + + int GetTrack() const; + MT_Scalar GetGain() const; + int GetPlaymode() const; + int GetPlaystate() const; + +}; + +#endif //__SND_CDOBJECT_H + diff --git a/intern/SoundSystem/SND_DependKludge.h b/intern/SoundSystem/SND_DependKludge.h new file mode 100644 index 00000000000..71514a87ca2 --- /dev/null +++ b/intern/SoundSystem/SND_DependKludge.h @@ -0,0 +1,56 @@ +/* + * SND_DependKludge.h + * + * who needs what? + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef HAVE_CONFIG_H + +#ifndef NO_SOUND + +#if defined (_WIN32) && !defined(FREE_WINDOWS) +# define USE_OPENAL +#elif defined (__linux__) || (__FreeBSD__) || defined(__APPLE__) || defined(__sun) +# define USE_OPENAL +#else +# ifdef USE_OPENAL +# undef USE_OPENAL +# endif +# ifdef USE_FMOD +# undef USE_FMOD +# endif +#endif + +#endif /* NO_SOUND */ + +#endif /* HAVE_CONFIG_H */ diff --git a/intern/SoundSystem/SND_DeviceManager.h b/intern/SoundSystem/SND_DeviceManager.h new file mode 100644 index 00000000000..b0b2a28ffb8 --- /dev/null +++ b/intern/SoundSystem/SND_DeviceManager.h @@ -0,0 +1,82 @@ +/* + * SND_DeviceManager.h + * + * singleton for creating, switching and deleting audiodevices + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_DEVICEMANAGER_H +#define __SND_DEVICEMANAGER_H + +#include "SND_IAudioDevice.h" + +class SND_DeviceManager +{ +public : + + /** + * a subscription is needed before instances are given away + * applications must call subscribe first, get an instance, and + * when they are finished with sound, unsubscribe + */ + static void Subscribe(); + static void Unsubscribe(); + + static SND_IAudioDevice* Instance(); + static void SetDeviceType(int device_type); + +private : + + /** + * Private to enforce singleton + */ + SND_DeviceManager(); + SND_DeviceManager(const SND_DeviceManager&); + ~SND_DeviceManager(); + + static SND_IAudioDevice* m_instance; + + /** + * The type of device to be created on a call + * to Instance(). + */ + static int m_device_type; + + /** + * Remember the number of subscriptions. + * if 0, delete the device + */ + static int m_subscriptions; +}; + +#endif //__SND_DEVICEMANAGER_H + diff --git a/intern/SoundSystem/SND_IAudioDevice.h b/intern/SoundSystem/SND_IAudioDevice.h new file mode 100644 index 00000000000..73d52e13c05 --- /dev/null +++ b/intern/SoundSystem/SND_IAudioDevice.h @@ -0,0 +1,346 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_IAUDIODEVICE +#define SND_IAUDIODEVICE + +#include "SND_SoundObject.h" +#include "SND_CDObject.h" +#include "SND_WaveCache.h" +#include "SND_WaveSlot.h" +#include "MT_Matrix3x3.h" + +class SND_IAudioDevice +{ +public: + + /** + * constructor + */ + SND_IAudioDevice() {}; + + /** + * destructor + */ + virtual ~SND_IAudioDevice() {}; + + /** + * check to see if initialization was successfull + * + * @return indication of succes + */ + virtual bool IsInitialized()=0; + + /** + * get the wavecache (which does sample (un)loading) + * + * @return pointer to the wavecache + */ + virtual SND_WaveCache* GetWaveCache() const =0; + + /** + * loads a sample into the device + * + * @param samplename the name of the sample + * @param memlocation pointer where the sample is stored + * @param size size of the sample in memory + * + * @return pointer to the slot with sample data + */ + virtual SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size)=0; + + /** + * remove a sample from the wavecache + * + * @param filename pointer to filename + */ +// virtual void RemoveSample(const char* filename)=0; + + /** + * remove all samples from the wavecache + */ + virtual void RemoveAllSamples()=0; + + /** + * get a new id from the device + * + * @param pObject pointer to soundobject + * + * @return indication of success + */ + virtual bool GetNewId(SND_SoundObject* pObject)=0; + + /** + * clear an id + * + * @param pObject pointer to soundobject + */ + virtual void ClearId(SND_SoundObject* pObject)=0; + + /** + * initialize the listener + */ + virtual void InitListener()=0; + + /** + * set the value of the propagation speed relative to which the + * source velocities are interpreted. + * f' = DOPPLER_FACTOR * f * (DOPPLER_VELOCITY - Vl) / (DOPPLER_VELOCITY + Vo) + * f: frequency in sample (soundobject) + * f': effective Doppler shifted frequency + * Vl: velocity listener + * Vo: velocity soundobject + * + * @param dopplervelocity scaling factor for doppler effect + */ + virtual void SetDopplerVelocity(MT_Scalar dopplervelocity) const =0; + + /** + * set a scaling to exaggerate or deemphasize the Doppler (pitch) + * shift resulting from the calculation. + * f' = DOPPLER_FACTOR * f * (DOPPLER_VELOCITY - Listener_velocity )/(DOPPLER_VELOCITY + object_velocity ) + * + * @param dopplerfactor scaling factor for doppler effect + */ + virtual void SetDopplerFactor(MT_Scalar dopplerfactor) const =0; + + /** + * set the roll-off factor + * + * @param rollofffactor a global volume scaling factor + */ + virtual void SetListenerRollOffFactor(MT_Scalar rollofffactor) const =0; + + /** + * make the context the current one + */ + virtual void MakeCurrent() const =0; + + /** + * update the device + */ + virtual void NextFrame() const =0; + + /** + * set the volume of the listener. + * + * @param gain the mastergain + */ + virtual void SetListenerGain(float gain) const =0; + + /** + * connect the buffer with the source + * + * @param id the id of the object + * @param buffer the buffer the sample is stored in + */ + virtual void SetObjectBuffer(int id, unsigned int buffer)=0; + + /** + * pause playback of the cd + * @param id the id of the object + * + * @return the state the object is in + */ + virtual int GetPlayState(int id) =0; + + /** + * play a sound belonging to an object. + * + * @param id the id of the object + */ + virtual void PlayObject(int id) =0; + + /** + * stop a sound belonging to an object. + * + * @param id the id of the object + */ + virtual void StopObject(int id) const =0; + + /** + * stop all sounds. + */ + virtual void StopAllObjects()=0; + + /** + * pause the sound belonging to an object. + * + * @param id the id of the object + */ + virtual void PauseObject(int id) const =0; + + /** + * set the sound to looping or non-looping. + * + * @param id the id of the object + * @param loopmode type of looping (no loop, normal, bidirectional) + */ + virtual void SetObjectLoop(int id, unsigned int loopmode) const =0; + + /** + * set the looppoints of a sound + * + * @param id the id of the object + * @param loopstart the startpoint of the loop (in samples) + * @param loopend the endpoint of the loop (in samples) + */ + virtual void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const =0; + + /** + * set the pitch of the sound. + * + * @param id the id of the object + * @param pitch the pitch + */ + virtual void SetObjectPitch(int id, MT_Scalar pitch) const =0; + + /** + * set the gain of the sound. + * + * @param id the id of the object + * @param gain the gain + */ + virtual void SetObjectGain(int id, MT_Scalar gain) const =0; + + /** + * ROLLOFF_FACTOR is per-Source parameter the application can use to increase or decrease + * the range of a source by decreasing or increasing the attenuation, respectively. The + * default value is 1. The implementation is free to optimize for a ROLLOFF_FACTOR value + * of 0, which indicates that the application does not wish any distance attenuation on + * the respective Source. + * + * @param id the id of the object + * @param rolloff a per-source volume scaling factor + */ + virtual void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const =0; + + /** + * min_gain indicates the minimal gain which is always guaranteed for this sound + * + * @param id the id of the object + * @param mingain the minimum gain of the object + */ + virtual void SetObjectMinGain(int id, MT_Scalar mingain) const =0; + + /** + * max_gain indicates the maximal gain which is always guaranteed for this sound + * + * @param id the id of the object + * @param maxgain the maximum gain of the object + */ + virtual void SetObjectMaxGain(int id, MT_Scalar maxgain) const =0; + /** + * set the distance at which the Listener will experience gain. + * G_dB = GAIN - 20*log10(1 + ROLLOFF_FACTOR*(dist-REFERENCE_DISTANCE)/REFERENCE_DISTANCE ); + * + * @param id the id of the object + * @param referencedistance the distance at which the listener will start hearing + */ + virtual void SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const =0; + + /** + * set the position, velocity and orientation of a sound. + * + * @param id the id of the object + * @param position the position of the object + * @param velocity the velocity of the object + * @param orientation the orientation of the object + * @param lisposition the position of the listener + * @param rollofffactor the rollofffactor of the object + */ + virtual void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const =0; + + /** + * make a sound 2D + * + * @param id the id of the object + */ + virtual void ObjectIs2D(int id) const =0; + + /** + * tell the device we want cd suppport + */ + virtual void UseCD() const =0; + + /** + * start playback of the cd + * + * @param track the tracknumber to start playback from + */ + virtual void PlayCD(int track) const =0; + + /** + * pause playback of the cd (true == pause, false == resume) + */ + virtual void PauseCD(bool pause) const =0; + + /** + * stop playback of the cd + */ + virtual void StopCD() const =0; + + /** + * set the playbackmode of the cd + * SND_CD_ALL play all tracks + * SND_CD_TRACK play one track + * SND_CD_TRACKLOOP play one track looped + * SND_CD_RANDOM play all tracks in random order + * + * @param playmode playmode + */ + virtual void SetCDPlaymode(int playmode) const =0; + + /** + * set the volume playback of the cd + * + * @param gain the gain + */ + virtual void SetCDGain(MT_Scalar gain) const =0; + + virtual void StartUsingDSP() =0; + virtual float* GetSpectrum() =0; + virtual void StopUsingDSP() =0; + +protected: + + virtual void RevokeSoundObject(SND_SoundObject* pObject)=0; +}; + +#endif //SND_IAUDIODEVICE + diff --git a/intern/SoundSystem/SND_Object.h b/intern/SoundSystem/SND_Object.h new file mode 100644 index 00000000000..b67ae3ee396 --- /dev/null +++ b/intern/SoundSystem/SND_Object.h @@ -0,0 +1,57 @@ +/* + * SND_Object.h + * + * Abstract sound object + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_OBJECT_H +#define __SND_OBJECT_H + +#include "GEN_List.h" +#include "MT_Matrix3x3.h" +#include "SoundDefines.h" + +/** + * SND_Object is an interface class for soundobjects, listeners and other + * kinds of sound related thingies. + */ + +class SND_Object : public GEN_Link +{ +public: + SND_Object() {}; + virtual ~SND_Object() {}; +}; + +#endif //__SND_OBJECT_H + diff --git a/intern/SoundSystem/SND_Scene.h b/intern/SoundSystem/SND_Scene.h new file mode 100644 index 00000000000..49cb40de714 --- /dev/null +++ b/intern/SoundSystem/SND_Scene.h @@ -0,0 +1,107 @@ +/* + * SND_Scene.h + * + * The scene for sounds. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#ifndef __SND_SCENE_H +#define __SND_SCENE_H + +#include "SoundDefines.h" +#include "SND_SoundObject.h" +#include "SND_CDObject.h" +#include "SND_SoundListener.h" +#include "SND_WaveSlot.h" + +#include "MT_Vector3.h" +#include "MT_Matrix3x3.h" +#include "STR_String.h" + +#include + + +class SND_Scene +{ + std::set m_soundobjects; + + GEN_List m_activeobjects; + class SND_IAudioDevice* m_audiodevice; + class SND_WaveCache* m_wavecache; + class SND_SoundListener m_listener; + bool m_audio; // to check if audio works + bool m_audioplayback; // to check if audioplayback is wanted + + void UpdateListener(); + void BuildActiveList(MT_Scalar curtime); + void UpdateActiveObects(); + void UpdateCD(); + +public: + SND_Scene(SND_IAudioDevice* adi); + ~SND_Scene(); + + bool IsPlaybackWanted(); + + void AddActiveObject(SND_SoundObject* pObject, MT_Scalar curtime); + void RemoveActiveObject(SND_SoundObject* pObject); + void DeleteObjectWhenFinished(SND_SoundObject* pObject); + + void Proceed(); + + int LoadSample(const STR_String& samplename, + void* memlocation, + int size); + void RemoveAllSamples(); + bool CheckBuffer(SND_SoundObject* pObject); + bool IsSampleLoaded(STR_String& samplename); + + void AddObject(SND_SoundObject* pObject); + bool SetCDObject(SND_CDObject* cdobject); + void DeleteObject(SND_SoundObject* pObject); + void RemoveAllObjects(); + void StopAllObjects(); + int GetObjectStatus(SND_SoundObject* pObject) const; + + void SetListenerTransform(const MT_Vector3& pos, + const MT_Vector3& vel, + const MT_Matrix3x3& mat); + + SND_SoundListener* GetListener(); +}; + +#endif //__SND_SCENE_H + diff --git a/intern/SoundSystem/SND_SoundListener.h b/intern/SoundSystem/SND_SoundListener.h new file mode 100644 index 00000000000..ce8315e6375 --- /dev/null +++ b/intern/SoundSystem/SND_SoundListener.h @@ -0,0 +1,85 @@ +/* + * SND_SoundListener.h + * + * A SoundListener is for sound what a camera is for vision. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_SOUNDLISTENER_H +#define __SND_SOUNDLISTENER_H + +#include "SND_Object.h" + +class SND_SoundListener : public SND_Object +{ +public: + SND_SoundListener(); + virtual ~SND_SoundListener(); + + void SetStateFlag(unsigned int stateflags); + void SetGain(MT_Scalar gain); + void SetPosition(const MT_Vector3& pos); + void SetVelocity(const MT_Vector3& vel); + void SetOrientation(const MT_Matrix3x3& ori); + void SetDopplerFactor(MT_Scalar dopplerfactor); + void SetDopplerVelocity(MT_Scalar dopplervelocity); + void SetScale(MT_Scalar scale); + + void SetModified(bool modified); + bool IsModified() const; + + unsigned int GetStateFlags() const; + MT_Scalar GetGain() const; + MT_Vector3 GetPosition() const; + MT_Vector3 GetVelocity() const; + MT_Matrix3x3 GetOrientation(); + + MT_Scalar GetDopplerFactor() const; + MT_Scalar GetDopplerVelocity() const; + MT_Scalar GetScale() const; + +private: + void* m_listener; + bool m_modified; + + MT_Scalar m_gain; /* overall gain */ + MT_Vector3 m_position; /* position; left/right, up/down, in/out */ + MT_Vector3 m_velocity; /* velocity of the listener */ + MT_Matrix3x3 m_orientation; /* orientation of the listener */ + + MT_Scalar m_dopplerfactor; /* scaling factor for the Doppler (pitch) shift */ + MT_Scalar m_dopplervelocity; /* factor for the reference velocity (for Dopplereffect) */ + MT_Scalar m_scale; +}; + +#endif //__SND_SOUNDLISTENER_H + diff --git a/intern/SoundSystem/SND_SoundObject.h b/intern/SoundSystem/SND_SoundObject.h new file mode 100644 index 00000000000..a6a98fba220 --- /dev/null +++ b/intern/SoundSystem/SND_SoundObject.h @@ -0,0 +1,162 @@ +/* + * SND_SoundObject.h + * + * Implementation of the abstract sound object + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_SOUNDOBJECT_H +#define __SND_SOUNDOBJECT_H + +#include "SND_Object.h" +#include "STR_String.h" + +/** + * SND_SoundObject is a class for api independent sounddata storage conected to an actuator + */ + +class SND_SoundObject : public SND_Object +{ +private: + STR_String m_samplename; /* name of the sample */ + STR_String m_objectname; /* name of the object */ + unsigned int m_buffer; + + bool m_active; /* is the object active or not? */ + int m_id; + MT_Scalar m_lifespan; /* the lifespan of the sound seconds */ + MT_Scalar m_timestamp; + + MT_Scalar m_length; /* length of the sample in seconds */ + + MT_Scalar m_gain; /* the gain of the object */ + MT_Scalar m_rollofffactor; /* the scaling factor to increase or decrease the range + of a source by decreasing or increasing the + attenuation, respectively */ + MT_Scalar m_referencedistance;/* the distance at which the listener will experience + gain */ + MT_Scalar m_mingain; /* indicates the minimal gain which is always guaranteed + for this source */ + MT_Scalar m_maxgain; /* indicates the maximal gain which is always guaranteed + for this source */ + + MT_Scalar m_pitch; /* the pitch of the object */ + MT_Vector3 m_position; /* position; left/right, up/down, in/out */ + MT_Vector3 m_velocity; /* velocity of the object */ + MT_Matrix3x3 m_orientation; /* orientation of the object */ + unsigned int m_loopmode; /* loop normal or bidirectional? */ + unsigned int m_loopstart; /* start of looppoint in samples! */ + unsigned int m_loopend; /* end of looppoint in samples! */ + bool m_is3d; /* is the object 3D or 2D? */ + int m_playstate; /* flag for current state of object */ + bool m_modified; + unsigned int m_running; + bool m_highpriority; /* may the sound be ditched when we run out of voices? */ + +public: + + SND_SoundObject(); + ~SND_SoundObject(); + + void SetBuffer(unsigned int buffer); + void SetActive(bool active); + + void StartSound(); + void StopSound(); + void PauseSound(); + void DeleteWhenFinished(); + + void SetObjectName(STR_String objectname); + void SetSampleName(STR_String samplename); + void SetLength(MT_Scalar length); + + void SetPitch(MT_Scalar pitch); + void SetGain(MT_Scalar gain); + void SetMinGain(MT_Scalar mingain); + void SetMaxGain(MT_Scalar maxgain); + void SetRollOffFactor(MT_Scalar rollofffactor); + void SetReferenceDistance(MT_Scalar distance); + void SetPosition(const MT_Vector3& pos); + void SetVelocity(const MT_Vector3& vel); + void SetOrientation(const MT_Matrix3x3& orient); + void SetLoopMode(unsigned int loopmode); + void SetLoopStart(unsigned int loopstart); + void SetLoopEnd(unsigned int loopend); + void Set3D(bool threedee); + void SetPlaystate(int playstate); + void SetHighPriority(bool priority); + + void SetId(int id); + void SetLifeSpan(); + void SetTimeStamp(MT_Scalar timestamp); + + void SetModified(bool modified); + + bool IsLifeSpanOver(MT_Scalar curtime) const; + bool IsActive() const; + bool IsModified() const; + bool IsHighPriority() const; + + void InitRunning(); + bool IsRunning() const; + void AddRunning(); + + int GetId() const; + MT_Scalar GetLifeSpan() const; + MT_Scalar GetTimestamp() const; + + unsigned int GetBuffer(); + const STR_String& GetSampleName(); + const STR_String& GetObjectName(); + + MT_Scalar GetLength() const; + MT_Scalar GetGain() const; + MT_Scalar GetPitch() const; + + MT_Scalar GetMinGain() const; + MT_Scalar GetMaxGain() const; + MT_Scalar GetRollOffFactor() const; + MT_Scalar GetReferenceDistance() const; + + MT_Vector3 GetPosition() const; + MT_Vector3 GetVelocity() const; + MT_Matrix3x3 GetOrientation() const; + unsigned int GetLoopMode() const; + unsigned int GetLoopStart() const; + unsigned int GetLoopEnd() const; + bool Is3D() const; + int GetPlaystate() const; + +}; + +#endif //__SND_SOUNDOBJECT_H + diff --git a/intern/SoundSystem/SND_Utils.h b/intern/SoundSystem/SND_Utils.h new file mode 100644 index 00000000000..de36065c48f --- /dev/null +++ b/intern/SoundSystem/SND_Utils.h @@ -0,0 +1,114 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_UTILS_H +#define SND_UTILS_H + +#include "SND_WaveSlot.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct +{ + unsigned char riff[4]; + signed int size; + unsigned char type[4]; +} WavFileHeader; + +typedef struct +{ + unsigned short format; + unsigned short numberofchannels; + unsigned int samplerate; + unsigned int bytespersec; + unsigned short blockalignment; + unsigned short bitrate; +} WavFmtHeader; + +typedef struct +{ + unsigned short size; + unsigned short samplesperblock; +} WavFmtExHeader; + +typedef struct +{ + unsigned int Manufacturer; + unsigned int Product; + unsigned int SamplePeriod; + unsigned int Note; + unsigned int FineTune; + unsigned int SMPTEFormat; + unsigned int SMPTEOffest; + unsigned int loops; + unsigned int SamplerData; + struct + { + unsigned int Identifier; + unsigned int Type; + unsigned int Start; + unsigned int End; + unsigned int Fraction; + unsigned int Count; + } Loop[1]; +} WavSampleHeader; + +typedef struct +{ + unsigned char id[4]; + unsigned int size; +} WavChunkHeader; + +/** + * loads a sample and returns a pointer + */ +extern void* SND_LoadSample(char *filename); + +extern bool SND_IsSampleValid(const STR_String& name, void* memlocation); +extern unsigned int SND_GetSampleFormat(void* sample); +extern unsigned int SND_GetNumberOfChannels(void* sample); +extern unsigned int SND_GetSampleRate(void* sample); +extern unsigned int SND_GetBitRate(void* sample); +extern unsigned int SND_GetNumberOfSamples(void* sample); +extern unsigned int SND_GetHeaderSize(void* sample); +extern unsigned int SND_GetExtraChunk(void* sample); + +extern void SND_GetSampleInfo(signed char* sample, SND_WaveSlot* waveslot); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/SoundSystem/SND_WaveCache.h b/intern/SoundSystem/SND_WaveCache.h new file mode 100644 index 00000000000..1a6445be966 --- /dev/null +++ b/intern/SoundSystem/SND_WaveCache.h @@ -0,0 +1,69 @@ +/* + * SND_WaveCache.h + * + * abstract wavecache, a way to organize samples + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#ifndef __SND_WAVECACHE_H +#define __SND_WAVECACHE_H + +#include "SND_WaveSlot.h" +#include "SoundDefines.h" +#include "SND_SoundObject.h" +#include + +class SND_WaveCache +{ +public: + SND_WaveCache(); + virtual ~SND_WaveCache(); + + SND_WaveSlot* GetWaveSlot(const STR_String& samplename); + + void RemoveAllSamples(); + void RemoveSample(const STR_String& samplename, int buffer); + +private: + std::map m_samplecache; + + SND_WaveSlot* m_bufferList[NUM_BUFFERS]; + + void FreeSamples(); +}; + +#endif //__SND_WAVECACHE_H + diff --git a/intern/SoundSystem/SND_WaveSlot.h b/intern/SoundSystem/SND_WaveSlot.h new file mode 100644 index 00000000000..bc92829d3d3 --- /dev/null +++ b/intern/SoundSystem/SND_WaveSlot.h @@ -0,0 +1,95 @@ +/* + * SND_WaveSlot.cpp + * + * class for storing sample related information + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_WAVESLOT_H +#define __SND_WAVESLOT_H + +#include "STR_String.h" + +class SND_WaveSlot +{ + STR_String m_samplename; + bool m_loaded; + void* m_data; + unsigned int m_buffer; + unsigned int m_sampleformat; + unsigned int m_numberofchannels; + unsigned int m_samplerate; + unsigned int m_bitrate; + unsigned int m_numberofsamples; + unsigned int m_filesize; + +public: + + SND_WaveSlot(): m_loaded(false), + m_data(NULL), + m_buffer(0), + m_sampleformat(0), + m_numberofchannels(0), + m_samplerate(0), + m_bitrate(0), + m_numberofsamples(0), + m_filesize(0) + {}; + ~SND_WaveSlot(); + + void SetSampleName(STR_String samplename); + void SetLoaded(bool loaded); + void SetData(void* data); + void SetBuffer(unsigned int buffer); + void SetSampleFormat(unsigned int sampleformat); + void SetNumberOfChannels(unsigned int numberofchannels); + void SetSampleRate(unsigned int samplerate); + void SetBitRate(unsigned int bitrate); + void SetNumberOfSamples(unsigned int numberofsamples); + void SetFileSize(unsigned int filesize); + + + const STR_String& GetSampleName(); + bool IsLoaded() const; + void* GetData(); + unsigned int GetBuffer() const; + unsigned int GetSampleFormat() const; + unsigned int GetNumberOfChannels() const; + unsigned int GetSampleRate() const; + unsigned int GetBitRate() const; + unsigned int GetNumberOfSamples() const; + unsigned int GetFileSize() const; + +}; + +#endif //__SND_WAVESLOT_H + diff --git a/intern/SoundSystem/SND_test/Makefile b/intern/SoundSystem/SND_test/Makefile new file mode 100644 index 00000000000..2fc531ae37e --- /dev/null +++ b/intern/SoundSystem/SND_test/Makefile @@ -0,0 +1,51 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = soundsystem +DIR = $(OCGDIR)/intern/SoundSystem +ALLTARGETS = $(OBJS) $(DIR)/$(DEBUG_DIR)SoundSystem + +include nan_compile.mk + +CPPFLAGS += $(NAN_LEVEL_1_WARNINGS) + +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I.. -I../SND_BlenderWaveCache -I../SND_OpenAL + +TESTLIB = $(OCGDIR)/gameengine/OpenALSoundSystem/$(DEBUG_DIR)libOpenALSoundSystem.a +TESTLIB += $(OCGDIR)/gameengine/BlenderWaveCache/$(DEBUG_DIR)libBlenderWaveCache.a +TESTLIB += $(OCGDIR)/intern/SoundSystem/$(DEBUG_DIR)libsoundsystem.a +TESTLIB += $(NAN_OPENAL)/lib/libopenal.a + +$(DIR)/$(DEBUG_DIR)SoundSystem: $(OBJS) $(TESTLIB) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(TESTLIB) -lm -pthread -ldl -lstdc++ diff --git a/intern/SoundSystem/SND_test/SND_test.c b/intern/SoundSystem/SND_test/SND_test.c new file mode 100644 index 00000000000..99de147c8a0 --- /dev/null +++ b/intern/SoundSystem/SND_test/SND_test.c @@ -0,0 +1,157 @@ +/* SND_test.c nov 2000 +* +* testfile for the SND module +* +* janco verduin +* +* $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "SND_C-api.h" +#include "BlenderWaveCacheCApi.h" +#include "OpenALC-Api.h" +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) +#include +#else +#include +#endif +#include + +static int buf[3]; + +float oPos[3]={3.0, 0.0,-1.0}; +float oVel[3]={0.0, 0.0, 1.0}; +float oOri[6]={0.0, 0.0, 1.0, 0.0, 1.0, 0.0}; + +void* ReadFile(char *filename) +{ + int file, filelen; + void *data = NULL; + +#if defined(WIN32) + file = open(filename, O_BINARY|O_RDONLY); +#else + file = open(filename, 0|O_RDONLY); +#endif + + if (file == -1) { + printf("can't open file.\n"); + printf("press q for quit.\n"); + + } + else { + filelen = lseek(file, 0, SEEK_END); + lseek(file, 0, SEEK_SET); + + if (filelen != 0){ + data = malloc(filelen); + if (read(file, data, filelen) != filelen) { + free(data); + data = NULL; + } + } + close(file); + + } + return (data); +} + +int main(int argc, char* argv[]) +{ + int ch; + char* samplename = NULL; + void* sampleinmemory = NULL; + SND_CacheHandle wavecache = NULL; + SND_SceneHandle scene = NULL; + SND_ObjectHandle object = NULL; + + wavecache = SND_GetWaveCache(); + scene = SND_CreateOpenALScene(wavecache); + + samplename = "2.wav"; + sampleinmemory = ReadFile(samplename); + + if (sampleinmemory) { + + object = SND_CreateObject(); + SND_AddMemoryLocation(samplename, sampleinmemory); + SND_SetSampleName(object, samplename); + SND_AddObject(scene, object); + printf("go your gang...\n"); + printf("1: play\n"); + printf("2: stop\n"); + printf("q: quit\n"); + } + do + { + ch = getchar(); + ch = toupper(ch); + switch (ch) + { + case '1': + { + SND_SetPitch(object, 1.0); + SND_SetGain(object, 1.0); + SND_StartSound(object); + break; + } + case '2': + { + SND_StopSound(object); + break; + } + default: + break; + } + + SND_Proceed(scene); + + } while (ch != 'Q'); + + if (object) { + + SND_RemoveObject(scene, object); + SND_DeleteObject(object); + } + + SND_DeleteScene(scene); + SND_DeleteCache(); + + return 0; + +} diff --git a/intern/SoundSystem/SoundDefines.h b/intern/SoundSystem/SoundDefines.h new file mode 100644 index 00000000000..f7a3a3c6619 --- /dev/null +++ b/intern/SoundSystem/SoundDefines.h @@ -0,0 +1,120 @@ +/* + * SoundDefines.h + * + * this is where all kinds of defines are stored + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SOUNDDEFINES_H +#define __SOUNDDEFINES_H + +/* the types of devices */ +enum +{ + snd_e_dummydevice = 0, + snd_e_fmoddevice, + snd_e_openaldevice +}; + +/* general stuff */ +#define NUM_BUFFERS 128 +#define NUM_SOURCES 16 + +/* openal related stuff */ +#define AL_LOOPING 0x1007 + +/* fmod related stuff */ +#ifdef WIN32 +#define MIXRATE 22050 +#else +#define MIXRATE 44100 +#endif +#define NUM_FMOD_MIN_HW_CHANNELS 16 +#define NUM_FMOD_MAX_HW_CHANNELS 16 + +/* activelist defines */ +enum +{ + SND_REMOVE_ACTIVE_OBJECT = 0, + SND_ADD_ACTIVE_OBJECT, + SND_DO_NOTHING +}; + +/* playstate flags */ +enum +{ + SND_UNKNOWN = -1, + SND_INITIAL, + SND_MUST_PLAY, + SND_PLAYING, + SND_MUST_STOP, + SND_STOPPED, + SND_MUST_PAUSE, + SND_PAUSED, + SND_MUST_RESUME, + SND_MUST_STOP_WHEN_FINISHED, + SND_MUST_BE_DELETED +}; + +/* loopmodes */ +enum +{ + SND_LOOP_OFF = 0, + SND_LOOP_NORMAL, + SND_LOOP_BIDIRECTIONAL +}; + + +/* cd playstate flags */ +enum +{ + SND_CD_ALL = 0, + SND_CD_TRACK, + SND_CD_TRACKLOOP +}; + +/* sample types */ +enum +{ + SND_WAVE_FORMAT_UNKNOWN = 0, + SND_WAVE_FORMAT_PCM, + SND_WAVE_FORMAT_ADPCM, + SND_WAVE_FORMAT_ALAW = 6, + SND_WAVE_FORMAT_MULAW, + SND_WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 17, + SND_WAVE_FORMAT_CONTROL_RES_VQLPC = 34, + SND_WAVE_FORMAT_GSM_610 = 49, + SND_WAVE_FORMAT_MPEG3 = 85 +}; + +#endif //__SOUNDDEFINES_H + diff --git a/intern/SoundSystem/dummy/Makefile b/intern/SoundSystem/dummy/Makefile new file mode 100644 index 00000000000..5d23d1a8a6a --- /dev/null +++ b/intern/SoundSystem/dummy/Makefile @@ -0,0 +1,45 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = DummySoundSystem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../intern +CPPFLAGS += -I.. +CPPFLAGS += -I. diff --git a/intern/SoundSystem/dummy/SND_DummyDevice.cpp b/intern/SoundSystem/dummy/SND_DummyDevice.cpp new file mode 100644 index 00000000000..7b99ec461df --- /dev/null +++ b/intern/SoundSystem/dummy/SND_DummyDevice.cpp @@ -0,0 +1,55 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * SND_FmodDevice derived from SND_IAudioDevice + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_DummyDevice.h" + +SND_DummyDevice::SND_DummyDevice() +{ +} + +SND_DummyDevice::~SND_DummyDevice() +{ +#ifdef ONTKEVER + printf("SND_DummyDevice destructor"); +#endif +} + + diff --git a/intern/SoundSystem/dummy/SND_DummyDevice.h b/intern/SoundSystem/dummy/SND_DummyDevice.h new file mode 100644 index 00000000000..6dff52d40d5 --- /dev/null +++ b/intern/SoundSystem/dummy/SND_DummyDevice.h @@ -0,0 +1,96 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_DUMMYDEVICE +#define SND_DUMMYDEVICE + +#include "SND_AudioDevice.h" + +class SND_DummyDevice : public SND_AudioDevice +{ +public: + SND_DummyDevice(); + ~SND_DummyDevice(); + + bool Init() { return false; } + + SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size) { return NULL; } + + void InitListener() {}; + void SetListenerGain(float gain) const {}; + void SetDopplerVelocity(MT_Scalar dopplervelocity) const {}; + void SetDopplerFactor(MT_Scalar dopplerfactor) const {}; + void SetListenerRollOffFactor(MT_Scalar rollofffactor) const {}; + + void MakeCurrent() const {}; + + void NextFrame() const {}; + + void SetObjectBuffer(int id, unsigned int buffer) {}; + + int GetPlayState(int id) { return SND_UNKNOWN; } + void PlayObject(int id) {}; + void StopObject(int id) const {}; + void StopAllObjects() {}; + void PauseObject(int id) const {}; + + void SetObjectLoop(int id, unsigned int loopmode) const {}; + void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const {}; + void SetObjectPitch(int id, MT_Scalar pitch) const {}; + void SetObjectGain(int id, MT_Scalar gain) const {}; + void SetObjectMinGain(int id, MT_Scalar mingain) const {}; + void SetObjectMaxGain(int id, MT_Scalar maxgain) const {}; + void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const {}; + void SetObjectReferenceDistance(int id, MT_Scalar distance) const {}; + + void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const {}; + void ObjectIs2D(int id) const {}; + + void PlayCD(int track) const {}; + void PauseCD(bool pause) const {}; + void StopCD() const {}; + void SetCDPlaymode(int playmode) const {}; + void SetCDGain(MT_Scalar gain) const {}; + + void StartUsingDSP() {}; + float* GetSpectrum() { return NULL; } + void StopUsingDSP() {}; +}; + +#endif //SND_DUMMYDEVICE + diff --git a/intern/SoundSystem/fmod/Makefile b/intern/SoundSystem/fmod/Makefile new file mode 100644 index 00000000000..d2810e8fa2f --- /dev/null +++ b/intern/SoundSystem/fmod/Makefile @@ -0,0 +1,46 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = FmodSoundSystem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_FMOD)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../intern +CPPFLAGS += -I.. +CPPFLAGS += -I. diff --git a/intern/SoundSystem/fmod/SND_FmodDevice.cpp b/intern/SoundSystem/fmod/SND_FmodDevice.cpp new file mode 100644 index 00000000000..06bcbc2f393 --- /dev/null +++ b/intern/SoundSystem/fmod/SND_FmodDevice.cpp @@ -0,0 +1,577 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * SND_FmodDevice derived from SND_IAudioDevice + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_FmodDevice.h" +#include "SoundDefines.h" +#include "SND_Utils.h" + +SND_FmodDevice::SND_FmodDevice() +{ + /* Removed the functionality for checking if noaudio was provided on */ + /* the commandline. */ + m_dspunit = NULL; + + m_audio = true; + + // let's check if we can get fmod to initialize... + if (m_audio) + { + signed char MinHardwareChannels = FSOUND_SetMinHardwareChannels(NUM_FMOD_MIN_HW_CHANNELS); + signed char MaxHardwareChannels = FSOUND_SetMaxHardwareChannels(NUM_FMOD_MAX_HW_CHANNELS); + + if (FSOUND_Init(MIXRATE, NUM_SOURCES, 0)) + { + m_max_channels = FSOUND_GetMaxChannels(); + m_num_hardware_channels = FSOUND_GetNumHardwareChannels(); + m_num_software_channels = NUM_SOURCES; + + // let's get us a wavecache + m_wavecache = new SND_WaveCache(); + + int i; + for (i = 0; i < NUM_BUFFERS; i++) + m_buffers[i] = NULL; + + for (i = 0; i < NUM_SOURCES; i++) + { + m_sources[i] = NULL; + m_frequencies[i] = 0; + m_channels[i] = 0; + } + } + else + { + m_audio = false; + } + } + +#ifdef ONTKEVER + int numdrivers = FSOUND_GetNumDrivers(); + int output = FSOUND_GetOutput(); + int oputputrate = FSOUND_GetOutputRate(); + int mixer = FSOUND_GetMixer(); + + printf("maxchannels is: %d\n", m_max_channels); + printf("num hw channels is: %d\n", m_num_hardware_channels); + printf("num sw channels is: %d\n", m_num_software_channels); + printf("numdrivers is: %d\n", numdrivers); + printf("output is: %d\n", output); + printf("oputputrate is: %d\n", oputputrate); + printf("mixer is: %d\n", mixer); +#endif +} + + + +SND_FmodDevice::~SND_FmodDevice() +{ + // let's see if we used the cd. if not, just leave it alone + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD) + { + this->StopCD(); + SND_CDObject::DisposeSystem(); + } + + StopUsingDSP(); + + FSOUND_Close(); +} + + + +void SND_FmodDevice::UseCD() const +{ + // only fmod has CD support, so only create it here + SND_CDObject::CreateSystem(); +} + + + +void SND_FmodDevice::MakeCurrent() const +{ + // empty +} + + + +SND_WaveSlot* SND_FmodDevice::LoadSample(const STR_String& name, + void* memlocation, + int size) +{ + SND_WaveSlot* waveslot = NULL; + STR_String samplename = name; + + if (m_audio) + { + /* first check if the sample is supported */ + if (SND_IsSampleValid(name, memlocation)) + { + /* create the waveslot */ + waveslot = m_wavecache->GetWaveSlot(samplename); + + if (waveslot) + { + int buffer = waveslot->GetBuffer(); + + /* load the sample from memory? */ + if (size && memlocation) + { + m_buffers[buffer] = FSOUND_Sample_Load(buffer, (char*)memlocation, FSOUND_LOADMEMORY, size); + + /* if the loading succeeded, fill the waveslot with info */ + if (m_buffers[buffer]) + { + int sampleformat = SND_GetSampleFormat(memlocation); + int numberofchannels = SND_GetNumberOfChannels(memlocation); + int samplerate = SND_GetSampleRate(memlocation); + int bitrate = SND_GetBitRate(memlocation); + int numberofsamples = SND_GetNumberOfSamples(memlocation); + + waveslot->SetFileSize(size); + waveslot->SetData(memlocation); + waveslot->SetSampleFormat(sampleformat); + waveslot->SetNumberOfChannels(numberofchannels); + waveslot->SetSampleRate(samplerate); + waveslot->SetBitRate(bitrate); + waveslot->SetNumberOfSamples(numberofsamples); + } + } + /* or from file? */ + else + { + m_buffers[buffer] = FSOUND_Sample_Load(buffer, samplename.Ptr(), FSOUND_LOOP_NORMAL, NULL); + } + +#ifdef ONTKEVER + int error = FSOUND_GetError(); + printf("sample load: errornumber is: %d\n", error); +#endif + + /* if the loading succeeded, mark the waveslot */ + if (m_buffers[buffer]) + { + waveslot->SetLoaded(true); + } + /* or when it failed, free the waveslot */ + else + { + m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer()); + waveslot = NULL; + } + } + } + } + + return waveslot; +} + + + + +// listener's and general stuff ////////////////////////////////////////////////////// + + + +/* sets the global dopplervelocity */ +void SND_FmodDevice::SetDopplerVelocity(MT_Scalar dopplervelocity) const +{ + /* not supported by fmod */ + FSOUND_3D_Listener_SetDopplerFactor(dopplervelocity); +} + + + +/* sets the global dopplerfactor */ +void SND_FmodDevice::SetDopplerFactor(MT_Scalar dopplerfactor) const +{ + FSOUND_3D_Listener_SetDopplerFactor(dopplerfactor); +} + + + +/* sets the global rolloff factor */ +void SND_FmodDevice::SetListenerRollOffFactor(MT_Scalar rollofffactor) const +{ + // not implemented in openal +} + + + +void SND_FmodDevice::NextFrame() const +{ + FSOUND_3D_Update(); +} + + + +// set the gain for the listener +void SND_FmodDevice::SetListenerGain(float gain) const +{ + int fmod_gain = (int)(gain * 255); + FSOUND_SetSFXMasterVolume(fmod_gain); +} + + + +void SND_FmodDevice::InitListener() +{ + // initialize the listener with these values that won't change + // (as long as we can have only one listener) + // now we can superimpose all listeners on each other (for they + // have the same settings) + float lispos[3] = {0,0,0}; + float lisvel[3] = {0,0,0}; + + FSOUND_3D_Listener_SetAttributes(lispos, lisvel, 0, -1, 0, 0, 0, 1); +} + + + +// source playstate stuff //////////////////////////////////////////////////////////// + + + +// check if the sound's still playing +int SND_FmodDevice::GetPlayState(int id) +{ + int result = SND_STOPPED; + + // klopt niet, fixen + signed char isplaying = FSOUND_IsPlaying(id); + + if (isplaying) + { + result = SND_PLAYING; + } + +/* hi reevan, just swap // of these 2 lines */ +// return result; + return 0; +} + + + +/* sets the buffer */ +void SND_FmodDevice::SetObjectBuffer(int id, unsigned int buffer) +{ + m_sources[id] = m_buffers[buffer]; +} + + + +// make the source play +void SND_FmodDevice::PlayObject(int id) +{ + m_channels[id] = FSOUND_PlaySound(FSOUND_FREE, m_sources[id]); + m_frequencies[id] = FSOUND_GetFrequency(m_channels[id]); +// printf("fmod: play \n"); +} + + + +// make the source stop +void SND_FmodDevice::StopObject(int id) const +{ + FSOUND_StopSound(m_channels[id]); +// printf("fmod: stop \n"); +} + + + +// stop all sources +void SND_FmodDevice::StopAllObjects() +{ + FSOUND_StopSound(FSOUND_ALL); +} + + + +// pause the source +void SND_FmodDevice::PauseObject(int id) const +{ + FSOUND_StopSound(m_channels[id]); +} + + + +// source properties stuff //////////////////////////////////////////////////////////// + + + +// give openal the object's pitch +void SND_FmodDevice::SetObjectPitch(int id, MT_Scalar pitch) const +{ + pitch = pitch * m_frequencies[id]; + char result = FSOUND_SetFrequency(m_channels[id], (int)pitch); +} + + + +// give openal the object's gain +void SND_FmodDevice::SetObjectGain(int id, MT_Scalar gain) const +{ + int vol = (int)(gain * 255); + FSOUND_SetVolume(m_channels[id], vol); +} + + + +// give openal the object's looping +void SND_FmodDevice::SetObjectLoop(int id, unsigned int loopmode) const +{ +// printf("loopmode: %d\n", loopmode); + switch (loopmode) + { + case SND_LOOP_OFF: + { +#ifndef __APPLE__ + char result = FSOUND_Sample_SetLoopMode(m_sources[id], FSOUND_LOOP_OFF); +#else + char result = FSOUND_SetLoopMode(m_sources[id], FSOUND_LOOP_OFF); +#endif +// char result = FSOUND_SetLoopMode(m_channels[id], FSOUND_LOOP_OFF); + break; + } + case SND_LOOP_NORMAL: + { +#ifndef __APPLE__ + char result = FSOUND_Sample_SetLoopMode(m_sources[id], FSOUND_LOOP_NORMAL); +#else + char result = FSOUND_SetLoopMode(m_sources[id], FSOUND_LOOP_NORMAL); +#endif +// char result = FSOUND_SetLoopMode(m_channels[id], FSOUND_LOOP_NORMAL); + break; + } + case SND_LOOP_BIDIRECTIONAL: + { +#ifndef __APPLE__ + char result = FSOUND_Sample_SetLoopMode(m_sources[id], FSOUND_LOOP_BIDI); +#else + char result = FSOUND_SetLoopMode(m_sources[id], FSOUND_LOOP_BIDI); +#endif +// char result = FSOUND_SetLoopMode(m_channels[id], FSOUND_LOOP_NORMAL); + break; + } + default: + break; + } +} + + + +void SND_FmodDevice::SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const +{ + FSOUND_Sample_SetLoopPoints(m_sources[id], loopstart, loopend); +} + + + +void SND_FmodDevice::SetObjectMinGain(int id, MT_Scalar mingain) const +{ + /* not supported by fmod */ +} + + + +void SND_FmodDevice::SetObjectMaxGain(int id, MT_Scalar maxgain) const +{ + /* not supported by fmod */ +} + + + +void SND_FmodDevice::SetObjectRollOffFactor(int id, MT_Scalar rollofffactor) const +{ + /* not supported by fmod */ +} + + + +void SND_FmodDevice::SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const +{ + /* not supported by fmod */ +} + + + +// give openal the object's position +void SND_FmodDevice::ObjectIs2D(int id) const +{ + float obpos[3] = {0,0,0}; + float obvel[3] = {0,0,0}; + + FSOUND_3D_SetAttributes(m_channels[id], obpos, obvel); +} + + + +void SND_FmodDevice::SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const +{ + float obpos[3]; + float obvel[3]; + + obpos[0] = (float)position[0] * (float)rollofffactor; //x (l/r) + obpos[1] = (float)position[1] * (float)rollofffactor; + obpos[2] = (float)position[2] * (float)rollofffactor; + + velocity.getValue(obvel); + FSOUND_3D_SetAttributes(m_channels[id], obpos, obvel); +} + + + +// cd support stuff //////////////////////////////////////////////////////////// + + +void SND_FmodDevice::PlayCD(int track) const +{ +#ifndef __APPLE__ + signed char result = FSOUND_CD_Play(track); +#else + signed char result = FSOUND_CD_Play(0, track); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::PlayCD(): track=%d, result=%d\n", track, (int)result); +#endif +} + + + +void SND_FmodDevice::PauseCD(bool pause) const +{ +#ifndef __APPLE__ + signed char result = FSOUND_CD_SetPaused(pause); +#else + signed char result = FSOUND_CD_SetPaused(0, pause); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::PauseCD(): pause=%d, result=%d\n", pause, (int)result); +#endif +} + + + +void SND_FmodDevice::StopCD() const +{ + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD) + { + if (pCD->GetUsed()) + { +#ifndef __APPLE__ + signed char result = FSOUND_CD_Stop(); +#else + signed char result = FSOUND_CD_Stop(0); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::StopCD(): result=%d\n", (int)result); +#endif + } + } +} + + + +void SND_FmodDevice::SetCDPlaymode(int playmode) const +{ +#ifndef __APPLE__ + FSOUND_CD_SetPlayMode(playmode); +#else + FSOUND_CD_SetPlayMode(0, playmode); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::SetCDPlaymode(): playmode=%d,\n", playmode); +#endif +} + + + +void SND_FmodDevice::SetCDGain(MT_Scalar gain) const +{ + int volume = gain * 255; +#ifndef __APPLE__ + signed char result = FSOUND_CD_SetVolume(volume); +#else + signed char result = FSOUND_CD_SetVolume(0, volume); +#endif + +#ifdef ONTKEVER + printf("SND_FmodDevice::SetCDGain(): gain=%f, volume=%d, result=%d\n", gain, volume, (int)result); +#endif +} + + + +void SND_FmodDevice::StartUsingDSP() +{ + m_dspunit = FSOUND_DSP_GetFFTUnit(); + + FSOUND_DSP_SetActive(m_dspunit, true); +} + + + +float* SND_FmodDevice::GetSpectrum() +{ + m_spectrum = FSOUND_DSP_GetSpectrum(); + + return m_spectrum; +} + + + +void SND_FmodDevice::StopUsingDSP() +{ + if (m_dspunit) + FSOUND_DSP_SetActive(m_dspunit, false); +} diff --git a/intern/SoundSystem/fmod/SND_FmodDevice.h b/intern/SoundSystem/fmod/SND_FmodDevice.h new file mode 100644 index 00000000000..d44cfb9d937 --- /dev/null +++ b/intern/SoundSystem/fmod/SND_FmodDevice.h @@ -0,0 +1,106 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_FMODDEVICE +#define SND_FMODDEVICE + +#include "fmod.h" +#include "SND_AudioDevice.h" +#include "SoundDefines.h" + +class SND_FmodDevice : public SND_AudioDevice +{ +public: + SND_FmodDevice(); + ~SND_FmodDevice(); + + SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size); + + void InitListener(); + void SetListenerGain(float gain) const; + void SetDopplerVelocity(MT_Scalar dopplervelocity) const; + void SetDopplerFactor(MT_Scalar dopplerfactor) const; + void SetListenerRollOffFactor(MT_Scalar rollofffactor) const; + + void MakeCurrent() const; + void NextFrame() const; + void UseCD() const; + + void SetObjectBuffer(int id, unsigned int buffer); + int GetPlayState(int id); + void PlayObject(int id); + void StopObject(int id) const; + void StopAllObjects(); + void PauseObject(int id) const; + + void SetObjectLoop(int id, unsigned int loopmode) const; + void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const; + void SetObjectPitch(int id, MT_Scalar pitch) const; + void SetObjectGain(int id, MT_Scalar gain) const; + void SetObjectMinGain(int id, MT_Scalar mingain) const; + void SetObjectMaxGain(int id, MT_Scalar maxgain) const; + void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const; + void SetObjectReferenceDistance(int id, MT_Scalar distance) const; + + void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const; + void ObjectIs2D(int id) const; + + void PlayCD(int track) const; + void PauseCD(bool pause) const; + void StopCD() const; + void SetCDPlaymode(int playmode) const; + void SetCDGain(MT_Scalar gain) const; + + void StartUsingDSP(); + float* GetSpectrum(); + void StopUsingDSP(); + +private: + FSOUND_SAMPLE* m_buffers[NUM_BUFFERS]; + FSOUND_SAMPLE* m_sources[NUM_SOURCES]; + FSOUND_DSPUNIT* m_dspunit; + int m_frequencies[NUM_SOURCES]; + int m_max_channels; + int m_num_hardware_channels; + int m_num_software_channels; + int m_channels[NUM_SOURCES]; + float* m_spectrum; +}; + +#endif //SND_FMODDEVICE + diff --git a/intern/SoundSystem/intern/Makefile b/intern/SoundSystem/intern/Makefile new file mode 100644 index 00000000000..cf793bdba25 --- /dev/null +++ b/intern/SoundSystem/intern/Makefile @@ -0,0 +1,49 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = SoundSystem +DIR = $(OCGDIR)/intern/SoundSystem + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_FMOD)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../../../source/blender/include +CPPFLAGS += -I../dummy +CPPFLAGS += -I../fmod +CPPFLAGS += -I../openal +CPPFLAGS += -I.. +CPPFLAGS += -I. diff --git a/intern/SoundSystem/intern/SND_AudioDevice.cpp b/intern/SoundSystem/intern/SND_AudioDevice.cpp new file mode 100644 index 00000000000..828edaed4b4 --- /dev/null +++ b/intern/SoundSystem/intern/SND_AudioDevice.cpp @@ -0,0 +1,245 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_AudioDevice.h" +#include "SND_SoundObject.h" + +#ifdef WIN32 +// This warning tells us about truncation of __long__ stl-generated names. +// It can occasionally cause DevStudio to have internal compiler warnings. +#pragma warning( disable : 4786 ) +#endif + + +SND_AudioDevice::SND_AudioDevice() +{ + m_wavecache = NULL; + m_audio = false; + + for (int i = 0; i < NUM_SOURCES; i++) + { + m_idObjectArray[i] = new SND_IdObject(); + m_idObjectArray[i]->SetId(i); + m_idObjectArray[i]->SetSoundObject(NULL); + m_idObjectList.addTail(m_idObjectArray[i]); + } +} + + + +SND_AudioDevice::~SND_AudioDevice() +{ + for (int i = 0; i < NUM_SOURCES; i++) + { + delete m_idObjectArray[i]; + m_idObjectArray[i] = NULL; + } + + if (m_wavecache) + { + delete m_wavecache; + m_wavecache = NULL; + } +} + + + +bool SND_AudioDevice::IsInitialized() +{ + return m_audio; +} + + + +SND_WaveCache* SND_AudioDevice::GetWaveCache() const +{ + return m_wavecache; +} + + + +/* seeks an unused id and returns it */ +bool SND_AudioDevice::GetNewId(SND_SoundObject* pObject) +{ +#ifdef ONTKEVER + printf("SND_AudioDevice::GetNewId\n"); +#endif + + bool result = false; + + // first, get the oldest (the first) idobject + SND_IdObject* pIdObject = (SND_IdObject*)m_idObjectList.getHead(); + + if (pIdObject->isTail()) + { + } + else + { + // find the first id object which doesn't have a high priority soundobject + bool ThisSoundMustStay = false; + bool OutOfIds = false; + + do + { + // if no soundobject present, it's seat may be taken + if (pIdObject->GetSoundObject()) + { + // and also if it ain't highprio + if (pIdObject->GetSoundObject()->IsHighPriority()) + { + ThisSoundMustStay = true; + pIdObject = (SND_IdObject*)pIdObject->getNext(); + + // if the last one is a priority sound too, then there are no id's left + // and we won't add any new sounds + if (pIdObject->isTail()) + OutOfIds = true; + } + else + { + ThisSoundMustStay = false; + } + } + else + { + ThisSoundMustStay = false; + } + + } while (ThisSoundMustStay && !OutOfIds); + + if (!OutOfIds) + { + SND_SoundObject* oldobject = pIdObject->GetSoundObject(); + + // revoke the old object if present + if (oldobject) + { +#ifdef ONTKEVER + printf("oldobject: %x\n", oldobject); +#endif + RevokeSoundObject(oldobject); + } + + // set the new soundobject into the idobject + pIdObject->SetSoundObject(pObject); + + // set the id into the soundobject + int id = pIdObject->GetId(); + pObject->SetId(id); + + // connect the new id to the buffer the sample is stored in + SetObjectBuffer(id, pObject->GetBuffer()); + + // remove the idobject from the list and add it in the back again + pIdObject->remove(); + m_idObjectList.addTail(pIdObject); + + result = true; + } + } + + return result; +} + + + +void SND_AudioDevice::ClearId(SND_SoundObject* pObject) +{ +#ifdef ONTKEVER + printf("SND_AudioDevice::ClearId\n"); +#endif + + if (pObject) + { + int id = pObject->GetId(); + + if (id != -1) + { + // lets get the idobject belonging to the soundobject + SND_IdObject* pIdObject = m_idObjectArray[id]; + SND_SoundObject* oldobject = pIdObject->GetSoundObject(); + + if (oldobject) + { + RevokeSoundObject(oldobject); + + // clear the idobject from the soundobject + pIdObject->SetSoundObject(NULL); + } + + // remove the idobject and place it in front + pIdObject->remove(); + m_idObjectList.addHead(pIdObject); + } + } +} + + + +void SND_AudioDevice::RevokeSoundObject(SND_SoundObject* pObject) +{ +#ifdef ONTKEVER + printf("SND_AudioDevice::RevokeSoundObject\n"); +#endif + + // stop the soundobject + int id = pObject->GetId(); + + if (id >= 0 && id < NUM_SOURCES) + { + StopObject(id); + + // remove the object from the 'activelist' + pObject->SetActive(false); + +#ifdef ONTKEVER + printf("pObject->remove();\n"); +#endif + } + + // make sure its id is invalid + pObject->SetId(-1); +} + +/* +void SND_AudioDevice::RemoveSample(const char* filename) +{ + if (m_wavecache) + m_wavecache->RemoveSample(filename); +} +*/ + +void SND_AudioDevice::RemoveAllSamples() +{ + if (m_wavecache) + m_wavecache->RemoveAllSamples(); +} + diff --git a/intern/SoundSystem/intern/SND_AudioDevice.h b/intern/SoundSystem/intern/SND_AudioDevice.h new file mode 100644 index 00000000000..6edd52955ae --- /dev/null +++ b/intern/SoundSystem/intern/SND_AudioDevice.h @@ -0,0 +1,118 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_AUDIODEVICE +#define SND_AUDIODEVICE + +#include "SND_IAudioDevice.h" +#include "SoundDefines.h" +#include "SND_IdObject.h" + +class SND_AudioDevice : public SND_IAudioDevice +{ +public: + SND_AudioDevice(); + virtual ~SND_AudioDevice(); + + virtual bool IsInitialized(); + + SND_WaveCache* GetWaveCache() const; + + bool GetNewId(SND_SoundObject* pObject); + void ClearId(SND_SoundObject* pObject); + + void UseCD() const {}; + + /* to be implemented in derived class + + virtual SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size) =0; + */ +// void RemoveSample(const char* filename); + void RemoveAllSamples(); + + /* to be implemented in derived class + + virtual void InitListener()=0; + virtual void SetListenerGain(float gain) const =0; + virtual void SetDopplerVelocity(MT_Scalar dopplervelocity) const =0; + virtual void SetDopplerFactor(MT_Scalar dopplerfactor) const =0; + virtual void SetListenerRollOffFactor(MT_Scalar rollofffactor) const =0; + + virtual void MakeCurrent() const =0; + + virtual void UpdateDevice() const =0; + + virtual void SetObjectBuffer(int id, unsigned int buffer)=0; + virtual int GetPlayState(int id)=0; + virtual void PlayObject(int id)=0; + virtual void StopObject(int id) const =0; + virtual void StopAllObjects()=0; + virtual void PauseObject(int id) const =0; + + virtual void SetObjectLoop(int id, bool loop) const =0; + virtual void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const =0; + virtual void SetObjectPitch(int id, MT_Scalar pitch) const =0; + virtual void SetObjectGain(int id, MT_Scalar gain) const =0; + virtual void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const =0; + virtual void SetObjectMinGain(int id, MT_Scalar mingain) const =0; + virtual void SetObjectMaxGain(int id, MT_Scalar maxgain) const =0; + virtual void SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const =0; + + virtual void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const =0; + virtual void ObjectIs2D(int id) const =0; + + virtual void PlayCD(int track) const =0; + virtual void PauseCD(bool pause) const =0; + virtual void StopCD() const =0; + virtual void SetCDPlaymode(int playmode) const =0; + virtual void SetCDGain(MT_Scalar gain) const =0; + virtual float* GetSpectrum() =0; + */ + +protected: + bool m_audio; + GEN_List m_idObjectList; + SND_IdObject* m_idObjectArray[NUM_SOURCES]; + SND_WaveCache* m_wavecache; + +private: + void RevokeSoundObject(SND_SoundObject* pObject); +}; + +#endif //SND_AUDIODEVICE + diff --git a/intern/SoundSystem/intern/SND_C-api.cpp b/intern/SoundSystem/intern/SND_C-api.cpp new file mode 100644 index 00000000000..1b03d66562c --- /dev/null +++ b/intern/SoundSystem/intern/SND_C-api.cpp @@ -0,0 +1,395 @@ +/* + * SND_C-Api.cpp + * + * C Api for soundmodule + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "SND_C-api.h" +#include "SND_DeviceManager.h" +#include "SND_Scene.h" + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + + + +void SND_SetDeviceType(int device_type) +{ + SND_DeviceManager::SetDeviceType(device_type); +} + + + +SND_AudioDeviceInterfaceHandle SND_GetAudioDevice() +{ + SND_IAudioDevice* audiodevice = NULL; + + SND_DeviceManager::Subscribe(); + audiodevice = SND_DeviceManager::Instance(); + + if (!audiodevice->IsInitialized()) + { + SND_DeviceManager::SetDeviceType(snd_e_dummydevice); + audiodevice = SND_DeviceManager::Instance(); + } + + return (SND_AudioDeviceInterfaceHandle)audiodevice; +} + + + +void SND_ReleaseDevice() +{ + SND_DeviceManager::Unsubscribe(); +} + + + +int SND_IsPlaybackWanted(SND_SceneHandle scene) +{ + assert(scene); + bool result = ((SND_Scene*)scene)->IsPlaybackWanted(); + + return (int)result; +} + + + +// create a scene +SND_SceneHandle SND_CreateScene(SND_AudioDeviceInterfaceHandle audiodevice) +{ + // initialize sound scene and object + SND_Scene* scene = new SND_Scene((SND_IAudioDevice*)audiodevice); + + return (SND_SceneHandle)scene; +} + + + +void SND_DeleteScene(SND_SceneHandle scene) +{ + assert(scene); + delete (SND_Scene*)scene; +} + + + +int SND_AddSample(SND_SceneHandle scene, + const char* filename, + void* memlocation, + int size) +{ + assert(scene); + assert(memlocation); + int buffer = ((SND_Scene*)scene)->LoadSample(filename, memlocation, size); + + return buffer; +} + + + +void SND_RemoveAllSamples(SND_SceneHandle scene) +{ + assert(scene); + ((SND_Scene*)scene)->RemoveAllSamples(); +} + + + +int SND_CheckBuffer(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + int result = (int)((SND_Scene*)scene)->CheckBuffer((SND_SoundObject*)object); + + return result; +} + + + +void SND_AddSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->AddObject((SND_SoundObject *)object); +} + + + +void SND_RemoveSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->DeleteObject((SND_SoundObject *)object); +} + + + +void SND_RemoveAllSounds(SND_SceneHandle scene) +{ + assert(scene); + ((SND_Scene*)scene)->RemoveAllObjects(); +} + + + +void SND_StopAllSounds(SND_SceneHandle scene) +{ + assert(scene); + ((SND_Scene*)scene)->StopAllObjects(); +} + + + +void SND_Proceed(SND_AudioDeviceInterfaceHandle audiodevice, SND_SceneHandle scene) +{ + assert(scene); + ((SND_Scene*)scene)->Proceed(); + ((SND_IAudioDevice*)audiodevice)->NextFrame(); +} + + + +SND_ListenerHandle SND_GetListener(SND_SceneHandle scene) +{ + assert(scene); + return (SND_ListenerHandle)((SND_Scene*)scene)->GetListener(); +} + + + +void SND_SetListenerGain(SND_SceneHandle scene, double gain) +{ + assert(scene); + SND_SoundListener* listener = ((SND_Scene*)scene)->GetListener(); + listener->SetGain((MT_Scalar)gain); +} + + + +void SND_SetDopplerFactor(SND_SceneHandle scene, double dopplerfactor) +{ + assert(scene); + SND_SoundListener* listener = ((SND_Scene*)scene)->GetListener(); + listener->SetDopplerFactor(dopplerfactor); +} + + + +void SND_SetDopplerVelocity(SND_SceneHandle scene, double dopplervelocity) +{ + assert(scene); + SND_SoundListener* listener = ((SND_Scene*)scene)->GetListener(); + listener->SetDopplerVelocity(dopplervelocity); +} + + + +// Object instantiation +SND_ObjectHandle SND_CreateSound() +{ + return (SND_ObjectHandle)new SND_SoundObject(); +} + + + +void SND_DeleteSound(SND_ObjectHandle object) +{ + assert(object); + delete (SND_SoundObject*)object; +} + + + +// Object control +void SND_StartSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->AddActiveObject((SND_SoundObject*)object, 0); +} + + + +void SND_StopSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->RemoveActiveObject((SND_SoundObject*)object); +} + + + +void SND_PauseSound(SND_SceneHandle scene, SND_ObjectHandle object) +{ + assert(scene); + assert(object); + ((SND_Scene*)scene)->RemoveActiveObject((SND_SoundObject*)object); +} + + + +void SND_SetSampleName(SND_ObjectHandle object, char* samplename) +{ + assert(object); + STR_String name = samplename; + ((SND_SoundObject*)object)->SetSampleName(name); +} + + + +void SND_SetGain(SND_ObjectHandle object, double gain) +{ + assert(object); + ((SND_SoundObject*)object)->SetGain(gain); +} + + + +void SND_SetMinimumGain(SND_ObjectHandle object, double minimumgain) +{ + assert(object); + ((SND_SoundObject*)object)->SetMinGain(minimumgain); +} + + + +void SND_SetMaximumGain(SND_ObjectHandle object, double maximumgain) +{ + assert(object); + ((SND_SoundObject*)object)->SetMaxGain(maximumgain); +} + + + +void SND_SetRollOffFactor(SND_ObjectHandle object, double rollofffactor) +{ + assert(object); + ((SND_SoundObject*)object)->SetRollOffFactor(rollofffactor); +} + + + +void SND_SetReferenceDistance(SND_ObjectHandle object, double referencedistance) +{ + assert(object); + ((SND_SoundObject*)object)->SetReferenceDistance(referencedistance); +} + + + +void SND_SetPitch(SND_ObjectHandle object, double pitch) +{ + assert(object); + ((SND_SoundObject*)object)->SetPitch(pitch); +} + + + +void SND_SetPosition(SND_ObjectHandle object, double* position) +{ + assert(object); + ((SND_SoundObject*)object)->SetPosition(position); +} + + + +void SND_SetVelocity(SND_ObjectHandle object, double* velocity) +{ + assert(object); + ((SND_SoundObject*)object)->SetVelocity(velocity); +} + + + +void SND_SetOrientation(SND_ObjectHandle object, double* orientation) +{ + assert(object); + ((SND_SoundObject*)object)->SetOrientation(orientation); +} + + + +void SND_SetLoopMode(SND_ObjectHandle object, int loopmode) +{ + assert(object); + ((SND_SoundObject*)object)->SetLoopMode(loopmode); +} + + + +void SND_SetLoopPoints(SND_ObjectHandle object, unsigned int loopstart, unsigned int loopend) +{ + assert(object); + ((SND_SoundObject*)object)->SetLoopStart(loopstart); + ((SND_SoundObject*)object)->SetLoopEnd(loopend); +} + + + +float SND_GetGain(SND_ObjectHandle object) +{ + assert(object); + MT_Scalar gain = ((SND_SoundObject*)object)->GetGain(); + return (float) gain; +} + + + +float SND_GetPitch(SND_ObjectHandle object) +{ + assert(object); + MT_Scalar pitch = ((SND_SoundObject*)object)->GetPitch(); + return (float) pitch; +} + + + +int SND_GetLoopMode(SND_ObjectHandle object) +{ + assert(object); + return ((SND_SoundObject*)object)->GetLoopMode(); +} + + + +int SND_GetPlaystate(SND_ObjectHandle object) +{ + assert(object); + return ((SND_SoundObject*)object)->GetPlaystate(); +} diff --git a/intern/SoundSystem/intern/SND_CDObject.cpp b/intern/SoundSystem/intern/SND_CDObject.cpp new file mode 100644 index 00000000000..e4fcdfaceeb --- /dev/null +++ b/intern/SoundSystem/intern/SND_CDObject.cpp @@ -0,0 +1,185 @@ +/* + * SND_CDObject.cpp + * + * Implementation for CD playback + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_CDObject.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_CDObject* SND_CDObject::m_instance = NULL; + +bool SND_CDObject::CreateSystem() +{ + bool result = false; + + if (!m_instance) + { + m_instance = new SND_CDObject(); + result = true; + } + + return result; +} + + + +bool SND_CDObject::DisposeSystem() +{ + bool result = false; + + if (m_instance) + { + delete m_instance; + m_instance = NULL; + result = true; + } + + return result; +} + + + +SND_CDObject* SND_CDObject::Instance() +{ + return m_instance; +} + + + +SND_CDObject::SND_CDObject() +{ + m_gain = 1; + m_playmode = SND_CD_ALL; + m_track = 1; + m_playstate = SND_STOPPED; + m_used = false; + + // don't set the cd standard on modified: + // if not used, we don't wanna touch it (performance) + m_modified = false; +} + + + +SND_CDObject::~SND_CDObject() +{ +} + + + +void SND_CDObject::SetGain(MT_Scalar gain) +{ + m_gain = gain; + m_modified = true; +} + + + +void SND_CDObject::SetPlaymode(int playmode) +{ + m_playmode = playmode; +} + + + +void SND_CDObject::SetPlaystate(int playstate) +{ + m_playstate = playstate; +} + + + +void SND_CDObject::SetTrack(int track) +{ + m_track = track; +} + + + +int SND_CDObject::GetTrack() const +{ + return m_track; +} + + + +MT_Scalar SND_CDObject::GetGain() const +{ + return m_gain; +} + + +int SND_CDObject::GetPlaystate() const +{ + return m_playstate; +} + + + +bool SND_CDObject::IsModified() const +{ + return m_modified; +} + + + +void SND_CDObject::SetModified(bool modified) +{ + m_modified = modified; +} + + + +int SND_CDObject::GetPlaymode() const +{ + return m_playmode; +} + + + +void SND_CDObject::SetUsed() +{ + m_used = true; +} + + + +bool SND_CDObject::GetUsed() +{ + return m_used; +} + diff --git a/intern/SoundSystem/intern/SND_DeviceManager.cpp b/intern/SoundSystem/intern/SND_DeviceManager.cpp new file mode 100644 index 00000000000..37487686d71 --- /dev/null +++ b/intern/SoundSystem/intern/SND_DeviceManager.cpp @@ -0,0 +1,144 @@ +/* + * SND_DeviceManager.h + * + * singleton for creating, switching and deleting audiodevices + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "SND_DeviceManager.h" +#include "SND_DependKludge.h" +#include "SND_DummyDevice.h" +#ifdef USE_FMOD +#include "SND_FmodDevice.h" +#endif +#ifdef USE_OPENAL +#include "SND_OpenALDevice.h" +#endif + +SND_IAudioDevice* SND_DeviceManager::m_instance = NULL; +int SND_DeviceManager::m_subscriptions = 0; + +#ifdef USE_OPENAL +int SND_DeviceManager::m_device_type = snd_e_openaldevice; +#else +# ifdef USE_FMOD +int SND_DeviceManager::m_device_type = snd_e_fmoddevice; +# else +int SND_DeviceManager::m_device_type = snd_e_dummydevice; +# endif +#endif + +void SND_DeviceManager::Subscribe() +{ + ++m_subscriptions; +} + + + +void SND_DeviceManager::Unsubscribe() +{ + --m_subscriptions; + + // only release memory if there is a m_instance but no subscriptions left + if (m_subscriptions == 0 && m_instance) + { + delete m_instance; + m_instance = NULL; + } + + if (m_subscriptions < 0) + m_subscriptions = 0; +} + + + +SND_IAudioDevice* SND_DeviceManager::Instance() +{ + // only give away an instance if there are subscriptions + if (m_subscriptions) + { + // if there's no instance yet, set and create a new one + if (m_instance == NULL) + { + SetDeviceType(m_device_type); + } + + return m_instance; + } + else + { + return NULL; + } +} + + + +void SND_DeviceManager::SetDeviceType(int device_type) +{ + // if we want to change devicetype, first delete the old one + if (m_instance) + { + delete m_instance; + m_instance = NULL; + } + + // let's create the chosen device + switch (device_type) + { +#ifdef USE_FMOD + case snd_e_fmoddevice: + { + m_instance = new SND_FmodDevice(); + m_device_type = device_type; + break; + } +#endif +#ifdef USE_OPENAL + case snd_e_openaldevice: + { + m_instance = new SND_OpenALDevice(); + m_device_type = device_type; + break; + } +#endif + default: + { + m_instance = new SND_DummyDevice(); + m_device_type = device_type; + break; + } + } +} diff --git a/intern/SoundSystem/intern/SND_IdObject.cpp b/intern/SoundSystem/intern/SND_IdObject.cpp new file mode 100644 index 00000000000..eac95de64a4 --- /dev/null +++ b/intern/SoundSystem/intern/SND_IdObject.cpp @@ -0,0 +1,79 @@ +/* + * SND_IdObject.cpp + * + * Object for storing runtime data, like id's, soundobjects etc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_IdObject.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_IdObject::SND_IdObject() +{ +} + + + +SND_IdObject::~SND_IdObject() +{ +} + + + +SND_SoundObject* SND_IdObject::GetSoundObject() +{ + return m_soundObject; +} + + + +void SND_IdObject::SetSoundObject(SND_SoundObject* pObject) +{ + m_soundObject = pObject; +} + + + +int SND_IdObject::GetId() +{ + return m_id; +} + + + +void SND_IdObject::SetId(int id) +{ + m_id = id; +} diff --git a/intern/SoundSystem/intern/SND_IdObject.h b/intern/SoundSystem/intern/SND_IdObject.h new file mode 100644 index 00000000000..fc9608b97bf --- /dev/null +++ b/intern/SoundSystem/intern/SND_IdObject.h @@ -0,0 +1,61 @@ +/* + * SND_IdObject.h + * + * Object for storing runtime data, like id's, soundobjects etc + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __SND_IDOBJECT_H +#define __SND_IDOBJECT_H + +#include "SND_SoundObject.h" +#include "GEN_List.h" +#include "SoundDefines.h" + +class SND_IdObject : public GEN_Link +{ + SND_SoundObject* m_soundObject; + int m_id; + +public: + SND_IdObject(); + virtual ~SND_IdObject(); + + SND_SoundObject* GetSoundObject(); + void SetSoundObject(SND_SoundObject* pObject); + + int GetId(); + void SetId(int id); +}; + +#endif //__SND_OBJECT_H + diff --git a/intern/SoundSystem/intern/SND_Scene.cpp b/intern/SoundSystem/intern/SND_Scene.cpp new file mode 100644 index 00000000000..ffb1cd44108 --- /dev/null +++ b/intern/SoundSystem/intern/SND_Scene.cpp @@ -0,0 +1,563 @@ +/* +* SND_Scene.cpp +* +* The scene for sounds. +* +* $Id$ +* + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // Get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_Scene.h" +#include "SND_DependKludge.h" +#include "SND_IAudioDevice.h" + +#include +#include + +//static unsigned int tijd = 0; + +SND_Scene::SND_Scene(SND_IAudioDevice* audiodevice) + : m_audiodevice(audiodevice) +{ + if (m_audiodevice) + m_wavecache = m_audiodevice->GetWaveCache(); + + if (!m_wavecache || !audiodevice) + { + m_audio = false; + } + else + { + //if so, go ahead! + m_audio = true; +#ifdef ONTKEVER + printf("SND_Scene::SND_Scene() m_audio == true\n"); +#endif + m_audiodevice->InitListener(); + } + + IsPlaybackWanted(); +} + + + +SND_Scene::~SND_Scene() +{ + StopAllObjects(); +} + + + +// check if audioplayback is wanted +bool SND_Scene::IsPlaybackWanted() +{ + /* Removed the functionality for checking if noaudio was provided on */ + /* the commandline. */ + if (m_audiodevice && m_wavecache) + { + m_audioplayback = true; + } + else + { + StopAllObjects(); + m_audioplayback = false; + } + + return m_audioplayback; +} + + + +int SND_Scene::LoadSample(const STR_String& samplename, + void* memlocation, + int size) +{ + int result = -1; + + if (m_audiodevice) + { + SND_WaveSlot* waveslot = m_audiodevice->LoadSample(samplename, memlocation, size); + + if (waveslot) + result = waveslot->GetBuffer(); + } + + return result; +} + + + +void SND_Scene::RemoveAllSamples() +{ + if (m_audio && m_audiodevice) + m_audiodevice->RemoveAllSamples(); +} + + + +bool SND_Scene::CheckBuffer(SND_SoundObject* pObject) +{ + bool result = false; + + if (pObject && m_wavecache) + { + SND_WaveSlot* waveslot = m_wavecache->GetWaveSlot(pObject->GetSampleName()); + + if (waveslot) + { + pObject->SetBuffer(waveslot->GetBuffer()); + + result = true; + } + } + + return result; +} + + + +bool SND_Scene::IsSampleLoaded(STR_String& samplename) +{ + bool result = false; + + if (samplename && m_wavecache) + { + SND_WaveSlot* waveslot = m_wavecache->GetWaveSlot(samplename); + + if (waveslot && waveslot->IsLoaded()) + result = true; + } + + return result; +} + + + +void SND_Scene::AddObject(SND_SoundObject* pObject) +{ + if (m_audio) + { + STR_String samplename = pObject->GetSampleName(); + SND_WaveSlot* slot = NULL; + + // don't add the object if no valid sample is referenced + if (samplename != "") + { + // check if the sample is already loaded + slot = m_wavecache->GetWaveSlot(samplename); + } + + if (slot) + { + pObject->SetBuffer(slot->GetBuffer()); + + // needed for expected lifespan of the sample, but ain't necesary anymore i think + MT_Scalar samplelength = slot->GetNumberOfSamples(); + MT_Scalar samplerate = slot->GetSampleRate(); + MT_Scalar soundlength = samplelength/samplerate; + pObject->SetLength(soundlength); + + // add the object to the list + m_soundobjects.insert((SND_SoundObject*)pObject); + } + } +} + + + +void SND_Scene::SetListenerTransform(const MT_Vector3& pos, + const MT_Vector3& vel, + const MT_Matrix3x3& ori) +{ + if (m_audio) + { + GetListener()->SetPosition(pos); + GetListener()->SetVelocity(vel); + GetListener()->SetOrientation(ori); + } +} + + + +void SND_Scene::UpdateListener() +{ + // process the listener if modified + if (m_listener.IsModified()) + { + m_audiodevice->SetListenerGain(m_listener.GetGain()); + + // fmod doesn't support dopplervelocity, so just use the dopplerfactor instead +#ifdef USE_FMOD + m_audiodevice->SetDopplerFactor(m_listener.GetDopplerVelocity()); +#else + m_audiodevice->SetDopplerVelocity(m_listener.GetDopplerVelocity()); + m_audiodevice->SetDopplerFactor(m_listener.GetDopplerFactor()); +#endif + m_listener.SetModified(false); + } +} + + + +void SND_Scene::AddActiveObject(SND_SoundObject* pObject, MT_Scalar curtime) +{ + if (m_audio) + { + if (pObject) + { +#ifdef ONTKEVER + printf("SND_Scene::AddActiveObject\n"); +#endif + + // first check if the object is already on the list + if (pObject->IsActive()) + { + pObject->SetTimeStamp(curtime); + pObject->StartSound(); + } + else + { + pObject->SetTimeStamp(curtime); + + // compute the expected lifespan + pObject->SetLifeSpan(); + + // lets give the new active-to-be object an id + if (m_audiodevice->GetNewId(pObject)) + { + // and add the object + m_activeobjects.addTail(pObject); + pObject->StartSound(); + pObject->SetActive(true); + } + } + } + } +} + + + +void SND_Scene::RemoveActiveObject(SND_SoundObject* pObject) +{ + if (m_audio) + { + if (pObject) + { +#ifdef ONTKEVER + printf("SND_Scene::RemoveActiveObject\n"); +#endif + // if inactive, remove it from the list + if (pObject->IsActive()) + { + // first make sure it is stopped + m_audiodevice->ClearId(pObject); + } + } + } +} + + + +void SND_Scene::UpdateActiveObects() +{ +// ++tijd; + + SND_SoundObject* pObject; + // update only the objects that need to be updated + for (pObject = (SND_SoundObject*)m_activeobjects.getHead(); + !pObject->isTail(); + pObject = (SND_SoundObject*)pObject->getNext()) + { + int id = pObject->GetId(); + + if (id >= 0) + { +#ifdef USE_FMOD + // fmod wants these set before playing the sample + if (pObject->IsModified()) + { + m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode()); + m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd()); + } + + // ok, properties Set. now see if it must play + if (pObject->GetPlaystate() == SND_MUST_PLAY) + { + m_audiodevice->PlayObject(id); + pObject->SetPlaystate(SND_PLAYING); + pObject->InitRunning(); +// printf("start play: %d\n", tijd); + } +#endif + if (pObject->Is3D()) + { + // Get the global positions and velocity vectors + // of the listener and soundobject + MT_Vector3 op = pObject->GetPosition(); + MT_Vector3 lp = m_listener.GetPosition(); + MT_Vector3 position = op - lp; + + // Calculate relative velocity in global coordinates + // of the sound with respect to the listener. + MT_Vector3 ov = pObject->GetVelocity(); + MT_Vector3 lv = m_listener.GetVelocity(); + MT_Vector3 velocity = ov - lv; + + // Now map the object position and velocity into + // the local coordinates of the listener. + MT_Matrix3x3 lo = m_listener.GetOrientation(); + + MT_Vector3 local_sound_pos = position * lo; + MT_Vector3 local_sound_vel = velocity * lo; + + m_audiodevice->SetObjectTransform( + id, + local_sound_pos, + local_sound_vel, + pObject->GetOrientation(), // make relative to listener! + lp, + pObject->GetRollOffFactor()); + } + else + { + m_audiodevice->ObjectIs2D(id); + } + + // update the situation + if (pObject->IsModified()) + { + m_audiodevice->SetObjectPitch(id, pObject->GetPitch()); + m_audiodevice->SetObjectGain(id, pObject->GetGain()); + m_audiodevice->SetObjectMinGain(id, pObject->GetMinGain()); + m_audiodevice->SetObjectMaxGain(id, pObject->GetMaxGain()); + m_audiodevice->SetObjectReferenceDistance(id, pObject->GetReferenceDistance()); + m_audiodevice->SetObjectRollOffFactor(id, pObject->GetRollOffFactor()); + m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode()); + m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd()); + pObject->SetModified(false); + } + + pObject->AddRunning(); + +#ifdef ONTKEVER + STR_String naam = pObject->GetObjectName(); + STR_String sample = pObject->GetSampleName(); + + int id = pObject->GetId(); + int buffer = pObject->GetBuffer(); + + float gain = pObject->GetGain(); + float pitch = pObject->GetPitch(); + float timestamp = pObject->GetTimestamp(); + + printf("naam: %s, sample: %s \n", naam.Ptr(), sample.Ptr()); + printf("id: %d, buffer: %d \n", id, buffer); + printf("gain: %f, pitch: %f, ts: %f \n\n", gain, pitch, timestamp); +#endif +#ifdef USE_OPENAL + // ok, properties Set. now see if it must play + if (pObject->GetPlaystate() == SND_MUST_PLAY) + { + m_audiodevice->PlayObject(id); + pObject->SetPlaystate(SND_PLAYING); + //break; + } +#endif + + // check to see if the sound is still playing + // if not: release its id + int playstate = m_audiodevice->GetPlayState(id); +#ifdef ONTKEVER + if (playstate != 2) + printf("%d - ",playstate); +#endif + + if ((playstate == SND_STOPPED) && !pObject->GetLoopMode()) + { + RemoveActiveObject(pObject); + } + } + } +} + + + +void SND_Scene::UpdateCD() +{ + if (m_audiodevice) + { + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD) + { + int playstate = pCD->GetPlaystate(); + + switch (playstate) + { + case SND_MUST_PLAY: + { + // initialize the cd only when you need it + m_audiodevice->SetCDGain(pCD->GetGain()); + m_audiodevice->SetCDPlaymode(pCD->GetPlaymode()); + m_audiodevice->PlayCD(pCD->GetTrack()); + pCD->SetPlaystate(SND_PLAYING); + pCD->SetUsed(); + break; + } + case SND_MUST_PAUSE: + { + m_audiodevice->PauseCD(true); + pCD->SetPlaystate(SND_PAUSED); + break; + } + case SND_MUST_RESUME: + { + m_audiodevice->PauseCD(false); + pCD->SetPlaystate(SND_PLAYING); + break; + } + case SND_MUST_STOP: + { + m_audiodevice->StopCD(); + pCD->SetPlaystate(SND_STOPPED); + break; + } + default: + { + } + } + + // this one is only for realtime modifying settings + if (pCD->IsModified()) + { + m_audiodevice->SetCDGain(pCD->GetGain()); + pCD->SetModified(false); + } + } + } +} + + + +void SND_Scene::Proceed() +{ + if (m_audio && m_audioplayback) + { + m_audiodevice->MakeCurrent(); + + UpdateListener(); + UpdateActiveObects(); + UpdateCD(); + +// m_audiodevice->UpdateDevice(); + } +} + + +void SND_Scene::DeleteObject(SND_SoundObject* pObject) +{ +#ifdef ONTKEVER + printf("SND_Scene::DeleteObject\n"); +#endif + + if (pObject) + { + if (m_audiodevice) + m_audiodevice->ClearId(pObject); + + // must remove object from m_activeList + std::set::iterator set_it; + set_it = m_soundobjects.find(pObject); + + if (set_it != m_soundobjects.end()) + m_soundobjects.erase(set_it); + + // release the memory + delete pObject; + pObject = NULL; + } +} + + + +void SND_Scene::RemoveAllObjects() +{ +#ifdef ONTKEVER + printf("SND_Scene::RemoveAllObjects\n"); +#endif + + StopAllObjects(); + + std::set::iterator it = m_soundobjects.begin(); + + while (it != m_soundobjects.end()) + { + delete (*it); + it++; + } + + m_soundobjects.clear(); +} + + + +void SND_Scene::StopAllObjects() +{ + if (m_audio) + { +#ifdef ONTKEVER + printf("SND_Scene::StopAllObjects\n"); +#endif + + SND_SoundObject* pObject; + + for (pObject = (SND_SoundObject*)m_activeobjects.getHead(); + !pObject->isTail(); + pObject = (SND_SoundObject*)pObject->getNext()) + { + m_audiodevice->ClearId(pObject); + } + } +} + + + +SND_SoundListener* SND_Scene::GetListener() +{ + return &m_listener; +} diff --git a/intern/SoundSystem/intern/SND_SoundListener.cpp b/intern/SoundSystem/intern/SND_SoundListener.cpp new file mode 100644 index 00000000000..0209ac5683a --- /dev/null +++ b/intern/SoundSystem/intern/SND_SoundListener.cpp @@ -0,0 +1,188 @@ +/* + * SND_SoundListener.cpp + * + * A SoundListener is for sound what a camera is for vision. + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_SoundListener.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_SoundListener::SND_SoundListener() +{ + m_modified = true; + m_gain = 1.0; + m_dopplerfactor = 1.0; + m_dopplervelocity = 1.0; + m_scale = 1.0; + m_position[0] = 0.0; + m_position[1] = 0.0; + m_position[2] = 0.0; + m_velocity[0] = 0.0; + m_velocity[1] = 0.0; + m_velocity[2] = 0.0; + m_orientation[0][0] = 1.0; + m_orientation[0][1] = 0.0; + m_orientation[0][2] = 0.0; + m_orientation[1][0] = 0.0; + m_orientation[1][1] = 1.0; + m_orientation[1][2] = 0.0; + m_orientation[2][0] = 0.0; + m_orientation[2][1] = 0.0; + m_orientation[2][2] = 1.0; +} + + +SND_SoundListener::~SND_SoundListener() +{ + ; /* intentionally empty */ + +} + + + +void SND_SoundListener::SetGain(MT_Scalar gain) +{ + m_gain = gain; + m_modified = true; +} + + + +void SND_SoundListener::SetPosition (const MT_Vector3& pos) +{ + m_position = pos; +} + + + +void SND_SoundListener::SetVelocity(const MT_Vector3& vel) +{ + m_velocity = vel; +} + + + +void SND_SoundListener::SetOrientation(const MT_Matrix3x3& ori) +{ + m_orientation = ori; +} + + + +void SND_SoundListener::SetDopplerFactor(MT_Scalar dopplerfactor) +{ + m_dopplerfactor = dopplerfactor; + m_modified = true; +} + + + +void SND_SoundListener::SetDopplerVelocity(MT_Scalar dopplervelocity) +{ + m_dopplervelocity = dopplervelocity; + m_modified = true; +} + + + +void SND_SoundListener::SetScale(MT_Scalar scale) +{ + m_scale = scale; + m_modified = true; +} + + + +MT_Scalar SND_SoundListener::GetGain() const +{ + return m_gain; +} + + + +MT_Vector3 SND_SoundListener::GetPosition() const +{ + return m_position; +} + + + +MT_Vector3 SND_SoundListener::GetVelocity() const +{ + return m_velocity; +} + + + +MT_Matrix3x3 SND_SoundListener::GetOrientation() +{ + return m_orientation; +} + + + +MT_Scalar SND_SoundListener::GetDopplerFactor() const +{ + return m_dopplerfactor; +} + + + +MT_Scalar SND_SoundListener::GetDopplerVelocity() const +{ + return m_dopplervelocity; +} + + + +MT_Scalar SND_SoundListener::GetScale() const +{ + return m_scale; +} + + + +bool SND_SoundListener::IsModified() const +{ + return m_modified; +} + + + +void SND_SoundListener::SetModified(bool modified) +{ + m_modified = modified; +} diff --git a/intern/SoundSystem/intern/SND_SoundObject.cpp b/intern/SoundSystem/intern/SND_SoundObject.cpp new file mode 100644 index 00000000000..e835b012ac1 --- /dev/null +++ b/intern/SoundSystem/intern/SND_SoundObject.cpp @@ -0,0 +1,508 @@ +/* + * SND_SoundObject.cpp + * + * Implementation of the abstract sound object + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_SoundObject.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_SoundObject::SND_SoundObject()// : m_modified(true) +{ + m_samplename = ""; + m_length = 0; + m_buffer = 0; + + m_gain = 0.0; + m_pitch = 1.0; + + m_mingain = 0.0; + m_maxgain = 1.0; + m_rollofffactor = 1.0; + m_referencedistance = 1.0; + + m_position[0] = 0.0; + m_position[1] = 0.0; + m_position[2] = 0.0; + m_velocity[0] = 0.0; + m_velocity[1] = 0.0; + m_velocity[2] = 0.0; + m_orientation[0][0] = 1.0; + m_orientation[0][1] = 0.0; + m_orientation[0][2] = 0.0; + m_orientation[1][0] = 0.0; + m_orientation[1][1] = 1.0; + m_orientation[1][2] = 0.0; + m_orientation[2][0] = 0.0; + m_orientation[2][1] = 0.0; + m_orientation[2][2] = 1.0; + + m_loopstart = 0; + m_loopend = 0; + m_loopmode = SND_LOOP_NORMAL; + m_is3d = true; + m_playstate = SND_INITIAL; + m_active = false; + m_id = -1; + m_lifespan = 0; + m_timestamp = 0; + m_modified = true; + m_running = 0; + m_highpriority = false; +} + + + +SND_SoundObject::~SND_SoundObject() +{ +} + + + +void SND_SoundObject::StartSound() +{ + m_playstate = SND_MUST_PLAY; +} + + + +void SND_SoundObject::StopSound() +{ + m_playstate = SND_MUST_STOP; +} + + + +void SND_SoundObject::PauseSound() +{ + m_playstate = SND_MUST_PAUSE; +} + + + +void SND_SoundObject::DeleteWhenFinished() +{ + m_playstate = SND_MUST_BE_DELETED; +} + + + +void SND_SoundObject::SetGain(MT_Scalar gain) +{ + m_gain = gain; + m_modified = true; +} + + + +void SND_SoundObject::SetMinGain(MT_Scalar mingain) +{ + m_mingain = mingain; + m_modified = true; +} + + + +void SND_SoundObject::SetMaxGain(MT_Scalar maxgain) +{ + m_maxgain = maxgain; + m_modified = true; +} + + + +void SND_SoundObject::SetRollOffFactor(MT_Scalar rollofffactor) +{ + m_rollofffactor = rollofffactor; + m_modified = true; +} + + + +void SND_SoundObject::SetReferenceDistance(MT_Scalar referencedistance) +{ + m_referencedistance = referencedistance; + m_modified = true; +} + + + +void SND_SoundObject::SetPitch(MT_Scalar pitch) +{ + m_pitch = pitch; + m_modified = true; +} + + + +void SND_SoundObject::SetLoopMode(unsigned int loopmode) +{ + m_loopmode = loopmode; + m_modified = true; +} + + + +void SND_SoundObject::SetLoopStart(unsigned int loopstart) +{ + m_loopstart = loopstart; + m_modified = true; +} + + + +void SND_SoundObject::SetLoopEnd(unsigned int loopend) +{ + m_loopend = loopend; + m_modified = true; +} + + + +void SND_SoundObject::Set3D(bool threedee) +{ + m_is3d = threedee; +} + + + +void SND_SoundObject::SetLifeSpan() +{ + m_lifespan = m_length / m_pitch; +} + + + +bool SND_SoundObject::IsLifeSpanOver(MT_Scalar curtime) const +{ + bool result = false; + + if ((curtime - m_timestamp) > m_lifespan) + result = true; + + return result; +} + + + +void SND_SoundObject::SetActive(bool active) +{ + m_active = active; + + if (!active) + { + m_playstate = SND_STOPPED; + (this)->remove(); + } +} + + + +void SND_SoundObject::SetBuffer(unsigned int buffer) +{ + m_buffer = buffer; +} + + + +void SND_SoundObject::SetObjectName(STR_String objectname) +{ + m_objectname = objectname; +} + + + +void SND_SoundObject::SetSampleName(STR_String samplename) +{ + m_samplename = samplename; +} + + + +void SND_SoundObject::SetLength(MT_Scalar length) +{ + m_length = length; +} + + + +void SND_SoundObject::SetPosition(const MT_Vector3& pos) +{ + m_position = pos; +} + + + +void SND_SoundObject::SetVelocity(const MT_Vector3& vel) +{ + m_velocity = vel; +} + + + +void SND_SoundObject::SetOrientation(const MT_Matrix3x3& orient) +{ + m_orientation = orient; +} + + + +void SND_SoundObject::SetPlaystate(int playstate) +{ + m_playstate = playstate; +} + + + +void SND_SoundObject::SetId(int id) +{ + m_id = id; +} + + + +void SND_SoundObject::SetTimeStamp(MT_Scalar timestamp) +{ + m_timestamp = timestamp; +} + + + +void SND_SoundObject::SetHighPriority(bool priority) +{ + m_highpriority = priority; +} + + + +bool SND_SoundObject::IsHighPriority() const +{ + return m_highpriority; +} + + + +bool SND_SoundObject::IsActive()const +{ + return m_active; +} + + + +int SND_SoundObject::GetId()const +{ + return m_id; +} + + + +MT_Scalar SND_SoundObject::GetLifeSpan()const +{ + return m_lifespan; +} + + + +MT_Scalar SND_SoundObject::GetTimestamp()const +{ + return m_timestamp; +} + + + +unsigned int SND_SoundObject::GetBuffer() +{ + return m_buffer; +} + + + +const STR_String& SND_SoundObject::GetSampleName() +{ + return m_samplename; +} + + + +const STR_String& SND_SoundObject::GetObjectName() +{ + return m_objectname; +} + + + +MT_Scalar SND_SoundObject::GetLength() const +{ + return m_length; +} + + + +MT_Scalar SND_SoundObject::GetGain() const +{ + return m_gain; +} + + + +MT_Scalar SND_SoundObject::GetPitch() const +{ + return m_pitch; +} + + + +MT_Scalar SND_SoundObject::GetMinGain() const +{ + return m_mingain; +} + + + +MT_Scalar SND_SoundObject::GetMaxGain() const +{ + return m_maxgain; +} + + + +MT_Scalar SND_SoundObject::GetRollOffFactor() const +{ + return m_rollofffactor; +} + + + +MT_Scalar SND_SoundObject::GetReferenceDistance() const +{ + return m_referencedistance; +} + + + +MT_Vector3 SND_SoundObject::GetPosition() const +{ + return m_position; +} + + + +MT_Vector3 SND_SoundObject::GetVelocity() const +{ + return m_velocity; +} + + + +MT_Matrix3x3 SND_SoundObject::GetOrientation() const +{ + return m_orientation; +} + + + +unsigned int SND_SoundObject::GetLoopMode() const +{ + return m_loopmode; +} + + + +unsigned int SND_SoundObject::GetLoopStart() const +{ + return m_loopstart; +} + + + +unsigned int SND_SoundObject::GetLoopEnd() const +{ + return m_loopend; +} + + + +bool SND_SoundObject::Is3D() const +{ + return m_is3d; +} + + + +int SND_SoundObject::GetPlaystate() const +{ + return m_playstate; +} + + + +bool SND_SoundObject::IsModified() const +{ + return m_modified; +} + + + +void SND_SoundObject::SetModified(bool modified) +{ + m_modified = modified; +} + + + +void SND_SoundObject::InitRunning() +{ + m_running = 0; +} + + + +bool SND_SoundObject::IsRunning() const +{ + bool result = false; + + if (m_running > 100) + result = true; + + return result; +} + + + +void SND_SoundObject::AddRunning() +{ + ++m_running; +} diff --git a/intern/SoundSystem/intern/SND_Utils.cpp b/intern/SoundSystem/intern/SND_Utils.cpp new file mode 100644 index 00000000000..0880576c292 --- /dev/null +++ b/intern/SoundSystem/intern/SND_Utils.cpp @@ -0,0 +1,447 @@ +/* + * SND_Utils.cpp + * + * Util functions for soundthingies + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_Utils.h" +#include "SoundDefines.h" +#include "SND_DependKludge.h" +/* +extern "C" { +#include "license_key.h" +} +*/ +#include +#include +#include +#include +#include + +#if defined(WIN32) +#include +#else +#include +#endif + +#define BUFFERSIZE 32 + + +/***************************************************************************** + * Begin of temporary Endian stuff. + * I think there should be a central place to handle endian conversion but for + * the time being it suffices. Note that the defines come from the Blender + * source. + *****************************************************************************/ +typedef enum +{ + SND_endianBig = 0, + SND_endianLittle +} SND_TEndian; + +#if defined(__BIG_ENDIAN__) || defined(__sparc) || defined(__sparc__) +const SND_TEndian SND_fEndian = SND_endianBig; +#else +const SND_TEndian SND_fEndian = SND_endianLittle; +#endif + +/* This one swaps the bytes in a short */ +#define SWITCH_SHORT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; \ + p_i[0] = p_i[1]; \ + p_i[1] = s_i; } + +/* This one rotates the bytes in an int */ +#define SWITCH_INT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i; \ + s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; } +/***************************************************************************** + * End of temporary Endian stuff. + *****************************************************************************/ + + +/* loads a file */ +void* SND_LoadSample(char *filename) +{ + int file, filelen, buffersize = BUFFERSIZE; + void* data = NULL; + +#if defined(WIN32) + file = open(filename, O_BINARY|O_RDONLY); +#else + file = open(filename, 0|O_RDONLY); +#endif + + if (file == -1) + { + //printf("can't open file.\n"); + //printf("press q for quit.\n"); + } + else + { + filelen = lseek(file, 0, SEEK_END); + lseek(file, 0, SEEK_SET); + + if (filelen != 0) + { + data = malloc(buffersize); + + if (read(file, data, buffersize) != buffersize) + { + free(data); + data = NULL; + } + } + close(file); + + } + return (data); +} + + + +bool SND_IsSampleValid(const STR_String& name, void* memlocation) +{ + bool result = false; + bool loadedsample = false; + char buffer[BUFFERSIZE]; + + if (!memlocation) + { + STR_String samplename = name; + memlocation = SND_LoadSample(samplename.Ptr()); + + if (memlocation) + loadedsample = true; + } + + if (memlocation) + { + memcpy(&buffer, memlocation, BUFFERSIZE); + + if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8))) + { + /* This was endian unsafe. See top of the file for the define. */ + short shortbuf = *((short *) &buffer[20]); + if (SND_fEndian == SND_endianBig) SWITCH_SHORT(shortbuf); + + if (shortbuf == SND_WAVE_FORMAT_PCM) + result = true; + + /* only fmod supports compressed wav */ +#ifdef USE_FMOD + switch (shortbuf) + { + case SND_WAVE_FORMAT_ADPCM: + case SND_WAVE_FORMAT_ALAW: + case SND_WAVE_FORMAT_MULAW: + case SND_WAVE_FORMAT_DIALOGIC_OKI_ADPCM: + case SND_WAVE_FORMAT_CONTROL_RES_VQLPC: + case SND_WAVE_FORMAT_GSM_610: + case SND_WAVE_FORMAT_MPEG3: + result = true; + break; + default: + { + break; + } + } +#endif + } +#ifdef USE_FMOD + /* only valid publishers may use ogg vorbis */ + else if (!memcmp(buffer, "OggS", 4)) + { + result = true; + } + /* only valid publishers may use mp3 */ + else if (((!memcmp(buffer, "ID3", 3)) || (!memcmp(buffer, "ÿû", 2)))) + { + result = true; + } +#endif + } + if (loadedsample) + { + free(memlocation); + memlocation = NULL; + } + + return result; +} + + + +/* checks if the passed pointer is a valid sample */ +bool CheckSample(void* sample) +{ + bool valid = false; + char buffer[32]; + + memcpy(buffer, sample, 16); + + if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8))) + { + valid = true; + } + + return valid; +} + + + +/* gets the type of the sample (0 == unknown, 1 == PCM etc */ +unsigned int SND_GetSampleFormat(void* sample) +{ + short sampletype = 0; + + if (CheckSample(sample)) + { + memcpy(&sampletype, ((char*)sample) + 20, 2); + } + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_SHORT(sampletype); + + return (unsigned int)sampletype; +} + + + +/* gets the number of channels in a sample */ +unsigned int SND_GetNumberOfChannels(void* sample) +{ + short numberofchannels = 0; + + if (CheckSample(sample)) + { + memcpy(&numberofchannels, ((char*)sample) + 22, 2); + } + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_SHORT(numberofchannels); + + return (unsigned int)numberofchannels; +} + + + +/* gets the samplerate of a sample */ +unsigned int SND_GetSampleRate(void* sample) +{ + unsigned int samplerate = 0; + + if (CheckSample(sample)) + { + memcpy(&samplerate, ((char*)sample) + 24, 4); + } + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_INT(samplerate); + + return samplerate; +} + + + +/* gets the bitrate of a sample */ +unsigned int SND_GetBitRate(void* sample) +{ + short bitrate = 0; + + if (CheckSample(sample)) + { + memcpy(&bitrate, ((char*)sample) + 34, 2); + } + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_SHORT(bitrate); + + return (unsigned int)bitrate; +} + + + +/* gets the length of the actual sample data (without the header) */ +unsigned int SND_GetNumberOfSamples(void* sample) +{ + unsigned int chunklength, length = 0, offset = 16; + char data[4]; + + if (CheckSample(sample)) + { + memcpy(&chunklength, ((char*)sample) + offset, 4); + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_INT(chunklength); + + offset = offset + chunklength + 4; + memcpy(data, ((char*)sample) + offset, 4); + + /* This seems very unsafe, what if data is never found (f.i. corrupt file)... */ + // lets find "data" + while (memcmp(data, "data", 4)) + { + offset += 4; + memcpy(data, ((char*)sample) + offset, 4); + } + offset += 4; + memcpy(&length, ((char*)sample) + offset, 4); + + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_INT(length); + } + + return length; +} + + + +/* gets the size of the entire header (file - sampledata) */ +unsigned int SND_GetHeaderSize(void* sample) +{ + unsigned int chunklength, headersize = 0, offset = 16; + char data[4]; + + if (CheckSample(sample)) + { + memcpy(&chunklength, ((char*)sample) + offset, 4); + /* This was endian unsafe. See top of the file for the define. */ + if (SND_fEndian == SND_endianBig) SWITCH_INT(chunklength); + offset = offset + chunklength + 4; + memcpy(data, ((char*)sample) + offset, 4); + + // lets find "data" + while (memcmp(data, "data", 4)) + { + offset += 4; + memcpy(data, ((char*)sample) + offset, 4); + } + headersize = offset + 8; + } + + + return headersize; +} + + + +unsigned int SND_GetExtraChunk(void* sample) +{ + unsigned int extrachunk = 0, chunklength, offset = 16; + char data[4]; + + if (CheckSample(sample)) + { + memcpy(&chunklength, ((char*)sample) + offset, 4); + offset = offset + chunklength + 4; + memcpy(data, ((char*)sample) + offset, 4); + + // lets find "cue" + while (memcmp(data, "cue", 3)) + { + offset += 4; + memcpy(data, ((char*)sample) + offset, 4); + } + } + + return extrachunk; +} + + + +void SND_GetSampleInfo(signed char* sample, SND_WaveSlot* waveslot) +{ + WavFileHeader fileheader; + WavFmtHeader fmtheader; + WavFmtExHeader fmtexheader; + WavSampleHeader sampleheader; + WavChunkHeader chunkheader; + + if (CheckSample(sample)) + { + memcpy(&fileheader, sample, sizeof(WavFileHeader)); + fileheader.size = SND_GetHeaderSize(sample); + sample += sizeof(WavFileHeader); + fileheader.size = ((fileheader.size+1) & ~1) - 4; + + while ((fileheader.size > 0) && (memcpy(&chunkheader, sample, sizeof(WavChunkHeader)))) + { + sample += sizeof(WavChunkHeader); + if (!memcmp(chunkheader.id, "fmt ", 4)) + { + memcpy(&fmtheader, sample, sizeof(WavFmtHeader)); + waveslot->SetSampleFormat(fmtheader.format); + + if (fmtheader.format == 0x0001) + { + waveslot->SetNumberOfChannels(fmtheader.numberofchannels); + waveslot->SetBitRate(fmtheader.bitrate); + waveslot->SetSampleRate(fmtheader.samplerate); + sample += chunkheader.size; + } + else + { + memcpy(&fmtexheader, sample, sizeof(WavFmtExHeader)); + sample += chunkheader.size; + } + } + else if (!memcmp(chunkheader.id, "data", 4)) + { + if (fmtheader.format == 0x0001) + { + waveslot->SetNumberOfSamples(chunkheader.size); + sample += chunkheader.size; + } + else if (fmtheader.format == 0x0011) + { + //IMA ADPCM + } + else if (fmtheader.format == 0x0055) + { + //MP3 WAVE + } + } + else if (!memcmp(chunkheader.id, "smpl", 4)) + { + memcpy(&sampleheader, sample, sizeof(WavSampleHeader)); + //loop = sampleheader.loops; + sample += chunkheader.size; + } + else + sample += chunkheader.size; + + sample += chunkheader.size & 1; + fileheader.size -= (((chunkheader.size + 1) & ~1) + 8); + } + } +} diff --git a/intern/SoundSystem/intern/SND_WaveCache.cpp b/intern/SoundSystem/intern/SND_WaveCache.cpp new file mode 100644 index 00000000000..e9868f77f57 --- /dev/null +++ b/intern/SoundSystem/intern/SND_WaveCache.cpp @@ -0,0 +1,141 @@ +/* + * SND_WaveCache.cpp + * + * abstract wavecache, a way to organize samples + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // Get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_WaveCache.h" +#include + +#ifdef __APPLE__ +# include +#else +# ifdef __FreeBSD__ +# include +# else +# include +# endif +#endif + +SND_WaveCache::SND_WaveCache() +{ + // do the buffer administration + for (int i = 0; i < NUM_BUFFERS; i++) + m_bufferList[i] = NULL; +} + + + +SND_WaveCache::~SND_WaveCache() +{ + // clean up the mess + FreeSamples(); + RemoveAllSamples(); +} + + + +SND_WaveSlot* SND_WaveCache::GetWaveSlot(const STR_String& samplename) +{ + SND_WaveSlot* waveslot = NULL; + + std::map::iterator find_result = m_samplecache.find(samplename); + + // let's see if we have already loaded this sample + if (find_result != m_samplecache.end()) + { + waveslot = (*find_result).second; + } + else + { + // so the sample wasn't loaded, so do it here + for (int bufnum = 0; bufnum < NUM_BUFFERS; bufnum++) + { + // find an empty buffer + if (m_bufferList[bufnum] == NULL) + { + waveslot = new SND_WaveSlot(); + waveslot->SetSampleName(samplename); + waveslot->SetBuffer(bufnum); + m_bufferList[bufnum] = waveslot; + break; + } + } + m_samplecache.insert(std::pair(samplename, waveslot)); + } + + return waveslot; +} + + + +void SND_WaveCache::RemoveAllSamples() +{ + // remove all samples + m_samplecache.clear(); + + // reset the list of buffers + for (int i = 0; i < NUM_BUFFERS; i++) + m_bufferList[i] = NULL; +} + + + +void SND_WaveCache::RemoveSample(const STR_String& samplename, int buffer) +{ + m_samplecache.erase(samplename); + m_bufferList[buffer] = NULL; +} + + + +void SND_WaveCache::FreeSamples() +{ + // iterate through the bufferlist and delete the waveslot if present + for (int i = 0; i < NUM_BUFFERS; i++) + { + if (m_bufferList[i]) + { + delete m_bufferList[i]; + m_bufferList[i] = NULL; + } + } +} diff --git a/intern/SoundSystem/intern/SND_WaveSlot.cpp b/intern/SoundSystem/intern/SND_WaveSlot.cpp new file mode 100644 index 00000000000..6c74e326743 --- /dev/null +++ b/intern/SoundSystem/intern/SND_WaveSlot.cpp @@ -0,0 +1,183 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SND_WaveSlot.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SND_WaveSlot::~SND_WaveSlot() +{ +#ifdef ONTKEVER + printf("neeeeeee...\n"); +#endif +} + + + +void SND_WaveSlot::SetSampleName(STR_String samplename) +{ + m_samplename = samplename; +} + + + +void SND_WaveSlot::SetLoaded(bool loaded) +{ + m_loaded = loaded; +} + + + +void SND_WaveSlot::SetData(void* data) +{ + m_data = data; +} + + + +void SND_WaveSlot::SetBuffer(unsigned int buffer) +{ + m_buffer = buffer; +} + + + +void SND_WaveSlot::SetSampleFormat(unsigned int sampleformat) +{ + m_sampleformat = sampleformat; +} + + + +void SND_WaveSlot::SetNumberOfChannels(unsigned int numberofchannels) +{ + m_numberofchannels = numberofchannels; +} + + + +void SND_WaveSlot::SetSampleRate(unsigned int samplerate) +{ + m_samplerate = samplerate; +} + + + +void SND_WaveSlot::SetBitRate(unsigned int bitrate) +{ + m_bitrate = bitrate; +} + + + +void SND_WaveSlot::SetNumberOfSamples(unsigned int numberofsamples) +{ + m_numberofsamples = numberofsamples; +} + + + +void SND_WaveSlot::SetFileSize(unsigned int filesize) +{ + m_filesize = filesize; +} + + + +const STR_String& SND_WaveSlot::GetSampleName() +{ + return m_samplename; +} + + + +bool SND_WaveSlot::IsLoaded() const +{ + return m_loaded; +} + + + +void* SND_WaveSlot::GetData() +{ + return m_data; +} + + + +unsigned int SND_WaveSlot::GetBuffer() const +{ + return m_buffer; +} + + + +unsigned int SND_WaveSlot::GetSampleFormat() const +{ + return m_sampleformat; +} + + + +unsigned int SND_WaveSlot::GetNumberOfChannels() const +{ + return m_numberofchannels; +} + + + +unsigned int SND_WaveSlot::GetSampleRate() const +{ + return m_samplerate; +} + + + +unsigned int SND_WaveSlot::GetBitRate() const +{ + return m_bitrate; +} + + + +unsigned int SND_WaveSlot::GetNumberOfSamples() const +{ + return m_numberofsamples; +} + + + +unsigned int SND_WaveSlot::GetFileSize() const +{ + return m_filesize; +} diff --git a/intern/SoundSystem/make/msvc_6_0/SoundSystem.dsp b/intern/SoundSystem/make/msvc_6_0/SoundSystem.dsp new file mode 100644 index 00000000000..c7ce7aa7a70 --- /dev/null +++ b/intern/SoundSystem/make/msvc_6_0/SoundSystem.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="SoundSystem" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SoundSystem - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SoundSystem.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SoundSystem.mak" CFG="SoundSystem - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SoundSystem - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SoundSystem - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SoundSystem - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\soundsystem" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\soundsystem" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /I "../../../../../lib/windows/string/include" /I "../../../../../lib/windows/moto/include" /I "../../dummy" /I "../../openal" /I "..\..\..\string" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\soundsystem\libSoundSystem.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\SoundSystem\include\*.h ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\soundsystem\*.lib ..\..\..\..\..\lib\windows\SoundSystem\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "SoundSystem - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SoundSystem___Win32_Debug" +# PROP BASE Intermediate_Dir "SoundSystem___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\soundsystem\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\soundsystem\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../" /I "../../../../../lib/windows/string/include" /I "../../../../../lib/windows/moto/include" /I "../../dummy" /I "../../openal" /I "..\..\..\string" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\soundsystem\debug\libSoundSystem.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\SoundSystem\include\*.h ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\soundsystem\debug\*.lib ..\..\..\..\..\lib\windows\SoundSystem\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "SoundSystem - Win32 Release" +# Name "SoundSystem - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\SND_AudioDevice.cpp +# End Source File +# Begin Source File + +SOURCE="..\..\intern\SND_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_CDObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_DeviceManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_IdObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_Scene.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_SoundListener.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_SoundObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_Utils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_WaveCache.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_WaveSlot.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\intern\SND_AudioDevice.h +# End Source File +# Begin Source File + +SOURCE="..\..\SND_C-api.h" +# End Source File +# Begin Source File + +SOURCE=..\..\SND_CDObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_DependKludge.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_DeviceManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_IAudioDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\SND_IdObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_Object.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_Scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_SoundListener.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_SoundObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_Utils.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_WaveCache.h +# End Source File +# Begin Source File + +SOURCE=..\..\SND_WaveSlot.h +# End Source File +# Begin Source File + +SOURCE=..\..\SoundDefines.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/SoundSystem/make/msvc_6_0/dummy/DummySoundSystem.dsp b/intern/SoundSystem/make/msvc_6_0/dummy/DummySoundSystem.dsp new file mode 100644 index 00000000000..4a27fdfa6e3 --- /dev/null +++ b/intern/SoundSystem/make/msvc_6_0/dummy/DummySoundSystem.dsp @@ -0,0 +1,103 @@ +# Microsoft Developer Studio Project File - Name="DummySoundSystem" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=DummySoundSystem - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "DummySoundSystem.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "DummySoundSystem.mak" CFG="DummySoundSystem - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DummySoundSystem - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "DummySoundSystem - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "DummySoundSystem - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\dummy" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\dummy" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\intern" /I "..\..\..\..\SoundSystem" /I "..\..\..\..\moto\include" /I "..\..\..\..\string" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\..\obj\windows\intern\soundsystem\dummy\libDummySoundSystem.lib" + +!ELSEIF "$(CFG)" == "DummySoundSystem - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\dummy\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\dummy\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\intern" /I "..\..\..\..\SoundSystem" /I "..\..\..\..\moto\include" /I "..\..\..\..\string" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\..\obj\windows\intern\soundsystem\dummy\debug\libDummySoundSystem.lib" + +!ENDIF + +# Begin Target + +# Name "DummySoundSystem - Win32 Release" +# Name "DummySoundSystem - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\dummy\SND_DummyDevice.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\dummy\SND_DummyDevice.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/SoundSystem/make/msvc_6_0/openal/OpenALSoundSystem.dsp b/intern/SoundSystem/make/msvc_6_0/openal/OpenALSoundSystem.dsp new file mode 100644 index 00000000000..67a6bd0bb5a --- /dev/null +++ b/intern/SoundSystem/make/msvc_6_0/openal/OpenALSoundSystem.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="OpenALSoundSystem" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=OpenALSoundSystem - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "OpenALSoundSystem.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "OpenALSoundSystem.mak" CFG="OpenALSoundSystem - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OpenALSoundSystem - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "OpenALSoundSystem - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "OpenALSoundSystem - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\openal" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\openal" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\intern" /I "..\..\..\..\SoundSystem" /I "..\..\..\..\SoundSystem\sdl" /I "..\..\..\..\moto\include" /I "..\..\..\..\string" /I "..\..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\..\lib\windows\sdl\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\..\obj\windows\intern\soundsystem\openal\libOpenALSoundSystem.lib" + +!ELSEIF "$(CFG)" == "OpenALSoundSystem - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "OpenALSoundSystem___Win32_Debug" +# PROP BASE Intermediate_Dir "OpenALSoundSystem___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\openal\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\intern\soundsystem\openal\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\intern" /I "..\..\..\..\SoundSystem" /I "..\..\..\..\SoundSystem\sdl" /I "..\..\..\..\moto\include" /I "..\..\..\..\string" /I "..\..\..\..\..\..\lib\windows\sdl\include" /I "..\..\..\..\..\..\lib\windows\openal\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\..\obj\windows\intern\soundsystem\openal\debug\libOpenALSoundSystem.lib" + +!ENDIF + +# Begin Target + +# Name "OpenALSoundSystem - Win32 Release" +# Name "OpenALSoundSystem - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\openal\SND_OpenALDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\sdl\SND_SDLCDDevice.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\openal\SND_OpenALDevice.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/SoundSystem/make/msvc_7_0/SoundSystem.vcproj b/intern/SoundSystem/make/msvc_7_0/SoundSystem.vcproj new file mode 100644 index 00000000000..f0952c582b7 --- /dev/null +++ b/intern/SoundSystem/make/msvc_7_0/SoundSystem.vcproj @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/SoundSystem/make/msvc_7_0/dummy/DummySoundSystem.vcproj b/intern/SoundSystem/make/msvc_7_0/dummy/DummySoundSystem.vcproj new file mode 100644 index 00000000000..103b589e732 --- /dev/null +++ b/intern/SoundSystem/make/msvc_7_0/dummy/DummySoundSystem.vcproj @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/SoundSystem/make/msvc_7_0/openal/OpenALSoundSystem.vcproj b/intern/SoundSystem/make/msvc_7_0/openal/OpenALSoundSystem.vcproj new file mode 100644 index 00000000000..8ce971ac1aa --- /dev/null +++ b/intern/SoundSystem/make/msvc_7_0/openal/OpenALSoundSystem.vcproj @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/SoundSystem/openal/Makefile b/intern/SoundSystem/openal/Makefile new file mode 100644 index 00000000000..84ae9b007b6 --- /dev/null +++ b/intern/SoundSystem/openal/Makefile @@ -0,0 +1,47 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = OpenALSoundSystem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_OPENAL)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../intern +CPPFLAGS += -I.. +CPPFLAGS += -I. +CPPFLAGS += -I../sdl diff --git a/intern/SoundSystem/openal/SND_OpenALDevice.cpp b/intern/SoundSystem/openal/SND_OpenALDevice.cpp new file mode 100644 index 00000000000..a278384dfd8 --- /dev/null +++ b/intern/SoundSystem/openal/SND_OpenALDevice.cpp @@ -0,0 +1,799 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * SND_OpenALDevice derived from SND_IAudioDevice + */ + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "SND_OpenALDevice.h" +#ifndef __APPLE__ +#include "SND_SDLCDDevice.h" +#endif +#include "SoundDefines.h" + +#include "SND_Utils.h" + +#ifdef APPLE_FRAMEWORK_FIX +#include +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#if defined(WIN32) +#include +#else +#include +#endif +#include + +#include + +/* untill openal gets unified we need this hack for non-windows systems */ +#if !defined(WIN32) && !defined(ALC_MAJOR_VERSION) + +#include + +ALvoid alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop); +ALvoid alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq); + +typedef struct /* WAV File-header */ +{ + ALubyte Id[4]; + ALsizei Size; + ALubyte Type[4]; +} WAVFileHdr_Struct; + +typedef struct /* WAV Fmt-header */ +{ + ALushort Format; + ALushort Channels; + ALuint SamplesPerSec; + ALuint BytesPerSec; + ALushort BlockAlign; + ALushort BitsPerSample; +} WAVFmtHdr_Struct; + +typedef struct /* WAV FmtEx-header */ +{ + ALushort Size; + ALushort SamplesPerBlock; +} WAVFmtExHdr_Struct; + +typedef struct /* WAV Smpl-header */ +{ + ALuint Manufacturer; + ALuint Product; + ALuint SamplePeriod; + ALuint Note; + ALuint FineTune; + ALuint SMPTEFormat; + ALuint SMPTEOffest; + ALuint Loops; + ALuint SamplerData; + struct + { + ALuint Identifier; + ALuint Type; + ALuint Start; + ALuint End; + ALuint Fraction; + ALuint Count; + } Loop[1]; +} WAVSmplHdr_Struct; + +typedef struct /* WAV Chunk-header */ +{ + ALubyte Id[4]; + ALuint Size; +} WAVChunkHdr_Struct; + +ALvoid alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop) +{ + WAVChunkHdr_Struct ChunkHdr; + WAVFmtExHdr_Struct FmtExHdr; + WAVFileHdr_Struct FileHdr; + WAVSmplHdr_Struct SmplHdr; + WAVFmtHdr_Struct FmtHdr; + ALbyte *Stream; + + *format=AL_FORMAT_MONO16; + *data=NULL; + *size=0; + *freq=22050; + *loop=AL_FALSE; + if (memory) + { + Stream=memory; + if (Stream) + { + memcpy(&FileHdr,Stream,sizeof(WAVFileHdr_Struct)); + Stream+=sizeof(WAVFileHdr_Struct); + FileHdr.Size=((FileHdr.Size+1)&~1)-4; + while ((FileHdr.Size!=0)&&(memcpy(&ChunkHdr,Stream,sizeof(WAVChunkHdr_Struct)))) + { + Stream+=sizeof(WAVChunkHdr_Struct); + if (!memcmp(ChunkHdr.Id,"fmt ",4)) + { + memcpy(&FmtHdr,Stream,sizeof(WAVFmtHdr_Struct)); + if (FmtHdr.Format==0x0001) + { + *format=(FmtHdr.Channels==1? + (FmtHdr.BitsPerSample==8?AL_FORMAT_MONO8:AL_FORMAT_MONO16): + (FmtHdr.BitsPerSample==8?AL_FORMAT_STEREO8:AL_FORMAT_STEREO16)); + *freq=FmtHdr.SamplesPerSec; + Stream+=ChunkHdr.Size; + } + else + { + memcpy(&FmtExHdr,Stream,sizeof(WAVFmtExHdr_Struct)); + Stream+=ChunkHdr.Size; + } + } + else if (!memcmp(ChunkHdr.Id,"data",4)) + { + if (FmtHdr.Format==0x0001) + { + *size=ChunkHdr.Size; + *data=malloc(ChunkHdr.Size+31); + if (*data) memcpy(*data,Stream,ChunkHdr.Size); + memset(((char *)*data)+ChunkHdr.Size,0,31); + Stream+=ChunkHdr.Size; + } + else if (FmtHdr.Format==0x0011) + { + //IMA ADPCM + } + else if (FmtHdr.Format==0x0055) + { + //MP3 WAVE + } + } + else if (!memcmp(ChunkHdr.Id,"smpl",4)) + { + memcpy(&SmplHdr,Stream,sizeof(WAVSmplHdr_Struct)); + *loop = (SmplHdr.Loops ? AL_TRUE : AL_FALSE); + Stream+=ChunkHdr.Size; + } + else Stream+=ChunkHdr.Size; + Stream+=ChunkHdr.Size&1; + FileHdr.Size-=(((ChunkHdr.Size+1)&~1)+8); + } + } + } +} + +ALvoid alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq) +{ + if (data) + free(data); +} + +#endif /* WIN32 */ + +#ifdef __APPLE__ +#define OUDE_OPENAL 1 +#endif + + +SND_OpenALDevice::SND_OpenALDevice() + : SND_AudioDevice(), + m_context(NULL), + m_device(NULL) +{ + /* Removed the functionality for checking if noaudio was provided on */ + /* the commandline. */ + m_audio = true; + m_context = NULL; + m_buffersinitialized = false; + m_sourcesinitialized = false; + + // let's check if we can get openal to initialize... + if (m_audio) + { +#ifdef OUDE_OPENAL + m_audio = true; // openal_2.12 + alutInit(NULL, NULL); // openal_2.12 +#else + m_audio = false; + + ALCdevice *dev = alcOpenDevice(NULL); + if (dev) { + m_context = alcCreateContext(dev, NULL); + + if (m_context) { +#ifdef AL_VERSION_1_1 + alcMakeContextCurrent((ALCcontext*)m_context); +#else + alcMakeContextCurrent(m_context); +#endif + m_audio = true; + m_device = dev; +#ifdef __linux__ + /* + * SIGHUP Hack: + * + * On Linux, alcDestroyContext generates a SIGHUP (Hangup) when killing the OpenAL + * mixer thread, which kills Blender. + * + * So we set the signal to ignore.... + * + * TODO: check if this applies to other platforms. + * + */ + signal(SIGHUP, SIG_IGN); +#endif + } + } + +#endif + } + + // then try to generate some buffers + if (m_audio) + { + // let openal generate its buffers + alGenBuffers(NUM_BUFFERS, m_buffers); + m_buffersinitialized = true; + + for (int i = 0; i < NUM_BUFFERS; i++) + { + if (!alIsBuffer(m_buffers[i])) + { + //printf("\n\n WARNING: OpenAL returned with an error. Continuing without audio.\n\n"); + m_audio = false; + break; + } + } + } + + // next: the sources + if (m_audio) + { +#ifdef OUDE_OPENAL + ALenum alc_error = ALC_NO_ERROR; // openal_2.12 +#elif defined(_WIN32) + // alcGetError has no arguments on windows + ALenum alc_error = alcGetError(); // openal_2.14+ +#else + ALenum alc_error = alcGetError(NULL); // openal_2.14+ +#endif + + // let openal generate its sources + if (alc_error == ALC_NO_ERROR) + { + alGenSources(NUM_SOURCES, m_sources); + m_sourcesinitialized = true; + } + } + + // let's get us a wavecache + if (m_audio) + { + m_wavecache = new SND_WaveCache(); + } +#ifndef __APPLE__ + m_cdrom = new SND_SDLCDDevice(); +#endif +} + +void SND_OpenALDevice::UseCD(void) const +{ + // only fmod has CD support, so only create it here + SND_CDObject::CreateSystem(); + +} + +void SND_OpenALDevice::MakeCurrent() const +{ +#ifdef WIN32 + alcMakeContextCurrent(m_context); +#endif +} + + + +SND_OpenALDevice::~SND_OpenALDevice() +{ + MakeCurrent(); + + if (m_buffersinitialized) + { + alDeleteBuffers(NUM_BUFFERS, m_buffers); + m_buffersinitialized = false; + } + + if (m_sourcesinitialized) + { + for (int i = 0; i < NUM_SOURCES; i++) + alSourceStop(m_sources[i]); + + alDeleteSources(NUM_SOURCES, m_sources); + m_sourcesinitialized = false; + } + + if (m_context) { + MakeCurrent(); +#ifdef AL_VERSION_1_1 + alcDestroyContext((ALCcontext*)m_context); +#else + alcDestroyContext(m_context); +#endif + m_context = NULL; + } + +#ifdef __linux__ + // restore the signal state above. + signal(SIGHUP, SIG_DFL); +#endif + // let's see if we used the cd. if not, just leave it alone + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD) + { + this->StopCD(); + SND_CDObject::DisposeSystem(); + } +#ifndef __APPLE__ + if (m_cdrom) + delete m_cdrom; +#endif +#ifdef OUDE_OPENAL + if (m_audio) + alutExit(); +#else + if (m_device) + alcCloseDevice((ALCdevice*) m_device); +#endif +} + + + +SND_WaveSlot* SND_OpenALDevice::LoadSample(const STR_String& name, + void* memlocation, + int size) +{ + SND_WaveSlot* waveslot = NULL; + STR_String samplename = name; + + if (m_audio) + { + /* create the waveslot */ + waveslot = m_wavecache->GetWaveSlot(samplename); + + /* do we support this sample? */ + if (SND_IsSampleValid(name, memlocation)) + { + if (waveslot) + { + int buffer = waveslot->GetBuffer(); + void* data = NULL; +#ifndef __APPLE__ + char loop = 'a'; +#endif + int sampleformat, bitrate, numberofchannels; + ALenum al_error = alGetError(); + +#ifdef OUDE_OPENAL + ALsizei samplerate, numberofsamples; // openal_2.12 +#else + int samplerate, numberofsamples; // openal_2.14+ +#endif + + /* Give them some safe defaults just incase */ + bitrate = numberofchannels = 0; + + /* load the sample from memory? */ + if (size && memlocation) + { + waveslot->SetFileSize(size); + + /* what was (our) buffer? */ + int buffer = waveslot->GetBuffer(); + + /* get some info out of the sample */ + SND_GetSampleInfo((signed char*)memlocation, waveslot); + numberofchannels = SND_GetNumberOfChannels(memlocation); + bitrate = SND_GetBitRate(memlocation); + + /* load the sample into openal */ +#if defined(OUDE_OPENAL) || defined (__APPLE__) + alutLoadWAVMemory((char*)memlocation, &sampleformat, &data, &numberofsamples, &samplerate); // openal_2.12 +#else +#ifdef AL_VERSION_1_1 + alutLoadWAVMemory((ALbyte*)memlocation, &sampleformat, &data, &numberofsamples, &samplerate, &loop);// openal_2.14+ +#else + alutLoadWAVMemory((signed char*)memlocation, &sampleformat, &data, &numberofsamples, &samplerate, &loop);// openal_2.14+ + +#endif +#endif + /* put it in the buffer */ + alBufferData(m_buffers[buffer], sampleformat, data, numberofsamples, samplerate); + } + /* or from file? */ + else + { +#ifdef __APPLE__ + alutLoadWAVFile((ALbyte *)samplename.Ptr(), &sampleformat, &data, &numberofsamples, &samplerate); +#else + alutLoadWAVFile((ALbyte *)samplename.Ptr(), &sampleformat, &data, &numberofsamples, &samplerate, &loop); +#endif + /* put it in the buffer */ + alBufferData(m_buffers[buffer], sampleformat, data, numberofsamples, samplerate); + } + + /* fill the waveslot with info */ + al_error = alGetError(); + if (al_error == AL_NO_ERROR && m_buffers[buffer]) + { + waveslot->SetData(data); + waveslot->SetSampleFormat(sampleformat); + waveslot->SetNumberOfChannels(numberofchannels); + waveslot->SetSampleRate(samplerate); + waveslot->SetBitRate(bitrate); + waveslot->SetNumberOfSamples(numberofsamples); + + /* if the loading succeeded, mark the waveslot */ + waveslot->SetLoaded(true); + } + else + { + /* or when it failed, free the waveslot */ + m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer()); + waveslot = NULL; + } + + /* and free the original stuff (copy was made in openal) */ + alutUnloadWAV(sampleformat, data, numberofsamples, samplerate); + } + } + else + { + /* sample not supported, remove waveslot */ + m_wavecache->RemoveSample(waveslot->GetSampleName(), waveslot->GetBuffer()); + waveslot = NULL; + } + } + return waveslot; +} + + + +// listener's and general stuff ////////////////////////////////////////////////////// + + + +/* sets the global dopplervelocity */ +void SND_OpenALDevice::SetDopplerVelocity(MT_Scalar dopplervelocity) const +{ + alDopplerVelocity ((float)dopplervelocity); +} + + + +/* sets the global dopplerfactor */ +void SND_OpenALDevice::SetDopplerFactor(MT_Scalar dopplerfactor) const +{ + alDopplerFactor ((float)dopplerfactor); +} + + + +/* sets the global rolloff factor */ +void SND_OpenALDevice::SetListenerRollOffFactor(MT_Scalar rollofffactor) const +{ + // not implemented in openal +} + + + +void SND_OpenALDevice::NextFrame() const +{ + // CD +#ifndef __APPLE__ + m_cdrom->NextFrame(); +#endif + // not needed by openal +} + + + +// set the gain for the listener +void SND_OpenALDevice::SetListenerGain(float gain) const +{ + alListenerf (AL_GAIN, gain); +} + + + +void SND_OpenALDevice::InitListener() +{ + // initialize the listener with these values that won't change + // (as long as we can have only one listener) + // now we can superimpose all listeners on each other (for they + // have the same settings) + float lispos[3] = {0,0,0}; + float lisvel[3] = {0,0,0}; +#ifdef WIN32 + float lisori[6] = {0,1,0,0,0,1}; +#else + float lisori[6] = {0,0,1,0,-1,0}; +#endif + + alListenerfv(AL_POSITION, lispos); + alListenerfv(AL_VELOCITY, lisvel); + alListenerfv(AL_ORIENTATION, lisori); +} + + + +// source playstate stuff //////////////////////////////////////////////////////////// + + + +/* sets the buffer */ +void SND_OpenALDevice::SetObjectBuffer(int id, unsigned int buffer) +{ + alSourcei (m_sources[id], AL_BUFFER, m_buffers[buffer]); +} + + + +// check if the sound's still playing +int SND_OpenALDevice::GetPlayState(int id) +{ + int alstate = 0; + int result = 0; + +#ifdef __APPLE__ + alGetSourcei(m_sources[id], AL_SOURCE_STATE, &alstate); +#else + alGetSourceiv(m_sources[id], AL_SOURCE_STATE, &alstate); +#endif + + switch(alstate) + { + case AL_INITIAL: + { + result = SND_INITIAL; + break; + } + case AL_PLAYING: + { + result = SND_PLAYING; + break; + } + case AL_PAUSED: + { + result = SND_PAUSED; + break; + } + case AL_STOPPED: + { + result = SND_STOPPED; + break; + } + default: + result = SND_UNKNOWN; + } + + return result; +} + + + +// make the source play +void SND_OpenALDevice::PlayObject(int id) +{ + alSourcePlay(m_sources[id]); +} + + + +// make the source stop +void SND_OpenALDevice::StopObject(int id) const +{ + float obpos[3] = {0,0,0}; + float obvel[3] = {0,0,0}; + + alSourcefv(m_sources[id], AL_POSITION, obpos); + alSourcefv(m_sources[id], AL_VELOCITY, obvel); + + alSourcef(m_sources[id], AL_GAIN, 1.0); + alSourcef(m_sources[id], AL_PITCH, 1.0); + alSourcei(m_sources[id], AL_LOOPING, AL_FALSE); + alSourceStop(m_sources[id]); +} + + + +// stop all sources +void SND_OpenALDevice::StopAllObjects() +{ + alSourceStopv(NUM_SOURCES, m_sources); +} + + + +// pause the source +void SND_OpenALDevice::PauseObject(int id) const +{ + alSourcePause(m_sources[id]); +} + + + +// source properties stuff //////////////////////////////////////////////////////////// + + + +// give openal the object's pitch +void SND_OpenALDevice::SetObjectPitch(int id, MT_Scalar pitch) const +{ + alSourcef (m_sources[id], AL_PITCH, (float)pitch); +} + + + +// give openal the object's gain +void SND_OpenALDevice::SetObjectGain(int id, MT_Scalar gain) const +{ + alSourcef (m_sources[id], AL_GAIN, (float)gain); +} + + + +// give openal the object's looping +void SND_OpenALDevice::SetObjectLoop(int id, unsigned int loopmode) const +{ + if (loopmode == SND_LOOP_OFF) + { + //printf("%d - ", id); + alSourcei (m_sources[id], AL_LOOPING, AL_FALSE); + } + else + alSourcei (m_sources[id], AL_LOOPING, AL_TRUE); +} + +void SND_OpenALDevice::SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const +{ + + +} + + +void SND_OpenALDevice::SetObjectMinGain(int id, MT_Scalar mingain) const +{ + alSourcef (m_sources[id], AL_MIN_GAIN, (float)mingain); +} + + + +void SND_OpenALDevice::SetObjectMaxGain(int id, MT_Scalar maxgain) const +{ + alSourcef (m_sources[id], AL_MAX_GAIN, (float)maxgain); +} + + + +void SND_OpenALDevice::SetObjectRollOffFactor(int id, MT_Scalar rollofffactor) const +{ + alSourcef (m_sources[id], AL_ROLLOFF_FACTOR, (float)rollofffactor); +} + + + +void SND_OpenALDevice::SetObjectReferenceDistance(int id, MT_Scalar referencedistance) const +{ + alSourcef (m_sources[id], AL_REFERENCE_DISTANCE, (float)referencedistance); +} + + + +// give openal the object's position +void SND_OpenALDevice::ObjectIs2D(int id) const +{ + float obpos[3] = {0,0,0}; + float obvel[3] = {0,0,0}; + + alSourcefv(m_sources[id], AL_POSITION, obpos); + alSourcefv(m_sources[id], AL_VELOCITY, obvel); +} + + + +void SND_OpenALDevice::SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const +{ + float obpos[3]; + float obvel[3]; + + obpos[0] = (float)position[0] * (float)rollofffactor; //x (l/r) + obpos[1] = (float)position[1] * (float)rollofffactor; + obpos[2] = (float)position[2] * (float)rollofffactor; + + alSourcefv(m_sources[id], AL_POSITION, obpos); + + velocity.getValue(obvel); + alSourcefv(m_sources[id], AL_VELOCITY, obvel); +} + +void SND_OpenALDevice::PlayCD(int track) const +{ +#ifndef __APPLE__ + m_cdrom->PlayCD(track); +#endif +} + + +void SND_OpenALDevice::PauseCD(bool pause) const +{ +#ifndef __APPLE__ + m_cdrom->PauseCD(pause); +#endif +} + +void SND_OpenALDevice::StopCD() const +{ +#ifndef __APPLE__ + SND_CDObject* pCD = SND_CDObject::Instance(); + + if (pCD && pCD->GetUsed()) + { + m_cdrom->StopCD(); + } +#endif +} + +void SND_OpenALDevice::SetCDPlaymode(int playmode) const +{ +#ifndef __APPLE__ + m_cdrom->SetCDPlaymode(playmode); +#endif +} + +void SND_OpenALDevice::SetCDGain(MT_Scalar gain) const +{ +#ifndef __APPLE__ + m_cdrom->SetCDGain(gain); +#endif +} diff --git a/intern/SoundSystem/openal/SND_OpenALDevice.h b/intern/SoundSystem/openal/SND_OpenALDevice.h new file mode 100644 index 00000000000..e54c0443462 --- /dev/null +++ b/intern/SoundSystem/openal/SND_OpenALDevice.h @@ -0,0 +1,110 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_OPENALDEVICE +#define SND_OPENALDEVICE + +#include "SND_AudioDevice.h" +#include "SoundDefines.h" + +typedef struct SDL_CD; + +class SND_OpenALDevice : public SND_AudioDevice +{ +public: + SND_OpenALDevice(); + virtual ~SND_OpenALDevice(); + + SND_WaveSlot* LoadSample(const STR_String& samplename, + void* memlocation, + int size); + + void InitListener(); + void SetListenerGain(float gain) const; + void SetDopplerVelocity(MT_Scalar dopplervelocity) const; + void SetDopplerFactor(MT_Scalar dopplerfactor) const; + void SetListenerRollOffFactor(MT_Scalar rollofffactor) const; + + void MakeCurrent() const; + + void NextFrame() const; + void UseCD() const; + + void SetObjectBuffer(int id, unsigned int buffer); + + int GetPlayState(int id); + void PlayObject(int id); + void StopObject(int id) const; + void StopAllObjects(); + void PauseObject(int id) const; + + void SetObjectLoop(int id, unsigned int loopmode) const; + void SetObjectLoopPoints(int id, unsigned int loopstart, unsigned int loopend) const; + void SetObjectPitch(int id, MT_Scalar pitch) const; + void SetObjectGain(int id, MT_Scalar gain) const; + void SetObjectMinGain(int id, MT_Scalar mingain) const; + void SetObjectMaxGain(int id, MT_Scalar maxgain) const; + void SetObjectRollOffFactor(int id, MT_Scalar rolloff) const; + void SetObjectReferenceDistance(int id, MT_Scalar distance) const; + + void SetObjectTransform(int id, + const MT_Vector3& position, + const MT_Vector3& velocity, + const MT_Matrix3x3& orientation, + const MT_Vector3& lisposition, + const MT_Scalar& rollofffactor) const; + void ObjectIs2D(int id) const; + + void PlayCD(int track) const; + void PauseCD(bool pause) const; + void StopCD() const; + void SetCDPlaymode(int playmode) const; + void SetCDGain(MT_Scalar gain) const; + + void StartUsingDSP() {}; + float* GetSpectrum() { return NULL; } + void StopUsingDSP() {}; + +private: + void* m_context; + void* m_device; + + unsigned int m_buffers[NUM_BUFFERS]; + unsigned int m_sources[NUM_SOURCES]; + bool m_buffersinitialized; + bool m_sourcesinitialized; +#ifndef __APPLE__ + class SND_SDLCDDevice* m_cdrom; +#endif +}; + +#endif //SND_OPENALDEVICE + diff --git a/intern/SoundSystem/openal/pthread_cancel.cpp b/intern/SoundSystem/openal/pthread_cancel.cpp new file mode 100644 index 00000000000..7651417db0b --- /dev/null +++ b/intern/SoundSystem/openal/pthread_cancel.cpp @@ -0,0 +1,70 @@ +/* $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * FreeBSD 3.4 does not yet have pthread_cancel (3.5 and above do) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef __FreeBSD__ + +#include + +#if (__FreeBSD_version < 350000) +#include + +#define FD_READ 0x1 +#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts) +#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type) + +int pthread_cancel(pthread_t pthread) { + pthread_exit(NULL); + return 0; +} + +long fpathconf(int fd, int name) +{ + long ret; + + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + ret = _thread_sys_fpathconf(fd, name); + _FD_UNLOCK(fd, FD_READ); + } + return ret; +} + +#endif + +int pthread_atfork(void *a, void *b, void *c) { + return 0; +} + +#endif diff --git a/intern/SoundSystem/sdl/Makefile b/intern/SoundSystem/sdl/Makefile new file mode 100644 index 00000000000..0a1632c4a41 --- /dev/null +++ b/intern/SoundSystem/sdl/Makefile @@ -0,0 +1,46 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = SDLSoundSystem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += $(NAN_SDLCFLAGS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../intern +CPPFLAGS += -I.. +CPPFLAGS += -I. diff --git a/intern/SoundSystem/sdl/SND_SDLCDDevice.cpp b/intern/SoundSystem/sdl/SND_SDLCDDevice.cpp new file mode 100644 index 00000000000..e2419b47269 --- /dev/null +++ b/intern/SoundSystem/sdl/SND_SDLCDDevice.cpp @@ -0,0 +1,155 @@ +/* + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * SND_SDLCDDevice + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "MT_Scalar.h" + +#include "SND_SDLCDDevice.h" +#include "SoundDefines.h" + +#include + +SND_SDLCDDevice::SND_SDLCDDevice() : + m_cdrom(NULL), + m_cdplaying(false), + m_cdtrack(0), + m_cdplaymode(SND_CD_TRACK), + m_frame(0) +{ + init(); +} + +void SND_SDLCDDevice::init() +{ + if (SDL_InitSubSystem(SDL_INIT_CDROM)) + { + fprintf(stderr, "Error initializing CDROM\n"); + return; + } + + /* Check for CD drives */ + if(!SDL_CDNumDrives()) + { + /* None found */ + fprintf(stderr, "No CDROM devices available\n"); + return; + } + + /* Open the default drive */ + m_cdrom = SDL_CDOpen(0); + + /* Did if open? Check if cdrom is NULL */ + if(!m_cdrom) + { + fprintf(stderr, "Couldn't open drive: %s", SDL_GetError()); + return; + } +} + +SND_SDLCDDevice::~SND_SDLCDDevice() +{ + StopCD(); + SDL_CDClose(m_cdrom); +} + +void SND_SDLCDDevice::NextFrame() +{ + m_frame++; + m_frame &= 127; + + if (!m_frame && m_cdrom && m_cdplaying && SDL_CDStatus(m_cdrom) == CD_STOPPED) + { + switch (m_cdplaymode) + { + case SND_CD_ALL: + if (m_cdtrack < m_cdrom->numtracks) + PlayCD(m_cdtrack + 1); + else + m_cdplaying = false; + break; + default: + case SND_CD_TRACK: + m_cdplaying = false; + break; + case SND_CD_TRACKLOOP: + PlayCD(m_cdtrack); + break; + } + + } +} + +void SND_SDLCDDevice::PlayCD(int track) +{ + if ( m_cdrom && CD_INDRIVE(SDL_CDStatus(m_cdrom)) ) { + SDL_CDPlayTracks(m_cdrom, track-1, 0, track, 0); + m_cdplaying = true; + m_cdtrack = track; + } +} + + +void SND_SDLCDDevice::PauseCD(bool pause) +{ + if (!m_cdrom) + return; + + if (pause) + SDL_CDPause(m_cdrom); + else + SDL_CDResume(m_cdrom); +} + +void SND_SDLCDDevice::StopCD() +{ + if (m_cdrom) + SDL_CDStop(m_cdrom); + m_cdplaying = false; +} + +void SND_SDLCDDevice::SetCDPlaymode(int playmode) +{ + m_cdplaymode = playmode; +} + +void SND_SDLCDDevice::SetCDGain(MT_Scalar gain) +{ + +} diff --git a/intern/SoundSystem/sdl/SND_SDLCDDevice.h b/intern/SoundSystem/sdl/SND_SDLCDDevice.h new file mode 100644 index 00000000000..829f361ea22 --- /dev/null +++ b/intern/SoundSystem/sdl/SND_SDLCDDevice.h @@ -0,0 +1,61 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SND_SDLCDDEVICE +#define SND_SDLCDDEVICE + +typedef struct SDL_CD; + +class SND_SDLCDDevice +{ +public: + SND_SDLCDDevice(); + ~SND_SDLCDDevice(); + + void NextFrame(); + + void PlayCD(int track); + void PauseCD(bool pause); + void StopCD(); + void SetCDPlaymode(int playmode); + void SetCDGain(MT_Scalar gain); + +private: + void init(); + /* CD Audio */ + SDL_CD* m_cdrom; + bool m_cdplaying; + int m_cdtrack; + unsigned char m_cdplaymode; + unsigned char m_frame; +}; + +#endif diff --git a/intern/bmfont/BMF_Api.h b/intern/bmfont/BMF_Api.h new file mode 100644 index 00000000000..1b4a4ee3129 --- /dev/null +++ b/intern/bmfont/BMF_Api.h @@ -0,0 +1,164 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * API of the OpenGL bitmap font library. + * Currently draws fonts using the glBitmap routine. + * This implies that drawing speed is heavyly dependant on + * the 2D capabilities of the graphics card. + */ + +#ifndef __BMF_API_H +#define __BMF_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BMF_Fonts.h" + +/** + * Returns the font for a given font type. + * @param font The font to retrieve. + * @return The font (or nil if not found). + */ +BMF_Font* BMF_GetFont(BMF_FontType font); + +/** + * Draws a character at the current raster position. + * @param font The font to use. + * @param c The character to draw. + * @return Indication of success (0 == error). + */ +int BMF_DrawCharacter(BMF_Font* font, char c); + +/** + * Draws a string at the current raster position. + * @param font The font to use. + * @param str The string to draw. + * @return Indication of success (0 == error). + */ +int BMF_DrawString(BMF_Font* font, char* str); + +/** + * Returns the width of a character in pixels. + * @param font The font to use. + * @param c The character. + * @return The length. + */ +int BMF_GetCharacterWidth(BMF_Font* font, char c); + +/** + * Returns the width of a string of characters. + * @param font The font to use. + * @param str The string. + * @return The length. + */ +int BMF_GetStringWidth(BMF_Font* font, char* str); + +/** + * Returns the bounding box of a string of characters. + * @param font The font to use. + * @param str The string. + * @param llx Lower left x coord + * @param lly Lower left y coord + * @param urx Upper right x coord + * @param ury Upper right y coord + */ +void BMF_GetStringBoundingBox(BMF_Font* font, char* str, float*llx, float *lly, float *urx, float *ury); + + +/** + * Returns the bounding box of the font. The width and + * height represent the bounding box of the union of + * all glyps. The minimum and maximum values of the + * box represent the extent of the font and its positioning + * about the origin. + */ +void BMF_GetFontBoundingBox(BMF_Font* font, int *xmin_r, int *ymin_r, int *xmax_r, int *ymax_r); + +/** + * Same as GetFontBoundingBox but only returns the height + */ +int BMF_GetFontHeight(BMF_Font* font); + +/** + * Convert the given @a font to a texture, and return the GL texture + * ID of the texture. If the texture ID is bound, text can + * be drawn using the texture by calling DrawStringTexture. + * + * @param font The font to create the texture from. + * @return The GL texture ID of the new texture, or -1 if unable + * to create. + */ +int BMF_GetFontTexture(BMF_Font* font); + +/** + * Draw the given @a str at the point @a x, @a y, @a z, using + * texture coordinates. This assumes that an appropriate texture + * has been bound, see BMF_BitmapFont::GetTexture(). The string + * is drawn along the positive X axis. + * + * @param font The font to draw with. + * @param string The c-string to draw. + * @param x The x coordinate to start drawing at. + * @param y The y coordinate to start drawing at. + * @param z The z coordinate to start drawing at. + */ +void BMF_DrawStringTexture(BMF_Font* font, char* string, float x, float y, float z); + + /** + * Draw the given @a string at the point @a xpos, @a ypos using + * char and float buffers. + * + * @param string The c-string to draw. + * @param xpos The x coordinate to start drawing at. + * @param ypos The y coordinate to start drawing at. + * @param fgcol The forground color. + * @param bgcol The background color. + * @param buf Unsigned char image buffer, when NULL to not operate on it. + * @param fbuf float image buffer, when NULL to not operate on it. + * @param w image buffer width. + * @param h image buffer height. + */ +void BMF_DrawStringBuf(BMF_Font* font, char *str, int posx, int posy, float *col, unsigned char *buf, float *fbuf, int w, int h); + + +#ifdef __cplusplus +} +#endif + +#endif /* __BMF_API_H */ + diff --git a/intern/bmfont/BMF_Fonts.h b/intern/bmfont/BMF_Fonts.h new file mode 100644 index 00000000000..bf7c370e47e --- /dev/null +++ b/intern/bmfont/BMF_Fonts.h @@ -0,0 +1,77 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Defines the names of the fonts in the library. + */ + +#ifndef __BMF_FONTS_H +#define __BMF_FONTS_H + +#include "BMF_Settings.h" + +typedef enum +{ + BMF_kHelvetica10 = 0, +#if BMF_INCLUDE_HELV12 + BMF_kHelvetica12, +#endif +#if BMF_INCLUDE_HELVB8 + BMF_kHelveticaBold8, +#endif +#if BMF_INCLUDE_HELVB10 + BMF_kHelveticaBold10, +#endif +#if BMF_INCLUDE_HELVB12 + BMF_kHelveticaBold12, +#endif +#if BMF_INCLUDE_HELVB14 + BMF_kHelveticaBold14, +#endif +#if BMF_INCLUDE_SCR12 + BMF_kScreen12, +#endif +#if BMF_INCLUDE_SCR14 + BMF_kScreen14, +#endif +#if BMF_INCLUDE_SCR15 + BMF_kScreen15, +#endif + BMF_kNumFonts +} BMF_FontType; + +typedef struct BMF_Font BMF_Font; + +#endif /* __BMF_FONTS_H */ + diff --git a/intern/bmfont/BMF_Settings.h b/intern/bmfont/BMF_Settings.h new file mode 100644 index 00000000000..247f9e474fc --- /dev/null +++ b/intern/bmfont/BMF_Settings.h @@ -0,0 +1,70 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Allows you to determine which fonts to include in the library. + */ + +#ifndef __BMF_SETTINGS_H +#define __BMF_SETTINGS_H + +/* This font is included always */ +#define BMF_INCLUDE_HELV10 1 + +#ifndef BMF_MINIMAL + +/* These fonts are included with the minimal setting defined */ +#define BMF_INCLUDE_HELV12 1 +#define BMF_INCLUDE_HELVB8 1 +#define BMF_INCLUDE_HELVB10 1 +#define BMF_INCLUDE_HELVB12 1 +#define BMF_INCLUDE_HELVB14 1 +#define BMF_INCLUDE_SCR12 1 +#define BMF_INCLUDE_SCR14 1 +#define BMF_INCLUDE_SCR15 1 + +#else /* BMF_MINIMAL */ +#define BMF_INCLUDE_HELV12 0 +#define BMF_INCLUDE_HELVB8 0 +#define BMF_INCLUDE_HELVB10 0 +#define BMF_INCLUDE_HELVB12 0 +#define BMF_INCLUDE_HELVB14 0 +#define BMF_INCLUDE_SCR12 0 +#define BMF_INCLUDE_SCR14 0 +#define BMF_INCLUDE_SCR15 0 + +#endif /* BMF_MINIMAL */ + +#endif /* __BMF_SETTINGS_H */ + diff --git a/intern/bmfont/CMakeLists.txt b/intern/bmfont/CMakeLists.txt new file mode 100644 index 00000000000..e3b8242ceac --- /dev/null +++ b/intern/bmfont/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . intern) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_bmfont "${SRC}" "${INC}") +#, libtype=['intern','player'], priority = [20, 185] ) diff --git a/intern/bmfont/Makefile b/intern/bmfont/Makefile new file mode 100644 index 00000000000..9c0193fee1b --- /dev/null +++ b/intern/bmfont/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bmfont main makefile. +# + +include nan_definitions.mk + +LIBNAME = bmfont +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not ready yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_BMFONT) ] || mkdir $(NAN_BMFONT) + @[ -d $(NAN_BMFONT)/include ] || mkdir $(NAN_BMFONT)/include + @[ -d $(NAN_BMFONT)/lib ] || mkdir $(NAN_BMFONT)/lib + @[ -d $(NAN_BMFONT)/lib/debug ] || mkdir $(NAN_BMFONT)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libbmfont.a $(NAN_BMFONT)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libbmfont.a $(NAN_BMFONT)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_BMFONT)/lib/libbmfont.a + ranlib $(NAN_BMFONT)/lib/debug/libbmfont.a +endif + @../tools/cpifdiff.sh *.h $(NAN_BMFONT)/include/ + diff --git a/intern/bmfont/SConscript b/intern/bmfont/SConscript new file mode 100644 index 00000000000..4febe2735e7 --- /dev/null +++ b/intern/bmfont/SConscript @@ -0,0 +1,10 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. intern' +incs += ' ' + env['BF_OPENGL_INC'] +defs = '' + +env.BlenderLib ('bf_bmfont', sources, Split(incs), Split(defs), libtype=['intern','player'], priority = [20, 185] ) diff --git a/intern/bmfont/intern/BMF_Api.cpp b/intern/bmfont/intern/BMF_Api.cpp new file mode 100644 index 00000000000..eaa8ffb939d --- /dev/null +++ b/intern/bmfont/intern/BMF_Api.cpp @@ -0,0 +1,186 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * Implementation of the API of the OpenGL bitmap font library. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_Api.h" + +#include "BMF_BitmapFont.h" + + +#if BMF_INCLUDE_HELV10 +extern BMF_FontData BMF_font_helv10; +static BMF_BitmapFont bmfHelv10(&BMF_font_helv10); +#endif // BMF_INCLUDE_HELV10 +#if BMF_INCLUDE_HELV12 +extern BMF_FontData BMF_font_helv12; +static BMF_BitmapFont bmfHelv12(&BMF_font_helv12); +#endif // BMF_INCLUDE_HELV12 +#if BMF_INCLUDE_HELVB8 +extern BMF_FontData BMF_font_helvb8; +static BMF_BitmapFont bmfHelvb8(&BMF_font_helvb8); +#endif // BMF_INCLUDE_HELVB8 +#if BMF_INCLUDE_HELVB10 +extern BMF_FontData BMF_font_helvb10; +static BMF_BitmapFont bmfHelvb10(&BMF_font_helvb10); +#endif // BMF_INCLUDE_HELVB10 +#if BMF_INCLUDE_HELVB12 +extern BMF_FontData BMF_font_helvb12; +static BMF_BitmapFont bmfHelvb12(&BMF_font_helvb12); +#endif // BMF_INCLUDE_HELVB12 +#if BMF_INCLUDE_HELVB14 +extern BMF_FontData BMF_font_helvb14; +static BMF_BitmapFont bmfHelvb14(&BMF_font_helvb14); +#endif // BMF_INCLUDE_HELVB14 +#if BMF_INCLUDE_SCR12 +extern BMF_FontData BMF_font_scr12; +static BMF_BitmapFont bmfScreen12(&BMF_font_scr12); +#endif // BMF_INCLUDE_SCR12 +#if BMF_INCLUDE_SCR14 +extern BMF_FontData BMF_font_scr14; +static BMF_BitmapFont bmfScreen14(&BMF_font_scr14); +#endif // BMF_INCLUDE_SCR14 +#if BMF_INCLUDE_SCR15 +extern BMF_FontData BMF_font_scr15; +static BMF_BitmapFont bmfScreen15(&BMF_font_scr15); +#endif // BMF_INCLUDE_SCR15 + + +BMF_Font* BMF_GetFont(BMF_FontType font) +{ + switch (font) + { +#if BMF_INCLUDE_HELV10 + case BMF_kHelvetica10: return (BMF_Font*) &bmfHelv10; +#endif // BMF_INCLUDE_HELV10 +#if BMF_INCLUDE_HELV12 + case BMF_kHelvetica12: return (BMF_Font*) &bmfHelv12; +#endif // BMF_INCLUDE_HELV12 +#if BMF_INCLUDE_HELVB8 + case BMF_kHelveticaBold8: return (BMF_Font*) &bmfHelvb8; +#endif // BMF_INCLUDE_HELVB8 +#if BMF_INCLUDE_HELVB10 + case BMF_kHelveticaBold10: return (BMF_Font*) &bmfHelvb10; +#endif // BMF_INCLUDE_HELVB10 +#if BMF_INCLUDE_HELVB12 + case BMF_kHelveticaBold12: return (BMF_Font*) &bmfHelvb12; +#endif // BMF_INCLUDE_HELVB12 +#if BMF_INCLUDE_HELVB14 + case BMF_kHelveticaBold14: return (BMF_Font*) &bmfHelvb14; +#endif // BMF_INCLUDE_HELVB12 +#if BMF_INCLUDE_SCR12 + case BMF_kScreen12: return (BMF_Font*) &bmfScreen12; +#endif // BMF_INCLUDE_SCR12 +#if BMF_INCLUDE_SCR14 + case BMF_kScreen14: return (BMF_Font*) &bmfScreen14; +#endif // BMF_INCLUDE_SCR14 +#if BMF_INCLUDE_SCR15 + case BMF_kScreen15: return (BMF_Font*) &bmfScreen15; +#endif // BMF_INCLUDE_SCR15 + default: + break; + } + return 0; +} + + +int BMF_DrawCharacter(BMF_Font* font, char c) +{ + char str[2] = {c, '\0'}; + return BMF_DrawString(font, str); +} + + +int BMF_DrawString(BMF_Font* font, char* str) +{ + if (!font) return 0; + ((BMF_BitmapFont*)font)->DrawString(str); + return 1; +} + + +int BMF_GetCharacterWidth(BMF_Font* font, char c) +{ + char str[2] = {c, '\0'}; + return BMF_GetStringWidth(font, str); +} + + +int BMF_GetStringWidth(BMF_Font* font, char* str) +{ + if (!font) return 0; + return ((BMF_BitmapFont*)font)->GetStringWidth(str); +} + +void BMF_GetStringBoundingBox(BMF_Font* font, char* str, float*llx, float *lly, float *urx, float *ury){ + if (!font){ + *llx = *lly = *urx = *ury = 0; + }else{ + ((BMF_BitmapFont*)font)->GetStringBoundingBox(str, llx, lly, urx, ury); + } +} + +void BMF_GetFontBoundingBox(BMF_Font* font, int *xmin_r, int *ymin_r, int *xmax_r, int *ymax_r) +{ + if (!font) return; + ((BMF_BitmapFont*)font)->GetFontBoundingBox(*xmin_r, *ymin_r, *xmax_r, *ymax_r); +} + +int BMF_GetFontHeight(BMF_Font* font) +{ + if (!font) return -1; + return ((BMF_BitmapFont*)font)->GetFontHeight(); +} + +int BMF_GetFontTexture(BMF_Font* font) { + if (!font) return -1; + return ((BMF_BitmapFont*)font)->GetTexture(); +} + +void BMF_DrawStringTexture(BMF_Font* font, char *string, float x, float y, float z) { + if (!font) return; + ((BMF_BitmapFont*)font)->DrawStringTexture(string, x, y, z); +} + +void BMF_DrawStringBuf(BMF_Font* font, char *str, int posx, int posy, float *col, unsigned char *buf, float *fbuf, int w, int h) { + if (!font) return; + ((BMF_BitmapFont*)font)->DrawStringBuf(str, posx, posy, col, buf, fbuf, w, h); +} diff --git a/intern/bmfont/intern/BMF_BitmapFont.cpp b/intern/bmfont/intern/BMF_BitmapFont.cpp new file mode 100644 index 00000000000..2ea14b4b203 --- /dev/null +++ b/intern/bmfont/intern/BMF_BitmapFont.cpp @@ -0,0 +1,322 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + */ + + +#include + + + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) || defined(__APPLE__) + #ifdef WIN32 + #if !defined(__CYGWIN32__) + #pragma warning(disable:4244) + #endif /* __CYGWIN32__ */ + #include + #include + #else // WIN32 + // __APPLE__ is defined + #include + #endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) + #include +#endif // defined(WIN32) || defined(__APPLE__) + +#include "BMF_BitmapFont.h" + + +BMF_BitmapFont::BMF_BitmapFont(BMF_FontData* fontData) +: m_fontData(fontData) +{ +} + + +BMF_BitmapFont::~BMF_BitmapFont(void) +{ +} + +void BMF_BitmapFont::DrawString(char* str) +{ + GLint alignment; + unsigned char c; + + glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + while ( (c = (unsigned char) *str++) ) { + BMF_CharData & cd = m_fontData->chars[c]; + + if (cd.data_offset==-1) { + GLubyte nullBitmap = 0; + + glBitmap(1, 1, 0, 0, cd.advance, 0, &nullBitmap); + } else { + GLubyte *bitmap = &m_fontData->bitmap_data[cd.data_offset]; + + glBitmap(cd.width, cd.height, cd.xorig, cd.yorig, cd.advance, 0, bitmap); + } + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); +} + + +int BMF_BitmapFont::GetStringWidth(char* str) +{ + unsigned char c; + int length = 0; + + while ( (c = (unsigned char) *str++) ) { + length += m_fontData->chars[c].advance; + } + + return length; +} + +void BMF_BitmapFont::GetFontBoundingBox(int & xMin, int & yMin, int & xMax, int & yMax) +{ + xMin = m_fontData->xmin; + yMin = m_fontData->ymin; + xMax = m_fontData->xmax; + yMax = m_fontData->ymax; +} + +int BMF_BitmapFont::GetFontHeight( void ) +{ + return m_fontData->ymax - m_fontData->ymin; +} + +void BMF_BitmapFont::GetStringBoundingBox(char* str, float*llx, float *lly, float *urx, float *ury) +{ + unsigned char c; + int length = 0; + int ascent = 0; + int descent = 0; + + while ( (c = (unsigned char) *str++) ) { + length += m_fontData->chars[c].advance; + int d = m_fontData->chars[c].yorig; + int a = m_fontData->chars[c].height - m_fontData->chars[c].yorig; + if(a > ascent) ascent = a; + if(d > descent) descent = d; + } + *llx = (float)0; + *lly = (float)-descent; + *urx = (float)length; + *ury = (float)ascent; +} + + +int BMF_BitmapFont::GetTexture() +{ + int fWidth = m_fontData->xmax - m_fontData->xmin; + int fHeight = m_fontData->ymax - m_fontData->ymin; + + if (fWidth>=16 || fHeight>=16) { + return -1; + } + + int cRows = 16, cCols = 16; + int cWidth = 16, cHeight = 16; + int iWidth = cCols*cWidth; + int iHeight = cRows*cHeight; + GLubyte *img = new GLubyte [iHeight*iWidth]; + GLuint texId; + + int baseLine = -(m_fontData->ymin); + + memset(img, 0, iHeight*iWidth); + for (int i = 0; i<256; i++) { + BMF_CharData & cd = m_fontData->chars[i]; + + if (cd.data_offset != -1) { + int cellX = i%16; + int cellY = i/16; + + for (int y = 0; ybitmap_data[cd.data_offset + ((cd.width+7)/8)*y]; + + for (int x = 0; xymin); + + glBegin(GL_QUADS); + while ( (c = (unsigned char) *str++) ) { + BMF_CharData & cd = m_fontData->chars[c]; + + if (cd.data_offset != -1) { + float cellX = (c%16)/16.0; + float cellY = (c/16)/16.0; + + glTexCoord2f(cellX + 1.0/16.0, cellY); + glVertex3f(x + pos + 16.0, -baseLine + y + 0.0, z); + + glTexCoord2f(cellX + 1.0/16.0, cellY + 1.0/16.0); + glVertex3f(x + pos + 16.0, -baseLine + y + 16.0, z); + + glTexCoord2f(cellX, cellY + 1.0/16.0); + glVertex3f(x + pos + 0.0, -baseLine + y + 16.0, z); + + glTexCoord2f(cellX, cellY); + glVertex3f(x + pos + 0.0, -baseLine + y + 0.0, z); + } + + pos += cd.advance; + } + glEnd(); +} + +#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val)) +void BMF_BitmapFont::DrawStringBuf(char *str, int posx, int posy, float *col, unsigned char *buf, float *fbuf, int w, int h) +{ + int x, y; + + if (buf==0 && fbuf==0) + return; + + /*offset for font*/ + posx -= m_fontData->xmin; + posy -= m_fontData->ymin; + + if (buf) { + unsigned char colch[4]; + unsigned char *max, *pixel; + unsigned char c; + + for (x=0; x<4; x++) { + colch[x] = FTOCHAR(col[x]); + } + + max = buf + (4 * (w * h)); + while ((c = (unsigned char) *str++)) { + BMF_CharData & cd = m_fontData->chars[c]; + if (cd.data_offset != -1) { + for (y = 0; y < cd.height; y++) { + unsigned char* chrRow = &m_fontData->bitmap_data[cd.data_offset + ((cd.width+7)/8)*y]; + for (x = cd.xorig; x < cd.width; x++) { + pixel = buf + 4 * (((posy + y - cd.yorig) * w) + (posx + x)); + if ((pixel < max) && (pixel > buf)) { + int byteIdx = x/8; + int bitIdx = 7 - (x%8); + + if (chrRow[byteIdx]&(1<chars[c]; + if (cd.data_offset != -1) { + for (y = 0; y < cd.height; y++) { + unsigned char* chrRow = &m_fontData->bitmap_data[cd.data_offset + ((cd.width+7)/8)*y]; + for (x = cd.xorig; x < cd.width; x++) { + pixel = fbuf + 4 * (((posy + y - cd.yorig) * w) + (posx + x)); + if ((pixel < max) && (pixel > fbuf)) { + int byteIdx = x/8; + int bitIdx = 7 - (x%8); + + if (chrRow[byteIdx]&(1< +#endif + +#include "BMF_FontData.h" + +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELV10 + +static unsigned char bitmap_data[]= { + 0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80, + 0xa0,0xa0,0x50,0x50,0xf8,0x28,0x7c,0x28, + 0x28,0x20,0x70,0xa8,0x28,0x70,0xa0,0xa8, + 0x70,0x20,0x26,0x29,0x16,0x10,0x08,0x68, + 0x94,0x64,0x64,0x98,0x98,0xa4,0x60,0x50, + 0x50,0x20,0x80,0x40,0x40,0x20,0x40,0x40, + 0x80,0x80,0x80,0x80,0x40,0x40,0x20,0x80, + 0x40,0x40,0x20,0x20,0x20,0x20,0x40,0x40, + 0x80,0xa0,0x40,0xa0,0x20,0x20,0xf8,0x20, + 0x20,0x80,0x40,0x40,0xf8,0x80,0x80,0x80, + 0x40,0x40,0x40,0x40,0x20,0x20,0x70,0x88, + 0x88,0x88,0x88,0x88,0x88,0x70,0x40,0x40, + 0x40,0x40,0x40,0x40,0xc0,0x40,0xf8,0x80, + 0x40,0x30,0x08,0x08,0x88,0x70,0x70,0x88, + 0x08,0x08,0x30,0x08,0x88,0x70,0x10,0x10, + 0xf8,0x90,0x50,0x50,0x30,0x10,0x70,0x88, + 0x08,0x08,0xf0,0x80,0x80,0xf8,0x70,0x88, + 0x88,0xc8,0xb0,0x80,0x88,0x70,0x40,0x40, + 0x20,0x20,0x10,0x10,0x08,0xf8,0x70,0x88, + 0x88,0x88,0x70,0x88,0x88,0x70,0x70,0x88, + 0x08,0x68,0x98,0x88,0x88,0x70,0x80,0x00, + 0x00,0x00,0x00,0x80,0x80,0x40,0x40,0x00, + 0x00,0x00,0x00,0x40,0x20,0x40,0x80,0x40, + 0x20,0xf0,0x00,0xf0,0x80,0x40,0x20,0x40, + 0x80,0x40,0x00,0x40,0x40,0x20,0x10,0x90, + 0x60,0x3e,0x00,0x40,0x00,0x9b,0x00,0xa4, + 0x80,0xa4,0x80,0xa2,0x40,0x92,0x40,0x4d, + 0x40,0x20,0x80,0x1f,0x00,0x82,0x82,0x7c, + 0x44,0x28,0x28,0x10,0x10,0xf0,0x88,0x88, + 0x88,0xf0,0x88,0x88,0xf0,0x78,0x84,0x80, + 0x80,0x80,0x80,0x84,0x78,0xf0,0x88,0x84, + 0x84,0x84,0x84,0x88,0xf0,0xf8,0x80,0x80, + 0x80,0xf8,0x80,0x80,0xf8,0x80,0x80,0x80, + 0x80,0xf0,0x80,0x80,0xf8,0x74,0x8c,0x84, + 0x8c,0x80,0x80,0x84,0x78,0x84,0x84,0x84, + 0x84,0xfc,0x84,0x84,0x84,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x60,0x90,0x10, + 0x10,0x10,0x10,0x10,0x10,0x88,0x88,0x90, + 0x90,0xe0,0xa0,0x90,0x88,0xf0,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x92,0x92,0x92, + 0xaa,0xaa,0xc6,0xc6,0x82,0x8c,0x8c,0x94, + 0x94,0xa4,0xa4,0xc4,0xc4,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x78,0x80,0x80,0x80, + 0x80,0xf0,0x88,0x88,0xf0,0x02,0x7c,0x8c, + 0x94,0x84,0x84,0x84,0x84,0x78,0x88,0x88, + 0x88,0x88,0xf0,0x88,0x88,0xf0,0x70,0x88, + 0x88,0x08,0x70,0x80,0x88,0x70,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0xf8,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x10,0x28, + 0x28,0x44,0x44,0x44,0x82,0x82,0x22,0x00, + 0x22,0x00,0x22,0x00,0x55,0x00,0x49,0x00, + 0x49,0x00,0x88,0x80,0x88,0x80,0x88,0x88, + 0x50,0x50,0x20,0x50,0x88,0x88,0x10,0x10, + 0x10,0x28,0x28,0x44,0x44,0x82,0xf8,0x80, + 0x40,0x20,0x20,0x10,0x08,0xf8,0xc0,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, + 0x20,0x20,0x40,0x40,0x40,0x40,0x80,0x80, + 0xc0,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0xc0,0x88,0x50,0x50,0x20,0x20,0xfc, + 0x80,0x80,0x40,0x68,0x90,0x90,0x70,0x10, + 0xe0,0xb0,0xc8,0x88,0x88,0xc8,0xb0,0x80, + 0x80,0x60,0x90,0x80,0x80,0x90,0x60,0x68, + 0x98,0x88,0x88,0x98,0x68,0x08,0x08,0x60, + 0x90,0x80,0xf0,0x90,0x60,0x40,0x40,0x40, + 0x40,0x40,0xe0,0x40,0x30,0x70,0x08,0x68, + 0x98,0x88,0x88,0x98,0x68,0x88,0x88,0x88, + 0x88,0xc8,0xb0,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x80,0x90,0x90, + 0xa0,0xc0,0xa0,0x90,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x92,0x92, + 0x92,0x92,0x92,0xec,0x88,0x88,0x88,0x88, + 0xc8,0xb0,0x70,0x88,0x88,0x88,0x88,0x70, + 0x80,0x80,0xb0,0xc8,0x88,0x88,0xc8,0xb0, + 0x08,0x08,0x68,0x98,0x88,0x88,0x98,0x68, + 0x80,0x80,0x80,0x80,0xc0,0xa0,0x60,0x90, + 0x10,0x60,0x90,0x60,0x60,0x40,0x40,0x40, + 0x40,0xe0,0x40,0x40,0x70,0x90,0x90,0x90, + 0x90,0x90,0x20,0x20,0x50,0x50,0x88,0x88, + 0x28,0x28,0x54,0x54,0x92,0x92,0x88,0x88, + 0x50,0x20,0x50,0x88,0x80,0x40,0x40,0x60, + 0xa0,0xa0,0x90,0x90,0xf0,0x80,0x40,0x20, + 0x10,0xf0,0x20,0x40,0x40,0x40,0x40,0x80, + 0x40,0x40,0x40,0x20,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x40, + 0x40,0x40,0x40,0x20,0x40,0x40,0x40,0x80, + 0x98,0x64,0x80,0x80,0x80,0x80,0x80,0x80, + 0x00,0x80,0x40,0x70,0xa8,0xa0,0xa0,0xa8, + 0x70,0x10,0xb0,0x48,0x40,0x40,0xe0,0x40, + 0x48,0x30,0x90,0x60,0x90,0x90,0x60,0x90, + 0x20,0xf8,0x20,0xf8,0x50,0x50,0x88,0x88, + 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80, + 0x80,0x80,0x70,0x88,0x18,0x70,0xc8,0x98, + 0x70,0xc0,0x88,0x70,0xa0,0x38,0x44,0x9a, + 0xa2,0x9a,0x44,0x38,0xe0,0x00,0xa0,0x20, + 0xe0,0x28,0x50,0xa0,0x50,0x28,0x08,0x08, + 0xf8,0xe0,0x38,0x44,0xaa,0xb2,0xba,0x44, + 0x38,0xe0,0x60,0x90,0x90,0x60,0xf8,0x00, + 0x20,0x20,0xf8,0x20,0x20,0xe0,0x40,0xa0, + 0x60,0xc0,0x20,0x40,0xe0,0x80,0x40,0x80, + 0x80,0xf0,0x90,0x90,0x90,0x90,0x90,0x28, + 0x28,0x28,0x28,0x28,0x68,0xe8,0xe8,0xe8, + 0x7c,0xc0,0xc0,0x40,0x40,0x40,0xc0,0x40, + 0xe0,0x00,0xe0,0xa0,0xe0,0xa0,0x50,0x28, + 0x50,0xa0,0x21,0x00,0x17,0x80,0x13,0x00, + 0x09,0x00,0x48,0x00,0x44,0x00,0xc4,0x00, + 0x42,0x00,0x27,0x12,0x15,0x0b,0x48,0x44, + 0xc4,0x42,0x21,0x00,0x17,0x80,0x13,0x00, + 0x09,0x00,0xc8,0x00,0x24,0x00,0x44,0x00, + 0xe2,0x00,0x60,0x90,0x80,0x40,0x20,0x20, + 0x00,0x20,0x82,0x82,0x7c,0x44,0x28,0x28, + 0x10,0x10,0x00,0x10,0x20,0x82,0x82,0x7c, + 0x44,0x28,0x28,0x10,0x10,0x00,0x10,0x08, + 0x82,0x82,0x7c,0x44,0x28,0x28,0x10,0x10, + 0x00,0x28,0x10,0x82,0x82,0x7c,0x44,0x28, + 0x28,0x10,0x10,0x00,0x28,0x14,0x82,0x82, + 0x7c,0x44,0x28,0x28,0x10,0x10,0x00,0x28, + 0x82,0x82,0x7c,0x44,0x28,0x28,0x10,0x10, + 0x10,0x28,0x10,0x8f,0x80,0x88,0x00,0x78, + 0x00,0x48,0x00,0x2f,0x80,0x28,0x00,0x18, + 0x00,0x1f,0x80,0x30,0x10,0x78,0x84,0x80, + 0x80,0x80,0x80,0x84,0x78,0xf8,0x80,0x80, + 0x80,0xf8,0x80,0x80,0xf8,0x00,0x20,0x40, + 0xf8,0x80,0x80,0x80,0xf8,0x80,0x80,0xf8, + 0x00,0x20,0x10,0xf8,0x80,0x80,0xf8,0x80, + 0x80,0x80,0xf8,0x00,0x50,0x20,0xf8,0x80, + 0x80,0x80,0xf8,0x80,0x80,0xf8,0x00,0x50, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x00,0x40,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x00,0x80,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x00,0xa0, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x00,0xa0,0x78,0x44,0x42,0x42,0xf2, + 0x42,0x44,0x78,0x8c,0x8c,0x94,0x94,0xa4, + 0xa4,0xc4,0xc4,0x00,0x50,0x28,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x10, + 0x20,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x78,0x00,0x10,0x08,0x78,0x84,0x84,0x84, + 0x84,0x84,0x84,0x78,0x00,0x28,0x10,0x78, + 0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00, + 0x50,0x28,0x78,0x84,0x84,0x84,0x84,0x84, + 0x84,0x78,0x00,0x48,0x88,0x50,0x20,0x50, + 0x88,0x80,0x78,0xc4,0xa4,0xa4,0x94,0x94, + 0x8c,0x78,0x04,0x78,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x00,0x10,0x20,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x20, + 0x10,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x00,0x28,0x10,0x78,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x00,0x48,0x10,0x10, + 0x10,0x28,0x28,0x44,0x44,0x82,0x00,0x10, + 0x08,0x80,0x80,0xf0,0x88,0x88,0xf0,0x80, + 0x80,0xa0,0x90,0x90,0x90,0xa0,0x90,0x90, + 0x60,0x68,0x90,0x90,0x70,0x10,0xe0,0x00, + 0x20,0x40,0x68,0x90,0x90,0x70,0x10,0xe0, + 0x00,0x20,0x10,0x68,0x90,0x90,0x70,0x10, + 0xe0,0x00,0x50,0x20,0x68,0x90,0x90,0x70, + 0x10,0xe0,0x00,0xa0,0x50,0x68,0x90,0x90, + 0x70,0x10,0xe0,0x00,0x50,0x68,0x90,0x90, + 0x70,0x10,0xe0,0x20,0x50,0x20,0x6c,0x92, + 0x90,0x7e,0x12,0xec,0x60,0x20,0x60,0x90, + 0x80,0x80,0x90,0x60,0x60,0x90,0x80,0xf0, + 0x90,0x60,0x00,0x20,0x40,0x60,0x90,0x80, + 0xf0,0x90,0x60,0x00,0x40,0x20,0x60,0x90, + 0x80,0xf0,0x90,0x60,0x00,0x50,0x20,0x60, + 0x90,0x80,0xf0,0x90,0x60,0x00,0x50,0x40, + 0x40,0x40,0x40,0x40,0x40,0x00,0x40,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, + 0xa0,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x00,0xa0,0x70,0x88,0x88,0x88,0x88,0x78, + 0x90,0x60,0x50,0x90,0x90,0x90,0x90,0x90, + 0xe0,0x00,0xa0,0x50,0x70,0x88,0x88,0x88, + 0x88,0x70,0x00,0x20,0x40,0x70,0x88,0x88, + 0x88,0x88,0x70,0x00,0x20,0x10,0x70,0x88, + 0x88,0x88,0x88,0x70,0x00,0x50,0x20,0x70, + 0x88,0x88,0x88,0x88,0x70,0x00,0x50,0x28, + 0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x50, + 0x20,0x00,0xf8,0x00,0x20,0x70,0x88,0xc8, + 0xa8,0x98,0x74,0x70,0x90,0x90,0x90,0x90, + 0x90,0x00,0x20,0x40,0x70,0x90,0x90,0x90, + 0x90,0x90,0x00,0x40,0x20,0x70,0x90,0x90, + 0x90,0x90,0x90,0x00,0x50,0x20,0x70,0x90, + 0x90,0x90,0x90,0x90,0x00,0x50,0x80,0x40, + 0x40,0x60,0xa0,0xa0,0x90,0x90,0x00,0x20, + 0x10,0x80,0x80,0xb0,0xc8,0x88,0x88,0xc8, + 0xb0,0x80,0x80,0x80,0x40,0x40,0x60,0xa0, + 0xa0,0x90,0x90,0x00,0x50, +}; + +BMF_FontData BMF_font_helv10 = { + -1, -2, + 10, 11, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 12, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 3, -1}, + {1, 8, -1, 0, 3, 0}, + {3, 2, -1, -6, 4, 8}, + {6, 7, 0, 0, 6, 10}, + {5, 9, 0, 1, 6, 17}, + {8, 8, 0, 0, 9, 26}, + {6, 8, -1, 0, 8, 34}, + {2, 3, -1, -5, 3, 42}, + {3, 10, 0, 2, 4, 45}, + {3, 10, -1, 2, 4, 55}, + {3, 3, 0, -5, 4, 65}, + {5, 5, 0, -1, 6, 68}, + {2, 3, 0, 2, 3, 73}, + {5, 1, -1, -3, 7, 76}, + {1, 1, -1, 0, 3, 77}, + {3, 8, 0, 0, 3, 78}, + {5, 8, 0, 0, 6, 86}, + {2, 8, -1, 0, 6, 94}, + {5, 8, 0, 0, 6, 102}, + {5, 8, 0, 0, 6, 110}, + {5, 8, 0, 0, 6, 118}, + {5, 8, 0, 0, 6, 126}, + {5, 8, 0, 0, 6, 134}, + {5, 8, 0, 0, 6, 142}, + {5, 8, 0, 0, 6, 150}, + {5, 8, 0, 0, 6, 158}, + {1, 6, -1, 0, 3, 166}, + {2, 8, 0, 2, 3, 172}, + {3, 5, -1, -1, 6, 180}, + {4, 3, 0, -2, 5, 185}, + {3, 5, -1, -1, 6, 188}, + {4, 8, -1, 0, 6, 193}, + {10, 10, 0, 2, 11, 201}, + {7, 8, 0, 0, 7, 221}, + {5, 8, -1, 0, 7, 229}, + {6, 8, -1, 0, 8, 237}, + {6, 8, -1, 0, 8, 245}, + {5, 8, -1, 0, 7, 253}, + {5, 8, -1, 0, 6, 261}, + {6, 8, -1, 0, 8, 269}, + {6, 8, -1, 0, 8, 277}, + {1, 8, -1, 0, 3, 285}, + {4, 8, 0, 0, 5, 293}, + {5, 8, -1, 0, 7, 301}, + {4, 8, -1, 0, 6, 309}, + {7, 8, -1, 0, 9, 317}, + {6, 8, -1, 0, 8, 325}, + {6, 8, -1, 0, 8, 333}, + {5, 8, -1, 0, 7, 341}, + {7, 9, -1, 1, 8, 349}, + {5, 8, -1, 0, 7, 358}, + {5, 8, -1, 0, 7, 366}, + {5, 8, 0, 0, 5, 374}, + {6, 8, -1, 0, 8, 382}, + {7, 8, 0, 0, 7, 390}, + {9, 8, 0, 0, 9, 398}, + {5, 8, -1, 0, 7, 414}, + {7, 8, 0, 0, 7, 422}, + {5, 8, -1, 0, 7, 430}, + {2, 10, -1, 2, 3, 438}, + {3, 8, 0, 0, 3, 448}, + {2, 10, 0, 2, 3, 456}, + {5, 5, 0, -3, 6, 466}, + {6, 1, 0, 2, 6, 471}, + {2, 3, 0, -5, 3, 472}, + {5, 6, 0, 0, 5, 475}, + {5, 8, 0, 0, 6, 481}, + {4, 6, 0, 0, 5, 489}, + {5, 8, 0, 0, 6, 495}, + {4, 6, 0, 0, 5, 503}, + {4, 8, 0, 0, 4, 509}, + {5, 8, 0, 2, 6, 517}, + {5, 8, 0, 0, 6, 525}, + {1, 8, 0, 0, 2, 533}, + {1, 9, 0, 1, 2, 541}, + {4, 8, 0, 0, 5, 550}, + {1, 8, 0, 0, 2, 558}, + {7, 6, 0, 0, 8, 566}, + {5, 6, 0, 0, 6, 572}, + {5, 6, 0, 0, 6, 578}, + {5, 8, 0, 2, 6, 584}, + {5, 8, 0, 2, 6, 592}, + {3, 6, 0, 0, 4, 600}, + {4, 6, 0, 0, 5, 606}, + {3, 8, 0, 0, 4, 612}, + {4, 6, 0, 0, 5, 620}, + {5, 6, 0, 0, 6, 626}, + {7, 6, 0, 0, 8, 632}, + {5, 6, 0, 0, 6, 638}, + {4, 8, 0, 2, 5, 644}, + {4, 6, 0, 0, 5, 652}, + {3, 10, 0, 2, 3, 658}, + {1, 10, -1, 2, 3, 668}, + {3, 10, 0, 2, 3, 678}, + {6, 2, 0, -3, 7, 688}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 3, -1}, + {1, 8, -1, 2, 3, 690}, + {5, 8, 0, 1, 6, 698}, + {5, 8, 0, 0, 6, 706}, + {4, 6, 0, -1, 5, 714}, + {5, 8, 0, 0, 6, 720}, + {1, 10, -1, 2, 3, 728}, + {5, 10, 0, 2, 6, 738}, + {3, 1, 0, -7, 3, 748}, + {7, 7, -1, 0, 9, 749}, + {3, 5, 0, -3, 4, 756}, + {5, 5, 0, 0, 6, 761}, + {5, 3, -1, -2, 7, 766}, + {3, 1, 0, -3, 4, 769}, + {7, 7, -1, 0, 9, 770}, + {3, 1, 0, -7, 3, 777}, + {4, 4, 0, -3, 4, 778}, + {5, 7, 0, 0, 6, 782}, + {3, 4, 0, -3, 3, 789}, + {3, 4, 0, -3, 3, 793}, + {2, 2, 0, -6, 3, 797}, + {4, 8, 0, 2, 5, 799}, + {6, 10, 0, 2, 6, 807}, + {2, 1, 0, -3, 3, 817}, + {2, 2, 0, 2, 3, 818}, + {2, 4, 0, -3, 3, 820}, + {3, 5, 0, -3, 4, 824}, + {5, 5, 0, 0, 6, 829}, + {9, 8, 0, 0, 9, 834}, + {8, 8, 0, 0, 9, 850}, + {9, 8, 0, 0, 9, 858}, + {4, 8, -1, 2, 6, 874}, + {7, 11, 0, 0, 7, 882}, + {7, 11, 0, 0, 7, 893}, + {7, 11, 0, 0, 7, 904}, + {7, 11, 0, 0, 7, 915}, + {7, 10, 0, 0, 7, 926}, + {7, 11, 0, 0, 7, 936}, + {9, 8, 0, 0, 10, 947}, + {6, 10, -1, 2, 8, 963}, + {5, 11, -1, 0, 7, 973}, + {5, 11, -1, 0, 7, 984}, + {5, 11, -1, 0, 7, 995}, + {5, 10, -1, 0, 7, 1006}, + {2, 11, 0, 0, 3, 1016}, + {2, 11, -1, 0, 3, 1027}, + {3, 11, 0, 0, 3, 1038}, + {3, 10, 0, 0, 3, 1049}, + {7, 8, 0, 0, 8, 1059}, + {6, 11, -1, 0, 8, 1067}, + {6, 11, -1, 0, 8, 1078}, + {6, 11, -1, 0, 8, 1089}, + {6, 11, -1, 0, 8, 1100}, + {6, 11, -1, 0, 8, 1111}, + {6, 10, -1, 0, 8, 1122}, + {5, 5, 0, -1, 6, 1132}, + {6, 10, -1, 1, 8, 1137}, + {6, 11, -1, 0, 8, 1147}, + {6, 11, -1, 0, 8, 1158}, + {6, 11, -1, 0, 8, 1169}, + {6, 10, -1, 0, 8, 1180}, + {7, 11, 0, 0, 7, 1190}, + {5, 8, -1, 0, 7, 1201}, + {4, 8, 0, 0, 5, 1209}, + {5, 9, 0, 0, 5, 1217}, + {5, 9, 0, 0, 5, 1226}, + {5, 9, 0, 0, 5, 1235}, + {5, 9, 0, 0, 5, 1244}, + {5, 8, 0, 0, 5, 1253}, + {5, 9, 0, 0, 5, 1261}, + {7, 6, 0, 0, 8, 1270}, + {4, 8, 0, 2, 5, 1276}, + {4, 9, 0, 0, 5, 1284}, + {4, 9, 0, 0, 5, 1293}, + {4, 9, 0, 0, 5, 1302}, + {4, 8, 0, 0, 5, 1311}, + {2, 9, 1, 0, 2, 1319}, + {2, 9, 0, 0, 2, 1328}, + {3, 9, 1, 0, 2, 1337}, + {3, 8, 0, 0, 2, 1346}, + {5, 9, 0, 0, 6, 1354}, + {4, 9, 0, 0, 5, 1363}, + {5, 9, 0, 0, 6, 1372}, + {5, 9, 0, 0, 6, 1381}, + {5, 9, 0, 0, 6, 1390}, + {5, 9, 0, 0, 6, 1399}, + {5, 8, 0, 0, 6, 1408}, + {5, 5, 0, -1, 6, 1416}, + {6, 6, 0, 0, 6, 1421}, + {4, 9, 0, 0, 5, 1427}, + {4, 9, 0, 0, 5, 1436}, + {4, 9, 0, 0, 5, 1445}, + {4, 8, 0, 0, 5, 1454}, + {4, 11, 0, 2, 5, 1462}, + {5, 10, 0, 2, 6, 1473}, + {4, 10, 0, 2, 5, 1483}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helv12.cpp b/intern/bmfont/intern/BMF_font_helv12.cpp new file mode 100644 index 00000000000..813d22475eb --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helv12.cpp @@ -0,0 +1,528 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELV12 + +static unsigned char bitmap_data[]= { + 0x80,0x00,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0xa0,0xa0,0xa0,0x50,0x50,0x50,0xfc, + 0x28,0xfc,0x28,0x28,0x20,0x70,0xa8,0xa8, + 0x28,0x70,0xa0,0xa8,0x70,0x20,0x23,0x00, + 0x14,0x80,0x14,0x80,0x13,0x00,0x08,0x00, + 0x68,0x00,0x94,0x00,0x94,0x00,0x62,0x00, + 0x72,0x8c,0x84,0x8a,0x50,0x30,0x48,0x48, + 0x30,0x80,0x40,0xc0,0x20,0x40,0x40,0x80, + 0x80,0x80,0x80,0x80,0x80,0x40,0x40,0x20, + 0x80,0x40,0x40,0x20,0x20,0x20,0x20,0x20, + 0x20,0x40,0x40,0x80,0xa0,0x40,0xa0,0x20, + 0x20,0xf8,0x20,0x20,0x80,0x40,0x40,0xf8, + 0x80,0x80,0x80,0x40,0x40,0x40,0x20,0x20, + 0x10,0x10,0x70,0x88,0x88,0x88,0x88,0x88, + 0x88,0x88,0x70,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0xe0,0x20,0xf8,0x80,0x80,0x40, + 0x20,0x10,0x08,0x88,0x70,0x70,0x88,0x88, + 0x08,0x08,0x30,0x08,0x88,0x70,0x08,0x08, + 0xfc,0x88,0x48,0x28,0x28,0x18,0x08,0x70, + 0x88,0x88,0x08,0x08,0xf0,0x80,0x80,0xf8, + 0x70,0x88,0x88,0x88,0xc8,0xb0,0x80,0x88, + 0x70,0x40,0x40,0x20,0x20,0x20,0x10,0x10, + 0x08,0xf8,0x70,0x88,0x88,0x88,0x88,0x70, + 0x88,0x88,0x70,0x70,0x88,0x08,0x08,0x78, + 0x88,0x88,0x88,0x70,0x80,0x00,0x00,0x00, + 0x00,0x80,0x80,0x40,0x40,0x00,0x00,0x00, + 0x00,0x40,0x0c,0x30,0xc0,0x30,0x0c,0xf8, + 0x00,0xf8,0xc0,0x30,0x0c,0x30,0xc0,0x20, + 0x00,0x20,0x20,0x10,0x10,0x88,0x88,0x70, + 0x3e,0x00,0x40,0x00,0x9b,0x00,0xa6,0x80, + 0xa2,0x40,0xa2,0x40,0x92,0x40,0x4d,0x40, + 0x60,0x80,0x1f,0x00,0x82,0x82,0x82,0x7c, + 0x44,0x44,0x28,0x28,0x10,0xf8,0x84,0x84, + 0x84,0xf8,0x84,0x84,0x84,0xf8,0x3c,0x42, + 0x80,0x80,0x80,0x80,0x80,0x42,0x3c,0xf8, + 0x84,0x82,0x82,0x82,0x82,0x82,0x84,0xf8, + 0xfc,0x80,0x80,0x80,0xfc,0x80,0x80,0x80, + 0xfc,0x80,0x80,0x80,0x80,0xf8,0x80,0x80, + 0x80,0xfc,0x3a,0x46,0x82,0x82,0x8e,0x80, + 0x80,0x42,0x3c,0x82,0x82,0x82,0x82,0xfe, + 0x82,0x82,0x82,0x82,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x70,0x88,0x88, + 0x08,0x08,0x08,0x08,0x08,0x08,0x82,0x84, + 0x88,0x90,0xe0,0xa0,0x90,0x88,0x84,0xf8, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x88,0x80,0x88,0x80,0x94,0x80,0x94,0x80, + 0xa2,0x80,0xa2,0x80,0xc1,0x80,0xc1,0x80, + 0x80,0x80,0x82,0x86,0x8a,0x8a,0x92,0xa2, + 0xa2,0xc2,0x82,0x3c,0x42,0x81,0x81,0x81, + 0x81,0x81,0x42,0x3c,0x80,0x80,0x80,0x80, + 0xf8,0x84,0x84,0x84,0xf8,0x3d,0x42,0x85, + 0x89,0x81,0x81,0x81,0x42,0x3c,0x84,0x84, + 0x84,0x88,0xf8,0x84,0x84,0x84,0xf8,0x78, + 0x84,0x84,0x04,0x18,0x60,0x80,0x84,0x78, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0xfe,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x10,0x10,0x28,0x28,0x44,0x44, + 0x44,0x82,0x82,0x22,0x00,0x22,0x00,0x22, + 0x00,0x55,0x00,0x55,0x00,0x49,0x00,0x88, + 0x80,0x88,0x80,0x88,0x80,0x82,0x44,0x44, + 0x28,0x10,0x28,0x44,0x44,0x82,0x10,0x10, + 0x10,0x10,0x28,0x44,0x44,0x82,0x82,0xfe, + 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0xfe, + 0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xc0,0x10,0x10,0x20,0x20, + 0x20,0x40,0x40,0x80,0x80,0xc0,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0xc0,0x88,0x50,0x20,0xfe,0xc0,0x80,0x40, + 0x74,0x88,0x88,0x78,0x08,0x88,0x70,0xb0, + 0xc8,0x88,0x88,0x88,0xc8,0xb0,0x80,0x80, + 0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x68, + 0x98,0x88,0x88,0x88,0x98,0x68,0x08,0x08, + 0x70,0x88,0x80,0xf8,0x88,0x88,0x70,0x40, + 0x40,0x40,0x40,0x40,0x40,0xe0,0x40,0x30, + 0x70,0x88,0x08,0x68,0x98,0x88,0x88,0x88, + 0x98,0x68,0x88,0x88,0x88,0x88,0x88,0xc8, + 0xb0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x00,0x80,0x80,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x40, + 0x88,0x90,0xa0,0xc0,0xc0,0xa0,0x90,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x92,0x92,0x92,0x92,0x92,0xda, + 0xa4,0x88,0x88,0x88,0x88,0x88,0xc8,0xb0, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x80, + 0x80,0x80,0xb0,0xc8,0x88,0x88,0x88,0xc8, + 0xb0,0x08,0x08,0x08,0x68,0x98,0x88,0x88, + 0x88,0x98,0x68,0x80,0x80,0x80,0x80,0x80, + 0xc0,0xa0,0x60,0x90,0x10,0x60,0x80,0x90, + 0x60,0x60,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x40,0x40,0x68,0x98,0x88,0x88,0x88,0x88, + 0x88,0x20,0x20,0x50,0x50,0x88,0x88,0x88, + 0x22,0x00,0x22,0x00,0x55,0x00,0x49,0x00, + 0x49,0x00,0x88,0x80,0x88,0x80,0x84,0x84, + 0x48,0x30,0x30,0x48,0x84,0x80,0x40,0x20, + 0x20,0x50,0x50,0x90,0x88,0x88,0x88,0xf0, + 0x80,0x40,0x40,0x20,0x10,0xf0,0x30,0x40, + 0x40,0x40,0x40,0x40,0x80,0x40,0x40,0x40, + 0x40,0x30,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x20, + 0x20,0x20,0x20,0x20,0x10,0x20,0x20,0x20, + 0x20,0xc0,0x98,0x64,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x80,0x40,0x70, + 0xc8,0xa0,0xa0,0xa0,0xa8,0x70,0x10,0xb0, + 0x48,0x20,0x20,0xf0,0x40,0x40,0x48,0x30, + 0x84,0x78,0x48,0x48,0x78,0x84,0x20,0x20, + 0xf8,0x20,0xf8,0x20,0x50,0x88,0x88,0x80, + 0x80,0x80,0x80,0x00,0x00,0x00,0x80,0x80, + 0x80,0x80,0x70,0x88,0x08,0x30,0x48,0x88, + 0x88,0x90,0x60,0x80,0x88,0x70,0xa0,0x3e, + 0x00,0x41,0x00,0x9c,0x80,0xa2,0x80,0xa0, + 0x80,0xa2,0x80,0x9c,0x80,0x41,0x00,0x3e, + 0x00,0xe0,0x00,0xa0,0x20,0xe0,0x28,0x50, + 0xa0,0x50,0x28,0x04,0x04,0x04,0xfc,0xf0, + 0x3e,0x00,0x41,0x00,0x94,0x80,0x94,0x80, + 0x98,0x80,0x94,0x80,0x9c,0x80,0x41,0x00, + 0x3e,0x00,0xf0,0x60,0x90,0x90,0x60,0xf8, + 0x00,0x20,0x20,0xf8,0x20,0x20,0xf0,0x40, + 0x20,0x90,0x60,0xc0,0x20,0x40,0x20,0xe0, + 0x80,0x40,0x80,0x80,0x80,0xe8,0x98,0x88, + 0x88,0x88,0x88,0x88,0x28,0x28,0x28,0x28, + 0x28,0x28,0x68,0xe8,0xe8,0xe8,0x68,0x3c, + 0x80,0xc0,0x20,0x20,0x40,0x40,0x40,0x40, + 0xc0,0x40,0xe0,0x00,0xe0,0xa0,0xe0,0xa0, + 0x50,0x28,0x50,0xa0,0x41,0x00,0x27,0x80, + 0x15,0x00,0x13,0x00,0x49,0x00,0x44,0x00, + 0x44,0x00,0xc2,0x00,0x41,0x00,0x47,0x80, + 0x22,0x00,0x11,0x00,0x14,0x80,0x4b,0x00, + 0x48,0x00,0x44,0x00,0xc2,0x00,0x41,0x00, + 0x21,0x00,0x17,0x80,0x15,0x00,0x0b,0x00, + 0xc9,0x00,0x24,0x00,0x44,0x00,0x22,0x00, + 0xe1,0x00,0x70,0x88,0x88,0x40,0x40,0x20, + 0x20,0x00,0x20,0x82,0x82,0x82,0x7c,0x44, + 0x44,0x28,0x10,0x10,0x00,0x10,0x20,0x82, + 0x82,0x82,0x7c,0x44,0x44,0x28,0x10,0x10, + 0x00,0x10,0x08,0x82,0x82,0x82,0x7c,0x44, + 0x44,0x28,0x10,0x10,0x00,0x28,0x10,0x82, + 0x82,0x82,0x7c,0x44,0x44,0x28,0x10,0x10, + 0x00,0x28,0x14,0x82,0x82,0x82,0x7c,0x44, + 0x44,0x28,0x10,0x10,0x00,0x28,0x82,0x82, + 0x82,0x7c,0x44,0x44,0x28,0x10,0x10,0x10, + 0x28,0x10,0x8f,0x80,0x88,0x00,0x88,0x00, + 0x78,0x00,0x4f,0x80,0x48,0x00,0x28,0x00, + 0x28,0x00,0x1f,0x80,0x30,0x08,0x08,0x3c, + 0x42,0x80,0x80,0x80,0x80,0x80,0x42,0x3c, + 0xfc,0x80,0x80,0x80,0xfc,0x80,0x80,0x80, + 0xfc,0x00,0x10,0x20,0xfc,0x80,0x80,0x80, + 0xfc,0x80,0x80,0x80,0xfc,0x00,0x10,0x08, + 0xfc,0x80,0x80,0x80,0xfc,0x80,0x80,0x80, + 0xfc,0x00,0x28,0x10,0xfc,0x80,0x80,0x80, + 0xfc,0x80,0x80,0x80,0xfc,0x00,0x28,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x00,0x40,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x80,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x00,0xa0,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x00,0xa0,0x7c,0x42, + 0x41,0x41,0xf1,0x41,0x41,0x42,0x7c,0x82, + 0x86,0x8a,0x8a,0x92,0xa2,0xa2,0xc2,0x82, + 0x00,0x28,0x14,0x3c,0x42,0x81,0x81,0x81, + 0x81,0x81,0x42,0x3c,0x00,0x08,0x10,0x3c, + 0x42,0x81,0x81,0x81,0x81,0x81,0x42,0x3c, + 0x00,0x08,0x04,0x3c,0x42,0x81,0x81,0x81, + 0x81,0x81,0x42,0x3c,0x00,0x14,0x08,0x3c, + 0x42,0x81,0x81,0x81,0x81,0x81,0x42,0x3c, + 0x00,0x28,0x14,0x3c,0x42,0x81,0x81,0x81, + 0x81,0x81,0x42,0x3c,0x00,0x24,0x88,0x50, + 0x20,0x50,0x88,0x80,0x00,0x5e,0x00,0x21, + 0x00,0x50,0x80,0x48,0x80,0x44,0x80,0x44, + 0x80,0x42,0x80,0x21,0x00,0x1e,0x80,0x00, + 0x40,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x00,0x10,0x20,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x10, + 0x08,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x00,0x28,0x10,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x48, + 0x10,0x10,0x10,0x10,0x28,0x44,0x44,0x82, + 0x82,0x00,0x10,0x08,0x80,0x80,0xf8,0x84, + 0x84,0x84,0xf8,0x80,0x80,0xb0,0x88,0x88, + 0x88,0xb0,0x88,0x88,0x88,0x70,0x74,0x88, + 0x88,0x78,0x08,0x88,0x70,0x00,0x10,0x20, + 0x74,0x88,0x88,0x78,0x08,0x88,0x70,0x00, + 0x20,0x10,0x74,0x88,0x88,0x78,0x08,0x88, + 0x70,0x00,0x50,0x20,0x74,0x88,0x88,0x78, + 0x08,0x88,0x70,0x00,0x50,0x28,0x74,0x88, + 0x88,0x78,0x08,0x88,0x70,0x00,0x50,0x74, + 0x88,0x88,0x78,0x08,0x88,0x70,0x30,0x48, + 0x30,0x77,0x00,0x88,0x80,0x88,0x00,0x7f, + 0x80,0x08,0x80,0x88,0x80,0x77,0x00,0x60, + 0x10,0x20,0x70,0x88,0x80,0x80,0x80,0x88, + 0x70,0x70,0x88,0x80,0xf8,0x88,0x88,0x70, + 0x00,0x20,0x40,0x70,0x88,0x80,0xf8,0x88, + 0x88,0x70,0x00,0x20,0x10,0x70,0x88,0x80, + 0xf8,0x88,0x88,0x70,0x00,0x50,0x20,0x70, + 0x88,0x80,0xf8,0x88,0x88,0x70,0x00,0x50, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00, + 0x40,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x00,0x80,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x00,0xa0,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x00,0xa0,0x70, + 0x88,0x88,0x88,0x88,0x78,0x08,0x50,0x30, + 0x68,0x88,0x88,0x88,0x88,0x88,0xc8,0xb0, + 0x00,0x50,0x28,0x70,0x88,0x88,0x88,0x88, + 0x88,0x70,0x00,0x20,0x40,0x70,0x88,0x88, + 0x88,0x88,0x88,0x70,0x00,0x20,0x10,0x70, + 0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x50, + 0x20,0x70,0x88,0x88,0x88,0x88,0x88,0x70, + 0x00,0x50,0x28,0x70,0x88,0x88,0x88,0x88, + 0x88,0x70,0x00,0x50,0x20,0x00,0xf8,0x00, + 0x20,0xb8,0x44,0x64,0x54,0x4c,0x44,0x3a, + 0x68,0x98,0x88,0x88,0x88,0x88,0x88,0x00, + 0x20,0x40,0x68,0x98,0x88,0x88,0x88,0x88, + 0x88,0x00,0x20,0x10,0x68,0x98,0x88,0x88, + 0x88,0x88,0x88,0x00,0x50,0x20,0x68,0x98, + 0x88,0x88,0x88,0x88,0x88,0x00,0x50,0x80, + 0x40,0x20,0x20,0x50,0x50,0x90,0x88,0x88, + 0x88,0x00,0x20,0x10,0x80,0x80,0x80,0xb0, + 0xc8,0x88,0x88,0x88,0xc8,0xb0,0x80,0x80, + 0xc0,0x20,0x20,0x20,0x30,0x50,0x50,0x48, + 0x88,0x88,0x00,0x50, +}; + +BMF_FontData BMF_font_helv12 = { + 0, -3, + 11, 12, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 16, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 4, -1}, + {1, 9, -1, 0, 3, 0}, + {3, 3, -1, -6, 5, 9}, + {6, 8, 0, 0, 7, 12}, + {5, 10, -1, 1, 7, 20}, + {9, 9, -1, 0, 11, 30}, + {7, 9, -1, 0, 9, 48}, + {2, 3, -1, -6, 3, 57}, + {3, 12, -1, 3, 4, 60}, + {3, 12, 0, 3, 4, 72}, + {3, 3, -1, -6, 5, 84}, + {5, 5, -1, -1, 7, 87}, + {2, 3, -1, 2, 4, 92}, + {5, 1, -1, -3, 8, 95}, + {1, 1, -1, 0, 3, 96}, + {4, 9, 0, 0, 4, 97}, + {5, 9, -1, 0, 7, 106}, + {3, 9, -1, 0, 7, 115}, + {5, 9, -1, 0, 7, 124}, + {5, 9, -1, 0, 7, 133}, + {6, 9, 0, 0, 7, 142}, + {5, 9, -1, 0, 7, 151}, + {5, 9, -1, 0, 7, 160}, + {5, 9, -1, 0, 7, 169}, + {5, 9, -1, 0, 7, 178}, + {5, 9, -1, 0, 7, 187}, + {1, 6, -1, 0, 3, 196}, + {2, 8, 0, 2, 3, 202}, + {6, 5, 0, -1, 7, 210}, + {5, 3, -1, -2, 7, 215}, + {6, 5, -1, -1, 7, 218}, + {5, 9, -1, 0, 7, 223}, + {10, 10, -1, 1, 12, 232}, + {7, 9, -1, 0, 9, 252}, + {6, 9, -1, 0, 8, 261}, + {7, 9, -1, 0, 9, 270}, + {7, 9, -1, 0, 9, 279}, + {6, 9, -1, 0, 8, 288}, + {6, 9, -1, 0, 8, 297}, + {7, 9, -1, 0, 9, 306}, + {7, 9, -1, 0, 9, 315}, + {1, 9, -1, 0, 3, 324}, + {5, 9, -1, 0, 7, 333}, + {7, 9, -1, 0, 8, 342}, + {5, 9, -1, 0, 7, 351}, + {9, 9, -1, 0, 11, 360}, + {7, 9, -1, 0, 9, 378}, + {8, 9, -1, 0, 10, 387}, + {6, 9, -1, 0, 8, 396}, + {8, 9, -1, 0, 10, 405}, + {6, 9, -1, 0, 8, 414}, + {6, 9, -1, 0, 8, 423}, + {7, 9, 0, 0, 7, 432}, + {6, 9, -1, 0, 8, 441}, + {7, 9, -1, 0, 9, 450}, + {9, 9, -1, 0, 11, 459}, + {7, 9, -1, 0, 9, 477}, + {7, 9, -1, 0, 9, 486}, + {7, 9, -1, 0, 9, 495}, + {2, 12, -1, 3, 3, 504}, + {4, 9, 0, 0, 4, 516}, + {2, 12, 0, 3, 3, 525}, + {5, 3, 0, -5, 6, 537}, + {7, 1, 0, 2, 7, 540}, + {2, 3, 0, -6, 3, 541}, + {6, 7, -1, 0, 7, 544}, + {5, 9, -1, 0, 7, 551}, + {5, 7, -1, 0, 7, 560}, + {5, 9, -1, 0, 7, 567}, + {5, 7, -1, 0, 7, 576}, + {4, 9, 0, 0, 3, 583}, + {5, 10, -1, 3, 7, 592}, + {5, 9, -1, 0, 7, 602}, + {1, 9, -1, 0, 3, 611}, + {2, 12, 0, 3, 3, 620}, + {5, 9, -1, 0, 6, 632}, + {1, 9, -1, 0, 3, 641}, + {7, 7, -1, 0, 9, 650}, + {5, 7, -1, 0, 7, 657}, + {5, 7, -1, 0, 7, 664}, + {5, 10, -1, 3, 7, 671}, + {5, 10, -1, 3, 7, 681}, + {3, 7, -1, 0, 4, 691}, + {4, 7, -1, 0, 6, 698}, + {3, 9, 0, 0, 3, 705}, + {5, 7, -1, 0, 7, 714}, + {5, 7, -1, 0, 7, 721}, + {9, 7, 0, 0, 9, 728}, + {6, 7, 0, 0, 6, 742}, + {5, 10, -1, 3, 7, 749}, + {4, 7, -1, 0, 6, 759}, + {4, 12, 0, 3, 4, 766}, + {1, 12, -1, 3, 3, 778}, + {4, 12, 0, 3, 4, 790}, + {6, 2, 0, -3, 7, 802}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 4, -1}, + {1, 10, -1, 3, 3, 804}, + {5, 9, -1, 1, 7, 814}, + {5, 9, -1, 0, 7, 823}, + {6, 6, 0, -1, 7, 832}, + {5, 9, -1, 0, 7, 838}, + {1, 11, -1, 2, 3, 847}, + {5, 12, 0, 3, 6, 858}, + {3, 1, 0, -8, 3, 870}, + {9, 9, -1, 0, 11, 871}, + {3, 5, -1, -4, 5, 889}, + {5, 5, -1, -1, 7, 894}, + {6, 4, -1, -2, 8, 899}, + {4, 1, 0, -3, 5, 903}, + {9, 9, -1, 0, 11, 904}, + {4, 1, 0, -8, 4, 922}, + {4, 4, 0, -4, 5, 923}, + {5, 7, -1, 0, 7, 927}, + {4, 5, 0, -3, 4, 934}, + {3, 5, 0, -3, 4, 939}, + {2, 2, 0, -8, 2, 944}, + {5, 10, -1, 3, 7, 946}, + {6, 12, 0, 3, 7, 956}, + {1, 1, -1, -3, 3, 968}, + {3, 4, 0, 3, 3, 969}, + {2, 5, -1, -3, 4, 973}, + {3, 5, -1, -4, 5, 978}, + {5, 5, -1, -1, 7, 983}, + {9, 9, 0, 0, 10, 988}, + {9, 9, 0, 0, 10, 1006}, + {9, 9, 0, 0, 10, 1024}, + {5, 9, -1, 3, 7, 1042}, + {7, 12, -1, 0, 9, 1051}, + {7, 12, -1, 0, 9, 1063}, + {7, 12, -1, 0, 9, 1075}, + {7, 12, -1, 0, 9, 1087}, + {7, 11, -1, 0, 9, 1099}, + {7, 12, -1, 0, 9, 1110}, + {9, 9, -1, 0, 11, 1122}, + {7, 12, -1, 3, 9, 1140}, + {6, 12, -1, 0, 8, 1152}, + {6, 12, -1, 0, 8, 1164}, + {6, 12, -1, 0, 8, 1176}, + {6, 11, -1, 0, 8, 1188}, + {2, 12, 0, 0, 3, 1199}, + {2, 12, -1, 0, 3, 1211}, + {3, 12, 0, 0, 3, 1223}, + {3, 11, 0, 0, 3, 1235}, + {8, 9, 0, 0, 9, 1246}, + {7, 12, -1, 0, 9, 1255}, + {8, 12, -1, 0, 10, 1267}, + {8, 12, -1, 0, 10, 1279}, + {8, 12, -1, 0, 10, 1291}, + {8, 12, -1, 0, 10, 1303}, + {8, 11, -1, 0, 10, 1315}, + {5, 5, -1, -1, 7, 1326}, + {10, 11, 0, 1, 10, 1331}, + {6, 12, -1, 0, 8, 1353}, + {6, 12, -1, 0, 8, 1365}, + {6, 12, -1, 0, 8, 1377}, + {6, 11, -1, 0, 8, 1389}, + {7, 12, -1, 0, 9, 1400}, + {6, 9, -1, 0, 8, 1412}, + {5, 9, -1, 0, 7, 1421}, + {6, 10, -1, 0, 7, 1430}, + {6, 10, -1, 0, 7, 1440}, + {6, 10, -1, 0, 7, 1450}, + {6, 10, -1, 0, 7, 1460}, + {6, 9, -1, 0, 7, 1470}, + {6, 10, -1, 0, 7, 1479}, + {9, 7, -1, 0, 11, 1489}, + {5, 10, -1, 3, 7, 1503}, + {5, 10, -1, 0, 7, 1513}, + {5, 10, -1, 0, 7, 1523}, + {5, 10, -1, 0, 7, 1533}, + {5, 9, -1, 0, 7, 1543}, + {2, 10, 0, 0, 3, 1552}, + {2, 10, -1, 0, 3, 1562}, + {3, 10, 0, 0, 3, 1572}, + {3, 9, 0, 0, 3, 1582}, + {5, 10, -1, 0, 7, 1591}, + {5, 10, -1, 0, 7, 1601}, + {5, 10, -1, 0, 7, 1611}, + {5, 10, -1, 0, 7, 1621}, + {5, 10, -1, 0, 7, 1631}, + {5, 10, -1, 0, 7, 1641}, + {5, 9, -1, 0, 7, 1651}, + {5, 5, -1, -1, 7, 1660}, + {7, 7, 0, 0, 7, 1665}, + {5, 10, -1, 0, 7, 1672}, + {5, 10, -1, 0, 7, 1682}, + {5, 10, -1, 0, 7, 1692}, + {5, 9, -1, 0, 7, 1702}, + {5, 13, -1, 3, 7, 1711}, + {5, 12, -1, 3, 7, 1724}, + {5, 12, -1, 3, 7, 1736}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helvb10.cpp b/intern/bmfont/intern/BMF_font_helvb10.cpp new file mode 100644 index 00000000000..66583767ffb --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helvb10.cpp @@ -0,0 +1,495 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELVB10 + +static unsigned char bitmap_data[]= { + 0x00,0xc0,0x00,0x80,0x80,0xc0,0xc0,0xc0, + 0xc0,0xa0,0xa0,0xa0,0x50,0x50,0xfc,0x28, + 0x7e,0x28,0x28,0x20,0x70,0xa8,0x28,0x38, + 0x70,0xe0,0xa8,0x70,0x20,0x8c,0x56,0x2c, + 0x10,0x10,0x68,0xb4,0x62,0x76,0xdc,0xcc, + 0xde,0x70,0xd8,0xd8,0x70,0x80,0x40,0xc0, + 0xc0,0x20,0x60,0x40,0xc0,0xc0,0xc0,0xc0, + 0x40,0x60,0x20,0x80,0xc0,0x40,0x60,0x60, + 0x60,0x60,0x40,0xc0,0x80,0xa0,0x40,0xa0, + 0x30,0x30,0xfc,0x30,0x30,0x80,0x40,0xc0, + 0xc0,0xf8,0xc0,0xc0,0x80,0x80,0x40,0x40, + 0x20,0x20,0x10,0x10,0x70,0xd8,0xd8,0xd8, + 0xd8,0xd8,0xd8,0x70,0x60,0x60,0x60,0x60, + 0x60,0x60,0xe0,0x60,0xf8,0xc0,0x60,0x30, + 0x18,0x18,0xd8,0x70,0x70,0xd8,0x18,0x18, + 0x30,0x18,0xd8,0x70,0x18,0x18,0xfc,0x98, + 0x58,0x38,0x18,0x08,0x70,0xd8,0x98,0x18, + 0xf0,0xc0,0xc0,0xf8,0x70,0xd8,0xd8,0xd8, + 0xf0,0xc0,0xd8,0x70,0x60,0x60,0x60,0x30, + 0x30,0x18,0x18,0xf8,0x70,0xd8,0xd8,0xd8, + 0x70,0xd8,0xd8,0x70,0x70,0xd8,0x18,0x78, + 0xd8,0xd8,0xd8,0x70,0xc0,0xc0,0x00,0x00, + 0xc0,0xc0,0x80,0x40,0xc0,0xc0,0x00,0x00, + 0xc0,0xc0,0x30,0x60,0xc0,0x60,0x30,0xf8, + 0x00,0xf8,0xc0,0x60,0x30,0x60,0xc0,0x60, + 0x00,0x60,0x60,0x30,0x18,0xd8,0x70,0x3e, + 0x00,0x40,0x00,0x9b,0x00,0xa4,0x80,0xa2, + 0x40,0x92,0x40,0x4d,0x40,0x60,0x80,0x1f, + 0x00,0xc6,0xc6,0xfe,0x6c,0x6c,0x6c,0x38, + 0x38,0xf8,0xcc,0xcc,0xcc,0xf8,0xcc,0xcc, + 0xf8,0x3c,0x66,0xc2,0xc0,0xc0,0xc2,0x66, + 0x3c,0xf0,0xd8,0xcc,0xcc,0xcc,0xcc,0xd8, + 0xf0,0xf8,0xc0,0xc0,0xc0,0xf8,0xc0,0xc0, + 0xf8,0xc0,0xc0,0xc0,0xc0,0xf0,0xc0,0xc0, + 0xf8,0x3a,0x66,0xc6,0xce,0xc0,0xc2,0x66, + 0x3c,0xcc,0xcc,0xcc,0xcc,0xfc,0xcc,0xcc, + 0xcc,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0x70,0xd8,0x18,0x18,0x18,0x18,0x18, + 0x18,0xc6,0xcc,0xd8,0xf0,0xe0,0xf0,0xd8, + 0xcc,0xf8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc9,0x80,0xc9,0x80,0xdd,0x80,0xd5, + 0x80,0xf7,0x80,0xe3,0x80,0xe3,0x80,0xc1, + 0x80,0xc6,0xce,0xce,0xd6,0xd6,0xe6,0xe6, + 0xc6,0x38,0x6c,0xc6,0xc6,0xc6,0xc6,0x6c, + 0x38,0xc0,0xc0,0xc0,0xf8,0xcc,0xcc,0xcc, + 0xf8,0x02,0x3c,0x6c,0xd6,0xc6,0xc6,0xc6, + 0x6c,0x38,0xcc,0xcc,0xcc,0xf8,0xcc,0xcc, + 0xcc,0xf8,0x78,0xcc,0x8c,0x1c,0x78,0xe0, + 0xcc,0x78,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0xfc,0x78,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0x10,0x38,0x38,0x6c,0x6c,0x6c, + 0xc6,0xc6,0x33,0x00,0x33,0x00,0x7f,0x80, + 0x6d,0x80,0x6d,0x80,0xcc,0xc0,0xcc,0xc0, + 0xcc,0xc0,0xc6,0xc6,0x6c,0x38,0x38,0x6c, + 0xc6,0xc6,0x18,0x18,0x18,0x3c,0x66,0x66, + 0xc3,0xc3,0xfc,0xc0,0x60,0x70,0x30,0x18, + 0x0c,0xfc,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xe0,0x10,0x10,0x20,0x20, + 0x40,0x40,0x80,0x80,0xe0,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0xe0,0x90,0x90, + 0xf0,0x60,0xfc,0xc0,0xc0,0x80,0x40,0x6c, + 0xd8,0xd8,0x78,0x98,0x70,0xf0,0xd8,0xd8, + 0xd8,0xd8,0xf0,0xc0,0xc0,0x70,0xd0,0xc0, + 0xc0,0xd0,0x70,0x78,0xd8,0xd8,0xd8,0xd8, + 0x78,0x18,0x18,0x70,0xd8,0xc0,0xf8,0xd8, + 0x70,0x60,0x60,0x60,0x60,0x60,0xf0,0x60, + 0x38,0x70,0x18,0x78,0xd8,0xd8,0xd8,0xd8, + 0x68,0xd8,0xd8,0xd8,0xd8,0xd8,0xf0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00, + 0xc0,0xc0,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x00,0x60,0xcc,0xd8,0xf0,0xe0,0xf0, + 0xd8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xdb,0xdb,0xdb,0xdb,0xdb, + 0xb6,0xd8,0xd8,0xd8,0xd8,0xd8,0xb0,0x70, + 0xd8,0xd8,0xd8,0xd8,0x70,0xc0,0xc0,0xf0, + 0xd8,0xd8,0xd8,0xd8,0xb0,0x18,0x18,0x78, + 0xd8,0xd8,0xd8,0xd8,0x68,0xc0,0xc0,0xc0, + 0xc0,0xe0,0xb0,0x70,0xd8,0x18,0x70,0xd8, + 0x70,0x30,0x60,0x60,0x60,0x60,0xf0,0x60, + 0x60,0x68,0xd8,0xd8,0xd8,0xd8,0xd8,0x20, + 0x70,0x50,0xd8,0xd8,0xd8,0x6c,0x6c,0x6c, + 0xd6,0xd6,0xd6,0xcc,0xcc,0x78,0x30,0x78, + 0xcc,0x60,0x30,0x30,0x78,0xd8,0xd8,0xd8, + 0xd8,0xf8,0xc0,0x60,0x30,0x18,0xf8,0x30, + 0x60,0x60,0x60,0x60,0xc0,0x60,0x60,0x60, + 0x30,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xc0,0x60,0x60,0x60,0x60, + 0x30,0x60,0x60,0x60,0xc0,0xb0,0x68,0x00, + 0xc0,0xc0,0xc0,0xc0,0x40,0x40,0x00,0xc0, + 0x40,0x70,0xd8,0xa0,0xa0,0xd8,0x70,0x10, + 0xd8,0x68,0x60,0x60,0xf0,0x60,0x68,0x38, + 0x84,0x78,0x48,0x48,0x78,0x84,0x30,0xfc, + 0x30,0xfc,0x48,0xcc,0x84,0x84,0x80,0x80, + 0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80, + 0x70,0x98,0x38,0x70,0xc8,0x98,0x70,0xe0, + 0xc8,0x70,0xa0,0x3c,0x42,0x9d,0xa1,0xa5, + 0x99,0x42,0x3c,0xe0,0x00,0xa0,0x20,0xe0, + 0x6c,0xd8,0x6c,0x08,0x08,0xf8,0xf0,0x3c, + 0x42,0xa5,0xb9,0xa5,0xbd,0x42,0x3c,0xe0, + 0xc0,0xa0,0x60,0xfc,0x00,0x30,0x30,0xfc, + 0x30,0x30,0xe0,0x40,0xa0,0x60,0xc0,0x20, + 0x40,0xe0,0x80,0x40,0xc0,0xc0,0xe8,0xd8, + 0xd8,0xd8,0xd8,0xd8,0x28,0x28,0x28,0x28, + 0x28,0x68,0xe8,0xe8,0xe8,0x7c,0xc0,0xc0, + 0x40,0x40,0x40,0xc0,0x40,0xe0,0x00,0xe0, + 0xa0,0xe0,0xd8,0x6c,0xd8,0x42,0x2f,0x26, + 0x12,0x48,0x48,0xc4,0x44,0x4e,0x24,0x2a, + 0x16,0x48,0x48,0xc4,0x44,0x42,0x2f,0x26, + 0x12,0xc8,0x28,0x44,0xe4,0x70,0xd8,0xc0, + 0x60,0x30,0x30,0x00,0x30,0xc6,0xc6,0xfe, + 0x6c,0x6c,0x6c,0x38,0x38,0x00,0x10,0x20, + 0xc6,0xc6,0xfe,0x6c,0x6c,0x6c,0x38,0x38, + 0x00,0x10,0x08,0xc6,0xc6,0xfe,0x6c,0x6c, + 0x6c,0x38,0x38,0x00,0x28,0x10,0xc6,0xc6, + 0xfe,0x6c,0x6c,0x6c,0x38,0x38,0x00,0x28, + 0x14,0xc6,0xc6,0xfe,0x6c,0x6c,0x6c,0x38, + 0x38,0x00,0x28,0xc6,0xc6,0xfe,0x6c,0x6c, + 0x6c,0x38,0x38,0x10,0x28,0x10,0xcf,0x80, + 0xcc,0x00,0xfc,0x00,0x6c,0x00,0x6f,0x80, + 0x6c,0x00,0x3c,0x00,0x3f,0x80,0x30,0x10, + 0x3c,0x66,0xc2,0xc0,0xc0,0xc2,0x66,0x3c, + 0xf8,0xc0,0xc0,0xc0,0xf8,0xc0,0xc0,0xf8, + 0x00,0x20,0x40,0xf8,0xc0,0xc0,0xc0,0xf8, + 0xc0,0xc0,0xf8,0x00,0x20,0x10,0xf8,0xc0, + 0xc0,0xc0,0xf8,0xc0,0xc0,0xf8,0x00,0x50, + 0x20,0xf8,0xc0,0xc0,0xc0,0xf8,0xc0,0xc0, + 0xf8,0x00,0x50,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0x00,0x40,0x80,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x80, + 0x40,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x00,0xa0,0x40,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x00,0x90,0x78,0x6c, + 0x66,0x66,0xf6,0x66,0x6c,0x78,0xc6,0xce, + 0xce,0xd6,0xd6,0xe6,0xe6,0xc6,0x00,0x28, + 0x14,0x38,0x6c,0xc6,0xc6,0xc6,0xc6,0x6c, + 0x38,0x00,0x08,0x10,0x38,0x6c,0xc6,0xc6, + 0xc6,0xc6,0x6c,0x38,0x00,0x10,0x08,0x38, + 0x6c,0xc6,0xc6,0xc6,0xc6,0x6c,0x38,0x00, + 0x28,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xc6, + 0x6c,0x38,0x00,0x28,0x14,0x38,0x6c,0xc6, + 0xc6,0xc6,0xc6,0x6c,0x38,0x00,0x28,0xcc, + 0x78,0x30,0x78,0xcc,0xb8,0x6c,0xe6,0xd6, + 0xd6,0xce,0x6c,0x3a,0x78,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0x00,0x10,0x20,0x78, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x00, + 0x10,0x08,0x78,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0x00,0x50,0x20,0x78,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0x00,0x48,0x18, + 0x18,0x18,0x3c,0x66,0x66,0xc3,0xc3,0x00, + 0x08,0x04,0xc0,0xc0,0xf8,0xcc,0xcc,0xcc, + 0xf8,0xc0,0xd0,0xc8,0xc8,0xc8,0xd0,0xc8, + 0xc8,0x70,0x6c,0xd8,0xd8,0x78,0x98,0x70, + 0x00,0x10,0x20,0x6c,0xd8,0xd8,0x78,0x98, + 0x70,0x00,0x20,0x10,0x6c,0xd8,0xd8,0x78, + 0x98,0x70,0x00,0x50,0x20,0x6c,0xd8,0xd8, + 0x78,0x98,0x70,0x00,0x50,0x28,0x6c,0xd8, + 0xd8,0x78,0x98,0x70,0x00,0x50,0x6c,0xd8, + 0xd8,0x78,0x98,0x70,0x20,0x50,0x20,0x6e, + 0xdb,0xd8,0x7f,0x9b,0x7e,0x60,0x20,0x70, + 0xd0,0xc0,0xc0,0xd0,0x70,0x70,0xd8,0xc0, + 0xf8,0xd8,0x70,0x00,0x20,0x40,0x70,0xd8, + 0xc0,0xf8,0xd8,0x70,0x00,0x20,0x10,0x70, + 0xd8,0xc0,0xf8,0xd8,0x70,0x00,0x50,0x20, + 0x70,0xd8,0xc0,0xf8,0xd8,0x70,0x00,0x50, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x40, + 0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00, + 0x80,0x40,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0x00,0xa0,0x40,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0x00,0xa0,0x70,0xd8,0xd8,0xd8,0xd8, + 0x70,0xa0,0x60,0x50,0xd8,0xd8,0xd8,0xd8, + 0xd8,0xb0,0x00,0xa0,0x50,0x70,0xd8,0xd8, + 0xd8,0xd8,0x70,0x00,0x20,0x40,0x70,0xd8, + 0xd8,0xd8,0xd8,0x70,0x00,0x20,0x10,0x70, + 0xd8,0xd8,0xd8,0xd8,0x70,0x00,0x50,0x20, + 0x70,0xd8,0xd8,0xd8,0xd8,0x70,0x00,0xa0, + 0x50,0x70,0xd8,0xd8,0xd8,0xd8,0x70,0x00, + 0x50,0x30,0x00,0xfc,0x00,0x30,0xb8,0x6c, + 0x6c,0x7c,0x6c,0x3a,0x68,0xd8,0xd8,0xd8, + 0xd8,0xd8,0x00,0x20,0x40,0x68,0xd8,0xd8, + 0xd8,0xd8,0xd8,0x00,0x20,0x10,0x68,0xd8, + 0xd8,0xd8,0xd8,0xd8,0x00,0x50,0x20,0x68, + 0xd8,0xd8,0xd8,0xd8,0xd8,0x00,0x50,0x60, + 0x30,0x30,0x78,0xd8,0xd8,0xd8,0xd8,0x00, + 0x20,0x10,0xc0,0xc0,0xf0,0xd8,0xc8,0xc8, + 0xd8,0xf0,0xc0,0xc0,0x60,0x30,0x30,0x78, + 0xd8,0xd8,0xd8,0xd8,0x00,0x50, +}; + +BMF_FontData BMF_font_helvb10 = { + -1, -2, + 10, 11, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 12, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 3, 0}, + {2, 8, -1, 0, 4, 1}, + {3, 3, -1, -5, 5, 9}, + {7, 7, 1, 0, 6, 12}, + {5, 10, 0, 1, 6, 19}, + {7, 8, 0, 0, 8, 29}, + {7, 8, 0, 0, 8, 37}, + {2, 4, 0, -4, 3, 45}, + {3, 10, 0, 2, 4, 49}, + {3, 10, 0, 2, 4, 59}, + {3, 3, 0, -5, 4, 69}, + {6, 5, 0, -1, 6, 72}, + {2, 4, 0, 2, 3, 77}, + {5, 1, -1, -3, 7, 81}, + {2, 2, 0, 0, 3, 82}, + {4, 8, 0, 0, 4, 84}, + {5, 8, 0, 0, 6, 92}, + {3, 8, -1, 0, 6, 100}, + {5, 8, 0, 0, 6, 108}, + {5, 8, 0, 0, 6, 116}, + {6, 8, 0, 0, 6, 124}, + {5, 8, 0, 0, 6, 132}, + {5, 8, 0, 0, 6, 140}, + {5, 8, 0, 0, 6, 148}, + {5, 8, 0, 0, 6, 156}, + {5, 8, 0, 0, 6, 164}, + {2, 6, 0, 0, 3, 172}, + {2, 8, 0, 2, 3, 178}, + {4, 5, 0, -1, 5, 186}, + {5, 3, 0, -2, 6, 191}, + {4, 5, 0, -1, 5, 194}, + {5, 8, 0, 0, 6, 199}, + {10, 9, 0, 1, 11, 207}, + {7, 8, 0, 0, 8, 225}, + {6, 8, 0, 0, 7, 233}, + {7, 8, 0, 0, 8, 241}, + {6, 8, 0, 0, 7, 249}, + {5, 8, 0, 0, 6, 257}, + {5, 8, 0, 0, 6, 265}, + {7, 8, 0, 0, 8, 273}, + {6, 8, 0, 0, 7, 281}, + {2, 8, 0, 0, 3, 289}, + {5, 8, 0, 0, 6, 297}, + {7, 8, 0, 0, 7, 305}, + {5, 8, 0, 0, 6, 313}, + {9, 8, 0, 0, 10, 321}, + {7, 8, 0, 0, 8, 337}, + {7, 8, 0, 0, 8, 345}, + {6, 8, 0, 0, 7, 353}, + {7, 9, 0, 1, 8, 361}, + {6, 8, 0, 0, 7, 370}, + {6, 8, 0, 0, 7, 378}, + {6, 8, 0, 0, 7, 386}, + {6, 8, 0, 0, 7, 394}, + {7, 8, 0, 0, 8, 402}, + {10, 8, 0, 0, 11, 410}, + {7, 8, 0, 0, 8, 426}, + {8, 8, 0, 0, 9, 434}, + {6, 8, 0, 0, 7, 442}, + {3, 10, 0, 2, 4, 450}, + {4, 8, 0, 0, 4, 460}, + {3, 10, 0, 2, 4, 468}, + {4, 4, 0, -4, 5, 478}, + {6, 1, 0, 2, 6, 482}, + {2, 4, 0, -4, 3, 483}, + {6, 6, 0, 0, 6, 487}, + {5, 8, 0, 0, 6, 493}, + {4, 6, 0, 0, 5, 501}, + {5, 8, 0, 0, 6, 507}, + {5, 6, 0, 0, 6, 515}, + {5, 8, 1, 0, 4, 521}, + {5, 8, 0, 2, 6, 529}, + {5, 8, 0, 0, 6, 537}, + {2, 8, 0, 0, 3, 545}, + {3, 10, 1, 2, 3, 553}, + {6, 8, 0, 0, 6, 563}, + {2, 8, 0, 0, 3, 571}, + {8, 6, 0, 0, 9, 579}, + {5, 6, 0, 0, 6, 585}, + {5, 6, 0, 0, 6, 591}, + {5, 8, 0, 2, 6, 597}, + {5, 8, 0, 2, 6, 605}, + {4, 6, 0, 0, 4, 613}, + {5, 6, 0, 0, 6, 619}, + {4, 8, 1, 0, 4, 625}, + {5, 6, 0, 0, 6, 633}, + {5, 6, 0, 0, 6, 639}, + {7, 6, 0, 0, 8, 645}, + {6, 6, 0, 0, 7, 651}, + {5, 8, 0, 2, 6, 657}, + {5, 6, 0, 0, 6, 665}, + {4, 10, 0, 2, 5, 671}, + {1, 10, -1, 2, 3, 681}, + {4, 10, 0, 2, 5, 691}, + {5, 2, 0, -3, 6, 701}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 3, 703}, + {2, 8, -1, 2, 4, 704}, + {5, 8, 0, 1, 6, 712}, + {5, 8, 0, 0, 6, 720}, + {6, 6, 0, -1, 6, 728}, + {6, 8, 0, 0, 7, 734}, + {1, 10, -1, 2, 3, 742}, + {5, 10, 0, 2, 6, 752}, + {3, 1, 0, -7, 3, 762}, + {8, 8, -1, 0, 10, 763}, + {3, 5, -1, -3, 5, 771}, + {6, 3, 0, -1, 7, 776}, + {5, 3, -1, -2, 7, 779}, + {4, 1, 0, -3, 5, 782}, + {8, 8, -1, 0, 10, 783}, + {3, 1, 0, -7, 3, 791}, + {3, 3, 0, -5, 4, 792}, + {6, 7, 0, 0, 6, 795}, + {3, 4, 0, -4, 3, 802}, + {3, 4, 0, -4, 3, 806}, + {2, 2, 0, -7, 3, 810}, + {5, 8, 0, 2, 6, 812}, + {6, 10, 0, 2, 6, 820}, + {2, 1, 0, -3, 3, 830}, + {2, 2, 0, 2, 3, 831}, + {2, 4, 0, -4, 3, 833}, + {3, 5, -1, -3, 5, 837}, + {6, 3, 0, -1, 7, 842}, + {8, 8, 0, 0, 9, 845}, + {7, 8, 0, 0, 9, 853}, + {8, 8, 0, 0, 9, 861}, + {5, 8, 0, 2, 6, 869}, + {7, 11, 0, 0, 8, 877}, + {7, 11, 0, 0, 8, 888}, + {7, 11, 0, 0, 8, 899}, + {7, 11, 0, 0, 8, 910}, + {7, 10, 0, 0, 8, 921}, + {7, 11, 0, 0, 8, 931}, + {9, 8, 0, 0, 10, 942}, + {7, 10, 0, 2, 8, 958}, + {5, 11, 0, 0, 6, 968}, + {5, 11, 0, 0, 6, 979}, + {5, 11, 0, 0, 6, 990}, + {5, 10, 0, 0, 6, 1001}, + {2, 11, 0, 0, 3, 1011}, + {2, 11, 0, 0, 3, 1022}, + {3, 11, 1, 0, 3, 1033}, + {4, 10, 1, 0, 3, 1044}, + {7, 8, 1, 0, 7, 1054}, + {7, 11, 0, 0, 8, 1062}, + {7, 11, 0, 0, 8, 1073}, + {7, 11, 0, 0, 8, 1084}, + {7, 11, 0, 0, 8, 1095}, + {7, 11, 0, 0, 8, 1106}, + {7, 10, 0, 0, 8, 1117}, + {6, 5, 0, -1, 6, 1127}, + {7, 8, 0, 0, 8, 1132}, + {6, 11, 0, 0, 7, 1140}, + {6, 11, 0, 0, 7, 1151}, + {6, 11, 0, 0, 7, 1162}, + {6, 10, 0, 0, 7, 1173}, + {8, 11, 0, 0, 9, 1183}, + {6, 8, 0, 0, 7, 1194}, + {5, 8, 0, 0, 6, 1202}, + {6, 9, 0, 0, 6, 1210}, + {6, 9, 0, 0, 6, 1219}, + {6, 9, 0, 0, 6, 1228}, + {6, 9, 0, 0, 6, 1237}, + {6, 8, 0, 0, 6, 1246}, + {6, 9, 0, 0, 6, 1254}, + {8, 6, 0, 0, 9, 1263}, + {4, 8, 0, 2, 5, 1269}, + {5, 9, 0, 0, 6, 1277}, + {5, 9, 0, 0, 6, 1286}, + {5, 9, 0, 0, 6, 1295}, + {5, 8, 0, 0, 6, 1304}, + {2, 9, 0, 0, 3, 1312}, + {2, 9, 0, 0, 3, 1321}, + {3, 9, 0, 0, 3, 1330}, + {3, 8, 0, 0, 3, 1339}, + {5, 9, 0, 0, 6, 1347}, + {5, 9, 0, 0, 6, 1356}, + {5, 9, 0, 0, 6, 1365}, + {5, 9, 0, 0, 6, 1374}, + {5, 9, 0, 0, 6, 1383}, + {5, 9, 0, 0, 6, 1392}, + {5, 8, 0, 0, 6, 1401}, + {6, 5, 0, -1, 6, 1409}, + {7, 6, 1, 0, 6, 1414}, + {5, 9, 0, 0, 6, 1420}, + {5, 9, 0, 0, 6, 1429}, + {5, 9, 0, 0, 6, 1438}, + {5, 8, 0, 0, 6, 1447}, + {5, 11, 0, 2, 6, 1455}, + {5, 10, 0, 2, 6, 1466}, + {5, 10, 0, 2, 6, 1476}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helvb12.cpp b/intern/bmfont/intern/BMF_font_helvb12.cpp new file mode 100644 index 00000000000..69230d48ae8 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helvb12.cpp @@ -0,0 +1,568 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELVB12 + +static unsigned char bitmap_data[]= { + 0x00,0xc0,0xc0,0x00,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xa0,0xa0,0xa0,0x6c, + 0x00,0x6c,0x00,0x6c,0x00,0xff,0x00,0x36, + 0x00,0x36,0x00,0x36,0x00,0x7f,0x80,0x1b, + 0x00,0x1b,0x00,0x1b,0x00,0x30,0x30,0x78, + 0xec,0xac,0x3c,0x38,0x70,0xf0,0xd4,0xdc, + 0x78,0x30,0x63,0x80,0x37,0xc0,0x36,0xc0, + 0x1f,0xc0,0x1b,0x80,0x0c,0x00,0x76,0x00, + 0xfe,0x00,0xdb,0x00,0xfb,0x00,0x71,0x80, + 0x73,0x80,0xff,0x00,0xce,0x00,0xcf,0x00, + 0xdd,0x80,0x79,0x80,0x38,0x00,0x6c,0x00, + 0x6c,0x00,0x7c,0x00,0x38,0x00,0x80,0x40, + 0xc0,0xc0,0x30,0x60,0x60,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x60,0x60,0x30, + 0xc0,0x60,0x60,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x60,0x60,0xc0,0xd8,0x70, + 0x70,0xf8,0x20,0x30,0x30,0xfc,0xfc,0x30, + 0x30,0x80,0x40,0xc0,0xc0,0xfc,0xfc,0xc0, + 0xc0,0xc0,0xc0,0xc0,0x60,0x60,0x60,0x20, + 0x30,0x30,0x30,0x18,0x18,0x18,0x78,0xfc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xfc, + 0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0xf0,0xf0,0x30,0xfc,0xfc,0xc0,0x60, + 0x70,0x38,0x18,0xcc,0xcc,0xfc,0x78,0x78, + 0xfc,0xcc,0xcc,0x0c,0x38,0x38,0x0c,0xcc, + 0xfc,0x78,0x0c,0x0c,0xfe,0xfe,0xcc,0x6c, + 0x6c,0x3c,0x3c,0x1c,0x1c,0x78,0xfc,0xcc, + 0xcc,0x0c,0xfc,0xf8,0xc0,0xc0,0xfc,0xfc, + 0x78,0xfc,0xcc,0xcc,0xcc,0xfc,0xf8,0xc0, + 0xcc,0xfc,0x78,0x60,0x60,0x60,0x30,0x30, + 0x30,0x18,0x18,0x0c,0xfc,0xfc,0x78,0xfc, + 0xcc,0xcc,0xcc,0x78,0x78,0xcc,0xcc,0xfc, + 0x78,0x78,0xfc,0xcc,0x0c,0x7c,0xfc,0xcc, + 0xcc,0xcc,0xfc,0x78,0xc0,0xc0,0x00,0x00, + 0x00,0x00,0xc0,0xc0,0x80,0x40,0xc0,0xc0, + 0x00,0x00,0x00,0x00,0xc0,0xc0,0x0c,0x38, + 0xe0,0xe0,0x38,0x0c,0xfc,0xfc,0x00,0xfc, + 0xfc,0xc0,0x70,0x1c,0x1c,0x70,0xc0,0x30, + 0x30,0x00,0x30,0x30,0x38,0x1c,0xcc,0xcc, + 0xfc,0x78,0x1f,0x00,0x71,0x80,0x40,0x00, + 0xdd,0x80,0xb6,0xc0,0xb2,0x40,0xb3,0x60, + 0xdb,0x20,0x4d,0xa0,0x60,0x40,0x39,0xc0, + 0x0f,0x00,0xc3,0xc3,0xff,0x7e,0x66,0x66, + 0x3c,0x3c,0x3c,0x18,0x18,0xf8,0xfc,0xcc, + 0xcc,0xcc,0xf8,0xf8,0xcc,0xcc,0xfc,0xf8, + 0x78,0xfc,0xcc,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xcc,0xfc,0x78,0xf8,0xfc,0xce,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xce,0xfc,0xf8,0xfc,0xfc, + 0xc0,0xc0,0xc0,0xf8,0xf8,0xc0,0xc0,0xfc, + 0xfc,0xc0,0xc0,0xc0,0xc0,0xc0,0xf8,0xf8, + 0xc0,0xc0,0xfc,0xfc,0x76,0xfe,0xc6,0xc6, + 0xde,0xde,0xc0,0xc0,0xc6,0xfe,0x7c,0xc6, + 0xc6,0xc6,0xc6,0xc6,0xfe,0xfe,0xc6,0xc6, + 0xc6,0xc6,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x70,0xf8,0xd8, + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0xc6,0xce,0xcc,0xd8,0xf8,0xf0,0xf0,0xd8, + 0xcc,0xcc,0xc6,0xfc,0xfc,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc9,0x80, + 0xc9,0x80,0xdd,0x80,0xdd,0x80,0xf7,0x80, + 0xf7,0x80,0xe3,0x80,0xe3,0x80,0xe3,0x80, + 0xc1,0x80,0xc1,0x80,0xc6,0xc6,0xce,0xce, + 0xde,0xd6,0xf6,0xe6,0xe6,0xc6,0xc6,0x7c, + 0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6, + 0xfe,0x7c,0xc0,0xc0,0xc0,0xc0,0xfc,0xfe, + 0xc6,0xc6,0xc6,0xfe,0xfc,0x06,0x7e,0xfc, + 0xce,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xfe, + 0x7c,0xc6,0xc6,0xc6,0xce,0xfc,0xfc,0xc6, + 0xc6,0xc6,0xfe,0xfc,0x78,0xfc,0xcc,0x0c, + 0x1c,0x78,0xe0,0xc0,0xcc,0xfc,0x78,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0xfc,0xfc,0x7c,0xfe,0xc6,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xc6,0xc6,0x18,0x18,0x18, + 0x3c,0x3c,0x3c,0x66,0x66,0x66,0xc3,0xc3, + 0x33,0x00,0x33,0x00,0x33,0x00,0x3b,0x00, + 0x7f,0x80,0x6d,0x80,0x6d,0x80,0x6d,0x80, + 0xcc,0xc0,0xcc,0xc0,0xcc,0xc0,0xc3,0xc3, + 0x66,0x7e,0x3c,0x18,0x3c,0x7e,0x66,0xc3, + 0xc3,0x18,0x18,0x18,0x18,0x18,0x3c,0x3c, + 0x66,0x66,0xc3,0xc3,0xfe,0xfe,0xc0,0x60, + 0x60,0x30,0x18,0x18,0x0c,0xfe,0xfe,0xe0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xe0,0x30,0x30,0x30, + 0x70,0x60,0x60,0x60,0xe0,0xc0,0xc0,0xc0, + 0xe0,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0xe0,0x88,0xd8, + 0x70,0x70,0x20,0xfe,0xc0,0xc0,0x80,0x40, + 0x76,0xfc,0xcc,0xfc,0x7c,0x8c,0xfc,0x78, + 0xd8,0xfc,0xcc,0xcc,0xcc,0xcc,0xfc,0xd8, + 0xc0,0xc0,0xc0,0x78,0xfc,0xcc,0xc0,0xc0, + 0xcc,0xfc,0x78,0x6c,0xfc,0xcc,0xcc,0xcc, + 0xcc,0xfc,0x6c,0x0c,0x0c,0x0c,0x78,0xfc, + 0xc0,0xfc,0xfc,0xcc,0xfc,0x78,0x60,0x60, + 0x60,0x60,0x60,0x60,0xf0,0xf0,0x60,0x70, + 0x30,0x78,0xfc,0x0c,0x6c,0xfc,0xcc,0xcc, + 0xcc,0xcc,0xfc,0x6c,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xec,0xfc,0xd8,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00, + 0xc0,0xc0,0xc0,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0x00,0x60,0x60, + 0xcc,0xd8,0xd8,0xf0,0xe0,0xf0,0xd8,0xcc, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xcc,0xc0, + 0xcc,0xc0,0xcc,0xc0,0xcc,0xc0,0xcc,0xc0, + 0xee,0xc0,0xff,0xc0,0xbb,0x80,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xec,0xfc,0xd8,0x78,0xfc, + 0xcc,0xcc,0xcc,0xcc,0xfc,0x78,0xc0,0xc0, + 0xc0,0xd8,0xfc,0xcc,0xcc,0xcc,0xcc,0xfc, + 0xd8,0x0c,0x0c,0x0c,0x6c,0xfc,0xcc,0xcc, + 0xcc,0xcc,0xfc,0x6c,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xe0,0xb0,0x78,0xfc,0xcc,0x1c, + 0x78,0xe0,0xfc,0x78,0x30,0x70,0x60,0x60, + 0x60,0x60,0xf0,0xf0,0x60,0x60,0x6c,0xfc, + 0xdc,0xcc,0xcc,0xcc,0xcc,0xcc,0x30,0x30, + 0x78,0x78,0x78,0xcc,0xcc,0xcc,0x24,0x24, + 0x76,0x76,0x7e,0xdb,0xdb,0xdb,0xcc,0xcc, + 0x78,0x38,0x70,0x78,0xcc,0xcc,0xe0,0xf0, + 0x30,0x30,0x38,0x78,0x78,0x48,0xcc,0xcc, + 0xcc,0xfc,0xfc,0x60,0x30,0x30,0x18,0xfc, + 0xfc,0x30,0x60,0x60,0x60,0x60,0x60,0x40, + 0x80,0x40,0x60,0x60,0x60,0x60,0x30,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0xc0,0x60,0x60,0x60, + 0x60,0x60,0x20,0x10,0x20,0x60,0x60,0x60, + 0x60,0xc0,0x98,0xfc,0x64,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0xc0,0xc0, + 0xc0,0x78,0xfc,0xec,0xe0,0xd0,0xd4,0xfc, + 0x78,0x0c,0xdc,0xfe,0x60,0x30,0x30,0xfc, + 0x30,0x60,0x64,0x7c,0x38,0xcc,0x78,0xcc, + 0xcc,0x78,0xcc,0x18,0x18,0x18,0x7e,0x18, + 0x7e,0x3c,0x66,0x66,0xc3,0xc3,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80, + 0x80,0x80,0x80,0x78,0xfc,0xcc,0x1c,0x38, + 0x6c,0xcc,0xcc,0xd8,0x70,0xe0,0xcc,0xfc, + 0x78,0xd8,0xd8,0x1f,0x00,0x71,0xc0,0x6e, + 0xc0,0xdb,0x60,0xdb,0x60,0xd8,0x60,0xdb, + 0x60,0xdb,0x60,0x6e,0xc0,0x71,0xc0,0x1f, + 0x00,0xf0,0x00,0xd0,0xb0,0x70,0xb0,0x60, + 0x36,0x6c,0xd8,0x6c,0x36,0x0c,0x0c,0xfc, + 0xfc,0xe0,0xe0,0x1f,0x00,0x71,0xc0,0x7b, + 0xc0,0xdb,0x60,0xdf,0x60,0xde,0x60,0xdb, + 0x60,0xdb,0x60,0x7e,0xc0,0x71,0xc0,0x1f, + 0x00,0xf0,0xf0,0x60,0x90,0x90,0x60,0xfc, + 0xfc,0x00,0x30,0x30,0xfc,0xfc,0x30,0x30, + 0xf0,0x40,0x20,0x10,0x90,0x60,0x60,0x90, + 0x10,0x20,0x90,0x60,0xc0,0x70,0x30,0xc0, + 0xc0,0xc0,0xec,0xfc,0xdc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0x36,0x36,0x36,0x36,0x36,0x36, + 0x36,0x36,0x76,0xf6,0xf6,0xf6,0xfe,0x7e, + 0xc0,0xc0,0xc0,0x60,0x40,0x40,0x40,0x40, + 0x40,0xc0,0x40,0xf8,0x00,0x70,0xd8,0xd8, + 0xd8,0x70,0xd8,0x6c,0x36,0x6c,0xd8,0x20, + 0x80,0x27,0xc0,0x12,0x80,0x12,0x80,0x09, + 0x80,0x4c,0x80,0x44,0x00,0x42,0x00,0x42, + 0x00,0xc1,0x00,0x41,0x00,0x23,0xc0,0x21, + 0x00,0x10,0x80,0x10,0x40,0x0a,0x40,0x4d, + 0x80,0x44,0x00,0x42,0x00,0x42,0x00,0xc1, + 0x00,0x41,0x00,0x20,0x80,0x27,0xc0,0x12, + 0x80,0x12,0x80,0x09,0x80,0x6c,0x80,0x94, + 0x00,0x12,0x00,0x22,0x00,0x91,0x00,0x61, + 0x00,0x78,0xfc,0xcc,0xcc,0xe0,0x70,0x30, + 0x30,0x00,0x30,0x30,0xc3,0xc3,0x7e,0x7e, + 0x24,0x3c,0x18,0x18,0x00,0x0c,0x38,0x30, + 0xc3,0xc3,0x7e,0x7e,0x24,0x3c,0x18,0x18, + 0x00,0x30,0x1c,0x0c,0xc3,0xc3,0x7e,0x7e, + 0x24,0x3c,0x18,0x18,0x00,0x66,0x3c,0x18, + 0xc3,0xc3,0x7e,0x7e,0x24,0x3c,0x18,0x18, + 0x00,0x2c,0x3e,0x1a,0xc3,0xc3,0x7e,0x7e, + 0x24,0x3c,0x18,0x18,0x00,0x6c,0x6c,0xc3, + 0xc3,0x7e,0x7e,0x24,0x3c,0x18,0x18,0x00, + 0x18,0x34,0x18,0xc7,0xe0,0xc7,0xe0,0xfe, + 0x00,0x7e,0x00,0x66,0x00,0x67,0xc0,0x37, + 0xc0,0x36,0x00,0x3e,0x00,0x1f,0xe0,0x1f, + 0xe0,0x60,0x30,0x20,0x78,0xfc,0xcc,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xcc,0xfc,0x78,0xfc, + 0xfc,0xc0,0xf8,0xf8,0xc0,0xfc,0xfc,0x00, + 0x18,0x70,0x60,0xfc,0xfc,0xc0,0xf8,0xf8, + 0xc0,0xfc,0xfc,0x00,0x60,0x38,0x18,0xfc, + 0xfc,0xc0,0xf8,0xf8,0xc0,0xfc,0xfc,0x00, + 0xcc,0x78,0x30,0xfc,0xfc,0xc0,0xf8,0xf8, + 0xc0,0xfc,0xfc,0x00,0xd8,0xd8,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x30, + 0xe0,0xc0,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x00,0xc0,0x70,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x00,0xcc, + 0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x00,0xd8,0xd8,0x7c,0x7e,0x67, + 0x63,0x63,0xfb,0xfb,0x63,0x67,0x7e,0x7c, + 0xc6,0xce,0xce,0xde,0xf6,0xe6,0xe6,0xc6, + 0x00,0x58,0x7c,0x34,0x7c,0xfe,0xc6,0xc6, + 0xc6,0xc6,0xfe,0x7c,0x00,0x18,0x70,0x60, + 0x7c,0xfe,0xc6,0xc6,0xc6,0xc6,0xfe,0x7c, + 0x00,0x30,0x1c,0x0c,0x7c,0xfe,0xc6,0xc6, + 0xc6,0xc6,0xfe,0x7c,0x00,0xcc,0x78,0x30, + 0x7c,0xfe,0xc6,0xc6,0xc6,0xc6,0xfe,0x7c, + 0x00,0x58,0x7c,0x34,0x7c,0xfe,0xc6,0xc6, + 0xc6,0xc6,0xfe,0x7c,0x00,0x6c,0x6c,0xcc, + 0x78,0x30,0x30,0x78,0xcc,0xde,0x00,0x7f, + 0x00,0x63,0x00,0x73,0x00,0x7b,0x00,0x6b, + 0x00,0x6f,0x00,0x67,0x00,0x63,0x00,0x7f, + 0x00,0x3d,0x80,0x7c,0xfe,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0x00,0x18,0x70,0x60,0x7c, + 0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00, + 0x30,0x1c,0x0c,0x7c,0xfe,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0x00,0xcc,0x78,0x30,0x7c, + 0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00, + 0x6c,0x6c,0x18,0x18,0x18,0x18,0x3c,0x7e, + 0xe7,0xc3,0x00,0x30,0x1c,0x0c,0xc0,0xc0, + 0xfc,0xfe,0xc6,0xc6,0xc6,0xfe,0xfc,0xc0, + 0xc0,0xd8,0xdc,0xcc,0xcc,0xcc,0xd8,0xd8, + 0xcc,0xcc,0xfc,0x78,0x76,0xfc,0xcc,0xfc, + 0x7c,0x8c,0xfc,0x78,0x00,0x18,0x70,0x60, + 0x76,0xfc,0xcc,0xfc,0x7c,0x8c,0xfc,0x78, + 0x00,0x60,0x38,0x18,0x76,0xfc,0xcc,0xfc, + 0x7c,0x8c,0xfc,0x78,0x00,0xcc,0x78,0x30, + 0x76,0xfc,0xcc,0xfc,0x7c,0x8c,0xfc,0x78, + 0x00,0x58,0x7c,0x34,0x76,0xfc,0xcc,0xfc, + 0x7c,0x8c,0xfc,0x78,0x00,0xd8,0xd8,0x76, + 0xfc,0xcc,0xfc,0x7c,0x8c,0xfc,0x78,0x00, + 0x30,0x68,0x30,0x77,0x80,0xff,0xc0,0xcc, + 0x00,0xff,0xc0,0x7f,0xc0,0x8c,0xc0,0xff, + 0xc0,0x7b,0x80,0x60,0x30,0x20,0x78,0xfc, + 0xcc,0xc0,0xc0,0xcc,0xfc,0x78,0x78,0xfc, + 0xc0,0xfc,0xfc,0xcc,0xfc,0x78,0x00,0x18, + 0x70,0x60,0x78,0xfc,0xc0,0xfc,0xfc,0xcc, + 0xfc,0x78,0x00,0x60,0x38,0x18,0x78,0xfc, + 0xc0,0xfc,0xfc,0xcc,0xfc,0x78,0x00,0xcc, + 0x78,0x30,0x78,0xfc,0xc0,0xfc,0xfc,0xcc, + 0xfc,0x78,0x00,0xd8,0xd8,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0x00,0x30,0xe0, + 0xc0,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x00,0xc0,0x70,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x00,0xcc,0x78, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x00,0xd8,0xd8,0x78,0xfc,0xcc,0xcc, + 0xcc,0xcc,0xfc,0x78,0xb0,0x60,0xd0,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xec,0xfc,0xd8,0x00, + 0xb0,0xf8,0x68,0x78,0xfc,0xcc,0xcc,0xcc, + 0xcc,0xfc,0x78,0x00,0x18,0x70,0x60,0x78, + 0xfc,0xcc,0xcc,0xcc,0xcc,0xfc,0x78,0x00, + 0x60,0x38,0x18,0x78,0xfc,0xcc,0xcc,0xcc, + 0xcc,0xfc,0x78,0x00,0xcc,0x78,0x30,0x78, + 0xfc,0xcc,0xcc,0xcc,0xcc,0xfc,0x78,0x00, + 0xb0,0xf8,0x68,0x78,0xfc,0xcc,0xcc,0xcc, + 0xcc,0xfc,0x78,0x00,0xd8,0xd8,0x30,0x30, + 0x00,0xfc,0xfc,0x00,0x30,0x30,0xc0,0x78, + 0xfc,0xcc,0xec,0xdc,0xcc,0xfc,0x78,0x0c, + 0x6c,0xfc,0xdc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0x00,0x18,0x70,0x60,0x6c,0xfc,0xdc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0x00,0x60,0x38,0x18, + 0x6c,0xfc,0xdc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0x00,0xcc,0x78,0x30,0x6c,0xfc,0xdc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0x00,0xd8,0xd8,0xe0, + 0xf0,0x30,0x30,0x38,0x78,0x78,0x48,0xcc, + 0xcc,0xcc,0x00,0x60,0x38,0x18,0xc0,0xc0, + 0xc0,0xd8,0xfc,0xcc,0xcc,0xcc,0xcc,0xfc, + 0xd8,0xc0,0xc0,0xc0,0xe0,0xf0,0x30,0x30, + 0x38,0x78,0x78,0x48,0xcc,0xcc,0xcc,0x00, + 0xd8,0xd8, +}; + +BMF_FontData BMF_font_helvb12 = { + -1, -3, + 11, 12, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 12, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 3, 0}, + {2, 11, -1, 0, 4, 1}, + {3, 3, 0, -8, 4, 12}, + {9, 11, 1, 0, 7, 15}, + {6, 13, 0, 2, 7, 37}, + {10, 11, 0, 0, 11, 50}, + {9, 11, 0, 0, 9, 72}, + {2, 4, 0, -7, 3, 94}, + {4, 14, 0, 3, 4, 98}, + {4, 14, 1, 3, 4, 112}, + {5, 5, 0, -6, 6, 126}, + {6, 6, 0, -1, 7, 131}, + {2, 4, 0, 2, 3, 137}, + {6, 2, -1, -3, 9, 141}, + {2, 2, 0, 0, 3, 143}, + {5, 13, 1, 2, 4, 145}, + {6, 11, 0, 0, 7, 158}, + {4, 11, 0, 0, 6, 169}, + {6, 11, 0, 0, 7, 180}, + {6, 11, 0, 0, 7, 191}, + {7, 11, 0, 0, 7, 202}, + {6, 11, 0, 0, 7, 213}, + {6, 11, 0, 0, 7, 224}, + {6, 11, 0, 0, 7, 235}, + {6, 11, 0, 0, 7, 246}, + {6, 11, 0, 0, 7, 257}, + {2, 8, -1, 0, 4, 268}, + {2, 10, -1, 2, 4, 276}, + {6, 6, 0, -1, 7, 286}, + {6, 5, 0, -2, 7, 292}, + {6, 6, 0, -1, 7, 297}, + {6, 11, 0, 0, 7, 303}, + {11, 12, 0, 1, 12, 314}, + {8, 11, 0, 0, 8, 338}, + {6, 11, -1, 0, 8, 349}, + {6, 11, -1, 0, 8, 360}, + {7, 11, -1, 0, 9, 371}, + {6, 11, -1, 0, 8, 382}, + {6, 11, -1, 0, 7, 393}, + {7, 11, -1, 0, 9, 404}, + {7, 11, -1, 0, 9, 415}, + {2, 11, -2, 0, 6, 426}, + {5, 11, 0, 0, 6, 437}, + {7, 11, -1, 0, 8, 448}, + {6, 11, -1, 0, 7, 459}, + {9, 11, -1, 0, 11, 470}, + {7, 11, -1, 0, 9, 492}, + {7, 11, -1, 0, 9, 503}, + {7, 11, -1, 0, 9, 514}, + {7, 12, -1, 1, 9, 525}, + {7, 11, -1, 0, 9, 537}, + {6, 11, -1, 0, 8, 548}, + {6, 11, 0, 0, 6, 559}, + {7, 11, -1, 0, 9, 570}, + {8, 11, 0, 0, 8, 581}, + {10, 11, 0, 0, 10, 592}, + {8, 11, 0, 0, 8, 614}, + {8, 11, 0, 0, 8, 625}, + {7, 11, 0, 0, 7, 636}, + {3, 14, 0, 3, 4, 647}, + {4, 11, 0, 0, 5, 661}, + {3, 14, 0, 3, 4, 672}, + {5, 5, 0, -6, 7, 686}, + {7, 1, 0, 2, 7, 691}, + {2, 4, 0, -7, 3, 692}, + {7, 8, 0, 0, 7, 696}, + {6, 11, 0, 0, 7, 704}, + {6, 8, 0, 0, 7, 715}, + {6, 11, 0, 0, 7, 723}, + {6, 8, 0, 0, 7, 734}, + {4, 11, 0, 0, 5, 742}, + {6, 11, 0, 3, 7, 753}, + {6, 11, 0, 0, 7, 764}, + {2, 11, -1, 0, 5, 775}, + {3, 14, 0, 3, 5, 786}, + {6, 11, 0, 0, 6, 800}, + {2, 11, -1, 0, 5, 811}, + {10, 8, 0, 0, 11, 822}, + {6, 8, 0, 0, 7, 838}, + {6, 8, 0, 0, 7, 846}, + {6, 11, 0, 3, 7, 854}, + {6, 11, 0, 3, 7, 865}, + {4, 8, 0, 0, 4, 876}, + {6, 8, 0, 0, 7, 884}, + {4, 10, 0, 0, 5, 892}, + {6, 8, 0, 0, 7, 902}, + {6, 8, 0, 0, 7, 910}, + {8, 8, 0, 0, 9, 918}, + {6, 8, 0, 0, 7, 926}, + {6, 11, 0, 3, 7, 934}, + {6, 8, 0, 0, 7, 945}, + {4, 14, 0, 3, 4, 953}, + {1, 13, -1, 2, 3, 967}, + {4, 14, 0, 3, 4, 980}, + {6, 3, 0, -3, 7, 994}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {2, 11, 0, 3, 3, 997}, + {6, 10, 0, 1, 7, 1008}, + {7, 11, 0, 0, 7, 1018}, + {6, 6, 0, -3, 7, 1029}, + {8, 11, 1, 0, 7, 1035}, + {1, 13, -1, 2, 3, 1046}, + {6, 14, 0, 3, 7, 1059}, + {5, 2, 0, -9, 5, 1073}, + {11, 11, 0, 0, 12, 1075}, + {4, 7, 0, -4, 5, 1097}, + {7, 5, 0, -2, 8, 1104}, + {6, 4, -1, -3, 9, 1109}, + {3, 2, 0, -3, 4, 1113}, + {11, 11, 0, 0, 12, 1115}, + {4, 2, 0, -9, 4, 1137}, + {4, 4, -1, -7, 6, 1139}, + {6, 9, 0, -1, 7, 1143}, + {4, 6, 0, -5, 4, 1152}, + {4, 6, 0, -5, 4, 1158}, + {4, 3, -1, -9, 4, 1164}, + {6, 11, 0, 3, 7, 1167}, + {7, 14, -1, 3, 10, 1178}, + {2, 2, 0, -5, 3, 1192}, + {3, 3, -1, 3, 5, 1194}, + {2, 6, 0, -5, 4, 1197}, + {5, 7, 0, -4, 6, 1203}, + {7, 5, 0, -2, 8, 1210}, + {10, 11, 0, 0, 11, 1215}, + {10, 11, 0, 0, 11, 1237}, + {10, 11, 0, 0, 11, 1259}, + {6, 11, 0, 3, 7, 1281}, + {8, 12, 0, 0, 8, 1292}, + {8, 12, 0, 0, 8, 1304}, + {8, 12, 0, 0, 8, 1316}, + {8, 12, 0, 0, 8, 1328}, + {8, 11, 0, 0, 8, 1340}, + {8, 12, 0, 0, 8, 1351}, + {11, 11, 0, 0, 12, 1363}, + {6, 14, -1, 3, 8, 1385}, + {6, 12, -1, 0, 8, 1399}, + {6, 12, -1, 0, 8, 1411}, + {6, 12, -1, 0, 8, 1423}, + {6, 11, -1, 0, 8, 1435}, + {4, 12, -1, 0, 6, 1446}, + {4, 12, -1, 0, 6, 1458}, + {6, 12, 0, 0, 6, 1470}, + {5, 11, 0, 0, 6, 1482}, + {8, 11, 0, 0, 9, 1493}, + {7, 12, -1, 0, 9, 1504}, + {7, 12, -1, 0, 9, 1516}, + {7, 12, -1, 0, 9, 1528}, + {7, 12, -1, 0, 9, 1540}, + {7, 12, -1, 0, 9, 1552}, + {7, 11, -1, 0, 9, 1564}, + {6, 6, 0, -1, 7, 1575}, + {9, 11, 0, 0, 9, 1581}, + {7, 12, -1, 0, 9, 1603}, + {7, 12, -1, 0, 9, 1615}, + {7, 12, -1, 0, 9, 1627}, + {7, 11, -1, 0, 9, 1639}, + {8, 12, 0, 0, 8, 1650}, + {7, 11, -1, 0, 9, 1662}, + {6, 11, 0, 0, 7, 1673}, + {7, 12, 0, 0, 7, 1684}, + {7, 12, 0, 0, 7, 1696}, + {7, 12, 0, 0, 7, 1708}, + {7, 12, 0, 0, 7, 1720}, + {7, 11, 0, 0, 7, 1732}, + {7, 12, 0, 0, 7, 1743}, + {10, 8, 0, 0, 11, 1755}, + {6, 11, 0, 3, 7, 1771}, + {6, 12, 0, 0, 7, 1782}, + {6, 12, 0, 0, 7, 1794}, + {6, 12, 0, 0, 7, 1806}, + {6, 11, 0, 0, 7, 1818}, + {4, 12, 0, 0, 5, 1829}, + {4, 12, 0, 0, 5, 1841}, + {6, 12, 1, 0, 5, 1853}, + {5, 11, 1, 0, 5, 1865}, + {6, 11, 0, 0, 7, 1876}, + {6, 12, 0, 0, 7, 1887}, + {6, 12, 0, 0, 7, 1899}, + {6, 12, 0, 0, 7, 1911}, + {6, 12, 0, 0, 7, 1923}, + {6, 12, 0, 0, 7, 1935}, + {6, 11, 0, 0, 7, 1947}, + {6, 8, 0, 0, 7, 1958}, + {6, 10, 0, 1, 7, 1966}, + {6, 12, 0, 0, 7, 1976}, + {6, 12, 0, 0, 7, 1988}, + {6, 12, 0, 0, 7, 2000}, + {6, 11, 0, 0, 7, 2012}, + {6, 15, 0, 3, 7, 2023}, + {6, 14, 0, 3, 7, 2038}, + {6, 14, 0, 3, 7, 2052}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helvb14.cpp b/intern/bmfont/intern/BMF_font_helvb14.cpp new file mode 100644 index 00000000000..e793295f295 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helvb14.cpp @@ -0,0 +1,626 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELVB14 + +static unsigned char bitmap_data[]= { + 0x00,0xc0,0xc0,0x00,0x00,0x80,0x80,0x80, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x90,0xd8,0xd8, + 0xd8,0x48,0x48,0x48,0xfe,0xfe,0x24,0x24, + 0x7f,0x7f,0x12,0x12,0x12,0x10,0x10,0x38, + 0x7c,0xd6,0xd6,0x16,0x3c,0x78,0xd0,0xd6, + 0xd6,0x7c,0x38,0x10,0x30,0xc0,0x11,0xe0, + 0x19,0x20,0x09,0x20,0x0d,0xe0,0x64,0xc0, + 0xf6,0x00,0x92,0x00,0x93,0x00,0xf1,0x00, + 0x61,0x80,0x71,0x80,0xff,0x00,0xce,0x00, + 0xc6,0x00,0xcf,0x00,0x79,0x00,0x30,0x00, + 0x38,0x00,0x6c,0x00,0x6c,0x00,0x7c,0x00, + 0x38,0x00,0x80,0x40,0xc0,0xc0,0x30,0x20, + 0x60,0x40,0x40,0xc0,0xc0,0xc0,0xc0,0xc0, + 0x40,0x40,0x60,0x20,0x30,0xc0,0x40,0x60, + 0x20,0x20,0x30,0x30,0x30,0x30,0x30,0x20, + 0x20,0x60,0x40,0xc0,0xd8,0x50,0x20,0xf8, + 0x20,0x20,0x30,0x30,0x30,0xfc,0xfc,0x30, + 0x30,0x30,0x80,0x40,0x40,0xc0,0xc0,0xfe, + 0xfe,0xc0,0xc0,0x80,0x80,0xc0,0x40,0x40, + 0x60,0x20,0x20,0x30,0x10,0x10,0x30,0x78, + 0x48,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x48, + 0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0xf0,0x30,0x10,0xfc,0xfc, + 0x60,0x60,0x30,0x18,0x18,0x0c,0xcc,0xcc, + 0x78,0x30,0x30,0x78,0xcc,0xcc,0x0c,0x38, + 0x38,0x0c,0xcc,0xcc,0x78,0x30,0x18,0x18, + 0xfc,0xfc,0x98,0x58,0x58,0x38,0x38,0x38, + 0x18,0x18,0x70,0xf8,0xcc,0x0c,0x0c,0xcc, + 0xfc,0xd8,0x60,0x60,0x7c,0x7c,0x30,0x78, + 0xcc,0xcc,0xcc,0xcc,0xfc,0xd8,0xc0,0x4c, + 0x7c,0x38,0x60,0x60,0x60,0x20,0x30,0x30, + 0x10,0x18,0x08,0x0c,0xfc,0xfc,0x70,0xf8, + 0xcc,0xcc,0xcc,0x78,0x30,0x78,0xcc,0xcc, + 0x7c,0x38,0x70,0xf8,0xc8,0x0c,0x6c,0xfc, + 0xcc,0xcc,0xcc,0xcc,0x78,0x30,0xc0,0xc0, + 0x00,0x00,0x00,0x00,0xc0,0xc0,0x80,0x40, + 0x40,0xc0,0xc0,0x00,0x00,0x00,0x00,0xc0, + 0xc0,0x02,0x0e,0x3c,0xf0,0xf0,0x3c,0x0e, + 0x02,0xfc,0xfc,0x00,0x00,0xfc,0xfc,0x80, + 0xe0,0x78,0x1e,0x1e,0x78,0xe0,0x80,0x30, + 0x30,0x00,0x30,0x30,0x18,0x18,0x0c,0xcc, + 0xcc,0x7c,0x38,0x0f,0x80,0x38,0x60,0x60, + 0x00,0x4d,0xc0,0xd3,0x20,0x93,0x30,0x91, + 0x10,0x91,0x90,0xc9,0x90,0x46,0x90,0x60, + 0x30,0x30,0x20,0x1c,0xc0,0x07,0x80,0xe1, + 0xc0,0x61,0x80,0x7f,0x80,0x7f,0x80,0x33, + 0x00,0x33,0x00,0x33,0x00,0x1e,0x00,0x1e, + 0x00,0x1e,0x00,0x0c,0x00,0x0c,0x00,0xfc, + 0xfe,0xc7,0xc3,0xc7,0xfe,0xfc,0xc6,0xc3, + 0xc7,0xfe,0xfc,0x3c,0x7e,0x63,0xc3,0xc0, + 0xc0,0xc0,0xc0,0xc3,0x63,0x7e,0x3c,0xfc, + 0xfe,0xc6,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, + 0xc6,0xfe,0xfc,0xfe,0xfe,0xc0,0xc0,0xc0, + 0xfe,0xfe,0xc0,0xc0,0xc0,0xfe,0xfe,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xfc,0xfc,0xc0,0xc0, + 0xc0,0xfe,0xfe,0x3e,0x80,0x7f,0x80,0x63, + 0x80,0xc1,0x80,0xc7,0x80,0xc7,0x80,0xc0, + 0x00,0xc0,0x00,0xc1,0x80,0x63,0x80,0x7f, + 0x00,0x3e,0x00,0xc3,0xc3,0xc3,0xc3,0xc3, + 0xff,0xff,0xc3,0xc3,0xc3,0xc3,0xc3,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0x78,0xfc,0xcc,0xcc,0xcc, + 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0xc3, + 0x80,0xc7,0x00,0xc6,0x00,0xcc,0x00,0xdc, + 0x00,0xf8,0x00,0xf0,0x00,0xd8,0x00,0xcc, + 0x00,0xce,0x00,0xc7,0x00,0xc3,0x00,0xfe, + 0xfe,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xcc,0xc0,0xcc,0xc0,0xcc, + 0xc0,0xde,0xc0,0xde,0xc0,0xd2,0xc0,0xd2, + 0xc0,0xf3,0xc0,0xf3,0xc0,0xe1,0xc0,0xe1, + 0xc0,0xe1,0xc0,0xc3,0xc7,0xc7,0xcf,0xcf, + 0xdb,0xdb,0xf3,0xf3,0xe3,0xe3,0xc3,0x3e, + 0x00,0x7f,0x00,0x63,0x00,0xc1,0x80,0xc1, + 0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80,0xc1, + 0x80,0x63,0x00,0x7f,0x00,0x3e,0x00,0xc0, + 0xc0,0xc0,0xc0,0xf8,0xfc,0xce,0xc6,0xc6, + 0xce,0xfc,0xf8,0x01,0x80,0x3d,0x80,0x7f, + 0x00,0x67,0x00,0xcd,0x80,0xcd,0x80,0xc1, + 0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80,0x63, + 0x00,0x7f,0x00,0x3e,0x00,0xc3,0xc3,0xc3, + 0xc3,0xc7,0xfe,0xfe,0xc7,0xc3,0xc7,0xfe, + 0xfc,0x3c,0x7e,0xe7,0xc3,0x07,0x1e,0x78, + 0xe0,0xc3,0xe7,0x7e,0x3c,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff, + 0xff,0x3c,0x7e,0xe7,0xc3,0xc3,0xc3,0xc3, + 0xc3,0xc3,0xc3,0xc3,0xc3,0x18,0x18,0x18, + 0x3c,0x3c,0x24,0x66,0x66,0x66,0xc3,0xc3, + 0xc3,0x30,0xc0,0x30,0xc0,0x30,0xc0,0x39, + 0xc0,0x79,0xe0,0x69,0x60,0x6f,0x60,0x6f, + 0x60,0xc6,0x30,0xc6,0x30,0xc6,0x30,0xc6, + 0x30,0xe3,0x80,0x63,0x00,0x63,0x00,0x36, + 0x00,0x36,0x00,0x1c,0x00,0x1c,0x00,0x36, + 0x00,0x36,0x00,0x63,0x00,0x63,0x00,0xe3, + 0x80,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0c, + 0x00,0x0c,0x00,0x1e,0x00,0x1e,0x00,0x33, + 0x00,0x33,0x00,0x61,0x80,0x61,0x80,0xe1, + 0xc0,0xff,0xff,0x60,0x70,0x30,0x18,0x18, + 0x0c,0x0e,0x06,0xff,0xff,0xe0,0xe0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xe0,0xe0,0x10,0x10,0x30,0x20, + 0x20,0x60,0x40,0x40,0xc0,0x80,0x80,0xe0, + 0xe0,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0xe0,0xe0,0xcc,0xcc, + 0x48,0x78,0x78,0x30,0x30,0xfe,0xc0,0xc0, + 0x80,0x40,0x6c,0xfc,0xcc,0xcc,0x7c,0x1c, + 0xcc,0xfc,0x78,0xd8,0xfc,0xee,0xc6,0xc6, + 0xc6,0xee,0xfc,0xd8,0xc0,0xc0,0xc0,0x38, + 0x7c,0xec,0xc0,0xc0,0xc0,0xec,0x7c,0x38, + 0x36,0x7e,0xee,0xc6,0xc6,0xc6,0xee,0x7e, + 0x36,0x06,0x06,0x06,0x38,0x7c,0xcc,0xc0, + 0xfc,0xcc,0xcc,0x78,0x30,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0xf0,0xf0,0x60,0x70, + 0x30,0x78,0xfc,0xc6,0x36,0x7e,0xee,0xc6, + 0xc6,0xc6,0xee,0x7e,0x36,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xe6,0xfe,0xdc,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0x00,0xc0,0xc0,0xc0,0xe0,0x60, + 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x00,0x60,0x60,0xce,0xcc,0xd8,0xd8, + 0xf0,0xf0,0xd8,0xd8,0xcc,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xcc,0xc0,0xcc,0xc0, + 0xcc,0xc0,0xcc,0xc0,0xcc,0xc0,0xcc,0xc0, + 0xcc,0xc0,0xff,0xc0,0xdb,0x80,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xc6,0xe6,0xfe,0xdc,0x38, + 0x7c,0xee,0xc6,0xc6,0xc6,0xee,0x7c,0x38, + 0xc0,0xc0,0xc0,0xd8,0xfc,0xee,0xc6,0xc6, + 0xc6,0xee,0xfc,0xd8,0x06,0x06,0x06,0x36, + 0x7e,0xee,0xc6,0xc6,0xc6,0xee,0x7e,0x36, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xf8, + 0xd0,0x78,0xfc,0xcc,0x1c,0x78,0xe0,0xcc, + 0xfc,0x78,0x30,0x70,0x60,0x60,0x60,0x60, + 0x60,0xf0,0xf0,0x60,0x60,0x76,0xfe,0xce, + 0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x30,0x30, + 0x30,0x78,0x78,0x48,0xcc,0xcc,0xcc,0x33, + 0x00,0x33,0x00,0x33,0x00,0x73,0x80,0x7f, + 0x80,0x4c,0x80,0x4c,0x80,0xcc,0xc0,0xcc, + 0xc0,0xc6,0xee,0x6c,0x38,0x38,0x38,0x6c, + 0xee,0xc6,0x60,0x70,0x10,0x18,0x38,0x38, + 0x2c,0x6c,0x6c,0xc6,0xc6,0xc6,0xfc,0xfc, + 0x60,0x60,0x30,0x18,0x18,0xfc,0xfc,0x30, + 0x70,0x60,0x60,0x60,0x60,0x60,0xc0,0x60, + 0x60,0x60,0x60,0x60,0x70,0x30,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xc0,0xe0,0x60, + 0x60,0x60,0x60,0x60,0x30,0x60,0x60,0x60, + 0x60,0x60,0xe0,0xc0,0x98,0xfc,0x64,0xc0, + 0xc0,0xc0,0xc0,0xc0,0x80,0x80,0x80,0x00, + 0x00,0xc0,0xc0,0x20,0x20,0x38,0x7c,0xec, + 0xe0,0xd0,0xd0,0xdc,0x7c,0x38,0x08,0x08, + 0xcc,0xfe,0x70,0x30,0x30,0xf8,0x60,0xc0, + 0xcc,0xcc,0x7c,0x38,0xcc,0x78,0xcc,0xcc, + 0xcc,0xcc,0x78,0xcc,0x18,0x18,0x18,0x7e, + 0x18,0x7e,0x18,0x3c,0x24,0x66,0x42,0xc3, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x38, + 0x7c,0x6c,0x0c,0x18,0x7c,0xe6,0xc6,0xce, + 0x7c,0x30,0x60,0x6c,0x7c,0x38,0xd8,0xd8, + 0x1e,0x00,0x33,0x00,0x40,0x80,0xde,0xc0, + 0xb3,0x40,0xa0,0x40,0xa0,0x40,0xb3,0x40, + 0xde,0xc0,0x40,0x80,0x33,0x00,0x1e,0x00, + 0xf0,0x00,0xd0,0xb0,0x70,0xb0,0x60,0x24, + 0x6c,0xd8,0xd8,0x6c,0x24,0x06,0x06,0x06, + 0xfe,0xfe,0xe0,0xe0,0x1e,0x00,0x33,0x00, + 0x40,0x80,0xd2,0xc0,0x96,0x40,0x9c,0x40, + 0x92,0x40,0x92,0x40,0xdc,0xc0,0x40,0x80, + 0x33,0x00,0x1e,0x00,0xf0,0x60,0x90,0x90, + 0x90,0x60,0xfc,0xfc,0x00,0x30,0x30,0x30, + 0xfc,0xfc,0x30,0x30,0x30,0xf0,0x80,0x40, + 0x20,0x90,0xb0,0x60,0x60,0xb0,0x10,0x60, + 0x30,0x90,0x60,0xc0,0x60,0xc0,0xc0,0xc0, + 0xf6,0xfe,0xce,0xc6,0xc6,0xc6,0xc6,0xc6, + 0xc6,0x14,0x14,0x14,0x14,0x14,0x14,0x14, + 0x14,0x74,0xf4,0xf4,0xf4,0xf4,0x74,0x3e, + 0xc0,0xc0,0xc0,0x60,0x40,0x20,0x20,0x20, + 0x20,0x20,0xe0,0x20,0xf0,0x00,0x60,0x90, + 0x90,0x90,0x60,0x90,0xd8,0x6c,0x6c,0xd8, + 0x90,0x20,0x40,0x10,0x40,0x13,0xe0,0x0a, + 0x40,0x09,0x40,0x24,0xc0,0x24,0x40,0x22, + 0x00,0x22,0x00,0x21,0x00,0xe1,0x00,0x20, + 0x80,0x21,0xe0,0x11,0x00,0x10,0x80,0x08, + 0x40,0x09,0x20,0x25,0x60,0x24,0xc0,0x22, + 0x00,0x22,0x00,0x21,0x00,0xe1,0x00,0x20, + 0x80,0x20,0x40,0x10,0x40,0x13,0xe0,0x0a, + 0x40,0x09,0x40,0x64,0xc0,0xb4,0x40,0x12, + 0x00,0x62,0x00,0x31,0x00,0x91,0x00,0x60, + 0x80,0x70,0xf8,0xcc,0xcc,0xc0,0x60,0x60, + 0x30,0x30,0x00,0x30,0x30,0xe1,0xc0,0x61, + 0x80,0x7f,0x80,0x3f,0x00,0x33,0x00,0x33, + 0x00,0x12,0x00,0x1e,0x00,0x1e,0x00,0x0c, + 0x00,0x0c,0x00,0x00,0x00,0x0c,0x00,0x18, + 0x00,0xe1,0xc0,0x61,0x80,0x7f,0x80,0x3f, + 0x00,0x33,0x00,0x33,0x00,0x12,0x00,0x1e, + 0x00,0x1e,0x00,0x0c,0x00,0x0c,0x00,0x00, + 0x00,0x0c,0x00,0x06,0x00,0xe1,0xc0,0x61, + 0x80,0x7f,0x80,0x3f,0x00,0x33,0x00,0x33, + 0x00,0x12,0x00,0x1e,0x00,0x1e,0x00,0x0c, + 0x00,0x0c,0x00,0x00,0x00,0x36,0x00,0x1c, + 0x00,0xe1,0xc0,0x61,0x80,0x7f,0x80,0x3f, + 0x00,0x33,0x00,0x33,0x00,0x12,0x00,0x1e, + 0x00,0x1e,0x00,0x0c,0x00,0x0c,0x00,0x00, + 0x00,0x16,0x00,0x0d,0x00,0xe1,0xc0,0x61, + 0x80,0x7f,0x80,0x3f,0x00,0x33,0x00,0x33, + 0x00,0x12,0x00,0x1e,0x00,0x1e,0x00,0x0c, + 0x00,0x0c,0x00,0x00,0x00,0x36,0x00,0x36, + 0x00,0xe1,0xc0,0x61,0x80,0x7f,0x80,0x3f, + 0x00,0x33,0x00,0x33,0x00,0x12,0x00,0x1e, + 0x00,0x1e,0x00,0x0c,0x00,0x0c,0x00,0x0c, + 0x00,0x0a,0x00,0x06,0x00,0xe3,0xf8,0x63, + 0xf8,0x7f,0x00,0x7f,0x00,0x33,0x00,0x33, + 0xf8,0x3b,0xf8,0x1b,0x00,0x1b,0x00,0x1f, + 0x00,0x0f,0xf8,0x0f,0xf8,0x18,0x0c,0x08, + 0x3c,0x7e,0x63,0xc3,0xc0,0xc0,0xc0,0xc0, + 0xc3,0x63,0x7e,0x3c,0xfe,0xfe,0xc0,0xc0, + 0xc0,0xfe,0xfe,0xc0,0xc0,0xfe,0xfe,0x00, + 0x18,0x30,0xfe,0xfe,0xc0,0xc0,0xc0,0xfe, + 0xfe,0xc0,0xc0,0xfe,0xfe,0x00,0x18,0x0c, + 0xfe,0xfe,0xc0,0xc0,0xc0,0xfe,0xfe,0xc0, + 0xc0,0xfe,0xfe,0x00,0x6c,0x38,0xfe,0xfe, + 0xc0,0xc0,0xc0,0xfe,0xfe,0xc0,0xc0,0xfe, + 0xfe,0x00,0x6c,0x6c,0x60,0x60,0x60,0x60, + 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00, + 0x60,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0xc0,0x60, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x00,0xd8,0x70,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x00,0xd8,0xd8,0x7e,0x00,0x7f,0x00, + 0x63,0x00,0x61,0x80,0x61,0x80,0xf9,0x80, + 0xf9,0x80,0x61,0x80,0x61,0x80,0x63,0x00, + 0x7f,0x00,0x7e,0x00,0xc3,0xc7,0xc7,0xcf, + 0xcb,0xdb,0xd3,0xf3,0xe3,0xe3,0xc3,0x00, + 0x2c,0x1a,0x3e,0x00,0x7f,0x00,0x63,0x00, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0x63,0x00,0x7f,0x00,0x3e,0x00, + 0x00,0x00,0x0c,0x00,0x18,0x00,0x3e,0x00, + 0x7f,0x00,0x63,0x00,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0x63,0x00, + 0x7f,0x00,0x3e,0x00,0x00,0x00,0x18,0x00, + 0x0c,0x00,0x3e,0x00,0x7f,0x00,0x63,0x00, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0x63,0x00,0x7f,0x00,0x3e,0x00, + 0x00,0x00,0x36,0x00,0x1c,0x00,0x3e,0x00, + 0x7f,0x00,0x63,0x00,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0x63,0x00, + 0x7f,0x00,0x3e,0x00,0x00,0x00,0x2c,0x00, + 0x1a,0x00,0x3e,0x00,0x7f,0x00,0x63,0x00, + 0xc1,0x80,0xc1,0x80,0xc1,0x80,0xc1,0x80, + 0xc1,0x80,0x63,0x00,0x7f,0x00,0x3e,0x00, + 0x00,0x00,0x36,0x00,0x36,0x00,0x84,0xcc, + 0x78,0x30,0x30,0x78,0xcc,0x84,0xbe,0x00, + 0xff,0x00,0x63,0x00,0xf1,0x80,0xd1,0x80, + 0xc9,0x80,0xc9,0x80,0xc5,0x80,0xc7,0x80, + 0x63,0x00,0x7f,0x80,0x3e,0x80,0x3c,0x7e, + 0xe7,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, + 0xc3,0x00,0x18,0x30,0x3c,0x7e,0xe7,0xc3, + 0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x00, + 0x18,0x0c,0x3c,0x7e,0xe7,0xc3,0xc3,0xc3, + 0xc3,0xc3,0xc3,0xc3,0xc3,0x00,0x6c,0x38, + 0x3c,0x7e,0xe7,0xc3,0xc3,0xc3,0xc3,0xc3, + 0xc3,0xc3,0xc3,0x00,0x6c,0x6c,0x0c,0x00, + 0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00, + 0x1e,0x00,0x1e,0x00,0x33,0x00,0x33,0x00, + 0x61,0x80,0xe1,0xc0,0x00,0x00,0x0c,0x00, + 0x06,0x00,0xc0,0xc0,0xf8,0xfc,0xce,0xc6, + 0xc6,0xce,0xfc,0xf8,0xc0,0xc0,0xd8,0xdc, + 0xc6,0xc6,0xc6,0xdc,0xd8,0xcc,0xcc,0xcc, + 0x7c,0x38,0x6c,0xfc,0xcc,0xcc,0x7c,0x1c, + 0xcc,0xfc,0x78,0x00,0x30,0x60,0x6c,0xfc, + 0xcc,0xcc,0x7c,0x1c,0xcc,0xfc,0x78,0x00, + 0x30,0x18,0x6c,0xfc,0xcc,0xcc,0x7c,0x1c, + 0xcc,0xfc,0x78,0x00,0xd8,0x70,0x6c,0xfc, + 0xcc,0xcc,0x7c,0x1c,0xcc,0xfc,0x78,0x00, + 0x58,0x34,0x6c,0xfc,0xcc,0xcc,0x7c,0x1c, + 0xcc,0xfc,0x78,0x00,0xd8,0xd8,0x6c,0xfc, + 0xcc,0xcc,0x7c,0x1c,0xcc,0xfc,0x78,0x00, + 0x30,0x28,0x18,0x73,0x80,0xff,0xc0,0xcc, + 0xc0,0xcc,0x00,0x7f,0xc0,0x1c,0xc0,0xcc, + 0xc0,0xff,0xc0,0x73,0x80,0x30,0x18,0x10, + 0x38,0x7c,0xec,0xc0,0xc0,0xc0,0xec,0x7c, + 0x38,0x38,0x7c,0xcc,0xc0,0xfc,0xcc,0xcc, + 0x78,0x30,0x00,0x30,0x60,0x38,0x7c,0xcc, + 0xc0,0xfc,0xcc,0xcc,0x78,0x30,0x00,0x30, + 0x18,0x38,0x7c,0xcc,0xc0,0xfc,0xcc,0xcc, + 0x78,0x30,0x00,0x6c,0x38,0x38,0x7c,0xcc, + 0xc0,0xfc,0xcc,0xcc,0x78,0x30,0x00,0xd8, + 0xd8,0x60,0x60,0x60,0x60,0x60,0x60,0x60, + 0x60,0x60,0x00,0x60,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0xc0, + 0x60,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x00,0xd8,0x70,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x00,0xd8, + 0xd8,0x38,0x7c,0xee,0xc6,0xc6,0xc6,0xee, + 0x7c,0x3c,0xf8,0x38,0x6c,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0xe6,0xfe,0xdc,0x00,0x58, + 0x34,0x38,0x7c,0xee,0xc6,0xc6,0xc6,0xee, + 0x7c,0x38,0x00,0x18,0x30,0x38,0x7c,0xee, + 0xc6,0xc6,0xc6,0xee,0x7c,0x38,0x00,0x30, + 0x18,0x38,0x7c,0xee,0xc6,0xc6,0xc6,0xee, + 0x7c,0x38,0x00,0x6c,0x38,0x38,0x7c,0xee, + 0xc6,0xc6,0xc6,0xee,0x7c,0x38,0x00,0x58, + 0x34,0x38,0x7c,0xee,0xc6,0xc6,0xc6,0xee, + 0x7c,0x38,0x00,0x6c,0x6c,0x30,0x30,0x00, + 0xfc,0xfc,0x00,0x30,0x30,0xb8,0x7c,0xee, + 0xe6,0xd6,0xce,0xee,0x7c,0x3a,0x76,0xfe, + 0xce,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00, + 0x18,0x30,0x76,0xfe,0xce,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0x00,0x30,0x18,0x76,0xfe, + 0xce,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00, + 0x6c,0x38,0x76,0xfe,0xce,0xc6,0xc6,0xc6, + 0xc6,0xc6,0xc6,0x00,0x6c,0x6c,0x60,0x70, + 0x10,0x18,0x38,0x38,0x2c,0x6c,0x6c,0xc6, + 0xc6,0xc6,0x00,0x30,0x18,0xc0,0xc0,0xc0, + 0xd8,0xfc,0xee,0xc6,0xc6,0xc6,0xee,0xfc, + 0xd8,0xc0,0xc0,0xc0,0x60,0x70,0x10,0x18, + 0x38,0x38,0x2c,0x6c,0x6c,0xc6,0xc6,0xc6, + 0x00,0x6c,0x6c, +}; + +BMF_FontData BMF_font_helvb14 = { + -2, -3, + 12, 14, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 12, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 3, 0}, + {2, 12, -1, 0, 4, 1}, + {5, 4, 0, -8, 6, 13}, + {8, 12, 1, 0, 7, 17}, + {7, 15, 0, 2, 7, 29}, + {11, 11, 0, 0, 12, 44}, + {9, 12, 0, 0, 9, 66}, + {2, 4, -1, -8, 4, 90}, + {4, 15, 0, 3, 4, 94}, + {4, 15, 1, 3, 4, 109}, + {5, 6, 0, -6, 5, 124}, + {6, 8, -1, 0, 8, 130}, + {2, 5, 0, 3, 3, 138}, + {7, 2, 0, -3, 8, 143}, + {2, 2, 0, 0, 3, 145}, + {4, 11, 0, 0, 4, 147}, + {6, 12, 0, 0, 7, 158}, + {4, 12, 0, 0, 7, 170}, + {6, 12, 0, 0, 7, 182}, + {6, 12, 0, 0, 7, 194}, + {6, 12, 0, 0, 7, 206}, + {6, 12, 0, 0, 7, 218}, + {6, 12, 0, 0, 7, 230}, + {6, 12, 0, 0, 7, 242}, + {6, 12, 0, 0, 7, 254}, + {6, 12, 0, 0, 7, 266}, + {2, 8, -1, 0, 4, 278}, + {2, 11, -1, 3, 4, 286}, + {7, 8, 0, 0, 8, 297}, + {6, 6, -1, -1, 8, 305}, + {7, 8, 0, 0, 8, 311}, + {6, 12, -1, 0, 8, 319}, + {12, 14, 0, 2, 13, 331}, + {10, 12, 1, 0, 9, 359}, + {8, 12, 0, 0, 9, 383}, + {8, 12, 0, 0, 9, 395}, + {8, 12, 0, 0, 9, 407}, + {7, 12, 0, 0, 8, 419}, + {7, 12, -1, 0, 8, 431}, + {9, 12, 0, 0, 10, 443}, + {8, 12, 0, 0, 9, 467}, + {2, 12, -1, 0, 5, 479}, + {6, 12, 0, 0, 7, 491}, + {9, 12, -1, 0, 10, 503}, + {7, 12, -1, 0, 8, 527}, + {10, 12, 0, 0, 11, 539}, + {8, 12, 0, 0, 9, 563}, + {9, 12, 0, 0, 10, 575}, + {7, 12, -1, 0, 9, 599}, + {9, 13, 0, 1, 10, 611}, + {8, 12, 0, 0, 9, 637}, + {8, 12, 0, 0, 9, 649}, + {8, 12, 0, 0, 9, 661}, + {8, 12, 0, 0, 9, 673}, + {8, 12, 0, 0, 9, 685}, + {12, 12, 0, 0, 13, 697}, + {9, 12, 0, 0, 10, 721}, + {10, 12, 1, 0, 9, 745}, + {8, 12, 0, 0, 9, 769}, + {3, 15, 0, 3, 4, 781}, + {4, 11, 0, 0, 4, 796}, + {3, 15, 0, 3, 4, 807}, + {6, 7, -1, -4, 8, 822}, + {7, 1, 0, 3, 7, 829}, + {2, 4, -1, -8, 4, 830}, + {6, 9, 0, 0, 7, 834}, + {7, 12, 0, 0, 8, 843}, + {6, 9, 0, 0, 7, 855}, + {7, 12, 0, 0, 8, 864}, + {6, 9, 0, 0, 7, 876}, + {4, 12, 0, 0, 5, 885}, + {7, 12, 0, 3, 8, 897}, + {7, 12, 0, 0, 8, 909}, + {2, 12, 0, 0, 3, 921}, + {3, 15, 1, 3, 3, 933}, + {7, 12, 0, 0, 7, 948}, + {2, 12, 0, 0, 3, 960}, + {10, 9, 0, 0, 11, 972}, + {7, 9, 0, 0, 8, 990}, + {7, 9, 0, 0, 8, 999}, + {7, 12, 0, 3, 8, 1008}, + {7, 12, 0, 3, 8, 1020}, + {5, 9, 0, 0, 5, 1032}, + {6, 9, 0, 0, 7, 1041}, + {4, 11, 0, 0, 5, 1050}, + {7, 9, 0, 0, 8, 1061}, + {6, 9, 0, 0, 7, 1070}, + {10, 9, 0, 0, 11, 1079}, + {7, 9, 0, 0, 8, 1097}, + {7, 12, 0, 3, 8, 1106}, + {6, 9, 0, 0, 7, 1118}, + {4, 15, 0, 3, 5, 1127}, + {1, 15, -1, 3, 4, 1142}, + {4, 15, 0, 3, 5, 1157}, + {6, 3, -1, -3, 8, 1172}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {2, 12, -1, 3, 4, 1175}, + {6, 13, 0, 2, 7, 1187}, + {7, 12, 0, 0, 7, 1200}, + {6, 8, 0, -2, 7, 1212}, + {8, 12, 1, 0, 7, 1220}, + {1, 15, -1, 3, 4, 1232}, + {7, 15, 0, 3, 7, 1247}, + {5, 2, 1, -10, 4, 1262}, + {10, 12, 0, 0, 10, 1264}, + {4, 7, 0, -5, 5, 1288}, + {6, 6, 0, -1, 7, 1295}, + {7, 5, 0, -2, 8, 1301}, + {3, 2, 0, -3, 4, 1306}, + {10, 12, 0, 0, 10, 1308}, + {4, 1, 0, -11, 4, 1332}, + {4, 5, 0, -7, 5, 1333}, + {6, 11, -1, 0, 8, 1338}, + {4, 7, 0, -5, 4, 1349}, + {4, 7, 0, -5, 4, 1356}, + {3, 2, -1, -10, 4, 1363}, + {7, 12, 0, 3, 8, 1365}, + {7, 15, 0, 3, 7, 1377}, + {2, 2, 0, -5, 3, 1392}, + {3, 3, 0, 3, 4, 1394}, + {3, 7, 0, -5, 4, 1397}, + {4, 7, 0, -5, 5, 1404}, + {6, 6, 0, -1, 7, 1411}, + {11, 12, 1, 0, 11, 1417}, + {11, 12, 1, 0, 11, 1441}, + {11, 12, 0, 0, 11, 1465}, + {6, 12, -1, 3, 8, 1489}, + {10, 14, 1, 0, 9, 1501}, + {10, 14, 1, 0, 9, 1529}, + {10, 14, 1, 0, 9, 1557}, + {10, 14, 1, 0, 9, 1585}, + {10, 14, 1, 0, 9, 1613}, + {10, 14, 1, 0, 9, 1641}, + {13, 12, 1, 0, 13, 1669}, + {8, 15, 0, 3, 9, 1693}, + {7, 14, 0, 0, 8, 1708}, + {7, 14, 0, 0, 8, 1722}, + {7, 14, 0, 0, 8, 1736}, + {7, 14, 0, 0, 8, 1750}, + {3, 14, 0, 0, 5, 1764}, + {3, 14, -1, 0, 5, 1778}, + {5, 14, 1, 0, 5, 1792}, + {5, 14, 1, 0, 5, 1806}, + {9, 12, 1, 0, 9, 1820}, + {8, 14, 0, 0, 9, 1844}, + {9, 14, 0, 0, 10, 1858}, + {9, 14, 0, 0, 10, 1886}, + {9, 14, 0, 0, 10, 1914}, + {9, 14, 0, 0, 10, 1942}, + {9, 14, 0, 0, 10, 1970}, + {6, 8, -1, 0, 8, 1998}, + {9, 12, 0, 0, 10, 2006}, + {8, 14, 0, 0, 9, 2030}, + {8, 14, 0, 0, 9, 2044}, + {8, 14, 0, 0, 9, 2058}, + {8, 14, 0, 0, 9, 2072}, + {10, 14, 1, 0, 9, 2086}, + {7, 12, -1, 0, 9, 2114}, + {7, 12, 0, 0, 8, 2126}, + {6, 12, 0, 0, 7, 2138}, + {6, 12, 0, 0, 7, 2150}, + {6, 12, 0, 0, 7, 2162}, + {6, 12, 0, 0, 7, 2174}, + {6, 12, 0, 0, 7, 2186}, + {6, 13, 0, 0, 7, 2198}, + {10, 9, 0, 0, 11, 2211}, + {6, 12, 0, 3, 7, 2229}, + {6, 12, 0, 0, 7, 2241}, + {6, 12, 0, 0, 7, 2253}, + {6, 12, 0, 0, 7, 2265}, + {6, 12, 0, 0, 7, 2277}, + {3, 12, 1, 0, 3, 2289}, + {3, 12, 0, 0, 3, 2301}, + {5, 12, 2, 0, 3, 2313}, + {5, 12, 2, 0, 3, 2325}, + {7, 12, 0, 0, 8, 2337}, + {7, 12, 0, 0, 8, 2349}, + {7, 12, 0, 0, 8, 2361}, + {7, 12, 0, 0, 8, 2373}, + {7, 12, 0, 0, 8, 2385}, + {7, 12, 0, 0, 8, 2397}, + {7, 12, 0, 0, 8, 2409}, + {6, 8, -1, 0, 8, 2421}, + {7, 9, 0, 0, 8, 2429}, + {7, 12, 0, 0, 8, 2438}, + {7, 12, 0, 0, 8, 2450}, + {7, 12, 0, 0, 8, 2462}, + {7, 12, 0, 0, 8, 2474}, + {7, 15, 0, 3, 8, 2486}, + {7, 15, 0, 3, 8, 2501}, + {7, 15, 0, 3, 8, 2516}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_helvb8.cpp b/intern/bmfont/intern/BMF_font_helvb8.cpp new file mode 100644 index 00000000000..79651b06519 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_helvb8.cpp @@ -0,0 +1,458 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_HELVB8 + +static unsigned char bitmap_data[]= { + 0x00,0x80,0x00,0x80,0x80,0x80,0x80,0xa0, + 0xa0,0xa0,0x50,0xf8,0x50,0xf8,0x50,0x40, + 0xe0,0x10,0x60,0x80,0x70,0x20,0x5c,0x54, + 0x2c,0xd0,0xa8,0xe8,0x58,0xb0,0xa8,0x48, + 0xa0,0x40,0x80,0x80,0x80,0x40,0x80,0x80, + 0x80,0x80,0x80,0x40,0x80,0x40,0x40,0x40, + 0x40,0x40,0x80,0x40,0xe0,0x40,0x20,0x20, + 0xf8,0x20,0x20,0x80,0x40,0x40,0xf0,0x80, + 0x80,0x80,0x80,0x80,0x40,0x40,0x40,0x60, + 0x90,0x90,0x90,0x90,0x60,0x40,0x40,0x40, + 0x40,0xc0,0x40,0xf0,0x40,0x20,0x10,0x90, + 0x60,0xc0,0x20,0x20,0xc0,0x20,0xc0,0x20, + 0x20,0xf0,0x60,0x20,0x20,0xc0,0x20,0x20, + 0xc0,0x80,0xe0,0x60,0x90,0x90,0xe0,0x80, + 0x70,0x40,0x40,0x40,0x20,0x10,0xf0,0x60, + 0x90,0x90,0x60,0x90,0x60,0x60,0x10,0x70, + 0x90,0x90,0x60,0x80,0x00,0x00,0x80,0x80, + 0x40,0x40,0x00,0x00,0x40,0x20,0x40,0x80, + 0x40,0x20,0xe0,0x00,0xe0,0x80,0x40,0x20, + 0x40,0x80,0x40,0x00,0x40,0x20,0xc0,0x78, + 0x80,0x9e,0xa5,0x99,0x41,0x3e,0x88,0x88, + 0x70,0x50,0x20,0x20,0xe0,0x90,0x90,0xe0, + 0x90,0xe0,0x70,0x88,0x80,0x80,0x88,0x70, + 0xf0,0x88,0x88,0x88,0x88,0xf0,0xf0,0x80, + 0x80,0xe0,0x80,0xf0,0x80,0x80,0x80,0xe0, + 0x80,0xf0,0x70,0x88,0x88,0x98,0x80,0x70, + 0x88,0x88,0x88,0xf8,0x88,0x88,0x80,0x80, + 0x80,0x80,0x80,0x80,0x40,0xa0,0x20,0x20, + 0x20,0x20,0x90,0x90,0xe0,0xc0,0xa0,0x90, + 0xe0,0x80,0x80,0x80,0x80,0x80,0xa8,0xa8, + 0xa8,0xa8,0xd8,0x88,0x88,0x98,0xa8,0xa8, + 0xc8,0x88,0x70,0x88,0x88,0x88,0x88,0x70, + 0x80,0x80,0xe0,0x90,0x90,0xe0,0x10,0x20, + 0x70,0x88,0x88,0x88,0x88,0x70,0x90,0x90, + 0xe0,0x90,0x90,0xe0,0xe0,0x10,0x10,0xe0, + 0x80,0x70,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x70,0x88,0x88,0x88,0x88,0x88,0x40,0xa0, + 0x90,0x90,0x90,0x90,0x48,0x48,0x6c,0x92, + 0x92,0x92,0x90,0x90,0x60,0x60,0x90,0x90, + 0x20,0x20,0x30,0x48,0x48,0xc8,0xf0,0x80, + 0x40,0x20,0x10,0xf0,0xc0,0x80,0x80,0x80, + 0x80,0x80,0xc0,0x40,0x40,0x40,0x40,0x80, + 0x80,0x80,0xc0,0x40,0x40,0x40,0x40,0x40, + 0xc0,0x88,0x50,0x20,0xf8,0x80,0x80,0x80, + 0xd0,0xa0,0xe0,0x20,0xc0,0xe0,0x90,0x90, + 0x90,0xe0,0x80,0x80,0x60,0x80,0x80,0x80, + 0x60,0x70,0x90,0x90,0x90,0x70,0x10,0x10, + 0x60,0x80,0xe0,0xa0,0x40,0x40,0x40,0x40, + 0x40,0xe0,0x40,0x20,0x60,0x10,0x70,0x90, + 0x90,0x70,0x90,0x90,0x90,0x90,0xe0,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80, + 0x80,0x40,0x40,0x40,0x40,0x40,0x40,0x00, + 0x40,0xa0,0xa0,0xc0,0xc0,0xa0,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xa8, + 0xa8,0xa8,0xa8,0xf0,0x90,0x90,0x90,0x90, + 0xe0,0x60,0x90,0x90,0x90,0x60,0x80,0xe0, + 0x90,0x90,0x90,0xe0,0x10,0x70,0x90,0x90, + 0x90,0x70,0x80,0x80,0x80,0xc0,0xa0,0xc0, + 0x20,0x60,0x80,0x60,0x40,0x40,0x40,0x40, + 0xe0,0x40,0x40,0x60,0xa0,0xa0,0xa0,0xa0, + 0x40,0xa0,0x90,0x90,0x90,0x50,0x50,0xa8, + 0xa8,0xa8,0x90,0x90,0x60,0x90,0x90,0x80, + 0x40,0x60,0x90,0x90,0x90,0xe0,0x80,0x40, + 0x20,0xe0,0x20,0x40,0x40,0xc0,0x40,0x40, + 0x20,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x40,0x40,0x60,0x40,0x40,0x80,0xb0, + 0x48,0x00,0x80,0x80,0x80,0x80,0x80,0x00, + 0x80,0x40,0x40,0xa0,0x80,0xa0,0x40,0x40, + 0xf0,0x40,0x40,0xe0,0x40,0x30,0x88,0x70, + 0x50,0x70,0x88,0x20,0x20,0xf8,0x50,0x88, + 0x80,0x80,0x80,0x00,0x80,0x80,0x80,0xe0, + 0x10,0x30,0x60,0x90,0x60,0x80,0x70,0x90, + 0x78,0x84,0xb4,0xa4,0xb4,0x84,0x78,0xe0, + 0x00,0xe0,0x20,0xc0,0x50,0xa0,0x50,0x10, + 0x10,0xf0,0xc0,0x78,0x84,0xac,0xb4,0xb4, + 0x84,0x78,0xe0,0x40,0xa0,0x40,0xf0,0x00, + 0x20,0xf0,0x20,0xc0,0x80,0x40,0x80,0xc0, + 0x20,0x60,0xe0,0x80,0x40,0x80,0x80,0xe0, + 0xa0,0xa0,0xa0,0x50,0x50,0x50,0x50,0xd0, + 0xd0,0xd0,0x78,0x80,0x80,0x80,0x40,0x40, + 0x40,0xc0,0x40,0xe0,0x00,0xe0,0xa0,0xe0, + 0xa0,0x50,0xa0,0x04,0x5e,0x2c,0x54,0x48, + 0xc4,0x40,0x0e,0x44,0x22,0x5c,0x48,0xc4, + 0x40,0x04,0x5e,0x2c,0xd4,0x28,0x64,0xe0, + 0x60,0x90,0x40,0x20,0x00,0x20,0x88,0x88, + 0x70,0x50,0x20,0x20,0x00,0x20,0x40,0x88, + 0x88,0x70,0x50,0x20,0x20,0x00,0x20,0x10, + 0x88,0x88,0x70,0x50,0x20,0x20,0x00,0x50, + 0x20,0x88,0x88,0x70,0x50,0x20,0x20,0x00, + 0x50,0x28,0x88,0x88,0x70,0x50,0x20,0x20, + 0x00,0x50,0x88,0x88,0x70,0x50,0x20,0x20, + 0x20,0x50,0x20,0x9e,0x90,0x7c,0x50,0x30, + 0x3e,0x80,0x40,0x70,0x88,0x80,0x88,0x88, + 0x70,0xf0,0x80,0x80,0xe0,0x80,0xf0,0x00, + 0x20,0x40,0xf0,0x80,0x80,0xe0,0x80,0xf0, + 0x00,0x40,0x20,0xf0,0x80,0x80,0xe0,0x80, + 0xf0,0x00,0xa0,0x40,0xf0,0x80,0x80,0xe0, + 0x80,0xf0,0x00,0xa0,0x40,0x40,0x40,0x40, + 0x40,0x40,0x00,0x40,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x00,0x80,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x00,0xa0,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x00,0xa0,0x70, + 0x48,0x48,0xe8,0x48,0x70,0x88,0x98,0xa8, + 0xa8,0xc8,0x88,0x00,0x50,0x28,0x70,0x88, + 0x88,0x88,0x88,0x70,0x00,0x20,0x40,0x70, + 0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x10, + 0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x50, + 0x20,0x70,0x88,0x88,0x88,0x88,0x70,0x00, + 0x50,0x28,0x70,0x88,0x88,0x88,0x88,0x70, + 0x00,0x50,0x90,0x60,0x60,0x90,0x80,0xf0, + 0xc8,0xa8,0x98,0x88,0x78,0x08,0x70,0x88, + 0x88,0x88,0x88,0x88,0x00,0x20,0x40,0x70, + 0x88,0x88,0x88,0x88,0x88,0x00,0x20,0x10, + 0x70,0x88,0x88,0x88,0x88,0x88,0x00,0x50, + 0x20,0x70,0x88,0x88,0x88,0x88,0x88,0x00, + 0x50,0x20,0x20,0x30,0x48,0x48,0xc8,0x00, + 0x10,0x08,0x80,0xf0,0x88,0x88,0xf0,0x80, + 0x80,0xa0,0x90,0x90,0xa0,0x90,0x60,0xd0, + 0xa0,0xe0,0x20,0xc0,0x00,0x40,0x80,0xd0, + 0xa0,0xe0,0x20,0xc0,0x00,0x40,0x20,0xd0, + 0xa0,0xe0,0x20,0xc0,0x00,0xa0,0x40,0x68, + 0x50,0x70,0x10,0x60,0x00,0xb0,0x68,0xd0, + 0xa0,0xe0,0x20,0xc0,0x00,0xa0,0xd0,0xa0, + 0xe0,0x20,0xc0,0x40,0xa0,0x40,0xd8,0xa0, + 0xf8,0x28,0xd0,0x80,0x40,0x60,0x80,0x80, + 0x80,0x60,0x60,0x80,0xe0,0xa0,0x40,0x00, + 0x20,0x40,0x60,0x80,0xe0,0xa0,0x40,0x00, + 0x40,0x20,0x60,0x80,0xe0,0xa0,0x40,0x00, + 0xa0,0x40,0x60,0x80,0xe0,0xa0,0x40,0x00, + 0xa0,0x40,0x40,0x40,0x40,0x40,0x00,0x40, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80, + 0x40,0x40,0x40,0x40,0x40,0x40,0x00,0xa0, + 0x40,0x40,0x40,0x40,0x40,0x40,0x00,0xa0, + 0x60,0x90,0x90,0x90,0x70,0xa0,0x60,0x90, + 0x90,0x90,0x90,0x90,0xe0,0x00,0xa0,0x50, + 0x60,0x90,0x90,0x90,0x60,0x00,0x20,0x40, + 0x60,0x90,0x90,0x90,0x60,0x00,0x20,0x10, + 0x60,0x90,0x90,0x90,0x60,0x00,0xa0,0x40, + 0x60,0x90,0x90,0x90,0x60,0x00,0xa0,0x50, + 0x60,0x90,0x90,0x90,0x60,0x00,0x90,0x20, + 0x00,0xf0,0x00,0x20,0x80,0x70,0x68,0x58, + 0x48,0x3c,0x02,0x60,0xa0,0xa0,0xa0,0xa0, + 0x00,0x40,0x80,0x60,0xa0,0xa0,0xa0,0xa0, + 0x00,0x40,0x20,0x60,0xa0,0xa0,0xa0,0xa0, + 0x00,0xa0,0x40,0x60,0xa0,0xa0,0xa0,0xa0, + 0x00,0xa0,0x80,0x40,0x60,0x90,0x90,0x90, + 0x00,0x20,0x10,0x80,0xe0,0x90,0x90,0x90, + 0xe0,0x80,0x80,0x40,0x60,0x90,0x90,0x90, + 0x00,0x50, +}; + +BMF_FontData BMF_font_helvb8 = { + 0, -2, + 9, 9, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 8, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 2, 0}, + {1, 6, -1, 0, 2, 1}, + {3, 3, -1, -3, 3, 7}, + {5, 5, 0, 0, 5, 10}, + {4, 7, -1, 1, 5, 15}, + {6, 6, -1, 0, 7, 22}, + {5, 6, -1, 0, 6, 28}, + {1, 3, -1, -3, 2, 34}, + {2, 7, -1, 1, 3, 37}, + {2, 7, -1, 1, 3, 44}, + {3, 3, -1, -2, 3, 51}, + {5, 5, -1, 0, 5, 54}, + {2, 3, 0, 2, 2, 59}, + {4, 1, -2, -2, 6, 62}, + {1, 1, -1, 0, 2, 63}, + {2, 7, -1, 1, 2, 64}, + {4, 6, -1, 0, 5, 71}, + {2, 6, -2, 0, 5, 77}, + {4, 6, -1, 0, 5, 83}, + {3, 6, -2, 0, 5, 89}, + {4, 6, -1, 0, 5, 95}, + {3, 6, -2, 0, 5, 101}, + {4, 6, -1, 0, 5, 107}, + {4, 6, -1, 0, 5, 113}, + {4, 6, -1, 0, 5, 119}, + {4, 6, -1, 0, 5, 125}, + {1, 4, -1, 0, 2, 131}, + {2, 6, 0, 2, 2, 135}, + {3, 5, -1, 0, 5, 141}, + {3, 3, -1, -1, 4, 146}, + {3, 5, -2, 0, 5, 149}, + {3, 5, -2, 0, 5, 154}, + {8, 7, -1, 1, 9, 159}, + {5, 6, -1, 0, 6, 166}, + {4, 6, -2, 0, 6, 172}, + {5, 6, -1, 0, 6, 178}, + {5, 6, -1, 0, 6, 184}, + {4, 6, -2, 0, 6, 190}, + {4, 6, -2, 0, 5, 196}, + {5, 6, -1, 0, 6, 202}, + {5, 6, -1, 0, 6, 208}, + {1, 6, -1, 0, 2, 214}, + {3, 6, -1, 0, 4, 220}, + {4, 6, -2, 0, 6, 226}, + {3, 6, -2, 0, 5, 232}, + {5, 6, -2, 0, 7, 238}, + {5, 6, -1, 0, 6, 244}, + {5, 6, -1, 0, 6, 250}, + {4, 6, -2, 0, 6, 256}, + {5, 8, -1, 2, 6, 262}, + {4, 6, -2, 0, 6, 270}, + {4, 6, -2, 0, 6, 276}, + {3, 6, -1, 0, 4, 282}, + {5, 6, -1, 0, 6, 288}, + {4, 6, -2, 0, 6, 294}, + {7, 6, -1, 0, 7, 300}, + {4, 6, -2, 0, 6, 306}, + {5, 6, -1, 0, 6, 312}, + {4, 6, -2, 0, 6, 318}, + {2, 7, -1, 1, 2, 324}, + {2, 7, 0, 1, 2, 331}, + {2, 7, 0, 1, 2, 338}, + {5, 3, 0, -2, 5, 345}, + {5, 1, 0, 1, 5, 348}, + {1, 3, -1, -3, 2, 349}, + {4, 5, -1, 0, 4, 352}, + {4, 7, -1, 0, 5, 357}, + {3, 5, -1, 0, 4, 364}, + {4, 7, -1, 0, 5, 369}, + {3, 5, -1, 0, 4, 376}, + {3, 7, -1, 0, 3, 381}, + {4, 6, -1, 1, 5, 388}, + {4, 7, -1, 0, 5, 394}, + {1, 7, -1, 0, 2, 401}, + {2, 9, 0, 2, 2, 408}, + {3, 7, -1, 0, 4, 417}, + {1, 7, -1, 0, 2, 424}, + {5, 5, -1, 0, 6, 431}, + {4, 5, -1, 0, 5, 436}, + {4, 5, -1, 0, 5, 441}, + {4, 6, -1, 1, 5, 446}, + {4, 6, -1, 1, 5, 452}, + {3, 5, -1, 0, 3, 458}, + {3, 5, -1, 0, 4, 463}, + {3, 7, -1, 0, 3, 468}, + {3, 5, -1, 0, 4, 475}, + {4, 5, -1, 0, 5, 480}, + {5, 5, -1, 0, 6, 485}, + {4, 5, -1, 0, 5, 490}, + {4, 6, -1, 1, 4, 495}, + {3, 5, -1, 0, 4, 501}, + {3, 7, 0, 1, 2, 506}, + {1, 7, -1, 1, 2, 513}, + {3, 7, 0, 1, 2, 520}, + {5, 2, -1, -2, 6, 527}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 1, 0, 0, 2, 529}, + {1, 7, -1, 2, 2, 530}, + {3, 7, -1, 1, 5, 537}, + {4, 6, -1, 0, 5, 544}, + {5, 5, 0, 0, 4, 550}, + {5, 5, -1, 0, 6, 555}, + {1, 7, -1, 1, 2, 560}, + {4, 8, -1, 2, 5, 567}, + {4, 1, 0, -5, 2, 575}, + {6, 7, -1, 1, 7, 576}, + {3, 5, 0, -1, 3, 583}, + {4, 3, -1, -1, 5, 588}, + {4, 3, -1, -1, 6, 591}, + {2, 1, 0, -2, 3, 594}, + {6, 7, -1, 1, 7, 595}, + {3, 1, 0, -5, 2, 602}, + {3, 3, -1, -3, 3, 603}, + {4, 5, -1, 0, 5, 606}, + {2, 4, -1, -2, 2, 611}, + {3, 4, 0, -2, 2, 615}, + {2, 2, 0, -4, 2, 619}, + {3, 6, -1, 2, 4, 621}, + {5, 8, 0, 2, 5, 627}, + {1, 2, -1, -1, 2, 635}, + {2, 2, 0, 2, 2, 637}, + {2, 4, 0, -2, 2, 639}, + {3, 5, 0, -1, 3, 643}, + {4, 3, -1, -1, 5, 648}, + {7, 7, 0, 1, 7, 651}, + {7, 7, 0, 1, 7, 658}, + {7, 7, 0, 1, 7, 665}, + {4, 6, -1, 1, 5, 672}, + {5, 9, -1, 0, 6, 678}, + {5, 9, -1, 0, 6, 687}, + {5, 9, -1, 0, 6, 696}, + {5, 9, -1, 0, 6, 705}, + {5, 8, -1, 0, 6, 714}, + {5, 9, -1, 0, 6, 722}, + {7, 6, -1, 0, 8, 731}, + {5, 8, -1, 2, 6, 737}, + {4, 9, -2, 0, 6, 745}, + {4, 9, -2, 0, 6, 754}, + {4, 9, -2, 0, 6, 763}, + {4, 8, -2, 0, 6, 772}, + {2, 9, 0, 0, 2, 780}, + {2, 9, -1, 0, 2, 789}, + {3, 9, 0, 0, 2, 798}, + {3, 8, 0, 0, 2, 807}, + {5, 6, -1, 0, 6, 815}, + {5, 9, -1, 0, 6, 821}, + {5, 9, -1, 0, 6, 830}, + {5, 9, -1, 0, 6, 839}, + {5, 9, -1, 0, 6, 848}, + {5, 9, -1, 0, 6, 857}, + {5, 8, -1, 0, 6, 866}, + {4, 4, -1, 0, 5, 874}, + {5, 8, -1, 1, 6, 878}, + {5, 9, -1, 0, 6, 886}, + {5, 9, -1, 0, 6, 895}, + {5, 9, -1, 0, 6, 904}, + {5, 8, -1, 0, 6, 913}, + {5, 9, -1, 0, 6, 921}, + {5, 6, -1, 0, 6, 930}, + {4, 7, -2, 1, 6, 936}, + {4, 8, -1, 0, 4, 943}, + {4, 8, -1, 0, 4, 951}, + {4, 8, -1, 0, 4, 959}, + {5, 8, 0, 0, 4, 967}, + {4, 7, -1, 0, 4, 975}, + {4, 8, -1, 0, 4, 982}, + {5, 5, -1, 0, 6, 990}, + {3, 7, -1, 2, 4, 995}, + {3, 8, -1, 0, 4, 1002}, + {3, 8, -1, 0, 4, 1010}, + {3, 8, -1, 0, 4, 1018}, + {3, 7, -1, 0, 4, 1026}, + {2, 8, 0, 0, 2, 1033}, + {2, 8, -1, 0, 2, 1041}, + {3, 8, 0, 0, 2, 1049}, + {3, 7, 0, 0, 2, 1057}, + {4, 8, -1, 0, 5, 1064}, + {4, 8, -1, 0, 5, 1072}, + {4, 8, -1, 0, 5, 1080}, + {4, 8, -1, 0, 5, 1088}, + {4, 8, -1, 0, 5, 1096}, + {4, 8, -1, 0, 5, 1104}, + {4, 7, -1, 0, 5, 1112}, + {4, 5, -1, 0, 5, 1119}, + {7, 7, 0, 1, 5, 1124}, + {3, 8, -1, 0, 4, 1131}, + {3, 8, -1, 0, 4, 1139}, + {3, 8, -1, 0, 4, 1147}, + {3, 7, -1, 0, 4, 1155}, + {4, 9, -1, 1, 4, 1162}, + {4, 7, -1, 1, 5, 1171}, + {4, 8, -1, 1, 4, 1178}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_scr12.cpp b/intern/bmfont/intern/BMF_font_scr12.cpp new file mode 100644 index 00000000000..bcdb87fcc0b --- /dev/null +++ b/intern/bmfont/intern/BMF_font_scr12.cpp @@ -0,0 +1,487 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_SCR12 + +static unsigned char bitmap_data[]= { + 0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80, + 0xa0,0xa0,0xa0,0xa0,0x50,0x50,0xfc,0x28, + 0x28,0x7e,0x14,0x14,0x20,0x70,0xa8,0x28, + 0x70,0xa0,0xa8,0x70,0x20,0x98,0x54,0x54, + 0x2c,0xd0,0xa8,0xa8,0x64,0x74,0x88,0x8c, + 0x50,0x20,0x50,0x48,0x30,0x80,0x40,0x20, + 0x20,0x20,0x40,0x40,0x80,0x80,0x80,0x80, + 0x40,0x40,0x20,0x80,0x40,0x40,0x20,0x20, + 0x20,0x20,0x40,0x40,0x80,0x20,0xa8,0x70, + 0xa8,0x20,0x20,0x20,0xf8,0x20,0x20,0x80, + 0x40,0x40,0xc0,0xf8,0x80,0x80,0x80,0x80, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08, + 0x70,0x88,0x88,0xc8,0xa8,0x98,0x88,0x70, + 0xe0,0x40,0x40,0x40,0x40,0x40,0xc0,0x40, + 0xf8,0x80,0x40,0x20,0x10,0x08,0x88,0x70, + 0x70,0x88,0x08,0x08,0x70,0x08,0x88,0x70, + 0x10,0x10,0x10,0xf8,0x90,0x50,0x30,0x10, + 0x70,0x88,0x08,0x08,0xf0,0x80,0x80,0xf8, + 0x70,0x88,0x88,0x88,0xf0,0x80,0x88,0x70, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0xf8, + 0x70,0x88,0x88,0x88,0x70,0x88,0x88,0x70, + 0x70,0x88,0x08,0x78,0x88,0x88,0x88,0x70, + 0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x40, + 0x40,0xc0,0x00,0x00,0x40,0x40,0x08,0x10, + 0x20,0x40,0x80,0x40,0x20,0x10,0x08,0xf8, + 0x00,0xf8,0x80,0x40,0x20,0x10,0x08,0x10, + 0x20,0x40,0x80,0x20,0x00,0x20,0x20,0x10, + 0x88,0x88,0x70,0x38,0x40,0x98,0xa8,0xa8, + 0x98,0x48,0x30,0x88,0x88,0xf8,0x88,0x50, + 0x50,0x20,0x20,0xf0,0x88,0x88,0x88,0xf0, + 0x88,0x88,0xf0,0x70,0x88,0x80,0x80,0x80, + 0x80,0x88,0x70,0xf0,0x88,0x88,0x88,0x88, + 0x88,0x88,0xf0,0xf8,0x80,0x80,0x80,0xf0, + 0x80,0x80,0xf8,0x80,0x80,0x80,0x80,0xf0, + 0x80,0x80,0xf8,0x68,0x98,0x88,0x88,0x98, + 0x80,0x88,0x70,0x88,0x88,0x88,0x88,0xf8, + 0x88,0x88,0x88,0xe0,0x40,0x40,0x40,0x40, + 0x40,0x40,0xe0,0x70,0x88,0x88,0x08,0x08, + 0x08,0x08,0x08,0x88,0x88,0x90,0xa0,0xc0, + 0xa0,0x90,0x88,0xf8,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x88,0x88,0xa8,0xa8,0xd8, + 0xd8,0x88,0x88,0x88,0x98,0x98,0xa8,0xa8, + 0xc8,0xc8,0x88,0x70,0x88,0x88,0x88,0x88, + 0x88,0x88,0x70,0x80,0x80,0x80,0x80,0xf0, + 0x88,0x88,0xf0,0x08,0x10,0x70,0xa8,0x88, + 0x88,0x88,0x88,0x88,0x70,0x88,0x90,0x90, + 0xa0,0xf0,0x88,0x88,0xf0,0x70,0x88,0x88, + 0x08,0x70,0x80,0x88,0x70,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0xf8,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x88,0x20,0x20,0x50, + 0x50,0x50,0x88,0x88,0x88,0x50,0x50,0xf8, + 0xa8,0xa8,0xa8,0x88,0x88,0x88,0x88,0x50, + 0x20,0x20,0x50,0x88,0x88,0x20,0x20,0x20, + 0x20,0x50,0x50,0x88,0x88,0xf8,0x80,0x40, + 0x40,0x20,0x10,0x08,0xf8,0xe0,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xe0,0x08,0x08, + 0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80, + 0xe0,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0xe0,0x88,0x50,0x20,0xfe,0x20,0x40,0x80, + 0x80,0x68,0x98,0x88,0x78,0x08,0x70,0xb0, + 0xc8,0x88,0x88,0xc8,0xb0,0x80,0x80,0x70, + 0x88,0x80,0x80,0x88,0x70,0x68,0x98,0x88, + 0x88,0x98,0x68,0x08,0x08,0x70,0x88,0x80, + 0xf8,0x88,0x70,0x40,0x40,0x40,0x40,0x40, + 0xf0,0x40,0x38,0xf0,0x08,0x68,0x98,0x88, + 0x88,0x98,0x68,0x88,0x88,0x88,0x88,0xc8, + 0xb0,0x80,0x80,0x20,0x20,0x20,0x20,0x20, + 0xe0,0x00,0x20,0x60,0x90,0x10,0x10,0x10, + 0x10,0x10,0x70,0x00,0x10,0x88,0x90,0xa0, + 0xc0,0xa0,0x90,0x80,0x80,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0xa8,0xa8,0xa8, + 0xa8,0xa8,0xd0,0x88,0x88,0x88,0x88,0xc8, + 0xb0,0x70,0x88,0x88,0x88,0x88,0x70,0x80, + 0x80,0xb0,0xc8,0x88,0x88,0xc8,0xb0,0x08, + 0x08,0x68,0x98,0x88,0x88,0x98,0x68,0x80, + 0x80,0x80,0x80,0xc8,0xb0,0x70,0x88,0x10, + 0x60,0x88,0x70,0x30,0x40,0x40,0x40,0x40, + 0xf0,0x40,0x68,0x98,0x88,0x88,0x88,0x88, + 0x20,0x20,0x50,0x50,0x88,0x88,0x50,0xa8, + 0xa8,0xa8,0x88,0x88,0x88,0x88,0x50,0x20, + 0x50,0x88,0xf0,0x08,0x68,0x98,0x88,0x88, + 0x88,0x88,0xf8,0x80,0x40,0x20,0x10,0xf8, + 0x18,0x20,0x20,0x20,0x20,0xc0,0x20,0x20, + 0x20,0x18,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0xc0,0x20,0x20,0x20, + 0x20,0x18,0x20,0x20,0x20,0xc0,0x98,0xb4, + 0x64,0x80,0x80,0x80,0x80,0x80,0x00,0x80, + 0x80,0x20,0x20,0x70,0x88,0x80,0x88,0x70, + 0x20,0x20,0xb0,0x48,0x40,0xf0,0x40,0x40, + 0x48,0x30,0x90,0x60,0x90,0x90,0x60,0x90, + 0x20,0x70,0x20,0x70,0x20,0x50,0x88,0x88, + 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80, + 0x80,0x80,0x70,0x88,0x10,0x28,0x48,0x90, + 0xa0,0x40,0x88,0x70,0xa0,0x78,0x84,0xb4, + 0xa4,0xb4,0x84,0x78,0xf0,0x90,0x70,0x10, + 0x60,0x14,0x28,0x50,0xa0,0x50,0x28,0x14, + 0x08,0xf8,0xf0,0x78,0x84,0xac,0xb4,0xb4, + 0x84,0x78,0xe0,0x60,0x90,0x60,0xf8,0x00, + 0x20,0x20,0xf8,0x20,0x20,0xe0,0x40,0x20, + 0xa0,0x40,0xc0,0x20,0x40,0x20,0xc0,0x80, + 0x40,0x80,0xe8,0x90,0x90,0x90,0x90,0x28, + 0x28,0x28,0x28,0x68,0xa8,0xa8,0xa8,0x7c, + 0x80,0x80,0xc0,0x40,0xe0,0x40,0x40,0xc0, + 0x40,0xf0,0x60,0x90,0x90,0x60,0xa0,0x50, + 0x28,0x14,0x28,0x50,0xa0,0x08,0x38,0xa8, + 0x58,0x28,0xf0,0x48,0x40,0xc0,0x40,0x38, + 0x10,0x88,0x68,0x30,0xf0,0x48,0x40,0xc0, + 0x40,0x08,0x38,0xa8,0x58,0x28,0xd0,0x28, + 0x40,0x20,0xc0,0x70,0x88,0x88,0x40,0x20, + 0x20,0x00,0x20,0x88,0x88,0xf8,0x88,0x50, + 0x50,0x20,0x00,0x20,0x40,0x88,0x88,0xf8, + 0x50,0x50,0x20,0x20,0x00,0x20,0x10,0x88, + 0x88,0xf8,0x50,0x50,0x20,0x20,0x00,0x50, + 0x20,0x88,0x88,0xf8,0x50,0x50,0x20,0x20, + 0x00,0xb0,0x68,0x88,0x88,0xf8,0x50,0x50, + 0x20,0x20,0x00,0x50,0x88,0x88,0xf8,0x50, + 0x50,0x20,0x20,0x20,0x50,0x20,0x9c,0x90, + 0xf0,0x50,0x5c,0x30,0x30,0x1c,0x60,0x20, + 0x70,0x88,0x80,0x80,0x80,0x80,0x88,0x70, + 0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00, + 0x20,0x40,0xf8,0x80,0x80,0xf0,0x80,0x80, + 0xf8,0x00,0x20,0x10,0xf8,0x80,0x80,0xf0, + 0x80,0x80,0xf8,0x00,0x50,0x20,0xf8,0x80, + 0x80,0xf0,0x80,0x80,0xf8,0x00,0x50,0xe0, + 0x40,0x40,0x40,0x40,0x40,0xe0,0x00,0x40, + 0x80,0xe0,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x00,0x40,0x20,0xe0,0x40,0x40,0x40,0x40, + 0x40,0xe0,0x00,0xa0,0x40,0xe0,0x40,0x40, + 0x40,0x40,0x40,0xe0,0x00,0xa0,0x78,0x44, + 0x44,0xf4,0x44,0x44,0x44,0x78,0x88,0x98, + 0x98,0xa8,0xc8,0xc8,0x88,0x00,0xb0,0x68, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, + 0x20,0x40,0x70,0x88,0x88,0x88,0x88,0x88, + 0x70,0x00,0x20,0x10,0x70,0x88,0x88,0x88, + 0x88,0x88,0x70,0x00,0x50,0x20,0x70,0x88, + 0x88,0x88,0x88,0x88,0x70,0x00,0xb0,0x68, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, + 0x50,0x88,0x50,0x20,0x50,0x88,0xb8,0x44, + 0x64,0x54,0x4c,0x44,0x3a,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x00,0x20,0x40,0x70, + 0x88,0x88,0x88,0x88,0x88,0x88,0x00,0x20, + 0x10,0x70,0x88,0x88,0x88,0x88,0x88,0x88, + 0x00,0x50,0x20,0x70,0x88,0x88,0x88,0x88, + 0x88,0x88,0x00,0x50,0x20,0x20,0x20,0x50, + 0x50,0x88,0x88,0x00,0x20,0x10,0x80,0x80, + 0xf0,0x88,0x88,0x88,0xf0,0x80,0x80,0xb0, + 0x88,0x88,0x88,0x90,0xa0,0x90,0x60,0x78, + 0x88,0x78,0x08,0x70,0x00,0x20,0x40,0x78, + 0x88,0x78,0x08,0x70,0x00,0x20,0x10,0x78, + 0x88,0x78,0x08,0x70,0x00,0x50,0x20,0x78, + 0x88,0x78,0x08,0x70,0x00,0xb0,0x68,0x78, + 0x88,0x78,0x08,0x70,0x00,0x50,0x78,0x88, + 0x78,0x08,0x70,0x00,0x20,0x50,0x20,0x6c, + 0x90,0x7c,0x12,0x6c,0x60,0x20,0x70,0x88, + 0x80,0x80,0x88,0x70,0x78,0x80,0xf8,0x88, + 0x70,0x00,0x20,0x40,0x78,0x80,0xf8,0x88, + 0x70,0x00,0x20,0x10,0x78,0x80,0xf8,0x88, + 0x70,0x00,0x50,0x20,0x78,0x80,0xf8,0x88, + 0x70,0x00,0x50,0x20,0x20,0x20,0x20,0xe0, + 0x00,0x40,0x80,0x20,0x20,0x20,0x20,0xe0, + 0x00,0x40,0x20,0x20,0x20,0x20,0x20,0xe0, + 0x00,0xa0,0x40,0x20,0x20,0x20,0x20,0xe0, + 0x00,0xa0,0x70,0x88,0x88,0x88,0x78,0x08, + 0x90,0x60,0xd0,0x88,0x88,0x88,0xc8,0xb0, + 0x00,0xb0,0x68,0x70,0x88,0x88,0x88,0x70, + 0x00,0x20,0x40,0x70,0x88,0x88,0x88,0x70, + 0x00,0x20,0x10,0x70,0x88,0x88,0x88,0x70, + 0x00,0x50,0x20,0x70,0x88,0x88,0x88,0x70, + 0x00,0xb0,0x68,0x70,0x88,0x88,0x88,0x70, + 0x00,0x50,0x20,0x00,0xf8,0x00,0x20,0xb8, + 0x64,0x54,0x4c,0x3a,0x68,0x98,0x88,0x88, + 0x88,0x00,0x20,0x40,0x68,0x98,0x88,0x88, + 0x88,0x00,0x20,0x10,0x68,0x98,0x88,0x88, + 0x88,0x00,0x50,0x20,0x68,0x98,0x88,0x88, + 0x88,0x00,0x50,0xf0,0x08,0x68,0x98,0x88, + 0x88,0x88,0x00,0x20,0x10,0x80,0x80,0xb0, + 0xc8,0x88,0x88,0xc8,0xb0,0x80,0x80,0xf0, + 0x08,0x68,0x98,0x88,0x88,0x88,0x00,0xd8, +}; + +BMF_FontData BMF_font_scr12 = { + 0, -2, + 7, 10, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 16, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 7, -1}, + {1, 8, -3, 0, 7, 0}, + {3, 4, -2, -5, 7, 8}, + {7, 8, 0, 0, 7, 12}, + {5, 9, -1, 1, 7, 20}, + {6, 8, 0, 0, 7, 29}, + {6, 8, 0, 0, 7, 37}, + {3, 4, -2, -5, 7, 45}, + {3, 10, -2, 2, 7, 49}, + {3, 10, -2, 2, 7, 59}, + {5, 5, -1, -3, 7, 69}, + {5, 5, -1, -1, 7, 74}, + {2, 4, -2, 2, 7, 79}, + {5, 1, -1, -3, 7, 83}, + {1, 2, -3, 0, 7, 84}, + {5, 10, -1, 1, 7, 86}, + {5, 8, -1, 0, 7, 96}, + {3, 8, -2, 0, 7, 104}, + {5, 8, -1, 0, 7, 112}, + {5, 8, -1, 0, 7, 120}, + {5, 8, -1, 0, 7, 128}, + {5, 8, -1, 0, 7, 136}, + {5, 8, -1, 0, 7, 144}, + {5, 8, -1, 0, 7, 152}, + {5, 8, -1, 0, 7, 160}, + {5, 8, -1, 0, 7, 168}, + {1, 6, -3, 0, 7, 176}, + {2, 8, -2, 2, 7, 182}, + {5, 9, -1, 1, 7, 190}, + {5, 3, -1, -2, 7, 199}, + {5, 9, -1, 1, 7, 202}, + {5, 8, -1, 0, 7, 211}, + {5, 8, -1, 0, 7, 219}, + {5, 8, -1, 0, 7, 227}, + {5, 8, -1, 0, 7, 235}, + {5, 8, -1, 0, 7, 243}, + {5, 8, -1, 0, 7, 251}, + {5, 8, -1, 0, 7, 259}, + {5, 8, -1, 0, 7, 267}, + {5, 8, -1, 0, 7, 275}, + {5, 8, -1, 0, 7, 283}, + {3, 8, -2, 0, 7, 291}, + {5, 8, -1, 0, 7, 299}, + {5, 8, -1, 0, 7, 307}, + {5, 8, -1, 0, 7, 315}, + {5, 8, -1, 0, 7, 323}, + {5, 8, -1, 0, 7, 331}, + {5, 8, -1, 0, 7, 339}, + {5, 8, -1, 0, 7, 347}, + {5, 10, -1, 2, 7, 355}, + {5, 8, -1, 0, 7, 365}, + {5, 8, -1, 0, 7, 373}, + {5, 8, -1, 0, 7, 381}, + {5, 8, -1, 0, 7, 389}, + {5, 8, -1, 0, 7, 397}, + {5, 8, -1, 0, 7, 405}, + {5, 8, -1, 0, 7, 413}, + {5, 8, -1, 0, 7, 421}, + {5, 8, -1, 0, 7, 429}, + {3, 9, -2, 1, 7, 437}, + {5, 10, -1, 1, 7, 446}, + {3, 9, -2, 1, 7, 456}, + {5, 3, -1, -5, 7, 465}, + {7, 1, 0, 1, 7, 468}, + {3, 4, -2, -5, 7, 469}, + {5, 6, -1, 0, 7, 473}, + {5, 8, -1, 0, 7, 479}, + {5, 6, -1, 0, 7, 487}, + {5, 8, -1, 0, 7, 493}, + {5, 6, -1, 0, 7, 501}, + {5, 8, -1, 0, 7, 507}, + {5, 8, -1, 2, 7, 515}, + {5, 8, -1, 0, 7, 523}, + {3, 8, -2, 0, 7, 531}, + {4, 10, -1, 2, 7, 539}, + {5, 8, -1, 0, 7, 549}, + {3, 8, -2, 0, 7, 557}, + {5, 6, -1, 0, 7, 565}, + {5, 6, -1, 0, 7, 571}, + {5, 6, -1, 0, 7, 577}, + {5, 8, -1, 2, 7, 583}, + {5, 8, -1, 2, 7, 591}, + {5, 6, -1, 0, 7, 599}, + {5, 6, -1, 0, 7, 605}, + {4, 7, -1, 0, 7, 611}, + {5, 6, -1, 0, 7, 618}, + {5, 6, -1, 0, 7, 624}, + {5, 6, -1, 0, 7, 630}, + {5, 6, -1, 0, 7, 636}, + {5, 8, -1, 2, 7, 642}, + {5, 6, -1, 0, 7, 650}, + {5, 10, -1, 2, 7, 656}, + {1, 10, -3, 1, 7, 666}, + {5, 10, -1, 2, 7, 676}, + {6, 3, 0, -2, 7, 686}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 8, -3, 2, 7, 689}, + {5, 9, -1, 0, 7, 697}, + {5, 8, -1, 0, 7, 706}, + {4, 6, -1, -2, 7, 714}, + {5, 8, -1, 0, 7, 720}, + {1, 10, -3, 1, 7, 728}, + {5, 10, -1, 1, 7, 738}, + {3, 1, -2, -7, 7, 748}, + {6, 7, 0, 0, 7, 749}, + {4, 5, -1, -4, 7, 756}, + {6, 7, 0, 0, 7, 761}, + {5, 2, -1, -3, 7, 768}, + {4, 1, -1, -3, 7, 770}, + {6, 7, 0, 0, 7, 771}, + {3, 1, -2, -7, 7, 778}, + {4, 3, -1, -4, 7, 779}, + {5, 7, -1, 0, 7, 782}, + {3, 5, -2, -4, 7, 789}, + {3, 5, -2, -4, 7, 794}, + {2, 2, -2, -7, 7, 799}, + {5, 6, -1, 1, 7, 801}, + {6, 9, 0, 1, 7, 807}, + {1, 2, -3, -3, 7, 816}, + {2, 2, -2, 2, 7, 818}, + {3, 5, -2, -4, 7, 820}, + {4, 5, -1, -4, 7, 825}, + {6, 7, 0, 0, 7, 830}, + {5, 10, -1, 1, 7, 837}, + {5, 10, -1, 1, 7, 847}, + {5, 10, -1, 1, 7, 857}, + {5, 8, -1, 2, 7, 867}, + {5, 10, -1, 0, 7, 875}, + {5, 10, -1, 0, 7, 885}, + {5, 10, -1, 0, 7, 895}, + {5, 10, -1, 0, 7, 905}, + {5, 9, -1, 0, 7, 915}, + {5, 10, -1, 0, 7, 924}, + {6, 8, 0, 0, 7, 934}, + {5, 10, -1, 2, 7, 942}, + {5, 10, -1, 0, 7, 952}, + {5, 10, -1, 0, 7, 962}, + {5, 10, -1, 0, 7, 972}, + {5, 9, -1, 0, 7, 982}, + {3, 10, -2, 0, 7, 991}, + {3, 10, -2, 0, 7, 1001}, + {3, 10, -2, 0, 7, 1011}, + {3, 9, -2, 0, 7, 1021}, + {6, 8, 0, 0, 7, 1030}, + {5, 10, -1, 0, 7, 1038}, + {5, 10, -1, 0, 7, 1048}, + {5, 10, -1, 0, 7, 1058}, + {5, 10, -1, 0, 7, 1068}, + {5, 10, -1, 0, 7, 1078}, + {5, 9, -1, 0, 7, 1088}, + {5, 5, -1, -1, 7, 1097}, + {7, 7, 0, 0, 7, 1102}, + {5, 10, -1, 0, 7, 1109}, + {5, 10, -1, 0, 7, 1119}, + {5, 10, -1, 0, 7, 1129}, + {5, 9, -1, 0, 7, 1139}, + {5, 10, -1, 0, 7, 1148}, + {5, 9, -1, 0, 7, 1158}, + {5, 8, -1, 0, 7, 1167}, + {5, 8, -1, 0, 7, 1175}, + {5, 8, -1, 0, 7, 1183}, + {5, 8, -1, 0, 7, 1191}, + {5, 8, -1, 0, 7, 1199}, + {5, 7, -1, 0, 7, 1207}, + {5, 9, -1, 0, 7, 1214}, + {7, 5, 0, 0, 7, 1223}, + {5, 8, -1, 2, 7, 1228}, + {5, 8, -1, 0, 7, 1236}, + {5, 8, -1, 0, 7, 1244}, + {5, 8, -1, 0, 7, 1252}, + {5, 7, -1, 0, 7, 1260}, + {3, 8, -2, 0, 7, 1267}, + {3, 8, -2, 0, 7, 1275}, + {3, 8, -2, 0, 7, 1283}, + {3, 7, -2, 0, 7, 1291}, + {5, 9, -1, 0, 7, 1298}, + {5, 8, -1, 0, 7, 1307}, + {5, 8, -1, 0, 7, 1315}, + {5, 8, -1, 0, 7, 1323}, + {5, 8, -1, 0, 7, 1331}, + {5, 8, -1, 0, 7, 1339}, + {5, 7, -1, 0, 7, 1347}, + {5, 5, -1, -1, 7, 1354}, + {7, 5, 0, 0, 7, 1359}, + {5, 8, -1, 0, 7, 1364}, + {5, 8, -1, 0, 7, 1372}, + {5, 8, -1, 0, 7, 1380}, + {5, 7, -1, 0, 7, 1388}, + {5, 10, -1, 2, 7, 1395}, + {5, 10, -1, 2, 7, 1405}, + {5, 9, -1, 2, 7, 1415}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_scr14.cpp b/intern/bmfont/intern/BMF_font_scr14.cpp new file mode 100644 index 00000000000..6a3ee9dd710 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_scr14.cpp @@ -0,0 +1,513 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_SCR14 + +static unsigned char bitmap_data[]= { + 0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80, + 0x80,0xa0,0xa0,0xa0,0xa0,0x50,0x50,0xfc, + 0x28,0x28,0x28,0x7e,0x14,0x14,0x20,0x70, + 0xa8,0x28,0x30,0x60,0xa0,0xa8,0x70,0x20, + 0x98,0x54,0x54,0x2c,0x10,0x68,0x54,0x54, + 0x32,0x74,0x88,0x8c,0x90,0x60,0x20,0x50, + 0x48,0x30,0x80,0x40,0x20,0x20,0x20,0x40, + 0x40,0x80,0x80,0x80,0x80,0x80,0x40,0x40, + 0x20,0x80,0x40,0x40,0x20,0x20,0x20,0x20, + 0x20,0x40,0x40,0x80,0x20,0xa8,0x70,0x70, + 0xa8,0x20,0x20,0x20,0xf8,0x20,0x20,0x80, + 0x40,0x40,0xc0,0xf8,0x80,0x80,0x80,0x80, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08, + 0x70,0x88,0x88,0xc8,0xa8,0x98,0x88,0x88, + 0x70,0xe0,0x40,0x40,0x40,0x40,0x40,0x40, + 0xc0,0x40,0xf8,0x80,0x40,0x20,0x10,0x08, + 0x88,0x88,0x70,0x70,0x88,0x08,0x08,0x70, + 0x08,0x08,0x88,0x70,0x10,0x10,0x10,0xf8, + 0x90,0x50,0x50,0x30,0x10,0x70,0x88,0x08, + 0x08,0x08,0xf0,0x80,0x80,0xf8,0x70,0x88, + 0x88,0x88,0x88,0xf0,0x80,0x88,0x70,0x40, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0xf8, + 0x70,0x88,0x88,0x88,0x70,0x88,0x88,0x88, + 0x70,0x70,0x88,0x08,0x08,0x78,0x88,0x88, + 0x88,0x70,0x80,0x80,0x00,0x00,0x80,0x80, + 0x80,0x40,0x40,0xc0,0x00,0x00,0x40,0x40, + 0x08,0x10,0x20,0x40,0x80,0x40,0x20,0x10, + 0x08,0xf8,0x00,0xf8,0x80,0x40,0x20,0x10, + 0x08,0x10,0x20,0x40,0x80,0x20,0x20,0x00, + 0x20,0x20,0x10,0x88,0x88,0x70,0x38,0x40, + 0x98,0xa8,0xa8,0x98,0x88,0x48,0x30,0x88, + 0x88,0xf8,0x88,0x50,0x50,0x50,0x20,0x20, + 0xf0,0x88,0x88,0x88,0xf0,0x88,0x88,0x88, + 0xf0,0x70,0x88,0x80,0x80,0x80,0x80,0x80, + 0x88,0x70,0xf0,0x88,0x88,0x88,0x88,0x88, + 0x88,0x88,0xf0,0xf8,0x80,0x80,0x80,0xf0, + 0x80,0x80,0x80,0xf8,0x80,0x80,0x80,0x80, + 0xf0,0x80,0x80,0x80,0xf8,0x68,0x98,0x88, + 0x88,0x98,0x80,0x80,0x88,0x70,0x88,0x88, + 0x88,0x88,0xf8,0x88,0x88,0x88,0x88,0xe0, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x70,0x88,0x88,0x08,0x08,0x08,0x08,0x08, + 0x08,0x88,0x88,0x90,0xa0,0xc0,0xa0,0x90, + 0x88,0x88,0xf8,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x88,0x88,0x88,0xa8,0xa8, + 0xd8,0xd8,0x88,0x88,0x88,0x98,0x98,0xa8, + 0xa8,0xc8,0xc8,0x88,0x88,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x88,0x70,0x80,0x80, + 0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x08, + 0x10,0x70,0xa8,0x88,0x88,0x88,0x88,0x88, + 0x88,0x70,0x88,0x88,0x90,0xa0,0xf0,0x88, + 0x88,0x88,0xf0,0x70,0x88,0x08,0x08,0x70, + 0x80,0x80,0x88,0x70,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0xf8,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x88,0x88,0x20,0x20, + 0x50,0x50,0x50,0x88,0x88,0x88,0x88,0x50, + 0x50,0xf8,0xa8,0xa8,0x88,0x88,0x88,0x88, + 0x88,0x88,0x50,0x50,0x20,0x50,0x50,0x88, + 0x88,0x20,0x20,0x20,0x20,0x20,0x50,0x50, + 0x88,0x88,0xf8,0x80,0x40,0x40,0x20,0x10, + 0x10,0x08,0xf8,0xf0,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xf0,0x08,0x08, + 0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80, + 0xf0,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0xf0,0x88,0x50,0x20,0xfe,0x20, + 0x40,0x80,0x80,0x68,0x98,0x88,0x78,0x08, + 0x88,0x70,0xb0,0xc8,0x88,0x88,0x88,0xc8, + 0xb0,0x80,0x80,0x70,0x88,0x80,0x80,0x80, + 0x88,0x70,0x68,0x98,0x88,0x88,0x88,0x98, + 0x68,0x08,0x08,0x70,0x88,0x80,0xf8,0x88, + 0x88,0x70,0x40,0x40,0x40,0x40,0x40,0x40, + 0xf0,0x40,0x38,0x70,0x88,0x08,0x68,0x98, + 0x88,0x88,0x88,0x98,0x68,0x88,0x88,0x88, + 0x88,0x88,0xc8,0xb0,0x80,0x80,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0x00,0x20,0x60, + 0x90,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x70,0x00,0x10,0x88,0x88,0x90,0xe0,0xa0, + 0x90,0x88,0x80,0x80,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0xa8,0xa8,0xa8, + 0xa8,0xa8,0xa8,0xd0,0x88,0x88,0x88,0x88, + 0x88,0xc8,0xb0,0x70,0x88,0x88,0x88,0x88, + 0x88,0x70,0x80,0x80,0x80,0xb0,0xc8,0x88, + 0x88,0x88,0xc8,0xb0,0x08,0x08,0x08,0x68, + 0x98,0x88,0x88,0x88,0x98,0x68,0x80,0x80, + 0x80,0x80,0x80,0xc8,0xb0,0x70,0x88,0x08, + 0x70,0x80,0x88,0x70,0x30,0x40,0x40,0x40, + 0x40,0x40,0xf0,0x40,0x40,0x68,0x98,0x88, + 0x88,0x88,0x88,0x88,0x20,0x20,0x50,0x50, + 0x88,0x88,0x88,0x50,0xa8,0xa8,0xa8,0xa8, + 0x88,0x88,0x88,0x88,0x50,0x20,0x50,0x88, + 0x88,0x70,0x88,0x08,0x68,0x98,0x88,0x88, + 0x88,0x88,0x88,0xf8,0x80,0x40,0x20,0x10, + 0x08,0xf8,0x18,0x20,0x20,0x20,0x20,0x20, + 0xc0,0x20,0x20,0x20,0x20,0x18,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0xc0,0x20,0x20,0x20,0x20,0x20, + 0x18,0x20,0x20,0x20,0x20,0xc0,0x98,0xb4, + 0x64,0x80,0x80,0x80,0x80,0x80,0x80,0x00, + 0x80,0x80,0x20,0x20,0x70,0x88,0x80,0x80, + 0x88,0x70,0x20,0x20,0xb0,0x48,0x40,0x40, + 0xf0,0x40,0x40,0x48,0x30,0x88,0x70,0x88, + 0x88,0x70,0x88,0x70,0x20,0xf8,0x20,0xf8, + 0x50,0x50,0x88,0x88,0x80,0x80,0x80,0x80, + 0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x80, + 0x70,0x88,0x10,0x28,0x48,0x88,0x90,0xa0, + 0x40,0x88,0x70,0xd8,0x38,0x44,0x92,0xaa, + 0xa2,0xaa,0x92,0x44,0x38,0xf8,0x00,0x68, + 0x90,0x70,0x10,0x60,0x12,0x24,0x48,0x90, + 0x48,0x24,0x12,0x08,0x08,0xf8,0xf0,0x38, + 0x44,0xaa,0xaa,0xb2,0xaa,0xb2,0x44,0x38, + 0xe0,0x60,0x90,0x90,0x60,0xf8,0x00,0x20, + 0x20,0xf8,0x20,0x20,0xe0,0x40,0x20,0xa0, + 0x40,0xc0,0x20,0x40,0x20,0xc0,0x80,0x40, + 0x80,0x80,0xb4,0xc8,0x88,0x88,0x88,0x88, + 0x28,0x28,0x28,0x28,0x28,0x68,0xa8,0xa8, + 0xa8,0x7c,0x80,0x80,0xc0,0x20,0x40,0xe0, + 0x40,0x40,0xc0,0x40,0xf8,0x00,0x70,0x88, + 0x88,0x88,0x70,0x90,0x48,0x24,0x12,0x24, + 0x48,0x90,0x04,0x9e,0x54,0x2c,0x14,0xe8, + 0x44,0x40,0xc0,0x40,0x1c,0x08,0x84,0x54, + 0x28,0x10,0xe8,0x44,0x40,0xc0,0x40,0x04, + 0x9e,0x54,0x2c,0xd4,0x28,0x44,0x20,0xc0, + 0x70,0x88,0x80,0x40,0x20,0x20,0x00,0x00, + 0x20,0x20,0x88,0x88,0xf8,0x88,0x50,0x50, + 0x20,0x20,0x00,0x20,0x40,0x88,0x88,0xf8, + 0x88,0x50,0x50,0x20,0x20,0x00,0x20,0x10, + 0x88,0x88,0xf8,0x88,0x50,0x50,0x20,0x20, + 0x00,0x50,0x20,0x88,0x88,0xf8,0x88,0x50, + 0x50,0x20,0x20,0x00,0xb0,0x68,0x88,0x88, + 0xf8,0x88,0x50,0x50,0x20,0x20,0x00,0xd8, + 0x88,0x88,0xf8,0x88,0x50,0x50,0x20,0x20, + 0x20,0x50,0x20,0x9c,0x90,0xf0,0x90,0x5c, + 0x50,0x30,0x30,0x1c,0x60,0x10,0x20,0x70, + 0x88,0x80,0x80,0x80,0x80,0x80,0x88,0x70, + 0xf8,0x80,0x80,0x80,0xf0,0x80,0x80,0xf8, + 0x00,0x20,0x40,0xf8,0x80,0x80,0x80,0xf0, + 0x80,0x80,0xf8,0x00,0x20,0x10,0xf8,0x80, + 0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x50, + 0x20,0xf8,0x80,0x80,0x80,0xf0,0x80,0x80, + 0xf8,0x00,0xd8,0xe0,0x40,0x40,0x40,0x40, + 0x40,0x40,0xe0,0x00,0x40,0x80,0xe0,0x40, + 0x40,0x40,0x40,0x40,0x40,0xe0,0x00,0x40, + 0x20,0xe0,0x40,0x40,0x40,0x40,0x40,0x40, + 0xe0,0x00,0xa0,0x40,0x70,0x20,0x20,0x20, + 0x20,0x20,0x20,0x70,0x00,0xd8,0x78,0x44, + 0x44,0x44,0xf4,0x44,0x44,0x44,0x78,0x88, + 0x98,0x98,0xa8,0xa8,0xc8,0xc8,0x88,0x00, + 0xb0,0x68,0x70,0x88,0x88,0x88,0x88,0x88, + 0x88,0x70,0x00,0x20,0x40,0x70,0x88,0x88, + 0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x10, + 0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70, + 0x00,0x50,0x20,0x70,0x88,0x88,0x88,0x88, + 0x88,0x88,0x70,0x00,0xb0,0x68,0x70,0x88, + 0x88,0x88,0x88,0x88,0x88,0x70,0x00,0xd8, + 0x88,0x50,0x20,0x50,0x88,0xb8,0x44,0x64, + 0x64,0x54,0x4c,0x4c,0x44,0x3a,0x70,0x88, + 0x88,0x88,0x88,0x88,0x88,0x88,0x00,0x20, + 0x40,0x70,0x88,0x88,0x88,0x88,0x88,0x88, + 0x88,0x00,0x20,0x10,0x70,0x88,0x88,0x88, + 0x88,0x88,0x88,0x88,0x00,0x50,0x20,0x70, + 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x00, + 0xd8,0x20,0x20,0x20,0x20,0x50,0x50,0x88, + 0x88,0x00,0x20,0x10,0xe0,0x40,0x78,0x44, + 0x44,0x44,0x78,0x40,0xe0,0xb0,0x88,0x88, + 0x88,0x90,0xa0,0x90,0x90,0x60,0x68,0x98, + 0x88,0x78,0x08,0x88,0x70,0x00,0x20,0x40, + 0x68,0x98,0x88,0x78,0x08,0x88,0x70,0x00, + 0x20,0x10,0x68,0x98,0x88,0x78,0x08,0x88, + 0x70,0x00,0x50,0x20,0x68,0x98,0x88,0x78, + 0x08,0x88,0x70,0x00,0xb0,0x68,0x68,0x98, + 0x88,0x78,0x08,0x88,0x70,0x00,0xd8,0x68, + 0x98,0x88,0x78,0x08,0x88,0x70,0x00,0x20, + 0x50,0x20,0x6c,0x92,0x90,0x7e,0x12,0x92, + 0x6c,0x60,0x10,0x20,0x70,0x88,0x80,0x80, + 0x80,0x88,0x70,0x70,0x88,0x80,0xf8,0x88, + 0x88,0x70,0x00,0x20,0x40,0x70,0x88,0x80, + 0xf8,0x88,0x88,0x70,0x00,0x20,0x10,0x70, + 0x88,0x80,0xf8,0x88,0x88,0x70,0x00,0x50, + 0x20,0x70,0x88,0x80,0xf8,0x88,0x88,0x70, + 0x00,0xd8,0x20,0x20,0x20,0x20,0x20,0x20, + 0xe0,0x00,0x20,0x40,0x20,0x20,0x20,0x20, + 0x20,0x20,0xe0,0x00,0x20,0x10,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0x00,0xa0,0x40, + 0x20,0x20,0x20,0x20,0x20,0x20,0xe0,0x00, + 0xd8,0x70,0x88,0x88,0x88,0x88,0x88,0x78, + 0x10,0xd0,0x20,0xd0,0x88,0x88,0x88,0x88, + 0x88,0xc8,0xb0,0x00,0xb0,0x68,0x70,0x88, + 0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x40, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, + 0x20,0x10,0x70,0x88,0x88,0x88,0x88,0x88, + 0x70,0x00,0x50,0x20,0x70,0x88,0x88,0x88, + 0x88,0x88,0x70,0x00,0xb0,0x68,0x70,0x88, + 0x88,0x88,0x88,0x88,0x70,0x00,0xd8,0x10, + 0x10,0x00,0xfe,0x00,0x10,0x10,0xb8,0x44, + 0x64,0x54,0x4c,0x44,0x3a,0x68,0x98,0x88, + 0x88,0x88,0x88,0x88,0x00,0x20,0x40,0x68, + 0x98,0x88,0x88,0x88,0x88,0x88,0x00,0x20, + 0x10,0x68,0x98,0x88,0x88,0x88,0x88,0x88, + 0x00,0x50,0x20,0x68,0x98,0x88,0x88,0x88, + 0x88,0x88,0x00,0xd8,0x70,0x88,0x08,0x68, + 0x98,0x88,0x88,0x88,0x88,0x88,0x00,0x20, + 0x10,0xe0,0x40,0x58,0x64,0x44,0x44,0x44, + 0x64,0x58,0x40,0xc0,0x70,0x88,0x08,0x68, + 0x98,0x88,0x88,0x88,0x88,0x88,0x00,0xd8, +}; + +BMF_FontData BMF_font_scr14 = { + 0, -3, + 7, 11, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 16, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 7, -1}, + {1, 9, -3, 0, 7, 0}, + {3, 4, -2, -5, 7, 9}, + {7, 9, 0, 0, 7, 13}, + {5, 10, -1, 1, 7, 22}, + {7, 9, 0, 0, 7, 32}, + {6, 9, 0, 0, 7, 41}, + {3, 4, -2, -5, 7, 50}, + {3, 11, -2, 1, 7, 54}, + {3, 11, -2, 1, 7, 65}, + {5, 6, -1, -2, 7, 76}, + {5, 5, -1, -2, 7, 82}, + {2, 4, -2, 2, 7, 87}, + {5, 1, -1, -4, 7, 91}, + {1, 2, -3, 0, 7, 92}, + {5, 10, -1, 0, 7, 94}, + {5, 9, -1, 0, 7, 104}, + {3, 9, -2, 0, 7, 113}, + {5, 9, -1, 0, 7, 122}, + {5, 9, -1, 0, 7, 131}, + {5, 9, -1, 0, 7, 140}, + {5, 9, -1, 0, 7, 149}, + {5, 9, -1, 0, 7, 158}, + {5, 9, -1, 0, 7, 167}, + {5, 9, -1, 0, 7, 176}, + {5, 9, -1, 0, 7, 185}, + {1, 6, -3, 0, 7, 194}, + {2, 8, -2, 1, 7, 200}, + {5, 9, -1, 0, 7, 208}, + {5, 3, -1, -3, 7, 217}, + {5, 9, -1, 0, 7, 220}, + {5, 9, -1, 0, 7, 229}, + {5, 9, -1, 0, 7, 238}, + {5, 9, -1, 0, 7, 247}, + {5, 9, -1, 0, 7, 256}, + {5, 9, -1, 0, 7, 265}, + {5, 9, -1, 0, 7, 274}, + {5, 9, -1, 0, 7, 283}, + {5, 9, -1, 0, 7, 292}, + {5, 9, -1, 0, 7, 301}, + {5, 9, -1, 0, 7, 310}, + {3, 9, -2, 0, 7, 319}, + {5, 9, -1, 0, 7, 328}, + {5, 9, -1, 0, 7, 337}, + {5, 9, -1, 0, 7, 346}, + {5, 9, -1, 0, 7, 355}, + {5, 9, -1, 0, 7, 364}, + {5, 9, -1, 0, 7, 373}, + {5, 9, -1, 0, 7, 382}, + {5, 11, -1, 2, 7, 391}, + {5, 9, -1, 0, 7, 402}, + {5, 9, -1, 0, 7, 411}, + {5, 9, -1, 0, 7, 420}, + {5, 9, -1, 0, 7, 429}, + {5, 9, -1, 0, 7, 438}, + {5, 9, -1, 0, 7, 447}, + {5, 9, -1, 0, 7, 456}, + {5, 9, -1, 0, 7, 465}, + {5, 9, -1, 0, 7, 474}, + {4, 11, -2, 1, 7, 483}, + {5, 10, -1, 0, 7, 494}, + {4, 11, -1, 1, 7, 504}, + {5, 3, -1, -6, 7, 515}, + {7, 1, 0, 2, 7, 518}, + {3, 4, -2, -5, 7, 519}, + {5, 7, -1, 0, 7, 523}, + {5, 9, -1, 0, 7, 530}, + {5, 7, -1, 0, 7, 539}, + {5, 9, -1, 0, 7, 546}, + {5, 7, -1, 0, 7, 555}, + {5, 9, -1, 0, 7, 562}, + {5, 10, -1, 3, 7, 571}, + {5, 9, -1, 0, 7, 581}, + {3, 9, -2, 0, 7, 590}, + {4, 12, -1, 3, 7, 599}, + {5, 9, -1, 0, 7, 611}, + {3, 9, -2, 0, 7, 620}, + {5, 7, -1, 0, 7, 629}, + {5, 7, -1, 0, 7, 636}, + {5, 7, -1, 0, 7, 643}, + {5, 10, -1, 3, 7, 650}, + {5, 10, -1, 3, 7, 660}, + {5, 7, -1, 0, 7, 670}, + {5, 7, -1, 0, 7, 677}, + {4, 9, -1, 0, 7, 684}, + {5, 7, -1, 0, 7, 693}, + {5, 7, -1, 0, 7, 700}, + {5, 7, -1, 0, 7, 707}, + {5, 7, -1, 0, 7, 714}, + {5, 10, -1, 3, 7, 721}, + {5, 7, -1, 0, 7, 731}, + {5, 12, -1, 2, 7, 738}, + {1, 12, -3, 2, 7, 750}, + {5, 12, -1, 2, 7, 762}, + {6, 3, 0, -3, 7, 774}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {1, 9, -3, 2, 7, 777}, + {5, 10, -1, 0, 7, 786}, + {5, 9, -1, 0, 7, 796}, + {5, 6, -1, -3, 7, 805}, + {5, 9, -1, 0, 7, 811}, + {1, 12, -3, 2, 7, 820}, + {5, 11, -1, 2, 7, 832}, + {5, 1, -1, -8, 7, 843}, + {7, 9, 0, 0, 7, 844}, + {5, 7, -1, -2, 7, 853}, + {7, 7, 0, 0, 7, 860}, + {5, 3, -1, -3, 7, 867}, + {4, 1, -1, -4, 7, 870}, + {7, 9, 0, 0, 7, 871}, + {3, 1, -2, -8, 7, 880}, + {4, 4, -1, -4, 7, 881}, + {5, 7, -1, 0, 7, 885}, + {3, 5, -2, -5, 7, 892}, + {3, 5, -2, -5, 7, 897}, + {2, 2, -3, -8, 7, 902}, + {6, 8, -1, 2, 7, 904}, + {6, 10, 0, 1, 7, 912}, + {1, 2, -3, -3, 7, 922}, + {3, 3, -2, 3, 7, 924}, + {3, 5, -2, -5, 7, 927}, + {5, 7, -1, -2, 7, 932}, + {7, 7, 0, 0, 7, 939}, + {7, 10, 0, 0, 7, 946}, + {6, 11, 0, 1, 7, 956}, + {7, 9, 0, -1, 7, 967}, + {5, 10, -1, 3, 7, 976}, + {5, 11, -1, 0, 7, 986}, + {5, 11, -1, 0, 7, 997}, + {5, 11, -1, 0, 7, 1008}, + {5, 11, -1, 0, 7, 1019}, + {5, 10, -1, 0, 7, 1030}, + {5, 11, -1, 0, 7, 1040}, + {6, 9, 0, 0, 7, 1051}, + {5, 12, -1, 3, 7, 1060}, + {5, 11, -1, 0, 7, 1072}, + {5, 11, -1, 0, 7, 1083}, + {5, 11, -1, 0, 7, 1094}, + {5, 10, -1, 0, 7, 1105}, + {3, 11, -2, 0, 7, 1115}, + {3, 11, -2, 0, 7, 1126}, + {3, 11, -2, 0, 7, 1137}, + {5, 10, -1, 0, 7, 1148}, + {6, 9, 0, 0, 7, 1158}, + {5, 11, -1, 0, 7, 1167}, + {5, 11, -1, 0, 7, 1178}, + {5, 11, -1, 0, 7, 1189}, + {5, 11, -1, 0, 7, 1200}, + {5, 11, -1, 0, 7, 1211}, + {5, 10, -1, 0, 7, 1222}, + {5, 5, -1, -1, 7, 1232}, + {7, 9, 0, 0, 7, 1237}, + {5, 11, -1, 0, 7, 1246}, + {5, 11, -1, 0, 7, 1257}, + {5, 11, -1, 0, 7, 1268}, + {5, 10, -1, 0, 7, 1279}, + {5, 11, -1, 0, 7, 1289}, + {6, 9, 0, 0, 7, 1300}, + {5, 9, -1, 0, 7, 1309}, + {5, 10, -1, 0, 7, 1318}, + {5, 10, -1, 0, 7, 1328}, + {5, 10, -1, 0, 7, 1338}, + {5, 10, -1, 0, 7, 1348}, + {5, 9, -1, 0, 7, 1358}, + {5, 11, -1, 0, 7, 1367}, + {7, 7, 0, 0, 7, 1378}, + {5, 10, -1, 3, 7, 1385}, + {5, 10, -1, 0, 7, 1395}, + {5, 10, -1, 0, 7, 1405}, + {5, 10, -1, 0, 7, 1415}, + {5, 9, -1, 0, 7, 1425}, + {3, 10, -2, 0, 7, 1434}, + {4, 10, -2, 0, 7, 1444}, + {3, 10, -2, 0, 7, 1454}, + {5, 9, -2, 0, 7, 1464}, + {5, 11, -1, 0, 7, 1473}, + {5, 10, -1, 0, 7, 1484}, + {5, 10, -1, 0, 7, 1494}, + {5, 10, -1, 0, 7, 1504}, + {5, 10, -1, 0, 7, 1514}, + {5, 10, -1, 0, 7, 1524}, + {5, 9, -1, 0, 7, 1534}, + {7, 7, 0, 0, 7, 1543}, + {7, 7, 0, 0, 7, 1550}, + {5, 10, -1, 0, 7, 1557}, + {5, 10, -1, 0, 7, 1567}, + {5, 10, -1, 0, 7, 1577}, + {5, 9, -1, 0, 7, 1587}, + {5, 13, -1, 3, 7, 1596}, + {6, 11, 0, 2, 7, 1609}, + {5, 12, -1, 3, 7, 1620}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/BMF_font_scr15.cpp b/intern/bmfont/intern/BMF_font_scr15.cpp new file mode 100644 index 00000000000..c130fadbf52 --- /dev/null +++ b/intern/bmfont/intern/BMF_font_scr15.cpp @@ -0,0 +1,528 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BMF_FontData.h" +#include "BMF_Settings.h" + +#if BMF_INCLUDE_SCR15 + +static unsigned char bitmap_data[]= { + 0x80,0x80,0x00,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x90,0x90,0x90,0x90,0x48,0x48, + 0x48,0xfe,0x24,0x24,0x24,0x7f,0x12,0x12, + 0x20,0x70,0xa8,0xa8,0x28,0x30,0x60,0xa0, + 0xa8,0xa8,0x70,0x20,0x8c,0x52,0x52,0x2c, + 0x10,0x10,0x68,0x94,0x94,0x62,0x72,0x8c, + 0x84,0x8a,0x50,0x20,0x30,0x48,0x48,0x30, + 0x80,0x40,0x60,0x60,0x10,0x20,0x40,0x40, + 0x80,0x80,0x80,0x80,0x80,0x40,0x40,0x20, + 0x10,0x80,0x40,0x20,0x20,0x10,0x10,0x10, + 0x10,0x10,0x20,0x20,0x40,0x80,0x20,0xa8, + 0x70,0x70,0xa8,0x20,0x10,0x10,0x10,0xfe, + 0x10,0x10,0x10,0x80,0x40,0x20,0x60,0x60, + 0xfc,0xc0,0xc0,0x80,0x80,0x40,0x40,0x20, + 0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x78, + 0x84,0x84,0xc4,0xa4,0x94,0x8c,0x84,0x84, + 0x78,0xe0,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0xc0,0x40,0xfc,0x80,0x40,0x20,0x10, + 0x08,0x04,0x84,0x84,0x78,0x78,0x84,0x04, + 0x04,0x04,0x38,0x04,0x04,0x84,0x78,0x08, + 0x08,0x08,0xfc,0x88,0x48,0x48,0x28,0x18, + 0x08,0x78,0x84,0x04,0x04,0x04,0xf8,0x80, + 0x80,0x80,0xfc,0x78,0x84,0x84,0x84,0x84, + 0xf8,0x80,0x80,0x84,0x78,0x20,0x20,0x20, + 0x10,0x10,0x08,0x08,0x04,0x04,0xfc,0x78, + 0x84,0x84,0x84,0x84,0x78,0x84,0x84,0x84, + 0x78,0x78,0x84,0x04,0x04,0x7c,0x84,0x84, + 0x84,0x84,0x78,0xc0,0xc0,0x00,0x00,0x00, + 0xc0,0xc0,0x80,0x40,0xc0,0xc0,0x00,0x00, + 0x00,0xc0,0xc0,0x04,0x08,0x10,0x20,0x40, + 0x80,0x40,0x20,0x10,0x08,0x04,0xfc,0x00, + 0x00,0xfc,0x80,0x40,0x20,0x10,0x08,0x04, + 0x08,0x10,0x20,0x40,0x80,0x10,0x10,0x00, + 0x10,0x10,0x08,0x04,0x84,0x84,0x78,0x38, + 0x44,0x80,0x98,0xa4,0xa4,0x9c,0x84,0x48, + 0x30,0x84,0x84,0xfc,0x84,0x48,0x48,0x48, + 0x30,0x30,0x30,0xf8,0x84,0x84,0x84,0x84, + 0xf8,0x84,0x84,0x84,0xf8,0x78,0x84,0x84, + 0x80,0x80,0x80,0x80,0x84,0x84,0x78,0xf0, + 0x88,0x84,0x84,0x84,0x84,0x84,0x84,0x88, + 0xf0,0xfc,0x80,0x80,0x80,0x80,0xf8,0x80, + 0x80,0x80,0xfc,0x80,0x80,0x80,0x80,0x80, + 0xf8,0x80,0x80,0x80,0xfc,0x74,0x8c,0x84, + 0x84,0x84,0x9c,0x80,0x80,0x84,0x78,0x84, + 0x84,0x84,0x84,0x84,0xfc,0x84,0x84,0x84, + 0x84,0xe0,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0xe0,0x70,0x88,0x88,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x84,0x84,0x88, + 0x90,0xa0,0xc0,0xa0,0x90,0x88,0x84,0xfc, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x82,0x82,0x92,0x92,0xaa,0xaa,0xc6, + 0xc6,0x82,0x82,0x84,0x8c,0x8c,0x94,0x94, + 0xa4,0xa4,0xc4,0xc4,0x84,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x80, + 0x80,0x80,0x80,0xf8,0x84,0x84,0x84,0x84, + 0xf8,0x04,0x08,0x10,0x78,0xa4,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x78,0x84,0x84, + 0x88,0x90,0xf8,0x84,0x84,0x84,0x84,0xf8, + 0x78,0x84,0x84,0x04,0x18,0x60,0x80,0x84, + 0x84,0x78,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0xfe,0x78,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x30,0x30, + 0x30,0x48,0x48,0x48,0x84,0x84,0x84,0x84, + 0x44,0x44,0x44,0xaa,0xaa,0xaa,0x92,0x92, + 0x92,0x82,0x84,0x84,0x48,0x48,0x30,0x30, + 0x48,0x48,0x84,0x84,0x10,0x10,0x10,0x10, + 0x10,0x28,0x44,0x44,0x82,0x82,0xfc,0x80, + 0x40,0x40,0x20,0x10,0x08,0x08,0x04,0xfc, + 0xf0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0xf0,0x04,0x04,0x08, + 0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x80, + 0x80,0xf0,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0xf0,0x88,0x50, + 0x20,0xff,0x20,0x40,0xc0,0xc0,0x74,0x88, + 0x88,0x78,0x08,0x88,0x70,0xb8,0xc4,0x84, + 0x84,0x84,0xc4,0xb8,0x80,0x80,0x80,0x78, + 0x84,0x80,0x80,0x80,0x84,0x78,0x74,0x8c, + 0x84,0x84,0x84,0x8c,0x74,0x04,0x04,0x04, + 0x78,0x84,0x80,0xfc,0x84,0x84,0x78,0x20, + 0x20,0x20,0x20,0x20,0x20,0xf8,0x20,0x20, + 0x1c,0x78,0x84,0x04,0x04,0x74,0x8c,0x84, + 0x84,0x84,0x8c,0x74,0x84,0x84,0x84,0x84, + 0x84,0xc4,0xb8,0x80,0x80,0x80,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0x00,0x20,0x20, + 0x70,0x88,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x38,0x00,0x08,0x08,0x84,0x88, + 0x90,0xe0,0xa0,0x90,0x88,0x80,0x80,0x80, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0xe0,0x92,0x92,0x92,0x92,0x92,0x92, + 0xec,0x84,0x84,0x84,0x84,0x84,0xc4,0xb8, + 0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x80, + 0x80,0x80,0x80,0xb8,0xc4,0x84,0x84,0x84, + 0xc4,0xb8,0x04,0x04,0x04,0x04,0x74,0x8c, + 0x84,0x84,0x84,0x8c,0x74,0x80,0x80,0x80, + 0x80,0x80,0xc4,0xb8,0x78,0x84,0x04,0x78, + 0x80,0x84,0x78,0x1c,0x20,0x20,0x20,0x20, + 0x20,0xf8,0x20,0x20,0x74,0x8c,0x84,0x84, + 0x84,0x84,0x84,0x30,0x30,0x48,0x48,0x84, + 0x84,0x84,0x6c,0x92,0x92,0x92,0x92,0x82, + 0x82,0x84,0x84,0x48,0x30,0x48,0x84,0x84, + 0x78,0x84,0x04,0x04,0x74,0x8c,0x84,0x84, + 0x84,0x84,0x84,0xfc,0x80,0x40,0x20,0x10, + 0x08,0xfc,0x1c,0x20,0x20,0x20,0x20,0x20, + 0xc0,0x20,0x20,0x20,0x20,0x20,0x1c,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xe0,0x10,0x10, + 0x10,0x10,0x10,0x0c,0x10,0x10,0x10,0x10, + 0x10,0xe0,0x98,0xb4,0x64,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x20, + 0x20,0x70,0x88,0x80,0x80,0x88,0x70,0x20, + 0x20,0xb8,0x44,0x40,0x40,0xf0,0x40,0x40, + 0x40,0x48,0x30,0x84,0x78,0x84,0x84,0x84, + 0x78,0x84,0x38,0x10,0x7c,0x10,0x7c,0x28, + 0x44,0x44,0x82,0x82,0x80,0x80,0x80,0x80, + 0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80, + 0x80,0x80,0x78,0x84,0x04,0x18,0x24,0x44, + 0x84,0x88,0x90,0x60,0x80,0x84,0x78,0xd8, + 0x38,0x44,0x92,0xaa,0xa2,0xaa,0x92,0x44, + 0x38,0xf8,0x00,0x68,0x90,0x70,0x10,0x60, + 0x09,0x12,0x24,0x48,0x90,0x48,0x24,0x12, + 0x09,0x04,0x04,0xfc,0xfc,0x38,0x44,0xaa, + 0xaa,0xb2,0xaa,0xb2,0x44,0x38,0xf0,0x60, + 0x90,0x90,0x60,0xfe,0x00,0x10,0x10,0x10, + 0xfe,0x10,0x10,0x10,0xf0,0x40,0x20,0x90, + 0x60,0xe0,0x10,0x60,0x10,0xe0,0x80,0x40, + 0x80,0x80,0x80,0xb4,0xc8,0x88,0x88,0x88, + 0x88,0x88,0x24,0x24,0x24,0x24,0x24,0x24, + 0x64,0xa4,0xa4,0xa4,0xa4,0x7e,0xc0,0xc0, + 0x20,0x40,0xe0,0x40,0x40,0xc0,0x40,0xf8, + 0x00,0x70,0x88,0x88,0x88,0x70,0x90,0x48, + 0x24,0x12,0x09,0x12,0x24,0x48,0x90,0x04, + 0x9e,0x54,0x2c,0x14,0xe8,0x44,0x42,0xc0, + 0x40,0x1e,0x08,0x84,0x52,0x2c,0x10,0xe8, + 0x44,0x42,0xc0,0x40,0x04,0x9e,0x54,0x2c, + 0xd4,0x28,0x44,0x22,0xc0,0x78,0x84,0x84, + 0x80,0x40,0x20,0x20,0x00,0x20,0x20,0x84, + 0x84,0xfc,0x84,0x48,0x48,0x30,0x30,0x00, + 0x20,0x40,0x84,0x84,0xfc,0x84,0x48,0x48, + 0x30,0x30,0x00,0x10,0x08,0x84,0x84,0xfc, + 0x84,0x48,0x48,0x30,0x30,0x00,0x48,0x30, + 0x84,0x84,0xfc,0x84,0x48,0x48,0x30,0x30, + 0x00,0x98,0x64,0x84,0x84,0xfc,0x84,0x48, + 0x48,0x30,0x30,0x00,0x6c,0x84,0x84,0xfc, + 0x84,0x48,0x48,0x30,0x30,0x30,0x48,0x30, + 0x9e,0x90,0x90,0xf0,0x90,0x5c,0x50,0x50, + 0x30,0x1e,0x30,0x08,0x10,0x78,0x84,0x84, + 0x80,0x80,0x80,0x80,0x84,0x84,0x78,0xfc, + 0x80,0x80,0x80,0xf8,0x80,0x80,0xfc,0x00, + 0x20,0x40,0xfc,0x80,0x80,0x80,0xf8,0x80, + 0x80,0xfc,0x00,0x10,0x08,0xfc,0x80,0x80, + 0x80,0xf8,0x80,0x80,0xfc,0x00,0x48,0x30, + 0xfc,0x80,0x80,0x80,0xf8,0x80,0x80,0xfc, + 0x00,0x6c,0xe0,0x40,0x40,0x40,0x40,0x40, + 0x40,0xe0,0x00,0x40,0x80,0xe0,0x40,0x40, + 0x40,0x40,0x40,0x40,0xe0,0x00,0x40,0x20, + 0xe0,0x40,0x40,0x40,0x40,0x40,0x40,0xe0, + 0x00,0x90,0x60,0x70,0x20,0x20,0x20,0x20, + 0x20,0x20,0x70,0x00,0xd8,0x78,0x44,0x42, + 0x42,0x42,0xf2,0x42,0x42,0x44,0x78,0x84, + 0x8c,0x94,0x94,0xa4,0xa4,0xc4,0x84,0x00, + 0x98,0x64,0x78,0x84,0x84,0x84,0x84,0x84, + 0x84,0x78,0x00,0x20,0x40,0x78,0x84,0x84, + 0x84,0x84,0x84,0x84,0x78,0x00,0x10,0x08, + 0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x78, + 0x00,0x48,0x30,0x78,0x84,0x84,0x84,0x84, + 0x84,0x84,0x78,0x00,0x98,0x64,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x6c, + 0x84,0x48,0x30,0x30,0x48,0x84,0xbc,0x42, + 0x62,0x52,0x52,0x4a,0x4a,0x46,0x42,0x3d, + 0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x00,0x20,0x40,0x78,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x00,0x10,0x08,0x78,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x48, + 0x30,0x78,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x00,0x6c,0x10,0x10,0x10,0x10,0x28, + 0x44,0x44,0x82,0x00,0x10,0x08,0xe0,0x40, + 0x7c,0x42,0x42,0x42,0x42,0x7c,0x40,0xe0, + 0x98,0xa4,0x84,0x84,0x84,0x88,0xb0,0x88, + 0x88,0x70,0x74,0x88,0x88,0x78,0x08,0x88, + 0x70,0x00,0x20,0x40,0x74,0x88,0x88,0x78, + 0x08,0x88,0x70,0x00,0x20,0x10,0x74,0x88, + 0x88,0x78,0x08,0x88,0x70,0x00,0x48,0x30, + 0x74,0x88,0x88,0x78,0x08,0x88,0x70,0x00, + 0x98,0x64,0x74,0x88,0x88,0x78,0x08,0x88, + 0x70,0x00,0xd8,0x74,0x88,0x88,0x78,0x08, + 0x88,0x70,0x00,0x30,0x48,0x30,0x6c,0x92, + 0x90,0x7e,0x12,0x92,0x6c,0x30,0x08,0x10, + 0x78,0x84,0x80,0x80,0x80,0x84,0x78,0x78, + 0x84,0x80,0xfc,0x84,0x84,0x78,0x00,0x20, + 0x40,0x78,0x84,0x80,0xfc,0x84,0x84,0x78, + 0x00,0x10,0x08,0x78,0x84,0x80,0xfc,0x84, + 0x84,0x78,0x00,0x48,0x30,0x78,0x84,0x80, + 0xfc,0x84,0x84,0x78,0x00,0x6c,0x20,0x20, + 0x20,0x20,0x20,0x20,0xe0,0x00,0x40,0x80, + 0x20,0x20,0x20,0x20,0x20,0x20,0xe0,0x00, + 0x40,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0xe0,0x00,0x90,0x60,0x10,0x10,0x10,0x10, + 0x10,0x10,0x70,0x00,0xd8,0x78,0x84,0x84, + 0x84,0x84,0x84,0x7c,0x04,0xc8,0x30,0xc8, + 0x84,0x84,0x84,0x84,0x84,0xc4,0xb8,0x00, + 0x98,0x64,0x78,0x84,0x84,0x84,0x84,0x84, + 0x78,0x00,0x20,0x40,0x78,0x84,0x84,0x84, + 0x84,0x84,0x78,0x00,0x10,0x08,0x78,0x84, + 0x84,0x84,0x84,0x84,0x78,0x00,0x48,0x30, + 0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00, + 0x98,0x64,0x78,0x84,0x84,0x84,0x84,0x84, + 0x78,0x00,0x00,0x6c,0x30,0x00,0x00,0xfc, + 0x00,0x00,0x30,0xbc,0x62,0x52,0x4a,0x46, + 0x42,0x3d,0x74,0x8c,0x84,0x84,0x84,0x84, + 0x84,0x00,0x20,0x40,0x74,0x8c,0x84,0x84, + 0x84,0x84,0x84,0x00,0x20,0x10,0x74,0x8c, + 0x84,0x84,0x84,0x84,0x84,0x00,0x48,0x30, + 0x74,0x8c,0x84,0x84,0x84,0x84,0x84,0x00, + 0x00,0x6c,0x78,0x84,0x04,0x04,0x74,0x8c, + 0x84,0x84,0x84,0x84,0x84,0x00,0x20,0x10, + 0xe0,0x40,0x40,0x5c,0x62,0x42,0x42,0x42, + 0x62,0x5c,0x40,0x40,0xc0,0x78,0x84,0x04, + 0x04,0x74,0x8c,0x84,0x84,0x84,0x84,0x84, + 0x00,0x00,0x6c, +}; + +BMF_FontData BMF_font_scr15 = { + 0, -4, + 8, 11, + { + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 20, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 8, -1}, + {1, 10, -3, 0, 8, 0}, + {4, 4, -2, -6, 8, 10}, + {8, 10, 0, 0, 8, 14}, + {5, 12, -1, 1, 8, 24}, + {7, 10, 0, 0, 8, 36}, + {7, 10, 0, 0, 8, 46}, + {3, 4, -2, -6, 8, 56}, + {4, 13, -2, 2, 8, 60}, + {4, 13, -2, 2, 8, 73}, + {5, 6, -1, -2, 8, 86}, + {7, 7, 0, -1, 8, 92}, + {3, 5, -2, 3, 8, 99}, + {6, 1, -1, -4, 8, 104}, + {2, 2, -3, 0, 8, 105}, + {6, 12, -1, 1, 8, 107}, + {6, 10, -1, 0, 8, 119}, + {3, 10, -3, 0, 8, 129}, + {6, 10, -1, 0, 8, 139}, + {6, 10, -1, 0, 8, 149}, + {6, 10, -1, 0, 8, 159}, + {6, 10, -1, 0, 8, 169}, + {6, 10, -1, 0, 8, 179}, + {6, 10, -1, 0, 8, 189}, + {6, 10, -1, 0, 8, 199}, + {6, 10, -1, 0, 8, 209}, + {2, 7, -3, 0, 8, 219}, + {2, 9, -3, 2, 8, 226}, + {6, 11, -1, 1, 8, 235}, + {6, 4, -1, -3, 8, 246}, + {6, 11, -1, 1, 8, 250}, + {6, 10, -1, 0, 8, 261}, + {6, 10, -1, 0, 8, 271}, + {6, 10, -1, 0, 8, 281}, + {6, 10, -1, 0, 8, 291}, + {6, 10, -1, 0, 8, 301}, + {6, 10, -1, 0, 8, 311}, + {6, 10, -1, 0, 8, 321}, + {6, 10, -1, 0, 8, 331}, + {6, 10, -1, 0, 8, 341}, + {6, 10, -1, 0, 8, 351}, + {3, 10, -2, 0, 8, 361}, + {5, 10, -1, 0, 8, 371}, + {6, 10, -1, 0, 8, 381}, + {6, 10, -1, 0, 8, 391}, + {7, 10, 0, 0, 8, 401}, + {6, 10, -1, 0, 8, 411}, + {6, 10, -1, 0, 8, 421}, + {6, 10, -1, 0, 8, 431}, + {6, 13, -1, 3, 8, 441}, + {6, 10, -1, 0, 8, 454}, + {6, 10, -1, 0, 8, 464}, + {7, 10, 0, 0, 8, 474}, + {6, 10, -1, 0, 8, 484}, + {6, 10, -1, 0, 8, 494}, + {7, 10, 0, 0, 8, 504}, + {6, 10, -1, 0, 8, 514}, + {7, 10, 0, 0, 8, 524}, + {6, 10, -1, 0, 8, 534}, + {4, 13, -2, 2, 8, 544}, + {6, 12, -1, 1, 8, 557}, + {4, 13, -2, 2, 8, 569}, + {5, 3, -1, -6, 8, 582}, + {8, 1, 0, 3, 8, 585}, + {3, 4, -2, -6, 8, 586}, + {6, 7, -1, 0, 8, 590}, + {6, 10, -1, 0, 8, 597}, + {6, 7, -1, 0, 8, 607}, + {6, 10, -1, 0, 8, 614}, + {6, 7, -1, 0, 8, 624}, + {6, 10, -1, 0, 8, 631}, + {6, 11, -1, 4, 8, 641}, + {6, 10, -1, 0, 8, 652}, + {3, 10, -2, 0, 8, 662}, + {5, 14, -1, 4, 8, 672}, + {6, 10, -1, 0, 8, 686}, + {3, 10, -2, 0, 8, 696}, + {7, 7, 0, 0, 8, 706}, + {6, 7, -1, 0, 8, 713}, + {6, 7, -1, 0, 8, 720}, + {6, 11, -1, 4, 8, 727}, + {6, 11, -1, 4, 8, 738}, + {6, 7, -1, 0, 8, 749}, + {6, 7, -1, 0, 8, 756}, + {6, 9, -1, 0, 8, 763}, + {6, 7, -1, 0, 8, 772}, + {6, 7, -1, 0, 8, 779}, + {7, 7, 0, 0, 8, 786}, + {6, 7, -1, 0, 8, 793}, + {6, 11, -1, 4, 8, 800}, + {6, 7, -1, 0, 8, 811}, + {6, 13, -1, 2, 8, 818}, + {1, 14, -3, 3, 8, 831}, + {6, 13, -1, 2, 8, 845}, + {6, 3, -1, -3, 8, 858}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0,0,0,0,0, -1}, + {0, 0, 0, 0, 8, -1}, + {1, 10, -3, 3, 8, 861}, + {5, 10, -1, 0, 8, 871}, + {6, 10, -1, 0, 8, 881}, + {6, 7, -1, -2, 8, 891}, + {7, 10, 0, 0, 8, 898}, + {1, 14, -3, 3, 8, 908}, + {6, 13, -1, 3, 8, 922}, + {5, 1, -1, -9, 8, 935}, + {7, 9, 0, 0, 8, 936}, + {5, 7, -1, -3, 8, 945}, + {8, 9, 0, 0, 8, 952}, + {6, 3, -1, -3, 8, 961}, + {6, 1, -1, -4, 8, 964}, + {7, 9, 0, 0, 8, 965}, + {4, 1, -2, -9, 8, 974}, + {4, 4, -2, -4, 8, 975}, + {7, 9, 0, 0, 8, 979}, + {4, 5, -2, -5, 8, 988}, + {4, 5, -2, -5, 8, 993}, + {2, 2, -3, -9, 8, 998}, + {6, 10, -1, 3, 8, 1000}, + {7, 12, 0, 2, 8, 1010}, + {2, 1, -3, -4, 8, 1022}, + {3, 3, -3, 3, 8, 1023}, + {3, 5, -3, -5, 8, 1026}, + {5, 7, -1, -3, 8, 1031}, + {8, 9, 0, 0, 8, 1038}, + {7, 10, 0, 0, 8, 1047}, + {7, 11, 0, 1, 8, 1057}, + {7, 9, 0, -1, 8, 1068}, + {6, 10, -1, 2, 8, 1077}, + {6, 11, -1, 0, 8, 1087}, + {6, 11, -1, 0, 8, 1098}, + {6, 11, -1, 0, 8, 1109}, + {6, 11, -1, 0, 8, 1120}, + {6, 10, -1, 0, 8, 1131}, + {6, 11, -1, 0, 8, 1141}, + {7, 10, 0, 0, 8, 1152}, + {6, 13, -1, 3, 8, 1162}, + {6, 11, -1, 0, 8, 1175}, + {6, 11, -1, 0, 8, 1186}, + {6, 11, -1, 0, 8, 1197}, + {6, 10, -1, 0, 8, 1208}, + {3, 11, -2, 0, 8, 1218}, + {3, 11, -2, 0, 8, 1229}, + {4, 11, -2, 0, 8, 1240}, + {5, 10, -1, 0, 8, 1251}, + {7, 10, 0, 0, 8, 1261}, + {6, 11, -1, 0, 8, 1271}, + {6, 11, -1, 0, 8, 1282}, + {6, 11, -1, 0, 8, 1293}, + {6, 11, -1, 0, 8, 1304}, + {6, 11, -1, 0, 8, 1315}, + {6, 10, -1, 0, 8, 1326}, + {6, 6, -1, -1, 8, 1336}, + {8, 10, 0, 0, 8, 1342}, + {6, 11, -1, 0, 8, 1352}, + {6, 11, -1, 0, 8, 1363}, + {6, 11, -1, 0, 8, 1374}, + {6, 10, -1, 0, 8, 1385}, + {7, 11, 0, 0, 8, 1395}, + {7, 10, 0, 0, 8, 1406}, + {6, 10, -1, 0, 8, 1416}, + {6, 10, -1, 0, 8, 1426}, + {6, 10, -1, 0, 8, 1436}, + {6, 10, -1, 0, 8, 1446}, + {6, 10, -1, 0, 8, 1456}, + {6, 9, -1, 0, 8, 1466}, + {6, 11, -1, 0, 8, 1475}, + {7, 7, 0, 0, 8, 1486}, + {6, 10, -1, 3, 8, 1493}, + {6, 10, -1, 0, 8, 1503}, + {6, 10, -1, 0, 8, 1513}, + {6, 10, -1, 0, 8, 1523}, + {6, 9, -1, 0, 8, 1533}, + {3, 10, -2, 0, 8, 1542}, + {3, 10, -2, 0, 8, 1552}, + {4, 10, -2, 0, 8, 1562}, + {5, 9, -1, 0, 8, 1572}, + {6, 11, -1, 0, 8, 1581}, + {6, 10, -1, 0, 8, 1592}, + {6, 10, -1, 0, 8, 1602}, + {6, 10, -1, 0, 8, 1612}, + {6, 10, -1, 0, 8, 1622}, + {6, 10, -1, 0, 8, 1632}, + {6, 10, -1, 0, 8, 1642}, + {6, 7, -1, 0, 8, 1652}, + {8, 7, 0, 0, 8, 1659}, + {6, 10, -1, 0, 8, 1666}, + {6, 10, -1, 0, 8, 1676}, + {6, 10, -1, 0, 8, 1686}, + {6, 10, -1, 0, 8, 1696}, + {6, 14, -1, 4, 8, 1706}, + {7, 13, 0, 3, 8, 1720}, + {6, 14, -1, 4, 8, 1733}, + }, + bitmap_data +}; + +#endif + diff --git a/intern/bmfont/intern/Makefile b/intern/bmfont/intern/Makefile new file mode 100644 index 00000000000..cd02eaa31bd --- /dev/null +++ b/intern/bmfont/intern/Makefile @@ -0,0 +1,44 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bmfont intern Makefile +# + +LIBNAME = bmfont +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I. +CPPFLAGS += -I.. +CPPFLAGS += -I$(OPENGL_HEADERS) + diff --git a/intern/bmfont/make/msvc_6_0/bmfont.dsp b/intern/bmfont/make/msvc_6_0/bmfont.dsp new file mode 100644 index 00000000000..a9d2d9722e1 --- /dev/null +++ b/intern/bmfont/make/msvc_6_0/bmfont.dsp @@ -0,0 +1,176 @@ +# Microsoft Developer Studio Project File - Name="bmfont" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=bmfont - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bmfont.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bmfont.mak" CFG="bmfont - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bmfont - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "bmfont - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bmfont - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\bmfont" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\bmfont" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../.." /I "../../intern" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\bmfont\libbmfont.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copying BMFONT files library (release target) to lib tree. +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\bmfont\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\bmfont\*.lib ..\..\..\..\..\lib\windows\bmfont\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "bmfont - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\bmfont\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\bmfont\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../.." /I "../../intern" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\bmfont\debug\libbmfont.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copying BMFONT files library (debug target) to lib tree. +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\bmfont\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\bmfont\debug\*.lib ..\..\..\..\..\lib\windows\bmfont\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "bmfont - Win32 Release" +# Name "bmfont - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\BMF_Api.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_BitmapFont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helv10.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helv12.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helvb10.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helvb12.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helvb14.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_helvb8.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_scr12.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_scr14.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_font_scr15.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\BMF_BitmapFont.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BMF_FontData.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\BMF_Api.h +# End Source File +# Begin Source File + +SOURCE=..\..\BMF_Fonts.h +# End Source File +# Begin Source File + +SOURCE=..\..\BMF_Settings.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/intern/bmfont/make/msvc_6_0/bmfont.dsw b/intern/bmfont/make/msvc_6_0/bmfont.dsw new file mode 100644 index 00000000000..d2e2f94cd0b --- /dev/null +++ b/intern/bmfont/make/msvc_6_0/bmfont.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bmfont"=.\bmfont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bmfont/make/msvc_7_0/bmfont.sln b/intern/bmfont/make/msvc_7_0/bmfont.sln new file mode 100644 index 00000000000..7f1979a8273 --- /dev/null +++ b/intern/bmfont/make/msvc_7_0/bmfont.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bmfont", "bmfont.vcproj", "{8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}.Debug.ActiveCfg = Debug|Win32 + {8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}.Debug.Build.0 = Debug|Win32 + {8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}.Release.ActiveCfg = Release|Win32 + {8CDFE9DC-F28C-4E1F-9389-3066BB0AB09F}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/bmfont/make/msvc_7_0/bmfont.vcproj b/intern/bmfont/make/msvc_7_0/bmfont.vcproj new file mode 100644 index 00000000000..089130bc5e0 --- /dev/null +++ b/intern/bmfont/make/msvc_7_0/bmfont.vcproj @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bmfont/test/Makefile b/intern/bmfont/test/Makefile new file mode 100644 index 00000000000..f7e0f927722 --- /dev/null +++ b/intern/bmfont/test/Makefile @@ -0,0 +1,63 @@ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Test the bmfont module +# + +LIBNAME = bmfont +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = simpletest + +include nan_subdirs.mk +include nan_compile.mk +include nan_link.mk + +TESTLIBS = $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)lib$(LIBNAME).a +TESTLIBS += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a +TESTLIBS += $(LCGDIR)/ghost/$(DEBUG_DIR)lib/libghost.a + + +ifeq ($(OS),$(findstring $(OS), "beos darwin linux freebsd openbsd")) + TESTLIBS += -L/usr/X11R6/lib -lglut -pthread +endif + +ifeq ($(OS),$(findstring $(OS), "solaris")) + TESTLIBS += -L/usr/openwin/lib -lglut -lX11 -lGL -lGLU -lXmu +endif + + +all debug:: + @echo "****> linking $@ in $(SOURCEDIR)" + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)BMF_Test $(DIR)/BMF_Test.o $(TESTLIBS) + +clean:: + $(RM) $(DIR)/BMF_Test $(DIR)/debug/BMF_Test + +test:: $(DIR)/BMF_Test + $(DIR)/BMF_Test $(NAN_TEST_VERBOSITY) + diff --git a/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsp b/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsp new file mode 100644 index 00000000000..13e6e65f706 --- /dev/null +++ b/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsp @@ -0,0 +1,109 @@ +# Microsoft Developer Studio Project File - Name="BMF_Test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=BMF_Test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BMF_Test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BMF_Test.mak" CFG="BMF_Test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BMF_Test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "BMF_Test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BMF_Test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../../../../../../obj/windows/intern/BMF_bmfont/test" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/BMF_bmfont/test" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../../" /I "../../../../../lib/windows/string/include" /I "../../../../../lib/windows/ghost/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libstring.a libghost.a glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 /libpath:"../../../../../lib/windows/string/lib" /libpath:"../../../../../lib/windows/ghost/lib" + +!ELSEIF "$(CFG)" == "BMF_Test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../../../../../../obj/windows/intern/BMF_bmfont/test/debug" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/BMF_bmfont/test/debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../" /I "../../../../../lib/windows/string/include" /I "../../../../../lib/windows/ghost/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib libstring.a libghost.a user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"../../../../../lib/windows/string/lib" /libpath:"../../../../../lib/windows/ghost/lib" + +!ENDIF + +# Begin Target + +# Name "BMF_Test - Win32 Release" +# Name "BMF_Test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\intern\BMF_glut_helb8.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\intern\BMF_glut_helb8.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\BMF_Test.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsw b/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsw new file mode 100644 index 00000000000..5baacb9adf7 --- /dev/null +++ b/intern/bmfont/test/make/msvc_6_0/BMF_Test.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BMF_Test"=.\BMF_Test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name BMF_bmfont + End Project Dependency +}}} + +############################################################################### + +Project: "BMF_bmfont"=..\..\..\make\msvc_6_0\BMF_bmfont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bmfont/test/simpletest/BMF_Test.cpp b/intern/bmfont/test/simpletest/BMF_Test.cpp new file mode 100644 index 00000000000..00f7bc30f45 --- /dev/null +++ b/intern/bmfont/test/simpletest/BMF_Test.cpp @@ -0,0 +1,229 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple test file for the bitmap font library using GHOST. + * @author Maarten Gribnau + * @date November 15, 2001 + */ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define FALSE 0 +#define TRUE 1 + +#if defined(WIN32) || defined(__APPLE__) +#ifdef WIN32 +#include +#include +#else // WIN32 +// __APPLE__ is defined +#include +#endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) +#include +#endif // defined(WIN32) || defined(__APPLE__) + + +#include "STR_String.h" +#include "GHOST_Rect.h" + +#include "GHOST_ISystem.h" +#include "GHOST_IEvent.h" +#include "GHOST_IEventConsumer.h" + +#include "BMF_Api.h" + +static class Application* fApp; +static GHOST_ISystem* fSystem = 0; + + +static void drawGL() +{ + GLint x = 10, y = 10; + + ::glRasterPos2i(x, y); + BMF_Font *font = BMF_GetFont(BMF_kHelvetica10); + BMF_DrawString(font, "Helvetica 10 point"); + y += 14; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelvetica12); + BMF_DrawString(font, "Helvetica 12 point"); + y += 16; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelveticaBold8); + BMF_DrawString(font, "Helvetica Bold 8 point"); + y += 12; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelveticaBold10); + BMF_DrawString(font, "Helvetica Bold 10 point"); + y += 14; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelveticaBold12); + BMF_DrawString(font, "Helvetica Bold 12 point"); + y += 16; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kHelveticaBold14); + BMF_DrawString(font, "Helvetica Bold 14 point"); + y += 18; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kScreen12); + BMF_DrawString(font, "Screen 12 point"); + y += 16; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kScreen14); + BMF_DrawString(font, "Screen 14 point"); + y += 18; + ::glRasterPos2i(x, y); + font = BMF_GetFont(BMF_kScreen15); + BMF_DrawString(font, "Screen 15 point"); +} + + +static void setViewPortGL(GHOST_IWindow* window) +{ + window->activateDrawingContext(); + GHOST_Rect bnds; + window->getClientBounds(bnds); + + ::glViewport(0, 0, bnds.getWidth(), bnds.getHeight()); + + ::glMatrixMode(GL_PROJECTION); + ::glLoadIdentity(); + ::glOrtho(0, bnds.getWidth(), 0, bnds.getHeight(), -10, 10); + + ::glClearColor(.2f,0.0f,0.0f,0.0f); + ::glClear(GL_COLOR_BUFFER_BIT); +} + + + +class Application : public GHOST_IEventConsumer { +public: + Application(GHOST_ISystem* system); + virtual bool processEvent(GHOST_IEvent* event); + + GHOST_ISystem* m_system; + GHOST_IWindow* m_mainWindow; + bool m_exitRequested; +}; + + +Application::Application(GHOST_ISystem* system) + : m_system(system), m_mainWindow(0), m_exitRequested(false) +{ + fApp = this; + + // Create the main window + STR_String title1 ("gears - main window"); + m_mainWindow = system->createWindow(title1, 10, 64, 320, 200, GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,FALSE); + if (!m_mainWindow) { + std::cout << "could not create main window\n"; + exit(-1); + } +} + + +bool Application::processEvent(GHOST_IEvent* event) +{ + bool handled = true; + + switch (event->getType()) { + case GHOST_kEventWindowClose: + { + GHOST_IWindow* window2 = event->getWindow(); + if (window2 == m_mainWindow) { + exit(0); + } else { + m_system->disposeWindow(window2); + } + } + break; + + case GHOST_kEventWindowActivate: + handled = false; + break; + case GHOST_kEventWindowDeactivate: + handled = false; + break; + case GHOST_kEventWindowUpdate: + { + GHOST_IWindow* window2 = event->getWindow(); + if (!m_system->validWindow(window2)) break; + { + setViewPortGL(window2); + drawGL(); + window2->swapBuffers(); + } + } + break; + + default: + handled = false; + break; + } + return handled; +} + + +int main(int /*argc*/, char** /*argv*/) +{ + // Create the system + GHOST_ISystem::createSystem(); + fSystem = GHOST_ISystem::getSystem(); + + if (fSystem) { + // Create an application object + Application app (fSystem); + + // Add the application as event consumer + fSystem->addEventConsumer(&app); + + // Enter main loop + while (!app.m_exitRequested) { + fSystem->processEvents(TRUE); + fSystem->dispatchEvents(); + } + } + + // Dispose the system + GHOST_ISystem::disposeSystem(); + + return 0; +} + diff --git a/intern/bmfont/test/simpletest/Makefile b/intern/bmfont/test/simpletest/Makefile new file mode 100644 index 00000000000..190a39f0e9b --- /dev/null +++ b/intern/bmfont/test/simpletest/Makefile @@ -0,0 +1,45 @@ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Test the bmfont module +# + +LIBNAME = bmfont +DIR = $(OCGDIR)/intern/$(LIBNAME)/test + +# we don't want a library here, only object files: +ALLTARGETS = $(OBJS) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS = -I../.. +CPPFLAGS += -I../../intern +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_GHOST)/include diff --git a/intern/boolop/CMakeLists.txt b/intern/boolop/CMakeLists.txt new file mode 100644 index 00000000000..0db6675237b --- /dev/null +++ b/intern/boolop/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . intern extern ../moto/include ../container ../memutil ../../source/blender/makesdna ../guardedalloc ../../source/blender/blenlib) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(blender_bop "${SRC}" "${INC}") +#, libtype='common', priority=5 ) diff --git a/intern/boolop/Makefile b/intern/boolop/Makefile new file mode 100644 index 00000000000..85e6754132e --- /dev/null +++ b/intern/boolop/Makefile @@ -0,0 +1,59 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bsp main makefile. +# + +include nan_definitions.mk + +LIBNAME = boolop +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +# not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_BOOLOP) ] || mkdir $(NAN_BOOLOP) + @[ -d $(NAN_BOOLOP)/include ] || mkdir $(NAN_BOOLOP)/include + @[ -d $(NAN_BOOLOP)/lib ] || mkdir $(NAN_BOOLOP)/lib + @[ -d $(NAN_BOOLOP)/lib/debug ] || mkdir $(NAN_BOOLOP)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libboolop.a $(NAN_BOOLOP)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libboolop.a $(NAN_BOOLOP)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_BOOLOP)/lib/libboolop.a + ranlib $(NAN_BOOLOP)/lib/debug/libboolop.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_BOOLOP)/include/ + + + + diff --git a/intern/boolop/SConscript b/intern/boolop/SConscript new file mode 100644 index 00000000000..a3f3c0b6433 --- /dev/null +++ b/intern/boolop/SConscript @@ -0,0 +1,14 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. intern extern ../moto/include ../container ../memutil' +incs += ' ../../source/blender/makesdna ../../intern/guardedalloc' +incs += ' ../../source/blender/blenlib' + +if (env['OURPLATFORM'] == 'win32-mingw'): + env.BlenderLib ('blender_bop', sources, Split(incs) , [], libtype=['common','intern'], priority = [5,50] ) +else: + env.BlenderLib ('blender_bop', sources, Split(incs) , [], libtype='common', priority = 5 ) + diff --git a/intern/boolop/extern/BOP_Interface.h b/intern/boolop/extern/BOP_Interface.h new file mode 100644 index 00000000000..7fe7ae226fd --- /dev/null +++ b/intern/boolop/extern/BOP_Interface.h @@ -0,0 +1,46 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_INTERFACE_H +#define BOP_INTERFACE_H + +#include "../../bsp/intern/BSP_CSGMesh.h" + +typedef enum EnumBoolOpState {BOP_OK, BOP_NO_SOLID, BOP_ERROR} BoolOpState; +typedef enum EnumBoolOpType {BOP_INTERSECTION=e_csg_intersection, BOP_UNION=e_csg_union, BOP_DIFFERENCE=e_csg_difference} BoolOpType; + +BoolOpState BOP_performBooleanOperation(BoolOpType opType, + BSP_CSGMesh** outputMesh, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices); + +#endif diff --git a/intern/boolop/intern/BOP_BBox.cpp b/intern/boolop/intern/BOP_BBox.cpp new file mode 100644 index 00000000000..767847e1e09 --- /dev/null +++ b/intern/boolop/intern/BOP_BBox.cpp @@ -0,0 +1,62 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_BBox.h" + +#include "MT_Scalar.h" + +/** + * Constructs a nwe bounding box. + */ +BOP_BBox::BOP_BBox() +{ + m_minX = MT_INFINITY; + m_minY = MT_INFINITY; + m_minZ = MT_INFINITY; + m_maxX = -MT_INFINITY; + m_maxY = -MT_INFINITY; + m_maxZ = -MT_INFINITY; +} + +/** + * Constructs a new bounding box using three points. + * @param p1 first point + * @param p2 second point + * @param p3 third point + */ +BOP_BBox::BOP_BBox(const MT_Point3& p1,const MT_Point3& p2,const MT_Point3& p3) +{ + m_minX = BOP_MIN(BOP_MIN(p1[0],p2[0]),p3[0]); + m_minY = BOP_MIN(BOP_MIN(p1[1],p2[1]),p3[1]); + m_minZ = BOP_MIN(BOP_MIN(p1[2],p2[2]),p3[2]); + m_maxX = BOP_MAX(BOP_MAX(p1[0],p2[0]),p3[0]); + m_maxY = BOP_MAX(BOP_MAX(p1[1],p2[1]),p3[1]); + m_maxZ = BOP_MAX(BOP_MAX(p1[2],p2[2]),p3[2]); +} diff --git a/intern/boolop/intern/BOP_BBox.h b/intern/boolop/intern/BOP_BBox.h new file mode 100644 index 00000000000..473a9828a1a --- /dev/null +++ b/intern/boolop/intern/BOP_BBox.h @@ -0,0 +1,96 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_BBOX_H +#define BOP_BBOX_H + +#include "MT_Point3.h" +#include "BOP_MathUtils.h" + +#define BOP_MAX(a, b) ((a > b) ? a : b) +#define BOP_MIN(a, b) ((a < b) ? a : b) +#define BOP_ABS(a) ((a < 0) ? -(a) : a) + +class BOP_BBox +{ +public: + MT_Scalar m_minX; + MT_Scalar m_minY; + MT_Scalar m_minZ; + MT_Scalar m_maxX; + MT_Scalar m_maxY; + MT_Scalar m_maxZ; + MT_Scalar m_centerX; + MT_Scalar m_centerY; + MT_Scalar m_centerZ; + MT_Scalar m_extentX; + MT_Scalar m_extentY; + MT_Scalar m_extentZ; + +public: + BOP_BBox(); + BOP_BBox(const MT_Point3& p1,const MT_Point3& p2,const MT_Point3& p3); + inline void add(const MT_Point3& p) + { + m_minX = BOP_MIN(m_minX,p[0]); + m_minY = BOP_MIN(m_minY,p[1]); + m_minZ = BOP_MIN(m_minZ,p[2]); + m_maxX = BOP_MAX(m_maxX,p[0]); + m_maxY = BOP_MAX(m_maxY,p[1]); + m_maxZ = BOP_MAX(m_maxZ,p[2]); + }; + + inline const MT_Scalar getCenterX() const {return m_centerX;}; + inline const MT_Scalar getCenterY() const {return m_centerY;}; + inline const MT_Scalar getCenterZ() const {return m_centerZ;}; + + inline const MT_Scalar getExtentX() const {return m_extentX;}; + inline const MT_Scalar getExtentY() const {return m_extentY;}; + inline const MT_Scalar getExtentZ() const {return m_extentZ;}; + + inline void compute() { + m_extentX = (m_maxX-m_minX)/2.0f; + m_extentY = (m_maxY-m_minY)/2.0f; + m_extentZ = (m_maxZ-m_minZ)/2.0f; + m_centerX = m_minX+m_extentX; + m_centerY = m_minY+m_extentY; + m_centerZ = m_minZ+m_extentZ; + }; + + inline const bool intersect(const BOP_BBox& b) const { + return (!((BOP_comp(m_maxX,b.m_minX)<0) || (BOP_comp(b.m_maxX,m_minX)<0) || + (BOP_comp(m_maxY,b.m_minY)<0) || (BOP_comp(b.m_maxY,m_minY)<0) || + (BOP_comp(m_maxZ,b.m_minZ)<0) || (BOP_comp(b.m_maxZ,m_minZ)<0))); + }; + + +}; + +#endif diff --git a/intern/boolop/intern/BOP_BSPNode.cpp b/intern/boolop/intern/BOP_BSPNode.cpp new file mode 100644 index 00000000000..68a20d7a5a4 --- /dev/null +++ b/intern/boolop/intern/BOP_BSPNode.cpp @@ -0,0 +1,717 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_MathUtils.h" +#include "BOP_BSPNode.h" +#include "MT_assert.h" +#include "MT_MinMax.h" +#include +using namespace std; + +/** + * Constructs a new BSP node. + * @param plane split plane. + */ +BOP_BSPNode::BOP_BSPNode(const MT_Plane3& plane) +{ + m_plane = plane; + m_inChild = NULL; + m_outChild = NULL; + m_deep = 1; +} + +/** + * Destroys a BSP tree. + */ +BOP_BSPNode::~BOP_BSPNode() +{ + if (m_inChild!=NULL) delete m_inChild; + if (m_outChild!=NULL) delete m_outChild; +} + +/** + * Adds a new face to this BSP tree. + * @param pts vector containing face points + * @param plane face plane. + */ + +unsigned int BOP_BSPNode::addFace(BOP_BSPPoints pts, + const MT_Plane3& plane ) +{ + unsigned int newDeep = 0; + BOP_TAG tag = ON; + + // find out if any points on the "face" lie in either half-space + BOP_IT_BSPPoints ptsEnd = pts.end(); + for(BOP_IT_BSPPoints itp=pts.begin();itp!=ptsEnd;itp++){ + tag = (BOP_TAG) ((int) tag | (int)testPoint(*itp)); + } + + if (tag == ON) { } // face lies on hyperplane: do nothing + else if ((tag & IN) != 0 && (tag & OUT) == 0) { // face is entirely on inside + if (m_inChild != NULL) + newDeep = m_inChild->addFace(pts, plane) + 1; + else { + m_inChild = new BOP_BSPNode(plane); + newDeep = 2; + } + } else if ((tag & OUT) != 0 && (tag & IN) == 0) { // face is entirely on outside + if (m_outChild != NULL) + newDeep = m_outChild->addFace(pts, plane) + 1; + else { + m_outChild = new BOP_BSPNode(plane); + newDeep = 2; + } + } else { // face lies in both half-spaces: split it + BOP_BSPPoints inside, outside; + MT_Point3 lpoint= pts[pts.size()-1]; + BOP_TAG ltag = testPoint(lpoint); + BOP_TAG tstate = ltag; + + // classify each line segment, looking for endpoints which lie on different + // sides of the hyperplane. + + ptsEnd = pts.end(); + for(BOP_IT_BSPPoints itp=pts.begin();itp!=ptsEnd;itp++){ + MT_Point3 npoint= *itp; + BOP_TAG ntag = testPoint(npoint); + + if(ltag != ON) { // last point not on hyperplane + if(tstate == IN) { + if (m_inChild != NULL) inside.push_back(lpoint); + } else { + if (m_outChild != NULL) outside.push_back(lpoint); + } + if(ntag != ON && ntag != tstate) { // last, self in different half-spaces + MT_Point3 mpoint = BOP_intersectPlane( m_plane, lpoint, npoint ); + if (m_inChild != NULL) inside.push_back(mpoint); + if (m_outChild != NULL) outside.push_back(mpoint); + tstate = ntag; + } + } else { // last point on hyperplane, so we're switching + // half-spaces + // boundary point belong to both faces + if (m_inChild != NULL) inside.push_back(lpoint); + if (m_outChild != NULL) outside.push_back(lpoint); + tstate = ntag; // state changes to new point tag + } + lpoint = npoint; // save point, tag for next iteration + ltag = ntag; + } + + if (m_inChild != NULL) + newDeep = m_inChild->addFace(inside, plane) + 1; + else { + m_inChild = new BOP_BSPNode(plane); + newDeep = 2; + } + if (m_outChild != NULL) + newDeep = MT_max(newDeep, m_outChild->addFace(outside, plane) + 1); + else { + m_outChild = new BOP_BSPNode(plane); + newDeep = MT_max(newDeep,(unsigned int)2); + } + } + + // update the deep attribute + m_deep = MT_max(m_deep,newDeep); + + return m_deep; +} + +/** + * Tests the point situation respect the node plane. + * @param p point to test. + * @return TAG result: IN, OUT or ON. + */ +BOP_TAG BOP_BSPNode::testPoint(const MT_Point3& p) const +{ + return BOP_createTAG(BOP_classify(p,m_plane)); + +} + +/** + * Classifies a face using its coordinates and plane. + * @param p1 first point. + * @param p2 second point. + * @param p3 third point. + * @param plane face plane. + * @return TAG result: IN, OUT or IN&OUT. + */ +BOP_TAG BOP_BSPNode::classifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + // local variables + MT_Point3 auxp1, auxp2; + BOP_TAG auxtag1, auxtag2, auxtag3; + + switch(BOP_createTAG(testPoint(p1),testPoint(p2),testPoint(p3))) { + // Classify the face on the IN side + case IN_IN_IN : + return classifyFaceIN(p1, p2, p3, plane); + case IN_IN_ON : + case IN_ON_IN : + case ON_IN_IN : + case IN_ON_ON : + case ON_IN_ON : + case ON_ON_IN : + return BOP_addON(classifyFaceIN(p1, p2, p3, plane)); + + // Classify the face on the OUT side + case OUT_OUT_OUT : + return classifyFaceOUT(p1, p2, p3, plane); + case OUT_OUT_ON : + case OUT_ON_OUT : + case ON_OUT_OUT : + case ON_ON_OUT : + case ON_OUT_ON : + case OUT_ON_ON : + return BOP_addON(classifyFaceOUT(p1, p2, p3, plane)); + + // Classify the ON face depending on it plane normal + case ON_ON_ON : + if (hasSameOrientation(plane)) + return BOP_addON(classifyFaceIN(p1, p2, p3, plane)); + else + return BOP_addON(classifyFaceOUT(p1, p2, p3, plane)); + + // Classify the face IN/OUT and one vertex ON + // becouse only one ON, only one way to subdivide the face + case IN_OUT_ON : + auxp1 = BOP_intersectPlane(m_plane, p1, p2); + auxtag1 = classifyFaceIN( p1, auxp1 , p3, plane); + auxtag2 = classifyFaceOUT(auxp1, p2, p3, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case OUT_IN_ON : + auxp1 = BOP_intersectPlane(m_plane, p1, p2); + auxtag1 = classifyFaceOUT(p1, auxp1, p3, plane); + auxtag2 = classifyFaceIN( auxp1, p2, p3, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case IN_ON_OUT : + auxp1 = BOP_intersectPlane(m_plane, p1, p3); + auxtag1 = classifyFaceIN( p1, p2, auxp1, plane); + auxtag2 = classifyFaceOUT(p2, p3, auxp1, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case OUT_ON_IN : + auxp1 = BOP_intersectPlane(m_plane, p1, p3); + auxtag1 = classifyFaceOUT(p1, p2, auxp1, plane); + auxtag2 = classifyFaceIN( p2, p3, auxp1, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case ON_IN_OUT : + auxp1 = BOP_intersectPlane(m_plane, p2, p3); + auxtag1 = classifyFaceIN( p1, p2, auxp1, plane); + auxtag2 = classifyFaceOUT(auxp1, p3, p1, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + case ON_OUT_IN : + auxp1 = BOP_intersectPlane(m_plane, p2, p3); + auxtag1 = classifyFaceOUT(p1, p2, auxp1, plane); + auxtag2 = classifyFaceIN( auxp1, p3, p1, plane); + return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT); + + // Classify IN/OUT face without ON vertices. + // Two ways to divide the triangle, + // will chose the least degenerated sub-triangles. + case IN_OUT_OUT : + auxp1 = BOP_intersectPlane(m_plane, p1, p2); + auxp2 = BOP_intersectPlane(m_plane, p1, p3); + + // f1: p1 auxp1 , auxp1 auxp2 + auxtag1 = classifyFaceIN(p1, auxp1, auxp2, plane); + + // f2: auxp1 p2 , p2 auxp2; f3: p2 p3 , p3 auxp2 || + // f2: auxp1 p3, p3 auxp2; f3: p2 p3 , p3 auxp1 + if (BOP_isInsideCircle(p2, p3, auxp1, auxp2)) { + auxtag2 = classifyFaceOUT(auxp1, p2, auxp2, plane); + auxtag3 = classifyFaceOUT(p2, p3, auxp2, plane); + } + else { + auxtag2 = classifyFaceOUT(auxp1, p3, auxp2, plane); + auxtag3 = classifyFaceOUT(p2, p3, auxp1, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case OUT_IN_IN : + auxp1 = BOP_intersectPlane(m_plane, p1, p2); + auxp2 = BOP_intersectPlane(m_plane, p1, p3); + + // f1: p1 auxp1 , auxp1 auxp2 + auxtag1 = classifyFaceOUT(p1, auxp1, auxp2, plane); + + // f2: auxp1 p2 , p2 auxp2; f3: p2 p3 , p3 auxp2 || + // f2: auxp1 p3, p3 auxp2; f3: p2 p3 , p3 auxp1 + if (BOP_isInsideCircle(p2, p3, auxp1, auxp2)) { + auxtag2 = classifyFaceIN(auxp1, p2, auxp2, plane); + auxtag3 = classifyFaceIN(p2, p3, auxp2, plane); + } + else { + auxtag2 = classifyFaceIN(auxp1, p3, auxp2, plane); + auxtag3 = classifyFaceIN(p2, p3, auxp1, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case OUT_IN_OUT : + auxp1 = BOP_intersectPlane(m_plane, p2, p1); + auxp2 = BOP_intersectPlane(m_plane, p2, p3); + + // f1: auxp1 p2 , p2 auxp2 + auxtag1 = classifyFaceIN(auxp1, p2, auxp2, plane); + + // f2: p1 auxp1 , auxp1 auxp2; f3: p1 auxp2 , auxp2 p3 || + // f2: p3 auxp1, auxp1 auxp2 f3:p1 auxp1, auxp1 p3 + if (BOP_isInsideCircle(p1, p3, auxp1, auxp2)) { + auxtag2 = classifyFaceOUT(p1, auxp1, auxp2, plane); + auxtag3 = classifyFaceOUT(p1, auxp2, p3, plane); + } + else { + auxtag2 = classifyFaceOUT(p3, auxp1, auxp2, plane); + auxtag3 = classifyFaceOUT(p1, auxp1, p3, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case IN_OUT_IN : + auxp1 = BOP_intersectPlane(m_plane, p2, p1); + auxp2 = BOP_intersectPlane(m_plane, p2, p3); + + // f1: auxp1 p2 , p2 auxp2 + auxtag1 = classifyFaceOUT(auxp1, p2, auxp2, plane); + + // f2: p1 auxp1 , auxp1 auxp2; f3: p1 auxp2 , auxp2 p3 || + // f2: p3 auxp1, auxp1 auxp2 f3:p1 auxp1, auxp1 p3 + if (BOP_isInsideCircle(p1, p3, auxp1, auxp2)) { + auxtag2 = classifyFaceIN(p1, auxp1, auxp2, plane); + auxtag3 = classifyFaceIN(p1, auxp2, p3, plane); + } + else { + auxtag2 = classifyFaceIN(p3, auxp1, auxp2, plane); + auxtag3 = classifyFaceIN(p1, auxp1, p3, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case OUT_OUT_IN : + auxp1 = BOP_intersectPlane(m_plane, p3, p1); + auxp2 = BOP_intersectPlane(m_plane, p3, p2); + + // f1: auxp1 auxp2 , auxp2 p3 + auxtag1 = classifyFaceIN(auxp1, auxp2, p3, plane); + + // f2: p1 p2 , p2 auxp2; f3:p1 auxp2 , auxp2 auxp1 || + // f2: p1 p2, p2 auxp1; f3:p2 auxp2, auxp2 auxp1 + if (BOP_isInsideCircle(p1, p2, auxp1, auxp2)) { + auxtag2 = classifyFaceOUT(p1, p2, auxp2, plane); + auxtag3 = classifyFaceOUT(p1, auxp2, auxp1, plane); + } + else { + auxtag2 = classifyFaceOUT(p1, p2, auxp1, plane); + auxtag3 = classifyFaceOUT(p2, auxp2, auxp1, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + case IN_IN_OUT : + auxp1 = BOP_intersectPlane(m_plane, p3, p1); + auxp2 = BOP_intersectPlane(m_plane, p3, p2); + + // f1: auxp1 auxp2 , auxp2 p3 + auxtag1 = classifyFaceOUT(auxp1, auxp2, p3, plane); + + // f2: p1 p2 , p2 auxp2; f3:p1 auxp2 , auxp2 auxp1 || + // f2: p1 p2, p2 auxp1; f3:p2 auxp2, auxp2 auxp1 + if (BOP_isInsideCircle(p1, p2, auxp1, auxp2)) { + auxtag2 = classifyFaceIN(p1, p2, auxp2, plane); + auxtag3 = classifyFaceIN(p1, auxp2, auxp1, plane); + } + else { + auxtag2 = classifyFaceIN(p1, p2, auxp1, plane); + auxtag3 = classifyFaceIN(p2, auxp2, auxp1, plane); + } + return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT); + + default: + return UNCLASSIFIED; + } +} + +/** + * Classifies a face through IN subtree. + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + */ +BOP_TAG BOP_BSPNode::classifyFaceIN(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if (m_inChild != NULL) + return m_inChild->classifyFace(p1, p2, p3, plane); + else + return IN; +} + +/** + * Classifies a face through OUT subtree. + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + */ +BOP_TAG BOP_BSPNode::classifyFaceOUT(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if (m_outChild != NULL) + return m_outChild->classifyFace(p1, p2, p3, plane); + else + return OUT; +} + +/** + * Simplified classification (optimized but requires that the face is not + * INOUT; only works correctly with faces completely IN or OUT). + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + * @return TAG result: IN or OUT. + */ +BOP_TAG BOP_BSPNode::simplifiedClassifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + MT_Point3 ret[3]; + + BOP_TAG tag = BOP_createTAG(testPoint(p1),testPoint(p2),testPoint(p3)); + + if ((tag & IN_IN_IN) != 0) { + if ((tag & OUT_OUT_OUT) != 0) { + if (splitTriangle(ret,m_plane,p1,p2,p3,tag)<0) + return simplifiedClassifyFaceIN(ret[0],ret[1],ret[2],plane); + else + return simplifiedClassifyFaceOUT(ret[0],ret[1],ret[2],plane); + } + else { + return simplifiedClassifyFaceIN(p1,p2,p3,plane); + } + } + else { + if ((tag & OUT_OUT_OUT) != 0) { + return simplifiedClassifyFaceOUT(p1,p2,p3,plane); + } + else { + if (hasSameOrientation(plane)) { + return simplifiedClassifyFaceIN(p1,p2,p3,plane); + } + else { + return simplifiedClassifyFaceOUT(p1,p2,p3,plane); + } + } + } + + return IN; +} + +/** + * Simplified classify through IN subtree. + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + */ +BOP_TAG BOP_BSPNode::simplifiedClassifyFaceIN(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if (m_inChild != NULL) + return m_inChild->simplifiedClassifyFace(p1, p2, p3, plane); + else + return IN; +} + +/** + * Simplified classify through OUT subtree. + * @param p1 firts face vertex. + * @param p2 second face vertex. + * @param p3 third face vertex. + * @param plane face plane. + */ +BOP_TAG BOP_BSPNode::simplifiedClassifyFaceOUT(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if (m_outChild != NULL) + return m_outChild->simplifiedClassifyFace(p1, p2, p3, plane); + else + return OUT; +} + +/** + * Determine if the input plane have the same orientation of the node plane. + * @param plane plane to test. + * @return TRUE if have the same orientation, FALSE otherwise. + */ +bool BOP_BSPNode::hasSameOrientation(const MT_Plane3& plane) const +{ + return (BOP_orientation(m_plane,plane)>0); +} + +/** + * Comparation between both childrens. + * @return 0 equal deep, 1 inChild more deep than outChild and -1 otherwise. + */ +int BOP_BSPNode::compChildren() const +{ + unsigned int deep1 = (m_inChild == NULL?0:m_inChild->getDeep()); + unsigned int deep2 = (m_outChild == NULL?0:m_outChild->getDeep()); + + if (deep1 == deep2) + return 0; + else if (deep1 < deep2) + return -1; + else + return 1; +} + +/** + * Extract a subtriangle from input triangle, is used for simplified classification. + * The subtriangle is obtained spliting the input triangle by input plane. + * @param res output subtriangle result. + * @param plane spliter plane. + * @param p1 first triangle point. + * @param p2 second triangle point. + * @param p3 third triangle point. + * @param tag triangle orientation respect the plane. + */ +int BOP_BSPNode::splitTriangle(MT_Point3* res, + const MT_Plane3& plane, + const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const BOP_TAG tag) const +{ + switch (tag) { + case IN_OUT_ON : + if (compChildren()<0) { + // f1: p1 new p3 || new = splitedge(p1,p2) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p1, p2 ); + res[2] = p3; + return -1; + }else{ + // f1: p2 new p3 || new = splitedge(p1,p2) + res[0] = p2; + res[1] = p3; + res[2] = BOP_intersectPlane( plane, p1, p2 ); + return 1; + } + case OUT_IN_ON : + if (compChildren()<0) { + // f1: p2 new p3 || new = splitedge(p1,p2) + res[0] = p2; + res[1] = p3; + res[2] = BOP_intersectPlane( plane, p1, p2 ); + return -1; + }else{ + // f1: p1 new p3 || new = splitedge(p1,p2) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p1, p2 ); + res[2] = p3; + return 1; + } + case IN_ON_OUT : + if (compChildren()<0) { + // f1: p1 p2 new || new = splitedge(p1,p3) + res[0] = p1; + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return -1; + }else{ + // f1: p2 p3 new || new = splitedge(p1,p3) + res[0] = p2; + res[1] = p3; + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return 1; + } + case OUT_ON_IN : + if (compChildren()<0) { + // f1: p2 p3 new || new = splitedge(p1,p3) + res[0] = p2; + res[1] = p3; + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return -1; + }else{ + // f1: p1 p2 new || new = splitedge(p1,p3) + res[0] = p1; + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return 1; + } + case ON_IN_OUT : + if (compChildren()<0) { + // f1: p1 p2 new || new = splitedge(p2,p3) + res[0] = p1; + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return -1; + }else{ + // f1: p1 p3 new || new = splitedge(p2,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p2, p3 ); + res[2] = p3; + return 1; + } + case ON_OUT_IN : + if (compChildren()<0) { + // f1: p1 p2 new || new = splitedge(p2,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p2, p3 ); + res[2] = p3; + return -1; + }else{ + // f1: p1 p2 new || new = splitedge(p2,p3) + res[0] = p1; + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return 1; + } + case IN_OUT_OUT : + if (compChildren()<=0) { + // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p1, p2 ); + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return -1; + }else{ + // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3) + res[0] = BOP_intersectPlane( plane, p1, p2 ); + res[1] = p2; + res[2] = p3; + return 1; + } + case OUT_IN_IN : + if (compChildren()<0) { + // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3) + res[0] = BOP_intersectPlane( plane, p1, p2 ); + res[1] = p2; + res[2] = p3; + return -1; + }else { + // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p1, p2 ); + res[2] = BOP_intersectPlane( plane, p1, p3 ); + return 1; + } + case OUT_IN_OUT : + if (compChildren()<=0) { + // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3) + res[0] = BOP_intersectPlane( plane, p2, p1 ); + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return -1; + }else { + // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p2, p1 ); + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return 1; + } + case IN_OUT_IN : + if (compChildren()<0) { + // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3) + res[0] = p1; + res[1] = BOP_intersectPlane( plane, p2, p1 ); + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return -1; + }else{ + // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3) + res[0] = BOP_intersectPlane( plane, p2, p1 ); + res[1] = p2; + res[2] = BOP_intersectPlane( plane, p2, p3 ); + return 1; + } + case OUT_OUT_IN : + if (compChildren()<=0) { + // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2) + res[0] = BOP_intersectPlane( plane, p3, p1 ); + res[1] = BOP_intersectPlane( plane, p3, p2 ); + res[2] = p3; + return -1; + }else{ + // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2) + res[0] = BOP_intersectPlane( plane, p3, p1 ); + res[1] = p1; + res[2] = p2; + return 1; + } + case IN_IN_OUT : + if (compChildren()<0) { + // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2) + res[0] = BOP_intersectPlane( plane, p3, p1 ); + res[1] = p1; + res[2] = p2; + return -1; + }else{ + // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2) + res[0] = BOP_intersectPlane( plane, p3, p1 ); + res[1] = BOP_intersectPlane( plane, p3, p2 ); + res[2] = p3; + return 1; + } + default: + return 0; + } +} + +/** + * Debug info. + */ +void BOP_BSPNode::print(unsigned int deep) +{ + cout << "(" << deep << "," << m_plane << ")," << endl; + if (m_inChild != NULL) + m_inChild->print(deep + 1); + else + cout << "(" << deep+1 << ",None)," << endl; + if (m_outChild != NULL) + m_outChild->print(deep + 1); + else + cout << "(" << deep+1 << ",None)," << endl; +} diff --git a/intern/boolop/intern/BOP_BSPNode.h b/intern/boolop/intern/BOP_BSPNode.h new file mode 100644 index 00000000000..39a84b94dec --- /dev/null +++ b/intern/boolop/intern/BOP_BSPNode.h @@ -0,0 +1,105 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_BSPNODE_H +#define BOP_BSPNODE_H + +#include "MT_Plane3.h" +#include "BOP_Tag.h" +#include "BOP_Face.h" + +typedef vector BOP_BSPPoints; +typedef vector::iterator BOP_IT_BSPPoints; + +class BOP_BSPNode +{ +protected: + BOP_BSPNode* m_inChild; + BOP_BSPNode* m_outChild; + MT_Plane3 m_plane; + unsigned int m_deep; + +public: + // Construction methods + BOP_BSPNode(const MT_Plane3& plane); + ~BOP_BSPNode(); + unsigned int addFace(BOP_BSPPoints pts, + const MT_Plane3& plane); + BOP_TAG classifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG simplifiedClassifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + +protected: + BOP_TAG testPoint(const MT_Point3& p) const; + BOP_TAG classifyFaceIN(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG classifyFaceOUT(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG simplifiedClassifyFaceIN(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG simplifiedClassifyFaceOUT(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + bool hasSameOrientation(const MT_Plane3& plane) const; + int compChildren() const; + int splitTriangle(MT_Point3* res, + const MT_Plane3& plane, + const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const BOP_TAG tag) const; + +public: + // Inline acces methods + inline void setInChild(BOP_BSPNode* inChild) { m_inChild=inChild; }; + inline void setOutChild(BOP_BSPNode* outChild) { m_outChild=outChild; }; + inline BOP_BSPNode* getInChild() { return m_inChild; }; + inline BOP_BSPNode* getOutChild() { return m_outChild; }; + inline bool isLeaf() const { return !m_inChild && !m_outChild; }; + inline void setPlane(const MT_Plane3& plane) {m_plane=plane;}; + inline MT_Plane3& getPlane() { return m_plane; }; + + inline unsigned int getDeep() const {return m_deep;}; + void print(unsigned int deep); +}; + +#endif diff --git a/intern/boolop/intern/BOP_BSPTree.cpp b/intern/boolop/intern/BOP_BSPTree.cpp new file mode 100644 index 00000000000..3ae375294cd --- /dev/null +++ b/intern/boolop/intern/BOP_BSPTree.cpp @@ -0,0 +1,189 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_BSPTree.h" +#include +#include +using namespace std; + +/** + * Constructs a new BSP tree. + */ +BOP_BSPTree::BOP_BSPTree() +{ + m_root = NULL; + m_bspBB = NULL; +} + +/** + * Destroys a BSP tree. + */ +BOP_BSPTree::~BOP_BSPTree() +{ + if (m_root!=NULL) delete m_root; + if (m_bspBB!=NULL) delete m_bspBB; +} + +/** + * Adds all mesh faces to BSP tree. + * @param mesh mesh to add. + * @param facesList face list to add. + */ +void BOP_BSPTree::addMesh(BOP_Mesh* mesh, BOP_Faces& facesList) +{ + for (BOP_IT_Faces it = facesList.begin(); it != facesList.end(); ++it) { + addFace( mesh, *it ); + } + +} + +/** + * Adds a new face into bsp tree. + * @param mesh Input data for BSP tree. + * @param face index to mesh face. + */ + +void BOP_BSPTree::addFace(BOP_Mesh* mesh, BOP_Face* face) +{ + addFace(mesh->getVertex(face->getVertex(0))->getPoint(), + mesh->getVertex(face->getVertex(1))->getPoint(), + mesh->getVertex(face->getVertex(2))->getPoint(), + face->getPlane()); +} + +/** + * Adds new facee to the bsp-tree. + * @param p1 first face point. + * @param p2 second face point. + * @param p3 third face point. + * @param plane face plane. + */ +void BOP_BSPTree::addFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) +{ + if (m_root == NULL) + m_root = new BOP_BSPNode(plane); + else { + BOP_BSPPoints pts; + + pts.push_back(p1); + pts.push_back(p2); + pts.push_back(p3); + + m_root->addFace(pts,plane); + } + + // update bounding box + m_bbox.add(p1); + m_bbox.add(p2); + m_bbox.add(p3); +} + +/** + * Tests face vs bsp-tree (returns where is the face respect bsp planes). + * @param p1 first face triangle point. + * @param p2 secons face triangle point. + * @param p3 third face triangle point. + * @param plane face plane. + * @return BSP_IN, BSP_OUT or BSP_IN_OUT + */ +BOP_TAG BOP_BSPTree::classifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if ( m_root != NULL ) + return m_root->classifyFace(p1, p2, p3, plane); + else + return OUT; +} + +/** + * Filters a face using the BSP bounding infomation. + * @param p1 first face triangle point. + * @param p2 secons face triangle point. + * @param p3 third face triangle point. + * @param face face to test. + * @return UNCLASSIFIED, BSP_IN, BSP_OUT or BSP_IN_OUT + */ +BOP_TAG BOP_BSPTree::filterFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + BOP_Face* face) +{ + if ( m_bspBB != NULL ) { + return m_bspBB->classifyFace(p1,p2,p3,face->getPlane()); + } + else + return UNCLASSIFIED; +} + +/** + * Tests face vs bsp-tree (returns where is the face respect bsp planes). + * @param p1 first face triangle point. + * @param p2 secons face triangle point. + * @param p3 third face triangle point. + * @param plane face plane. + * @return BSP_IN, BSP_OUT or BSP_IN_OUT + */ +BOP_TAG BOP_BSPTree::simplifiedClassifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const +{ + if ( m_root != NULL ) + return m_root->simplifiedClassifyFace(p1, p2, p3, plane); + else + return OUT; +} + +/** + * Returns the deep of this BSP tree. + * @return tree deep + */ +unsigned int BOP_BSPTree::getDeep() const +{ + if ( m_root != NULL ) + return m_root->getDeep(); + else + return 0; +} + +/** + * Prints debug information. + */ +void BOP_BSPTree::print() +{ + if ( m_root != NULL ) + m_root->print( 0 ); +} + diff --git a/intern/boolop/intern/BOP_BSPTree.h b/intern/boolop/intern/BOP_BSPTree.h new file mode 100644 index 00000000000..412d5a40753 --- /dev/null +++ b/intern/boolop/intern/BOP_BSPTree.h @@ -0,0 +1,74 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_BSPTREE_H +#define BOP_BSPTREE_H + +#include "BOP_BSPNode.h" +#include "BOP_Mesh.h" +#include "BOP_Tag.h" +#include "BOP_BBox.h" + +class BOP_BSPTree +{ +protected: + BOP_BSPNode* m_root; + BOP_BSPNode* m_bspBB; + BOP_BBox m_bbox; +public: + // Construction methods + BOP_BSPTree(); + virtual ~BOP_BSPTree(); + void addMesh(BOP_Mesh* mesh, BOP_Faces& facesList); + void addFace(BOP_Mesh* mesh, BOP_Face* face); + virtual void addFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane); + BOP_TAG classifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + BOP_TAG filterFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + BOP_Face* face); + BOP_TAG simplifiedClassifyFace(const MT_Point3& p1, + const MT_Point3& p2, + const MT_Point3& p3, + const MT_Plane3& plane) const; + unsigned int getDeep() const; + void print(); + inline void setRoot(BOP_BSPNode* root) {m_root=root;}; + inline BOP_BSPNode* getRoot() const {return m_root;}; +}; + +#endif + diff --git a/intern/boolop/intern/BOP_Chrono.h b/intern/boolop/intern/BOP_Chrono.h new file mode 100644 index 00000000000..5ce64f7a57c --- /dev/null +++ b/intern/boolop/intern/BOP_Chrono.h @@ -0,0 +1,52 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_CHRONO_H +#define BOP_CHRONO_H + +#include + +class BOP_Chrono +{ +private: + clock_t m_begin; +public: + BOP_Chrono(){}; + void start() {m_begin = clock();}; + float stamp() { + clock_t c = clock(); + clock_t stmp = c - m_begin; + m_begin = c; + float t = ((float) stmp / (float) CLOCKS_PER_SEC)*1000.0f; + return t; + }; +}; + +#endif diff --git a/intern/boolop/intern/BOP_Edge.cpp b/intern/boolop/intern/BOP_Edge.cpp new file mode 100644 index 00000000000..31411133878 --- /dev/null +++ b/intern/boolop/intern/BOP_Edge.cpp @@ -0,0 +1,81 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Edge.h" + +/** + * Constructs a new edge. + * @param v1 vertex index + * @param v2 vertex index + */ +BOP_Edge::BOP_Edge(BOP_Index v1, BOP_Index v2) +{ + m_vertexs[0] = v1; + m_vertexs[1] = v2; +} + +/** + * Adds a new face index to this edge. + * @param i face index + */ +void BOP_Edge::addFace(BOP_Index i) +{ + if (!containsFace(i)) + m_faces.push_back(i); +} + +/** + * Returns if this edge contains the specified face index. + * @param i face index + * @return true if this edge contains the specified face index, false otherwise + */ +bool BOP_Edge::containsFace(BOP_Index i) +{ + int pos=0; + for(BOP_IT_Indexs it = m_faces.begin();it!=m_faces.end();pos++,it++) { + if ((*it) == i) + return true; + } + + return false; +} + +/** + * Replaces an edge vertex index. + * @param oldIndex old vertex index + * @param newIndex new vertex index + */ +void BOP_Edge::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) +{ + if (m_vertexs[0] == oldIndex) m_vertexs[0] = newIndex; + else if (m_vertexs[1] == oldIndex) m_vertexs[1] = newIndex; +} + + diff --git a/intern/boolop/intern/BOP_Edge.h b/intern/boolop/intern/BOP_Edge.h new file mode 100644 index 00000000000..abf5dd0a8c8 --- /dev/null +++ b/intern/boolop/intern/BOP_Edge.h @@ -0,0 +1,55 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_EDGE_H +#define BOP_EDGE_H + +#include "BOP_Indexs.h" + +class BOP_Edge +{ +private: + BOP_Index m_vertexs[2]; + BOP_Indexs m_faces; + + bool containsFace(BOP_Index i); + +public: + BOP_Edge(BOP_Index v1, BOP_Index v2); + inline BOP_Index getVertex1() { return m_vertexs[0];}; + inline BOP_Index getVertex2() { return m_vertexs[1];}; + void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex); + inline BOP_Index getFace(unsigned int i){return m_faces[i];}; + inline unsigned int getNumFaces(){return m_faces.size();}; + inline BOP_Indexs &getFaces(){return m_faces;}; + void addFace(BOP_Index face); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Face.cpp b/intern/boolop/intern/BOP_Face.cpp new file mode 100644 index 00000000000..ebe34237d4f --- /dev/null +++ b/intern/boolop/intern/BOP_Face.cpp @@ -0,0 +1,426 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Face.h" + +/******************************************************************************/ +/*** BOP_Face ***/ +/******************************************************************************/ + +/** + * Constructs a new face. + * @param plane face plane + * @param originalFace index of the original face + */ +BOP_Face::BOP_Face(MT_Plane3 plane, BOP_Index originalFace) +{ + m_plane = plane; + m_tag = UNCLASSIFIED; + m_originalFace = originalFace; + m_split = 0; + m_bbox = NULL; +} + +/** + * Inverts this face. + */ +void BOP_Face::invert() +{ + getPlane().Invert(); + BOP_Index aux = m_indexs[0]; + m_indexs[0] = m_indexs[2]; + m_indexs[2] = aux; +} + +/******************************************************************************/ +/*** BOP_Face ***/ +/******************************************************************************/ + +/** + * Constructs a new triangle face. + * @param v1 vertex index + * @param v2 vertex index + * @param v3 vertex index + * @param plane face plane + * @param originalFace index of the original face + */ +BOP_Face3::BOP_Face3(BOP_Index v1, BOP_Index v2, BOP_Index v3, MT_Plane3 plane, BOP_Index originalFace): BOP_Face(plane,originalFace) +{ + m_indexs[0] = v1; + m_indexs[1] = v2; + m_indexs[2] = v3; + m_size = 3; +} + +/** + * Returns the relative edge index (1,2,3) for the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param e relative edge index (1,2,3) + * @return true if (v1,v2) is an edge of this face, false otherwise + */ +bool BOP_Face3::getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e) +{ + if (m_indexs[0] == v1) { + if (m_indexs[1] == v2) { + e = 1; + } + else if (m_indexs[2] == v2) { + e = 3; + } + else + return false; + } + else if (m_indexs[1] == v1) { + if (m_indexs[0] == v2) { + e = 1; + } + else if (m_indexs[2] == v2) { + e = 2; + } + else + return false; + } + else if (m_indexs[2] == v1) { + if (m_indexs[0] == v2) { + e = 3; + } + else if (m_indexs[1] == v2) { + e = 2; + } + else + return false; + }else { + return false; + } + + return true; +} + +/** + * Returns if this face contains the specified vertex index. + * @param v vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face3::containsVertex(BOP_Index v) +{ + return (m_indexs[0] == v || m_indexs[1] == v || m_indexs[2] == v); +} + +/** + * Returns the neighbours of the specified vertex index. + * @param v vertex index + * @param prev previous vertex index + * @param next next vertex index + * @return true if this face contains the vertex index v, false otherwise + */ +bool BOP_Face3::getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next) +{ + if (m_indexs[0] == v) { + prev = m_indexs[2]; + next = m_indexs[1]; + } + else if (m_indexs[1] == v) { + prev = m_indexs[0]; + next = m_indexs[2]; + } + else if (m_indexs[2] == v) { + prev = m_indexs[1]; + next = m_indexs[0]; + } + else return false; + + return true; +} + +/** + * Returns the previous neighbour of the specified vertex index. + * @param v vertex index + * @param w previous vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face3::getPreviousVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) w = m_indexs[2]; + else if (m_indexs[1] == v) w = m_indexs[0]; + else if (m_indexs[2] == v) w = m_indexs[1]; + else return false; + + return true; +} + +/** + * Returns the next neighbour of the specified vertex index. + * @param v vertex index + * @param w vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face3::getNextVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) w = m_indexs[1]; + else if (m_indexs[1] == v) w = m_indexs[2]; + else if (m_indexs[2] == v) w = m_indexs[0]; + else return false; + + return true; +} + +/** + * Replaces a face vertex index. + * @param oldIndex old vertex index + * @param newIndex new vertex index + */ +void BOP_Face3::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) +{ + /* if the old index really exists, and new index also exists already, + * don't create an edge with both vertices == newIndex */ + + if( (m_indexs[0] == oldIndex || m_indexs[1] == oldIndex || m_indexs[2] == oldIndex) && + (m_indexs[0] == newIndex || m_indexs[1] == newIndex || m_indexs[2] == newIndex) ) { + setTAG(BROKEN); + } + + if (m_indexs[0] == oldIndex) m_indexs[0] = newIndex; + else if (m_indexs[1] == oldIndex) m_indexs[1] = newIndex; + else if (m_indexs[2] == oldIndex) m_indexs[2] = newIndex; +} + +/******************************************************************************/ +/*** BOP_Face4 ***/ +/******************************************************************************/ + +/** + * Constructs a new quad face. + * @param v1 vertex index + * @param v2 vertex index + * @param v3 vertex index + * @param v4 vertex index + * @param plane face plane + * @param originalFace index of the original face + */ +BOP_Face4::BOP_Face4(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, MT_Plane3 plane, + BOP_Index originalFace): + BOP_Face(plane,originalFace) +{ + m_indexs[0] = v1; + m_indexs[1] = v2; + m_indexs[2] = v3; + m_indexs[3] = v4; + + m_size = 4; +} + +/** + * Returns if this face contains the specified vertex index. + * @param v vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face4::containsVertex(BOP_Index v) +{ + return (m_indexs[0] == v || m_indexs[1] == v || m_indexs[2] == v || m_indexs[3]==v); +} + +/** + * Returns the neighbours of the specified vertex index. + * @param v vertex index + * @param prev previous vertex index + * @param next next vertex index + * @param opp opposite vertex index + * @return true if this face contains the vertex index v, false otherwise + */ +bool BOP_Face4::getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next, BOP_Index &opp) +{ + if (m_indexs[0] == v) { + prev = m_indexs[3]; + next = m_indexs[1]; + opp = m_indexs[2]; + } + else if (m_indexs[1] == v) { + prev = m_indexs[0]; + next = m_indexs[2]; + opp = m_indexs[3]; + } + else if (m_indexs[2] == v) { + prev = m_indexs[1]; + next = m_indexs[3]; + opp = m_indexs[0]; + } + else if (m_indexs[3] == v) { + prev = m_indexs[2]; + next = m_indexs[0]; + opp = m_indexs[1]; + } + else return false; + + return true; +} + +/** + * Returns the previous neighbour of the specified vertex index. + * @param v vertex index + * @param w previous vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face4::getPreviousVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) w = m_indexs[3]; + else if (m_indexs[1] == v) w = m_indexs[0]; + else if (m_indexs[2] == v) w = m_indexs[1]; + else if (m_indexs[3] == v) w = m_indexs[2]; + else return false; + + return true; +} + +/** + * Returns the next neighbour of the specified vertex index. + * @param v vertex index + * @param w next vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face4::getNextVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) w = m_indexs[1]; + else if (m_indexs[1] == v) w = m_indexs[2]; + else if (m_indexs[2] == v) w = m_indexs[3]; + else if (m_indexs[3] == v) w = m_indexs[0]; + else return false; + + return true; +} + +/** + * Returns the opposite neighbour of the specified vertex index. + * @param v vertex index + * @param w opposite vertex index + * @return true if this face contains the specified vertex index, false otherwise + */ +bool BOP_Face4::getOppositeVertex(BOP_Index v, BOP_Index &w) +{ + if (m_indexs[0] == v) + w = m_indexs[2]; + else if (m_indexs[1] == v) + w = m_indexs[3]; + else if (m_indexs[2] == v) + w = m_indexs[0]; + else if (m_indexs[3] == v) + w = m_indexs[1]; + else + return false; + + return true; +} + +/** + * Replaces a face vertex index. + * @param oldIndex old vertex index + * @param newIndex new vertex index + */ +void BOP_Face4::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) +{ + if (m_indexs[0] == oldIndex) m_indexs[0] = newIndex; + else if (m_indexs[1] == oldIndex) m_indexs[1] = newIndex; + else if (m_indexs[2] == oldIndex) m_indexs[2] = newIndex; + else if (m_indexs[3] == oldIndex) m_indexs[3] = newIndex; +} + +/** + * Returns the relative edge index (1,2,3,4) for the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param e relative edge index (1,2,3,4) + * @return true if (v1,v2) is an edge of this face, false otherwise + */ +bool BOP_Face4::getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e) +{ + if (m_indexs[0] == v1) { + if (m_indexs[1] == v2) { + e = 1; + } + else if (m_indexs[3] == v2) { + e = 4; + } + else + return false; + } + else if (m_indexs[1] == v1) { + if (m_indexs[0] == v2) { + e = 1; + } + else if (m_indexs[2] == v2) { + e = 2; + } + else + return false; + } + else if (m_indexs[2] == v1) { + if (m_indexs[1] == v2) { + e = 2; + } + else if (m_indexs[3] == v2) { + e = 3; + } + else + return false; + } + else if (m_indexs[3] == v1) { + if (m_indexs[2] == v2) { + e = 3; + } + else if (m_indexs[0] == v2) { + e = 4; + } + else + return false; + } + else return false; + + return true; +} + +/** + * Implements operator <<. + */ +ostream &operator<<(ostream &stream, BOP_Face *f) +{ + char aux[20]; + BOP_stringTAG(f->m_tag,aux); + if (f->size()==3) { + stream << "Face[" << f->getVertex(0) << "," << f->getVertex(1) << ","; + stream << f->getVertex(2) << "] (" << aux << ") <-- " << f->m_originalFace; + } + else { + stream << "Face[" << f->getVertex(0) << "," << f->getVertex(1) << ","; + stream << f->getVertex(2) << "," << f->getVertex(3) << "] (" << aux; + stream << ") <-- " << f->m_originalFace; + } + + return stream; +} diff --git a/intern/boolop/intern/BOP_Face.h b/intern/boolop/intern/BOP_Face.h new file mode 100644 index 00000000000..1d854ec00ca --- /dev/null +++ b/intern/boolop/intern/BOP_Face.h @@ -0,0 +1,116 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_FACE_H +#define BOP_FACE_H + +#include "BOP_Tag.h" +#include "MT_Plane3.h" +#include "BOP_Indexs.h" +#include "BOP_BBox.h" +#include +#include +using namespace std; + +class BOP_Face; + +typedef vector BOP_Faces; +typedef vector::iterator BOP_IT_Faces; + +class BOP_Face +{ +private: + BOP_TAG m_tag; + MT_Plane3 m_plane; + BOP_Index m_originalFace; + +protected: + BOP_Index m_indexs[4]; + unsigned int m_size; + unsigned int m_split; + BOP_BBox *m_bbox; + +public: + BOP_Face(MT_Plane3 plane, BOP_Index originalFace); + virtual ~BOP_Face(){if (m_bbox) delete m_bbox;}; + inline MT_Plane3 getPlane() const {return m_plane;}; + inline void setPlane(const MT_Plane3 plane) {m_plane = plane;}; + inline BOP_TAG getTAG() const {return m_tag;}; + inline void setTAG(const BOP_TAG t) {m_tag = t;}; + inline BOP_Index getOriginalFace() const {return m_originalFace;}; + inline void setOriginalFace(const BOP_Index originalFace) {m_originalFace=originalFace;}; + inline BOP_Index getVertex(unsigned int i) const {return m_indexs[i];}; + inline void setVertex(const BOP_Index idx, const BOP_Index i) {m_indexs[idx]=i;}; + inline unsigned int getSplit() const {return m_split;}; + inline void setSplit(const unsigned int i) {m_split=i;}; + + void invert(); + inline void setBBox(const MT_Point3& p1,const MT_Point3& p2,const MT_Point3& p3) { + m_bbox = new BOP_BBox(p1, p2, p3);}; + inline BOP_BBox *getBBox() {return m_bbox;}; + inline void freeBBox(){if (m_bbox!=NULL) {delete m_bbox; m_bbox=NULL;} }; + + inline unsigned int size() const {return m_size;}; + + virtual bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e) = 0; + virtual void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) = 0; + virtual bool containsVertex(BOP_Index v) = 0; + + friend ostream &operator<<(ostream &stream, BOP_Face *f); +}; + +class BOP_Face3: public BOP_Face +{ +public: + BOP_Face3(BOP_Index i, BOP_Index j, BOP_Index k, MT_Plane3 p, BOP_Index originalFace); + bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e); + void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex); + bool containsVertex(BOP_Index v); + + bool getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next); + bool getPreviousVertex(BOP_Index v, BOP_Index &w); + bool getNextVertex(BOP_Index v, BOP_Index &w); +}; + +class BOP_Face4: public BOP_Face +{ +public: + BOP_Face4(BOP_Index i, BOP_Index j, BOP_Index k, BOP_Index l, MT_Plane3 p, BOP_Index originalFace); + bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e); + void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex); + bool containsVertex(BOP_Index v); + + bool getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next, BOP_Index &opp); + bool getPreviousVertex(BOP_Index v, BOP_Index &w); + bool getNextVertex(BOP_Index v, BOP_Index &w); + bool getOppositeVertex(BOP_Index v, BOP_Index &w); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Face2Face.cpp b/intern/boolop/intern/BOP_Face2Face.cpp new file mode 100644 index 00000000000..ef67e5dd24b --- /dev/null +++ b/intern/boolop/intern/BOP_Face2Face.cpp @@ -0,0 +1,1245 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Marc Freixas, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Face2Face.h" +#include "BOP_BBox.h" + +// TAGS for segment classification in x-segment creation +// sA -> point of sA +// sB -> point of sB +// sX -> point of sA and SB +#define sA_sB 12 +#define sB_sA 21 +#define sX_sA 31 +#define sA_sX 13 +#define sX_sB 32 +#define sB_sX 23 +#define sX_sX 33 + +#define sA_sA_sB 112 +#define sB_sB_sA 221 +#define sB_sA_sA 211 +#define sA_sB_sB 122 +#define sA_sB_sA 121 +#define sB_sA_sB 212 +#define sA_sX_sB 132 +#define sB_sX_sA 231 +#define sX_sA_sB 312 +#define sX_sB_sA 321 +#define sA_sB_sX 123 +#define sB_sA_sX 213 + +#define sA_sA_sB_sB 1122 +#define sB_sB_sA_sA 2211 +#define sA_sB_sA_sB 1212 +#define sB_sA_sB_sA 2121 +#define sA_sB_sB_sA 1221 +#define sB_sA_sA_sB 2112 + +void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesB, + BOP_Face* faceA, + BOP_Face* faceB, + bool invert); + +void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesB, + BOP_Face* faceB, + BOP_Segment sA, + MT_Plane3 planeA, + bool invert); + +void BOP_intersectNonCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesA, + BOP_Faces* facesB, + BOP_Face* faceA, + BOP_Face* faceB); + +void BOP_getPoints(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Segment& sA, + MT_Plane3 planeB, + MT_Point3* points, + unsigned int* faces, + unsigned int& size, + unsigned int faceValue); + +void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bool &invertA, bool &invertB); + +void BOP_createXS(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Face* faceB, + BOP_Segment sA, + BOP_Segment sB, + bool invert, + BOP_Segment* segments); + +void BOP_createXS(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Face* faceB, + MT_Plane3 planeA, + MT_Plane3 planeB, + BOP_Segment sA, + BOP_Segment sB, + bool invert, + BOP_Segment* segments); + +BOP_Index BOP_getVertexIndex(BOP_Mesh* mesh, + MT_Point3 point, + unsigned int cfgA, + unsigned int cfgB, + BOP_Index vA, + BOP_Index vB, + bool invert); + +BOP_Index BOP_getVertexIndex(BOP_Mesh *mesh, MT_Point3 point, unsigned int cfg, BOP_Index v); + +void triangulate(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face *face, BOP_Segment s); + +BOP_Face *BOP_getOppositeFace(BOP_Mesh* mesh, + BOP_Faces* faces, + BOP_Face* face, + BOP_Edge* edge); + +bool BOP_overlap(MT_Vector3 normal, + MT_Point3 p1, + MT_Point3 p2, + MT_Point3 p3, + MT_Point3 q1, + MT_Point3 q2, + MT_Point3 q3); + +void BOP_mergeVertexs(BOP_Mesh *mesh, unsigned int firstFace); + + +/** + * Computes intersections between faces of both lists. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesA set of faces from object A + * @param facesB set of faces from object B + * + * Two optimizations were added here: + * 1) keep the bounding box for a face once it's created; this is + * especially important for B faces, since they were being created and + * recreated over and over + * 2) associate a "split" index in the faceB vector with each A face; when + * an A face is split, we will not need to recheck any B faces have + * already been checked against that original A face + */ + +void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) +{ + for(unsigned int idxFaceA=0;idxFaceAsize();idxFaceA++) { + BOP_Face *faceA = (*facesA)[idxFaceA]; + MT_Plane3 planeA = faceA->getPlane(); + MT_Point3 p1 = mesh->getVertex(faceA->getVertex(0))->getPoint(); + MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint(); + MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint(); + + /* get (or create) bounding box for face A */ + if( faceA->getBBox() == NULL ) + faceA->setBBox(p1,p2,p3); + BOP_BBox *boxA = faceA->getBBox(); + + /* start checking B faces with the previously stored split index */ + + for(unsigned int idxFaceB=faceA->getSplit(); + idxFaceBsize() && (faceA->getTAG() != BROKEN) && (faceA->getTAG() != PHANTOM);) { + BOP_Face *faceB = (*facesB)[idxFaceB]; + faceA->setSplit(idxFaceB); + if ((faceB->getTAG() != BROKEN) && (faceB->getTAG() != PHANTOM)) { + + /* get (or create) bounding box for face B */ + if( faceB->getBBox() == NULL ) + faceB->setBBox(mesh->getVertex(faceB->getVertex(0))->getPoint(), + mesh->getVertex(faceB->getVertex(1))->getPoint(), + mesh->getVertex(faceB->getVertex(2))->getPoint()); + BOP_BBox *boxB = faceB->getBBox(); + + if (boxA->intersect(*boxB)) { + MT_Plane3 planeB = faceB->getPlane(); + if (BOP_containsPoint(planeB,p1) && + BOP_containsPoint(planeB,p2) && + BOP_containsPoint(planeB,p3)) { + if (BOP_orientation(planeB,planeA)>0) { + BOP_intersectCoplanarFaces(mesh,facesB,faceA,faceB,false); + } + } + else { + BOP_intersectNonCoplanarFaces(mesh,facesA,facesB,faceA,faceB); + } + } + } + idxFaceB++; + } + } + + + // Clean broken faces from facesA + BOP_IT_Faces it; + it = facesA->begin(); + while (it != facesA->end()) { + BOP_Face *face = *it; + if (face->getTAG() == BROKEN) it = facesA->erase(it); + else it++; + } + /* + it = facesB->begin(); + while (it != facesB->end()) { + BOP_Face *face = *it; + if (face->getTAG() == BROKEN) it = facesB->erase(it); + else it++; + } + */ +} + +/** + * Computes intesections of coplanars faces from object A with faces from object B. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesA set of faces from object A + * @param facesB set of faces from object B + */ +void BOP_sew(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) +{ + for(unsigned int idxFaceB = 0; idxFaceB < facesB->size(); idxFaceB++) { + BOP_Face *faceB = (*facesB)[idxFaceB]; + MT_Plane3 planeB = faceB->getPlane(); + MT_Point3 p1 = mesh->getVertex(faceB->getVertex(0))->getPoint(); + MT_Point3 p2 = mesh->getVertex(faceB->getVertex(1))->getPoint(); + MT_Point3 p3 = mesh->getVertex(faceB->getVertex(2))->getPoint(); + + for(unsigned int idxFaceA = 0; + idxFaceA < facesA->size() && + faceB->getTAG() != BROKEN && + faceB->getTAG() != PHANTOM; + idxFaceA++) { + BOP_Face *faceA = (*facesA)[idxFaceA]; + if ((faceA->getTAG() != BROKEN)&&(faceA->getTAG() != PHANTOM)) { + MT_Plane3 planeA = faceA->getPlane(); + if (BOP_containsPoint(planeA,p1) && + BOP_containsPoint(planeA,p2) && + BOP_containsPoint(planeA,p3)) { + if (BOP_orientation(planeA,planeB) > 0) { + BOP_intersectCoplanarFaces(mesh,facesA,faceB,faceA,true); + } + } + } + } + } +} + +/** + * Triangulates faceB using edges of faceA that both are complanars. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesB set of faces from object B + * @param faceA face from object A + * @param faceB face from object B + * @param invert indicates if faceA has priority over faceB + */ +void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesB, + BOP_Face* faceA, + BOP_Face* faceB, + bool invert) +{ + unsigned int oldSize = facesB->size(); + unsigned int originalFaceB = faceB->getOriginalFace(); + + MT_Point3 p1 = mesh->getVertex(faceA->getVertex(0))->getPoint(); + MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint(); + MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint(); + + MT_Vector3 normal(faceA->getPlane().x(),faceA->getPlane().y(),faceA->getPlane().z()); + + MT_Vector3 p1p2 = p2-p1; + + MT_Plane3 plane1((p1p2.cross(normal).normalized()),p1); + + BOP_Segment sA; + sA.m_cfg1 = BOP_Segment::createVertexCfg(1); + sA.m_v1 = faceA->getVertex(0); + sA.m_cfg2 = BOP_Segment::createVertexCfg(2); + sA.m_v2 = faceA->getVertex(1); + + BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane1,invert); + + MT_Vector3 p2p3 = p3-p2; + MT_Plane3 plane2((p2p3.cross(normal).normalized()),p2); + + sA.m_cfg1 = BOP_Segment::createVertexCfg(2); + sA.m_v1 = faceA->getVertex(1); + sA.m_cfg2 = BOP_Segment::createVertexCfg(3); + sA.m_v2 = faceA->getVertex(2); + + if (faceB->getTAG() == BROKEN) { + for(unsigned int idxFace = oldSize; idxFace < facesB->size(); idxFace++) { + BOP_Face *face = (*facesB)[idxFace]; + if (face->getTAG() != BROKEN && originalFaceB == face->getOriginalFace()) + BOP_intersectCoplanarFaces(mesh,facesB,face,sA,plane2,invert); + } + } + else { + BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane2,invert); + } + + MT_Vector3 p3p1 = p1-p3; + MT_Plane3 plane3((p3p1.cross(normal).normalized()),p3); + + sA.m_cfg1 = BOP_Segment::createVertexCfg(3); + sA.m_v1 = faceA->getVertex(2); + sA.m_cfg2 = BOP_Segment::createVertexCfg(1); + sA.m_v2 = faceA->getVertex(0); + + if (faceB->getTAG() == BROKEN) { + for(unsigned int idxFace = oldSize; idxFace < facesB->size(); idxFace++) { + BOP_Face *face = (*facesB)[idxFace]; + if (face->getTAG() != BROKEN && originalFaceB == face->getOriginalFace()) + BOP_intersectCoplanarFaces(mesh,facesB,face,sA,plane3,invert); + } + } + else { + BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane3,invert); + } +} + +/** + * Triangulates faceB using segment sA and planeA. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesB set of faces from object B + * @param faceB face from object B + * @param sA segment to intersect with faceB + * @param planeA plane to intersect with faceB + * @param invert indicates if sA has priority over faceB + */ +void BOP_intersectCoplanarFaces(BOP_Mesh* mesh, + BOP_Faces* facesB, + BOP_Face* faceB, + BOP_Segment sA, + MT_Plane3 planeA, + bool invert) +{ + BOP_Segment sB = BOP_splitFace(planeA,mesh,faceB); + + if (BOP_Segment::isDefined(sB.m_cfg1)) { + BOP_Segment xSegment[2]; + BOP_createXS(mesh,NULL,faceB,planeA,MT_Plane3(),sA,sB,invert,xSegment); + if (BOP_Segment::isDefined(xSegment[1].m_cfg1)) { + unsigned int sizefaces = mesh->getNumFaces(); + triangulate(mesh,facesB,faceB,xSegment[1]); + BOP_mergeVertexs(mesh,sizefaces); + } + } +} + +/** + * Triangulates faceB using edges of faceA that both are not complanars. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesB set of faces from object B + * @param faceA face from object A + * @param faceB face from object B + */ +void BOP_intersectNonCoplanarFaces(BOP_Mesh *mesh, + BOP_Faces *facesA, + BOP_Faces *facesB, + BOP_Face *faceA, + BOP_Face *faceB) +{ + // Obtain segments of faces A and B from the intersection with their planes + BOP_Segment sA = BOP_splitFace(faceB->getPlane(),mesh,faceA); + BOP_Segment sB = BOP_splitFace(faceA->getPlane(),mesh,faceB); + + if (BOP_Segment::isDefined(sA.m_cfg1) && BOP_Segment::isDefined(sB.m_cfg1)) { + // There is an intesection, build the X-segment + BOP_Segment xSegment[2]; + BOP_createXS(mesh,faceA,faceB,sA,sB,false,xSegment); + + unsigned int sizefaces = mesh->getNumFaces(); + triangulate(mesh,facesA,faceA,xSegment[0]); + BOP_mergeVertexs(mesh,sizefaces); + + sizefaces = mesh->getNumFaces(); + triangulate(mesh,facesB,faceB,xSegment[1]); + BOP_mergeVertexs(mesh,sizefaces); + } +} + +/** + * Tests if faces since firstFace have all vertexs non-coincident of colinear, otherwise repairs the mesh. + * @param mesh mesh that contains the faces, edges and vertices + * @param firstFace first face index to be tested + */ +void BOP_mergeVertexs(BOP_Mesh *mesh, unsigned int firstFace) +{ + unsigned int numFaces = mesh->getNumFaces(); + for(unsigned int idxFace = firstFace; idxFace < numFaces; idxFace++) { + BOP_Face *face = mesh->getFace(idxFace); + if ((face->getTAG() != BROKEN) && (face->getTAG() != PHANTOM)) { + MT_Point3 vertex1 = mesh->getVertex(face->getVertex(0))->getPoint(); + MT_Point3 vertex2 = mesh->getVertex(face->getVertex(1))->getPoint(); + MT_Point3 vertex3 = mesh->getVertex(face->getVertex(2))->getPoint(); + if (BOP_collinear(vertex1,vertex2,vertex3)) // collinear triangle + face->setTAG(PHANTOM); + } + } +} + +/** + * Obtains the points of the segment created from the intersection between faceA and planeB. + * @param mesh mesh that contains the faces, edges and vertices + * @param faceA intersected face + * @param sA segment of the intersection between faceA and planeB + * @param planeB intersected plane + * @param points array of points where the new points are saved + * @param faces array of relative face index to the points + * @param size size of arrays points and faces + * @param faceValue relative face index of new points + */ +void BOP_getPoints(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Segment& sA, + MT_Plane3 planeB, + MT_Point3* points, + unsigned int* faces, + unsigned int& size, + unsigned int faceValue) +{ + MT_Point3 p1,p2; + + if (BOP_Segment::isDefined(sA.m_cfg1)) { + if (BOP_Segment::isEdge(sA.m_cfg1)) { + // the new point becomes of split faceA edge + p1 = BOP_splitEdge(planeB,mesh,faceA,BOP_Segment::getEdge(sA.m_cfg1)); + } + else if (BOP_Segment::isVertex(sA.m_cfg1)) { + // the new point becomes of vertex faceA + p1 = mesh->getVertex(BOP_Segment::getVertex(sA.m_v1))->getPoint(); + } + + if (BOP_Segment::isDefined(sA.m_cfg2)) { + if (BOP_Segment::isEdge(sA.m_cfg2)) { + p2 = BOP_splitEdge(planeB,mesh,faceA,BOP_Segment::getEdge(sA.m_cfg2)); + } + else if (BOP_Segment::isVertex(sA.m_cfg2)) { + p2 = mesh->getVertex(BOP_Segment::getVertex(sA.m_v2))->getPoint(); + } + points[size] = p1; + points[size+1] = p2; + faces[size] = faceValue; + faces[size+1] = faceValue; + size += 2; + } + + else { + points[size] = p1; + faces[size] = faceValue; + size++; + } + } +} + +/** + * Sorts the colinear points and relative face indices. + * @param points array of points where the new points are saved + * @param faces array of relative face index to the points + * @param size size of arrays points and faces + * @param invertA indicates if points of same relative face had been exchanged + */ +void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bool &invertA, bool &invertB) { + MT_Point3 sortedPoints[4]; + unsigned int sortedFaces[4], position[4]; + unsigned int i; + if (size == 2) { + + // Trivial case, only test the merge ... + if (BOP_fuzzyZero(points[0].distance(points[1]))) { + face[0] = 3; + size--; + } + } + else { + // size is 3 or 4 + // Get segment extreme points + MT_Scalar maxDistance = -1; + for(i=0;i maxDistance){ + maxDistance = distance; + position[0] = i; + position[size-1] = j; + } + } + } + + // Get segment inner points + position[1] = position[2] = size; + for(i=0;i d2) { + unsigned int aux = position[1]; + position[1] = position[2]; + position[2] = aux; + } + } + + // Sort data + for(i=0;i 0 && sB.m_cfg1 > 0 . + * @param mesh mesh that contains the faces, edges and vertices + * @param faceA face of object A + * @param faceB face of object B + * @param sA segment of intersection between faceA and planeB + * @param sB segment of intersection between faceB and planeA + * @param invert indicates if faceA has priority over faceB + * @param segmemts array of the output x-segments + */ + void BOP_createXS(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Face* faceB, + BOP_Segment sA, + BOP_Segment sB, + bool invert, + BOP_Segment* segments) { + BOP_createXS(mesh, faceA, faceB, faceA->getPlane(), faceB->getPlane(), + sA, sB, invert, segments); + } + +/** + * Computes the x-segment of two segments (the shared interval). The segments needs to have sA.m_cfg1 > 0 && sB.m_cfg1 > 0 . + * @param mesh mesh that contains the faces, edges and vertices + * @param faceA face of object A + * @param faceB face of object B + * @param planeA plane of faceA + * @param planeB plane of faceB + * @param sA segment of intersection between faceA and planeB + * @param sB segment of intersection between faceB and planeA + * @param invert indicates if faceA has priority over faceB + * @param segmemts array of the output x-segments + */ +void BOP_createXS(BOP_Mesh* mesh, + BOP_Face* faceA, + BOP_Face* faceB, + MT_Plane3 planeA, + MT_Plane3 planeB, + BOP_Segment sA, + BOP_Segment sB, + bool invert, + BOP_Segment* segments) +{ + MT_Point3 points[4]; // points of the segments + unsigned int face[4]; // relative face indexs (1 => faceA, 2 => faceB) + unsigned int size = 0; // size of points and relative face indexs + + BOP_getPoints(mesh, faceA, sA, planeB, points, face, size, 1); + BOP_getPoints(mesh, faceB, sB, planeA, points, face, size, 2); + + bool invertA = false; + bool invertB = false; + BOP_mergeSort(points,face,size,invertA,invertB); + + if (invertA) sA.invert(); + if (invertB) sB.invert(); + + // Compute the configuration label + unsigned int label = 0; + for(unsigned int i =0; i < size; i++) { + label = face[i]+label*10; + } + + if (size == 1) { + // Two coincident points + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + segments[0].m_cfg2 = segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + } + else if (size == 2) { + switch(label) { + // Two non-coincident points + case sA_sB: + case sB_sA: + segments[0].m_cfg1 = + segments[1].m_cfg1 = + segments[0].m_cfg2 = + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + // Two coincident points and one non-coincident of sA + case sA_sX: + segments[0].m_cfg1 = sA.m_cfg2; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg1, + sA.m_v2, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + case sX_sA: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + // Two coincident points and one non-coincident of sB + case sB_sX: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg2; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg1, sB.m_cfg2, + sA.m_v1, sB.m_v2, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + case sX_sB: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + // coincident points 2-2 + case sX_sX: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg2, + sA.m_v2, sB.m_v2, invert); + segments[1].m_v2 = segments[0].m_v2; + break; + + default: + break; + } + } + else if (size == 3) { + switch(label) { + case sA_sA_sB: + case sB_sA_sA: + case sA_sB_sB: + case sB_sB_sA: + segments[0].m_cfg1 = + segments[1].m_cfg1 = + segments[0].m_cfg2 = + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case sA_sB_sA: + segments[1].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1); + segments[1].m_cfg1 = sB.m_cfg1; + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[0].m_cfg1 = sA.getConfig(); + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[0].m_v1 = segments[1].m_v1; + break; + + case sB_sA_sB: + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1); + segments[0].m_cfg1 = sA.m_cfg1; + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg1 = sB.getConfig(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_v1 = segments[0].m_v1; + break; + + case sA_sX_sB: + segments[0].m_cfg1 = sA.m_cfg2; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg1, + sA.m_v2, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case sB_sX_sA: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg2; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg1, sB.m_cfg2, + sA.m_v1, sB.m_v2, invert); + segments[1].m_v1 = segments[0].m_v1; + segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg(); + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case sX_sA_sB: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.getConfig(); + segments[0].m_v2 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sA.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sX_sB_sA: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, + sA.m_v1, sB.m_v1, invert); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.getConfig(); + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg2,sB.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sA_sB_sX: + segments[0].m_cfg1 = sA.getConfig(); + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh, points[2], sA.m_cfg2, sB.m_cfg2, + sA.m_v2, sB.m_v2, invert); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sB_sA_sX: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.getConfig(); + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh, points[2], sA.m_cfg2, sB.m_cfg2, + sA.m_v2, sB.m_v2, invert); + segments[1].m_v2 = segments[0].m_v2; + break; + + default: + break; + } + } + else { + // 4! + switch(label) { + case sA_sA_sB_sB: + case sB_sB_sA_sA: + segments[0].m_cfg1 = + segments[1].m_cfg1 = + segments[0].m_cfg2 = + segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case sA_sB_sA_sB: + segments[0].m_cfg1 = sA.getConfig(); + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = sB.getConfig(); + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sA.m_cfg2,sA.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sB_sA_sB_sA: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.getConfig(); + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.getConfig(); + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sB.m_cfg2,sB.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sA_sB_sB_sA: + segments[0].m_cfg1 = sA.getConfig(); + segments[1].m_cfg1 = sB.m_cfg1; + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = segments[0].m_cfg1; + segments[1].m_cfg2 = sB.m_cfg2; + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sB.m_cfg2,sB.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + case sB_sA_sA_sB: + segments[0].m_cfg1 = sA.m_cfg1; + segments[1].m_cfg1 = sB.getConfig(); + segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1); + segments[1].m_v1 = segments[0].m_v1; + + segments[0].m_cfg2 = sA.m_cfg2; + segments[1].m_cfg2 = segments[1].m_cfg1; + segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sA.m_cfg2,sA.m_v2); + segments[1].m_v2 = segments[0].m_v2; + break; + + default: + break; + } + } + + segments[0].sort(); + segments[1].sort(); +} + +/** + * Computes the vertex index of a point. + * @param mesh mesh that contains the faces, edges and vertices + * @param point input point + * @param cfgA configuration of point on faceA + * @param cfgB configuration of point on faceB + * @param vA vertex index of point on faceA + * @param vB vertex index of point on faceB + * @param invert indicates if vA has priority over vB + * @return final vertex index in the mesh + */ +BOP_Index BOP_getVertexIndex(BOP_Mesh* mesh, + MT_Point3 point, + unsigned int cfgA, + unsigned int cfgB, + BOP_Index vA, + BOP_Index vB, + bool invert) +{ + if (BOP_Segment::isVertex(cfgA)) { // exists vertex index on A + if (BOP_Segment::isVertex(cfgB)) { // exists vertex index on B + // unify vertex indexs + if (invert) + return mesh->replaceVertexIndex(vA,vB); + else + return mesh->replaceVertexIndex(vB,vA); + } + else + return vA; + } + else {// does not exist vertex index on A + if (BOP_Segment::isVertex(cfgB)) // exists vertex index on B + return vB; + else {// does not exist vertex index on B + return mesh->addVertex(point); + } + } +} + +/** + * Computes the vertex index of a point. + * @param mesh mesh that contains the faces, edges and vertices + * @param cfg configuration of point + * @param v vertex index of point + * @return final vertex index in the mesh + */ +BOP_Index BOP_getVertexIndex(BOP_Mesh *mesh, MT_Point3 point, unsigned int cfg, BOP_Index v) +{ + if (BOP_Segment::isVertex(cfg)) // vertex existent + return v; + else { + return mesh->addVertex(point); + } +} + +/******************************************************************************/ +/*** TRIANGULATE ***/ +/******************************************************************************/ + +/** + * Triangulates the input face according to the specified segment. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains the original face and the new triangulated faces + * @param face face to be triangulated + * @param s segment used to triangulate face + */ +void triangulate(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face *face, BOP_Segment s) +{ + if (BOP_Segment::isUndefined(s.m_cfg1)) { + // Nothing to do + } + else if (BOP_Segment::isVertex(s.m_cfg1)) { + // VERTEX(v1) + VERTEX(v2) => nothing to do + } + else if (BOP_Segment::isEdge(s.m_cfg1)) { + if (BOP_Segment::isVertex(s.m_cfg2) || BOP_Segment::isUndefined(s.m_cfg2)) { + // EDGE(v1) + VERTEX(v2) + BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); + BOP_triangulateA(mesh,faces,face,s.m_v1,BOP_Segment::getEdge(s.m_cfg1)); + BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); + BOP_triangulateA(mesh, faces, opposite, s.m_v1, e); + } + } + else { + // EDGE(v1) + EDGE(v2) + if (BOP_Segment::getEdge(s.m_cfg1) == BOP_Segment::getEdge(s.m_cfg2)) { + // EDGE(v1) == EDGE(v2) + BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); + BOP_triangulateD(mesh, faces, face, s.m_v1, s.m_v2, + BOP_Segment::getEdge(s.m_cfg1)); + BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); + BOP_triangulateD(mesh, faces, opposite, s.m_v1, s.m_v2, e); + } + } + else { // EDGE(v1) != EDGE(v2) + BOP_Edge *edge1 = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1)); + BOP_Edge *edge2 = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg2)); + BOP_triangulateE(mesh, faces, face, s.m_v1, s.m_v2, + BOP_Segment::getEdge(s.m_cfg1), + BOP_Segment::getEdge(s.m_cfg2)); + BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge1); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge1->getVertex1(), edge1->getVertex2(),e); + BOP_triangulateA(mesh, faces, opposite, s.m_v1, e); + } + opposite = BOP_getOppositeFace(mesh,faces,face,edge2); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge2->getVertex1(), edge2->getVertex2(),e); + BOP_triangulateA(mesh, faces, opposite, s.m_v2, e); + } + } + } + } + else if (BOP_Segment::isIn(s.m_cfg1)) { + if (BOP_Segment::isVertex(s.m_cfg2) || BOP_Segment::isUndefined(s.m_cfg2)) { + // IN(v1) + VERTEX(v2) + BOP_triangulateB(mesh,faces,face,s.m_v1); + } + else if (BOP_Segment::isEdge(s.m_cfg2)) { + // IN(v1) + EDGE(v2) + BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg2)); + BOP_triangulateF(mesh,faces,face,s.m_v1,s.m_v2,BOP_Segment::getEdge(s.m_cfg2)); + BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge); + if (opposite != NULL) { + unsigned int e; + opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e); + BOP_triangulateA(mesh, faces, opposite, s.m_v2, e); + } + } + else // IN(v1) + IN(v2) + BOP_triangulateC(mesh,faces,face,s.m_v1,s.m_v2); + } +} + +/** + * Returns if a face is in the set of faces. + * @param faces set of faces + * @param face face to be searched + * @return if the face is inside faces + */ +bool BOP_containsFace(BOP_Faces *faces, BOP_Face *face) +{ + const BOP_IT_Faces facesEnd = faces->end(); + for(BOP_IT_Faces it=faces->begin();it!=facesEnd;it++) + { + if (*it == face) + return true; + } + + return false; +} + +/** + * Returns the first face of faces that shares the input edge of face. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces + * @param face input face + * @param edge face's edge + * @return first face that shares the edge of input face + */ +BOP_Face *BOP_getOppositeFace(BOP_Mesh* mesh, + BOP_Faces* faces, + BOP_Face* face, + BOP_Edge* edge) +{ + if (edge == NULL) + return NULL; + + BOP_Indexs auxfaces = edge->getFaces(); + const BOP_IT_Indexs auxfacesEnd = auxfaces.end(); + for(BOP_IT_Indexs it = auxfaces.begin(); it != auxfacesEnd; it++) { + BOP_Face *auxface = mesh->getFace(*it); + if ((auxface != face) && (auxface->getTAG()!=BROKEN) && + BOP_containsFace(faces,auxface)) { + return auxface; + } + } + + return NULL; +} + +/******************************************************************************/ +/*** OVERLAPPING ***/ +/******************************************************************************/ + +/** + * Removes faces from facesB that are overlapped with anyone from facesA. + * @param mesh mesh that contains the faces, edges and vertices + * @param facesA set of faces from object A + * @param facesB set of faces from object B + */ +void BOP_removeOverlappedFaces(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB) +{ + for(unsigned int i=0;isize();i++) { + BOP_Face *faceI = (*facesA)[i]; + if (faceI->getTAG()==BROKEN) continue; + bool overlapped = false; + MT_Point3 p1 = mesh->getVertex(faceI->getVertex(0))->getPoint(); + MT_Point3 p2 = mesh->getVertex(faceI->getVertex(1))->getPoint(); + MT_Point3 p3 = mesh->getVertex(faceI->getVertex(2))->getPoint(); + for(unsigned int j=0;jsize();) { + BOP_Face *faceJ = (*facesB)[j]; + if (faceJ->getTAG()!=BROKEN) { + MT_Plane3 planeJ = faceJ->getPlane(); + if (BOP_containsPoint(planeJ,p1) && BOP_containsPoint(planeJ,p2) + && BOP_containsPoint(planeJ,p3)) { + MT_Point3 q1 = mesh->getVertex(faceJ->getVertex(0))->getPoint(); + MT_Point3 q2 = mesh->getVertex(faceJ->getVertex(1))->getPoint(); + MT_Point3 q3 = mesh->getVertex(faceJ->getVertex(2))->getPoint(); + if (BOP_overlap(MT_Vector3(planeJ.x(),planeJ.y(),planeJ.z()), + p1,p2,p3,q1,q2,q3)) { + facesB->erase(facesB->begin()+j,facesB->begin()+(j+1)); + faceJ->setTAG(BROKEN); + overlapped = true; + } + else j++; + } + else j++; + }else j++; + } + if (overlapped) faceI->setTAG(OVERLAPPED); + } +} + +/** + * Computes if triangle p1,p2,p3 is overlapped with triangle q1,q2,q3. + * @param normal normal of the triangle p1,p2,p3 + * @param p1 point of first triangle + * @param p2 point of first triangle + * @param p3 point of first triangle + * @param q1 point of second triangle + * @param q2 point of second triangle + * @param q3 point of second triangle + * @return if there is overlapping between both triangles + */ +bool BOP_overlap(MT_Vector3 normal, MT_Point3 p1, MT_Point3 p2, MT_Point3 p3, + MT_Point3 q1, MT_Point3 q2, MT_Point3 q3) +{ + MT_Vector3 p1p2 = p2-p1; + MT_Plane3 plane1(p1p2.cross(normal),p1); + + MT_Vector3 p2p3 = p3-p2; + MT_Plane3 plane2(p2p3.cross(normal),p2); + + MT_Vector3 p3p1 = p1-p3; + MT_Plane3 plane3(p3p1.cross(normal),p3); + + BOP_TAG tag1 = BOP_createTAG(BOP_classify(q1,plane1)); + BOP_TAG tag2 = BOP_createTAG(BOP_classify(q1,plane2)); + BOP_TAG tag3 = BOP_createTAG(BOP_classify(q1,plane3)); + BOP_TAG tagQ1 = BOP_createTAG(tag1,tag2,tag3); + if (tagQ1 == IN_IN_IN) return true; + + tag1 = BOP_createTAG(BOP_classify(q2,plane1)); + tag2 = BOP_createTAG(BOP_classify(q2,plane2)); + tag3 = BOP_createTAG(BOP_classify(q2,plane3)); + BOP_TAG tagQ2 = BOP_createTAG(tag1,tag2,tag3); + if (tagQ2 == IN_IN_IN) return true; + + tag1 = BOP_createTAG(BOP_classify(q3,plane1)); + tag2 = BOP_createTAG(BOP_classify(q3,plane2)); + tag3 = BOP_createTAG(BOP_classify(q3,plane3)); + BOP_TAG tagQ3 = BOP_createTAG(tag1,tag2,tag3); + if (tagQ3 == IN_IN_IN) return true; + + if ((tagQ1 & OUT_OUT_OUT) == 0 && (tagQ2 & OUT_OUT_OUT) == 0 && + (tagQ3 & OUT_OUT_OUT) == 0) return true; + else return false; +} diff --git a/intern/boolop/intern/BOP_Face2Face.h b/intern/boolop/intern/BOP_Face2Face.h new file mode 100644 index 00000000000..09ed4edd076 --- /dev/null +++ b/intern/boolop/intern/BOP_Face2Face.h @@ -0,0 +1,44 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_FACE2FACE_H +#define BOP_FACE2FACE_H + +#include "BOP_Mesh.h" +#include "BOP_Segment.h" +#include "BOP_Triangulator.h" +#include "BOP_Splitter.h" +#include "BOP_BSPTree.h" + +void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB); +void BOP_sew(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB); +void BOP_removeOverlappedFaces(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB); + +#endif diff --git a/intern/boolop/intern/BOP_Indexs.h b/intern/boolop/intern/BOP_Indexs.h new file mode 100644 index 00000000000..c5546e73252 --- /dev/null +++ b/intern/boolop/intern/BOP_Indexs.h @@ -0,0 +1,41 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_Indexs_H +#define BOP_Indexs_H + +#include +using namespace std; + +typedef unsigned int BOP_Index; +typedef vector BOP_Indexs; +typedef vector::iterator BOP_IT_Indexs; + +#endif diff --git a/intern/boolop/intern/BOP_Interface.cpp b/intern/boolop/intern/BOP_Interface.cpp new file mode 100644 index 00000000000..3c61fd6c7b8 --- /dev/null +++ b/intern/boolop/intern/BOP_Interface.cpp @@ -0,0 +1,505 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include "../extern/BOP_Interface.h" +#include "../../bsp/intern/BSP_CSGMesh_CFIterator.h" +#include "BOP_BSPTree.h" +#include "BOP_Mesh.h" +#include "BOP_Face2Face.h" +#include "BOP_Merge.h" +#include "BOP_Chrono.h" + +//#define DEBUG + +BoolOpState BOP_intersectionBoolOp(BOP_Mesh* meshC, + BOP_Faces* facesA, + BOP_Faces* facesB, + bool invertMeshA, + bool invertMeshB); +BOP_Face3* BOP_createFace(BOP_Mesh* mesh, + BOP_Index vertex1, + BOP_Index vertex2, + BOP_Index vertex3, + BOP_Index origFace); +void BOP_addMesh(BOP_Mesh* mesh, + BOP_Faces* meshFacesId, + CSG_FaceIteratorDescriptor& face_it, + CSG_VertexIteratorDescriptor& vertex_it, + bool invert); +BSP_CSGMesh* BOP_newEmptyMesh(); +BSP_CSGMesh* BOP_exportMesh(BOP_Mesh* inputMesh, + bool invert); +void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp); +void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted); +void BOP_meshClassify(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp); + +/** + * Performs a generic booleam operation, the entry point for external modules. + * @param opType Boolean operation type BOP_INTERSECTION, BOP_UNION, BOP_DIFFERENCE + * @param outputMesh Output mesh, the final result (the object C) + * @param obAFaces Object A faces list + * @param obAVertices Object A vertices list + * @param obBFaces Object B faces list + * @param obBVertices Object B vertices list + * @param interpFunc Interpolating function + * @return operation state: BOP_OK, BOP_NO_SOLID, BOP_ERROR + */ +BoolOpState BOP_performBooleanOperation(BoolOpType opType, + BSP_CSGMesh** outputMesh, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices) +{ + #ifdef DEBUG + cout << "BEGIN BOP_performBooleanOperation" << endl; + #endif + + // Set invert flags depending on boolean operation type: + // INTERSECTION: A^B = and(A,B) + // UNION: A|B = not(and(not(A),not(B))) + // DIFFERENCE: A-B = and(A,not(B)) + bool invertMeshA = (opType == BOP_UNION); + bool invertMeshB = (opType != BOP_INTERSECTION); + bool invertMeshC = (opType == BOP_UNION); + + // Faces list for both objects, used by boolean op. + BOP_Faces meshAFacesId; + BOP_Faces meshBFacesId; + + // Build C-mesh, the output mesh + BOP_Mesh meshC; + + // Add A-mesh into C-mesh + BOP_addMesh(&meshC, &meshAFacesId, obAFaces, obAVertices, invertMeshA); + + // Add B-mesh into C-mesh + BOP_addMesh(&meshC, &meshBFacesId, obBFaces, obBVertices, invertMeshB); + + // for now, allow operations on non-manifold (non-solid) meshes +#if 0 + if (!meshC.isClosedMesh()) + return BOP_NO_SOLID; +#endif + + // Perform the intersection boolean operation. + BoolOpState result = BOP_intersectionBoolOp(&meshC, &meshAFacesId, &meshBFacesId, + invertMeshA, invertMeshB); + + // Invert the output mesh if is required + *outputMesh = BOP_exportMesh(&meshC, invertMeshC); + + #ifdef DEBUG + cout << "END BOP_performBooleanOperation" << endl; + #endif + + return result; +} + +/** + * Computes the intersection boolean operation. Creates a new mesh resulting from + * an intersection of two meshes. + * @param meshC Input & Output mesh + * @param facesA Mesh A faces list + * @param facesB Mesh B faces list + * @param invertMeshA determines if object A is inverted + * @param invertMeshB determines if object B is inverted + * @return operation state: BOP_OK, BOP_NO_SOLID, BOP_ERROR + */ +BoolOpState BOP_intersectionBoolOp(BOP_Mesh* meshC, + BOP_Faces* facesA, + BOP_Faces* facesB, + bool invertMeshA, + bool invertMeshB) +{ + #ifdef DEBUG + BOP_Chrono chrono; + float t = 0.0f; + float c = 0.0f; + chrono.start(); + cout << "---" << endl; + #endif + + // Create BSPs trees for mesh A & B + BOP_BSPTree bspA; + bspA.addMesh(meshC, *facesA); + + BOP_BSPTree bspB; + bspB.addMesh(meshC, *facesB); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Create BSP " << c << endl; + #endif + + unsigned int numVertices = meshC->getNumVertexs(); + + // mesh pre-filter + BOP_simplifiedMeshFilter(meshC, facesA, &bspB, invertMeshB); + if ((0.25*facesA->size()) > bspB.getDeep()) + BOP_meshFilter(meshC, facesA, &bspB); + + BOP_simplifiedMeshFilter(meshC, facesB, &bspA, invertMeshA); + if ((0.25*facesB->size()) > bspA.getDeep()) + BOP_meshFilter(meshC, facesB, &bspA); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "mesh Filter " << c << endl; + #endif + + // Face 2 Face + BOP_Face2Face(meshC,facesA,facesB); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Face2Face " << c << endl; + #endif + + // BSP classification + BOP_meshClassify(meshC,facesA,&bspB); + BOP_meshClassify(meshC,facesB,&bspA); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Classification " << c << endl; + #endif + + // Process overlapped faces + BOP_removeOverlappedFaces(meshC,facesA,facesB); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Remove overlap " << c << endl; + #endif + + // Sew two meshes + BOP_sew(meshC,facesA,facesB); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Sew " << c << endl; + #endif + + // Merge faces + BOP_Merge::getInstance().mergeFaces(meshC,numVertices); + + #ifdef DEBUG + c = chrono.stamp(); t += c; + cout << "Merge faces " << c << endl; + cout << "Total " << t << endl; + // Test integrity + meshC->testMesh(); + #endif + + return BOP_OK; +} + +/** + * Preprocess to filter no collisioned faces. + * @param meshC Input & Output mesh data + * @param faces Faces list to test + * @param bsp BSP tree used to filter + */ +void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp) +{ + BOP_IT_Faces it; + BOP_TAG tag; + + it = faces->begin(); + while (it!=faces->end()) { + BOP_Face *face = *it; + MT_Point3 p1 = meshC->getVertex(face->getVertex(0))->getPoint(); + MT_Point3 p2 = meshC->getVertex(face->getVertex(1))->getPoint(); + MT_Point3 p3 = meshC->getVertex(face->getVertex(2))->getPoint(); + if ((tag = bsp->classifyFace(p1,p2,p3,face->getPlane()))==OUT||tag==OUTON) { + face->setTAG(BROKEN); + it = faces->erase(it); + } + else if (tag == IN) { + it = faces->erase(it); + }else{ + it++; + } + } +} + +/** + * Pre-process to filter no collisioned faces. + * @param meshC Input & Output mesh data + * @param faces Faces list to test + * @param bsp BSP tree used to filter + * @param inverted determines if the object is inverted + */ +void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted) +{ + BOP_IT_Faces it; + + it = faces->begin(); + while (it!=faces->end()) { + BOP_Face *face = *it; + MT_Point3 p1 = meshC->getVertex(face->getVertex(0))->getPoint(); + MT_Point3 p2 = meshC->getVertex(face->getVertex(1))->getPoint(); + MT_Point3 p3 = meshC->getVertex(face->getVertex(2))->getPoint(); + if (bsp->filterFace(p1,p2,p3,face)==OUT) { + if (!inverted) face->setTAG(BROKEN); + it = faces->erase(it); + } + else { + it++; + } + } +} + +/** + * Process to classify the mesh faces using a bsp tree. + * @param meshC Input & Output mesh data + * @param faces Faces list to classify + * @param bsp BSP tree used to face classify + */ +void BOP_meshClassify(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp) +{ + for(BOP_IT_Faces face=faces->begin();face!=faces->end();face++) { + if ((*face)->getTAG()!=BROKEN) { + MT_Point3 p1 = meshC->getVertex((*face)->getVertex(0))->getPoint(); + MT_Point3 p2 = meshC->getVertex((*face)->getVertex(1))->getPoint(); + MT_Point3 p3 = meshC->getVertex((*face)->getVertex(2))->getPoint(); + if (bsp->simplifiedClassifyFace(p1,p2,p3,(*face)->getPlane())!=IN) { + (*face)->setTAG(BROKEN); + } + } + } +} + +/** + * Returns a new mesh triangle. + * @param meshC Input & Output mesh data + * @param vertex1 first vertex of the new face + * @param vertex2 second vertex of the new face + * @param vertex3 third vertex of the new face + * @param origFace identifier of the new face + * @return new the new face + */ +BOP_Face3 *BOP_createFace3(BOP_Mesh* mesh, + BOP_Index vertex1, + BOP_Index vertex2, + BOP_Index vertex3, + BOP_Index origFace) +{ + MT_Point3 p1 = mesh->getVertex(vertex1)->getPoint(); + MT_Point3 p2 = mesh->getVertex(vertex2)->getPoint(); + MT_Point3 p3 = mesh->getVertex(vertex3)->getPoint(); + MT_Plane3 plane(p1,p2,p3); + + return new BOP_Face3(vertex1, vertex2, vertex3, plane, origFace); +} + +/** + * Adds mesh information into destination mesh. + * @param mesh input/output mesh, destination for the new mesh data + * @param meshFacesId output mesh faces, contains an added faces list + * @param face_it faces iterator + * @param vertex_it vertices iterator + * @param inverted if TRUE adding inverted faces, non-inverted otherwise + */ +void BOP_addMesh(BOP_Mesh* mesh, + BOP_Faces* meshFacesId, + CSG_FaceIteratorDescriptor& face_it, + CSG_VertexIteratorDescriptor& vertex_it, + bool invert) +{ + unsigned int vtxIndexOffset = mesh->getNumVertexs(); + + // The size of the vertex data array will be at least the number of faces. + CSG_IVertex vertex; + while (!vertex_it.Done(vertex_it.it)) { + vertex_it.Fill(vertex_it.it,&vertex); + MT_Point3 pos(vertex.position); + mesh->addVertex(pos); + vertex_it.Step(vertex_it.it); + } + + CSG_IFace face; + + // now for the polygons. + // we may need to decalare some memory for user defined face properties. + + BOP_Face3 *newface; + + while (!face_it.Done(face_it.it)) { + face_it.Fill(face_it.it,&face); + + // Let's not rely on quads being coplanar - especially if they + // are coming out of that soup of code from blender... + if (face.vertex_number == 4){ + // QUAD + if (invert) { + newface = BOP_createFace3(mesh, + face.vertex_index[2] + vtxIndexOffset, + face.vertex_index[0] + vtxIndexOffset, + face.vertex_index[3] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + newface = BOP_createFace3(mesh, + face.vertex_index[2] + vtxIndexOffset, + face.vertex_index[1] + vtxIndexOffset, + face.vertex_index[0] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + } + else { + newface = BOP_createFace3(mesh, + face.vertex_index[0] + vtxIndexOffset, + face.vertex_index[2] + vtxIndexOffset, + face.vertex_index[3] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + newface = BOP_createFace3(mesh, + face.vertex_index[0] + vtxIndexOffset, + face.vertex_index[1] + vtxIndexOffset, + face.vertex_index[2] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + } + } + else { + // TRIANGLES + if (invert) { + newface = BOP_createFace3(mesh, + face.vertex_index[2] + vtxIndexOffset, + face.vertex_index[1] + vtxIndexOffset, + face.vertex_index[0] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + } + else { + newface = BOP_createFace3(mesh, + face.vertex_index[0] + vtxIndexOffset, + face.vertex_index[1] + vtxIndexOffset, + face.vertex_index[2] + vtxIndexOffset, + face.orig_face); + meshFacesId->push_back(newface); + mesh->addFace(newface); + } + } + + face_it.Step(face_it.it); + } +} + +/** + * Returns an empty mesh with the specified properties. + * @return a new empty mesh + */ +BSP_CSGMesh* BOP_newEmptyMesh() +{ + BSP_CSGMesh* mesh = BSP_CSGMesh::New(); + if (mesh == NULL) return mesh; + + vector* vertices = new vector; + + mesh->SetVertices(vertices); + + return mesh; +} + +/** + * Exports a BOP_Mesh to a BSP_CSGMesh. + * @param mesh Input mesh + * @param invert if TRUE export with inverted faces, no inverted otherwise + * @return the corresponding new BSP_CSGMesh + */ +BSP_CSGMesh* BOP_exportMesh(BOP_Mesh* mesh, + bool invert) +{ + BSP_CSGMesh* outputMesh = BOP_newEmptyMesh(); + + if (outputMesh == NULL) return NULL; + + // vtx index dictionary, to translate indeces from input to output. + map dic; + map::iterator itDic; + + unsigned int count = 0; + + // Add a new face for each face in the input list + BOP_Faces faces = mesh->getFaces(); + BOP_Vertexs vertexs = mesh->getVertexs(); + + for (BOP_IT_Faces face = faces.begin(); face != faces.end(); face++) { + if ((*face)->getTAG()!=BROKEN){ + // Add output face + outputMesh->FaceSet().push_back(BSP_MFace()); + BSP_MFace& outFace = outputMesh->FaceSet().back(); + + // Copy face + outFace.m_verts.clear(); + outFace.m_plane = (*face)->getPlane(); + outFace.m_orig_face = (*face)->getOriginalFace(); + + // invert face if is required + if (invert) (*face)->invert(); + + // Add the face vertex if not added yet + for (unsigned int pos=0;pos<(*face)->size();pos++) { + BSP_VertexInd outVtxId; + BOP_Index idVertex = (*face)->getVertex(pos); + itDic = dic.find(idVertex); + if (itDic == dic.end()) { + // The vertex isn't added yet + outVtxId = BSP_VertexInd(outputMesh->VertexSet().size()); + BSP_MVertex outVtx((mesh->getVertex(idVertex))->getPoint()); + outVtx.m_edges.clear(); + outputMesh->VertexSet().push_back(outVtx); + dic[idVertex] = outVtxId; + count++; + } + else { + // The vertex is added + outVtxId = BSP_VertexInd(itDic->second); + } + + outFace.m_verts.push_back(outVtxId); + } + } + } + + // Build the mesh edges using topological informtion + outputMesh->BuildEdges(); + + return outputMesh; +} diff --git a/intern/boolop/intern/BOP_MathUtils.cpp b/intern/boolop/intern/BOP_MathUtils.cpp new file mode 100644 index 00000000000..e0d96b465ee --- /dev/null +++ b/intern/boolop/intern/BOP_MathUtils.cpp @@ -0,0 +1,471 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Marc Freixas, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_MathUtils.h" +#include +using namespace std; + +/** + * Compares two scalars with EPSILON accuracy. + * @param A scalar + * @param B scalar + * @return 1 if A > B, -1 if A < B, 0 otherwise + */ +int BOP_comp(const MT_Scalar A, const MT_Scalar B) +{ +#ifndef VAR_EPSILON + if (A >= B + BOP_EPSILON) return 1; + else if (B >= A + BOP_EPSILON) return -1; + else return 0; +#else + int expA, expB; + float mant; + frexp(A, &expA); /* get exponents of each number */ + frexp(B, &expB); + + if(expA < expB) /* find the larger exponent */ + expA = expB; + mant = frexp((A-B), &expB); /* get exponent of the difference */ + /* mantissa will only be zero is (A-B) is really zero; otherwise, also + * also allow a "reasonably" small exponent or "reasonably large" + * difference in exponents to be considers "close to zero" */ + if( mant == 0 || expB < -30 || expA - expB > 31) return 0; + else if( mant > 0) return 1; + else return -1; +#endif +} + +/** + * Compares a scalar with EPSILON accuracy. + * @param A scalar + * @return 1 if A > 0, -1 if A < 0, 0 otherwise + */ +int BOP_comp0(const MT_Scalar A) +{ + if (A >= BOP_EPSILON) return 1; + else if (0 >= A + BOP_EPSILON) return -1; + else return 0; +} + +/** + * Compares two scalar triplets with EPSILON accuracy. + * @param A scalar triplet + * @param B scalar triplet + * @return 1 if A > B, -1 if A < B, 0 otherwise + */ +int BOP_comp(const MT_Tuple3& A, const MT_Tuple3& B) +{ +#ifndef VAR_EPSILON + if (A.x() >= (B.x() + BOP_EPSILON)) return 1; + else if (B.x() >= (A.x() + BOP_EPSILON)) return -1; + else if (A.y() >= (B.y() + BOP_EPSILON)) return 1; + else if (B.y() >= (A.y() + BOP_EPSILON)) return -1; + else if (A.z() >= (B.z() + BOP_EPSILON)) return 1; + else if (B.z() >= (A.z() + BOP_EPSILON)) return -1; + else return 0; +#else + int result = BOP_comp(A.x(), B.x()); + if (result != 0) return result; + result = BOP_comp(A.y(), B.y()); + if (result != 0) return result; + return BOP_comp(A.z(), B.z()); +#endif +} + +/** + * Compares two scalars strictly. + * @param A scalar + * @param B scalar + * @return 1 if A > B, -1 if A < B, 0 otherwise + */ +int BOP_exactComp(const MT_Scalar A, const MT_Scalar B) +{ + if (A > B) return 1; + else if (B > A) return -1; + else return 0; +} +/** + * Compares two scalar strictly. + * @param A scalar triplet + * @param B scalar triplet + * @return 1 if A > B, -1 if A < B, 0 otherwise + */ +int BOP_exactComp(const MT_Tuple3& A, const MT_Tuple3& B) +{ + if (A.x() > B.x()) return 1; + else if (B.x() > A.x()) return -1; + else if (A.y() > B.y()) return 1; + else if (B.y() > A.y()) return -1; + else if (A.z() > B.z()) return 1; + else if (B.z() > A.z()) return -1; + else return 0; +} + +/** + * Returns if p1 is between p2 and p3 and lay on the same line (are collinears). + * @param p1 point + * @param p2 point + * @param p3 point + * @return true if p1 is between p2 and p3 and lay on the same line, false otherwise + */ +bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3) +{ + MT_Scalar distance = p2.distance(p3); + return (p1.distance(p2) < distance && p1.distance(p3) < distance) && BOP_collinear(p1,p2,p3); +} + +/** + * Returns if three points lay on the same line (are collinears). + * @param p1 point + * @param p2 point + * @param p3 point + * @return true if the three points lay on the same line, false otherwise + */ +bool BOP_collinear(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3) +{ + if( BOP_comp(p1,p2) == 0 || BOP_comp(p2,p3) == 0 ) return true; + + MT_Vector3 v1 = p2 - p1; + MT_Vector3 v2 = p3 - p2; + + /* normalize vectors before taking their cross product, so its length + * has some actual meaning */ + // if(MT_fuzzyZero(v1.length()) || MT_fuzzyZero(v2.length())) return true; + v1.normalize(); + v2.normalize(); + + MT_Vector3 w = v1.cross(v2); + + return (BOP_fuzzyZero(w.x()) && BOP_fuzzyZero(w.y()) && BOP_fuzzyZero(w.z())); +} + +/** + * Returns if a quad (coplanar) is convex. + * @return true if the quad is convex, false otherwise + */ +bool BOP_convex(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4) +{ + MT_Vector3 v1 = p3 - p1; + MT_Vector3 v2 = p4 - p2; + MT_Vector3 quadPlane = v1.cross(v2); + // plane1 is the perpendicular plane that contains the quad diagonal (p2,p4) + MT_Plane3 plane1(quadPlane.cross(v2),p2); + // if p1 and p3 are classified in the same region, the quad is not convex + if (BOP_classify(p1,plane1) == BOP_classify(p3,plane1)) return false; + else { + // Test the other quad diagonal (p1,p3) and perpendicular plane + MT_Plane3 plane2(quadPlane.cross(v1),p1); + // if p2 and p4 are classified in the same region, the quad is not convex + return (BOP_classify(p2,plane2) != BOP_classify(p4,plane2)); + } +} + +/** + * Returns if a quad (coplanar) is concave and where is the split edge. + * @return 0 if is convex, 1 if is concave and split edge is p1-p3 and -1 if is + * cancave and split edge is p2-p4. + */ +int BOP_concave(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4) +{ + MT_Vector3 v1 = p3 - p1; + MT_Vector3 v2 = p4 - p2; + MT_Vector3 quadPlane = v1.cross(v2); + // plane1 is the perpendicular plane that contains the quad diagonal (p2,p4) + MT_Plane3 plane1(quadPlane.cross(v2),p2); + // if p1 and p3 are classified in the same region, the quad is not convex + if (BOP_classify(p1,plane1) == BOP_classify(p3,plane1)) return 1; + else { + // Test the other quad diagonal (p1,p3) and perpendicular plane + MT_Plane3 plane2(quadPlane.cross(v1),p1); + // if p2 and p4 are classified in the same region, the quad is not convex + if (BOP_classify(p2,plane2) == BOP_classify(p4,plane2)) return -1; + else return 0; + } +} + +/** + * Computes the intersection between two lines (on the same plane). + * @param vL1 first line vector + * @param pL1 first line point + * @param vL2 second line vector + * @param pL2 second line point + * @param intersection intersection point (if exists) + * @return false if lines are parallels, true otherwise + */ +bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, + const MT_Point3& pL2, MT_Point3 &intersection) +{ + // NOTE: + // If the lines aren't on the same plane, the intersection point will not be valid. + // So be careful !! + + MT_Scalar t = -1; + MT_Scalar den = (vL1.y()*vL2.x() - vL1.x() * vL2.y()); + + if (!BOP_fuzzyZero(den)) { + t = (pL2.y()*vL1.x() - vL1.y()*pL2.x() + pL1.x()*vL1.y() - pL1.y()*vL1.x()) / den ; + } + else { + den = (vL1.y()*vL2.z() - vL1.z() * vL2.y()); + if (!BOP_fuzzyZero(den)) { + t = (pL2.y()*vL1.z() - vL1.y()*pL2.z() + pL1.z()*vL1.y() - pL1.y()*vL1.z()) / den ; + } + else { + den = (vL1.x()*vL2.z() - vL1.z() * vL2.x()); + if (!BOP_fuzzyZero(den)) { + t = (pL2.x()*vL1.z() - vL1.x()*pL2.z() + pL1.z()*vL1.x() - pL1.x()*vL1.z()) / den ; + } + else { + return false; + } + } + } + + intersection.setValue(vL2.x()*t + pL2.x(), vL2.y()*t + pL2.y(), vL2.z()*t + pL2.z()); + return true; +} + +/** + * Returns the center of the circle defined by three points. + * @param p1 point + * @param p2 point + * @param p3 point + * @param center circle center + * @return false if points are collinears, true otherwise + */ +bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + MT_Point3& center) +{ + // Compute quad plane + MT_Vector3 p1p2 = p2-p1; + MT_Vector3 p1p3 = p3-p1; + MT_Plane3 plane1(p1,p2,p3); + MT_Vector3 plane = plane1.Normal(); + + // Compute first line vector, perpendicular to plane vector and edge (p1,p2) + MT_Vector3 vL1 = p1p2.cross(plane); + if( MT_fuzzyZero(vL1.length() ) ) + return false; + vL1.normalize(); + + // Compute first line point, middle point of edge (p1,p2) + MT_Point3 pL1 = p1.lerp(p2, 0.5); + + // Compute second line vector, perpendicular to plane vector and edge (p1,p3) + MT_Vector3 vL2 = p1p3.cross(plane); + if( MT_fuzzyZero(vL2.length() ) ) + return false; + vL2.normalize(); + + // Compute second line point, middle point of edge (p1,p3) + MT_Point3 pL2 = p1.lerp(p3, 0.5); + + // Compute intersection (the lines lay on the same plane, so the intersection exists + // only if they are not parallel!!) + return BOP_intersect(vL1,pL1,vL2,pL2,center); +} + +/** + * Returns if points q is inside the circle defined by p1, p2 and p3. + * @param p1 point + * @param p2 point + * @param p3 point + * @param q point + * @return true if p4 or p5 are inside the circle, false otherwise. If + * the circle does not exist (p1, p2 and p3 are collinears) returns true + */ +bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& q) +{ + MT_Point3 center; + + // Compute circle center + bool ok = BOP_getCircleCenter(p1,p2,p3,center); + + if (!ok) return true; // p1,p2 and p3 are collinears + + // Check if q is inside the circle + MT_Scalar r = p1.distance(center); + MT_Scalar d = q.distance(center); + return (BOP_comp(d,r) <= 0); +} + +/** + * Returns if points p4 or p5 is inside the circle defined by p1, p2 and p3. + * @param p1 point + * @param p2 point + * @param p3 point + * @param p4 point + * @param p5 point + * @return true if p4 or p5 is inside the circle, false otherwise. If + * the circle does not exist (p1, p2 and p3 are collinears) returns true + */ +bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& p4, const MT_Point3& p5) +{ + MT_Point3 center; + bool ok = BOP_getCircleCenter(p1,p2,p3,center); + + if (!ok) return true; // Collinear points! + + // Check if p4 or p5 is inside the circle + MT_Scalar r = p1.distance(center); + MT_Scalar d1 = p4.distance(center); + MT_Scalar d2 = p5.distance(center); + return (BOP_comp(d1,r) <= 0 || BOP_comp(d2,r) <= 0); +} + +/** + * Returns if two planes share the same orientation. + * @return >0 if planes share the same orientation + */ +MT_Scalar BOP_orientation(const MT_Plane3& p1, const MT_Plane3& p2) +{ + // Dot product between plane normals + return (p1.x()*p2.x() + p1.y()*p2.y() + p1.z()*p2.z()); +} + +/** + * Classifies a point according to the specified plane with EPSILON accuracy. + * @param p point + * @param plane plane + * @return >0 if the point is above (OUT), + * =0 if the point is on (ON), + * <0 if the point is below (IN) + */ +int BOP_classify(const MT_Point3& p, const MT_Plane3& plane) +{ + // Compare plane - point distance with zero + return BOP_comp0(plane.signedDistance(p)); +} + +/** + * Intersects a plane with the line that contains the specified points. + * @param plane split plane + * @param p1 first line point + * @param p2 second line point + * @return intersection between plane and line that contains p1 and p2 + */ +MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2) +{ + // Compute intersection between plane and line ... + // + // L: (p2-p1)lambda + p1 + // + // supposes resolve equation ... + // + // coefA*((p2.x - p1.y)*lambda + p1.x) + ... + coefD = 0 + + MT_Point3 intersection = MT_Point3(0,0,0); //never ever return anything undefined! + MT_Scalar den = plane.x()*(p2.x()-p1.x()) + + plane.y()*(p2.y()-p1.y()) + + plane.z()*(p2.z()-p1.z()); + if (den != 0) { + MT_Scalar lambda = (-plane.x()*p1.x()-plane.y()*p1.y()-plane.z()*p1.z()-plane.w()) / den; + intersection.setValue(p1.x() + (p2.x()-p1.x())*lambda, + p1.y() + (p2.y()-p1.y())*lambda, + p1.z() + (p2.z()-p1.z())*lambda); + return intersection; + } + return intersection; +} + +/** + * Returns if a plane contains a point with EPSILON accuracy. + * @param plane plane + * @param point point + * @return true if the point is on the plane, false otherwise + */ +bool BOP_containsPoint(const MT_Plane3& plane, const MT_Point3& point) +{ + return BOP_fuzzyZero(plane.signedDistance(point)); +} + +/** + * Pre: p0, p1 and p2 is a triangle and q is an interior point. + * @param p0 point + * @param p1 point + * @param p2 point + * @param q point + * @return intersection point I + * v + * (p0)-----(I)----->(p1) + * \ ^ / + * \ |w / + * \ | / + * \ (q) / + * \ | / + * \ | / + * \ | / + * (p2) + * + * v = P1-P2 + * w = P3-Q + * r0(t) = v*t+P1 + * r1(t) = w*t+P3 + * I = r0^r1 + */ +MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, + const MT_Point3& q) +{ + MT_Vector3 v(p0.x()-p1.x(), p0.y()-p1.y(), p0.z()-p1.z()); + MT_Vector3 w(p2.x()-q.x(), p2.y()-q.y(), p2.z()-q.z()); + MT_Point3 I; + + BOP_intersect(v,p0,w,p2,I); + return I; +} + +/** + * Pre: p0, p1 and q are collinears. + * @param p0 point + * @param p1 point + * @param q point + * @return 0 if q == p0, 1 if q == p1, or a value between 0 and 1 otherwise + * + * (p0)-----(q)------------(p1) + * |<-d1-->| | + * |<---------d0---------->| + * + */ +MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q) +{ + MT_Scalar d0 = p0.distance(p1); + MT_Scalar d1 = p0.distance(q); + MT_Scalar d; + + if (BOP_fuzzyZero(d0)) d = 1.0; + else if (BOP_fuzzyZero(d1)) d = 0.0; + else d = d1 / d0; + return d; +} diff --git a/intern/boolop/intern/BOP_MathUtils.h b/intern/boolop/intern/BOP_MathUtils.h new file mode 100644 index 00000000000..3cff2d6a23b --- /dev/null +++ b/intern/boolop/intern/BOP_MathUtils.h @@ -0,0 +1,82 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Marc Freixas, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_MATHUTILS_H +#define BOP_MATHUTILS_H + +#include +#include +#include "MT_Point3.h" +#include "MT_Plane3.h" + +/* define this to give better precision comparisons */ +#define VAR_EPSILON + +#ifndef VAR_EPSILON +const MT_Scalar BOP_EPSILON(1.0e-5); +#else +const MT_Scalar BOP_EPSILON(9.3132257461547852e-10); /* ~= 2**-30 */ +#endif + +inline int BOP_sign(MT_Scalar x) { + return x < 0.0 ? -1 : x > 0.0 ? 1 : 0; +} +inline MT_Scalar BOP_abs(MT_Scalar x) { return fabs(x); } +int BOP_comp(const MT_Scalar A, const MT_Scalar B); +int BOP_comp(const MT_Tuple3& A, const MT_Tuple3& B); +int BOP_comp0(const MT_Scalar A); +inline bool BOP_fuzzyZero(MT_Scalar x) { return BOP_comp0(x) == 0; } +int BOP_exactComp(const MT_Scalar A, const MT_Scalar B); +int BOP_exactComp(const MT_Tuple3& A, const MT_Tuple3& B); +bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3); +bool BOP_collinear(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3); +bool BOP_convex(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& p4); +int BOP_concave(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4); +bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, + const MT_Point3& pL2, MT_Point3& intersection); +bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& center); +bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& p4, const MT_Point3& p5); +bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, + const MT_Point3& q); +MT_Scalar BOP_orientation(const MT_Plane3& p1, const MT_Plane3& p2); +int BOP_classify(const MT_Point3& p, const MT_Plane3& plane); +MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2); +bool BOP_containsPoint(const MT_Plane3& plane, const MT_Point3& point); +MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, + const MT_Point3& q); +MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q); + +#endif diff --git a/intern/boolop/intern/BOP_Merge.cpp b/intern/boolop/intern/BOP_Merge.cpp new file mode 100644 index 00000000000..c2b1a2db2b7 --- /dev/null +++ b/intern/boolop/intern/BOP_Merge.cpp @@ -0,0 +1,807 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Marc Freixas, Ken Hughes + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Merge.h" + + +#ifdef _MSC_VER +#if _MSC_VER < 1300 +#include +#endif +#endif + +/** + * SINGLETON (use method BOP_Merge.getInstance). + */ +BOP_Merge BOP_Merge::SINGLETON; + +/** + * Simplifies a mesh, merging its faces. + * @param m mesh + * @param v index of the first mergeable vertex (can be removed by merge) + */ +void BOP_Merge::mergeFaces(BOP_Mesh *m, BOP_Index v) +{ + m_mesh = m; + m_firstVertex = v; + + bool cont = false; + + // Merge faces + mergeFaces(); + + do { + // Add quads ... + cont = createQuads(); + if (cont) { + // ... and merge new faces + cont = mergeFaces(); + } + // ... until the merge is not succesful + } while(cont); +} + +/** + * Simplifies a mesh, merging its faces. + */ +bool BOP_Merge::mergeFaces() +{ + BOP_Indexs mergeVertices; + BOP_Vertexs vertices = m_mesh->getVertexs(); + BOP_IT_Vertexs v = vertices.begin(); + const BOP_IT_Vertexs verticesEnd = vertices.end(); + + // Advance to first mergeable vertex + advance(v,m_firstVertex); + BOP_Index pos = m_firstVertex; + + // Add unbroken vertices to the list + while(v!=verticesEnd) { + if ((*v)->getTAG() != BROKEN) mergeVertices.push_back(pos); + v++;pos++; + } + + // Merge faces with that vertices + return mergeFaces(mergeVertices); +} + + +/** + * Simplifies a mesh, merging the faces with the specified vertices. + * @param mergeVertices vertices to test + * @return true if a face merge was performed + */ +bool BOP_Merge::mergeFaces(BOP_Indexs &mergeVertices) +{ + // Check size > 0! + if (mergeVertices.size() == 0) return false; + + // New faces added by merge + BOP_Faces newFaces; + + // Old faces removed by merge + BOP_Faces oldFaces; + + // Get the first vertex index and add it to + // the current pending vertices to merge + BOP_Index v = mergeVertices[0]; + BOP_Indexs pendingVertices; + pendingVertices.push_back(v); + + // Get faces with index v that come from the same original face + BOP_LFaces facesByOriginalFace; + getFaces(facesByOriginalFace,v); + + bool merged = true; + + // Check it has any unbroken face + if (facesByOriginalFace.size()==0) { + // v has not any unbroken face (so it's a new BROKEN vertex) + (m_mesh->getVertex(v))->setTAG(BROKEN); + merged = false; + } + + // Merge vertex faces + const BOP_IT_LFaces facesEnd = facesByOriginalFace.end(); + + for(BOP_IT_LFaces facesByOriginalFaceX = facesByOriginalFace.begin(); + (facesByOriginalFaceX != facesEnd)&&merged; + facesByOriginalFaceX++) { + merged = mergeFaces((*facesByOriginalFaceX),oldFaces,newFaces,pendingVertices,v); + } + + // Check if the are some pendingVertices to merge + if (pendingVertices.size() > 1 && merged) { + // There are pending vertices that we need to merge in order to merge v ... + for(unsigned int i=1;isetTAG(BROKEN); + + // ... and add merged faces (that are the new merged faces without pending vertices) + const BOP_IT_Faces newFacesEnd = newFaces.end(); + for(BOP_IT_Faces newFace=newFaces.begin();newFace!=newFacesEnd;newFace++) { + m_mesh->addFace(*newFace); + // Also, add new face vertices to the queue of vertices to merge if they weren't + for(BOP_Index i = 0;i<(*newFace)->size();i++) { + BOP_Index vertexIndex = (*newFace)->getVertex(i); + if (vertexIndex >= m_firstVertex && !containsIndex(mergeVertices,vertexIndex)) + mergeVertices.push_back(vertexIndex); + } + } + // Set the merged vertices to BROKEN ... + const BOP_IT_Indexs pendingEnd = pendingVertices.end(); + for(BOP_IT_Indexs pendingVertex = pendingVertices.begin(); pendingVertex != pendingEnd;pendingVertex++) { + BOP_Index pV = *pendingVertex; + m_mesh->getVertex(pV)->setTAG(BROKEN); + // ... and remove them from mergeVertices queue + const BOP_IT_Indexs mergeEnd = mergeVertices.end(); + for(BOP_IT_Indexs mergeVertex = mergeVertices.begin(); mergeVertex != mergeEnd;mergeVertex++) { + BOP_Index mV = *mergeVertex; + if (mV == pV) { + mergeVertices.erase(mergeVertex); + break; + } + } + } + } + else { + // The merge was not succesful, remove the vertex frome merge vertices queue + mergeVertices.erase(mergeVertices.begin()); + + // free the not used newfaces + const BOP_IT_Faces newFacesEnd = newFaces.end(); + for(BOP_IT_Faces newFace=newFaces.begin();newFace!=newFacesEnd;newFace++) { + delete (*newFace); + } + } + + // Invoke mergeFaces and return the merge result + return (mergeFaces(mergeVertices) || merged); +} + + +/** + * Simplifies a mesh, merging the faces with vertex v that come from the same face. + * @param oldFaces sequence of old mesh faces obtained from the merge + * @param newFaces sequence of new mesh faces obtained from the merge + * @param vertices sequence of indexs (v1 ... vi = v ... vn) where : + * v is the current vertex to test, + * vj (j < i) are tested vertices, + * vk (k >= i) are vertices required to test to merge vj + * (so if a vertex vk can't be merged, the merge is not possible). + * @return true if the vertex v was 'merged' (obviously it could require to test + * some new vertices that will be added to the vertices list) + */ +bool BOP_Merge::mergeFaces(BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v) { + + bool merged = true; + + // Get faces with v that come from the same original face, (without the already 'merged' from vertices) + BOP_LFaces facesByOriginalFace; + getFaces(facesByOriginalFace,vertices,v); + + if (facesByOriginalFace.size()==0) { + // All the faces with this vertex were already merged!!! + return true; + } + else { + // Merge faces + const BOP_IT_LFaces facesEnd = facesByOriginalFace.end(); + for(BOP_IT_LFaces facesByOriginalFaceX = facesByOriginalFace.begin(); + (facesByOriginalFaceX != facesEnd)&&merged; + facesByOriginalFaceX++) { + merged = mergeFaces((*facesByOriginalFaceX),oldFaces,newFaces,vertices,v); + } + } + return merged; +} + + +/** + * Merge a set of faces removing the vertex index v. + * @param faces set of faces + * @param oldFaces set of old faces obtained from the merge + * @param newFaces set of new faces obtained from the merge + * @param vertices sequence of indexs (v1 ... vi = v ... vn) where : + * v is the current vertex to test, + * vj (j < i) are tested vertices, + * vk (k >= i) are vertices required to test to merge vj + * (so if a vertex vk can't be merged, the merge is not possible). + * @param v vertex index + * @return true if the merge is succesful, false otherwise + */ +bool BOP_Merge::mergeFaces(BOP_Faces &faces, BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v) +{ + + bool merged = false; + + if (faces.size() == 2) { + // Merge a pair of faces into a new face without v + BOP_Face *faceI = faces[0]; + BOP_Face *faceJ = faces[1]; + BOP_Face *faceK = mergeFaces(faceI,faceJ,vertices,v); + if (faceK != NULL) { + newFaces.push_back(faceK); + oldFaces.push_back(faceI); + oldFaces.push_back(faceJ); + merged = true; + } + else merged = false; + } + else if (faces.size() == 4) { + // Merge two pair of faces into a new pair without v + // First we try to perform a simplify merge to avoid more pending vertices + // (for example, if we have two triangles and two quads it will be better + // to do 3+4 and 3+4 than 3+3 and 4+4) + BOP_Face *oldFace1 = faces[0]; + BOP_Face *oldFace2, *newFace1; + unsigned int indexJ = 1; + while (indexJ < faces.size() && !merged) { + oldFace2 = faces[indexJ]; + newFace1 = mergeFaces(oldFace1,oldFace2,v); + if (newFace1 != NULL) merged = true; + else indexJ++; + } + if (merged) { + // Merge the other pair of faces + unsigned int indexK, indexL; + if (indexJ == 1) {indexK = 2;indexL = 3;} + else if (indexJ == 2) {indexK = 1;indexL = 3;} + else {indexK = 1;indexL = 2;} + BOP_Face *oldFace3 = faces[indexK]; + BOP_Face *oldFace4 = faces[indexL]; + unsigned int oldSize = vertices.size(); + BOP_Face *newFace2 = mergeFaces(oldFace3,oldFace4,vertices,v); + if (newFace2 != NULL) { + newFaces.push_back(newFace1); + newFaces.push_back(newFace2); + oldFaces.push_back(oldFace1); + oldFaces.push_back(oldFace2); + oldFaces.push_back(oldFace3); + oldFaces.push_back(oldFace4); + merged = true; + } + else { + // Undo all changes + delete newFace1; + merged = false; + unsigned int count = vertices.size() - oldSize; + if (count != 0) + vertices.erase(vertices.end() - count, vertices.end()); + } + } + if (!merged) { + // Try a complete merge + merged = true; + while (faces.size()>0 && merged) { + indexJ = 1; + BOP_Face *faceI = faces[0]; + merged = false; + while (indexJ < faces.size()) { + BOP_Face *faceJ = faces[indexJ]; + BOP_Face *faceK = mergeFaces(faceI,faceJ,vertices,v); + if (faceK != NULL) { + // faceK = faceI + faceJ and it does not include v! + faces.erase(faces.begin()+indexJ,faces.begin()+(indexJ+1)); + faces.erase(faces.begin(),faces.begin()+1); + newFaces.push_back(faceK); + oldFaces.push_back(faceI); + oldFaces.push_back(faceJ); + merged = true; + break; + } + else indexJ++; + } + } + } + } + else merged = false; // there are N=1 or N=3 or N>4 faces! + + // Return merge result + return merged; +} + +/** + * Returns a new quad from the merge of two faces (one quad and one triangle) + * that share the vertex v and come from the same original face. + * @param faceI mesh face (quad or triangle) with index v + * @param faceJ mesh face (quad or triangle) with index v + * @param v vertex index shared by both faces + * @return if the merge is possible, a new quad without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v) +{ + if (faceI->size() == 3) { + if (faceJ->size() == 4) + return mergeFaces((BOP_Face4*)faceJ,(BOP_Face3*)faceI,v); + } + else if (faceI->size() == 4) { + if (faceJ->size() == 3) + return mergeFaces((BOP_Face4*)faceI,(BOP_Face3*)faceJ,v); + } + return NULL; +} + +/** + * Returns a new face from the merge of two faces (quads or triangles) that + * share te vertex v and come from the same original face. + * @param faceI mesh face (quad or triangle) with index v + * @param faceJ mesh face (quad or triangle) with index v + * @param pending vector with pending vertices (required to merge two quads into + * a new quad or one quad and one triangle into a new triangle; these merges + * suppose to remove two vertexs, v and its neighbour, that will be a pending + * vertex to merge if it wasn't) + * @param v vertex index shared by both faces + * @return if the merge is possible, a new face without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Indexs &pending, BOP_Index v) +{ + if (faceI->size() == 3) { + if (faceJ->size() == 3) + return mergeFaces((BOP_Face3*)faceI,(BOP_Face3*)faceJ,v); + else if (faceJ->size() == 4) + return mergeFaces((BOP_Face4*)faceJ,(BOP_Face3*)faceI,pending,v); + } + else if (faceI->size() == 4) { + if (faceJ->size() == 3) + return mergeFaces((BOP_Face4*)faceI,(BOP_Face3*)faceJ,pending,v); + else if (faceJ->size() == 4) + return mergeFaces((BOP_Face4*)faceI,(BOP_Face4*)faceJ,pending,v); + } + return NULL; +} + +/** + * Returns a new triangle from the merge of two triangles that share the vertex + * v and come from the same original face. + * @param faceI mesh triangle + * @param faceJ mesh triangle + * @param v vertex index shared by both triangles + * @return If the merge is possible, a new triangle without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, prevJ, nextJ; + faceI->getNeighbours(v,prevI,nextI); + faceJ->getNeighbours(v,prevJ,nextJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + + // Merge test + if (prevI == nextJ) { + // Both faces share the edge (prevI,v) == (v,nextJ) + if (BOP_between(vertex,vNextI,vPrevJ)) { + faceK = new BOP_Face3(prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + else if (nextI == prevJ) { + // Both faces share the edge (v,nextI) == (prevJ,v) + if (BOP_between(vertex,vPrevI,vNextJ)) { + faceK = new BOP_Face3(prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + return faceK; +} + +/** + * Returns a new quad from the merge of one quad and one triangle that share + * the vertex v and come from the same original face. + * @param faceI mesh quad + * @param faceJ mesh triangle + * @param v vertex index shared by both faces + * @return If the merge is possible, a new quad without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, opp, prevJ, nextJ; + faceI->getNeighbours(v,prevI,nextI,opp); + faceJ->getNeighbours(v,prevJ,nextJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vOpp = m_mesh->getVertex(opp)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + + // Merge test + if (prevI == nextJ) { + if (BOP_between(vertex,vNextI,vPrevJ) && !BOP_collinear(vPrevJ,vPrevI,vOpp) + && BOP_convex(vOpp,vPrevI,vPrevJ,vNextI)) { + faceK = new BOP_Face4(opp,prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + else if (nextI == prevJ) { + if (BOP_between(vertex,vPrevI,vNextJ) && !BOP_collinear(vNextJ,vNextI,vOpp) + && BOP_convex(vOpp,vPrevI,vNextJ,vNextI)) { + faceK = new BOP_Face4(opp,prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + return faceK; +} + +/** + * Returns a new face (quad or triangle) from the merge of one quad and one + * triangle that share the vertex v and come from the same original face. + * @param faceI mesh quad + * @param faceJ mesh triangle + * @param pending vector with pending vertices (required to merge one quad + * and one triangle into a new triangle; it supposes to remove two vertexs, + * v and its neighbour, that will be a new pending vertex if it wasn't) + * @param v vertex index shared by both faces + * @return If the merge is possible, a new face without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Indexs &pending, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, opp, prevJ, nextJ; + faceI->getNeighbours(v,prevI,nextI,opp); + faceJ->getNeighbours(v,prevJ,nextJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vOpp = m_mesh->getVertex(opp)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + + // Merge test + if (prevI == nextJ) { + if (BOP_between(vertex,vNextI,vPrevJ)) { + if (!BOP_collinear(vPrevJ,vPrevI,vOpp) && BOP_convex(vOpp,vPrevI,vPrevJ,vNextI)) { + // The result is a new quad + faceK = new BOP_Face4(opp,prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + else if (BOP_between(vPrevI,vPrevJ,vOpp)) { + // The result is a triangle (only if prevI can be merged) + if (prevI < m_firstVertex) return NULL; // It can't be merged + faceK = new BOP_Face3(nextI,opp,prevJ,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + if (!containsIndex(pending, prevI)) pending.push_back(prevI); + } + } + } + else if (nextI == prevJ) { + if (BOP_between(vertex,vPrevI,vNextJ)) { + if (!BOP_collinear(vNextJ,vNextI,vOpp) && BOP_convex(vOpp,vPrevI,vNextJ,vNextI)) { + // The result is a new quad + faceK = new BOP_Face4(opp,prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + else if (BOP_between(vNextI,vOpp,vNextJ)) { + // The result is a triangle (only if nextI can be merged) + if (nextI < m_firstVertex) return NULL; + faceK = new BOP_Face3(prevI,nextJ,opp,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + if (!containsIndex(pending, nextI)) pending.push_back(nextI); + } + } + } + return faceK; +} + +/** + * Returns a new quad from the merge of two quads that share + * the vertex v and come from the same original face. + * @param faceI mesh quad + * @param faceJ mesh quad + * @param pending vector with pending vertices (required to merge the two + * quads supposes to remove two vertexs, v and its neighbour, + * that will be a new pending vertex if it wasn't) + * @param v vertex index shared by both quads + * @return If the merge is possible, a new quad without v + */ +BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face4 *faceJ, BOP_Indexs &pending, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, oppI, prevJ, nextJ, oppJ; + faceI->getNeighbours(v,prevI,nextI,oppI); + faceJ->getNeighbours(v,prevJ,nextJ,oppJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vOppI = m_mesh->getVertex(oppI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + MT_Point3 vOppJ = m_mesh->getVertex(oppJ)->getPoint(); + + // Merge test + if (prevI == nextJ) { + // prevI/nextJ will be a new vertex required to merge + if (prevI < m_firstVertex) return NULL; // It can't be merged + if (BOP_between(vertex,vPrevJ,vNextI) && BOP_between(vNextJ,vOppJ,vOppI)) { + faceK = new BOP_Face4(oppJ,prevJ,nextI,oppI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + // We add prevI to the pending list if it wasn't yet + if (!containsIndex(pending, prevI)) pending.push_back(prevI); + } + } + else if (nextI == prevJ) { + // nextI/prevJ will be a new vertex required to merge + if (nextI < m_firstVertex) return NULL; // It can't be merged + if (BOP_between(vertex,vPrevI,vNextJ) && BOP_between(vNextI,vOppI,vOppJ)) { + faceK = new BOP_Face4(oppI,prevI,nextJ,oppJ,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + // Add nextI to the pending list if it wasn't yet + if (!containsIndex(pending, nextI)) pending.push_back(nextI); + } + } + return faceK; +} + + +/** + * Simplifies the mesh, merging the pairs of triangles that come frome the + * same original face and define a quad. + * @return true if a quad was added, false otherwise + */ +bool BOP_Merge::createQuads() +{ + + BOP_Faces quads; + + // Get mesh faces + BOP_Faces faces = m_mesh->getFaces(); + + + // Merge mesh triangles + const BOP_IT_Faces facesIEnd = (faces.end()-1); + const BOP_IT_Faces facesJEnd = faces.end(); + for(BOP_IT_Faces faceI=faces.begin();faceI!=facesIEnd;faceI++) { + if ((*faceI)->getTAG() == BROKEN || (*faceI)->size() != 3) continue; + for(BOP_IT_Faces faceJ=(faceI+1);faceJ!=facesJEnd;faceJ++) { + if ((*faceJ)->getTAG() == BROKEN || (*faceJ)->size() != 3 || + (*faceJ)->getOriginalFace() != (*faceI)->getOriginalFace()) continue; + + // Test if both triangles share a vertex index + BOP_Index v; + bool found = false; + for(unsigned int i=0;i<3 && !found;i++) { + v = (*faceI)->getVertex(i); + found = (*faceJ)->containsVertex(v); + + } + if (!found) continue; + + BOP_Face *faceK = createQuad((BOP_Face3*)*faceI,(BOP_Face3*)*faceJ,v); + if (faceK != NULL) { + // Set triangles to BROKEN + (*faceI)->setTAG(BROKEN); + (*faceJ)->setTAG(BROKEN); + quads.push_back(faceK); + break; + } + } + } + + // Add quads to mesh + const BOP_IT_Faces quadsEnd = quads.end(); + for(BOP_IT_Faces quad=quads.begin();quad!=quadsEnd;quad++) m_mesh->addFace(*quad); + return (quads.size() > 0); +} + +/** + * Returns a new quad (convex) from the merge of two triangles that share the + * vertex index v. + * @param faceI mesh triangle + * @param faceJ mesh triangle + * @param v vertex index shared by both triangles + * @return a new convex quad if the merge is possible + */ +BOP_Face* BOP_Merge::createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v) +{ + BOP_Face *faceK = NULL; + + // Get faces data + BOP_Index prevI, nextI, prevJ, nextJ; + faceI->getNeighbours(v,prevI,nextI); + faceJ->getNeighbours(v,prevJ,nextJ); + MT_Point3 vertex = m_mesh->getVertex(v)->getPoint(); + MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint(); + MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint(); + MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint(); + MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint(); + + // Quad test + if (prevI == nextJ) { + if (!BOP_collinear(vNextI,vertex,vPrevJ) && !BOP_collinear(vNextI,vPrevI,vPrevJ) && + BOP_convex(vertex,vNextI,vPrevI,vPrevJ)) { + faceK = new BOP_Face4(v,nextI,prevI,prevJ,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + else if (nextI == prevJ) { + if (!BOP_collinear(vPrevI,vertex,vNextJ) && !BOP_collinear(vPrevI,vNextI,vNextJ) && + BOP_convex(vertex,vNextJ,vNextI,vPrevI)) { + faceK = new BOP_Face4(v,nextJ,nextI,prevI,faceI->getPlane(),faceI->getOriginalFace()); + faceK->setTAG(faceI->getTAG()); + } + } + return faceK; +} + +/** + * Returns if a index is inside a set of indexs. + * @param indexs set of indexs + * @param i index + * @return true if the index is inside the set, false otherwise + */ +bool BOP_Merge::containsIndex(BOP_Indexs indexs, BOP_Index i) +{ + const BOP_IT_Indexs indexsEnd = indexs.end(); + for(BOP_IT_Indexs it=indexs.begin();it!=indexsEnd;it++) { + if (*it == i) return true; + } + return false; +} + +/** + * Creates a list of lists L1, L2, ... LN where + * LX = mesh faces with vertex v that come from the same original face + * @param facesByOriginalFace list of faces lists + * @param v vertex index + */ +void BOP_Merge::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Index v) +{ + // Get edges with vertex v + BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges(); + const BOP_IT_Indexs edgeEnd = edgeIndexs.end(); + for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) { + // Foreach edge, add its no broken faces to the output list + BOP_Edge* edge = m_mesh->getEdge(*edgeIndex); + BOP_Indexs faceIndexs = edge->getFaces(); + const BOP_IT_Indexs faceEnd = faceIndexs.end(); + for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) { + BOP_Face* face = m_mesh->getFace(*faceIndex); + if (face->getTAG() != BROKEN) { + bool found = false; + // Search if we already have created a list for the + // faces that come from the same original face + const BOP_IT_LFaces lfEnd = facesByOriginalFace.end(); + for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin(); + facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) { + if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) { + // Search that the face has not been added to the list before + for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) { + if ((*facesByOriginalFaceX)[i] == face) { + found = true; + break; + } + } + if (!found) { + // Add the face to the list + if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face); + else facesByOriginalFaceX->push_back(face); + found = true; + } + break; + } + } + if (!found) { + // Create a new list and add the current face + BOP_Faces facesByOriginalFaceX; + facesByOriginalFaceX.push_back(face); + facesByOriginalFace.push_back(facesByOriginalFaceX); + } + } + } + } +} + +/** + * Creates a list of lists L1, L2, ... LN where + * LX = mesh faces with vertex v that come from the same original face + * and without any of the vertices that appear before v in vertices + * @param facesByOriginalFace list of faces lists + * @param vertices vector with vertices indexs that contains v + * @param v vertex index + */ +void BOP_Merge::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v) +{ + // Get edges with vertex v + BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges(); + const BOP_IT_Indexs edgeEnd = edgeIndexs.end(); + for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) { + // Foreach edge, add its no broken faces to the output list + BOP_Edge* edge = m_mesh->getEdge(*edgeIndex); + BOP_Indexs faceIndexs = edge->getFaces(); + const BOP_IT_Indexs faceEnd = faceIndexs.end(); + for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) { + BOP_Face* face = m_mesh->getFace(*faceIndex); + if (face->getTAG() != BROKEN) { + // Search if the face contains any of the forbidden vertices + bool found = false; + for(BOP_IT_Indexs vertex = vertices.begin();*vertex!= v;vertex++) { + if (face->containsVertex(*vertex)) { + // face contains a forbidden vertex! + found = true; + break; + } + } + if (!found) { + // Search if we already have created a list with the + // faces that come from the same original face + const BOP_IT_LFaces lfEnd = facesByOriginalFace.end(); + for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin(); + facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) { + if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) { + // Search that the face has not been added to the list before + for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) { + if ((*facesByOriginalFaceX)[i] == face) { + found = true; + break; + } + } + if (!found) { + // Add face to the list + if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face); + else facesByOriginalFaceX->push_back(face); + found = true; + } + break; + } + } + if (!found) { + // Create a new list and add the current face + BOP_Faces facesByOriginalFaceX; + facesByOriginalFaceX.push_back(face); + facesByOriginalFace.push_back(facesByOriginalFaceX); + } + } + } + } + } +} diff --git a/intern/boolop/intern/BOP_Merge.h b/intern/boolop/intern/BOP_Merge.h new file mode 100644 index 00000000000..2ccce8e137b --- /dev/null +++ b/intern/boolop/intern/BOP_Merge.h @@ -0,0 +1,74 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_MERGE_H +#define BOP_MERGE_H + +#include "BOP_Mesh.h" +#include "BOP_Tag.h" +#include "BOP_MathUtils.h" +#include "MEM_SmartPtr.h" + +typedef vector< BOP_Faces > BOP_LFaces; +typedef vector< BOP_Faces >::iterator BOP_IT_LFaces; + +class BOP_Merge { + private: + BOP_Mesh* m_mesh; + BOP_Index m_firstVertex; + static BOP_Merge SINGLETON; + + BOP_Merge() {}; + bool mergeFaces(); + bool mergeFaces(BOP_Indexs &mergeVertices); + bool mergeFaces(BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v); + bool mergeFaces(BOP_Faces &faces, BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Indexs &pending, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Indexs &pending, BOP_Index v); + BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face4 *faceJ, BOP_Indexs &pending, BOP_Index v); + bool createQuads(); + BOP_Face *createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v); + bool containsIndex(BOP_Indexs indexs, BOP_Index index); + void getFaces(BOP_LFaces &facesByOriginalFace, BOP_Index v); + void getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v); + + public: + + static BOP_Merge &getInstance() { + return SINGLETON; + } + + void mergeFaces(BOP_Mesh *m, BOP_Index v); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Mesh.cpp b/intern/boolop/intern/BOP_Mesh.cpp new file mode 100644 index 00000000000..0b70cc61533 --- /dev/null +++ b/intern/boolop/intern/BOP_Mesh.cpp @@ -0,0 +1,1080 @@ +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Mesh.h" +#include "BOP_MathUtils.h" +#include +#include + +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" + +BOP_Mesh::BOP_Mesh() +{ +#ifdef HASH +#ifdef HASH_PRINTF_DEBUG + printf ("has hashing\n"); +#endif + hash = NULL; + hashsize = 0; +#endif +} + +/** + * Destroys a mesh. + */ +BOP_Mesh::~BOP_Mesh() +{ + const BOP_IT_Vertexs vertexsEnd = m_vertexs.end(); + for(BOP_IT_Vertexs itv=m_vertexs.begin();itv!=vertexsEnd;itv++){ + delete *itv; + } + m_vertexs.clear(); + + const BOP_IT_Edges edgesEnd = m_edges.end(); + for(BOP_IT_Edges ite=m_edges.begin();ite!=edgesEnd;ite++){ + delete *ite; + } + m_edges.clear(); + + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces itf=m_faces.begin();itf!=facesEnd;itf++){ + delete *itf; + } + m_faces.clear(); + +#ifdef HASH + while( hashsize ) { + --hashsize; + BLI_freelistN( &hash[hashsize] ); + } + MEM_freeN( hash ); + hash = NULL; +#endif +} + +/** + * Adds a new vertex. + * @param p vertex point + * @return mesh vertex index + */ +BOP_Index BOP_Mesh::addVertex(MT_Point3 p) +{ + m_vertexs.push_back(new BOP_Vertex(p)); + return m_vertexs.size()-1; +} + +/** + * Adds a new edge. + * @param v1 mesh vertex index + * @param v2 mesh vertex index + * @return mesh edge index + */ +BOP_Index BOP_Mesh::addEdge(BOP_Index v1, BOP_Index v2) +{ +#ifdef HASH + /* prepare a new hash entry for the edge */ + int minv; + EdgeEntry *h = (EdgeEntry *)MEM_callocN( sizeof( EdgeEntry ), "edgehash" ); + + /* store sorted, smallest vert first */ + if( v1 < v2 ) { + minv = HASH(v1); + h->v1 = v1; + h->v2 = v2; + } else { + minv = HASH(v2); + h->v1 = v2; + h->v2 = v1; + } + h->index = m_edges.size(); + + /* if hash index larger than hash list, extend the list */ + if( minv >= hashsize ) { + int newsize = (minv + 8) & ~7; + ListBase *nhash = (ListBase *)MEM_mallocN( + newsize * sizeof( ListBase ), + "edgehashtable" ); + /* copy old entries */ + memcpy( nhash, hash, sizeof( ListBase ) * hashsize ); + /* clear new ones */ + while( hashsize < newsize ) { + nhash[hashsize].first = nhash[hashsize].last = NULL; + ++hashsize; + } + if( hash ) + MEM_freeN( hash ); + hash = nhash; + } + + /* add the entry to tail of the right hash list */ + BLI_addtail( &hash[minv], h ); +#endif + m_edges.push_back(new BOP_Edge(v1,v2)); + return m_edges.size()-1; +} + +#ifdef HASH +/** + * replace one vertex with another in the hash list + * @param o old mesh vertex index + * @param n new mesh vertex index + * @param x edge's other mesh vertex index + */ +void BOP_Mesh::rehashVertex(BOP_Index o, BOP_Index n, BOP_Index x) +{ + EdgeEntry *edge; + int minv = HASH(o); + BOP_Index v1, v2; + + /* figure out where and what to look for */ + if( o < x ) { + minv = HASH(o); + v1 = o; v2 = x; + } else { + minv = HASH(x); + v1 = x; v2 = o; + } + + /* if hash is valid, search for the match */ + if( minv < hashsize ) { + for(edge = (EdgeEntry *)hash[minv].first; + edge; edge = edge->next ) { + if(edge->v1 == v1 && edge->v2 == v2) + break; + } + + /* NULL edge == no match */ + if(!edge) { +#ifdef HASH_PRINTF_DEBUG + printf ("OOPS! didn't find edge (%d %d)\n",v1,v2); +#endif + return; + } +#ifdef HASH_PRINTF_DEBUG + printf ("found edge (%d %d)\n",v1,v2); +#endif + /* remove the edge from the old hash list */ + BLI_remlink( &hash[minv], edge ); + + /* decide where the new edge should go */ + if( n < x ) { + minv = HASH(n); + v1 = n; v2 = x; + } else { + minv = HASH(x); + edge->v1 = x; edge->v2 = n; + } + + /* if necessary, extend the hash list */ + if( minv >= hashsize ) { +#ifdef HASH_PRINTF_DEBUG + printf ("OOPS! new vertex too large! (%d->%d)\n",o,n); +#endif + int newsize = (minv + 8) & ~7; + ListBase *nhash = (ListBase *)MEM_mallocN( + newsize * sizeof( ListBase ), + "edgehashtable" ); + memcpy( nhash, hash, sizeof( ListBase ) * hashsize ); + while( hashsize < newsize ) { + nhash[hashsize].first = nhash[hashsize].last = NULL; + ++hashsize; + } + if( hash ) + MEM_freeN( hash ); + hash = nhash; + } + + /* add the entry to tail of the right hash list */ + BLI_addtail( &hash[minv], edge ); + } else { +#ifdef HASH_PRINTF_DEBUG + printf ("OOPS! hash not large enough for (%d %d)\n",minv,hashsize); +#endif + } +} +#endif + +/** + * Adds a new face. + * @param face mesh face + * @return mesh face index + */ +BOP_Index BOP_Mesh::addFace(BOP_Face *face) +{ + if (face->size()==3) + return addFace((BOP_Face3 *)face); + else + return addFace((BOP_Face4 *)face); +} + +/** + * Adds a new triangle. + * @param face mesh triangle + * @return mesh face index + */ +BOP_Index BOP_Mesh::addFace(BOP_Face3 *face) +{ + BOP_Index indexface = m_faces.size(); + + BOP_Index index1 = face->getVertex(0); + BOP_Index index2 = face->getVertex(1); + BOP_Index index3 = face->getVertex(2); + + m_faces.push_back((BOP_Face *)face); + + BOP_Index edge; + + if (!getIndexEdge(index1,index2,edge)) { + edge = addEdge(index1,index2); + getVertex(index1)->addEdge(edge); + getVertex(index2)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index2,index3,edge)) { + edge = addEdge(index2,index3); + getVertex(index2)->addEdge(edge); + getVertex(index3)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index3,index1,edge)) { + edge = addEdge(index3,index1); + getVertex(index3)->addEdge(edge); + getVertex(index1)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if ((index1 == index2) || (index1 == index3) || (index2 == index3)) + face->setTAG(BROKEN); + + return indexface; +} + +/** + * Adds a new quad. + * @param face mesh quad + * @return mesh face index + */ +BOP_Index BOP_Mesh::addFace(BOP_Face4 *face) +{ + m_faces.push_back((BOP_Face *)face); + BOP_Index indexface = m_faces.size()-1; + + BOP_Index index1 = face->getVertex(0); + BOP_Index index2 = face->getVertex(1); + BOP_Index index3 = face->getVertex(2); + BOP_Index index4 = face->getVertex(3); + + BOP_Index edge; + + if (!getIndexEdge(index1,index2,edge)) { + edge = addEdge(index1,index2); + getVertex(index1)->addEdge(edge); + getVertex(index2)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index2,index3,edge)) { + edge = addEdge(index2,index3); + getVertex(index2)->addEdge(edge); + getVertex(index3)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index3,index4,edge)) { + edge = addEdge(index3,index4); + getVertex(index3)->addEdge(edge); + getVertex(index4)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if (!getIndexEdge(index4,index1,edge)) { + edge = addEdge(index4,index1); + getVertex(index4)->addEdge(edge); + getVertex(index1)->addEdge(edge); + } + + getEdge(edge)->addFace(indexface); + + if ((index1 == index2) || (index1 == index3) || (index1 == index4) || + (index2 == index3) || (index2 == index4) || (index3 == index4)) + face->setTAG(BROKEN); + + return m_faces.size()-1; +} + +/** + * Returns if a faces set contains the specified face. + * @param faces faces set + * @param face face + * @return true if the set contains the specified face + */ +bool BOP_Mesh::containsFace(BOP_Faces *faces, BOP_Face *face) +{ + const BOP_IT_Faces facesEnd = faces->end(); + for(BOP_IT_Faces it = faces->begin();it!=facesEnd;it++) { + if (face == *it) + return true; + } + + return false; +} +/** + * Returns the first edge with the specified vertex index from a list of edge indexs. + * @param edges edge indexs + * @param v vertex index + * @return first edge with the specified vertex index, NULL otherwise + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Indexs edges, BOP_Index v) +{ + const BOP_IT_Indexs edgesEnd = edges.end(); + for(BOP_IT_Indexs it=edges.begin();it!=edgesEnd;it++){ + BOP_Edge *edge = m_edges[*it]; + if ((edge->getVertex1() == v) || (edge->getVertex2() == v)) + return edge; + } + return NULL; +} + +/** + * Returns the mesh edge with the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @return mesh edge with the specified vertex indexs, NULL otherwise + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Index v1, BOP_Index v2) +{ +#ifdef HASH + int minv; + EdgeEntry *edge; + + /* figure out where and what to search for */ + if( v1 < v2 ) { + minv = HASH(v1); + } else { + minv = HASH(v2); + BOP_Index tmp = v1; + v1 = v2; + v2 = tmp; + } + + /* if hash index valid, search the list and return match if found */ + if( minv < hashsize ) { + for(edge = (EdgeEntry *)hash[minv].first; + edge; edge = edge->next ) { + if(edge->v1 == v1 && edge->v2 == v2) + return m_edges[edge->index]; + } + } +#else + const BOP_IT_Edges edgesEnd = m_edges.end(); + for(BOP_IT_Edges edge=m_edges.begin();edge!=edgesEnd;edge++) { + if (((*edge)->getVertex1() == v1 && (*edge)->getVertex2() == v2) || + ((*edge)->getVertex1() == v2 && (*edge)->getVertex2() == v1)) + return *edge; + } +#endif + return NULL; +} + +/** + * Returns the mesh edge index with the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param e edge index with the specified vertex indexs + * @return true if there is a mesh edge with the specified vertex indexs, false otherwise + */ +bool BOP_Mesh::getIndexEdge(BOP_Index v1, BOP_Index v2, BOP_Index &e) +{ +#ifdef HASH + int minv; + EdgeEntry *edge; + + /* figure out what and where to look */ + if( v1 < v2 ) { + minv = HASH(v1); + } else { + minv = HASH(v2); + BOP_Index tmp = v1; + v1 = v2; + v2 = tmp; + } + + /* if hash index is valid, look for a match */ + if( minv < hashsize ) { + for(edge = (EdgeEntry *)hash[minv].first; + edge; edge = edge->next ) { + if(edge->v1 == v1 && edge->v2 == v2) + break; + } + + /* edge != NULL means match */ + if(edge) { +#ifdef HASH_PRINTF_DEBUG + printf ("found edge (%d %d)\n",v1,v2); +#endif + e = edge->index; + return true; + } +#ifdef HASH_PRINTF_DEBUG + else + printf ("didn't find edge (%d %d)\n",v1,v2); +#endif + } +#else + BOP_Index pos=0; + const BOP_IT_Edges edgesEnd = m_edges.end(); + for(BOP_IT_Edges edge=m_edges.begin();edge!=edgesEnd;edge++,pos++) { + if (((*edge)->getVertex1() == v1 && (*edge)->getVertex2() == v2) || + ((*edge)->getVertex1() == v2 && (*edge)->getVertex2() == v1)){ + e = pos; + return true; + } + } +#endif + return false; +} + +/** + * Returns the mesh edge on the specified face and relative edge index. + * @param face mesh face + * @param edge face relative edge index + * @return mesh edge on the specified face and relative index, NULL otherwise + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Face *face, unsigned int edge) +{ + if (face->size()==3) + return getEdge((BOP_Face3 *)face,edge); + else + return getEdge((BOP_Face4 *)face,edge); +} + +/** + * Returns the mesh edge on the specified triangle and relative edge index. + * @param face mesh triangle + * @param edge face relative edge index + * @return mesh edge on the specified triangle and relative index, NULL otherwise + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Face3 *face, unsigned int edge) +{ + switch(edge){ + case 1: + return getEdge(m_vertexs[face->getVertex(0)]->getEdges(),face->getVertex(1)); + case 2: + return getEdge(m_vertexs[face->getVertex(1)]->getEdges(),face->getVertex(2)); + case 3: + return getEdge(m_vertexs[face->getVertex(2)]->getEdges(),face->getVertex(0)); + }; + + return NULL; +} + +/** + * Returns the mesh edge on the specified quad and relative edge index. + * @param face mesh quad + * @param edge face relative edge index + * @return mesh edge on the specified quad and relative index, NULL otherwise + */ +BOP_Edge * BOP_Mesh::getEdge(BOP_Face4 *face, unsigned int edge) +{ + switch(edge){ + case 1: + return getEdge(m_vertexs[face->getVertex(0)]->getEdges(),face->getVertex(1)); + case 2: + return getEdge(m_vertexs[face->getVertex(1)]->getEdges(),face->getVertex(2)); + case 3: + return getEdge(m_vertexs[face->getVertex(2)]->getEdges(),face->getVertex(3)); + case 4: + return getEdge(m_vertexs[face->getVertex(3)]->getEdges(),face->getVertex(0)); + }; + + return NULL; +} + +/** + * Returns the mesh face with the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param v3 vertex index + * @return mesh edge with the specified vertex indexs, NULL otherwise + */ +BOP_Face* BOP_Mesh::getFace(BOP_Index v1, BOP_Index v2, BOP_Index v3) +{ + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++) { + if ((*face)->containsVertex(v1) && (*face)->containsVertex(v2) && + (*face)->containsVertex(v3)) + return (*face); + } + return NULL; +} + +/** + * Returns the mesh face index with the specified vertex indexs. + * @param v1 vertex index + * @param v2 vertex index + * @param v3 vertex index + * @param f face index with the specified vertex indexs + * @return true if there is a mesh face with the specified vertex indexs, false otherwise + */ +bool BOP_Mesh::getIndexFace(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index &f) +{ + BOP_Index pos=0; + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++,pos++) { + if ((*face)->containsVertex(v1) && (*face)->containsVertex(v2) && + (*face)->containsVertex(v3)){ + f = pos; + return true; + } + } + return false; +} + +/** + * Returns the vertices set of this mesh. + * @return vertices set + */ +BOP_Vertexs &BOP_Mesh::getVertexs() +{ + return m_vertexs; +} + +/** + * Returns the edges set of this mesh. + * @return edges set + */ +BOP_Edges &BOP_Mesh::getEdges() +{ + return m_edges; +} + +/** + * Returns the faces set of this mesh. + * @return faces set + */ +BOP_Faces &BOP_Mesh::getFaces() +{ + return m_faces; +} + +/** + * Returns the mesh vertex with the specified index. + * @param i vertex index + * @return vertex with the specified index + */ +BOP_Vertex* BOP_Mesh::getVertex(BOP_Index i) +{ + return m_vertexs[i]; +} + +/** + * Returns the mesh edge with the specified index. + * @param i edge index + * @return edge with the specified index + */ +BOP_Edge* BOP_Mesh::getEdge(BOP_Index i) +{ + return m_edges[i]; +} + +/** + * Returns the mesh face with the specified index. + * @param i face index + * @return face with the specified index + */ +BOP_Face* BOP_Mesh::getFace(BOP_Index i) +{ + return m_faces[i]; +} + +/** + * Returns the number of vertices of this mesh. + * @return number of vertices + */ +unsigned int BOP_Mesh::getNumVertexs() +{ + return m_vertexs.size(); +} + +/** + * Returns the number of edges of this mesh. + * @return number of edges + */ +unsigned int BOP_Mesh::getNumEdges() +{ + return m_edges.size(); +} + +/** + * Returns the number of faces of this mesh. + * @return number of faces + */ +unsigned int BOP_Mesh::getNumFaces() +{ + return m_faces.size(); +} + +/** + * Returns the number of vertices of this mesh with the specified tag. + * @return number of vertices with the specified tag + */ +unsigned int BOP_Mesh::getNumVertexs(BOP_TAG tag) +{ + unsigned int count = 0; + const BOP_IT_Vertexs vertexsEnd = m_vertexs.end(); + for(BOP_IT_Vertexs vertex=m_vertexs.begin();vertex!=vertexsEnd;vertex++) { + if ((*vertex)->getTAG() == tag) count++; + } + return count; +} +/** + * Returns the number of faces of this mesh with the specified tag. + * @return number of faces with the specified tag + */ +unsigned int BOP_Mesh::getNumFaces(BOP_TAG tag) +{ + unsigned int count = 0; + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++) { + if ((*face)->getTAG() == tag) count++; + } + return count; +} + +/** + * Marks faces which bad edges as BROKEN (invalid face, no further processing). + * @param edge edge which is being replaced + * @param mesh mesh containing faces + */ + +static void removeBrokenFaces( BOP_Edge *edge, BOP_Mesh *mesh ) +{ + BOP_Faces m_faces = mesh->getFaces(); + + BOP_Indexs edgeFaces = edge->getFaces(); + const BOP_IT_Indexs edgeFacesEnd = edgeFaces.end(); + for(BOP_IT_Indexs idxFace=edgeFaces.begin();idxFace!=edgeFacesEnd; + idxFace++) + m_faces[*idxFace]->setTAG(BROKEN); +} + +/** + * Replaces a vertex index. + * @param oldIndex old vertex index + * @param newIndex new vertex index + */ +BOP_Index BOP_Mesh::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) +{ + BOP_IT_Indexs oldEdgeIndex; + if (oldIndex==newIndex) return newIndex; + + // Update faces, edges and vertices + BOP_Vertex *oldVertex = m_vertexs[oldIndex]; + BOP_Vertex *newVertex = m_vertexs[newIndex]; + BOP_Indexs oldEdges = oldVertex->getEdges(); + + // Update faces to the newIndex + BOP_IT_Indexs oldEdgesEnd = oldEdges.end(); + for(oldEdgeIndex=oldEdges.begin();oldEdgeIndex!=oldEdgesEnd; + oldEdgeIndex++) { + BOP_Edge *edge = m_edges[*oldEdgeIndex]; + if ((edge->getVertex1()==oldIndex && edge->getVertex2()==newIndex) || + (edge->getVertex2()==oldIndex && edge->getVertex1()==newIndex)) { + // Remove old edge ==> set edge faces to BROKEN + removeBrokenFaces( edge, this ); + oldVertex->removeEdge(*oldEdgeIndex); + newVertex->removeEdge(*oldEdgeIndex); + } + else { + BOP_Indexs faces = edge->getFaces(); + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs face=faces.begin();face!=facesEnd;face++) { + if (m_faces[*face]->getTAG()!=BROKEN) + m_faces[*face]->replaceVertexIndex(oldIndex,newIndex); + } + } + } + + oldEdgesEnd = oldEdges.end(); + for(oldEdgeIndex=oldEdges.begin();oldEdgeIndex!=oldEdgesEnd; + oldEdgeIndex++) { + BOP_Edge * edge = m_edges[*oldEdgeIndex]; + BOP_Edge * edge2; + BOP_Index v1 = edge->getVertex1(); + + v1 = (v1==oldIndex?edge->getVertex2():v1); + if ((edge2 = getEdge(newIndex,v1)) == NULL) { + edge->replaceVertexIndex(oldIndex,newIndex); + if ( edge->getVertex1() == edge->getVertex2() ) { + removeBrokenFaces( edge, this ); + oldVertex->removeEdge(*oldEdgeIndex); + } +#ifdef HASH + rehashVertex(oldIndex,newIndex,v1); +#endif + newVertex->addEdge(*oldEdgeIndex); + } + else { + BOP_Indexs faces = edge->getFaces(); + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs f=faces.begin();f!=facesEnd;f++) { + if (m_faces[*f]->getTAG()!=BROKEN) + edge2->addFace(*f); + } + BOP_Vertex *oppositeVertex = m_vertexs[v1]; + oppositeVertex->removeEdge(*oldEdgeIndex); + edge->replaceVertexIndex(oldIndex,newIndex); + if ( edge->getVertex1() == edge->getVertex2() ) { + removeBrokenFaces( edge, this ); + oldVertex->removeEdge(*oldEdgeIndex); + newVertex->removeEdge(*oldEdgeIndex); + } +#ifdef HASH + rehashVertex(oldIndex,newIndex,v1); +#endif + } + } + oldVertex->setTAG(BROKEN); + + return newIndex; +} + +bool BOP_Mesh::isClosedMesh() +{ + for(unsigned int i=0; igetFaces(); + unsigned int count = 0; + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) { + if (m_faces[*it]->getTAG()!=BROKEN) + count++; + } + + if ((count%2)!=0) return false; + } + + return true; +} + + +/** *************************************************************************** + * DEBUG METHODS * + * This functions are used to test the mesh state and debug program errors. * + ******************************************************************************/ + +/** + * print + */ +void BOP_Mesh::print() +{ + unsigned int i; + cout << "--Faces--" << endl; + for(i=0;igetPoint() << endl; + } +} + +/** + * printFormat + */ +void BOP_Mesh::printFormat(BOP_Faces *faces) +{ + if (faces->size()) { + for(unsigned int it=1;itsize();it++) { + if ((*faces)[it]->getTAG()!=BROKEN) { + cout << m_vertexs[(*faces)[it]->getVertex(0)]->getPoint() << " "; + cout << m_vertexs[(*faces)[it]->getVertex(1)]->getPoint() << " "; + cout << m_vertexs[(*faces)[it]->getVertex(2)]->getPoint() << endl; + } + } + } +} + +/** + * saveFormat + */ +void BOP_Mesh::saveFormat(BOP_Faces *faces,char *filename) +{ + ofstream fout(filename); + + if (!fout.is_open()) { + cerr << "BOP_Mesh::saveFormat Error: Could not create file." << endl; + return; + } + + unsigned int count = 0; + if (faces->size()) { + for(unsigned int it=0;itsize();it++) { + if ((*faces)[it]->getTAG()!=BROKEN) { + count++; + } + } + } + + fout << count << endl; + if (faces->size()) { + for(unsigned int it=0;itsize();it++) { + if ((*faces)[it]->getTAG()!=BROKEN){ + fout << m_vertexs[(*faces)[it]->getVertex(0)]->getPoint() << " "; + fout << m_vertexs[(*faces)[it]->getVertex(1)]->getPoint() << " "; + fout << m_vertexs[(*faces)[it]->getVertex(2)]->getPoint() << endl; + } + } + } + + fout.close(); +} + +/** + * printFormat + */ +void BOP_Mesh::printFormat() +{ + cout << "--Vertices--" << endl; + if (m_vertexs.size()>0) { + cout << "{" << m_vertexs[0]->getPoint().x() << ","; + cout << m_vertexs[0]->getPoint().y() << ","; + cout << m_vertexs[0]->getPoint().z() << "}"; + for(unsigned int i=1;igetPoint().x() << ","; + cout << m_vertexs[i]->getPoint().y() << ","; + cout << m_vertexs[i]->getPoint().z() << "}"; + } + cout << endl; + } + + cout << "--Faces--" << endl; + if (m_faces.size()>0) { + cout << "{" << m_faces[0]->getVertex(0) << ","; + cout << m_faces[0]->getVertex(1) << "," << m_faces[0]->getVertex(2) << "}"; + for(unsigned int i=1;igetVertex(0) << ","; + cout << m_faces[i]->getVertex(1) << "," << m_faces[i]->getVertex(2) << "}"; + } + cout << endl; + } +} + +/** + * printFace + */ +void BOP_Mesh::printFace(BOP_Face *face, int col) +{ + cout << "--Face" << endl; + cout << m_vertexs[face->getVertex(0)]->getPoint(); + cout << " " << m_vertexs[face->getVertex(1)]->getPoint(); + cout << " " << m_vertexs[face->getVertex(2)]->getPoint(); + if (face->size()==4) + cout << " " << m_vertexs[face->getVertex(3)]->getPoint(); + cout << " " << col << endl; +} + +/** + * testMesh + */ +void BOP_Mesh::testMesh() +{ + + BOP_Face* cares[10]; + unsigned int nedges=0,i; + for(i=0;igetFaces(); + unsigned int count = 0; + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) { + if (m_faces[*it]->getTAG()!=BROKEN) { + cares[count] = m_faces[*it]; + count++; + + } + } + + if ((count%2)!=0) nedges++; + } + if (nedges) + cout << nedges << " wrong edges." << endl; + else + cout << "well edges." << endl; + + unsigned int duplFaces = 0; + unsigned int wrongFaces = 0; + for(i=0;igetTAG()==BROKEN) + continue; + + if (testFace(faceI)){ + wrongFaces++; + cout << "Wrong Face: " << faceI << endl; + } + + for(unsigned int j=i+1;jgetTAG()==BROKEN) + continue; + + if (testFaces(faceI,faceJ)){ + duplFaces++; + cout << "Duplicate FaceI: " << faceI << endl; + cout << "Duplicate FaceJ: " << faceJ << endl; + } + } + } + + cout << duplFaces << " duplicate faces." << endl; + cout << wrongFaces << " wrong faces." << endl; +} + +/** + * testFace + */ +bool BOP_Mesh::testFace(BOP_Face *face){ + + for(unsigned int i=0;isize();i++){ + for(unsigned int j=i+1;jsize();j++){ + if (face->getVertex(i)==face->getVertex(j)) + return true; + } + } + + return false; +} + +/** + * testFaces + */ +bool BOP_Mesh::testFaces(BOP_Face *faceI, BOP_Face *faceJ){ + + if (faceI->size()size()){ + for(unsigned int i=0;isize();i++){ + if (!faceJ->containsVertex(faceI->getVertex(i))) + return false; + } + //faceI->setTAG(BROKEN); + } + else{ + for(unsigned int i=0;isize();i++){ + if (!faceI->containsVertex(faceJ->getVertex(i))) + return false; + } + //faceJ->setTAG(BROKEN); + } + + return true; +} + +/** + * testPlane + */ +void BOP_Mesh::testPlane(BOP_Face *face) +{ + MT_Plane3 plane1(m_vertexs[face->getVertex(0)]->getPoint(), + m_vertexs[face->getVertex(1)]->getPoint(), + m_vertexs[face->getVertex(2)]->getPoint()); + + if (BOP_orientation(plane1,face->getPlane()) < 0) { + cout << "Test Plane " << face << " v1: "; + cout << m_vertexs[face->getVertex(0)]->getPoint() << " v2: "; + cout << m_vertexs[face->getVertex(1)]->getPoint() << " v3: "; + cout << m_vertexs[face->getVertex(2)]->getPoint() << " plane: "; + cout << face->getPlane() << endl; + cout << "Incorrect vertices order!!! plane1: " << plane1 << " ("; + cout << BOP_orientation(plane1,face->getPlane()) << ") " << " invert "; + cout << MT_Plane3(m_vertexs[face->getVertex(2)]->getPoint(), + m_vertexs[face->getVertex(1)]->getPoint(), + m_vertexs[face->getVertex(0)]->getPoint()) << endl; + if (BOP_collinear(m_vertexs[face->getVertex(0)]->getPoint(), + m_vertexs[face->getVertex(1)]->getPoint(), + m_vertexs[face->getVertex(2)]->getPoint())) { + cout << " COLLINEAR!!!" << endl; + } + else { + cout << endl; + } + } +} + +/** + * testEdges + */ +bool BOP_Mesh::testEdges(BOP_Faces *facesObj) +{ + for(unsigned int i=0;igetFaces(); + unsigned int count = 0; + const BOP_IT_Indexs facesEnd = faces.end(); + for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) { + if ((m_faces[*it]->getTAG()!=BROKEN) && containsFace(facesObj,m_faces[*it])) + count++; + } + if ((count%2)!=0) { + return false; + } + } + + return true; +} + +/** + * updatePlanes + */ +void BOP_Mesh::updatePlanes() +{ + const BOP_IT_Faces facesEnd = m_faces.end(); + for(BOP_IT_Faces it = m_faces.begin();it!=facesEnd;it++) { + BOP_Face *face = *it; + MT_Plane3 plane(m_vertexs[face->getVertex(0)]->getPoint(), + m_vertexs[face->getVertex(1)]->getPoint(), + m_vertexs[face->getVertex(2)]->getPoint()); + face->setPlane(plane); + } +} + diff --git a/intern/boolop/intern/BOP_Mesh.h b/intern/boolop/intern/BOP_Mesh.h new file mode 100644 index 00000000000..f671b9a96c9 --- /dev/null +++ b/intern/boolop/intern/BOP_Mesh.h @@ -0,0 +1,124 @@ +/* + * TEMPORARY defines to enable hashing support + */ + +#define HASH(x) ((x) >> 5) /* each "hash" covers 32 indices */ +// #define HASH_PRINTF_DEBUG /* uncomment to enable debug output */ + +/** + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_MESH_H +#define BOP_MESH_H + +#include "BOP_Vertex.h" +#include "BOP_Edge.h" +#include "BOP_Face.h" +#include "DNA_listBase.h" + +typedef vector BOP_Vertexs; +typedef vector BOP_Edges; +typedef vector::iterator BOP_IT_Vertexs; +typedef vector::iterator BOP_IT_Edges; + +#ifdef HASH +typedef struct EdgeEntry { + struct EdgeEntry *next, *pref; + BOP_Index v1, v2, index; +} EdgeEntry; +#endif + +class BOP_Mesh +{ +private: + BOP_Vertexs m_vertexs; + BOP_Edges m_edges; + BOP_Faces m_faces; +#ifdef HASH + ListBase *hash; + int hashsize; +#endif + + BOP_Index addEdge(BOP_Index v1, BOP_Index v2); + BOP_Edge *getEdge(BOP_Indexs edges, BOP_Index v2); + bool containsFace(BOP_Faces *faces, BOP_Face *face); + + bool testEdges(BOP_Faces *faces); + bool testFaces(BOP_Face *faceI, BOP_Face *faceJ); + bool testFace(BOP_Face *face); + +public: + BOP_Mesh(); + ~BOP_Mesh(); + + BOP_Index addVertex(MT_Point3 point); + BOP_Index addFace(BOP_Face *face); + BOP_Index addFace(BOP_Face3 *face); + BOP_Index addFace(BOP_Face4 *face); + BOP_Vertex* getVertex(BOP_Index v); + BOP_Face*getFace(BOP_Index v); + BOP_Edge* getEdge(BOP_Index v); + BOP_Edge* getEdge(BOP_Face * face, unsigned int edge); + BOP_Edge* getEdge(BOP_Face3 * face, unsigned int edge); + BOP_Edge* getEdge(BOP_Face4 * face, unsigned int edge); + BOP_Edge* getEdge(BOP_Index v1, BOP_Index v2); + bool getIndexEdge(BOP_Index v1, BOP_Index v2, BOP_Index &e); + BOP_Vertexs &getVertexs(); + BOP_Edges &getEdges(); + BOP_Faces &getFaces(); + BOP_Face* getFace(BOP_Index v1, BOP_Index v2, BOP_Index v3); + bool getIndexFace(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index &f); + unsigned int getNumVertexs(); + unsigned int getNumEdges(); + unsigned int getNumFaces(); + unsigned int getNumVertexs(BOP_TAG tag); + unsigned int getNumFaces(BOP_TAG tag); + BOP_Index replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex); +#ifdef HASH + void rehashVertex(BOP_Index oldIndex, BOP_Index newIndex, + BOP_Index otherIndex); +#endif + bool isClosedMesh(); + + // Debug functions + void print(); + void printFormat(); + void printFormat(BOP_Faces *faces); + void saveFormat(BOP_Faces *faces, char *filename); + void printFace(BOP_Face *face, int col = 0); + void testPlane(BOP_Face *face); + void testMesh(); + void updatePlanes(); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Segment.cpp b/intern/boolop/intern/BOP_Segment.cpp new file mode 100644 index 00000000000..2a81660c4ff --- /dev/null +++ b/intern/boolop/intern/BOP_Segment.cpp @@ -0,0 +1,247 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Segment.h" + +#define UNDEFINED 0 + +/** + * Constructs a new segment. + */ +BOP_Segment::BOP_Segment(){ + m_cfg1 = UNDEFINED; + m_cfg2 = UNDEFINED; +} + +/** + * Returns the relative edge index between two relative vertex indices. + * @param v1 relative vertex index + * @param v2 relative vertex index + * @return relative edge index between two relative vertex indices, -1 otherwise + */ +int BOP_Segment::getEdgeBetween(unsigned int v1, unsigned int v2) +{ + if ((v1 == 1 && v2 == 2) || (v1 == 2 && v2 == 1)) return 1; + if ((v1 == 3 && v2 == 2) || (v1 == 2 && v2 == 3)) return 2; + if ((v1 == 1 && v2 == 3) || (v1 == 3 && v2 == 1)) return 3; + return -1; +} + +/** + * Returns if a relative vertex index is on a relative edge index. + * @param v relative vertex index + * @param e relative edge index + * @return true if the relative vertex index is on the relative edge index, + * false otherwise. + */ +bool BOP_Segment::isOnEdge(unsigned int v, unsigned int e) +{ + if (v == 1 && (e == 1 || e == 3)) return true; + if (v == 2 && (e == 1 || e == 2)) return true; + if (v == 3 && (e == 2 || e == 3)) return true; + return false; +} + +/** + * Inverts the segment, swapping ends data. + */ +void BOP_Segment::invert() +{ + BOP_Index aux = m_v1; + m_v1 = m_v2; + m_v2 = aux; + aux = m_cfg1; + m_cfg1 = m_cfg2; + m_cfg2 = aux; +} + +/** + * Sorts the segment according to ends configuration. + * The criterion to sort is ... + * + * UNDEFINED < VERTEX < EDGE < IN + * cfg1 > cfg2 + * + * so ... + * + * VERTEX(cfg1) => UNDEFINED(cfg2) || VERTEX(cfg2) + * EDGE(cfg1) => UNDEFINED(cfg2) || VERTEX(cfg2) || EDGE(cfg2) + * IN(cfg1) => UNDEFINED(cfg2) || VERTEX(cfg2) || EDGE(cfg2) || IN(cfg2) + */ +void BOP_Segment::sort() +{ + if (m_cfg1 < m_cfg2) invert(); +} + +/** + * Returns if the specified end segment configuration is IN. + * @return true if the specified end segment configuration is IN, false otherwise + */ +bool BOP_Segment::isIn(unsigned int cfg) +{ + return (cfg == 20); +} + +/** + * Returns if the specified end segment configuration is EDGE. + * @return true if the specified end segment configuration is EDGE, false otherwise + */ +bool BOP_Segment::isEdge(unsigned int cfg) +{ + return (cfg > 10) && (cfg < 20); +} + +/** + * Returns if the specified end segment configuration is VERTEX. + * @return true if the specified end segment configuration is VERTEX, false otherwise + */ +bool BOP_Segment::isVertex(unsigned int cfg) +{ + return (cfg!=UNDEFINED) && (cfg < 10); +} + +/** + * Returns if the specified end segment configuration is DEFINED (not UNDEFINED). + * @return true if the specified end segment configuration is DEFINED, false otherwise + */ +bool BOP_Segment::isDefined(unsigned int cfg) +{ + return (cfg != UNDEFINED); +} + +/** + * Returns if the specified end segment configuration is UNDEFINED. + * @return true if the specified end segment configuration is UNDEFINED, false otherwise + */ +bool BOP_Segment::isUndefined(unsigned int cfg) +{ + return (cfg == UNDEFINED); +} + +/** + * Returns the relative edge index from the specified end segment configuration. + * @return relative edge index from the specified end segment configuration + */ +unsigned int BOP_Segment::getEdge(unsigned int cfg) +{ + return cfg-10; +} + +/** + * Returns the relative vertex index from the specified end segment configuration. + * @return relative vertex index from the specified end segment configuration + */ +BOP_Index BOP_Segment::getVertex(unsigned int cfg) +{ + return cfg; +} + +/** + * Returns the end segment configuration for the specified relative edge index. + * @return end segment configuration for the specified relative edge index + */ +unsigned int BOP_Segment::createEdgeCfg(unsigned int edge) +{ + return 10+edge; +} + +/** + * Returns the end segment configuration for the specified relative vertex index. + * @return end segment configuration for the specified relative vertex index + */ +unsigned int BOP_Segment::createVertexCfg(BOP_Index vertex) +{ + return vertex; +} + +/** + * Returns the end segment IN configuration. + * @return end segment IN configuration + */ +unsigned int BOP_Segment::createInCfg() +{ + return 20; +} + +/** + * Returns the end segment UNDEFINED configuration. + * @return end segment UNDEFINED configuration + */ +unsigned int BOP_Segment::createUndefinedCfg() +{ + return UNDEFINED; +} + +/** + * Returns the inner segment configuration. + * @return inner segment configuration + */ +unsigned int BOP_Segment::getConfig() +{ + if (isUndefined(m_cfg1)) return m_cfg2; + else if (isUndefined(m_cfg2)) return m_cfg1; + else if (isVertex(m_cfg1)) { + // v1 is vertex + if (isVertex(m_cfg2)) { + // v2 is vertex + return createEdgeCfg(getEdgeBetween(getVertex(m_cfg1),getVertex(m_cfg2))); + } + else if (isEdge(m_cfg2)) { + // v2 is edge + if (isOnEdge(m_cfg1,getEdge(m_cfg2))) return m_cfg2; + else return createInCfg(); //IN + } + else return createInCfg(); //IN + } + else if (isEdge(m_cfg1)) { + // v1 is edge + if (isVertex(m_cfg2)) { + // v2 is vertex + if (isOnEdge(m_cfg2,getEdge(m_cfg1))) return m_cfg1; + else return createInCfg(); //IN + } + else if (isEdge(m_cfg2)) { + // v2 is edge + if (m_cfg1 == m_cfg2) return m_cfg1; + else return createInCfg(); // IN + } + else return createInCfg(); // IN + } + else return createInCfg(); // IN +} + +/** + * Implements operator << + */ +ostream &operator<<(ostream &stream, const BOP_Segment &c) +{ + cout << "m_v1: " << c.m_v1 << "(" << c.m_cfg1 << ") m_v2: " << c.m_v2 << "(" << c.m_cfg2 << ")"; + return stream; +} diff --git a/intern/boolop/intern/BOP_Segment.h b/intern/boolop/intern/BOP_Segment.h new file mode 100644 index 00000000000..caa6157346c --- /dev/null +++ b/intern/boolop/intern/BOP_Segment.h @@ -0,0 +1,73 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_SEGMENT_H +#define BOP_SEGMENT_H + +#include "BOP_Indexs.h" +#include +using namespace std; + +class BOP_Segment +{ +private: + int getEdgeBetween(unsigned int v1, unsigned int v2); + bool isOnEdge(unsigned int v, unsigned int e); + +public: + // Cfg : Configuration of the vertices + // Values: + // 20 IN, + // 1X Intersected edge X{1,2,3} of the face, + // 0X Coincident vertice X{1,2,3} of the face, + // 0 otherwise + unsigned int m_cfg1, m_cfg2; + BOP_Index m_v1, m_v2; // if cfgX >0, vX is the vertice index of the face + BOP_Segment(); + + static bool isIn(unsigned int cfg); + static bool isEdge(unsigned int cfg); + static bool isVertex(unsigned int cfg); + static bool isDefined(unsigned int cfg); + static bool isUndefined(unsigned int cfg); + static unsigned int getEdge(unsigned int cfg); + static BOP_Index getVertex(unsigned int cfg); + static unsigned int createEdgeCfg(unsigned int edge); + static unsigned int createVertexCfg(BOP_Index vertex); + static unsigned int createInCfg(); + static unsigned int createUndefinedCfg(); + void invert(); + void sort(); + unsigned int getConfig(); + + friend ostream &operator<<(ostream &stream, const BOP_Segment &c); +}; + +#endif diff --git a/intern/boolop/intern/BOP_Splitter.cpp b/intern/boolop/intern/BOP_Splitter.cpp new file mode 100644 index 00000000000..07f1f4d6c96 --- /dev/null +++ b/intern/boolop/intern/BOP_Splitter.cpp @@ -0,0 +1,193 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Splitter.h" +#include "BOP_Tag.h" + +#include +using namespace std; + +/** + * Returns the split point resulting from intersect a plane and a mesh face + * according to its specified relative edge. + * @param plane split plane + * @param m mesh + * @param f face + * @param e relative edge index + * @return intersection point + */ +MT_Point3 BOP_splitEdge(MT_Plane3 plane, BOP_Mesh *m, BOP_Face *f, unsigned int e) +{ + int v1 = -1, v2 = -1; + + switch(e) { + case 1: + v1 = f->getVertex(0); + v2 = f->getVertex(1); + break; + case 2: + v1 = f->getVertex(1); + v2 = f->getVertex(2); + break; + case 3: + v1 = f->getVertex(2); + v2 = f->getVertex(0); + break; + default: + // wrong relative edge index! + break; + } + + MT_Point3 p1 = m->getVertex(v1)->getPoint(); + MT_Point3 p2 = m->getVertex(v2)->getPoint(); + return BOP_intersectPlane(plane,p1,p2); +} + +/** + * Returns the segment resulting from intersect a plane and a mesh face. + * @param plane split plane + * @param m mesh + * @param f face + * @return segment if there is intersection, NULL otherwise + */ +BOP_Segment BOP_splitFace(MT_Plane3 plane, BOP_Mesh *m, BOP_Face *f) +{ + BOP_Vertex *v1 = m->getVertex(f->getVertex(0)); + BOP_Vertex *v2 = m->getVertex(f->getVertex(1)); + BOP_Vertex *v3 = m->getVertex(f->getVertex(2)); + + // Classify face vertices + BOP_TAG tag1 = BOP_createTAG(BOP_classify(v1->getPoint(),plane)); + BOP_TAG tag2 = BOP_createTAG(BOP_classify(v2->getPoint(),plane)); + BOP_TAG tag3 = BOP_createTAG(BOP_classify(v3->getPoint(),plane)); + + // Classify face according to its vertices classification + BOP_TAG tag = BOP_createTAG(tag1,tag2,tag3); + + BOP_Segment s; + + switch(tag) { + case IN_IN_IN : + case OUT_OUT_OUT : + case ON_ON_ON : + s.m_cfg1 = s.m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case ON_OUT_OUT : + case ON_IN_IN : + s.m_v1 = f->getVertex(0); + s.m_cfg1 = BOP_Segment::createVertexCfg(1); + s.m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case OUT_ON_OUT : + case IN_ON_IN : + s.m_v1 = f->getVertex(1); + s.m_cfg1 = BOP_Segment::createVertexCfg(2); + s.m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case OUT_OUT_ON : + case IN_IN_ON : + s.m_v1 = f->getVertex(2); + s.m_cfg1 = BOP_Segment::createVertexCfg(3); + s.m_cfg2 = BOP_Segment::createUndefinedCfg(); + break; + + case ON_ON_IN : + case ON_ON_OUT : + s.m_v1 = f->getVertex(0); + s.m_v2 = f->getVertex(1); + s.m_cfg1 = BOP_Segment::createVertexCfg(1); + s.m_cfg2 = BOP_Segment::createVertexCfg(2); + break; + + case ON_OUT_ON : + case ON_IN_ON : + s.m_v1 = f->getVertex(0); + s.m_v2 = f->getVertex(2); + s.m_cfg1 = BOP_Segment::createVertexCfg(1); + s.m_cfg2 = BOP_Segment::createVertexCfg(3); + break; + + case OUT_ON_ON : + case IN_ON_ON : + s.m_v1 = f->getVertex(1); + s.m_v2 = f->getVertex(2); + s.m_cfg1 = BOP_Segment::createVertexCfg(2); + s.m_cfg2 = BOP_Segment::createVertexCfg(3); + break; + + case IN_OUT_ON : + case OUT_IN_ON : + s.m_v2 = f->getVertex(2); + s.m_cfg1 = BOP_Segment::createEdgeCfg(1); + s.m_cfg2 = BOP_Segment::createVertexCfg(3); + break; + + case IN_ON_OUT : + case OUT_ON_IN : + s.m_v1 = f->getVertex(1); + s.m_cfg1 = BOP_Segment::createVertexCfg(2); + s.m_cfg2 = BOP_Segment::createEdgeCfg(3); + break; + + case ON_IN_OUT : + case ON_OUT_IN : + s.m_v1 = f->getVertex(0); + s.m_cfg1 = BOP_Segment::createVertexCfg(1); + s.m_cfg2 = BOP_Segment::createEdgeCfg(2); + break; + + case OUT_IN_IN : + case IN_OUT_OUT : + s.m_cfg1 = BOP_Segment::createEdgeCfg(1); + s.m_cfg2 = BOP_Segment::createEdgeCfg(3); + break; + + case OUT_IN_OUT : + case IN_OUT_IN : + s.m_cfg1 = BOP_Segment::createEdgeCfg(1); + s.m_cfg2 = BOP_Segment::createEdgeCfg(2); + break; + + case OUT_OUT_IN : + case IN_IN_OUT : + s.m_cfg1 = BOP_Segment::createEdgeCfg(2); + s.m_cfg2 = BOP_Segment::createEdgeCfg(3); + break; + + default: + // wrong TAG! + break; + } + + return s; +} diff --git a/intern/boolop/intern/BOP_Splitter.h b/intern/boolop/intern/BOP_Splitter.h new file mode 100644 index 00000000000..02cbdd2aa72 --- /dev/null +++ b/intern/boolop/intern/BOP_Splitter.h @@ -0,0 +1,44 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_SPLITTER_H +#define BOP_SPLITTER_H + +#include "BOP_MathUtils.h" +#include "BOP_Segment.h" +#include "BOP_Mesh.h" + +#include "MT_Plane3.h" +#include "MT_Point3.h" + +MT_Point3 BOP_splitEdge(MT_Plane3 plane, BOP_Mesh *mesh, BOP_Face *face, unsigned int edge); +BOP_Segment BOP_splitFace(MT_Plane3 plane, BOP_Mesh *mesh, BOP_Face *face); + +#endif diff --git a/intern/boolop/intern/BOP_Tag.cpp b/intern/boolop/intern/BOP_Tag.cpp new file mode 100644 index 00000000000..6a8832870fa --- /dev/null +++ b/intern/boolop/intern/BOP_Tag.cpp @@ -0,0 +1,142 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Tag.h" + +/** + * Gets the tag description. + * @param t tag + * @param dest tag description + */ +void BOP_stringTAG(BOP_TAG t, char *dest) { + + switch(t){ + case IN_IN_IN: + sprintf(dest, "IN_IN_IN"); + break; + case IN_IN_ON: + sprintf(dest, "IN_IN_ON"); + break; + case IN_ON_IN: + sprintf(dest, "IN_ON_IN"); + break; + case IN_ON_ON: + sprintf(dest, "IN_ON_ON"); + break; + case ON_IN_IN: + sprintf(dest, "ON_IN_IN"); + break; + case ON_IN_ON: + sprintf(dest, "ON_IN_ON"); + break; + case ON_ON_IN: + sprintf(dest, "ON_ON_IN"); + break; + case ON_ON_ON: + sprintf(dest, "ON_ON_ON"); + break; + case OUT_OUT_OUT: + sprintf(dest, "OUT_OUT_OUT"); + break; + case OUT_OUT_ON: + sprintf(dest, "OUT_OUT_ON"); + break; + case OUT_ON_OUT: + sprintf(dest, "OUT_ON_OUT"); + break; + case OUT_ON_ON: + sprintf(dest, "OUT_ON_ON"); + break; + case ON_OUT_OUT: + sprintf(dest, "ON_OUT_OUT"); + break; + case ON_OUT_ON: + sprintf(dest, "ON_OUT_ON"); + break; + case ON_ON_OUT: + sprintf(dest, "ON_ON_OUT"); + break; + case OUT_OUT_IN: + sprintf(dest, "OUT_OUT_IN"); + break; + case OUT_IN_OUT: + sprintf(dest, "OUT_IN_OUT"); + break; + case OUT_IN_IN: + sprintf(dest, "OUT_IN_IN"); + break; + case IN_OUT_OUT: + sprintf(dest, "IN_OUT_OUT"); + break; + case IN_OUT_IN: + sprintf(dest, "IN_OUT_IN"); + break; + case IN_IN_OUT: + sprintf(dest, "IN_IN_OUT"); + break; + case OUT_ON_IN: + sprintf(dest, "OUT_ON_IN"); + break; + case OUT_IN_ON: + sprintf(dest, "OUT_IN_ON"); + break; + case IN_ON_OUT: + sprintf(dest, "IN_ON_OUT"); + break; + case IN_OUT_ON: + sprintf(dest, "IN_OUT_ON"); + break; + case ON_IN_OUT: + sprintf(dest, "ON_IN_OUT"); + break; + case ON_OUT_IN: + sprintf(dest, "ON_OUT_IN"); + break; + case UNCLASSIFIED: + sprintf(dest, "UNCLASSIFIED"); + break; + case BROKEN: + sprintf(dest, "BROKEN"); + break; + case PHANTOM: + sprintf(dest, "PHANTOM"); + break; + case OVERLAPPED: + sprintf(dest, "OVERLAPPED"); + break; + case INOUT: + sprintf(dest, "INOUT"); + break; + default: + sprintf(dest, "DESCONEGUT %d",t); + break; + } + +} diff --git a/intern/boolop/intern/BOP_Tag.h b/intern/boolop/intern/BOP_Tag.h new file mode 100644 index 00000000000..2b6ff93b679 --- /dev/null +++ b/intern/boolop/intern/BOP_Tag.h @@ -0,0 +1,145 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +#ifndef BOP_TAG_H +#define BOP_TAG_H + +#define IN_TAG 0x02 // Below the plane +#define ON_TAG 0x00 // On the plane +#define OUT_TAG 0x01 // Above the plane +#define INOUT_TAG 0x0E // Above and below the plane +#define INON_TAG 0x12 // Below and on the plane +#define OUTON_TAG 0x11 // Above and on the plane +#define UNCLASSIFIED_TAG 0x0F // Expecting to be classified + +#define PHANTOM_TAG 0x0C // Phantom face +#define OVERLAPPED_TAG 0x0D // Overlapped face +#define BROKEN_TAG 0x0B // Splitted and unused ... + +#define ON_ON_IN_TAG IN_TAG +#define ON_IN_ON_TAG IN_TAG << 2 +#define IN_ON_ON_TAG IN_TAG << 4 + +#define ON_ON_OUT_TAG OUT_TAG +#define ON_OUT_ON_TAG OUT_TAG << 2 +#define OUT_ON_ON_TAG OUT_TAG << 4 + +#define ON_ON_ON_TAG ON_TAG +#define IN_IN_IN_TAG IN_ON_ON_TAG | ON_IN_ON_TAG | ON_ON_IN_TAG +#define OUT_OUT_OUT_TAG OUT_ON_ON_TAG | ON_OUT_ON_TAG | ON_ON_OUT_TAG + +#define IN_IN_ON_TAG IN_ON_ON_TAG | ON_IN_ON_TAG +#define IN_ON_IN_TAG IN_ON_ON_TAG | ON_ON_IN_TAG +#define ON_IN_IN_TAG ON_IN_ON_TAG | ON_ON_IN_TAG + +#define OUT_OUT_ON_TAG OUT_ON_ON_TAG | ON_OUT_ON_TAG +#define OUT_ON_OUT_TAG OUT_ON_ON_TAG | ON_ON_OUT_TAG +#define ON_OUT_OUT_TAG ON_OUT_ON_TAG | ON_ON_OUT_TAG + +#define IN_OUT_OUT_TAG IN_ON_ON_TAG | ON_OUT_OUT_TAG +#define OUT_IN_OUT_TAG ON_IN_ON_TAG | OUT_ON_OUT_TAG +#define OUT_OUT_IN_TAG ON_ON_IN_TAG | OUT_OUT_ON_TAG + +#define OUT_IN_IN_TAG ON_IN_IN_TAG | OUT_ON_ON_TAG +#define IN_OUT_IN_TAG IN_ON_IN_TAG | ON_OUT_ON_TAG +#define IN_IN_OUT_TAG IN_IN_ON_TAG | ON_ON_OUT_TAG + +#define IN_ON_OUT_TAG IN_ON_ON_TAG | ON_ON_OUT_TAG +#define IN_OUT_ON_TAG IN_ON_ON_TAG | ON_OUT_ON_TAG +#define ON_IN_OUT_TAG ON_IN_ON_TAG | ON_ON_OUT_TAG +#define ON_OUT_IN_TAG ON_ON_IN_TAG | ON_OUT_ON_TAG +#define OUT_IN_ON_TAG ON_IN_ON_TAG | OUT_ON_ON_TAG +#define OUT_ON_IN_TAG ON_ON_IN_TAG | OUT_ON_ON_TAG + +typedef enum BOP_TAGEnum { + IN = IN_TAG, + ON = ON_TAG, + OUT = OUT_TAG, + INOUT = INOUT_TAG, + INON = INON_TAG, + OUTON = OUTON_TAG, + UNCLASSIFIED = UNCLASSIFIED_TAG, + PHANTOM = PHANTOM_TAG, + OVERLAPPED = OVERLAPPED_TAG, + BROKEN = BROKEN_TAG, + IN_ON_ON = IN_ON_ON_TAG, + ON_IN_ON = ON_IN_ON_TAG, + ON_ON_IN = ON_ON_IN_TAG, + OUT_ON_ON = OUT_ON_ON_TAG, + ON_OUT_ON = ON_OUT_ON_TAG, + ON_ON_OUT = ON_ON_OUT_TAG, + ON_ON_ON = ON_ON_ON_TAG, + IN_IN_IN = IN_IN_IN_TAG, + OUT_OUT_OUT = OUT_OUT_OUT_TAG, + IN_IN_ON = IN_IN_ON_TAG, + IN_ON_IN = IN_ON_IN_TAG, + ON_IN_IN = ON_IN_IN_TAG, + OUT_OUT_ON = OUT_OUT_ON_TAG, + OUT_ON_OUT = OUT_ON_OUT_TAG, + ON_OUT_OUT = ON_OUT_OUT_TAG, + IN_OUT_OUT = IN_OUT_OUT_TAG, + OUT_IN_OUT = OUT_IN_OUT_TAG, + OUT_OUT_IN = OUT_OUT_IN_TAG, + OUT_IN_IN = OUT_IN_IN_TAG, + IN_OUT_IN = IN_OUT_IN_TAG, + IN_IN_OUT = IN_IN_OUT_TAG, + IN_ON_OUT = IN_ON_OUT_TAG, + IN_OUT_ON = IN_OUT_ON_TAG, + ON_IN_OUT = ON_IN_OUT_TAG, + ON_OUT_IN = ON_OUT_IN_TAG, + OUT_IN_ON = OUT_IN_ON_TAG, + OUT_ON_IN = OUT_ON_IN_TAG } BOP_TAG; + +inline BOP_TAG BOP_createTAG(BOP_TAG tag1, BOP_TAG tag2, BOP_TAG tag3) +{ + return (BOP_TAG) (tag1 << 4 | tag2 << 2 | tag3); +} + +inline BOP_TAG BOP_createTAG(int i) +{ + return i < 0 ? IN : i > 0 ? OUT : ON; +} + +inline BOP_TAG BOP_addON(BOP_TAG tag) +{ + return (tag==IN?INON:(tag==OUT?OUTON:tag)); +} + +void BOP_stringTAG(BOP_TAG tag, char *dest); + +inline bool BOP_compTAG(BOP_TAG tag1, BOP_TAG tag2) +{ + return (tag1==tag2) || (BOP_addON(tag1) == BOP_addON(tag2)); +} + +#endif diff --git a/intern/boolop/intern/BOP_Triangulator.cpp b/intern/boolop/intern/BOP_Triangulator.cpp new file mode 100644 index 00000000000..fd7b3154195 --- /dev/null +++ b/intern/boolop/intern/BOP_Triangulator.cpp @@ -0,0 +1,572 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Triangulator.h" +#include +using namespace std; + +void BOP_addFace(BOP_Mesh* mesh, BOP_Faces *faces, BOP_Face* face, BOP_TAG tag); +void BOP_splitQuad(BOP_Mesh* mesh, MT_Plane3 plane, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, + BOP_Face* triangles[], BOP_Index original); +BOP_Index BOP_getTriangleVertex(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4); +BOP_Index BOP_getNearestVertex(BOP_Mesh* mesh, BOP_Index u, BOP_Index v1, BOP_Index v2); +bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5); +bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index w); +void BOP_triangulateC_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5); +void BOP_triangulateD_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5); + +/** + * Triangulates the face in two new faces by splitting one edge. + * + * * + * /|\ + * / | \ + * / | \ + * / | \ + * / | \ + * *-----x-----* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v vertex index that intersects the edge + * @param e relative edge index used to triangulate the face + */ + + +void BOP_triangulateA(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v, unsigned int e) +{ + BOP_Face *face1, *face2; + if (e == 1) { + face1 = new BOP_Face3(face->getVertex(0), v, face->getVertex(2), face->getPlane(), + face->getOriginalFace()); + face2 = new BOP_Face3(v, face->getVertex(1), face->getVertex(2), face->getPlane(), + face->getOriginalFace()); + } + else if (e == 2) { + face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(), + face->getOriginalFace()); + face2 = new BOP_Face3(face->getVertex(0), v, face->getVertex(2), face->getPlane(), + face->getOriginalFace()); + } + else if (e == 3) { + face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(), + face->getOriginalFace()); + face2 = new BOP_Face3(face->getVertex(1), face->getVertex(2), v, face->getPlane(), + face->getOriginalFace()); + } + else { + return; + } + + BOP_addFace(mesh, faces, face1, face->getTAG()); + BOP_addFace(mesh, faces, face2, face->getTAG()); + face1->setSplit(face->getSplit()); + face2->setSplit(face->getSplit()); + + face->setTAG(BROKEN); + face->freeBBox(); +} + +/** + * Triangulates the face in three new faces by one inner point. + * + * * + * / \ + * / \ + * / \ + * / x \ + * / \ + * *-----------* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v vertex index that lays inside face + */ +void BOP_triangulateB(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v) +{ + BOP_Face *face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(), + face->getOriginalFace()); + BOP_Face *face2 = new BOP_Face3(face->getVertex(1), face->getVertex(2), v, face->getPlane(), + face->getOriginalFace()); + BOP_Face *face3 = new BOP_Face3(face->getVertex(2), face->getVertex(0), v, face->getPlane(), + face->getOriginalFace()); + + BOP_addFace(mesh,faces,face1,face->getTAG()); + BOP_addFace(mesh,faces,face2,face->getTAG()); + BOP_addFace(mesh,faces,face3,face->getTAG()); + face1->setSplit(face->getSplit()); + face2->setSplit(face->getSplit()); + face3->setSplit(face->getSplit()); + face->setTAG(BROKEN); + face->freeBBox(); +} + + +/** + * Triangulates the face in five new faces by two inner points. + * + * * + * / \ + * / \ + * / \ + * / x x \ + * / \ + * *-----------* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 first vertex index that lays inside face + * @param v2 second vertex index that lays inside face + */ +void BOP_triangulateC(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v1, BOP_Index v2) +{ + if (!BOP_isInsideCircle(mesh, face->getVertex(0), v1, v2, face->getVertex(1), face->getVertex(2))) { + BOP_triangulateC_split(mesh, faces, face, face->getVertex(0), face->getVertex(1), + face->getVertex(2), v1, v2); + } + else if (!BOP_isInsideCircle(mesh, face->getVertex(1), v1, v2, face->getVertex(0), face->getVertex(2))) { + BOP_triangulateC_split(mesh, faces, face, face->getVertex(1), face->getVertex(2), + face->getVertex(0), v1, v2); + } + else if (!BOP_isInsideCircle(mesh, face->getVertex(2), v1, v2, face->getVertex(0), face->getVertex(1))) { + BOP_triangulateC_split(mesh, faces, face, face->getVertex(2), face->getVertex(0), + face->getVertex(1), v1, v2); + } + else { + BOP_triangulateC_split(mesh, faces, face, face->getVertex(2), face->getVertex(0), + face->getVertex(1), v1, v2); + } +} + +/** + * Triangulates the face (v1,v2,v3) in five new faces by two inner points (v4,v5), where + * v1 v4 v5 defines the nice triangle and v4 v5 v2 v3 defines the quad to be tesselated. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 first vertex index that defines the original triangle + * @param v2 second vertex index that defines the original triangle + * @param v3 third vertex index that defines the original triangle + * @param v4 first vertex index that lays inside face + * @param v5 second vertex index that lays inside face + */ +void BOP_triangulateC_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5) +{ + BOP_Index v = BOP_getTriangleVertex(mesh, v1, v2, v4, v5); + BOP_Index w = (v == v4 ? v5 : v4); + BOP_Face *face1 = new BOP_Face3(v1, v, w, face->getPlane(), face->getOriginalFace()); + BOP_Face *face2 = new BOP_Face3(v1, v2, v, face->getPlane(), face->getOriginalFace()); + BOP_Face *face3 = new BOP_Face3(v1, w, v3, face->getPlane(), face->getOriginalFace()); + + // v1 v w defines the nice triangle in the correct order + // v1 v2 v defines one lateral triangle in the correct order + // v1 w v3 defines the other lateral triangle in the correct order + // w v v2 v3 defines the quad in the correct order + + BOP_addFace(mesh, faces, face1, face->getTAG()); + BOP_addFace(mesh, faces, face2, face->getTAG()); + BOP_addFace(mesh, faces, face3, face->getTAG()); + + face1->setSplit(face->getSplit()); + face2->setSplit(face->getSplit()); + face3->setSplit(face->getSplit()); + + BOP_Face *faces45[2]; + + BOP_splitQuad(mesh, face->getPlane(), v2, v3, w, v, faces45, face->getOriginalFace()); + BOP_addFace(mesh, faces, faces45[0], face->getTAG()); + BOP_addFace(mesh, faces, faces45[1], face->getTAG()); + faces45[0]->setSplit(face->getSplit()); + faces45[1]->setSplit(face->getSplit()); + + face->setTAG(BROKEN); + face->freeBBox(); +} + + +/** + * Triangulates the face in three new faces by splitting twice an edge. + * + * * + * / \ + * / \ + * / \ + * / \ + * / \ + * *---x---x---* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 first vertex index that intersects the edge + * @param v2 second vertex index that intersects the edge + * @param e relative edge index used to triangulate the face + */ +void BOP_triangulateD(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v1, + BOP_Index v2, unsigned int e) +{ + if (e == 1) { + BOP_triangulateD_split(mesh, faces, face, face->getVertex(0), face->getVertex(1), + face->getVertex(2), v1, v2); + } + else if (e == 2) { + BOP_triangulateD_split(mesh, faces, face, face->getVertex(1), face->getVertex(2), + face->getVertex(0), v1, v2); + } + else if (e == 3) { + BOP_triangulateD_split(mesh, faces, face, face->getVertex(2), face->getVertex(0), + face->getVertex(1), v1, v2); + } +} + +/** + * Triangulates the face (v1,v2,v3) in three new faces by splitting twice an edge. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 first vertex index that defines the original triangle + * @param v2 second vertex index that defines the original triangle + * @param v3 third vertex index that defines the original triangle + * @param v4 first vertex index that lays on the edge + * @param v5 second vertex index that lays on the edge + */ +void BOP_triangulateD_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5) +{ + BOP_Index v = BOP_getNearestVertex(mesh, v1, v4, v5); + BOP_Index w = (v == v4 ? v5 : v4); + BOP_Face *face1 = new BOP_Face3(v1, v, v3, face->getPlane(), face->getOriginalFace()); + BOP_Face *face2 = new BOP_Face3(v, w, v3, face->getPlane(), face->getOriginalFace()); + BOP_Face *face3 = new BOP_Face3(w, v2, v3, face->getPlane(), face->getOriginalFace()); + + BOP_addFace(mesh, faces, face1, face->getTAG()); + BOP_addFace(mesh, faces, face2, face->getTAG()); + BOP_addFace(mesh, faces, face3, face->getTAG()); + face1->setSplit(face->getSplit()); + face2->setSplit(face->getSplit()); + face3->setSplit(face->getSplit()); + + face->setTAG(BROKEN); + face->freeBBox(); +} + + +/** + * Triangulates the face in three new faces by splitting two edges. + * + * * + * / \ + * / \ + * x x + * / \ + * / \ + * *-----------* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 vertex index that intersects the first edge + * @param v1 vertex index that intersects the second edge + * @param e1 first relative edge index used to triangulate the face + * @param e2 second relative edge index used to triangulate the face + */ +void BOP_triangulateE(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, unsigned int e1, unsigned int e2) +{ + // Sort the edges to reduce the cases + if (e1 > e2) { + unsigned int aux = e1; + e1 = e2; + e2 = aux; + aux = v1; + v1 = v2; + v2 = aux; + } + // e1 < e2! + BOP_Face *face1; + BOP_Face *faces23[2]; + if (e1 == 1 && e2 == 2) { + // the vertex is 2 + face1 = new BOP_Face3(face->getVertex(1), v2, v1, face->getPlane(), + face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v1, v2, + faces23, face->getOriginalFace()); + } + else if (e1 == 1 && e2 == 3) { + // the vertex is 1 + face1 = new BOP_Face3(face->getVertex(0), v1, v2, face->getPlane(), + face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v2, v1, + faces23, face->getOriginalFace()); + } + else if (e1 == 2 && e2 == 3) { + // the vertex is 3 + face1 = new BOP_Face3(face->getVertex(2), v2, v1, face->getPlane(), + face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v1, v2, + faces23, face->getOriginalFace()); + } + else { + return; + } + + BOP_addFace(mesh, faces, face1, face->getTAG()); + BOP_addFace(mesh, faces, faces23[0], face->getTAG()); + BOP_addFace(mesh, faces, faces23[1], face->getTAG()); + face1->setSplit(face->getSplit()); + faces23[0]->setSplit(face->getSplit()); + faces23[1]->setSplit(face->getSplit()); + face->setTAG(BROKEN); + face->freeBBox(); +} + +/** + * Triangulates the face in four new faces by one edge and one inner point. + * + * * + * / \ + * / \ + * x x \ + * / \ + * / \ + * *-----------* + * + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains face and will contains new faces + * @param face input face to be triangulate + * @param v1 vertex index that lays inside face + * @param v2 vertex index that intersects the edge + * @param e relative edge index used to triangulate the face + */ +void BOP_triangulateF(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, + BOP_Index v1, BOP_Index v2, unsigned int e) +{ + BOP_Face *faces12[2]; + BOP_Face *faces34[2]; + if (e == 1) { + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v2, v1, + faces12, face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v1, v2, + faces34, face->getOriginalFace()); + } + else if (e == 2) { + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v2, v1, + faces12, face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v1, v2, + faces34, face->getOriginalFace()); + } + else if (e==3) { + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v2, v1, + faces12, face->getOriginalFace()); + BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v1, v2, + faces34, face->getOriginalFace()); + } + else { + return; + } + + BOP_addFace(mesh, faces, faces12[0], face->getTAG()); + BOP_addFace(mesh, faces, faces12[1], face->getTAG()); + BOP_addFace(mesh, faces, faces34[0], face->getTAG()); + BOP_addFace(mesh, faces, faces34[1], face->getTAG()); + faces12[0]->setSplit(face->getSplit()); + faces12[1]->setSplit(face->getSplit()); + faces34[0]->setSplit(face->getSplit()); + faces34[1]->setSplit(face->getSplit()); + + face->setTAG(BROKEN); + face->freeBBox(); +} + +/** + * Adds the new face into the faces set and the mesh and sets it a new tag. + * @param mesh mesh that contains the faces, edges and vertices + * @param faces set of faces that contains oldFace + * @param face input face to be added + * @param tag tag of the new face + */ +void BOP_addFace(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_TAG tag) +{ + BOP_Index av1 = face->getVertex(0); + BOP_Index av2 = face->getVertex(1); + BOP_Index av3 = face->getVertex(2); + + /* + * Before adding a new face to the face list, be sure it's not + * already there. Duplicate faces have been found to cause at + * least two instances of infinite loops. Also, some faces are + * created which have the same vertex twice. Don't add these either. + * + * When someone has more time to look into this issue, it's possible + * this code may be removed again. + */ + if( av1==av2 || av2==av3 || av3==av1 ) return; + + for(unsigned int idxFace=0;idxFacesize();idxFace++) { + BOP_Face *faceA = (*faces)[idxFace]; + BOP_Index bv1 = faceA->getVertex(0); + BOP_Index bv2 = faceA->getVertex(1); + BOP_Index bv3 = faceA->getVertex(2); + + if( ( av1==bv1 && av2==bv2 && av3==bv3 ) || + ( av1==bv1 && av2==bv3 && av3==bv2 ) || + ( av1==bv2 && av2==bv1 && av3==bv3 ) || + ( av1==bv2 && av2==bv3 && av3==bv1 ) || + ( av1==bv3 && av2==bv2 && av3==bv1 ) || + ( av1==bv3 && av2==bv1 && av3==bv3 ) ) + return; + } + + face->setTAG(tag); + faces->push_back(face); + mesh->addFace(face); +} + +/** + * Computes the best quad triangulation. + * @param mesh mesh that contains the faces, edges and vertices + * @param plane plane used to create the news faces + * @param v1 first vertex index + * @param v2 second vertex index + * @param v3 third vertex index + * @param v4 fourth vertex index + * @param triangles array of faces where the new two faces will be saved + * @param original face index to the new faces + */ +void BOP_splitQuad(BOP_Mesh* mesh, MT_Plane3 plane, BOP_Index v1, BOP_Index v2, + BOP_Index v3, BOP_Index v4, BOP_Face* triangles[], BOP_Index original) +{ + MT_Point3 p1 = mesh->getVertex(v1)->getPoint(); + MT_Point3 p2 = mesh->getVertex(v2)->getPoint(); + MT_Point3 p3 = mesh->getVertex(v3)->getPoint(); + MT_Point3 p4 = mesh->getVertex(v4)->getPoint(); + + int res = BOP_concave(p1,p2,p3,p4); + + if (res==0) { + MT_Plane3 plane1(p1, p2, p3); + MT_Plane3 plane2(p1, p3, p4); + + if (BOP_isInsideCircle(mesh, v1, v2, v4, v3) && + BOP_orientation(plane1, plane) && + BOP_orientation(plane2, plane)) { + triangles[0] = new BOP_Face3(v1, v2, v3, plane, original); + triangles[1] = new BOP_Face3(v1, v3, v4, plane, original); + } + else { + triangles[0] = new BOP_Face3(v1, v2, v4, plane, original); + triangles[1] = new BOP_Face3(v2, v3, v4, plane, original); + } + } + else if (res==-1) { + triangles[0] = new BOP_Face3(v1, v2, v4, plane, original); + triangles[1] = new BOP_Face3(v2, v3, v4, plane, original); + } + else { + triangles[0] = new BOP_Face3(v1, v2, v3, plane, original); + triangles[1] = new BOP_Face3(v1, v3, v4, plane, original); + } +} + +/** + * Returns the vertex (v3 or v4) that splits the quad (v1,v2,v3,v4) in the best pair of triangles. + * @param mesh mesh that contains the faces, edges and vertices + * @param v1 first vertex index + * @param v2 second vertex index + * @param v3 third vertex index + * @param v4 fourth vertex index + * @return v3 if the best split triangles are (v1,v2,v3) and (v1,v3,v4), v4 otherwise + */ +BOP_Index BOP_getTriangleVertex(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4) +{ + if (BOP_isInsideCircle(mesh, v1, v2, v4, v3)) { + return v3; + } + return v4; +} + +/** + * Returns which of vertex v1 or v2 is nearest to u. + * @param mesh mesh that contains the faces, edges and vertices + * @param u reference vertex index + * @param v1 first vertex index + * @param v2 second vertex index + * @return the nearest vertex index + */ +BOP_Index BOP_getNearestVertex(BOP_Mesh* mesh, BOP_Index u, BOP_Index v1, BOP_Index v2) +{ + MT_Point3 q = mesh->getVertex(u)->getPoint(); + MT_Point3 p1 = mesh->getVertex(v1)->getPoint(); + MT_Point3 p2 = mesh->getVertex(v2)->getPoint(); + if (BOP_comp(q.distance(p1), q.distance(p2)) > 0) return v2; + else return v1; +} + +/** + * Computes if vertexs v4 and v5 are not inside the circle defined by v1,v2,v3 (seems to be a nice triangle) + * @param mesh mesh that contains the faces, edges and vertices + * @param v1 first vertex index + * @param v2 second vertex index + * @param v3 third vertex index + * @param v4 fourth vertex index + * @param v5 five vertex index + * @return if v1,v2,v3 defines a nice triangle against v4,v5 + */ +bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5) +{ + return BOP_isInsideCircle(mesh->getVertex(v1)->getPoint(), + mesh->getVertex(v2)->getPoint(), + mesh->getVertex(v3)->getPoint(), + mesh->getVertex(v4)->getPoint(), + mesh->getVertex(v5)->getPoint()); +} + +/** + * Computes if vertex w is not inside the circle defined by v1,v2,v3 (seems to be a nice triangle) + * @param mesh mesh that contains the faces, edges and vertices + * @param v1 first vertex index + * @param v2 second vertex index + * @param v3 third vertex index + * @param w fourth vertex index + * @return if v1,v2,v3 defines a nice triangle against w + */ +bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index w) +{ + return BOP_isInsideCircle(mesh->getVertex(v1)->getPoint(), + mesh->getVertex(v2)->getPoint(), + mesh->getVertex(v3)->getPoint(), + mesh->getVertex(w)->getPoint()); +} diff --git a/intern/boolop/intern/BOP_Triangulator.h b/intern/boolop/intern/BOP_Triangulator.h new file mode 100644 index 00000000000..12223e1ea1f --- /dev/null +++ b/intern/boolop/intern/BOP_Triangulator.h @@ -0,0 +1,44 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_TRIANGULATOR_H +#define BOP_TRIANGULATOR_H + +#include "BOP_MathUtils.h" +#include "BOP_Mesh.h" + +void BOP_triangulateA(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v, unsigned int e); +void BOP_triangulateB(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v); +void BOP_triangulateC(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2); +void BOP_triangulateD(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e); +void BOP_triangulateE(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e1, unsigned int e2); +void BOP_triangulateF(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e); + +#endif diff --git a/intern/boolop/intern/BOP_Vertex.cpp b/intern/boolop/intern/BOP_Vertex.cpp new file mode 100644 index 00000000000..c039df5775d --- /dev/null +++ b/intern/boolop/intern/BOP_Vertex.cpp @@ -0,0 +1,94 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "BOP_Vertex.h" + +/** + * Constructs a new vertex with the specified coordinates. + * @param x X-axis coordinate + * @param y Y-axis coordinate + * @param z Z-axis coordinate + */ +BOP_Vertex::BOP_Vertex(double x, double y, double z) +{ + m_point.setValue(x,y,z); + m_tag = UNCLASSIFIED; +} + +/** + * Constructs a new vertex with the specified point. + * @param p point XYZ + */ +BOP_Vertex::BOP_Vertex(MT_Point3 p) +{ + m_point = p; + m_tag = UNCLASSIFIED; +} + +/** + * Adds a new edge index to this vertex. + * @param i edge index + */ +void BOP_Vertex::addEdge(BOP_Index i) +{ + if (!containsEdge(i)) + m_edges.push_back(i); +} + +/** + * Removes an edge index from this vertex. + * @param i edge index + */ +void BOP_Vertex::removeEdge(BOP_Index i) +{ + for(BOP_IT_Indexs it = m_edges.begin();it!=m_edges.end();it++) { + if ((*it)==i) { + m_edges.erase(it); + return; + } + } +} + +/** + * Returns if this vertex contains the specified edge index. + * @param i edge index + * @return true if this vertex contains the specified edge index, false otherwise + */ +bool BOP_Vertex::containsEdge(BOP_Index i) +{ + int pos=0; + for(BOP_IT_Indexs it = m_edges.begin();it!=m_edges.end();pos++,it++) { + if ((*it)==i){ + return true; + } + } + + return false; +} diff --git a/intern/boolop/intern/BOP_Vertex.h b/intern/boolop/intern/BOP_Vertex.h new file mode 100644 index 00000000000..a781407af34 --- /dev/null +++ b/intern/boolop/intern/BOP_Vertex.h @@ -0,0 +1,60 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BOP_VERTEX_H +#define BOP_VERTEX_H + +#include "BOP_Tag.h" +#include "BOP_Indexs.h" +#include "MT_Point3.h" + +class BOP_Vertex +{ +private: + MT_Point3 m_point; + BOP_Indexs m_edges; + BOP_TAG m_tag; + + bool containsEdge(BOP_Index i); + +public: + BOP_Vertex(double x, double y, double z); + BOP_Vertex(MT_Point3 d); + void addEdge(BOP_Index i); + void removeEdge(BOP_Index i); + inline BOP_Index getEdge(unsigned int i) { return m_edges[i];}; + inline unsigned int getNumEdges() { return m_edges.size();}; + inline BOP_Indexs &getEdges() { return m_edges;}; + inline MT_Point3 getPoint() const { return m_point;}; + inline BOP_TAG getTAG() { return m_tag;}; + inline void setTAG(BOP_TAG t) { m_tag = t;}; +}; + +#endif diff --git a/intern/boolop/intern/Makefile b/intern/boolop/intern/Makefile new file mode 100644 index 00000000000..0838f44ca8a --- /dev/null +++ b/intern/boolop/intern/Makefile @@ -0,0 +1,51 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# string intern Makefile +# + +LIBNAME = boolop +DIR = $(OCGDIR)/intern/$(LIBNAME) +DIRS = common + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../extern +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include +CPPFLAGS += -I../../../source/blender/makesdna +CPPFLAGS += -I../../../source/blender/blenlib +CPPFLAGS += -Icommon + + diff --git a/intern/boolop/make/msvc_6_0/boolop.dsp b/intern/boolop/make/msvc_6_0/boolop.dsp new file mode 100644 index 00000000000..f8a072b4531 --- /dev/null +++ b/intern/boolop/make/msvc_6_0/boolop.dsp @@ -0,0 +1,222 @@ +# Microsoft Developer Studio Project File - Name="boolop" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=boolop - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "boolop.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "boolop.mak" CFG="boolop - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "boolop - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "boolop - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "boolop - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\source\blender\makesdna\\" /I "..\..\..\..\..\lib\windows\moto\include\\" /I "..\..\..\..\..\lib\windows\container\include\\" /I "..\..\..\..\..\lib\windows\memutil\include\\" /I "../../extern" /I "..\..\..\..\..\lib\windows\guardedalloc\include\\" /I "..\..\..\..\source\blender\blenlib\\" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy to lib folder XCOPY /Y .\release\*.lib ..\..\..\..\..\lib\windows\boolop\lib\*.lib +# End Special Build Tool + +!ELSEIF "$(CFG)" == "boolop - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\blender\makesdna\\" /I "..\..\..\..\..\lib\windows\moto\include\\" /I "..\..\..\..\..\lib\windows\container\include\\" /I "..\..\..\..\..\lib\windows\memutil\include\\" /I "../../extern" /I "..\..\..\..\..\lib\windows\guardedalloc\include\\" /I "..\..\..\..\source\blender\blenlib\\" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "boolop - Win32 Release" +# Name "boolop - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\BOP_BBox.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_BSPNode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_BSPTree.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Edge.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Face.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Face2Face.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Interface.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_MathUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Merge.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Mesh.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Segment.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Splitter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Tag.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Triangulator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Vertex.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\intern\BOP_BBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_BSPNode.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_BSPTree.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Chrono.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Edge.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Face.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Face2Face.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Indexs.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_MathUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Merge.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Mesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Segment.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Splitter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Tag.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Triangulator.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BOP_Vertex.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/boolop/make/msvc_7_0/boolop.vcproj b/intern/boolop/make/msvc_7_0/boolop.vcproj new file mode 100644 index 00000000000..7ae417e42d5 --- /dev/null +++ b/intern/boolop/make/msvc_7_0/boolop.vcproj @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bsp/CMakeLists.txt b/intern/bsp/CMakeLists.txt new file mode 100644 index 00000000000..b6fbb8e4812 --- /dev/null +++ b/intern/bsp/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC intern ../container ../moto/include ../memutil) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(blender_BSP "${SRC}" "${INC}") +#, libtype='core', priority=15 ) diff --git a/intern/bsp/Makefile b/intern/bsp/Makefile new file mode 100644 index 00000000000..818e4d69606 --- /dev/null +++ b/intern/bsp/Makefile @@ -0,0 +1,59 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bsp main makefile. +# + +include nan_definitions.mk + +LIBNAME = bsp +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +# not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_BSP) ] || mkdir $(NAN_BSP) + @[ -d $(NAN_BSP)/include ] || mkdir $(NAN_BSP)/include + @[ -d $(NAN_BSP)/lib ] || mkdir $(NAN_BSP)/lib + @[ -d $(NAN_BSP)/lib/debug ] || mkdir $(NAN_BSP)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libbsp.a $(NAN_BSP)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libbsp.a $(NAN_BSP)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_BSP)/lib/libbsp.a + ranlib $(NAN_BSP)/lib/debug/libbsp.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_BSP)/include/ + + + + diff --git a/intern/bsp/SConscript b/intern/bsp/SConscript new file mode 100644 index 00000000000..e363fd1d4c3 --- /dev/null +++ b/intern/bsp/SConscript @@ -0,0 +1,12 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = 'intern ../container ../moto/include ../memutil' + +if (env['OURPLATFORM'] == 'win32-mingw'): + env.BlenderLib ('blender_BSP', sources, Split(incs), [], libtype=['common','intern'], priority=[26,26] ) +else: + env.BlenderLib ('blender_BSP', sources, Split(incs), [], libtype='core', priority=15 ) + diff --git a/intern/bsp/extern/CSG_BooleanOps.h b/intern/bsp/extern/CSG_BooleanOps.h new file mode 100644 index 00000000000..1e862568cda --- /dev/null +++ b/intern/bsp/extern/CSG_BooleanOps.h @@ -0,0 +1,360 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef CSG_BOOLEANOPS_H +#define CSG_BOOLEANOPS_H + + +/** + * @section Interface structures for CSG module. + * This interface falls into 2 categories. + * The first section deals with an abstract mesh description + * between blender and this module. The second deals with + * the module functions. + * The CSG module needs to know about the following entities: + */ + +/** + * CSG_IFace -- an interface polygon structure. + * vertex_index is a fixed size array of 4 elements containing indices into + * an abstract vertex container. 3 or 4 of these elements may be used to + * describe either quads or triangles. + * vertex_number is the number of vertices in this face - either 3 or 4. + * vertex_colors is an array of {r,g,b} triplets one for each vertex index. + * tex_coords is an array of {u,v} triplets one for each vertex index. + * user_data is a pointer to arbitary data of fixed width , + * this data is copied around with the face, and duplicated if a face is + * split. Contains things like material index. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int vertex_index[4]; + int vertex_number; + int orig_face; +} CSG_IFace; + +/** + * CSG_IVertex -- an interface vertex structure. + * position is the location of the vertex in 3d space. + */ + +typedef struct { + float position[3]; +} CSG_IVertex; + +/** + * The actual useful data contained in a group of faces is + * described by the following struct + */ + +/** + * @section Iterator abstraction. + * + * The CSG module asks blender to fill in an instance of the above + * structure, and requests blender to move up and down (iterate) through + * it's face and vertex containers. + * + * An iterator supports the following functions. + * int IsDone(iterator *it) -- returns true if the iterator has reached + * the end of it's container. + * + * void Fill(iterator *it,DataType *data) -- Return the contents of the + * container at the current iterator position. + * + * void Step(iterator *it) -- increment the iterator to the next position + * in the container. + * + * The iterator is used in the following manner. + * + * MyIterator * iterator = ... + * DataType data; + * + * while (!IsDone(iterator)) { + * Fill(iterator,&data); + * //process information pointed to by data + * ... + * Step(iterator); + * } + * + * The CSG module does not want to know about the implementation of these + * functions so we use the c function ptr mechanism to hide them. Our + * iterator descriptor now looks like this. + */ + +typedef void* CSG_IteratorPtr; + +typedef int (*CSG_FaceItDoneFunc)(CSG_IteratorPtr it); +typedef void (*CSG_FaceItFillFunc)(CSG_IteratorPtr it,CSG_IFace *face); +typedef void (*CSG_FaceItStepFunc)(CSG_IteratorPtr it); +typedef void (*CSG_FaceItResetFunc)(CSG_IteratorPtr it); + +typedef struct CSG_FaceIteratorDescriptor { + CSG_IteratorPtr it; + CSG_FaceItDoneFunc Done; + CSG_FaceItFillFunc Fill; + CSG_FaceItStepFunc Step; + CSG_FaceItResetFunc Reset; + unsigned int num_elements; +} CSG_FaceIteratorDescriptor; + +/** + * Similarly to walk through the vertex arrays we have. + */ +typedef int (*CSG_VertexItDoneFunc)(CSG_IteratorPtr it); +typedef void (*CSG_VertexItFillFunc)(CSG_IteratorPtr it,CSG_IVertex *face); +typedef void (*CSG_VertexItStepFunc)(CSG_IteratorPtr it); +typedef void (*CSG_VertexItResetFunc)(CSG_IteratorPtr it); + +typedef struct CSG_VertexIteratorDescriptor { + CSG_IteratorPtr it; + CSG_VertexItDoneFunc Done; + CSG_VertexItFillFunc Fill; + CSG_VertexItStepFunc Step; + CSG_VertexItResetFunc Reset; + unsigned int num_elements; +} CSG_VertexIteratorDescriptor; + +/** + * The actual iterator structures are not exposed to the CSG module, they + * will contain datatypes specific to blender. + */ + +/** + * @section CSG Module interface functions. + * + * The functions below are to be used in the following way: + * + * // Create a boolean operation handle + * CSG_BooleanOperation *operation = CSG_NewBooleanFunction(); + * if (operation == NULL) { + * // deal with low memory exception + * } + * + * // Report to the user if they will loose any data! + * ... + * + * // Get some mesh iterators for your mesh data structures + * CSG_FaceIteratorDescriptor obA_faces = ... + * CSG_VertexIteratorDescriptor obA_verts = ... + * + * // same for object B + * CSG_FaceIteratorDescriptor obB_faces = ... + * CSG_VertexIteratorDescriptor obB_verts = ... + * + * // perform the operation...! + * + * int success = CSG_PerformBooleanOperation( + * operation, + * e_csg_intersection, + * obA_faces, + * obA_vertices, + * obB_faces, + * obB_vertices + * ); + * + * // if the operation failes report miserable faiulre to user + * // and clear up data structures. + * if (!success) { + * ... + * CSG_FreeBooleanOperation(operation); + * return; + * } + * + * // read the new mesh vertices back from the module + * // and assign to your own mesh structure. + * + * // First we need to create a CSG_IVertex so the module can fill it in. + * CSG_IVertex vertex; + * CSG_VertexIteratorDescriptor * verts_it = CSG_OutputVertexDescriptor(operation); + * + * // initialize your vertex container with the number of verts (verts_it->num_elements) + * + * while (!verts_it->Done(verts_it->it)) { + * verts_it->Fill(verts_it->it,&vertex); + * + * // create a new vertex of your own type and add it + * // to your mesh structure. + * verts_it->Step(verts_it->it); + * } + * // Free the vertex iterator + * CSG_FreeVertexDescriptor(verts_it); + * + * // similarly for faces. + * CSG_IFace face; + * + * // you may need to reserve some memory in face->user_data here. + * + * // initialize your face container with the number of faces (faces_it->num_elements) + * + * CSG_FaceIteratorDescriptor * faces_it = CSG_OutputFaceDescriptor(operation); + * + * while (!faces_it->Done(faces_it->it)) { + * faces_it->Fill(faces_it->it,&face); + * + * // create a new face of your own type and add it + * // to your mesh structure. + * faces_it->Step(&faces_it->it); + * } + * + * // Free the face iterator + * CSG_FreeVertexDescriptor(faces_it); + * + * // that's it free the operation. + * + * CSG_FreeBooleanOperation(operation); + * return; + * + */ + +/** + * Description of boolean operation type. + */ + +typedef enum { + e_csg_union, + e_csg_intersection, + e_csg_difference, + e_csg_classify +} CSG_OperationType; + +/** + * 'Handle' into the CSG module that identifies a particular CSG operation. + * the pointer CSG_info containers module specific data, and should not + * be touched in anyway outside of the module. + */ + +typedef struct { + void *CSG_info; +} CSG_BooleanOperation; + +/** + * Return a ptr to a CSG_BooleanOperation object allocated + * on the heap. The CSG module owns the memory associated with + * the returned ptr, use CSG_FreeBooleanOperation() to free this memory. + */ + CSG_BooleanOperation * +CSG_NewBooleanFunction( + void +); + +/** + * Attempt to perform a boolean operation between the 2 objects of the + * desired type. This may fail due to an internal error or lack of memory. + * In this case 0 is returned, otehrwise 1 is returned indicating success. + * @param operation is a 'handle' into the CSG_Module created by CSG_NewBooleanFunction() + * @param op_type is the operation to perform. + * @param obAFaces is an iterator over the faces of objectA, + * @param obAVertices is an iterator over the vertices of objectA + * @param obAFaces is an iterator over the faces of objectB, + * @param obAVertices is an iterator over the vertices of objectB + * @param interp_func the face_vertex data interpolation function.(see above) + * + * All iterators must be valid and pointing to the first element in their + * respective containers. + */ + int +CSG_PerformBooleanOperation( + CSG_BooleanOperation * operation, + CSG_OperationType op_type, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices +); + +/** + * If the a boolean operation was successful, you may access the results + * through the following functions. + * + * CSG_OuputFaceDescriptor() returns a ptr to a CSG_FaceIteratorDesciptor + * allocated on the heap and owned by the CSG module. The iterator is + * positioned at the start of the internal face container. + * CSG_OutputVertexDescriptor() returns a ptr to a CSG_VertexIteratorDescriptor + * allocated on the heap and owned by the CSG module. The iterator is + * positioned at the start of the internal vertex container. + * There is no function to rewind an iterator but you may obtain more + * than one + * iterator at a time. Please use the function CSG_FreeFaceIterator() + * and CSG_FreeVertexIterator to free internal memory allocated for these + * iterators. + * + * If the last operation was not successful, these functions return NULL. + */ + int +CSG_OutputFaceDescriptor( + CSG_BooleanOperation * operation, + CSG_FaceIteratorDescriptor * output +); + + int +CSG_OutputVertexDescriptor( + CSG_BooleanOperation * operation, + CSG_VertexIteratorDescriptor *output +); + +/** + * Clean up functions. + * Free internal memory associated with CSG interface structures. You must + * call these functions on any structures created by the module, even if + * subsequent operations did not succeed. + */ + void +CSG_FreeVertexDescriptor( + CSG_VertexIteratorDescriptor * v_descriptor +); + + void +CSG_FreeFaceDescriptor( + CSG_FaceIteratorDescriptor * f_descriptor +); + +/** + * Free the memory associated with a boolean operation. + * NOTE any iterator descriptor describing the output will become + * invalid after this call and should be freed immediately. + */ + void +CSG_FreeBooleanOperation( + CSG_BooleanOperation *operation +); + +#ifdef __cplusplus +} +#endif + + + +#endif + diff --git a/intern/bsp/intern/BSP_CSGException.h b/intern/bsp/intern/BSP_CSGException.h new file mode 100644 index 00000000000..c2d79630be2 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGException.h @@ -0,0 +1,58 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_CSGException_h +#define NAN_INCLUDED_CSGException_h + +// stick in more error types as you think of them + +enum BSP_ExceptionType{ + e_split_error, + e_mesh_error, + e_mesh_input_error, + e_param_error, + e_tree_build_error +}; + + +class BSP_CSGException { +public : + BSP_ExceptionType m_e_type; + + BSP_CSGException ( + BSP_ExceptionType type + ) : m_e_type (type) + { + } +}; + +#endif + diff --git a/intern/bsp/intern/BSP_CSGMesh.cpp b/intern/bsp/intern/BSP_CSGMesh.cpp new file mode 100644 index 00000000000..5da39c8d551 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh.cpp @@ -0,0 +1,655 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + + +#include "BSP_CSGMesh.h" +#include "MT_assert.h" +#include "CTR_TaggedSetOps.h" +#include "MT_Plane3.h" +#include "BSP_CSGException.h" + +// for vector reverse +#include +#include +using namespace std; + +BSP_CSGMesh:: +BSP_CSGMesh( +) : + MEM_RefCountable() +{ + m_verts = NULL; + m_faces = NULL; + m_edges = NULL; +} + + BSP_CSGMesh * +BSP_CSGMesh:: +New( +){ + return new BSP_CSGMesh(); +} + + BSP_CSGMesh * +BSP_CSGMesh:: +NewCopy( +) const { + + BSP_CSGMesh *mesh = New(); + if (mesh == NULL) return NULL; + + mesh->m_bbox_max = m_bbox_max; + mesh->m_bbox_min = m_bbox_min; + + if (m_edges != NULL) { + mesh->m_edges = new vector(*m_edges); + if (mesh->m_edges == NULL) { + delete mesh; + return NULL; + } + } + if (m_verts != NULL) { + mesh->m_verts = new vector(*m_verts); + if (mesh->m_verts == NULL) { + if (m_edges != NULL) free(mesh->m_edges); + delete mesh; + return NULL; + } + } + if (m_faces != NULL) { + mesh->m_faces = new vector(*m_faces); + if (mesh->m_faces == NULL) { + delete mesh; + return NULL; + } + } + + return mesh; +} + + void +BSP_CSGMesh:: +Invert( +){ + + vector & faces = FaceSet(); + + vector::const_iterator faces_end = faces.end(); + vector::iterator faces_it = faces.begin(); + + for (; faces_it != faces_end; ++faces_it) { + faces_it->Invert(); + } +} + + bool +BSP_CSGMesh:: +SetVertices( + vector *verts +){ + if (verts == NULL) return false; + + // create polygon and edge arrays and reserve some space. + m_faces = new vector; + if (!m_faces) return false; + + m_faces->reserve(verts->size()/2); + + // previous verts get deleted here. + m_verts = verts; + return true; +} + + void +BSP_CSGMesh:: +AddPolygon( + const int * verts, + int num_verts +){ + MT_assert(verts != NULL); + MT_assert(num_verts >=3); + + if (verts == NULL || num_verts <3) return; + + // make a polyscone from these vertex indices. + + const BSP_FaceInd fi = m_faces->size(); + m_faces->push_back(BSP_MFace()); + BSP_MFace & face = m_faces->back(); + + insert_iterator > insert_point(face.m_verts,face.m_verts.end()); + copy (verts,verts + num_verts,insert_point); + + // compute and store the plane equation for this face. + + MT_Plane3 face_plane = FacePlane(fi); + face.m_plane = face_plane; +}; + +// assumes that the face already has a plane equation + void +BSP_CSGMesh:: +AddPolygon( + const BSP_MFace &face +){ + m_faces->push_back(face); +}; + + + bool +BSP_CSGMesh:: +BuildEdges( +){ + + if (m_faces == NULL) return false; + + if (m_edges != NULL) { + DestroyEdges(); + } + + m_edges = new vector; + + if (m_edges == NULL) { + return false; + } + + + //iterate through the face set and add edges for all polygon + //edges + + vector::const_iterator f_it_end = FaceSet().end(); + vector::iterator f_it_begin = FaceSet().begin(); + vector::iterator f_it = FaceSet().begin(); + + vector dummy; + + for (;f_it != f_it_end; ++f_it) { + + BSP_MFace & face = *f_it; + + int vertex_num = face.m_verts.size(); + BSP_VertexInd prev_vi(face.m_verts[vertex_num-1]); + + for (int vert = 0; vert < vertex_num; ++vert) { + + BSP_FaceInd fi(f_it - f_it_begin); + InsertEdge(prev_vi,face.m_verts[vert],fi,dummy); + prev_vi = face.m_verts[vert]; + } + + } + dummy.clear(); + return true; +} + + void +BSP_CSGMesh:: +DestroyEdges( +){ + if ( m_edges != NULL ) { + delete m_edges; + m_edges = NULL; + } + + // Run through the vertices + // and clear their edge arrays. + + if (m_verts){ + + vector::const_iterator vertex_end = VertexSet().end(); + vector::iterator vertex_it = VertexSet().begin(); + + for (; vertex_it != vertex_end; ++vertex_it) { + vertex_it->m_edges.clear(); + } + } +} + + + BSP_EdgeInd +BSP_CSGMesh:: +FindEdge( + const BSP_VertexInd & v1, + const BSP_VertexInd & v2 +) const { + + vector &verts = VertexSet(); + vector &edges = EdgeSet(); + + BSP_MEdge e; + e.m_verts[0] = v1; + e.m_verts[1] = v2; + + vector &v1_edges = verts[v1].m_edges; + vector::const_iterator v1_end = v1_edges.end(); + vector::const_iterator v1_begin = v1_edges.begin(); + + for (; v1_begin != v1_end; ++v1_begin) { + if (edges[*v1_begin] == e) return *v1_begin; + } + + return BSP_EdgeInd::Empty(); +} + + void +BSP_CSGMesh:: +InsertEdge( + const BSP_VertexInd & v1, + const BSP_VertexInd & v2, + const BSP_FaceInd & f, + vector &new_edges +){ + + MT_assert(!v1.IsEmpty()); + MT_assert(!v2.IsEmpty()); + MT_assert(!f.IsEmpty()); + + if (v1.IsEmpty() || v2.IsEmpty() || f.IsEmpty()) { + BSP_CSGException e(e_mesh_error); + throw (e); + } + + vector &verts = VertexSet(); + vector &edges = EdgeSet(); + + BSP_EdgeInd e; + + e = FindEdge(v1,v2); + if (e.IsEmpty()) { + // This edge does not exist -- make a new one + + BSP_MEdge temp_e; + temp_e.m_verts[0] = v1; + temp_e.m_verts[1] = v2; + + e = m_edges->size(); + // set the face index from the edge back to this polygon. + temp_e.m_faces.push_back(f); + + m_edges->push_back(temp_e); + + // add the edge index to it's vertices + verts[v1].AddEdge(e); + verts[v2].AddEdge(e); + + new_edges.push_back(e); + + } else { + + // edge already exists + // insure that there is no polygon already + // attached to the other side of this edge + // swap the empty face pointer in edge with f + + BSP_MEdge &edge = edges[e]; + + // set the face index from the edge back to this polygon. + edge.m_faces.push_back(f); + } +} + + +// geometry access +////////////////// + + vector & +BSP_CSGMesh:: +VertexSet( +) const { + return *m_verts; +} + + vector & +BSP_CSGMesh:: +FaceSet( +) const { + return *m_faces; +} + + vector & +BSP_CSGMesh:: +EdgeSet( +) const { + return *m_edges; +} + +BSP_CSGMesh:: +~BSP_CSGMesh( +){ + if ( m_verts != NULL ) delete m_verts; + if ( m_faces != NULL ) delete m_faces; + if ( m_edges != NULL ) delete m_edges; +} + +// local geometry queries. +///////////////////////// + +// face queries +/////////////// + + void +BSP_CSGMesh:: +FaceVertices( + const BSP_FaceInd & f, + vector &output +){ + vector & face_set = FaceSet(); + output.insert( + output.end(), + face_set[f].m_verts.begin(), + face_set[f].m_verts.end() + ); +} + + + void +BSP_CSGMesh:: +FaceEdges( + const BSP_FaceInd & fi, + vector &output +){ + // take intersection of the edges emminating from all the vertices + // of this polygon; + + vector &faces = FaceSet(); + vector &edges = EdgeSet(); + + const BSP_MFace & f = faces[fi]; + + // collect vertex edges; + + vector::const_iterator face_verts_it = f.m_verts.begin(); + vector::const_iterator face_verts_end = f.m_verts.end(); + + vector< vector > vertex_edges(f.m_verts.size()); + + int vector_slot = 0; + + for (;face_verts_it != face_verts_end; ++face_verts_it, ++vector_slot) { + VertexEdges(*face_verts_it,vertex_edges[vector_slot]); + } + + int prev = vector_slot - 1; + + // intersect pairs of edge sets + + for (int i = 0; i < vector_slot;i++) { + CTR_TaggedSetOps::IntersectPair(vertex_edges[prev],vertex_edges[i],edges,output); + prev = i; + } + + // should always have 3 or more unique edges per face. + MT_assert(output.size() >=3); + + if (output.size() < 3) { + BSP_CSGException e(e_mesh_error); + throw(e); + } +}; + +// edge queries +/////////////// + + void +BSP_CSGMesh:: +EdgeVertices( + const BSP_EdgeInd & e, + vector &output +){ + const vector &edges = EdgeSet(); + output.push_back(edges[e].m_verts[0]); + output.push_back(edges[e].m_verts[1]); +} + + void +BSP_CSGMesh:: +EdgeFaces( + const BSP_EdgeInd & e, + vector &output +){ + + vector & edge_set = EdgeSet(); + output.insert( + output.end(), + edge_set[e].m_faces.begin(), + edge_set[e].m_faces.end() + ); + +} + +// vertex queries +///////////////// + + void +BSP_CSGMesh:: +VertexEdges( + const BSP_VertexInd &v, + vector &output +){ + + vector & vertex_set = VertexSet(); + output.insert( + output.end(), + vertex_set[v].m_edges.begin(), + vertex_set[v].m_edges.end() + ); +} + + void +BSP_CSGMesh:: +VertexFaces( + const BSP_VertexInd &vi, + vector &output +) { + + vector &edges = EdgeSet(); + vector &faces = FaceSet(); + vector &verts = VertexSet(); + + const vector &v_edges = verts[vi].m_edges; + vector::const_iterator e_it = v_edges.begin(); + + for (; e_it != v_edges.end(); ++e_it) { + + BSP_MEdge &e = edges[*e_it]; + + // iterate through the faces of this edge - push unselected + // edges to ouput and then select the edge + + vector::const_iterator e_faces_end = e.m_faces.end(); + vector::iterator e_faces_it = e.m_faces.begin(); + + for (;e_faces_it != e_faces_end; ++e_faces_it) { + + if (!faces[*e_faces_it].SelectTag()) { + output.push_back(*e_faces_it); + faces[*e_faces_it].SetSelectTag(true); + } + } + } + + // deselect selected faces. + vector::iterator f_it = output.begin(); + + for (; f_it != output.end(); ++f_it) { + faces[*f_it].SetSelectTag(false); + } +} + + bool +BSP_CSGMesh:: +SC_Face( + BSP_FaceInd f +){ + + + +#if 0 + { + // check area is greater than zero. + + vector & verts = VertexSet(); + + vector f_verts; + FaceVertices(f,f_verts); + + MT_assert(f_verts.size() >= 3); + + BSP_VertexInd root = f_verts[0]; + + MT_Scalar area = 0; + + for (int i=2; i < f_verts.size(); i++) { + MT_Vector3 a = verts[root].m_pos; + MT_Vector3 b = verts[f_verts[i-1]].m_pos; + MT_Vector3 c = verts[f_verts[i]].m_pos; + + MT_Vector3 l1 = b-a; + MT_Vector3 l2 = c-b; + + area += (l1.cross(l2)).length()/2; + } + + MT_assert(!MT_fuzzyZero(area)); + } +#endif + // Check coplanarity +#if 0 + MT_Plane3 plane = FacePlane(f); + + const BSP_MFace & face = FaceSet()[f]; + vector::const_iterator f_verts_it = face.m_verts.begin(); + vector::const_iterator f_verts_end = face.m_verts.end(); + + for (;f_verts_it != f_verts_end; ++f_verts_it) { + MT_Scalar dist = plane.signedDistance( + VertexSet()[*f_verts_it].m_pos + ); + + MT_assert(fabs(dist) < BSP_SPLIT_EPSILON); + } +#endif + + + // Check connectivity + + vector f_edges; + FaceEdges(f,f_edges); + + MT_assert(f_edges.size() == FaceSet()[f].m_verts.size()); + + unsigned int i; + for (i = 0; i < f_edges.size(); ++i) { + + int matches = 0; + for (unsigned int j = 0; j < EdgeSet()[f_edges[i]].m_faces.size(); j++) { + + if (EdgeSet()[f_edges[i]].m_faces[j] == f) matches++; + } + + MT_assert(matches == 1); + + } + return true; +} + + MT_Plane3 +BSP_CSGMesh:: +FacePlane( + const BSP_FaceInd & fi +) const{ + + const BSP_MFace & f0 = FaceSet()[fi]; + + // Have to be a bit careful here coz the poly may have + // a lot of parallel edges. Should walk round the polygon + // and check length of cross product. + + const MT_Vector3 & p1 = VertexSet()[f0.m_verts[0]].m_pos; + const MT_Vector3 & p2 = VertexSet()[f0.m_verts[1]].m_pos; + + int face_size = f0.m_verts.size(); + MT_Vector3 n; + + for (int i = 2 ; i & face_set = FaceSet(); + + vector::const_iterator face_it = face_set.begin(); + vector::const_iterator face_end = face_set.end(); + + int sum = 0; + + for (;face_it != face_end; face_it++) { + + // Should be careful about degenerate faces here. + sum += face_it->m_verts.size() - 2; + } + + return sum; +} + diff --git a/intern/bsp/intern/BSP_CSGMesh.h b/intern/bsp/intern/BSP_CSGMesh.h new file mode 100644 index 00000000000..47903520157 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh.h @@ -0,0 +1,249 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_BSP_CSGMesh_h +#define NAN_INCLUDED_BSP_CSGMesh_h + +#include "BSP_MeshPrimitives.h" +#include "MEM_SmartPtr.h" +#include "MEM_RefCountPtr.h" +#include "MEM_NonCopyable.h" +#include "../extern/CSG_BooleanOps.h" + + +class MT_Plane3; + +class BSP_CSGMesh : + public MEM_NonCopyable, + public MEM_RefCountable +{ + +public : + + static + BSP_CSGMesh * + New( + ); + + bool + SetVertices( + std::vector *verts + ); + + void + AddPolygon( + const int * verts, + int num_verts + ); + + // assumes that the face already has a plane equation + void + AddPolygon( + const BSP_MFace &face + ); + + + // Allocate and build the mesh edges. + //////////////////////////////////// + + bool + BuildEdges( + ); + + // Clean the mesh of edges. and edge pointers + // This removes the circular connectivity information + ///////////////////////////////////////////// + + void + DestroyEdges( + ); + + // return a new seperate copy of the + // mesh allocated on the heap. + + BSP_CSGMesh * + NewCopy( + ) const; + + + // Reverse the winding order of every polygon + // in the mesh and swap the planes around. + + void + Invert( + ); + + + // geometry access + ////////////////// + + std::vector & + VertexSet( + ) const ; + + std::vector & + FaceSet( + ) const ; + + std::vector & + EdgeSet( + ) const; + + ~BSP_CSGMesh( + ); + + // local geometry queries. + ///////////////////////// + + // face queries + /////////////// + + void + FaceVertices( + const BSP_FaceInd & f, + std::vector &output + ); + + void + FaceEdges( + const BSP_FaceInd & f, + std::vector &output + ); + + // edge queries + /////////////// + + void + EdgeVertices( + const BSP_EdgeInd & e, + std::vector &output + ); + + void + EdgeFaces( + const BSP_EdgeInd & e, + std::vector &output + ); + + // vertex queries + ///////////////// + + void + VertexEdges( + const BSP_VertexInd & v, + std::vector &output + ); + + void + VertexFaces( + const BSP_VertexInd & v, + std::vector &output + ); + + // Returns the edge index of the edge from v1 to v2. + // Does this by searching the edge sets of v1 - but not v2. + // If you are paranoid you should check both and make sure the + // indices are the same. If the edge doe not exist edgeInd is empty. + + BSP_EdgeInd + FindEdge( + const BSP_VertexInd &v1, + const BSP_VertexInd &v2 + ) const; + + + /** + * Sanity checkers + */ + + // make sure the edge faces have a pointer to f + + bool + SC_Face( + BSP_FaceInd f + ); + + /** + * Return the face plane equation + */ + + MT_Plane3 + FacePlane( + const BSP_FaceInd &fi + )const; + + + /** + * Recompute Face plane equations. + * essential if you have been messing with the object. + */ + + void + ComputeFacePlanes( + ); + + /** + * Count the number of trinagles in the mesh. + * This is not the same as the number of polygons. + */ + + int + CountTriangles( + ) const; + +private : + + void + InsertEdge( + const BSP_VertexInd &v1, + const BSP_VertexInd &v2, + const BSP_FaceInd &f, + std::vector &new_edges + ); + + + // Private to insure heap instantiation. + + BSP_CSGMesh( + ); + + std::vector *m_verts; + std::vector *m_faces; + std::vector *m_edges; + + MT_Vector3 m_bbox_min; + MT_Vector3 m_bbox_max; + +}; + + +#endif + diff --git a/intern/bsp/intern/BSP_CSGMesh_CFIterator.h b/intern/bsp/intern/BSP_CSGMesh_CFIterator.h new file mode 100644 index 00000000000..010f62159a5 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh_CFIterator.h @@ -0,0 +1,270 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_CSGMesh_CFIterator_h + +#define BSP_CSGMesh_CFIterator_h + +#include "BSP_CSGMesh.h" +#include "../extern/CSG_BooleanOps.h" +/** + * This class defines 2 C style iterators over a CSG mesh, one for + * vertices and 1 for faces. They conform to the iterator interface + * defined in CSG_BooleanOps.h + */ + +struct BSP_CSGMesh_VertexIt { + BSP_CSGMesh *mesh; + BSP_MVertex * pos; +}; + + +inline + void +BSP_CSGMesh_VertexIt_Destruct( + CSG_VertexIteratorDescriptor * iterator +) { + delete ((BSP_CSGMesh_VertexIt *)(iterator->it)); + iterator->it = NULL; + iterator->Done = NULL; + iterator->Fill = NULL; + iterator->Reset = NULL; + iterator->Step = NULL; + iterator->num_elements = 0; +}; + + +inline + int +BSP_CSGMesh_VertexIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + /* dereferencing iterator::end() is illegal, so we dereference 1 before it */ + /* also check that vector is not empty */ + if (vertex_it->mesh->VertexSet().size() && + vertex_it->pos <= &(*(vertex_it->mesh->VertexSet().end() -1) )) return 0; + return 1; +}; + +inline + void +BSP_CSGMesh_VertexIt_Fill( + CSG_IteratorPtr it, + CSG_IVertex *vert +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + vertex_it->pos->m_pos.getValue(vert->position); +}; + +inline + void +BSP_CSGMesh_VertexIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + ++(vertex_it->pos); +}; + +inline + void +BSP_CSGMesh_VertexIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + vertex_it->pos = &vertex_it->mesh->VertexSet()[0]; +}; + +inline + void +BSP_CSGMeshVertexIt_Construct( + BSP_CSGMesh *mesh, + CSG_VertexIteratorDescriptor *output +){ + // user should have insured mesh is not equal to NULL. + + output->Done = BSP_CSGMesh_VertexIt_Done; + output->Fill = BSP_CSGMesh_VertexIt_Fill; + output->Step = BSP_CSGMesh_VertexIt_Step; + output->Reset = BSP_CSGMesh_VertexIt_Reset; + output->num_elements = mesh->VertexSet().size(); + + BSP_CSGMesh_VertexIt * v_it = new BSP_CSGMesh_VertexIt; + v_it->mesh = mesh; + if( output->num_elements > 0 ) + v_it->pos = &mesh->VertexSet()[0]; + output->it = v_it; +}; + + +/** + * Face iterator. + */ + +struct BSP_CSGMesh_FaceIt { + BSP_CSGMesh *mesh; + BSP_MFace *pos; + int face_triangle; +}; + + +inline + void +BSP_CSGMesh_FaceIt_Destruct( + CSG_FaceIteratorDescriptor *iterator +) { + delete ((BSP_CSGMesh_FaceIt *)(iterator->it)); + iterator->it = NULL; + iterator->Done = NULL; + iterator->Fill = NULL; + iterator->Reset = NULL; + iterator->Step = NULL; + iterator->num_elements = 0; +}; + + +inline + int +BSP_CSGMesh_FaceIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + + /* dereferencing iterator::end() is illegal, so we dereference 1 before it */ + /* also check that vector is not empty */ + if (face_it->mesh->FaceSet().size() && + face_it->pos <= &(*(face_it->mesh->FaceSet().end() -1))) { + if (face_it->face_triangle + 3 <= (int)face_it->pos->m_verts.size()) { + return 0; + } + } + return 1; +}; + +inline + void +BSP_CSGMesh_FaceIt_Fill( + CSG_IteratorPtr it, + CSG_IFace *face +){ + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + // essentially iterating through a triangle fan here. + + if (face_it->pos->m_verts.size()>3) { + // QUAD + face->vertex_index[0] = int(face_it->pos->m_verts[0]); + face->vertex_index[1] = int(face_it->pos->m_verts[1]); + face->vertex_index[2] = int(face_it->pos->m_verts[2]); + face->vertex_index[3] = int(face_it->pos->m_verts[3]); + + face->orig_face = face_it->pos->m_orig_face; + + face->vertex_number = 4; + } + else { + // TRIANGLE + face->vertex_index[0] = int(face_it->pos->m_verts[0]); + face->vertex_index[1] = int(face_it->pos->m_verts[1]); + face->vertex_index[2] = int(face_it->pos->m_verts[2]); + + face->orig_face = face_it->pos->m_orig_face; + + face->vertex_number = 3; + } +}; + +inline + void +BSP_CSGMesh_FaceIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + + /* dereferencing iterator::end() is illegal, so we dereference 1 before it */ + /* also check that vector is not empty */ + if (face_it->mesh->FaceSet().size() && + face_it->pos <= &(*(face_it->mesh->FaceSet().end() -1))) { + + //if (face_it->face_triangle + 3 < face_it->pos->m_verts.size()) { + // (face_it->face_triangle)++; + //} else { + face_it->face_triangle = 0; + (face_it->pos) ++; + //} + } +}; + +inline + void +BSP_CSGMesh_FaceIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * f_it = (BSP_CSGMesh_FaceIt *)it; + f_it->pos = &f_it->mesh->FaceSet()[0]; + f_it->face_triangle = 0; +}; + +inline + void +BSP_CSGMesh_FaceIt_Construct( + BSP_CSGMesh * mesh, + CSG_FaceIteratorDescriptor *output +) { + + output->Done = BSP_CSGMesh_FaceIt_Done; + output->Fill = BSP_CSGMesh_FaceIt_Fill; + output->Step = BSP_CSGMesh_FaceIt_Step; + output->Reset = BSP_CSGMesh_FaceIt_Reset; + + output->num_elements = mesh->FaceSet().size(); + + BSP_CSGMesh_FaceIt * f_it = new BSP_CSGMesh_FaceIt; + f_it->mesh = mesh; + if( output->num_elements > 0 ) + f_it->pos = &mesh->FaceSet()[0]; + f_it->face_triangle = 0; + + output->it = f_it; +}; + + +#endif + diff --git a/intern/bsp/intern/BSP_MeshPrimitives.cpp b/intern/bsp/intern/BSP_MeshPrimitives.cpp new file mode 100644 index 00000000000..54db5851be3 --- /dev/null +++ b/intern/bsp/intern/BSP_MeshPrimitives.cpp @@ -0,0 +1,301 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BSP_MeshPrimitives.h" + +#include "MT_assert.h" +#include "BSP_CSGException.h" +#include + +using namespace std; + +BSP_MVertex:: +BSP_MVertex( +) : + m_pos (MT_Point3()), + m_select_tag (false), + m_open_tag (0) +{ +}; + +BSP_MVertex:: +BSP_MVertex( + const MT_Point3 & pos +) : + m_pos(pos), + m_select_tag (false), + m_open_tag (0) +{ +}; + + + bool +BSP_MVertex:: +RemoveEdge( + BSP_EdgeInd e +){ + vector::iterator result = find(m_edges.begin(),m_edges.end(),e); + if (result == m_edges.end()) { + return false; + } + BSP_EdgeInd last = m_edges.back(); + m_edges.pop_back(); + if (m_edges.empty()) return true; + + *result = last; + return true; +} + + void +BSP_MVertex:: +AddEdge( + BSP_EdgeInd e +){ + m_edges.push_back(e); +} + + void +BSP_MVertex:: +SwapEdge( + BSP_EdgeInd e_old, + BSP_EdgeInd e_new +){ + vector::iterator result = + find(m_edges.begin(),m_edges.end(),e_old); + if (result == m_edges.end()) { + BSP_CSGException e(e_mesh_error); + throw(e); + MT_assert(false); + } + + *result = e_new; +} + + bool +BSP_MVertex:: +SelectTag( +) const{ + return m_select_tag; +} + + void +BSP_MVertex:: +SetSelectTag( + bool tag +){ + m_select_tag = tag; +} + + int +BSP_MVertex:: +OpenTag( +) const { + return m_open_tag; +} + + void +BSP_MVertex:: +SetOpenTag( + int tag +){ + m_open_tag = tag; +} + + +/** + * Edge Primitive Methods. + */ + +BSP_MEdge:: +BSP_MEdge( +){ + m_verts[0] = m_verts[1] = BSP_VertexInd::Empty(); +} + + bool +BSP_MEdge:: +operator == ( + BSP_MEdge & rhs +){ + // edges are the same if their vertex indices are the + // same!!! Other properties are not checked + + int matches = 0; + + if (this->m_verts[0] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[0] == rhs.m_verts[1]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[1]) { + ++matches; + } + + if (matches >= 2) { + return true; + } + return false; +} + + void +BSP_MEdge:: +SwapFace( + BSP_FaceInd old_f, + BSP_FaceInd new_f +){ + vector::iterator result = + find(m_faces.begin(),m_faces.end(),old_f); + if (result == m_faces.end()) { + BSP_CSGException e(e_mesh_error); + throw(e); + MT_assert(false); + } + + *result = new_f; +} + + BSP_VertexInd +BSP_MEdge:: +OpVertex( + BSP_VertexInd vi +) const { + if (vi == m_verts[0]) return m_verts[1]; + if (vi == m_verts[1]) return m_verts[0]; + MT_assert(false); + BSP_CSGException e(e_mesh_error); + throw(e); + + return BSP_VertexInd::Empty(); +} + + bool +BSP_MEdge:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +} + void +BSP_MEdge:: +SetSelectTag( + bool tag +){ + m_verts[1].SetTag(int(tag)); +} + + int +BSP_MEdge:: +OpenTag( +) const { + return m_verts[0].Tag(); +} + + void +BSP_MEdge:: +SetOpenTag( + int tag +) { + // Note conversion from int to unsigned int!!!!! + m_verts[0].SetTag(tag); +} + + +/** + * Face primitive methods + */ + + +BSP_MFace:: +BSP_MFace( +): + m_open_tag(-1), + m_orig_face(0) +{ + // nothing to do +} + + void +BSP_MFace:: +Invert( +){ + + // TODO replace reverse as I think some compilers + // do not support the STL routines employed. + + reverse( + m_verts.begin(), + m_verts.end() + ); + + // invert the normal + m_plane.Invert(); +} + + bool +BSP_MFace:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +} + + void +BSP_MFace:: +SetSelectTag( + bool tag +){ + m_verts[1].SetTag(int(tag)); +}; + + int +BSP_MFace:: +OpenTag( +) const { + return m_open_tag; +} + + void +BSP_MFace:: +SetOpenTag( + int tag +){ + // Note conversion from int to unsigned int!!!!! + m_open_tag = tag; +} + + + diff --git a/intern/bsp/intern/BSP_MeshPrimitives.h b/intern/bsp/intern/BSP_MeshPrimitives.h new file mode 100644 index 00000000000..d245ed02524 --- /dev/null +++ b/intern/bsp/intern/BSP_MeshPrimitives.h @@ -0,0 +1,279 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_BSP_MeshPrimitives +#define NAN_INCLUDED_BSP_MeshPrimitives + +#include "CTR_TaggedIndex.h" +#include "MT_Vector3.h" +#include "MT_Plane3.h" + +#include + +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_VertexInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_EdgeInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_FaceInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_FragInd; + + +typedef std::vector BSP_VertexList; +typedef std::vector BSP_EdgeList; +typedef std::vector BSP_FaceList; + +/** + * Enum representing classification of primitives + * with respect to a hyperplane. + */ + +enum BSP_Classification{ + e_unclassified = 0, + e_classified_in = 1, + e_classified_out = 2, + e_classified_on = 4, + e_classified_spanning = 7 +}; + +/** + * @section Mesh linkage + * The mesh is linked in a similar way to the decimation mesh, + * although the primitives are a little more general and not + * limited to manifold meshes. + * Vertices -> (2+)Edges + * Edges -> (1+)Polygons + * Edges -> (2)Vertices. + * Polygons -> (3+)Vertices. + * + * this structure allows for arbitrary polygons (assumed to be convex). + * Edges can point to more than 2 polygons (non-manifold) + * + * We also define 2 different link types between edges and their + * neighbouring polygons. A weak link and a strong link. + * A weak link means the polygon is in a different mesh fragment + * to the other polygon. A strong link means the polygon is in the + * same fragment. + * This is not entirely consistent as it means edges have to be associated + * with fragments, in reality only polygons will be - edges and vertices + * will live in global pools. I guess we should mark edges as being on plane + * boundaries. This leaves a problem with non-manifold edges because for example + * 3 of 4 possible edges could lie in 1 fragment and the remaining edge lie in + * another, there is no way to work out then from one polygon which neighbouring + * polygons are in the same/different mesh fragment. + * + * By definition an edge will only ever lie on 1 hyperplane. We can then just + * tag neighbouring polygons with one of 3 tags to group them. + */ + +class BSP_MVertex { +public : + MT_Point3 m_pos; + BSP_EdgeList m_edges; + + /** + * TODO + * Is this boolean necessary or can we nick a few bits of m_edges[0] + * for example? + * The only problem with this is that if the vertex is degenerate then + * m_edges[0] may not exist. If the algorithm guarentees that this is + * not the case then it should be changed. + */ + + bool m_select_tag; + int m_open_tag; + + BSP_MVertex( + ); + + BSP_MVertex( + const MT_Point3 & pos + ); + + BSP_MVertex & + operator = ( + const BSP_MVertex & other + ) { + m_pos = other.m_pos; + m_edges = other.m_edges; + m_select_tag = other.m_select_tag; + m_open_tag = other.m_open_tag; + return (*this); + }; + + bool + RemoveEdge( + BSP_EdgeInd e + ); + + void + AddEdge( + BSP_EdgeInd e + ); + + void + SwapEdge( + BSP_EdgeInd e_old, + BSP_EdgeInd e_new + ); + + /** + * These operations are ONLY valid when the + * vertex has some edges associated with it. + * This is left to the user to guarentee. + * Also note that these tag's are not guarenteed + * to survive after a call to RemoveEdge(), + * because we use edges for the open tag. + */ + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ); + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); +}; + +class BSP_MEdge { +public : + BSP_VertexInd m_verts[2]; + BSP_FaceList m_faces; + + BSP_MEdge( + ); + + bool operator == ( + BSP_MEdge & rhs + ); + + void + SwapFace( + BSP_FaceInd old_f, + BSP_FaceInd new_f + ); + + BSP_VertexInd + OpVertex( + BSP_VertexInd vi + ) const; + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + /** + * We use one of the vertex indices for tag informtaion. + * This means these tags will not survive if you change + * the vertex indices. + */ + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ) ; +}; + +class BSP_MFace { +public : + + BSP_VertexList m_verts; + + // We also store the plane equation of this + // face. Generating on the fly during tree + // construction can lead to a lot of numerical errors. + // because the polygon size can get very small. + + MT_Plane3 m_plane; + + int m_open_tag; + unsigned int m_orig_face; + + BSP_MFace( + ); + + // Invert the face , done by reversing the vertex order + // and inverting the face normal. + + void + Invert( + ); + + /** + * Tagging + * We use the tag from m_verts[1] for the select tag + * and the the tag from m_verts[0] for the open tag. + * There is always a chance that the polygon contains + * no vertices but this should be checked at construction + * time. + * Also note that changing the vertex indices of this polygon + * will likely remove tagging information. + * + */ + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ) ; + +}; + +#endif + diff --git a/intern/bsp/intern/CSG_BooleanOps.cpp b/intern/bsp/intern/CSG_BooleanOps.cpp new file mode 100644 index 00000000000..c6f4c5d34d0 --- /dev/null +++ b/intern/bsp/intern/CSG_BooleanOps.cpp @@ -0,0 +1,183 @@ +/** + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * Implementation of external api for CSG part of BSP lib interface. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "../extern/CSG_BooleanOps.h" +#include "BSP_CSGMesh_CFIterator.h" +#include "MEM_RefCountPtr.h" + +#include "../../boolop/extern/BOP_Interface.h" +#include +using namespace std; + +#include "BSP_MeshPrimitives.h" + +struct BSP_MeshInfo { + BSP_CSGMesh *output_mesh; +}; + +using namespace std; + + CSG_BooleanOperation * +CSG_NewBooleanFunction( + void +){ + BSP_MeshInfo * mesh_info = new BSP_MeshInfo; + CSG_BooleanOperation * output = new CSG_BooleanOperation; + + if (mesh_info==NULL || output==NULL) return NULL; + + mesh_info->output_mesh = NULL; + output->CSG_info = mesh_info; + + return output; +} + +/** + * Compute the boolean operation, UNION, INTERSECION or DIFFERENCE + */ + int +CSG_PerformBooleanOperation( + CSG_BooleanOperation *operation, + CSG_OperationType op_type, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices +){ + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast(operation->CSG_info); + if (mesh_info == NULL) return 0; + + obAFaces.Reset(obAFaces.it); + obBFaces.Reset(obBFaces.it); + obAVertices.Reset(obAVertices.it); + obBVertices.Reset(obBVertices.it); + + BoolOpType boolType; + + switch( op_type ) { + case e_csg_union: + boolType = BOP_UNION; + break; + case e_csg_difference: + boolType = BOP_DIFFERENCE; + break; + default: + boolType = BOP_INTERSECTION; + break; + } + + BoolOpState boolOpResult; + try { + boolOpResult = BOP_performBooleanOperation( boolType, + (BSP_CSGMesh**) &(mesh_info->output_mesh), + obAFaces, obAVertices, obBFaces, obBVertices); + } + catch(...) { + return 0; + } + + switch (boolOpResult) { + case BOP_OK: return 1; + case BOP_NO_SOLID: return -2; + case BOP_ERROR: return 0; + default: return 1; + } +} + + int +CSG_OutputFaceDescriptor( + CSG_BooleanOperation * operation, + CSG_FaceIteratorDescriptor * output +){ + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast(operation->CSG_info); + + if (mesh_info == NULL) return 0; + if (mesh_info->output_mesh == NULL) return 0; + + BSP_CSGMesh_FaceIt_Construct(mesh_info->output_mesh,output); + return 1; +} + + + int +CSG_OutputVertexDescriptor( + CSG_BooleanOperation * operation, + CSG_VertexIteratorDescriptor *output +){ + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast(operation->CSG_info); + + if (mesh_info == NULL) return 0; + if (mesh_info->output_mesh == NULL) return 0; + + BSP_CSGMeshVertexIt_Construct(mesh_info->output_mesh,output); + return 1; +} + + void +CSG_FreeVertexDescriptor( + CSG_VertexIteratorDescriptor * v_descriptor +){ + BSP_CSGMesh_VertexIt_Destruct(v_descriptor); +} + + + void +CSG_FreeFaceDescriptor( + CSG_FaceIteratorDescriptor * f_descriptor +){ + BSP_CSGMesh_FaceIt_Destruct(f_descriptor); +} + + + void +CSG_FreeBooleanOperation( + CSG_BooleanOperation *operation +){ + if (operation != NULL) { + BSP_MeshInfo * mesh_info = static_cast(operation->CSG_info); + + delete (mesh_info->output_mesh); + delete(mesh_info); + delete(operation); + } +} + diff --git a/intern/bsp/intern/Makefile b/intern/bsp/intern/Makefile new file mode 100644 index 00000000000..a5e8565a6ff --- /dev/null +++ b/intern/bsp/intern/Makefile @@ -0,0 +1,48 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# string intern Makefile +# + +LIBNAME = bsp +DIR = $(OCGDIR)/intern/$(LIBNAME) +DIRS = common + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../extern +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include +CPPFLAGS += -Icommon + + diff --git a/intern/bsp/make/msvc6_0/bsplib.dsp b/intern/bsp/make/msvc6_0/bsplib.dsp new file mode 100644 index 00000000000..00bac967221 --- /dev/null +++ b/intern/bsp/make/msvc6_0/bsplib.dsp @@ -0,0 +1,138 @@ +# Microsoft Developer Studio Project File - Name="bsplib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=bsplib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bsplib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bsplib.mak" CFG="bsplib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bsplib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "bsplib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bsplib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\bsp\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\bsp\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /I "../../../../../lib/windows/memutil/include" /I "../.." /I "../../../../../lib/windows/moto/include" /I "../../../../../lib/windows/container/include" /I "..\..\..\container" /I "..\..\..\moto\include" /I "..\..\..\memutil" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\bsp\libbsp.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\bsp\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\bsp\*.lib ..\..\..\..\..\lib\windows\bsp\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "bsplib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\bsp\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\bsp\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../../../../lib/windows/memutil" /I "../.." /I "../../../../../lib/windows/moto/include" /I "../../../../../lib/windows/container/include" /I "../../../../../lib/windows/memutil/include" /I "..\..\..\container" /I "..\..\..\moto\include" /I "..\..\..\memutil" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\bsp\debug\libbsp.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\bsp\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\bsp\debug\*.lib ..\..\..\..\..\lib\windows\bsp\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\bsp\debug\vc60.* ..\..\..\..\..\lib\windows\bsp\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "bsplib - Win32 Release" +# Name "bsplib - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGException.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGISplitter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh_CFIterator.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_MeshPrimitives.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_MeshPrimitives.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\CSG_BooleanOps.cpp +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\extern\CSG_BooleanOps.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/bsp/make/msvc6_0/bsplib.dsw b/intern/bsp/make/msvc6_0/bsplib.dsw new file mode 100644 index 00000000000..1827dc3746e --- /dev/null +++ b/intern/bsp/make/msvc6_0/bsplib.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bsplib"=.\bsplib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bsp/make/msvc_7_0/bsplib.sln b/intern/bsp/make/msvc_7_0/bsplib.sln new file mode 100644 index 00000000000..e8c116b639e --- /dev/null +++ b/intern/bsp/make/msvc_7_0/bsplib.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bsplib", "bsplib.vcproj", "{20F0EE62-A21A-46B7-B425-7923F4674B4F}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {20F0EE62-A21A-46B7-B425-7923F4674B4F}.Debug.ActiveCfg = Debug|Win32 + {20F0EE62-A21A-46B7-B425-7923F4674B4F}.Debug.Build.0 = Debug|Win32 + {20F0EE62-A21A-46B7-B425-7923F4674B4F}.Release.ActiveCfg = Release|Win32 + {20F0EE62-A21A-46B7-B425-7923F4674B4F}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/bsp/make/msvc_7_0/bsplib.vcproj b/intern/bsp/make/msvc_7_0/bsplib.vcproj new file mode 100644 index 00000000000..59fb9f3691d --- /dev/null +++ b/intern/bsp/make/msvc_7_0/bsplib.vcproj @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp new file mode 100644 index 00000000000..aaa45273845 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp @@ -0,0 +1,126 @@ +# Microsoft Developer Studio Project File - Name="BSP_GhostTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=BSP_GhostTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BSP_GhostTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BSP_GhostTest.mak" CFG="BSP_GhostTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BSP_GhostTest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "BSP_GhostTest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BSP_GhostTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /Ob2 /I "../../extern/" /I "../../../../lib/windows/string/include" /I "../../../../lib/windows/ghost/include" /I "../../../../lib/windows/moto/include" /I "../../../../lib/windows/memutil/include" /I "../../../../lib/windows/container/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\lib\windows\glut-3.7\lib\\" + +!ELSEIF "$(CFG)" == "BSP_GhostTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../extern/" /I "../../../../lib/windows/string/include" /I "../../../../lib/windows/ghost/include" /I "../../../../lib/windows/moto/include" /I "../../../../lib/windows/memutil/include" /I "../../../../lib/windows/container/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\lib\windows\glut-3.7\lib\\" + +!ENDIF + +# Begin Target + +# Name "BSP_GhostTest - Win32 Release" +# Name "BSP_GhostTest - Win32 Debug" +# Begin Source File + +SOURCE=.\BSP_GhostTest3D.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_GhostTest3D.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_MeshDrawer.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_MeshDrawer.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_PlyLoader.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_PlyLoader.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_TMesh.h +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\ply.h +# End Source File +# Begin Source File + +SOURCE=.\plyfile.c +# End Source File +# End Target +# End Project diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw new file mode 100644 index 00000000000..802fba84bef --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw @@ -0,0 +1,125 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BSP_GhostTest"=.\BSP_GhostTest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bsplib + End Project Dependency + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency +}}} + +############################################################################### + +Project: "MoTo"=..\..\..\moto\make\msvc_6_0\MoTo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bsplib"=..\..\make\msvc6_0\bsplib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name container + End Project Dependency + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency +}}} + +############################################################################### + +Project: "container"=..\..\..\container\make\msvc_6_0\container.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency +}}} + +############################################################################### + +Project: "ghost"=..\..\..\ghost\make\msvc\ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "memutil"=..\..\..\memutil\make\msvc_60\memutil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "string"=..\..\..\string\make\msvc_6_0\string.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp new file mode 100644 index 00000000000..ec34b104e4a --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp @@ -0,0 +1,658 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + +* $Id$ +* Copyright (C) 2001 NaN Technologies B.V. +*/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) || defined(__APPLE__) +# ifdef WIN32 +# include +# include +# include +# else // WIN32 +# include +# endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) +# include +# include +#endif // defined(WIN32) || defined(__APPLE__) + + +#include "BSP_GhostTest3D.h" +#include "BSP_MeshDrawer.h" + +#include "GHOST_ISystem.h" +#include "GHOST_IWindow.h" + +#include "MT_Quaternion.h" +#include "MT_Transform.h" +#include "CSG_BooleanOps.h" + +#include + + int +EmptyInterpFunc( + void *d1, + void * d2, + void *dnew, + float epsilon +){ + return 0; +} + + + +using namespace std; + + +BSP_GhostTestApp3D:: +BSP_GhostTestApp3D( +) : + m_window(NULL), + m_system(NULL), + m_finish_me_off(false), + m_current_object(0) +{ + //nothing to do; +} + + void +BSP_GhostTestApp3D:: +SetMesh( + MEM_SmartPtr mesh +){ + m_meshes.push_back(mesh); + + BSP_RotationSetting rotation_setting; + BSP_TranslationSetting translation_setting; + + rotation_setting.m_angle_x = MT_Scalar(0); + rotation_setting.m_angle_y = MT_Scalar(0); + rotation_setting.m_moving = false; + rotation_setting.x_old = 0; + rotation_setting.y_old = 0; + + translation_setting.m_t_x = MT_Scalar(0); + translation_setting.m_t_y = MT_Scalar(0); + translation_setting.m_t_z = MT_Scalar(0); + translation_setting.m_moving = false; + translation_setting.x_old = 0; + translation_setting.y_old = 0; + + m_rotation_settings.push_back(rotation_setting); + m_translation_settings.push_back(translation_setting); + m_render_modes.push_back(e_wireframe_shaded); + m_scale_settings.push_back(MT_Scalar(1)); + +} + + void +BSP_GhostTestApp3D:: +Swap( + int i +){ + + if (!m_rotation_settings[i].m_moving && !m_translation_settings[i].m_moving) { + swap(m_meshes[i],m_meshes.back()); + swap(m_rotation_settings[i],m_rotation_settings.back()); + swap(m_translation_settings[i],m_translation_settings.back()); + swap(m_scale_settings[i],m_scale_settings.back()); + swap(m_render_modes[i],m_render_modes.back()); + } +} + + + MT_Transform +BSP_GhostTestApp3D:: +GetTransform( + int i +){ + + MT_Quaternion q_ax(MT_Vector3(0,1,0),m_rotation_settings[i].m_angle_x); + MT_Quaternion q_ay(MT_Vector3(1,0,0),m_rotation_settings[i].m_angle_y); + + MT_Point3 tr( + m_translation_settings[i].m_t_x, + m_translation_settings[i].m_t_y, + m_translation_settings[i].m_t_z + ); + + + MT_Matrix3x3 rotx(q_ax); + MT_Matrix3x3 roty(q_ay); + + MT_Matrix3x3 rot = rotx * roty; + + MT_Transform trans(tr,rot); + + MT_Transform scalet; + scalet.setIdentity(); + scalet.scale(m_scale_settings[i],m_scale_settings[i],m_scale_settings[i]); + + return trans * scalet; +} + + void +BSP_GhostTestApp3D:: +Operate( + int type +){ + + CSG_VertexIteratorDescriptor * vA = VertexIt_Construct(m_meshes[0],GetTransform(0)); + CSG_FaceIteratorDescriptor * fA = FaceIt_Construct(m_meshes[0]); + + CSG_VertexIteratorDescriptor * vB = VertexIt_Construct(m_meshes[1],GetTransform(1)); + CSG_FaceIteratorDescriptor * fB = FaceIt_Construct(m_meshes[1]); + + // describe properties. + + CSG_MeshPropertyDescriptor props; + props.user_face_vertex_data_size = 0; + props.user_data_size = 0; + + CSG_BooleanOperation * op = CSG_NewBooleanFunction(); + props = CSG_DescibeOperands(op,props,props); + + CSG_PerformBooleanOperation( + op,CSG_OperationType(type), + *fA,*vA,*fB,*vB,EmptyInterpFunc + ); + + CSG_FaceIteratorDescriptor out_f; + CSG_OutputFaceDescriptor(op,&out_f); + + CSG_VertexIteratorDescriptor out_v; + CSG_OutputVertexDescriptor(op,&out_v); + + MEM_SmartPtr new_mesh (BuildMesh(props,out_f,out_v)); + + // free stuff + + CSG_FreeVertexDescriptor(&out_v); + CSG_FreeFaceDescriptor(&out_f); + CSG_FreeBooleanOperation(op); + + op = NULL; + SetMesh(new_mesh); +} + + + void +BSP_GhostTestApp3D:: +UpdateFrame( +){ +if (m_window) { + + GHOST_Rect v_rect; + m_window->getClientBounds(v_rect); + + glViewport(0,0,v_rect.getWidth(),v_rect.getHeight()); + +} +} + + +MT_Vector3 +BSP_GhostTestApp3D:: +UnProject( + const MT_Vector3 & vec +) { + + GLint viewport[4]; + GLdouble mvmatrix[16],projmatrix[16]; + + glGetIntegerv(GL_VIEWPORT,viewport); + glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX,projmatrix); + + GLdouble realy = viewport[3] - vec.y() - 1; + GLdouble outx,outy,outz; + + gluUnProject(vec.x(),realy,vec.z(),mvmatrix,projmatrix,viewport,&outx,&outy,&outz); + + return MT_Vector3(outx,outy,outz); +} + + + bool +BSP_GhostTestApp3D:: +InitApp( +){ + + // create a system and window with opengl + // rendering context. + + GHOST_TSuccess success = GHOST_ISystem::createSystem(); + if (success == GHOST_kFailure) return false; + + m_system = GHOST_ISystem::getSystem(); + if (m_system == NULL) return false; + + m_system->addEventConsumer(this); + + m_window = m_system->createWindow( + "GHOST crud3D!", + 100,100,512,512,GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL,false + ); + + if ( + m_window == NULL + ) { + m_system = NULL; + GHOST_ISystem::disposeSystem(); + return false; + } + + // make an opengl frustum for this wind + + MT_Vector3 min,max; + + min = m_meshes[0]->m_min; + max = m_meshes[0]->m_max; + InitOpenGl(min,max); + + return true; +} + + void +BSP_GhostTestApp3D:: +Run( +){ + if (m_system == NULL) { + return; + } + + while (!m_finish_me_off) { + m_system->processEvents(true); + m_system->dispatchEvents(); + }; +} + + bool +BSP_GhostTestApp3D:: +processEvent( + GHOST_IEvent* event +){ + + bool handled = false; + + switch(event->getType()) { + case GHOST_kEventWindowSize: + case GHOST_kEventWindowActivate: + UpdateFrame(); + case GHOST_kEventWindowUpdate: + DrawPolies(); + handled = true; + break; + case GHOST_kEventButtonDown: + { + int x,y; + m_system->getCursorPosition(x,y); + + + int wx,wy; + m_window->screenToClient(x,y,wx,wy); + + GHOST_TButtonMask button = + static_cast(event->getData())->button; + + if (button == GHOST_kButtonMaskLeft) { + m_rotation_settings[m_current_object].m_moving = true; + m_rotation_settings[m_current_object].x_old = x; + m_rotation_settings[m_current_object].y_old = y; + } else + if (button == GHOST_kButtonMaskRight) { + m_translation_settings[m_current_object].m_moving = true; + m_translation_settings[m_current_object].x_old = x; + m_translation_settings[m_current_object].y_old = y; + } else + + m_window->invalidate(); + handled = true; + break; + + } + + case GHOST_kEventButtonUp: + { + + GHOST_TButtonMask button = + static_cast(event->getData())->button; + + if (button == GHOST_kButtonMaskLeft) { + m_rotation_settings[m_current_object].m_moving = false; + m_rotation_settings[m_current_object].x_old = 0; + m_rotation_settings[m_current_object].y_old = 0; + + } else + if (button == GHOST_kButtonMaskRight) { + m_translation_settings[m_current_object].m_moving = false; + m_translation_settings[m_current_object].x_old; + m_translation_settings[m_current_object].y_old; + + } + m_window->invalidate(); + handled = true; + break; + + } + + case GHOST_kEventCursorMove: + { + int x,y; + m_system->getCursorPosition(x,y); + int wx,wy; + m_window->screenToClient(x,y,wx,wy); + + if (m_rotation_settings[m_current_object].m_moving) { + m_rotation_settings[m_current_object].m_angle_x = MT_Scalar(wx)/20; + m_rotation_settings[m_current_object].x_old = wx; + m_rotation_settings[m_current_object].m_angle_y = MT_Scalar(wy)/20; + m_rotation_settings[m_current_object].y_old = wy; + + m_window->invalidate(); + } + if (m_translation_settings[m_current_object].m_moving) { + + // project current objects bounding box center into screen space. + // unproject mouse point into object space using z-value from + // projected bounding box center. + + GHOST_Rect bounds; + m_window->getClientBounds(bounds); + + int w_h = bounds.getHeight(); + + y = w_h - wy; + x = wx; + + double mvmatrix[16]; + double projmatrix[16]; + GLint viewport[4]; + + double px, py, pz,sz; + + /* Get the matrices needed for gluUnProject */ + glGetIntegerv(GL_VIEWPORT, viewport); + glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); + + // work out the position of the end effector in screen space + + GLdouble ex,ey,ez; + + ex = m_translation_settings[m_current_object].m_t_x; + ey = m_translation_settings[m_current_object].m_t_y; + ez = m_translation_settings[m_current_object].m_t_z; + + gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz); + gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz); + + m_translation_settings[m_current_object].m_t_x = px; + m_translation_settings[m_current_object].m_t_y = py; + m_translation_settings[m_current_object].m_t_z = pz; + m_window->invalidate(); + + } + + handled = true; + break; + } + + case GHOST_kEventKeyDown : + { + GHOST_TEventKeyData *kd = + static_cast(event->getData()); + + + switch(kd->key) { + case GHOST_kKeyI: + { + // now intersect meshes. + Operate(e_csg_intersection); + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyU: + { + Operate(e_csg_union); + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyD: + { + Operate(e_csg_difference); + handled = true; + m_window->invalidate(); + break; + } + + case GHOST_kKeyA: + { + + m_scale_settings[m_current_object] *= 1.1; + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyZ: + { + m_scale_settings[m_current_object] *= 0.8; + + handled = true; + m_window->invalidate(); + break; + } + + case GHOST_kKeyR: + m_render_modes[m_current_object]++; + if (m_render_modes[m_current_object] > e_last_render_mode) { + m_render_modes[m_current_object] = e_first_render_mode; + } + handled = true; + m_window->invalidate(); + break; + + case GHOST_kKeyB: + handled = true; + m_window->invalidate(); + break; + + case GHOST_kKeyQ: + m_finish_me_off = true; + handled = true; + break; + + case GHOST_kKeyS: + Swap(m_current_object); + m_window->invalidate(); + handled = true; + break; + + case GHOST_kKeySpace: + + // increment the current object only if the object is not being + // manipulated. + if (! (m_rotation_settings[m_current_object].m_moving || m_translation_settings[m_current_object].m_moving)) { + m_current_object ++; + if (m_current_object >= m_meshes.size()) { + m_current_object = 0; + + } + } + m_window->invalidate(); + handled = true; + break; + default : + break; + } + } + + default : + break; + } + return handled; +}; + +BSP_GhostTestApp3D:: +~BSP_GhostTestApp3D( +){ + + if (m_window) { + m_system->disposeWindow(m_window); + m_window = NULL; + GHOST_ISystem::disposeSystem(); + m_system = NULL; + } +}; + + + + void +BSP_GhostTestApp3D:: +DrawPolies( +){ + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + for (int i = 0; i < m_meshes.size(); ++i) { + MT_Transform trans = GetTransform(i); + + float opengl_mat[16]; + trans.getValue(opengl_mat); + + glPushMatrix(); + glMultMatrixf(opengl_mat); + MT_Vector3 color(1.0,1.0,1.0); + if (i == m_current_object) { + color = MT_Vector3(1.0,0,0); + } + BSP_MeshDrawer::DrawMesh(m_meshes[i].Ref(),m_render_modes[i]); + + glPopMatrix(); + } + + m_window->swapBuffers(); + +} + + void +BSP_GhostTestApp3D:: +InitOpenGl( + const MT_Vector3 &min, + const MT_Vector3 &max +){ + + GLfloat light_diffuse0[] = {1.0, 0.0, 0.0, 0.5}; /* Red diffuse light. */ + GLfloat light_position0[] = {1.0, 1.0, 1.0, 0.0}; /* Infinite light location. */ + + GLfloat light_diffuse1[] = {1.0, 1.0, 1.0, 0.5}; /* Red diffuse light. */ + GLfloat light_position1[] = {1.0, 0, 0, 0.0}; /* Infinite light location. */ + + /* Enable a single OpenGL light. */ + + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0); + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + + + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + + // make sure there is no back face culling. + // glDisable(GL_CULL_FACE); + + // use two sided lighting model + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); + + /* Use depth buffering for hidden surface elimination. */ + + glEnable(GL_DEPTH_TEST); + + /* Setup the view of the cube. */ + + glMatrixMode(GL_PROJECTION); + + // center of the box + 3* depth of box + + MT_Vector3 center = (min + max) * 0.5; + MT_Vector3 diag = max - min; + + float depth = diag.length(); + float distance = 5; + + gluPerspective( + /* field of view in degree */ 40.0, + /* aspect ratio */ 1.0, + /* Z near */ 1.0, + /* Z far */ distance * depth * 2 + ); + glMatrixMode(GL_MODELVIEW); + + gluLookAt( + center.x(), center.y(), center.z() + distance*depth, //eye + center.x(), center.y(), center.z(), //center + 0.0, 1.0, 0. + ); /* up is in positive Y direction */ + +} + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h new file mode 100644 index 00000000000..042c73174a6 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h @@ -0,0 +1,163 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_GhostTest_h +#define BSP_GhostTest_h + +#include "GHOST_IEventConsumer.h" +#include "MT_Vector3.h" +#include "BSP_TMesh.h" +#include "BSP_MeshDrawer.h" + +#include + +class GHOST_IWindow; +class GHOST_ISystem; + + +class BSP_GhostTestApp3D : +public GHOST_IEventConsumer +{ +public : + // Construct an instance of the application; + + BSP_GhostTestApp3D( + ); + + // initialize the applicaton + + bool + InitApp( + ); + + // Run the application untill internal return. + void + Run( + ); + + ~BSP_GhostTestApp3D( + ); + + void + SetMesh( + MEM_SmartPtr mesh + ); + +private : + + struct BSP_RotationSetting { + MT_Scalar m_angle_x; + MT_Scalar m_angle_y; + int x_old; + int y_old; + bool m_moving; + }; + + struct BSP_TranslationSetting { + MT_Scalar m_t_x; + MT_Scalar m_t_y; + MT_Scalar m_t_z; + int x_old; + int y_old; + bool m_moving; + }; + + // Return the transform of object i + + MT_Transform + GetTransform( + int active_object + ); + + // Perform an operation between the first two objects in the + // list + + void + Operate( + int type + ); + + // Swap mesh i and settings with the last mesh in list. + + void + Swap( + int i + ); + + void + DrawPolies( + ); + + void + UpdateFrame( + ); + + MT_Vector3 + UnProject( + const MT_Vector3 & vec + ); + + // Create a frustum and projection matrix to + // look at the bounding box + + void + InitOpenGl( + const MT_Vector3 &min, + const MT_Vector3 &max + ); + + + // inherited from GHOST_IEventConsumer + bool + processEvent( + GHOST_IEvent* event + ); + + GHOST_IWindow *m_window; + GHOST_ISystem *m_system; + + bool m_finish_me_off; + + // List of current meshes. + std::vector< MEM_SmartPtr > m_meshes; + + std::vector< BSP_RotationSetting> m_rotation_settings; + std::vector< BSP_TranslationSetting> m_translation_settings; + std::vector< MT_Scalar> m_scale_settings; + std::vector< int> m_render_modes; + + int m_current_object; + + +}; + +#endif + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp new file mode 100644 index 00000000000..4f5f5d46535 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp @@ -0,0 +1,164 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BSP_MeshDrawer.h" + +#include "BSP_TMesh.h" + +#if defined(WIN32) || defined(__APPLE__) +# ifdef WIN32 +# include +# include +# include +# else // WIN32 +# include +# endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) +# include +# include +#endif // defined(WIN32) || defined(__APPLE__) + +#include + +using namespace std; + + void +BSP_MeshDrawer:: +DrawMesh( + BSP_TMesh &mesh, + int render_mode +){ + + + if (render_mode == e_none) return; + + // decompose polygons into triangles. + + glEnable(GL_LIGHTING); + + + if (render_mode == e_wireframe || render_mode == e_wireframe_shaded) { + + glColor3f(0.0, 0.0, 0.0); + + if (render_mode == e_wireframe) { + glDisable(GL_LIGHTING); + } else { + glEnable(GL_LIGHTING); + } + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.0,1.0); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + + glColor3f(1.0, 1.0, 1.0); + glDisable(GL_LIGHTING); + glDisable(GL_POLYGON_OFFSET_FILL); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } else { + + glEnable(GL_LIGHTING); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + } + + +} + + + void +BSP_MeshDrawer:: +DrawPolies( + BSP_TMesh &mesh +){ + + const vector & verts = mesh.VertexSet(); + const vector &faces = mesh.FaceSet(); + + // just draw the edges for now. + + vector::const_iterator vertex_it = verts.begin(); + + + vector::const_iterator faces_it = faces.begin(); + vector::const_iterator faces_end = faces.end(); + + for (;faces_it != faces_end; ++faces_it ){ + + glNormal3f( + faces_it->m_normal.x(), + faces_it->m_normal.y(), + faces_it->m_normal.z() + ); + + glVertex3f( + verts[faces_it->m_verts[0]].m_pos.x(), + verts[faces_it->m_verts[0]].m_pos.y(), + verts[faces_it->m_verts[0]].m_pos.z() + ); + glVertex3f( + verts[faces_it->m_verts[1]].m_pos.x(), + verts[faces_it->m_verts[1]].m_pos.y(), + verts[faces_it->m_verts[1]].m_pos.z() + ); + glVertex3f( + verts[faces_it->m_verts[2]].m_pos.x(), + verts[faces_it->m_verts[2]].m_pos.y(), + verts[faces_it->m_verts[2]].m_pos.z() + ); + } +} + + + + + + + + + + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h new file mode 100644 index 00000000000..314b9691137 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h @@ -0,0 +1,75 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_MeshDrawer_h +#define BSP_MeshDrawer_h + +class BSP_TMesh; +class MT_Vector3; + +enum BSP_TRenderMode { + e_shaded, + e_none, + e_wireframe, + e_wireframe_shaded, + e_first_render_mode = e_shaded, + e_last_render_mode = e_wireframe_shaded +}; + +class BSP_MeshDrawer +{ +public : + static + void + DrawMesh( + BSP_TMesh &mesh, + int render_mode + ); + +private : + + static + void + DrawPolies( + BSP_TMesh &mesh + ); + + + BSP_MeshDrawer( + ); + + ~BSP_MeshDrawer( + ); + +}; + +#endif + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp new file mode 100644 index 00000000000..f148250f1aa --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp @@ -0,0 +1,200 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BSP_PlyLoader.h" + +#include "MT_Vector3.h" +#include "ply.h" + +struct LoadVertex { + float x,y,z; /* the usual 3-space position of a vertex */ +}; + +struct LoadFace { + unsigned char intensity; /* this user attaches intensity to faces */ + unsigned char nverts; /* number of vertex indices in list */ + int *verts; /* vertex index list */ +}; + + + MEM_SmartPtr +BSP_PlyLoader:: +NewMeshFromFile( + char * file_name, + MT_Vector3 &min, + MT_Vector3 &max + +) { + + min = MT_Vector3(MT_INFINITY,MT_INFINITY,MT_INFINITY); + max = MT_Vector3(-MT_INFINITY,-MT_INFINITY,-MT_INFINITY); + + PlyProperty vert_props[] = { /* list of property information for a vertex */ + {"x", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,x), 0, 0, 0, 0}, + {"y", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,y), 0, 0, 0, 0}, + {"z", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,z), 0, 0, 0, 0}, + }; + + PlyProperty face_props[] = { /* list of property information for a vertex */ + {"vertex_indices", PLY_INT, PLY_INT, offsetof(LoadFace,verts), + 1, PLY_UCHAR, PLY_UCHAR, offsetof(LoadFace,nverts)}, + }; + + MEM_SmartPtr mesh = new BSP_TMesh; + + if (mesh == NULL) return NULL; + + int i,j; + PlyFile *ply; + int nelems; + char **elist; + int file_type; + float version; + int nprops; + int num_elems; + PlyProperty **plist; + + char *elem_name; + + LoadVertex load_vertex; + LoadFace load_face; + + /* open a PLY file for reading */ + ply = ply_open_for_reading( + file_name, + &nelems, + &elist, + &file_type, + &version + ); + + if (ply == NULL) return NULL; + + /* go through each kind of element that we learned is in the file */ + /* and read them */ + + for (i = 0; i < nelems; i++) { + + /* get the description of the first element */ + + elem_name = elist[i]; + plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops); + + /* print the name of the element, for debugging */ + + /* if we're on vertex elements, read them in */ + + if (equal_strings ("vertex", elem_name)) { + + /* set up for getting vertex elements */ + + ply_get_property (ply, elem_name, &vert_props[0]); + ply_get_property (ply, elem_name, &vert_props[1]); + ply_get_property (ply, elem_name, &vert_props[2]); + + // make some memory for the vertices + mesh->VertexSet().reserve(num_elems); + + /* grab all the vertex elements */ + for (j = 0; j < num_elems; j++) { + + /* grab and element from the file */ + ply_get_element (ply, (void *)&load_vertex); + // pass the vertex into the mesh builder. + + if (load_vertex.x < min.x()) { + min.x() = load_vertex.x; + } else + if (load_vertex.x > max.x()) { + max.x()= load_vertex.x; + } + + if (load_vertex.y < min.y()) { + min.y() = load_vertex.y; + } else + if (load_vertex.y > max.y()) { + max.y()= load_vertex.y; + } + + if (load_vertex.z < min.z()) { + min.z() = load_vertex.z; + } else + if (load_vertex.z > max.z()) { + max.z()= load_vertex.z; + } + + BSP_TVertex my_vert; + my_vert.m_pos = MT_Vector3(load_vertex.x,load_vertex.y,load_vertex.z); + mesh->VertexSet().push_back(my_vert); + } + + + } + + /* if we're on face elements, read them in */ + if (equal_strings ("face", elem_name)) { + + /* set up for getting face elements */ + + ply_get_property (ply, elem_name, &face_props[0]); + + /* grab all the face elements */ + for (j = 0; j < num_elems; j++) { + + ply_get_element (ply, (void *)&load_face); + + int v; + for (v = 2; v< load_face.nverts; v++) { + + BSP_TFace f; + + f.m_verts[0] = load_face.verts[0]; + f.m_verts[1] = load_face.verts[v-1]; + f.m_verts[2] = load_face.verts[v]; + + mesh->BuildNormal(f); + mesh->FaceSet().push_back(f); + } + // free up the memory this pile of shit used to allocate the polygon's vertices + free (load_face.verts); + } + + } + } + /* close the PLY file */ + ply_close (ply); + + return mesh; +} diff --git a/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h new file mode 100644 index 00000000000..d2e9b8cd2cc --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h @@ -0,0 +1,64 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_PlyLoader_h +#define BSP_PlyLoader_h + +#include "MEM_SmartPtr.h" +#include "BSP_TMesh.h" + +class BSP_PlyLoader { +public : + + static + MEM_SmartPtr + NewMeshFromFile( + char * file_name, + MT_Vector3 &min, + MT_Vector3 &max + ); + + +private : + + // unimplemented - not for instantiation. + + BSP_PlyLoader( + ); + + ~BSP_PlyLoader( + ); +}; + + + +#endif + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h b/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h new file mode 100644 index 00000000000..eeb4df3d0d9 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h @@ -0,0 +1,401 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef BSP_TMesh_h +#define BSP_TMesh_h + +#include "MT_Point3.h" +#include "MT_Vector3.h" +#include "MT_Transform.h" + +#include "MEM_SmartPtr.h" + +#include + +#include "CSG_BooleanOps.h" + +/** + * A very basic test mesh. + */ + +struct BSP_TVertex { + MT_Point3 m_pos; +}; + +struct BSP_TFace { + int m_verts[3]; + MT_Vector3 m_normal; +}; + + +class BSP_TMesh { +public : + + std::vector m_verts; + std::vector m_faces; + + MT_Vector3 m_min,m_max; + + std::vector & + VertexSet( + ){ + return m_verts; + } + + std::vector & + FaceSet( + ) { + return m_faces; + } + + void + AddFace( + int *verts, + int num_verts + ){ + int i; + for (i= 2; i it)); + iterator->it = NULL; + delete(iterator); +}; + + +static + int +VertexIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + if (vertex_it->pos < vertex_it->mesh->VertexSet().end()) return 0; + return 1; +}; + +static + void +VertexIt_Fill( + CSG_IteratorPtr it, + CSG_IVertex *vert +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + MT_Point3 p = vertex_it->pos->m_pos; + p = vertex_it->trans * p; + + p.getValue(vert->position); +}; + +static + void +VertexIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + ++(vertex_it->pos); +}; + +static + void +VertexIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + vertex_it->pos = vertex_it->mesh->VertexSet().begin(); +}; + +static + CSG_VertexIteratorDescriptor * +VertexIt_Construct( + BSP_TMesh *mesh, + MT_Transform trans +){ + // user should have insured mesh is not equal to NULL. + + CSG_VertexIteratorDescriptor * output = new CSG_VertexIteratorDescriptor; + if (output == NULL) return NULL; + output->Done = VertexIt_Done; + output->Fill = VertexIt_Fill; + output->Step = VertexIt_Step; + output->Reset = VertexIt_Reset; + output->num_elements = mesh->VertexSet().size(); + + VertexIt * v_it = new VertexIt; + v_it->mesh = mesh; + v_it->pos = mesh->VertexSet().begin(); + v_it->trans = trans; + output->it = v_it; + return output; +}; + + +/** + * Face iterator. + */ + +struct FaceIt { + BSP_TMesh * mesh; + BSP_TFace *pos; +}; + + +static + void +FaceIt_Destruct( + CSG_FaceIteratorDescriptor * iterator +) { + delete ((FaceIt *)(iterator->it)); + iterator->it = NULL; + delete(iterator); +}; + + +static + int +FaceIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + + if (face_it->pos < face_it->mesh->FaceSet().end()) { + return 0; + } + return 1; +}; + +static + void +FaceIt_Fill( + CSG_IteratorPtr it, + CSG_IFace *face +){ + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + // essentially iterating through a triangle fan here. + + face->vertex_index[0] = int(face_it->pos->m_verts[0]); + face->vertex_index[1] = int(face_it->pos->m_verts[1]); + face->vertex_index[2] = int(face_it->pos->m_verts[2]); + + face->vertex_number = 3; +}; + +static + void +FaceIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + + face_it->pos ++; +}; + +static + void +FaceIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + + face_it->pos = face_it->mesh->FaceSet().begin(); +}; + +static + CSG_FaceIteratorDescriptor * +FaceIt_Construct( + BSP_TMesh * mesh +) { + CSG_FaceIteratorDescriptor * output = new CSG_FaceIteratorDescriptor; + if (output == NULL) return NULL; + + output->Done = FaceIt_Done; + output->Fill = FaceIt_Fill; + output->Step = FaceIt_Step; + output->Reset = FaceIt_Reset; + + output->num_elements = mesh->FaceSet().size(); + + FaceIt * f_it = new FaceIt; + f_it->mesh = mesh; + f_it->pos = mesh->FaceSet().begin(); + + output->it = f_it; + + return output; +}; + +/** + * Some Build functions. + */ + +static + MEM_SmartPtr +BuildMesh( + CSG_MeshPropertyDescriptor &props, + CSG_FaceIteratorDescriptor &face_it, + CSG_VertexIteratorDescriptor &vertex_it +) { + MEM_SmartPtr mesh = new BSP_TMesh(); + + CSG_IVertex vert; + + while (!vertex_it.Done(vertex_it.it)) { + + vertex_it.Fill(vertex_it.it,&vert); + + BSP_TVertex v; + v.m_pos = MT_Point3(vert.position); + mesh->VertexSet().push_back(v); + + vertex_it.Step(vertex_it.it); + } + + + CSG_IFace face; + + while (!face_it.Done(face_it.it)) { + face_it.Fill(face_it.it,&face); + + BSP_TFace f; + + f.m_verts[0] = face.vertex_index[0], + f.m_verts[1] = face.vertex_index[1], + f.m_verts[2] = face.vertex_index[2], + + mesh->BuildNormal(f); + + mesh->FaceSet().push_back(f); + + face_it.Step(face_it.it); + } + + return mesh; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif + diff --git a/intern/bsp/test/BSP_GhostTest/Makefile b/intern/bsp/test/BSP_GhostTest/Makefile new file mode 100644 index 00000000000..06dded40a17 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# BSP_GhostTest Makefile +# + +LIBNAME = BSP_GhostTest +SOURCEDIR = intern/bsp/test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_BSP)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_GHOST)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I../../extern/ + +ifeq ($(OS),windows) + CPPFLAGS += -I$(NAN_LIBDIR)/windows/glut-3.7/include +endif + + + diff --git a/intern/bsp/test/BSP_GhostTest/main.cpp b/intern/bsp/test/BSP_GhostTest/main.cpp new file mode 100644 index 00000000000..6b0e0d66234 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/main.cpp @@ -0,0 +1,151 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "BSP_GhostTest3D.h" + +#include "BSP_TMesh.h" +#include "MEM_SmartPtr.h" +#include "BSP_PlyLoader.h" + +#include + +using namespace std; +#if 1 + MEM_SmartPtr +NewTestMesh( + int x, + int y, + MT_Scalar fx, + MT_Scalar fy, + MT_Scalar ampx, + MT_Scalar ampy, + MT_Scalar sx, + MT_Scalar sy +) { + + MEM_SmartPtr output = new BSP_TMesh; + + std::vector &verts = output->VertexSet(); + + int i,j; + + MT_Scalar x_scale = fx*MT_PI/x; + MT_Scalar y_scale = fy*MT_PI/y; + + MT_Scalar fsx = sx/x; + MT_Scalar fsy = sy/y; + + for (j = 0; j < y; j++) { + for (i = 0; i < x; i++) { + float z = ampx*sin(x_scale * i) + ampy*sin(y_scale * j); + + MT_Vector3 val(i*fsx - sx/2,j*fsy - sy/2,z); + + BSP_TVertex chuff; + chuff.m_pos = val; + verts.push_back(chuff); + } + } + + int poly[4]; + + for (j = 0; j < (y-1); j++) { + for (i = 0; i < (x-1); i++) { + + poly[0] = j*x + i; + poly[1] = poly[0] + 1; + poly[2] = poly[1] + y; + poly[3] = poly[2] -1; + + output->AddFace(poly,4); + } + } + + output->m_min = MT_Vector3(-sx/2,-sy/2,-ampx -ampy); + output->m_max = MT_Vector3(sx/2,sy/2,ampx + ampy); + + return output; +} +#endif + + +int main() { + + MT_Vector3 min,max; + MT_Vector3 min2,max2; + +#if 1 + MEM_SmartPtr mesh1 = BSP_PlyLoader::NewMeshFromFile("bsp_cube.ply",min,max); + MEM_SmartPtr mesh2 = BSP_PlyLoader::NewMeshFromFile("bsp_cube.ply",min2,max2); + + mesh1->m_min = min; + mesh1->m_max = max; + mesh2->m_min = min2; + mesh1->m_max = max2; + +#else + MEM_SmartPtr mesh1 = NewTestMesh(10,10,2,2,4,4,20,20); + MEM_SmartPtr mesh2 = NewTestMesh(10,10,2,2,4,4,20,20); +#endif + + if (!mesh1) { + cout << "could not load mesh!"; + return 0; + } + + + +// MEM_SmartPtr mesh2 = new BSP_TMesh(mesh1.Ref()); + + BSP_GhostTestApp3D app; + + cout << "Mesh polygons :" << mesh1->FaceSet().size() << "\n"; + cout << "Mesh vertices :" << mesh1->VertexSet().size() << "\n"; + + app.SetMesh(mesh1); + app.SetMesh(mesh2); + + + app.InitApp(); + + app.Run(); + + return 0; + +} + + + + diff --git a/intern/bsp/test/BSP_GhostTest/ply.h b/intern/bsp/test/BSP_GhostTest/ply.h new file mode 100644 index 00000000000..7947d224c5f --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/ply.h @@ -0,0 +1,200 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + +Header for PLY polygon files. + +- Greg Turk, March 1994 + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties three floating-point values x,y,z and three unsigned +chars for red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#ifndef __PLY_H__ +#define __PLY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define PLY_ASCII 1 /* ascii PLY file */ +#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ +#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ + +#define PLY_OKAY 0 /* ply routine worked okay */ +#define PLY_ERROR -1 /* error in ply routine */ + +/* scalar data types supported by PLY format */ + +#define PLY_START_TYPE 0 +#define PLY_CHAR 1 +#define PLY_SHORT 2 +#define PLY_INT 3 +#define PLY_UCHAR 4 +#define PLY_USHORT 5 +#define PLY_UINT 6 +#define PLY_FLOAT 7 +#define PLY_DOUBLE 8 +#define PLY_END_TYPE 9 + +#define PLY_SCALAR 0 +#define PLY_LIST 1 + + +typedef struct PlyProperty { /* description of a property */ + + char *name; /* property name */ + int external_type; /* file's data type */ + int internal_type; /* program's data type */ + int offset; /* offset bytes of prop in a struct */ + + int is_list; /* 1 = list, 0 = scalar */ + int count_external; /* file's count type */ + int count_internal; /* program's count type */ + int count_offset; /* offset byte for list count */ + +} PlyProperty; + +typedef struct PlyElement { /* description of an element */ + char *name; /* element name */ + int num; /* number of elements in this object */ + int size; /* size of element (bytes) or -1 if variable */ + int nprops; /* number of properties for this element */ + PlyProperty **props; /* list of properties in the file */ + char *store_prop; /* flags: property wanted by user? */ + int other_offset; /* offset to un-asked-for props, or -1 if none*/ + int other_size; /* size of other_props structure */ +} PlyElement; + +typedef struct PlyOtherProp { /* describes other properties in an element */ + char *name; /* element name */ + int size; /* size of other_props */ + int nprops; /* number of properties in other_props */ + PlyProperty **props; /* list of properties in other_props */ +} PlyOtherProp; + +typedef struct OtherData { /* for storing other_props for an other element */ + void *other_props; +} OtherData; + +typedef struct OtherElem { /* data for one "other" element */ + char *elem_name; /* names of other elements */ + int elem_count; /* count of instances of each element */ + OtherData **other_data; /* actual property data for the elements */ + PlyOtherProp *other_props; /* description of the property data */ +} OtherElem; + +typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ + int num_elems; /* number of other elements */ + OtherElem *other_list; /* list of data for other elements */ +} PlyOtherElems; + +typedef struct PlyFile { /* description of PLY file */ + FILE *fp; /* file pointer */ + int file_type; /* ascii or binary */ + float version; /* version number of file */ + int nelems; /* number of elements of object */ + PlyElement **elems; /* list of elements */ + int num_comments; /* number of comments */ + char **comments; /* list of comments */ + int num_obj_info; /* number of items of object information */ + char **obj_info; /* list of object info items */ + PlyElement *which_elem; /* which element we're currently writing */ + PlyOtherElems *other_elems; /* "other" elements from a PLY file */ +} PlyFile; + +/* memory allocation */ +static char *my_alloc(); +#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) + + +/*** delcaration of routines ***/ + +extern PlyFile *ply_write(FILE *, int, char **, int); +extern PlyFile *ply_open_for_writing(char *, int, char **, int, float *); +extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *); +extern void ply_describe_property(PlyFile *, char *, PlyProperty *); +extern void ply_element_count(PlyFile *, char *, int); +extern void ply_header_complete(PlyFile *); +extern void ply_put_element_setup(PlyFile *, char *); +extern void ply_put_element(PlyFile *, void *); +extern void ply_put_comment(PlyFile *, char *); +extern void ply_put_obj_info(PlyFile *, char *); +extern PlyFile *ply_read(FILE *, int *, char ***); +extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *); +extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*); +extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *); +extern void ply_get_property(PlyFile *, char *, PlyProperty *); +extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); +extern void ply_get_element(PlyFile *, void *); +extern char **ply_get_comments(PlyFile *, int *); +extern char **ply_get_obj_info(PlyFile *, int *); +extern void ply_close(PlyFile *); +extern void ply_get_info(PlyFile *, float *, int *); +extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int); +extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *); +extern void ply_put_other_elements (PlyFile *); +extern void ply_free_other_elements (PlyOtherElems *); + +extern int equal_strings(char *, char *); + + +#ifdef __cplusplus +} +#endif +#endif /* !__PLY_H__ */ + diff --git a/intern/bsp/test/BSP_GhostTest/plyfile.c b/intern/bsp/test/BSP_GhostTest/plyfile.c new file mode 100644 index 00000000000..fd808aa0889 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/plyfile.c @@ -0,0 +1,2552 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + +The interface routines for reading and writing PLY polygon files. + +Greg Turk, February 1994 + +--------------------------------------------------------------- + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties the floating-point values x,y,z and the three unsigned +chars representing red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#include +#include +#include +#include +#include "ply.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +char *type_names[] = { +"invalid", +"char", "short", "int", +"uchar", "ushort", "uint", +"float", "double", +}; + +int ply_type_size[] = { + 0, 1, 2, 4, 1, 2, 4, 4, 8 +}; + +#define NO_OTHER_PROPS -1 + +#define DONT_STORE_PROP 0 +#define STORE_PROP 1 + +#define OTHER_PROP 0 +#define NAMED_PROP 1 + + +/* returns 1 if strings are equal, 0 if not */ +int equal_strings(char *, char *); + +/* find an element in a plyfile's list */ +PlyElement *find_element(PlyFile *, char *); + +/* find a property in an element's list */ +PlyProperty *find_property(PlyElement *, char *, int *); + +/* write to a file the word describing a PLY file data type */ +void write_scalar_type (FILE *, int); + +/* read a line from a file and break it up into separate words */ +char **get_words(FILE *, int *, char **); +char **old_get_words(FILE *, int *); + +/* write an item to a file */ +void write_binary_item(FILE *, int, unsigned int, double, int); +void write_ascii_item(FILE *, int, unsigned int, double, int); +double old_write_ascii_item(FILE *, char *, int); + +/* add information to a PLY file descriptor */ +void add_element(PlyFile *, char **); +void add_property(PlyFile *, char **); +void add_comment(PlyFile *, char *); +void add_obj_info(PlyFile *, char *); + +/* copy a property */ +void copy_property(PlyProperty *, PlyProperty *); + +/* store a value into where a pointer and a type specify */ +void store_item(char *, int, int, unsigned int, double); + +/* return the value of a stored item */ +void get_stored_item( void *, int, int *, unsigned int *, double *); + +/* return the value stored in an item, given ptr to it and its type */ +double get_item_value(char *, int); + +/* get binary or ascii item and store it according to ptr and type */ +void get_ascii_item(char *, int, int *, unsigned int *, double *); +void get_binary_item(FILE *, int, int *, unsigned int *, double *); + +/* get a bunch of elements from a file */ +void ascii_get_element(PlyFile *, char *); +void binary_get_element(PlyFile *, char *); + +/* memory allocation */ +char *my_alloc(int, int, char *); + + +/*************/ +/* Writing */ +/*************/ + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: + fp - the given file pointer + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_write( + FILE *fp, + int nelems, + char **elem_names, + int file_type +) +{ + int i; + PlyFile *plyfile; + PlyElement *elem; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create a record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->file_type = file_type; + plyfile->num_comments = 0; + plyfile->num_obj_info = 0; + plyfile->nelems = nelems; + plyfile->version = 1.0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* tuck aside the names of the elements */ + + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems); + for (i = 0; i < nelems; i++) { + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + plyfile->elems[i] = elem; + elem->name = strdup (elem_names[i]); + elem->num = 0; + elem->nprops = 0; + } + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for writing. + +Entry: + filename - name of file to read from + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_writing( + char *filename, + int nelems, + char **elem_names, + int file_type, + float *version +) +{ + PlyFile *plyfile; + char *name; + FILE *fp; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for writing */ + + fp = fopen (name, "w"); + if (fp == NULL) { + return (NULL); + } + + /* create the actual PlyFile structure */ + + plyfile = ply_write (fp, nelems, elem_names, file_type); + if (plyfile == NULL) + return (NULL); + + /* say what PLY file version number we're writing */ + *version = plyfile->version; + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Describe an element, including its properties and how many will be written +to the file. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written + nprops - number of properties contained in the element + prop_list - list of properties +******************************************************************************/ + +void ply_describe_element( + PlyFile *plyfile, + char *elem_name, + int nelems, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; + + /* copy the list of properties */ + + elem->nprops = nprops; + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * nprops); + + for (i = 0; i < nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[i] = prop; + elem->store_prop[i] = NAMED_PROP; + copy_property (prop, &prop_list[i]); + } +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + prop - the new property +******************************************************************************/ + +void ply_describe_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *elem_prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_property: can't find element '%s'\n", + elem_name); + return; + } + + /* create room for new property */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + elem->store_prop = (char *) myalloc (sizeof (char)); + elem->nprops = 1; + } + else { + elem->nprops++; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * elem->nprops); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * elem->nprops); + } + + /* copy the new property */ + + elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[elem->nprops - 1] = elem_prop; + elem->store_prop[elem->nprops - 1] = NAMED_PROP; + copy_property (elem_prop, prop); +} + + +/****************************************************************************** +Describe what the "other" properties are that are to be stored, and where +they are in an element. +******************************************************************************/ + +void ply_describe_other_properties( + PlyFile *plyfile, + PlyOtherProp *other, + int offset +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, other->name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n", + other->name); + return; + } + + /* create room for other properties */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) + myalloc (sizeof (PlyProperty *) * other->nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops); + elem->nprops = 0; + } + else { + int newsize; + newsize = elem->nprops + other->nprops; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * newsize); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * newsize); + } + + /* copy the other properties */ + + for (i = 0; i < other->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, other->props[i]); + elem->props[elem->nprops] = prop; + elem->store_prop[elem->nprops] = OTHER_PROP; + elem->nprops++; + } + + /* save other info about other properties */ + elem->other_size = other->size; + elem->other_offset = offset; +} + + +/****************************************************************************** +State how many of a given element will be written. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written +******************************************************************************/ + +void ply_element_count( + PlyFile *plyfile, + char *elem_name, + int nelems +) +{ + PlyElement *elem; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; +} + + +/****************************************************************************** +Signal that we've described everything a PLY file's header and that the +header should be written to the file. + +Entry: + plyfile - file identifier +******************************************************************************/ + +void ply_header_complete(PlyFile *plyfile) +{ + int i,j; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + + fprintf (fp, "ply\n"); + + switch (plyfile->file_type) { + case PLY_ASCII: + fprintf (fp, "format ascii 1.0\n"); + break; + case PLY_BINARY_BE: + fprintf (fp, "format binary_big_endian 1.0\n"); + break; + case PLY_BINARY_LE: + fprintf (fp, "format binary_little_endian 1.0\n"); + break; + default: + fprintf (stderr, "ply_header_complete: bad file type = %d\n", + plyfile->file_type); + exit (-1); + } + + /* write out the comments */ + + for (i = 0; i < plyfile->num_comments; i++) + fprintf (fp, "comment %s\n", plyfile->comments[i]); + + /* write out object information */ + + for (i = 0; i < plyfile->num_obj_info; i++) + fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]); + + /* write out information about each element */ + + for (i = 0; i < plyfile->nelems; i++) { + + elem = plyfile->elems[i]; + fprintf (fp, "element %s %d\n", elem->name, elem->num); + + /* write out each property */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (prop->is_list) { + fprintf (fp, "property list "); + write_scalar_type (fp, prop->count_external); + fprintf (fp, " "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + else { + fprintf (fp, "property "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + } + } + + fprintf (fp, "end_header\n"); +} + + +/****************************************************************************** +Specify which elements are going to be written. This should be called +before a call to the routine ply_put_element(). + +Entry: + plyfile - file identifier + elem_name - name of element we're talking about +******************************************************************************/ + +void ply_put_element_setup(PlyFile *plyfile, char *elem_name) +{ + PlyElement *elem; + + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name); + exit (-1); + } + + plyfile->which_elem = elem; +} + + +/****************************************************************************** +Write an element to the file. This routine assumes that we're +writing the type of element specified in the last call to the routine +ply_put_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to the element +******************************************************************************/ + +void ply_put_element(PlyFile *plyfile, void *elem_ptr) +{ + int j,k; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + char *elem_data,*item; + char **item_ptr; + int list_count; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + char **other_ptr; + + elem = plyfile->which_elem; + elem_data = elem_ptr; + other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset); + + /* write out either to an ascii or binary file */ + + if (plyfile->file_type == PLY_ASCII) { + + /* write an ascii file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = elem_ptr; + if (prop->is_list) { + item = elem_data + prop->count_offset; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else { + item = elem_data + prop->offset; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + fprintf (fp, "\n"); + } + else { + + /* write a binary file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = elem_ptr; + if (prop->is_list) { + item = elem_data + prop->count_offset; + item_size = ply_type_size[prop->count_internal]; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else { + item = elem_data + prop->offset; + item_size = ply_type_size[prop->internal_type]; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + } +} + + +/****************************************************************************** +Specify a comment that will be written in the header. + +Entry: + plyfile - file identifier + comment - the comment to be written +******************************************************************************/ + +void ply_put_comment(PlyFile *plyfile, char *comment) +{ + /* (re)allocate space for new comment */ + if (plyfile->num_comments == 0) + plyfile->comments = (char **) myalloc (sizeof (char *)); + else + plyfile->comments = (char **) realloc (plyfile->comments, + sizeof (char *) * (plyfile->num_comments + 1)); + + /* add comment to list */ + plyfile->comments[plyfile->num_comments] = strdup (comment); + plyfile->num_comments++; +} + + +/****************************************************************************** +Specify a piece of object information (arbitrary text) that will be written +in the header. + +Entry: + plyfile - file identifier + obj_info - the text information to be written +******************************************************************************/ + +void ply_put_obj_info(PlyFile *plyfile, char *obj_info) +{ + /* (re)allocate space for new info */ + if (plyfile->num_obj_info == 0) + plyfile->obj_info = (char **) myalloc (sizeof (char *)); + else + plyfile->obj_info = (char **) realloc (plyfile->obj_info, + sizeof (char *) * (plyfile->num_obj_info + 1)); + + /* add info to list */ + plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info); + plyfile->num_obj_info++; +} + + + + + + + +/*************/ +/* Reading */ +/*************/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: + fp - the given file pointer + +Exit: + nelems - number of elements in object + elem_names - list of element names + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names) +{ + int i,j; + PlyFile *plyfile; + int nwords; + char **words; + int found_format = 0; + char **elist; + PlyElement *elem; + char *orig_line; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->nelems = 0; + plyfile->comments = NULL; + plyfile->num_comments = 0; + plyfile->obj_info = NULL; + plyfile->num_obj_info = 0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* read and parse the file's header */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (!words || !equal_strings (words[0], "ply")) + return (NULL); + + while (words) { + + /* parse words */ + + if (equal_strings (words[0], "format")) { + if (nwords != 3) + return (NULL); + if (equal_strings (words[1], "ascii")) + plyfile->file_type = PLY_ASCII; + else if (equal_strings (words[1], "binary_big_endian")) + plyfile->file_type = PLY_BINARY_BE; + else if (equal_strings (words[1], "binary_little_endian")) + plyfile->file_type = PLY_BINARY_LE; + else + return (NULL); + plyfile->version = (float)atof (words[2]); + found_format = 1; + } + else if (equal_strings (words[0], "element")) + add_element (plyfile, words); + else if (equal_strings (words[0], "property")) + add_property (plyfile, words); + else if (equal_strings (words[0], "comment")) + add_comment (plyfile, orig_line); + else if (equal_strings (words[0], "obj_info")) + add_obj_info (plyfile, orig_line); + else if (equal_strings (words[0], "end_header")) + break; + + /* free up words space */ + free (words); + + words = get_words (plyfile->fp, &nwords, &orig_line); + } + + /* create tags for each property of each element, to be used */ + /* later to say whether or not to store each property for the user */ + + for (i = 0; i < plyfile->nelems; i++) { + elem = plyfile->elems[i]; + elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops); + for (j = 0; j < elem->nprops; j++) + elem->store_prop[j] = DONT_STORE_PROP; + elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */ + } + + /* set return values about the elements */ + + elist = (char **) myalloc (sizeof (char *) * plyfile->nelems); + for (i = 0; i < plyfile->nelems; i++) + elist[i] = strdup (plyfile->elems[i]->name); + + *elem_names = elist; + *nelems = plyfile->nelems; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for reading. + +Entry: + filename - name of file to read from + +Exit: + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_reading( + char *filename, + int *nelems, + char ***elem_names, + int *file_type, + float *version +) +{ + FILE *fp; + PlyFile *plyfile; + char *name; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for reading */ + + fp = fopen (name, "r"); + if (fp == NULL) + return (NULL); + + /* create the PlyFile data structure */ + + plyfile = ply_read (fp, nelems, elem_names); + + /* determine the file type and version */ + + *file_type = plyfile->file_type; + *version = plyfile->version; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Get information about a particular element. + +Entry: + plyfile - file identifier + elem_name - name of element to get information about + +Exit: + nelems - number of elements of this type in the file + nprops - number of properties + returns a list of properties, or NULL if the file doesn't contain that elem +******************************************************************************/ + +PlyProperty **ply_get_element_description( + PlyFile *plyfile, + char *elem_name, + int *nelems, + int *nprops +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + PlyProperty **prop_list; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) + return (NULL); + + *nelems = elem->num; + *nprops = elem->nprops; + + /* make a copy of the element's property list */ + prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops); + for (i = 0; i < elem->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + prop_list[i] = prop; + } + + /* return this duplicate property list */ + return (prop_list); +} + + +/****************************************************************************** +Specify which properties of an element are to be returned. This should be +called before a call to the routine ply_get_element(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + nprops - number of properties + prop_list - list of properties +******************************************************************************/ + +void ply_get_element_setup( + PlyFile *plyfile, + char *elem_name, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + for (i = 0; i < nprops; i++) { + + /* look for actual property */ + prop = find_property (elem, prop_list[i].name, &index); + if (prop == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop_list[i].name, elem_name); + continue; + } + + /* store its description */ + prop->internal_type = prop_list[i].internal_type; + prop->offset = prop_list[i].offset; + prop->count_internal = prop_list[i].count_internal; + prop->count_offset = prop_list[i].count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; + } +} + + +/****************************************************************************** +Specify a property of an element that is to be returned. This should be +called (usually multiple times) before a call to the routine ply_get_element(). +This routine should be used in preference to the less flexible old routine +called ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + prop - property to add to those that will be returned +******************************************************************************/ + +void ply_get_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *prop_ptr; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + + prop_ptr = find_property (elem, prop->name, &index); + if (prop_ptr == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop->name, elem_name); + return; + } + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void ply_get_element(PlyFile *plyfile, void *elem_ptr) +{ + if (plyfile->file_type == PLY_ASCII) + ascii_get_element (plyfile, (char *) elem_ptr); + else + binary_get_element (plyfile, (char *) elem_ptr); +} + + +/****************************************************************************** +Extract the comments from the header information of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_comments - number of comments returned + returns a pointer to a list of comments +******************************************************************************/ + +char **ply_get_comments(PlyFile *plyfile, int *num_comments) +{ + *num_comments = plyfile->num_comments; + return (plyfile->comments); +} + + +/****************************************************************************** +Extract the object information (arbitrary text) from the header information +of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_obj_info - number of lines of text information returned + returns a pointer to a list of object info lines +******************************************************************************/ + +char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info) +{ + *num_obj_info = plyfile->num_obj_info; + return (plyfile->obj_info); +} + + +/****************************************************************************** +Make ready for "other" properties of an element-- those properties that +the user has not explicitly asked for, but that are to be stashed away +in a special structure to be carried along with the element's other +information. + +Entry: + plyfile - file identifier + elem - element for which we want to save away other properties +******************************************************************************/ + +void setup_other_props(PlyElement *elem) +{ + int i; + PlyProperty *prop; + int size = 0; + int type_size; + + /* Examine each property in decreasing order of size. */ + /* We do this so that all data types will be aligned by */ + /* word, half-word, or whatever within the structure. */ + + for (type_size = 8; type_size > 0; type_size /= 2) { + + /* add up the space taken by each property, and save this information */ + /* away in the property descriptor */ + + for (i = 0; i < elem->nprops; i++) { + + /* don't bother with properties we've been asked to store explicitly */ + if (elem->store_prop[i]) + continue; + + prop = elem->props[i]; + + /* internal types will be same as external */ + prop->internal_type = prop->external_type; + prop->count_internal = prop->count_external; + + /* check list case */ + if (prop->is_list) { + + /* pointer to list */ + if (type_size == sizeof (void *)) { + prop->offset = size; + size += sizeof (void *); /* always use size of a pointer here */ + } + + /* count of number of list elements */ + if (type_size == ply_type_size[prop->count_external]) { + prop->count_offset = size; + size += ply_type_size[prop->count_external]; + } + } + /* not list */ + else if (type_size == ply_type_size[prop->external_type]) { + prop->offset = size; + size += ply_type_size[prop->external_type]; + } + } + + } + + /* save the size for the other_props structure */ + elem->other_size = size; +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. The user needn't be concerned for how +these properties are stored. + +Entry: + plyfile - file identifier + elem_name - name of element that we want to store other_props in + offset - offset to where other_props will be stored inside user's structure + +Exit: + returns pointer to structure containing description of other_props +******************************************************************************/ + +PlyOtherProp *ply_get_other_properties( + PlyFile *plyfile, + char *elem_name, + int offset +) +{ + int i; + PlyElement *elem; + PlyOtherProp *other; + PlyProperty *prop; + int nprops; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n", + elem_name); + return (NULL); + } + + /* remember that this is the "current" element */ + plyfile->which_elem = elem; + + /* save the offset to where to store the other_props */ + elem->other_offset = offset; + + /* place the appropriate pointers, etc. in the element's property list */ + setup_other_props (elem); + + /* create structure for describing other_props */ + other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp)); + other->name = strdup (elem_name); +#if 0 + if (elem->other_offset == NO_OTHER_PROPS) { + other->size = 0; + other->props = NULL; + other->nprops = 0; + return (other); + } +#endif + other->size = elem->other_size; + other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops); + + /* save descriptions of each "other" property */ + nprops = 0; + for (i = 0; i < elem->nprops; i++) { + if (elem->store_prop[i]) + continue; + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + other->props[nprops] = prop; + nprops++; + } + other->nprops = nprops; + +#if 1 + /* set other_offset pointer appropriately if there are NO other properties */ + if (other->nprops == 0) { + elem->other_offset = NO_OTHER_PROPS; + } +#endif + + /* return structure */ + return (other); +} + + + + +/*************************/ +/* Other Element Stuff */ +/*************************/ + + + + +/****************************************************************************** +Grab all the data for an element that a user does not want to explicitly +read in. + +Entry: + plyfile - pointer to file + elem_name - name of element whose data is to be read in + elem_count - number of instances of this element stored in the file + +Exit: + returns pointer to ALL the "other" element data for this PLY file +******************************************************************************/ + +PlyOtherElems *ply_get_other_element ( + PlyFile *plyfile, + char *elem_name, + int elem_count +) +{ + int i; + PlyElement *elem; + PlyOtherElems *other_elems; + OtherElem *other; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, + "ply_get_other_element: can't find element '%s'\n", elem_name); + exit (-1); + } + + /* create room for the new "other" element, initializing the */ + /* other data structure if necessary */ + + if (plyfile->other_elems == NULL) { + plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems)); + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem)); + other = &(other_elems->other_list[0]); + other_elems->num_elems = 1; + } + else { + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) realloc (other_elems->other_list, + sizeof (OtherElem) * other_elems->num_elems + 1); + other = &(other_elems->other_list[other_elems->num_elems]); + other_elems->num_elems++; + } + + /* count of element instances in file */ + other->elem_count = elem_count; + + /* save name of element */ + other->elem_name = strdup (elem_name); + + /* create a list to hold all the current elements */ + other->other_data = (OtherData **) + malloc (sizeof (OtherData *) * other->elem_count); + + /* set up for getting elements */ + other->other_props = ply_get_other_properties (plyfile, elem_name, + offsetof(OtherData,other_props)); + + /* grab all these elements */ + for (i = 0; i < other->elem_count; i++) { + /* grab and element from the file */ + other->other_data[i] = (OtherData *) malloc (sizeof (OtherData)); + ply_get_element (plyfile, (void *) other->other_data[i]); + } + + /* return pointer to the other elements data */ + return (other_elems); +} + + +/****************************************************************************** +Pass along a pointer to "other" elements that we want to save in a given +PLY file. These other elements were presumably read from another PLY file. + +Entry: + plyfile - file pointer in which to store this other element info + other_elems - info about other elements that we want to store +******************************************************************************/ + +void ply_describe_other_elements ( + PlyFile *plyfile, + PlyOtherElems *other_elems +) +{ + int i; + OtherElem *other; + + /* ignore this call if there is no other element */ + if (other_elems == NULL) + return; + + /* save pointer to this information */ + plyfile->other_elems = other_elems; + + /* describe the other properties of this element */ + + for (i = 0; i < other_elems->num_elems; i++) { + other = &(other_elems->other_list[i]); + ply_element_count (plyfile, other->elem_name, other->elem_count); + ply_describe_other_properties (plyfile, other->other_props, + offsetof(OtherData,other_props)); + } +} + + +/****************************************************************************** +Write out the "other" elements specified for this PLY file. + +Entry: + plyfile - pointer to PLY file to write out other elements for +******************************************************************************/ + +void ply_put_other_elements (PlyFile *plyfile) +{ + int i,j; + OtherElem *other; + + /* make sure we have other elements to write */ + if (plyfile->other_elems == NULL) + return; + + /* write out the data for each "other" element */ + + for (i = 0; i < plyfile->other_elems->num_elems; i++) { + + other = &(plyfile->other_elems->other_list[i]); + ply_put_element_setup (plyfile, other->elem_name); + + /* write out each instance of the current element */ + for (j = 0; j < other->elem_count; j++) + ply_put_element (plyfile, (void *) other->other_data[j]); + } +} + + +/****************************************************************************** +Free up storage used by an "other" elements data structure. + +Entry: + other_elems - data structure to free up +******************************************************************************/ + + + + +/*******************/ +/* Miscellaneous */ +/*******************/ + + + +/****************************************************************************** +Close a PLY file. + +Entry: + plyfile - identifier of file to close +******************************************************************************/ + +void ply_close(PlyFile *plyfile) +{ + fclose (plyfile->fp); + + /* free up memory associated with the PLY file */ + free (plyfile); +} + + +/****************************************************************************** +Get version number and file type of a PlyFile. + +Entry: + ply - pointer to PLY file + +Exit: + version - version of the file + file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE +******************************************************************************/ + +void ply_get_info(PlyFile *ply, float *version, int *file_type) +{ + if (ply == NULL) + return; + + *version = ply->version; + *file_type = ply->file_type; +} + + +/****************************************************************************** +Compare two strings. Returns 1 if they are the same, 0 if not. +******************************************************************************/ + +int equal_strings(char *s1, char *s2) +{ + + while (*s1 && *s2) + if (*s1++ != *s2++) + return (0); + + if (*s1 != *s2) + return (0); + else + return (1); +} + + +/****************************************************************************** +Find an element from the element list of a given PLY object. + +Entry: + plyfile - file id for PLY file + element - name of element we're looking for + +Exit: + returns the element, or NULL if not found +******************************************************************************/ + +PlyElement *find_element(PlyFile *plyfile, char *element) +{ + int i; + + for (i = 0; i < plyfile->nelems; i++) + if (equal_strings (element, plyfile->elems[i]->name)) + return (plyfile->elems[i]); + + return (NULL); +} + + +/****************************************************************************** +Find a property in the list of properties of a given element. + +Entry: + elem - pointer to element in which we want to find the property + prop_name - name of property to find + +Exit: + index - index to position in list + returns a pointer to the property, or NULL if not found +******************************************************************************/ + +PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index) +{ + int i; + + for (i = 0; i < elem->nprops; i++) + if (equal_strings (prop_name, elem->props[i]->name)) { + *index = i; + return (elem->props[i]); + } + + *index = -1; + return (NULL); +} + + +/****************************************************************************** +Read an element from an ascii file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to element +******************************************************************************/ + +void ascii_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + char **words; + int nwords; + int which_word; + char *elem_data,*item; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *orig_line; + char *other_data; + int other_flag; + + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } else { + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + } + + /* read in the element */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (words == NULL) { + fprintf (stderr, "ply_get_element: unexpected end of file\n"); + exit (-1); + } + + which_word = 0; + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list) { /* a list */ + + /* get and store the number of items in the list */ + get_ascii_item (words[which_word++], prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[prop->internal_type]; + store_array = (char **) (elem_data + prop->offset); + + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else { /* not a list */ + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } + + free (words); +} + + +/****************************************************************************** +Read an element from a binary file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to an element +******************************************************************************/ + +void binary_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + FILE *fp = plyfile->fp; + char *elem_data,*item; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *other_data; + int other_flag; + + + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } + else { + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + } + /* read in a number of elements */ + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list) { /* a list */ + + /* get and store the number of items in the list */ + get_binary_item (fp, prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + /* The "if" was added by Afra Zomorodian 8/22/95 + * so that zipper won't crash reading plies that have additional + * properties. + */ + if (store_it) { + item_size = ply_type_size[prop->internal_type]; + } + store_array = (char **) (elem_data + prop->offset); + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_binary_item (fp, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else { /* not a list */ + get_binary_item (fp, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } +} + + +/****************************************************************************** +Write to a file the word that represents a PLY data type. + +Entry: + fp - file pointer + code - code for type +******************************************************************************/ + +void write_scalar_type (FILE *fp, int code) +{ + /* make sure this is a valid code */ + + if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) { + fprintf (stderr, "write_scalar_type: bad data code = %d\n", code); + exit (-1); + } + + /* write the code to a file */ + + fprintf (fp, "%s", type_names[code]); +} + + +/****************************************************************************** +Get a text line from a file and break it up into words. + +IMPORTANT: The calling routine call "free" on the returned pointer once +finished with it. + +Entry: + fp - file to read from + +Exit: + nwords - number of words returned + orig_line - the original line of characters + returns a list of words from the line, or NULL if end-of-file +******************************************************************************/ + +char **get_words(FILE *fp, int *nwords, char **orig_line) +{ +#define BIG_STRING 4096 + static char str[BIG_STRING]; + static char str_copy[BIG_STRING]; + char **words; + int max_words = 10; + int num_words = 0; + char *ptr,*ptr2; + char *result; + + words = (char **) myalloc (sizeof (char *) * max_words); + + /* read in a line */ + result = fgets (str, BIG_STRING, fp); + if (result == NULL) { + *nwords = 0; + *orig_line = NULL; + return (NULL); + } + + /* convert line-feed and tabs into spaces */ + /* (this guarentees that there will be a space before the */ + /* null character at the end of the string) */ + + str[BIG_STRING-2] = ' '; + str[BIG_STRING-1] = '\0'; + + for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) { + *ptr2 = *ptr; + if (*ptr == '\t') { + *ptr = ' '; + *ptr2 = ' '; + } + else if (*ptr == '\n') { + *ptr = ' '; + *ptr2 = '\0'; + break; + } + } + + /* find the words in the line */ + + ptr = str; + while (*ptr != '\0') { + + /* jump over leading spaces */ + while (*ptr == ' ') + ptr++; + + /* break if we reach the end */ + if (*ptr == '\0') + break; + + /* save pointer to beginning of word */ + if (num_words >= max_words) { + max_words += 10; + words = (char **) realloc (words, sizeof (char *) * max_words); + } + words[num_words++] = ptr; + + /* jump over non-spaces */ + while (*ptr != ' ') + ptr++; + + /* place a null character here to mark the end of the word */ + *ptr++ = '\0'; + } + + /* return the list of words */ + *nwords = num_words; + *orig_line = str_copy; + return (words); +} + + +/****************************************************************************** +Return the value of an item, given a pointer to it and its type. + +Entry: + item - pointer to item + type - data type that "item" points to + +Exit: + returns a double-precision float that contains the value of the item +******************************************************************************/ + +double get_item_value(char *item, int type) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch (type) { + case PLY_CHAR: + pchar = (char *) item; + int_value = *pchar; + return ((double) int_value); + case PLY_UCHAR: + puchar = (unsigned char *) item; + int_value = *puchar; + return ((double) int_value); + case PLY_SHORT: + pshort = (short int *) item; + int_value = *pshort; + return ((double) int_value); + case PLY_USHORT: + pushort = (unsigned short int *) item; + int_value = *pushort; + return ((double) int_value); + case PLY_INT: + pint = (int *) item; + int_value = *pint; + return ((double) int_value); + case PLY_UINT: + puint = (unsigned int *) item; + uint_value = *puint; + return ((double) uint_value); + case PLY_FLOAT: + pfloat = (float *) item; + double_value = *pfloat; + return (double_value); + case PLY_DOUBLE: + pdouble = (double *) item; + double_value = *pdouble; + return (double_value); + default: + fprintf (stderr, "get_item_value: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as raw binary bytes. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_binary_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + unsigned char uchar_val; + char char_val; + unsigned short ushort_val; + short short_val; + float float_val; + + switch (type) { + case PLY_CHAR: + char_val = (char)int_val; + fwrite (&char_val, 1, 1, fp); + break; + case PLY_SHORT: + short_val = (short)int_val; + fwrite (&short_val, 2, 1, fp); + break; + case PLY_INT: + fwrite (&int_val, 4, 1, fp); + break; + case PLY_UCHAR: + uchar_val = (unsigned char) uint_val; + fwrite (&uchar_val, 1, 1, fp); + break; + case PLY_USHORT: + ushort_val = (unsigned short)uint_val; + fwrite (&ushort_val, 2, 1, fp); + break; + case PLY_UINT: + fwrite (&uint_val, 4, 1, fp); + break; + case PLY_FLOAT: + float_val = (float) double_val; + fwrite (&float_val, 4, 1, fp); + break; + case PLY_DOUBLE: + fwrite (&double_val, 8, 1, fp); + break; + default: + fprintf (stderr, "write_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_ascii_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + switch (type) { + case PLY_CHAR: + case PLY_SHORT: + case PLY_INT: + fprintf (fp, "%d ", int_val); + break; + case PLY_UCHAR: + case PLY_USHORT: + case PLY_UINT: + fprintf (fp, "%u ", uint_val); + break; + case PLY_FLOAT: + case PLY_DOUBLE: + fprintf (fp, "%g ", double_val); + break; + default: + fprintf (stderr, "write_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: + fp - file to write to + item - pointer to item to write + type - data type that "item" points to + +Exit: + returns a double-precision float that contains the value of the written item +******************************************************************************/ + +double old_write_ascii_item(FILE *fp, char *item, int type) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch (type) { + case PLY_CHAR: + pchar = (char *) item; + int_value = *pchar; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_UCHAR: + puchar = (unsigned char *) item; + int_value = *puchar; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_SHORT: + pshort = (short int *) item; + int_value = *pshort; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_USHORT: + pushort = (unsigned short int *) item; + int_value = *pushort; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_INT: + pint = (int *) item; + int_value = *pint; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_UINT: + puint = (unsigned int *) item; + uint_value = *puint; + fprintf (fp, "%u ", uint_value); + return ((double) uint_value); + case PLY_FLOAT: + pfloat = (float *) item; + double_value = *pfloat; + fprintf (fp, "%g ", double_value); + return (double_value); + case PLY_DOUBLE: + pdouble = (double *) item; + double_value = *pdouble; + fprintf (fp, "%g ", double_value); + return (double_value); + default: + fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item that is in memory, and place the result +into an integer, an unsigned integer and a double. + +Entry: + ptr - pointer to the item + type - data type supposedly in the item + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_stored_item( + void *ptr, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case PLY_CHAR: + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UCHAR: + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_SHORT: + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_USHORT: + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_INT: + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UINT: + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_FLOAT: + *double_val = *((float *) ptr); + *int_val = (int)*double_val; + *uint_val = (unsigned int)*double_val; + break; + case PLY_DOUBLE: + *double_val = *((double *) ptr); + *int_val = (int)*double_val; + *uint_val =(unsigned int) *double_val; + break; + default: + fprintf (stderr, "get_stored_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item from a binary file, and place the result +into an integer, an unsigned integer and a double. + +Entry: + fp - file to get item from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_binary_item( + FILE *fp, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + char c[8]; + void *ptr; + + ptr = (void *) c; + + switch (type) { + case PLY_CHAR: + fread (ptr, 1, 1, fp); + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UCHAR: + fread (ptr, 1, 1, fp); + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_SHORT: + fread (ptr, 2, 1, fp); + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_USHORT: + fread (ptr, 2, 1, fp); + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_INT: + fread (ptr, 4, 1, fp); + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UINT: + fread (ptr, 4, 1, fp); + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_FLOAT: + fread (ptr, 4, 1, fp); + *double_val = *((float *) ptr); + *int_val = (int)*double_val; + *uint_val =(unsigned int) *double_val; + break; + case PLY_DOUBLE: + fread (ptr, 8, 1, fp); + *double_val = *((double *) ptr); + *int_val = (int)*double_val; + *uint_val = (unsigned int)*double_val; + break; + default: + fprintf (stderr, "get_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Extract the value of an item from an ascii word, and place the result +into an integer, an unsigned integer and a double. + +Entry: + word - word to extract value from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_ascii_item( + char *word, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case PLY_CHAR: + case PLY_UCHAR: + case PLY_SHORT: + case PLY_USHORT: + case PLY_INT: + *int_val = atoi (word); + *uint_val = *int_val; + *double_val = *int_val; + break; + + case PLY_UINT: + *uint_val = strtoul (word, (char **) NULL, 10); + *int_val = *uint_val; + *double_val = *uint_val; + break; + + case PLY_FLOAT: + case PLY_DOUBLE: + *double_val = atof (word); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + + default: + fprintf (stderr, "get_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Store a value into a place being pointed to, guided by a data type. + +Entry: + item - place to store value + type - data type + int_val - integer version of value + uint_val - unsigned integer version of value + double_val - double version of value + +Exit: + item - pointer to stored value +******************************************************************************/ + +void store_item ( + char *item, + int type, + int int_val, + unsigned int uint_val, + double double_val +) +{ + unsigned char *puchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + + switch (type) { + case PLY_CHAR: + *item = (char) int_val; + break; + case PLY_UCHAR: + puchar = (unsigned char *) item; + *puchar = (unsigned char)uint_val; + break; + case PLY_SHORT: + pshort = (short *) item; + *pshort = (short)int_val; + break; + case PLY_USHORT: + pushort = (unsigned short *) item; + *pushort = (unsigned short)uint_val; + break; + case PLY_INT: + pint = (int *) item; + *pint = int_val; + break; + case PLY_UINT: + puint = (unsigned int *) item; + *puint = uint_val; + break; + case PLY_FLOAT: + pfloat = (float *) item; + *pfloat = (float)double_val; + break; + case PLY_DOUBLE: + pdouble = (double *) item; + *pdouble = double_val; + break; + default: + fprintf (stderr, "store_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Add an element to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the element + nwords - number of words in the list +******************************************************************************/ + +void add_element (PlyFile *plyfile, char **words) +{ + PlyElement *elem; + + /* create the new element */ + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + elem->name = strdup (words[1]); + elem->num = atoi (words[2]); + elem->nprops = 0; + + /* make room for new element in the object's list of elements */ + if (plyfile->nelems == 0) + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *)); + else + plyfile->elems = (PlyElement **) realloc (plyfile->elems, + sizeof (PlyElement *) * (plyfile->nelems + 1)); + + /* add the new element to the object's list */ + plyfile->elems[plyfile->nelems] = elem; + plyfile->nelems++; +} + + +/****************************************************************************** +Return the type of a property, given the name of the property. + +Entry: + name - name of property type + +Exit: + returns integer code for property, or 0 if not found +******************************************************************************/ + +int get_prop_type(char *type_name) +{ + int i; + + for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++) + if (equal_strings (type_name, type_names[i])) + return (i); + + /* if we get here, we didn't find the type */ + return (0); +} + + +/****************************************************************************** +Add a property to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the property + nwords - number of words in the list +******************************************************************************/ + +void add_property (PlyFile *plyfile, char **words) +{ + PlyProperty *prop; + PlyElement *elem; + + /* create the new property */ + + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + + if (equal_strings (words[1], "list")) { /* is a list */ + prop->count_external = get_prop_type (words[2]); + prop->external_type = get_prop_type (words[3]); + prop->name = strdup (words[4]); + prop->is_list = 1; + } + else { /* not a list */ + prop->external_type = get_prop_type (words[1]); + prop->name = strdup (words[2]); + prop->is_list = 0; + } + + /* add this property to the list of properties of the current element */ + + elem = plyfile->elems[plyfile->nelems - 1]; + + if (elem->nprops == 0) + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + else + elem->props = (PlyProperty **) realloc (elem->props, + sizeof (PlyProperty *) * (elem->nprops + 1)); + + elem->props[elem->nprops] = prop; + elem->nprops++; +} + + +/****************************************************************************** +Add a comment to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing comment +******************************************************************************/ + +void add_comment (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "comment" and leading spaces and tabs */ + i = 7; + while (line[i] == ' ' || line[i] == '\t') + i++; + + ply_put_comment (plyfile, &line[i]); +} + + +/****************************************************************************** +Add a some object information to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing text info +******************************************************************************/ + +void add_obj_info (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "obj_info" and leading spaces and tabs */ + i = 8; + while (line[i] == ' ' || line[i] == '\t') + i++; + + ply_put_obj_info (plyfile, &line[i]); +} + + +/****************************************************************************** +Copy a property. +******************************************************************************/ + +void copy_property(PlyProperty *dest, PlyProperty *src) +{ + dest->name = strdup (src->name); + dest->external_type = src->external_type; + dest->internal_type = src->internal_type; + dest->offset = src->offset; + + dest->is_list = src->is_list; + dest->count_external = src->count_external; + dest->count_internal = src->count_internal; + dest->count_offset = src->count_offset; +} + + +/****************************************************************************** +Allocate some memory. + +Entry: + size - amount of memory requested (in bytes) + lnum - line number from which memory was requested + fname - file name from which memory was requested +******************************************************************************/ + +static char *my_alloc(int size, int lnum, char *fname) +{ + char *ptr; + + ptr = (char *) malloc (size); + + if (ptr == 0) { + fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname); + } + + return (ptr); +} + diff --git a/intern/bsp/test/Makefile b/intern/bsp/test/Makefile new file mode 100644 index 00000000000..17ed638d745 --- /dev/null +++ b/intern/bsp/test/Makefile @@ -0,0 +1,72 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# bsp test makefile. +# + +LIBNAME = bsp +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +DIRS = BSP_GhostTest + +include nan_subdirs.mk + +include nan_link.mk + +LIBS = $(OCGDIR)/intern/$(LIBNAME)/test/BSP_GhostTest/$(DEBUG_DIR)libBSP_GhostTest.a +LIBS += $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)libbsp.a + +SLIBS += $(NAN_MOTO)/lib/$(DEBUG_DIR)libmoto.a +SLIBS += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a +SLIBS += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a + +ifeq ($(OS),$(findstring $(OS), "beos darwin linux freebsd openbsd")) + LLIBS = -L/usr/X11R6/lib -lglut -pthread -lXi -lXmu +endif + +all debug:: $(LIBS) $(DIR)/$(DEBUG_DIR)BSPGhostTest + +$(DIR)/$(DEBUG_DIR)BSPGhostTest: + @echo "****> linking $@ in $(DIR)" + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)BSPGhostTest $(LIBS) $(SLIBS) $(LLIBS) $(DADD) + +clean:: + $(RM) $(DIR)/BSPGhostTest $(DIR)/debug/BSPGhostTest + +test:: all + $(DIR)/BSPGhostTest + + + + + diff --git a/intern/container/CMakeLists.txt b/intern/container/CMakeLists.txt new file mode 100644 index 00000000000..497a7355edf --- /dev/null +++ b/intern/container/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC .) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(blender_CTR "${SRC}" "${INC}") +#, libtype=['intern'], priority = 10 ) diff --git a/intern/container/CTR_List.h b/intern/container/CTR_List.h new file mode 100644 index 00000000000..2ca2d60d0e7 --- /dev/null +++ b/intern/container/CTR_List.h @@ -0,0 +1,142 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + + +#ifndef CTR_LIST_H +#define CTR_LIST_H + +class CTR_Link { +public: + CTR_Link( + ) ; + + CTR_Link( + CTR_Link *next, + CTR_Link *prev + ) ; + + CTR_Link * + getNext( + ) const ; + + CTR_Link * + getPrev( + ) const ; + + bool + isHead( + ) const ; + + bool + isTail( + ) const ; + + void + insertBefore( + CTR_Link *link + ) ; + + void + insertAfter( + CTR_Link *link + ) ; + + void + remove( + ) ; + +private: + CTR_Link *m_next; + CTR_Link *m_prev; +}; + +class CTR_List { +public: + + CTR_List( + ) ; + + CTR_Link * + getHead( + ) const ; + + CTR_Link * + getTail( + ) const ; + + void + addHead( + CTR_Link *link + ) ; + + void + addTail( + CTR_Link *link + ) ; + +private: + CTR_Link m_head; + CTR_Link m_tail; +}; + +#endif + diff --git a/intern/container/CTR_Map.h b/intern/container/CTR_Map.h new file mode 100644 index 00000000000..8329337479b --- /dev/null +++ b/intern/container/CTR_Map.h @@ -0,0 +1,149 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef CTR_MAP_H +#define CTR_MAP_H + +template +class CTR_Map { +private: + struct Entry { + Entry (Entry *next, Key key, Value value) : + m_next(next), + m_key(key), + m_value(value) {} + + Entry *m_next; + Key m_key; + Value m_value; + }; + +public: + CTR_Map(int num_buckets = 100) : m_num_buckets(num_buckets) { + m_buckets = new Entry *[num_buckets]; + for (int i = 0; i < num_buckets; ++i) { + m_buckets[i] = 0; + } + } + + int size() { + int count=0; + for (int i=0;im_next; + count++; + } + } + return count; + } + + Value* at(int index) { + int count=0; + for (int i=0;im_value; + } + bucket = bucket->m_next; + count++; + } + } + return 0; + } + + void clear() { + for (int i = 0; i < m_num_buckets; ++i) { + Entry *entry_ptr = m_buckets[i]; + + while (entry_ptr != 0) { + Entry *tmp_ptr = entry_ptr->m_next; + delete entry_ptr; + entry_ptr = tmp_ptr; + } + m_buckets[i] = 0; + } + } + + ~CTR_Map() { + clear(); + delete [] m_buckets; + } + + void insert(const Key& key, const Value& value) { + Entry *entry_ptr = m_buckets[key.hash() % m_num_buckets]; + while ((entry_ptr != 0) && !(key == entry_ptr->m_key)) { + entry_ptr = entry_ptr->m_next; + } + + if (entry_ptr != 0) { + entry_ptr->m_value = value; + } + else { + Entry **bucket = &m_buckets[key.hash() % m_num_buckets]; + *bucket = new Entry(*bucket, key, value); + } + } + + void remove(const Key& key) { + Entry **entry_ptr = &m_buckets[key.hash() % m_num_buckets]; + while ((*entry_ptr != 0) && !(key == (*entry_ptr)->m_key)) { + entry_ptr = &(*entry_ptr)->m_next; + } + + if (*entry_ptr != 0) { + Entry *tmp_ptr = (*entry_ptr)->m_next; + delete *entry_ptr; + *entry_ptr = tmp_ptr; + } + } + + Value *operator[](Key key) { + Entry *bucket = m_buckets[key.hash() % m_num_buckets]; + while ((bucket != 0) && !(key == bucket->m_key)) { + bucket = bucket->m_next; + } + return bucket != 0 ? &bucket->m_value : 0; + } + +private: + int m_num_buckets; + Entry **m_buckets; +}; + +#endif + diff --git a/intern/container/CTR_TaggedIndex.h b/intern/container/CTR_TaggedIndex.h new file mode 100644 index 00000000000..87bc8a4315e --- /dev/null +++ b/intern/container/CTR_TaggedIndex.h @@ -0,0 +1,201 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple tagged index class. + */ + +#ifndef NAN_INCLUDED_CTR_TaggedIndex_h +#define NAN_INCLUDED_CTR_TaggedIndex_h + +/** + * This class is supposed to be a simple tagged index class. If these + * were indices into a mesh then we would never need 32 bits for such indices. + * It is often handy to have a few extra bits around to mark objects etc. We + * steal a few bits of CTR_TaggedIndex objects for this purpose. From the outside + * it will behave like a standard unsigned int but just carry the extra tag + * information around with it. + */ + +#include + +enum { + + empty_tag = 0x0, + empty_index = 0xffffffff +}; + +template < + int tag_shift, + int index_mask +> class CTR_TaggedIndex { +public: + CTR_TaggedIndex( + ) : + m_val ((empty_tag << tag_shift) | (empty_index & index_mask)) + { + } + + CTR_TaggedIndex( + const int val + ) : + m_val ((val & index_mask) | ((empty_tag << tag_shift) & (~index_mask))) { + } + + CTR_TaggedIndex( + const unsigned int val + ) : + m_val ((val & index_mask) | ((empty_tag << tag_shift) & (~index_mask))) { + } + + CTR_TaggedIndex( + const long int val + ) : + m_val ( ((long int) val & index_mask) + | ( (empty_tag << tag_shift) + & (~index_mask)) ) { + } + + CTR_TaggedIndex( + const long unsigned int val + ) : + m_val ( ((long unsigned int)val & index_mask) + | ( (empty_tag << tag_shift) + & (~index_mask) ) ) { + } + + + CTR_TaggedIndex( + const CTR_TaggedIndex &my_index + ): + m_val(my_index.m_val) + { + } + + bool + operator == ( + const CTR_TaggedIndex& rhs + ) const { + + return ((this->m_val & index_mask) == (rhs.m_val & index_mask)); + } + + operator unsigned int () const { + return m_val & index_mask; + } + + operator unsigned long int () const { + return (unsigned long int)(m_val & index_mask); + } + + operator int () const { + return int(m_val & index_mask); + } + + operator long int () const { + return (long int)(m_val & index_mask); + } + + bool + IsEmpty( + ) const { + return ((m_val & index_mask) == (empty_index & index_mask)); + } + + + static + CTR_TaggedIndex + Empty( + ) { + return CTR_TaggedIndex(); + } + + void + Invalidate( + ) { + m_val = (empty_tag << tag_shift) | (empty_index & index_mask); + } + + + unsigned int + Tag ( + ) const { + return m_val >> tag_shift; + } + + void + SetTag( + unsigned int tag + ) { + m_val = (m_val & index_mask) | ((tag << tag_shift) & (~index_mask)); + } + + void + EmptyTag( + ) { + m_val = (m_val & index_mask) | ((empty_tag << tag_shift) & (~index_mask)); + } + + bool + IsEmptyTag( + ) const { + return (Tag() == Empty().Tag()); + } + + // functionals + + struct greater : std::binary_function + { + bool + operator()( + const CTR_TaggedIndex& a, + const CTR_TaggedIndex& b + ) const { + return (int(a) > int(b)); + } + }; + + +private : + CTR_TaggedIndex( + const CTR_TaggedIndex *index + ) {}; + + unsigned int m_val; + + +}; + +#endif + diff --git a/intern/container/CTR_TaggedSetOps.h b/intern/container/CTR_TaggedSetOps.h new file mode 100644 index 00000000000..0a0367ec673 --- /dev/null +++ b/intern/container/CTR_TaggedSetOps.h @@ -0,0 +1,300 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_TaggedSetOps_h +#define NAN_INCLUDED_LOD_TaggedSetOps_h + +#include "MEM_NonCopyable.h" +#include + +/** + * This class contains some utility functions for finding the intersection, + * union, and difference of a collection of stl vector of indices into + * a set of primitives. + * + * These are mainly used as helper functions in the decimation and bsp + * libraries. + * + * This template class assumes that each value of type IndexType encountered + * in the list is a valid index into an array of primitives. This is not + * checked at run-time and is left to the user to insure. Prmitives of + * type ObjectType must have the following public methods to be used by + * this template class: + * + * int + * OpenTag(void) --- return a persistent tag value for the primitive + * + * void + * SetOpenTag(int bla) --- set the persistent tag value for this primitive to bla. + * + * bool + * SelectTag() --- return a persistent boolean tag for this primitive + * + * void + * SetSelectTag(bool bla) --- set the persistent boolean tag for this primitive to bla. + * + * Here persistent means that the tag should be associated with the object for the + * entire lifetime of the primitive. Again none of this stuff is enforced you have + * to make sure that your primitives do the right thing. Often these tags can be + * cunningly stowed away inside some of the spare bits in the primitive. See + * CTR_TaggedIndex for such a class. + * + */ + +template + +class CTR_TaggedSetOps : public MEM_NonCopyable { + +public : + + static + void + Intersect( + const std::vector< std::vector > &index_list, + std::vector &primitives, + std::vector &output, + unsigned int mask, + unsigned int shift + ) { + + // iterate through vectors in index_list + // iterate through individual members of each vector + // mark each obejct that the index points to + + typename std::vector< std::vector >::const_iterator + last_vector = index_list.end(); + typename std::vector< std::vector >::const_iterator + start_vector = index_list.begin(); + + // FIXME some temporary space + + std::vector temp_union; + temp_union.reserve(64); + + int tag_num = 0; + + for (; start_vector != last_vector; ++start_vector) { + + typename std::vector::const_iterator + last_index = start_vector->end(); + typename std::vector::const_iterator + start_index = start_vector->begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + + if (!prim.OpenTag()) { + // compute the union + temp_union.push_back(*start_index); + } + int tag = prim.OpenTag(); + tag = (tag & mask) >> shift; + tag += 1; + prim.SetOpenTag((prim.OpenTag() & ~mask)| ((tag << shift) & mask)); + } + + ++tag_num; + } + + // now iterate through the union and pull out all those with the right tag + + typename std::vector::const_iterator last_index = + temp_union.end(); + typename std::vector::const_iterator start_index = + temp_union.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + + if (prim.OpenTag() == tag_num) { + //it's part of the intersection! + + output.push_back(*start_index); + // because we're iterating through the union + // it's safe to remove the tag at this point + + prim.SetOpenTag(prim.OpenTag() & ~mask); + } + } + }; + + // note not a strict set intersection! + // if x appears twice in b and is part of the intersection + // it will appear twice in the intersection + + static + void + IntersectPair( + const std::vector &a, + const std::vector &b, + std::vector &primitives, + std::vector &output + ) { + + typename std::vector::const_iterator last_index = + a.end(); + typename std::vector::const_iterator start_index = + a.begin(); + + for (; start_index != last_index; ++start_index) { + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(true); + } + last_index = b.end(); + start_index = b.begin(); + + for (; start_index != last_index; ++start_index) { + ObjectType & prim = primitives[*start_index]; + if (prim.SelectTag()) { + output.push_back(*start_index); + } + } + // deselect + last_index = a.end(); + start_index = a.begin(); + + for (; start_index != last_index; ++start_index) { + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(false); + } + }; + + + static + void + Union( + std::vector< std::vector > &index_list, + std::vector &primitives, + std::vector &output + ) { + + // iterate through vectors in index_list + // iterate through individual members of each vector + // mark each obejct that the index points to + + typename std::vector< std::vector >::const_iterator + last_vector = index_list.end(); + typename std::vector< std::vector >::iterator + start_vector = index_list.begin(); + + for (; start_vector != last_vector; ++start_vector) { + + typename std::vector::const_iterator + last_index = start_vector->end(); + typename std::vector::iterator + start_index = start_vector->begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + + if (!prim.SelectTag()) { + // compute the union + output.push_back(*start_index); + prim.SetSelectTag(true); + } + } + } + + // now iterate through the union and reset the tags + + typename std::vector::const_iterator last_index = + output.end(); + typename std::vector::iterator start_index = + output.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(false); + } + } + + + static + void + Difference( + std::vector< IndexType> &a, + std::vector< IndexType> &b, + std::vector &primitives, + std::vector< IndexType> &output + ) { + + // iterate through b mark all + // iterate through a and add to output all unmarked + + typename std::vector::const_iterator last_index = + b.end(); + typename std::vector::iterator start_index = + b.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(true); + } + + last_index = a.end(); + start_index = a.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + if (!prim.SelectTag()) { + output.push_back(*start_index); + } + } + + // clean up the tags + + last_index = b.end(); + start_index = b.begin(); + + for (; start_index != last_index; ++start_index) { + + ObjectType & prim = primitives[*start_index]; + prim.SetSelectTag(false); + } + }; + +private : + + // private constructor - this class is not meant for + // instantiation + + CTR_TaggedSetOps(); + +}; + +#endif + diff --git a/intern/container/CTR_UHeap.h b/intern/container/CTR_UHeap.h new file mode 100644 index 00000000000..a7fc33387ee --- /dev/null +++ b/intern/container/CTR_UHeap.h @@ -0,0 +1,305 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * @author Laurence + * @mainpage CTR_UHeap an updatable heap template class (also + * known as an updatable priority queue) + * + * Todo: Make CTR_UHeapable a template class with m_key the + * template parameter, so that arbitrary value types with + * operators (=,>) defined can be used. + * + */ + +#ifndef NAN_INCLUDED_CTR_UHeap_h +#define NAN_INCLUDED_CTR_UHeap_h + +#include + +#include "MEM_NonCopyable.h" + +class CTR_UHeapable { + +public : + int & + HeapPos( + ){ + return m_ind; + }; + float & + HeapKey( + ) { + return m_key; + }; + + const + float & + HeapKey( + ) const { + return m_key; + }; + + const + int & + HeapPos( + ) const { + return m_ind; + }; + +private : + + float m_key; + int m_ind; + +protected : + + CTR_UHeapable( + ) : m_key (0), + m_ind (0) + { + }; + + ~CTR_UHeapable( + ){ + }; +}; + +template +class CTR_UHeap : public MEM_NonCopyable +{ + +public: + + static + CTR_UHeap * + New( + ) { + return new CTR_UHeap(); + } + + void + MakeHeap( + HeapType *base + ) { + int i; + int start = Parent(m_vector.size()-1); + for (i = start; i >=0; --i) { + DownHeap(base,i); + } + }; + + void + Insert( + HeapType *base, + int elem + ) { + // add element to vector + m_vector.push_back(elem); + base[elem].HeapPos() = m_vector.size()-1; + + // push the element up the heap + UpHeap(base,m_vector.size()-1); + } + + // access to the vector for initial loading of elements + + std::vector & + HeapVector( + ) { + return m_vector; + }; + + + void + Remove( + HeapType *base, + int i + ) { + + // exchange with last element - pop last + // element and move up or down the heap as appropriate + if (m_vector.empty()) { + assert(false); + } + + if (i != int(m_vector.size())-1) { + + Swap(base,i,m_vector.size() - 1); + m_vector.pop_back(); + + if (!m_vector.empty()) { + UpHeap(base,i); + DownHeap(base,i); + } + } else { + m_vector.pop_back(); + } + } + + int + Top( + ) const { + if (m_vector.empty()) return -1; + return m_vector[0]; + } + + + void + SC_Heap( + HeapType *base + ) { + int i; + for (i = 1; i < int(m_vector.size()) ; i++) { + + CTR_UHeapable * elem = base + m_vector[i]; + CTR_UHeapable * p_elem = base + m_vector[Parent(i)]; + + assert(p_elem->HeapKey() >= elem->HeapKey()); + assert(elem->HeapPos() == i); + } + + }; + + + ~CTR_UHeap( + ) { + }; + + +private: + + CTR_UHeap( + ) { + }; + + + std::vector m_vector; + +private: + void + Swap( + HeapType *base, + int i, + int j + ){ + std::swap(m_vector[i],m_vector[j]); + + CTR_UHeapable *heap_i = base + m_vector[i]; + CTR_UHeapable *heap_j = base + m_vector[j]; + + // Exchange heap positions + heap_i->HeapPos() = i; + heap_j->HeapPos() = j; + } + + int + Parent( + unsigned int i + ) { + return (i-1) >> 1; + } + int + Left( + int i + ) { + return (i<<1)+1; + } + + int + Right( + int i + ) { + return (i<<1)+2; + } + + float + HeapVal( + HeapType *base, + int i + ) { + return base[m_vector[i]].HeapKey(); + } + + void + DownHeap( + HeapType *base, + int i + ) { + int heap_size = m_vector.size(); + + int l = Left(i); + int r = Right(i); + + int largest; + if (l < heap_size && HeapVal(base,l) > HeapVal(base,i)) { + largest = l; + } else { + largest = i; + } + + if (r < heap_size && HeapVal(base,r) > HeapVal(base,largest)) { + largest = r; + } + + if (largest != i) { + // exchange i and largest + Swap(base,i,largest); + DownHeap(base,largest); + } + } + + void + UpHeap( + HeapType *base, + int i + ) { + + // swap parents untill it's found a place in the heap < it's parent or + // top of heap + + while (i > 0) { + int p = Parent(i); + if (HeapVal(base,i) < HeapVal(base,p)) { + break; + } + Swap(base,p,i); + i = p; + } + } +}; + +#endif + diff --git a/intern/container/Makefile b/intern/container/Makefile new file mode 100644 index 00000000000..48343612ef2 --- /dev/null +++ b/intern/container/Makefile @@ -0,0 +1,52 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# container main makefile. +# + +include nan_definitions.mk + +LIBNAME = container +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_CONTAINER) ] || mkdir $(NAN_CONTAINER) + @[ -d $(NAN_CONTAINER)/include ] || mkdir $(NAN_CONTAINER)/include + @[ -d $(NAN_CONTAINER)/lib ] || mkdir $(NAN_CONTAINER)/lib + @[ -d $(NAN_CONTAINER)/lib/debug ] || mkdir $(NAN_CONTAINER)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libcontainer.a $(NAN_CONTAINER)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libcontainer.a $(NAN_CONTAINER)/lib/debug + @../tools/cpifdiff.sh *.h $(NAN_CONTAINER)/include/ + diff --git a/intern/container/SConscript b/intern/container/SConscript new file mode 100644 index 00000000000..d05104da562 --- /dev/null +++ b/intern/container/SConscript @@ -0,0 +1,7 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') +incs = '.' + +env.BlenderLib ('blender_CTR', sources, Split(incs) , [], libtype='intern', priority = 10 ) diff --git a/intern/container/intern/CTR_List.cpp b/intern/container/intern/CTR_List.cpp new file mode 100644 index 00000000000..9cbb384c835 --- /dev/null +++ b/intern/container/intern/CTR_List.cpp @@ -0,0 +1,153 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "CTR_List.h" + + +CTR_Link:: +CTR_Link( +) : + m_next(0), + m_prev(0) +{ +} + +CTR_Link:: +CTR_Link( + CTR_Link *next, + CTR_Link *prev +) : + m_next(next), + m_prev(prev) +{ +} + + CTR_Link * +CTR_Link:: +getNext( +) const { + return m_next; +} + + CTR_Link * +CTR_Link:: +getPrev( +) const { + return m_prev; +} + + bool +CTR_Link:: +isHead( +) const { + return m_prev == 0; +} + + bool +CTR_Link:: +isTail( +) const { + return m_next == 0; +} + + void +CTR_Link:: +insertBefore( + CTR_Link *link +) { + m_next = link; + m_prev = link->m_prev; + m_next->m_prev = this; + m_prev->m_next = this; +} + + void +CTR_Link:: +insertAfter( + CTR_Link *link +) { + m_next = link->m_next; + m_prev = link; + m_next->m_prev = this; + m_prev->m_next = this; +} + + void +CTR_Link:: +remove( +) { + m_next->m_prev = m_prev; + m_prev->m_next = m_next; +} + + +CTR_List:: +CTR_List( +) : + m_head(&m_tail, 0), + m_tail(0, &m_head) +{ +} + + CTR_Link * +CTR_List:: +getHead( +) const { + return m_head.getNext(); +} + + CTR_Link * +CTR_List:: +getTail( +) const { + return m_tail.getPrev(); +} + + void +CTR_List:: +addHead( + CTR_Link *link +) { + link->insertAfter(&m_head); +} + + void +CTR_List:: +addTail( + CTR_Link *link +) { + link->insertBefore(&m_tail); +} + diff --git a/intern/container/intern/Makefile b/intern/container/intern/Makefile new file mode 100644 index 00000000000..292df5b7cbc --- /dev/null +++ b/intern/container/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# container intern Makefile +# + +LIBNAME = container +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I.. + diff --git a/intern/container/make/msvc_6_0/container.dsp b/intern/container/make/msvc_6_0/container.dsp new file mode 100644 index 00000000000..2ccf1f0a384 --- /dev/null +++ b/intern/container/make/msvc_6_0/container.dsp @@ -0,0 +1,133 @@ +# Microsoft Developer Studio Project File - Name="container" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=container - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "container.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "container.mak" CFG="container - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "container - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "container - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "container - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\container" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\container" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../../../obj/windows/intern/container/libcontainer.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\container\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\container\*.lib ..\..\..\..\..\lib\windows\container\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "container - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\container\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\container\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\container\debug\libcontainer.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\container\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\container\debug\*.lib ..\..\..\..\..\lib\windows\container\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\container\debug\vc60.* ..\..\..\..\..\lib\windows\container\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "container - Win32 Release" +# Name "container - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\CTR_List.cpp + +!IF "$(CFG)" == "container - Win32 Release" + +# ADD CPP /I "../extern" /I "../../" + +!ELSEIF "$(CFG)" == "container - Win32 Debug" + +# ADD CPP /I "../../" + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\CTR_List.h +# End Source File +# Begin Source File + +SOURCE=..\..\CTR_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\CTR_TaggedIndex.h +# End Source File +# Begin Source File + +SOURCE=..\..\CTR_TaggedSetOps.h +# End Source File +# Begin Source File + +SOURCE=..\..\CTR_UHeap.h +# End Source File +# End Target +# End Project diff --git a/intern/container/make/msvc_6_0/container.dsw b/intern/container/make/msvc_6_0/container.dsw new file mode 100644 index 00000000000..13092e3c427 --- /dev/null +++ b/intern/container/make/msvc_6_0/container.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "container"=.\container.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/container/make/msvc_7_0/container.sln b/intern/container/make/msvc_7_0/container.sln new file mode 100644 index 00000000000..16ce8e35563 --- /dev/null +++ b/intern/container/make/msvc_7_0/container.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "container", "container.vcproj", "{E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}.Debug.ActiveCfg = Debug|Win32 + {E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}.Debug.Build.0 = Debug|Win32 + {E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}.Release.ActiveCfg = Release|Win32 + {E9E5B187-2E50-4DD7-9577-327FE6C9E6B0}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/container/make/msvc_7_0/container.vcproj b/intern/container/make/msvc_7_0/container.vcproj new file mode 100644 index 00000000000..2aefffb6a60 --- /dev/null +++ b/intern/container/make/msvc_7_0/container.vcproj @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/decimation/CMakeLists.txt b/intern/decimation/CMakeLists.txt new file mode 100644 index 00000000000..3b7f428c9b9 --- /dev/null +++ b/intern/decimation/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . ../moto/include ../container ../memutil) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_decimation "${SRC}" "${INC}") +#, libtype=['core','common','player'], priority = [10, 20, 25] ) diff --git a/intern/decimation/Makefile b/intern/decimation/Makefile new file mode 100644 index 00000000000..7bf645a39c9 --- /dev/null +++ b/intern/decimation/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# decimation main makefile. +# + +include nan_definitions.mk + +LIBNAME = decimation +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_DECIMATION) ] || mkdir $(NAN_DECIMATION) + @[ -d $(NAN_DECIMATION)/include ] || mkdir $(NAN_DECIMATION)/include + @[ -d $(NAN_DECIMATION)/lib ] || mkdir $(NAN_DECIMATION)/lib + @[ -d $(NAN_DECIMATION)/lib/debug ] || mkdir $(NAN_DECIMATION)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libdecimation.a $(NAN_DECIMATION)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libdecimation.a $(NAN_DECIMATION)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_DECIMATION)/lib/libdecimation.a + ranlib $(NAN_DECIMATION)/lib/debug/libdecimation.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_DECIMATION)/include/ + diff --git a/intern/decimation/SConscript b/intern/decimation/SConscript new file mode 100644 index 00000000000..cf199fb3bc5 --- /dev/null +++ b/intern/decimation/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. ../moto/include ../container ../memutil' + +env.BlenderLib ('bf_decimation', sources, Split(incs) , [], libtype=['core','common','player'], priority = [10, 20, 25] ) diff --git a/intern/decimation/extern/LOD_decimation.h b/intern/decimation/extern/LOD_decimation.h new file mode 100644 index 00000000000..6ebce0206f3 --- /dev/null +++ b/intern/decimation/extern/LOD_decimation.h @@ -0,0 +1,116 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * @author Laurence Bourn + * @date 6/7/2001 + * + * This is the external interface for the decimation module. + */ + +#ifndef NAN_INCLUDED_LOD_decimation_h +#define NAN_INCLUDED_LOD_decimation_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * External decimation structure + */ + +typedef struct LOD_Decimation_Info { + float * vertex_buffer; + float * vertex_normal_buffer; + int * triangle_index_buffer; + int vertex_num; + int face_num; + void * intern; +} LOD_Decimation_Info; + +typedef LOD_Decimation_Info* LOD_Decimation_InfoPtr; + +/** + * Create internal mesh representation from + * LOD_Decimation_Info structure. + * @return 1 on successful loading + * @return 0 on failure + * @warning This should be changed to return an enumeration + * detailing the error encountered + */ + +extern int LOD_LoadMesh(LOD_Decimation_InfoPtr info); + +/** + * Allocate and Compute internal data strucures required for + * decimation. + * @return 1 on successful computation of data + * @return 0 on failure + * @warning This should be changed to return an enumeration + * detailing the error encountered + */ + +extern int LOD_PreprocessMesh(LOD_Decimation_InfoPtr info); + +/** + * Once both the stages above have been completed + * this function collapses a single edge in the mesh. + * The LOD_Decimation_Info structure is updated + * to represent the new mesh. + * @return 1 if an edge was collapsed. + * @return 0 if no suitable edge was found to be collapsable + * You should stop calling this method in this case + * @warning Do not expect that the order of polygons, vertices or + * vertex normals will be preserved by this operation. This function + * returns a packed array of polygons and vertices and so necessarily + * the order will be different. This means you should not expect to + * find the same polygon in the same place in the polygon array after + * this function has been called. + */ + +extern int LOD_CollapseEdge(LOD_Decimation_InfoPtr info); + +/** + * Free any memory the decimation process used + * during the decimation process + * @return 1 if internal data successfully freed + * @return 0 if no data was freed + */ + +extern int LOD_FreeDecimationData(LOD_Decimation_InfoPtr); + +#ifdef __cplusplus +} +#endif + +#endif // NAN_INCLUDED_LOD_decimation_h + diff --git a/intern/decimation/intern/LOD_DecimationClass.h b/intern/decimation/intern/LOD_DecimationClass.h new file mode 100644 index 00000000000..1a3e8dd3620 --- /dev/null +++ b/intern/decimation/intern/LOD_DecimationClass.h @@ -0,0 +1,117 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_DecimationClass_h +#define NAN_INCLUDED_LOD_DecimationClass_h + +#include "MEM_SmartPtr.h" +#include "MEM_NonCopyable.h" + +#include "LOD_ManMesh2.h" +#include "LOD_QSDecimator.h" +#include "LOD_ExternNormalEditor.h" +#include "../extern/LOD_decimation.h" +#include "LOD_ExternBufferEditor.h" + + +class LOD_DecimationClass : public MEM_NonCopyable +{ +public : + + enum { + e_not_loaded, + e_loaded, + e_preprocessed + } m_e_decimation_state; + + + static + LOD_DecimationClass * + New( + LOD_Decimation_InfoPtr extern_info + ) { + // create everything + + MEM_SmartPtr output(new LOD_DecimationClass()); + MEM_SmartPtr mesh(LOD_ManMesh2::New()); + MEM_SmartPtr extern_editor(LOD_ExternBufferEditor::New(extern_info)); + + if (mesh == NULL || extern_editor == NULL) return NULL; + MEM_SmartPtr normals(LOD_ExternNormalEditor::New(extern_info,mesh.Ref())); + + if (normals == NULL) return NULL; + MEM_SmartPtr decimator(LOD_QSDecimator::New( + mesh.Ref(), + normals.Ref(), + extern_editor.Ref() + )); + if (decimator == NULL || output == NULL) return NULL; + + output->m_mesh = mesh.Release(); + output->m_decimator = decimator.Release(); + output->m_normals = normals.Release(); + output->m_extern_editor = extern_editor.Release(); + + return output.Release(); + } + + LOD_ManMesh2 & + Mesh( + ){ + return m_mesh.Ref(); + } + + LOD_QSDecimator & + Decimator( + ) { + return m_decimator.Ref(); + } + + LOD_ExternNormalEditor & + FaceEditor( + ){ + return m_normals.Ref(); + } + +private : + + LOD_DecimationClass( + ) : m_e_decimation_state(e_not_loaded) { + }; + + MEM_SmartPtr m_mesh; + MEM_SmartPtr m_decimator; + MEM_SmartPtr m_normals; + MEM_SmartPtr m_extern_editor; +}; + +#endif + diff --git a/intern/decimation/intern/LOD_EdgeCollapser.cpp b/intern/decimation/intern/LOD_EdgeCollapser.cpp new file mode 100644 index 00000000000..86b2fbaf423 --- /dev/null +++ b/intern/decimation/intern/LOD_EdgeCollapser.cpp @@ -0,0 +1,413 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_EdgeCollapser.h" + +#include "LOD_ManMesh2.h" +#include "CTR_TaggedSetOps.h" +#include +#include + + +using namespace std; + + + LOD_EdgeCollapser * +LOD_EdgeCollapser:: +New( +){ + return new LOD_EdgeCollapser(); +} + + + bool +LOD_EdgeCollapser:: +TJunctionTest( + LOD_ManMesh2 &mesh, + vector &e_v0v1, + LOD_EdgeInd collapse_edge +){ + + // we need to copy the egdes in e_v0v1 from the mesh + // into a new buffer -> we are going to modify them + + int original_size = e_v0v1.size(); + if (original_size == 0) return true; + + vector &edge_set = mesh.EdgeSet(); + + LOD_VertexInd c_v0 = edge_set[collapse_edge].m_verts[0]; + LOD_VertexInd c_v1 = edge_set[collapse_edge].m_verts[1]; + + vector temp_edges; + temp_edges.reserve(e_v0v1.size()); + + vector::iterator edge_it = e_v0v1.begin(); + vector::const_iterator edge_end = e_v0v1.end(); + + for (;edge_it != edge_end; ++edge_it) { + temp_edges.push_back(edge_set[*edge_it]); + } + + // in the copied edges replace all instances of c_v0 with c_v1 + + vector::iterator e_it = temp_edges.begin(); + vector::const_iterator e_it_end = temp_edges.end(); + + for (; e_it != e_it_end; ++e_it) { + + if (e_it->m_verts[0] == c_v0) { + e_it->m_verts[0] = c_v1; + } + if (e_it->m_verts[1] == c_v0) { + e_it->m_verts[1] = c_v1; + } + + // normalize the edge + if (int(e_it->m_verts[0]) > int(e_it->m_verts[1])) { + LOD_EdgeInd temp = e_it->m_verts[0]; + e_it->m_verts[0] = e_it->m_verts[1]; + e_it->m_verts[1] = temp; + } + } + + // sort the edges using the edge less functional + + sort(temp_edges.begin(),temp_edges.end(),LOD_EdgeCollapser::less()); + // count the unique edges. + + e_it = temp_edges.begin(); + e_it_end = temp_edges.end(); + + int coincedent_edges = 0; + + vector::const_iterator last_edge = e_it; + ++e_it; + + for (; e_it != e_it_end; ++e_it) { + + if ((e_it->m_verts[0] == last_edge->m_verts[0]) && + (e_it->m_verts[1] == last_edge->m_verts[1]) + ) { + ++coincedent_edges; + } + last_edge = e_it; + } + + // now if the collapse edge is a boundary edges + // then we are alloved at most one coincedent edge + + // otherwise at most 2 coincedent edges + + if (edge_set[collapse_edge].BoundaryEdge()) { + return (coincedent_edges > 1); + } else { + return (coincedent_edges > 2); + } + + +} + + + + bool +LOD_EdgeCollapser:: +CollapseEdge( + LOD_EdgeInd ei, + LOD_ManMesh2 &mesh, + vector & degenerate_edges, + vector & degenerate_faces, + vector & degenerate_vertices, + vector & new_edges, + vector & update_faces, + vector & update_vertices +){ + + vector &verts = mesh.VertexSet(); + vector &edges = mesh.EdgeSet(); + vector &faces = mesh.FaceSet(); + + // shouldn't do this (use mesh interface instead!) + LOD_VertexInd v0_ind = edges[ei].m_verts[0]; + LOD_VertexInd v1_ind = edges[ei].m_verts[1]; +#if 0 + LOD_Vertex &v0 = verts[v0_ind]; + LOD_Vertex &v1 = verts[v1_ind]; +#endif + vector > e_v01(2); + e_v01[0].reserve(32); + e_v01[1].reserve(32); + + mesh.VertexEdges(v0_ind,e_v01[0]); + mesh.VertexEdges(v1_ind,e_v01[1]); + + + // compute the union of e_v0 and e_v1 -> this is the degenerate edges of the collapse + // we remove old edges and replace edges inside the collapse zone with new ones + + CTR_TaggedSetOps::Union(e_v01,edges,degenerate_edges); + + vector< vector > p_v01(2); + p_v01[0].reserve(32); + p_v01[1].reserve(32); + + mesh.VertexFaces(v0_ind,p_v01[0]); + mesh.VertexFaces(v1_ind,p_v01[1]); + + // compute the union of p_v0 anf p_v1 + vector p_v0v1; + p_v0v1.reserve(32); + + CTR_TaggedSetOps::Union(p_v01,faces,p_v0v1); + + // compute the union of all the edges in p_v0v1 this is the collapse zone + + vector > e_input_vectors(p_v0v1.size()); + + vector::iterator p_v0v1_end = p_v0v1.end(); + vector::iterator p_v0v1_start = p_v0v1.begin(); + + vector >::iterator vector_insert_it = e_input_vectors.begin(); + + for (;p_v0v1_start != p_v0v1_end; ++p_v0v1_start , ++vector_insert_it) { + mesh.FaceEdges(*p_v0v1_start,*vector_insert_it); + } + + vector collapse_zone; + collapse_zone.reserve(32); + + CTR_TaggedSetOps::Union(e_input_vectors,edges,collapse_zone); + + // compute the ring edges = collpase_zone - e_v0v1 + + vector edge_ring; + edge_ring.reserve(32); + + CTR_TaggedSetOps::Difference(collapse_zone,degenerate_edges,edges,edge_ring); + + // T Junction test + ////////////////// + // At this point we check to see if any of the polygons + // in p_v0v1 are coninceddent - this leads + // to errors later on if we try and insert a polygon + // into the mesh to an edge which already has 2 polygons. + + // not that t junctions occur naturally from edge collapses + // and are not just the result of coincedent polygons + // for example consider collapsing an edge that forms part + // of a triangular bottle neck. + + // Really we need to make sure that we don't create t-junctions. + + // I think that a sufficient test is to check the number of + // coincedent edge pairs after a collapse. If it is more than 2 + // then collapsing the edge may result in an undeleted edge + // sharing more than 2 polygons. This test probably is too + // restictive though. + + // To perform this test we need to make a copy of the edges + // in e_v0v1. We then apply the contraction to these edge + // copies. Sort them using a function that places coincedent + // edges next to each other. And then count the number + // of coincedent pairs. + + // Of course we have to do this test before we change any of the + // mesh -> so we can back out safely. + + if (TJunctionTest(mesh,degenerate_edges,ei)) return false; + + // Compute the set of possibly degenerate vertices + // this is the union of all the vertices of polygons + // of v0 and v1 + + vector::iterator face_it = p_v0v1.begin(); + vector::const_iterator face_end = p_v0v1.end(); + + + vector > p_v0v1_vertices(p_v0v1.size()); + + for (int i = 0; face_it != face_end; ++face_it, ++i) { + mesh.FaceVertices(*face_it,p_v0v1_vertices[i]); + } + + vector vertex_ring; + vertex_ring.reserve(32); + + CTR_TaggedSetOps::Union(p_v0v1_vertices,verts,vertex_ring); + + // remove all the internal edges e_v0v1 from the mesh. + // for each edge remove the egde from it's vertices edge lists. + + vector::iterator edge_it = degenerate_edges.begin(); + vector::const_iterator edge_end = degenerate_edges.end(); + + for (; !(edge_it == edge_end); ++edge_it) { + + LOD_EdgeInd ed = (*edge_it); + LOD_Edge & edge = edges[ed];//*edge_it]; + + verts[edge.m_verts[0]].RemoveEdge(ed); + verts[edge.m_verts[1]].RemoveEdge(ed); + } + + // we postpone deletion of the internal edges untill the end + // this is because deleting edges invalidates all of the + // EdgeInd vectors above. + + + // now untie all the polygons in p_v0v1 from the edge ring + + // select all polygons in p_v0v1 + + face_it = p_v0v1.begin(); + face_end = p_v0v1.end(); + + for (;face_it != face_end; ++face_it) { + faces[*face_it].SetSelectTag(true); + } + + edge_it = edge_ring.begin(); + edge_end = edge_ring.end(); + + for (;edge_it != edge_end; ++edge_it) { + LOD_Edge & edge = edges[*edge_it]; + + // presumably all edges in edge_ring point to at least + // one polygon from p_v0v1 + + if (!edge.m_faces[0].IsEmpty() && faces[edge.m_faces[0]].SelectTag()) { + edge.m_faces[0].Invalidate(); + } + + if (!edge.m_faces[1].IsEmpty() && faces[edge.m_faces[1]].SelectTag()) { + edge.m_faces[1].Invalidate(); + } + } + + // deselect the faces + + face_it = p_v0v1.begin(); + face_end = p_v0v1.end(); + + for (;face_it != face_end; ++face_it) { + faces[*face_it].SetSelectTag(false); + } + + // perform the edge collapse + //////////////////////////// + + // iterate through the polygons of p_v0 and replace the vertex + // index v0 with v1 + + face_it = p_v01[0].begin(); + face_end = p_v01[0].end(); + + for (;face_it != face_end; ++face_it) { + faces[*face_it].SwapVertex(v0_ind,v1_ind); + } + + face_it = p_v0v1.begin(); + face_end = p_v0v1.end(); + + for (;face_it != face_end; ++face_it) { + if (faces[*face_it].Degenerate()) { + degenerate_faces.push_back(*face_it); + } else { + update_faces.push_back(*face_it); + } + } + + // Add all the non-degenerate faces back into the + // mesh. Get a record of the new edges created in + // this process. + + face_it = update_faces.begin(); + face_end = update_faces.end(); + + for (;face_it != face_end; ++face_it) { + mesh.ConnectTriangle(*face_it,new_edges); + } + + // degenerate ring primitives + ///////////////////////////// + + // we now need to examine each of the edges on the ring + // and work out if they are degenerate - if so we attempt + // to delete them -> add them to the other edges to delete + // in e_v0v1 + + edge_it = edge_ring.begin(); + edge_end = edge_ring.end(); + + for (;edge_it != edge_end; ++edge_it) { + if (edges[*edge_it].Degenerate()) { + degenerate_edges.push_back(*edge_it); + } + } + + // do the same for the ring vertices. + + vector::iterator vertex_it = vertex_ring.begin(); + vector::const_iterator vertex_end = vertex_ring.end(); + + for (;vertex_it != vertex_end; ++vertex_it) { + if (verts[*vertex_it].Degenerate()) { + degenerate_vertices.push_back(*vertex_it); + } else { + update_vertices.push_back(*vertex_it); + } + } + + // we now know all the degenerate primitives + // and the new primitives we have inserted into the mesh + + // We now delete the mesh primitives, mesh.DeleteXXXXXX() methods + // assume that the index vectors are sorted into descending order. + // we do that now. + + sort(degenerate_edges.begin(),degenerate_edges.end(),LOD_EdgeInd::greater()); + sort(degenerate_faces.begin(),degenerate_faces.end(),LOD_FaceInd::greater()); + sort(degenerate_vertices.begin(),degenerate_vertices.end(),LOD_VertexInd::greater()); + + + return true; + +} + +LOD_EdgeCollapser:: +LOD_EdgeCollapser( +){ + // nothing to do +} diff --git a/intern/decimation/intern/LOD_EdgeCollapser.h b/intern/decimation/intern/LOD_EdgeCollapser.h new file mode 100644 index 00000000000..482eccacec2 --- /dev/null +++ b/intern/decimation/intern/LOD_EdgeCollapser.h @@ -0,0 +1,116 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLDUED_EgdeCollapser_h +#define NAN_INCLDUED_EgdeCollapser_h + +// This is a helper class that collapses edges of a 2 - manifold mesh. + +#include "LOD_MeshPrimitives.h" +#include "MEM_NonCopyable.h" +#include +#include + +class LOD_ManMesh2; + +class LOD_EdgeCollapser +: public MEM_NonCopyable +{ + +public : + + static + LOD_EdgeCollapser * + New( + ); + + // returns via arguments the set of modified + // verts,edges and faces. + + bool + CollapseEdge( + LOD_EdgeInd ei, + LOD_ManMesh2 &mesh, + std::vector & degenerate_edges, + std::vector & degenerate_faces, + std::vector & degenerate_vertices, + std::vector & new_edges, + std::vector & update_faces, + std::vector & update_vertices + ); + +private : + + LOD_EdgeCollapser( + ); + + // Test to see if the result of collapsing the + // edge produces 2 junctions in the mesh i.e. where + // an edge is shared by more than 2 polygons + + // We count the number of coincedent edge pairs that + // result from the collapse of collapse_edge. + + // If collapse edge is a boundary edge then the number of + // coincedent pairs should be 1 + // else it should be 2. + + bool + TJunctionTest( + LOD_ManMesh2 &mesh, + std::vector &e_v0v1, + LOD_EdgeInd collapse_edge + ); + + // here's the definition of the sort function + // we use to determine coincedent edges + + // assumes the edges are normalized i.e. m_verts[0] <= m_verts[1] + + struct less : std::binary_function { + bool + operator()( + const LOD_Edge& a, + const LOD_Edge& b + ) const { + + if (int(a.m_verts[0]) == int(b.m_verts[0])) { + return (int(a.m_verts[1]) < int(b.m_verts[1])); + } else { + return (int(a.m_verts[0]) < int(b.m_verts[0])); + } + } + }; + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_ExternBufferEditor.h b/intern/decimation/intern/LOD_ExternBufferEditor.h new file mode 100644 index 00000000000..9f628c4455b --- /dev/null +++ b/intern/decimation/intern/LOD_ExternBufferEditor.h @@ -0,0 +1,164 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + */ + +#ifndef NAN_INCLUDED_LOD_ExternBufferEditor_h +#define NAN_INCLUDED_LOD_ExternBufferEditor_h + +#include "LOD_MeshPrimitives.h" +#include +#include "LOD_ManMesh2.h" +#include "../extern/LOD_decimation.h" + + +// This class syncs external vertex/face buffers +// with the internal mesh representation during +// decimation. + +class LOD_ExternBufferEditor +{ + +public : + + static + LOD_ExternBufferEditor * + New( + LOD_Decimation_InfoPtr extern_info + ){ + if (extern_info == NULL) return NULL; + return new LOD_ExternBufferEditor(extern_info); + } + + // update the external vertex buffer with vertices + // from the mesh + + void + CopyModifiedVerts( + LOD_ManMesh2 & mesh, + const std::vector & mod_vertices + ){ + + std::vector::const_iterator v_start = mod_vertices.begin(); + std::vector::const_iterator v_end = mod_vertices.end(); + + std::vector & mesh_verts = mesh.VertexSet(); + + float * const extern_vertex_ptr = m_extern_info->vertex_buffer; + + for (; v_start != v_end; ++v_start) { + float * mod_vert = extern_vertex_ptr + int(*v_start)*3; + mesh_verts[*v_start].CopyPosition(mod_vert); + } + } + + // update the external face buffer with faces from the mesh + + void + CopyModifiedFaces( + LOD_ManMesh2 & mesh, + const std::vector & mod_faces + ){ + + std::vector::const_iterator f_start = mod_faces.begin(); + std::vector::const_iterator f_end = mod_faces.end(); + + std::vector &mesh_faces = mesh.FaceSet(); + + int * const extern_face_ptr = m_extern_info->triangle_index_buffer; + + for (; f_start != f_end; ++f_start) { + int *mod_face = extern_face_ptr + 3*int(*f_start); + mesh_faces[*f_start].CopyVerts(mod_face); + } + } + + + // Copy the last vertex over the vertex specified by + // vi. Decrement the size of the vertex array + + void + CopyBackVertex( + LOD_VertexInd vi + ){ + + float * const extern_vertex_ptr = m_extern_info->vertex_buffer; + int * extern_vertex_num = &(m_extern_info->vertex_num); + + float * last_external_vert = extern_vertex_ptr + 3*((*extern_vertex_num) - 1); + float * external_vert = extern_vertex_ptr + 3*int(vi); + + external_vert[0] = last_external_vert[0]; + external_vert[1] = last_external_vert[1]; + external_vert[2] = last_external_vert[2]; + + *extern_vertex_num -=1; + } + + // Copy the last face over the face specified by fi + // Decrement the size of the face array + + void + CopyBackFace( + LOD_FaceInd fi + ) { + int * const extern_face_ptr = m_extern_info->triangle_index_buffer; + int * extern_face_num = &(m_extern_info->face_num); + + int * last_external_face = extern_face_ptr + 3*((*extern_face_num) -1); + int * external_face = extern_face_ptr + 3*int(fi); + external_face[0] = last_external_face[0]; + external_face[1] = last_external_face[1]; + external_face[2] = last_external_face[2]; + + *extern_face_num -=1; + } + + +private : + + LOD_ExternBufferEditor( + LOD_Decimation_InfoPtr extern_info + ) : + m_extern_info (extern_info) + { + } + + LOD_Decimation_InfoPtr const m_extern_info; + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_ExternNormalEditor.cpp b/intern/decimation/intern/LOD_ExternNormalEditor.cpp new file mode 100644 index 00000000000..7c9191b60c7 --- /dev/null +++ b/intern/decimation/intern/LOD_ExternNormalEditor.cpp @@ -0,0 +1,267 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "LOD_ExternNormalEditor.h" +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +using namespace std; + + +LOD_ExternNormalEditor:: +LOD_ExternNormalEditor( + LOD_Decimation_InfoPtr extern_info, + LOD_ManMesh2 &mesh +) : + m_extern_info (extern_info), + m_mesh(mesh) +{ +} + + LOD_ExternNormalEditor * +LOD_ExternNormalEditor:: +New( + LOD_Decimation_InfoPtr extern_info, + LOD_ManMesh2 &mesh +){ + if (extern_info == NULL) return NULL; + + MEM_SmartPtr output(new LOD_ExternNormalEditor(extern_info,mesh)); + + int face_num = mesh.FaceSet().size(); + + MEM_SmartPtr > normals(new vector); + + if (output == NULL || + normals == NULL + ) { + return NULL; + } + + normals->reserve(face_num); + output->m_normals = normals.Release(); + + return output.Release(); +}; + + + void +LOD_ExternNormalEditor:: +Remove( + std::vector &sorted_faces +){ + // assumes a collection of faces sorted in descending order . + + vector & normals = m_normals.Ref(); + + vector::const_iterator it_start = sorted_faces.begin(); + vector::const_iterator it_end = sorted_faces.end(); + + for (; it_start != it_end; ++it_start) { + + if (normals.size() > 0) { + MT_Vector3 temp = normals[*it_start]; + + normals[*it_start] = normals.back(); + normals.back() = temp; + + normals.pop_back(); + } + + // FIXME - throw exception + } +} + + + void +LOD_ExternNormalEditor:: +Add( +){ + MT_Vector3 zero(0.0f,0.0f,0.0f); + m_normals->push_back(zero); +}; + + void +LOD_ExternNormalEditor:: +Update( + std::vector &sorted_faces +){ + vector & normals = m_normals.Ref(); + + vector::const_iterator it_start = sorted_faces.begin(); + vector::const_iterator it_end = sorted_faces.end(); + + const vector &faces = m_mesh.FaceSet(); + + for (; it_start != it_end; ++it_start) { + normals[*it_start] = ComputeNormal(faces[*it_start]); + } +}; + + + + +// vertex normals +///////////////// + + void +LOD_ExternNormalEditor:: +RemoveVertexNormals( + std::vector &sorted_verts +){ + + float * vertex_normals = m_extern_info->vertex_normal_buffer; + + // assumption here that the vertexs normal number corresponds with + // the number of vertices ! + + int vertex_normal_num = m_extern_info->vertex_num; + + vector::const_iterator it_start = sorted_verts.begin(); + vector::const_iterator it_end = sorted_verts.end(); + + for (; it_start != it_end; ++it_start) { + + if (vertex_normal_num > 0) { + float * vertex_normal = vertex_normals + int(*it_start)*3; + float * last_vertex = vertex_normals + ((vertex_normal_num-1)*3); + + MT_Vector3 last_v(last_vertex); + last_v.getValue(vertex_normal); + vertex_normal_num--; + } + + // FIXME - through exception + } +}; + + + + void +LOD_ExternNormalEditor:: +UpdateVertexNormals( + std::vector &sorted_verts +){ + float * vertex_normals = m_extern_info->vertex_normal_buffer; + + vector::const_iterator it_start = sorted_verts.begin(); + vector::const_iterator it_end = sorted_verts.end(); + + for (; it_start != it_end; ++it_start) { + MT_Vector3 temp = ComputeVertexNormal(*it_start); + float * vertex_normal = vertex_normals + int(*it_start)*3; + temp.getValue(vertex_normal); + } +} + +// Editor specific methods +////////////////////////// + + void +LOD_ExternNormalEditor:: +BuildNormals( +) { + const vector &faces = m_mesh.FaceSet(); + vector & normals = m_normals.Ref(); + + int face_num = faces.size(); + int cur_face = 0; + + for (; cur_face < face_num; ++cur_face) { + + MT_Vector3 new_normal = ComputeNormal(faces[cur_face]); + normals.push_back(new_normal); + } +} + +const + MT_Vector3 +LOD_ExternNormalEditor:: +ComputeNormal( + const LOD_TriFace &face +) const { + + const vector &verts = m_mesh.VertexSet(); + + MT_Vector3 vec1 = + verts[face.m_verts[1]].pos - + verts[face.m_verts[0]].pos; + + MT_Vector3 vec2 = + verts[face.m_verts[2]].pos - + verts[face.m_verts[1]].pos; + + vec1 = vec1.cross(vec2); + + if (!vec1.fuzzyZero()) { + vec1.normalize(); + return (vec1); + } else { + return (MT_Vector3(1.0,0,0)); + } +} + +const + MT_Vector3 +LOD_ExternNormalEditor:: +ComputeVertexNormal( + const LOD_VertexInd v +) const { + + // average the face normals surrounding this + // vertex and normalize + // vector &verts = m_mesh.VertexSet(); /*unused*/ + const vector & face_normals = m_normals.Ref(); + + vector vertex_faces; + vertex_faces.reserve(32); + + m_mesh.VertexFaces(v,vertex_faces); + + MT_Vector3 normal(0,0,0); + + vector::const_iterator face_it = vertex_faces.begin(); + vector::const_iterator face_end = vertex_faces.end(); + + for (; face_it != face_end; ++face_it) { + normal += face_normals[*face_it]; + } + + if (!normal.fuzzyZero()) { + normal.normalize(); + return (normal); + } else { + return (MT_Vector3(1.0,0,0)); + } +} diff --git a/intern/decimation/intern/LOD_ExternNormalEditor.h b/intern/decimation/intern/LOD_ExternNormalEditor.h new file mode 100644 index 00000000000..190ea5bdd8c --- /dev/null +++ b/intern/decimation/intern/LOD_ExternNormalEditor.h @@ -0,0 +1,134 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_ExternNormalEditor_h +#define NAN_INCLUDED_ExternNormalEditor_h + +#include "MEM_NonCopyable.h" +#include "LOD_ManMesh2.h" +#include "MT_Vector3.h" +#include "../extern/LOD_decimation.h" + +class LOD_ExternNormalEditor : public MEM_NonCopyable +{ + +public : + + // Creation + /////////// + + static + LOD_ExternNormalEditor * + New( + LOD_Decimation_InfoPtr, + LOD_ManMesh2 &mesh + ); + + // Property editor interface + //////////////////////////// + + + // Faces + //////// + void + Remove( + std::vector &sorted_faces + ); + + void + Add( + ); + + void + Update( + std::vector &sorted_faces + ); + + const + std::vector & + Normals( + ) const { + return m_normals.Ref(); + }; + + + // vertex normals + ///////////////// + + void + RemoveVertexNormals( + std::vector &sorted_verts + ); + + + void + UpdateVertexNormals( + std::vector &sorted_verts + ); + + // Editor specific methods + ////////////////////////// + + void + BuildNormals( + ); + + +private : + + MEM_SmartPtr > m_normals; + + LOD_ManMesh2 &m_mesh; + LOD_Decimation_InfoPtr m_extern_info; + +private : + + + LOD_ExternNormalEditor( + LOD_Decimation_InfoPtr extern_info, + LOD_ManMesh2 &mesh + ); + + const + MT_Vector3 + ComputeNormal( + const LOD_TriFace &face + ) const ; + + const + MT_Vector3 + ComputeVertexNormal ( + const LOD_VertexInd vi + ) const; +}; + +#endif + diff --git a/intern/decimation/intern/LOD_FaceNormalEditor.cpp b/intern/decimation/intern/LOD_FaceNormalEditor.cpp new file mode 100644 index 00000000000..bb384dca04c --- /dev/null +++ b/intern/decimation/intern/LOD_FaceNormalEditor.cpp @@ -0,0 +1,294 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +// implementation of LOD_FaceNormalEditor.h + +/////////////////////////////////////// +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_FaceNormalEditor.h" + +using namespace std; + +LOD_FaceNormalEditor:: +LOD_FaceNormalEditor( + LOD_ManMesh2 & mesh +) : m_mesh(mesh) { +}; + + LOD_FaceNormalEditor * +LOD_FaceNormalEditor:: +New( + LOD_ManMesh2 &mesh +){ + // build a set of normals of the same size + // as the number of polys in the mesh + + MEM_SmartPtr output(new LOD_FaceNormalEditor(mesh)); + + int face_num = mesh.FaceSet().size(); + + MEM_SmartPtr > normals(new vector); + MEM_SmartPtr > vertex_normals(new vector); + + if (output == NULL || + normals == NULL + ) { + return NULL; + } + + normals->reserve(face_num); + vertex_normals->reserve(mesh.VertexSet().size()); + output->m_normals = normals.Release(); + output->m_vertex_normals = vertex_normals.Release(); + + return output.Release(); +}; + + +// Property editor interface +//////////////////////////// + + void +LOD_FaceNormalEditor:: +Remove( + std::vector &sorted_faces +){ + + // assumes a collection of faces sorted in descending order . + + vector & normals = m_normals.Ref(); + + vector::const_iterator it_start = sorted_faces.begin(); + vector::const_iterator it_end = sorted_faces.end(); + + for (; it_start != it_end; ++it_start) { + + if (normals.size() > 0) { + MT_Vector3 temp = normals[*it_start]; + + normals[*it_start] = normals.back(); + normals.back() = temp; + + normals.pop_back(); + } + + // FIXME - through exception + } +} + + + void +LOD_FaceNormalEditor:: +Add( +){ + MT_Vector3 zero(0.0f,0.0f,0.0f); + m_normals->push_back(zero); +} + + void +LOD_FaceNormalEditor:: +Update( + std::vector &sorted_faces +){ + + vector & normals = m_normals.Ref(); + + vector::const_iterator it_start = sorted_faces.begin(); + vector::const_iterator it_end = sorted_faces.end(); + + const vector &faces = m_mesh.FaceSet(); + + for (; it_start != it_end; ++it_start) { + normals[*it_start] = ComputeNormal(faces[*it_start]); + } +}; + +// vertex normals +///////////////// + + + void +LOD_FaceNormalEditor:: +RemoveVertexNormals( + vector &sorted_verts +){ + vector & vertex_normals = m_vertex_normals.Ref(); + + vector::const_iterator it_start = sorted_verts.begin(); + vector::const_iterator it_end = sorted_verts.end(); + + for (; it_start != it_end; ++it_start) { + + if (vertex_normals.size() > 0) { + MT_Vector3 temp = vertex_normals[*it_start]; + + vertex_normals[*it_start] = vertex_normals.back(); + vertex_normals.back() = temp; + + vertex_normals.pop_back(); + } + + // FIXME - through exception + } +}; + + void +LOD_FaceNormalEditor:: +UpdateVertexNormals( + vector &sorted_verts +){ + vector & vertex_normals = m_vertex_normals.Ref(); + + vector::const_iterator it_start = sorted_verts.begin(); + vector::const_iterator it_end = sorted_verts.end(); + + for (; it_start != it_end; ++it_start) { + vertex_normals[*it_start] = ComputeVertexNormal(*it_start); + } +} + + + +// Editor specific methods +////////////////////////// + + void +LOD_FaceNormalEditor:: +BuildNormals( +){ + + const vector &faces = m_mesh.FaceSet(); + vector & normals = m_normals.Ref(); + + int face_num = faces.size(); + int cur_face = 0; + + for (; cur_face < face_num; ++cur_face) { + + MT_Vector3 new_normal = ComputeNormal(faces[cur_face]); + normals.push_back(new_normal); + } + // now build the vertex normals + + vector & vertex_normals = m_vertex_normals.Ref(); + const vector &verts = m_mesh.VertexSet(); + + int vertex_num = verts.size(); + int cur_vertex = 0; + + for (; cur_vertex < vertex_num; ++cur_vertex) { + MT_Vector3 new_normal = ComputeVertexNormal(cur_vertex); + vertex_normals.push_back(new_normal); + } +} + +const + MT_Vector3 +LOD_FaceNormalEditor:: +ComputeNormal( + const LOD_TriFace &face +) const { + + const vector &verts = m_mesh.VertexSet(); + + MT_Vector3 vec1 = + verts[face.m_verts[1]].pos - + verts[face.m_verts[0]].pos; + + MT_Vector3 vec2 = + verts[face.m_verts[2]].pos - + verts[face.m_verts[1]].pos; + + vec1 = vec1.cross(vec2); + + if (!vec1.fuzzyZero()) { + vec1.normalize(); + return (vec1); + } else { + return (MT_Vector3(1.0,0,0)); + } +} + +const + MT_Vector3 +LOD_FaceNormalEditor:: +ComputeVertexNormal( + const LOD_VertexInd v +) const { + + // average the face normals surrounding this + // vertex and normalize + const vector & face_normals = m_normals.Ref(); + + vector vertex_faces; + vertex_faces.reserve(32); + + m_mesh.VertexFaces(v,vertex_faces); + + MT_Vector3 normal(0,0,0); + + vector::const_iterator face_it = vertex_faces.begin(); + vector::const_iterator face_end = vertex_faces.end(); + + for (; face_it != face_end; ++face_it) { + normal += face_normals[*face_it]; + } + + if (!normal.fuzzyZero()) { + normal.normalize(); + return (normal); + } else { + return (MT_Vector3(1.0,0,0)); + } +} + + + + + + + + + + + + + + + + + + + + diff --git a/intern/decimation/intern/LOD_FaceNormalEditor.h b/intern/decimation/intern/LOD_FaceNormalEditor.h new file mode 100644 index 00000000000..892e1f0fbc7 --- /dev/null +++ b/intern/decimation/intern/LOD_FaceNormalEditor.h @@ -0,0 +1,143 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_FaceNormalEditor_h +#define NAN_INCLUDED_FaceNormalEditor_h + +#include "MEM_NonCopyable.h" +#include "LOD_ManMesh2.h" +#include "MT_Vector3.h" + + +class LOD_FaceNormalEditor : public MEM_NonCopyable +{ + +public : + + // Creation + /////////// + + static + LOD_FaceNormalEditor * + New( + LOD_ManMesh2 &mesh + ); + + // Property editor interface + //////////////////////////// + + + // Faces + //////// + void + Remove( + std::vector &sorted_faces + ); + + void + Add( + ); + + void + Update( + std::vector &sorted_faces + ); + + + // vertex normals + ///////////////// + + void + RemoveVertexNormals( + std::vector &sorted_verts + ); + + + void + UpdateVertexNormals( + std::vector &sorted_verts + ); + + + + const + std::vector & + Normals( + ) const { + return m_normals.Ref(); + }; + + + const + std::vector & + VertexNormals( + ) const { + return m_vertex_normals.Ref(); + }; + + // Editor specific methods + ////////////////////////// + + void + BuildNormals( + ); + + +private : + + MEM_SmartPtr > m_normals; + MEM_SmartPtr > m_vertex_normals; + + LOD_ManMesh2 &m_mesh; + +private : + + + LOD_FaceNormalEditor(LOD_ManMesh2 &mesh); + + const + MT_Vector3 + ComputeNormal( + const LOD_TriFace &face + ) const ; + + const + MT_Vector3 + ComputeVertexNormal ( + const LOD_VertexInd vi + ) const; + + + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_ManMesh2.cpp b/intern/decimation/intern/LOD_ManMesh2.cpp new file mode 100644 index 00000000000..322a48e337b --- /dev/null +++ b/intern/decimation/intern/LOD_ManMesh2.cpp @@ -0,0 +1,621 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_ManMesh2.h" + +#include "MT_assert.h" +#include +#include "LOD_MeshException.h" +#include "CTR_TaggedSetOps.h" +#include "CTR_UHeap.h" +#include "LOD_ExternBufferEditor.h" + + +using namespace std; + +LOD_ManMesh2:: +LOD_ManMesh2( +) : + m_bbox_min(0,0,0), + m_bbox_max(0,0,0) +{ +} + + + LOD_ManMesh2 * +LOD_ManMesh2:: +New( +){ + MEM_SmartPtr output(new LOD_ManMesh2()); + if (output == NULL) return NULL; + + // build the vertex, edge and face sets. + + MEM_SmartPtr > verts(new vector); + MEM_SmartPtr > faces(new vector); + MEM_SmartPtr > edges(new vector); + + if ((faces == NULL) || (edges == NULL) || (verts == NULL)) { + return NULL; + } + + output->m_verts = verts.Release(); + output->m_faces = faces.Release(); + output->m_edges = edges.Release(); + + return output.Release(); +} + +// take ownership of the vertices. + + bool +LOD_ManMesh2:: +SetVertices( + MEM_SmartPtr > verts +){ + + + // take ownership of vertices + m_verts = verts; + + // create a polygon and edge buffer of half the size + // and just use the automatic resizing feature of vector<> + // to worry about the dynamic array resizing + + m_faces->clear(); + m_edges->clear(); + + m_faces->reserve(m_verts->size()/2); + m_edges->reserve(m_verts->size()/2); + + return true; + +} + + +// add a triangle to the mesh + + void +LOD_ManMesh2:: +AddTriangle( + int verts[3] +) { + + MT_assert(verts[0] < int(m_verts->size())); + MT_assert(verts[1] < int(m_verts->size())); + MT_assert(verts[2] < int(m_verts->size())); + + LOD_TriFace face; + face.m_verts[0] = verts[0]; + face.m_verts[1] = verts[1]; + face.m_verts[2] = verts[2]; + + LOD_FaceInd face_index = m_faces->size(); + + m_faces->push_back(face); + + // now work out if any of the directed edges or their + // companion edges exist already. + // We go through the edges associated with each of the given vertices + + // the safest thing to do is iterate through each of the edge sets + // check against each of the 2 other triangle edges to see if they are there + + vector new_edges; + new_edges.reserve(3); + + InsertEdge(verts[0],verts[1],face_index,new_edges); + InsertEdge(verts[1],verts[2],face_index,new_edges); + InsertEdge(verts[2],verts[0],face_index,new_edges); + +} + +// Adds the index of any created edges to new_edges + + bool +LOD_ManMesh2:: +InsertEdge( + const LOD_VertexInd v1, + const LOD_VertexInd v2, + const LOD_FaceInd f, + vector &new_edges +){ + + MT_assert(!v1.IsEmpty()); + MT_assert(!v2.IsEmpty()); + MT_assert(!f.IsEmpty()); + + vector &verts = VertexSet(); + vector &edges = EdgeSet(); + + LOD_EdgeInd e; + + e = FindEdge(v1,v2); + + if (e.IsEmpty()) { + // This edge does not exist -- make a new one + + LOD_Edge temp_e; + temp_e.m_verts[0] = v1; + temp_e.m_verts[1] = v2; + + e = m_edges->size(); + + // set the face ptr for this half-edge + temp_e.m_faces[0] = f; + + m_edges->push_back(temp_e); + + // add the edge index to it's vertices + + verts[v1].AddEdge(e); + verts[v2].AddEdge(e); + + new_edges.push_back(e); + + } else { + + // edge already exists + // insure that there is no polygon already + // attached to the other side of this edge + + // swap the empty face pointer in edge with f + + LOD_Edge &edge = edges[e]; + + edge.SwapFace(LOD_FaceInd::Empty(),f); + } + + + return true; + +} + + void +LOD_ManMesh2:: +ConnectTriangle( + LOD_FaceInd fi, + std::vector & new_edges +){ + + vector &faces = FaceSet(); + + MT_assert(!faces[fi].Degenerate()); + + LOD_TriFace & face = faces[fi]; + + InsertEdge(face.m_verts[0],face.m_verts[1],fi,new_edges); + InsertEdge(face.m_verts[1],face.m_verts[2],fi,new_edges); + InsertEdge(face.m_verts[2],face.m_verts[0],fi,new_edges); +}; + + + + +// geometry access +////////////////// + + vector & +LOD_ManMesh2:: +VertexSet( +) const { + return m_verts.Ref(); +} + + vector & +LOD_ManMesh2:: +FaceSet( +) const { + return m_faces.Ref(); +} + + vector & +LOD_ManMesh2:: +EdgeSet( +) const { + return m_edges.Ref(); +}; + +LOD_ManMesh2:: +~LOD_ManMesh2( +){ + //auto ptr takes care of vertex arrays etc. +} + + LOD_EdgeInd +LOD_ManMesh2:: +FindEdge( + const LOD_VertexInd v1, + const LOD_VertexInd v2 +) { + + vector &verts = VertexSet(); + vector &edges = EdgeSet(); + + LOD_Edge e; + e.m_verts[0] = v1; + e.m_verts[1] = v2; + + vector &v1_edges = verts[v1].m_edges; + vector::const_iterator v1_end = v1_edges.end(); + vector::iterator v1_begin = v1_edges.begin(); + + for (; v1_begin != v1_end; ++v1_begin) { + if (edges[*v1_begin] == e) return *v1_begin; + } + + return LOD_EdgeInd::Empty(); +} + +// face queries +/////////////// + + void +LOD_ManMesh2:: +FaceVertices( + LOD_FaceInd fi, + vector &output +){ + const vector &faces = FaceSet(); + const LOD_TriFace & f = faces[fi]; + + output.push_back(f.m_verts[0]); + output.push_back(f.m_verts[1]); + output.push_back(f.m_verts[2]); +} + + void +LOD_ManMesh2:: +FaceEdges( + LOD_FaceInd fi, + vector &output +){ + const vector &faces = FaceSet(); + vector &edges = EdgeSet(); + vector &verts = VertexSet(); + + const LOD_TriFace & f = faces[fi]; + // intersect vertex edges + + vector & v0_edges = verts[f.m_verts[0]].m_edges; + vector & v1_edges = verts[f.m_verts[1]].m_edges; + vector & v2_edges = verts[f.m_verts[2]].m_edges; + + CTR_TaggedSetOps::IntersectPair(v0_edges,v1_edges,edges,output); + CTR_TaggedSetOps::IntersectPair(v1_edges,v2_edges,edges,output); + CTR_TaggedSetOps::IntersectPair(v2_edges,v0_edges,edges,output); + + MT_assert(output.size() == 3); + if (output.size() != 3) { + LOD_MeshException e(LOD_MeshException::e_non_manifold); + throw(e); + } +} + + +// edge queries +/////////////// + + void +LOD_ManMesh2:: +EdgeVertices( + LOD_EdgeInd ei, + vector &output +){ + const vector &edges = EdgeSet(); + const LOD_Edge & e = edges[ei]; + + output.push_back(e.m_verts[0]); + output.push_back(e.m_verts[1]); +} + + void +LOD_ManMesh2:: +EdgeFaces( + LOD_EdgeInd ei, + vector &output +){ + const vector &edges = EdgeSet(); + const LOD_Edge & e = edges[ei]; + + if (!e.m_faces[0].IsEmpty()) { + output.push_back(e.m_faces[0]); + } + if (!e.m_faces[1].IsEmpty()) { + output.push_back(e.m_faces[1]); + } +} + +// vertex queries +///////////////// + + void +LOD_ManMesh2:: +VertexEdges( + LOD_VertexInd vi, + vector &output +){ + // iterate through the edges of v and push them onto the + // output + + vector &verts = VertexSet(); + + vector & v_edges = verts[vi].m_edges; + vector::iterator v_it = v_edges.begin(); + + for (; v_it != v_edges.end(); ++v_it) { + output.push_back(*v_it); + } +} + + void +LOD_ManMesh2:: +VertexFaces( + LOD_VertexInd vi, + vector &output +){ + const vector &verts = VertexSet(); + vector &edges = EdgeSet(); + vector &faces = FaceSet(); + + const vector &v_edges = verts[vi].m_edges; + vector::const_iterator e_it = v_edges.begin(); + + for (; e_it != v_edges.end(); ++e_it) { + + LOD_Edge &e = edges[*e_it]; + + if ((!e.m_faces[0].IsEmpty()) && (!faces[e.m_faces[0]].SelectTag())) { + output.push_back(e.m_faces[0]); + faces[e.m_faces[0]].SetSelectTag(true); + } + + if ((!e.m_faces[1].IsEmpty()) && (!faces[e.m_faces[1]].SelectTag())) { + output.push_back(e.m_faces[1]); + faces[e.m_faces[1]].SetSelectTag(true); + } + } + + vector::iterator f_it = output.begin(); + + for (; f_it != output.end(); ++f_it) { + faces[*f_it].SetSelectTag(false); + } +}; + + void +LOD_ManMesh2:: +SetBBox( + MT_Vector3 bbox_min, + MT_Vector3 bbox_max +){ + m_bbox_min = bbox_min; + m_bbox_max = bbox_max; +}; + + void +LOD_ManMesh2:: +SC_TriFace( + LOD_FaceInd f +){ + LOD_TriFace face = (*m_faces)[f]; + + // check for unique vertices + + if ( + (face.m_verts[0] == face.m_verts[1]) || + (face.m_verts[1] == face.m_verts[2]) || + (face.m_verts[2] == face.m_verts[0]) + ) { + MT_assert(false); + } + +} + + + void +LOD_ManMesh2:: +SC_EdgeList( + LOD_VertexInd v +){ + vector &edges = EdgeSet(); + vector &verts = VertexSet(); + + vector::iterator e_it = verts[v].m_edges.begin(); + + for (;e_it != verts[v].m_edges.end(); ++e_it) { + MT_assert( (edges[*e_it].m_verts[0] == v) || (edges[*e_it].m_verts[1] == v)); + } + +}; + + void +LOD_ManMesh2:: +DeleteVertex( + LOD_ExternBufferEditor & extern_editor, + LOD_VertexInd v +){ + + vector &edges = EdgeSet(); + vector &verts = VertexSet(); + vector &faces = FaceSet(); + + // need to update all the edge and polygons pointing to + // the last vertex in m_verts + + if (verts.size() == 1) { + verts.clear(); + return; + } + + LOD_VertexInd last = LOD_VertexInd(verts.end() - verts.begin() - 1); + + if (!(last == v)) { + + // we asume that v is already disconnected + + vector v_faces; + vector v_edges; + + v_faces.reserve(64); + v_edges.reserve(64); + + VertexFaces(last,v_faces); + VertexEdges(last,v_edges); + + // map the faces and edges to look at v + + vector::iterator face_it = v_faces.begin(); + + for(; face_it != v_faces.end(); ++face_it) { + faces[*face_it].SwapVertex(last,v); + } + vector::iterator edge_it = v_edges.begin(); + + for (; edge_it != v_edges.end(); ++edge_it) { + edges[*edge_it].SwapVertex(last,v); + } + + // copy the last vertex onto v and pop off the back. + + verts[v] = verts[last]; + + // tidy external buffer + extern_editor.CopyModifiedFaces(*this,v_faces); + } + + verts.pop_back(); + extern_editor.CopyBackVertex(v); + + +}; + + void +LOD_ManMesh2:: +DeleteEdge( + LOD_EdgeInd e, + CTR_UHeap * heap +){ + vector &edges = EdgeSet(); + vector &verts = VertexSet(); + + if (edges.size() == 1) { + edges.clear(); + return; + } + + LOD_EdgeInd last = LOD_EdgeInd(edges.end() - edges.begin() - 1); + + if (!(last == e)) { + vector e_verts; + e_verts.reserve(2); + EdgeVertices(last,e_verts); + // something is wrong if there arent two! + + verts[e_verts[0]].SwapEdge(last,e); + verts[e_verts[1]].SwapEdge(last,e); + + // edges[e] should already have been removed from the heap + + MT_assert(edges[e].HeapPos() == 0xffffffff); + + edges[e] = edges[last]; + // also have to swap there heap positions.!!!!! + + heap->HeapVector()[edges[e].HeapPos()] = e; + + + } + edges.pop_back(); +}; + + void +LOD_ManMesh2:: +DeleteFace( + LOD_ExternBufferEditor & extern_editor, + LOD_FaceInd f +){ + + vector &edges = EdgeSet(); + vector &faces = FaceSet(); + + if (faces.size() == 1) { + faces.clear(); + return; + } + + LOD_FaceInd last = LOD_FaceInd(faces.end() - faces.begin() - 1); + + if (!(last == f)) { + + // we have to update the edges which point to the last + // face + + vector f_edges; + f_edges.reserve(3); + + FaceEdges(last,f_edges); + + vector::iterator edge_it = f_edges.begin(); + vector::const_iterator edge_end = f_edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + edges[*edge_it].SwapFace(last,f); + } + + faces[f] = faces[last]; + + } + faces.pop_back(); + + // tidy external buffers + extern_editor.CopyBackFace(f); +}; + + + + + + + + + + + + + + + + diff --git a/intern/decimation/intern/LOD_ManMesh2.h b/intern/decimation/intern/LOD_ManMesh2.h new file mode 100644 index 00000000000..46ddcff5d80 --- /dev/null +++ b/intern/decimation/intern/LOD_ManMesh2.h @@ -0,0 +1,264 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_ManMesh2_h +#define NAN_INCLUDED_ManMesh2_h + +#include "LOD_MeshPrimitives.h" +#include "MEM_SmartPtr.h" +#include + +template class CTR_UHeap; + +class LOD_ExternBufferEditor; + +class LOD_ManMesh2 // Manifold 2 dimensional mesh +{ + +public: + + static + LOD_ManMesh2 * + New( + ); + + // take ownership of the vertices. + + bool + SetVertices( + MEM_SmartPtr > verts + ); + + // Add a triangle to the mesh + + void + AddTriangle( + int verts[3] + ); + + void + ConnectTriangle( + LOD_FaceInd fi, + std::vector & new_edges + ); + + // geometry access + ////////////////// + + std::vector & + VertexSet( + ) const ; + + std::vector & + FaceSet( + ) const ; + + std::vector & + EdgeSet( + ) const; + + ~LOD_ManMesh2( + ); + + // local geometry queries + ///////////////////////// + + // face queries + /////////////// + + void + FaceVertices( + LOD_FaceInd f, + std::vector &output + ); + + void + FaceEdges( + LOD_FaceInd f, + std::vector &output + ); + + // edge queries + /////////////// + + void + EdgeVertices( + LOD_EdgeInd e, + std::vector &output + ); + + void + EdgeFaces( + LOD_EdgeInd e, + std::vector &output + ); + + // vertex queries + ///////////////// + + void + VertexEdges( + LOD_VertexInd v, + std::vector &output + ); + + void + VertexFaces( + LOD_VertexInd v, + std::vector &output + ); + + void + SetBBox( + MT_Vector3 bbox_min, + MT_Vector3 bbox_max + ); + + MT_Vector3 + BBoxMin( + ) const { + return m_bbox_min; + }; + + MT_Vector3 + BBoxMax( + ) const { + return m_bbox_max; + }; + + // Remove a primitive from the mesh + /////////////////////////////////// + + // These methods assume you have correctly + // tidied up the index pointers in other primitives, + // so that nothing refers to this object any more + + // These methods exchange the primitive with the + // last primitive in the vector. It modifies everything + // pointing to the last primitive correctly. + + // FIXME refactor extern editor out of primitive deletion + // insead return a vector of primitives that need to be + // modified and do this externally + + void + DeleteVertex( + LOD_ExternBufferEditor & extern_editor, + LOD_VertexInd v + ); + + void + DeleteEdge( + LOD_EdgeInd e, + CTR_UHeap *heap + ); + + void + DeleteFace( + LOD_ExternBufferEditor & extern_editor, + LOD_FaceInd f + ); + + // Sanity Check routines + //////////////////////// + + // Make sure the edge sets and the vertex sets are + // consistent + + void + SC_TriFace( + LOD_FaceInd f + ); + + // basic sanity checking of an edge list bails out if there are more than 1024 + // edges + + void + SC_EdgeList( + LOD_EdgeInd e + ); + + + // Check to see that the edges of v1 and v2 are unique. + + bool + SC_UniqueEdge( + LOD_EdgeInd e + ); + + +private : + + + // Returns the edge index of the edge from v1 to v2. + // Does this by searching the edge sets of v1 - but not v2. + // If you are paranoid you should check both and make sure the + // indices are the same. If the edge doe not exist edgeInd is empty. + + LOD_EdgeInd + FindEdge( + const LOD_VertexInd v1, + const LOD_VertexInd v2 + ); + + // Insert an edge into the mesh + // Tie up the ptrs and create space for the edge + // returns manifold errors - need to sort out memory edges + + bool + InsertEdge( + const LOD_VertexInd v1, + const LOD_VertexInd v2, + const LOD_FaceInd f, + std::vector &new_edges + ); + + +private : + + LOD_ManMesh2( + ); + + MEM_SmartPtr< std::vector > m_verts; + MEM_SmartPtr< std::vector > m_faces; + MEM_SmartPtr< std::vector > m_edges; + + // not sure of these descrtiptions of the mesh should + // reside in this class coz may lead to very bloated interface. + + MT_Vector3 m_bbox_min; + MT_Vector3 m_bbox_max; + + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_MeshBounds.h b/intern/decimation/intern/LOD_MeshBounds.h new file mode 100644 index 00000000000..f694ff2dcb3 --- /dev/null +++ b/intern/decimation/intern/LOD_MeshBounds.h @@ -0,0 +1,132 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MeshBounds_h +#define NAN_INCLUDED_MeshBounds_h + +#include "MEM_SmartPtr.h" +#include "LOD_MeshPrimitives.h" +#include "LOD_ManMesh2.h" +#include "MT_assert.h" + +// simple class to compute the mesh bounds of a manifold mesh, + +class LOD_MeshBounds { + +public : + static + LOD_MeshBounds * + New( + ){ + + MEM_SmartPtr output(new LOD_MeshBounds()); + return output.Release(); + } + + void + ComputeBounds( + const LOD_ManMesh2 * mesh + ){ + MT_assert(mesh!=NULL); + MT_assert(mesh->VertexSet().size() > 0); + + const std::vector &verts = mesh->VertexSet(); + + m_min = verts[0].pos; + m_max = verts[0].pos; + + // iterate through the verts + + int t; + const int size = verts.size(); + + for (t=1; t< size ; ++t) { + + UpdateBounds(verts[t].pos,m_min,m_max); + } + } + + MT_Vector3 + Min( + ) const { + return m_min; + } + + MT_Vector3 + Max( + ) const { + return m_max; + } + +private : + + void + UpdateBounds( + MT_Vector3 vertex, + MT_Vector3& min, + MT_Vector3& max + ) { + if (vertex.x() < min.x()) { + min.x() = vertex.x(); + } else + if (vertex.x() > max.x()) { + max.x()= vertex.x(); + } + + if (vertex.y() < min.y()) { + min.y() = vertex.y(); + } else + if (vertex.y() > max.y()) { + max.y()= vertex.y(); + } + + if (vertex.z() < min.z()) { + min.z() = vertex.z(); + } else + if (vertex.z() > max.z()) { + max.z()= vertex.z(); + } + } + + LOD_MeshBounds( + ) : + m_min(0,0,0), + m_max(0,0,0) + { + }; + + MT_Vector3 m_min; + MT_Vector3 m_max; + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_MeshException.h b/intern/decimation/intern/LOD_MeshException.h new file mode 100644 index 00000000000..4bad167a81b --- /dev/null +++ b/intern/decimation/intern/LOD_MeshException.h @@ -0,0 +1,54 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MeshExceptions_h +#define NAN_INCLUDED_MeshExceptions_h + +class LOD_MeshException { + +public : + + // stick in more error types as you think of them + + enum ExceptionType{ + e_non_manifold, + e_search_error + } m_e_type; + + LOD_MeshException ( + ExceptionType type + ) : m_e_type (type) + { + } +}; + +#endif + diff --git a/intern/decimation/intern/LOD_MeshPrimitives.cpp b/intern/decimation/intern/LOD_MeshPrimitives.cpp new file mode 100644 index 00000000000..42707252a45 --- /dev/null +++ b/intern/decimation/intern/LOD_MeshPrimitives.cpp @@ -0,0 +1,407 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_MeshPrimitives.h" + +#include "MT_assert.h" +#include "LOD_MeshException.h" +#include + +using namespace std; + +// Vertex Methods +///////////////// + +LOD_Vertex:: +LOD_Vertex( +) : + pos (MT_Vector3()), + m_select_tag(false) +{ +}; + + bool +LOD_Vertex:: +RemoveEdge( + LOD_EdgeInd e +){ + + vector::iterator result = find(m_edges.begin(),m_edges.end(),e); + if (result == m_edges.end()) { + return false; + } + + std::swap(*result, m_edges.back()); + m_edges.pop_back(); + return true; +}; + + void +LOD_Vertex:: +AddEdge( + LOD_EdgeInd e +){ + m_edges.push_back(e); +}; + + void +LOD_Vertex:: +SwapEdge( + LOD_EdgeInd e_old, + LOD_EdgeInd e_new +){ + + vector::iterator result = + find(m_edges.begin(),m_edges.end(),e_old); + if (result == m_edges.end()) { + MT_assert(false); + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + } + + *result = e_new; +}; + + bool +LOD_Vertex:: +SelectTag( +) const { + return m_select_tag; +}; + + void +LOD_Vertex:: +SetSelectTag( + bool tag +){ + m_select_tag = tag; +}; + + bool +LOD_Vertex:: +Degenerate( +){ + return m_edges.empty(); +} + + void +LOD_Vertex:: +CopyPosition( + float *float_ptr +){ + pos.getValue(float_ptr); +} + + + +// Edge Methods +/////////////// + +LOD_Edge:: +LOD_Edge ( +) { + m_verts[0] = m_verts[1] = LOD_VertexInd::Empty(); + m_faces[0] = m_faces[1] = LOD_FaceInd::Empty(); +} + + bool +LOD_Edge:: +operator == ( + LOD_Edge & rhs +) { + // edges are the same if their vertex indices are the + // same!!! Other properties are not checked + + int matches = 0; + + if (this->m_verts[0] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[0] == rhs.m_verts[1]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[1]) { + ++matches; + } + + if (matches >= 2) { + return true; + } + return false; +} + +// Elementary helper methods +//////////////////////////// + + LOD_FaceInd +LOD_Edge:: +OpFace( + LOD_FaceInd f +) const { + if (f == m_faces[0]) { + return m_faces[1]; + } else + if (f == m_faces[1]) { + return m_faces[0]; + } else { + MT_assert(false); + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + + return LOD_FaceInd::Empty(); + } +} + + void +LOD_Edge:: +SwapFace( + LOD_FaceInd old_f, + LOD_FaceInd new_f +) { + if (old_f == m_faces[0]) { + m_faces[0] = new_f; + } else + if (old_f == m_faces[1]) { + m_faces[1] = new_f; + } else { + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + } +} + + +// return the half edge face - the half edge is defined +// by the {vertex,edge} tuple. + + LOD_FaceInd +LOD_Edge:: +HalfEdgeFace( + LOD_VertexInd vi +){ + if (vi == m_verts[0]) return m_faces[0]; + if (vi == m_verts[1]) return m_faces[1]; + MT_assert(false); + + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + + return LOD_FaceInd::Empty(); +} + + + LOD_VertexInd +LOD_Edge:: +OpVertex( + LOD_VertexInd vi +) { + if (vi == m_verts[0]) return m_verts[1]; + if (vi == m_verts[1]) return m_verts[0]; + MT_assert(false); + + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + + return LOD_VertexInd::Empty(); +} + +// replace the vertex v_old with vertex v_new +// error if v_old is not one of the original vertices + + void +LOD_Edge:: +SwapVertex( + LOD_VertexInd v_old, + LOD_VertexInd v_new +) { + if (v_old == m_verts[0]) { + m_verts[0] = v_new; + } else + if (v_old == m_verts[1]) { + m_verts[1] = v_new; + } else { + + MT_assert(false); + + LOD_MeshException e(LOD_MeshException::e_search_error); + throw(e); + } + if(m_verts[0] == m_verts[1]) { + MT_assert(false); + + LOD_MeshException e(LOD_MeshException::e_non_manifold); + throw(e); + } + +} + + bool +LOD_Edge:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +}; + + void +LOD_Edge:: +SetSelectTag( + bool tag +) { + m_verts[1].SetTag(int(tag)); +}; + + int +LOD_Edge:: +OpenTag( +) const { + return m_faces[0].Tag(); +} + + void +LOD_Edge:: +SetOpenTag( + int tag +) { + m_faces[0].SetTag(tag); +} + + bool +LOD_Edge:: +Degenerate( +) const { + return ( + (m_faces[0].IsEmpty() && m_faces[1].IsEmpty()) || + (m_verts[0] == m_verts[1]) + ); +}; + +// TriFace Methods +////////////////// + +LOD_TriFace:: +LOD_TriFace( +) { + m_verts[0] = m_verts[1] = m_verts[2] = LOD_VertexInd::Empty(); +} + +// Elementary helper methods +//////////////////////////// + + void +LOD_TriFace:: +SwapVertex( + LOD_VertexInd old_v, + LOD_VertexInd new_v +) { + // could save branching here... + + if (m_verts[0] == old_v) { + m_verts[0] = new_v; + } else + if (m_verts[1] == old_v) { + m_verts[1] = new_v; + } else + if (m_verts[2] == old_v) { + m_verts[2] = new_v; + } else { + MT_assert(false); + + LOD_MeshException excep(LOD_MeshException::e_search_error); + throw(excep); + } +} + + bool +LOD_TriFace:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +}; + + void +LOD_TriFace:: +SetSelectTag( + bool tag +) { + m_verts[1].SetTag(int(tag)); +}; + + int +LOD_TriFace:: +OpenTag( +) { + return m_verts[2].Tag(); +} + + void +LOD_TriFace:: +SetOpenTag( + int tag +) { + m_verts[2].SetTag(tag); +} + + bool +LOD_TriFace:: +Degenerate( +) { + + return ( + (m_verts[0] == m_verts[1]) || + (m_verts[1] == m_verts[2]) || + (m_verts[2] == m_verts[0]) + ); +} + + void +LOD_TriFace:: +CopyVerts( + int * index_ptr +){ + index_ptr[0] = m_verts[0]; + index_ptr[1] = m_verts[1]; + index_ptr[2] = m_verts[2]; +}; + + + + + + + + + diff --git a/intern/decimation/intern/LOD_MeshPrimitives.h b/intern/decimation/intern/LOD_MeshPrimitives.h new file mode 100644 index 00000000000..1168c9cc813 --- /dev/null +++ b/intern/decimation/intern/LOD_MeshPrimitives.h @@ -0,0 +1,220 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MeshPrimitives_h +#define NAN_INCLUDED_MeshPrimitives_h + +#include "MT_Vector3.h" +#include "CTR_TaggedIndex.h" +#include "CTR_UHeap.h" +#include + +typedef CTR_TaggedIndex<24,0x00ffffff> LOD_VertexInd; +typedef CTR_TaggedIndex<24,0x00ffffff> LOD_EdgeInd; +typedef CTR_TaggedIndex<24,0x00ffffff> LOD_FaceInd; +typedef CTR_TaggedIndex<24,0x00ffffff> LOD_HeapInd; + +class LOD_Vertex { +public : + MT_Vector3 pos; + std::vector m_edges; + bool m_select_tag; + + LOD_Vertex( + ) ; + + bool + RemoveEdge( + LOD_EdgeInd e + ); + + void + AddEdge( + LOD_EdgeInd e + ); + + void + SwapEdge( + LOD_EdgeInd e_old, + LOD_EdgeInd e_new + ); + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + bool + Degenerate( + ); + + void + CopyPosition( + float *float_ptr + ); + +private : + + +}; + +class LOD_Edge : public CTR_UHeapable { +public : + LOD_VertexInd m_verts[2]; + LOD_FaceInd m_faces[2]; + + LOD_Edge ( + ); + + bool operator == ( + LOD_Edge & rhs + ); + + // Elementary helper methods + //////////////////////////// + + LOD_FaceInd + OpFace( + LOD_FaceInd f + ) const ; + + void + SwapFace( + LOD_FaceInd old_f, + LOD_FaceInd new_f + ) ; + + + // return the half edge face - the half edge is defined + // by the {vertex,edge} tuple. + + LOD_FaceInd + HalfEdgeFace( + LOD_VertexInd vi + ); + + + LOD_VertexInd + OpVertex( + LOD_VertexInd vi + ); + + // replace the vertex v_old with vertex v_new + // error if v_old is not one of the original vertices + + void + SwapVertex( + LOD_VertexInd v_old, + LOD_VertexInd v_new + ) ; + + bool + SelectTag( + ) const ; + + void + SetSelectTag( + bool tag + ); + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ) ; + + bool + Degenerate( + ) const; + + bool + BoundaryEdge( + ) const { + return (m_faces[0].IsEmpty() || m_faces[1].IsEmpty()); + }; + + +}; + +class LOD_TriFace { +public: + + LOD_VertexInd m_verts[3]; + + LOD_TriFace( + ); + + // Elementary helper methods + //////////////////////////// + + void + SwapVertex( + LOD_VertexInd old_v, + LOD_VertexInd new_v + ); + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + int + OpenTag( + ); + void + SetOpenTag( + int tag + ); + + bool + Degenerate( + ); + + void + CopyVerts( + int * index_ptr + ); + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_QSDecimator.cpp b/intern/decimation/intern/LOD_QSDecimator.cpp new file mode 100644 index 00000000000..a9fd5267c54 --- /dev/null +++ b/intern/decimation/intern/LOD_QSDecimator.cpp @@ -0,0 +1,328 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_QSDecimator.h" + +#include "LOD_ExternBufferEditor.h" + +using namespace std; + + LOD_QSDecimator * +LOD_QSDecimator:: +New( + LOD_ManMesh2 &mesh, + LOD_ExternNormalEditor &face_editor, + LOD_ExternBufferEditor &extern_editor +){ + + MEM_SmartPtr output + = new LOD_QSDecimator(mesh,face_editor,extern_editor); + + MEM_SmartPtr collapser(LOD_EdgeCollapser::New()); + MEM_SmartPtr q_editor(LOD_QuadricEditor::New(mesh)); + + if ( + output == NULL || + collapser == NULL || + q_editor == NULL + ) { + return NULL; + } + output->m_collapser = collapser.Release(); + output->m_quadric_editor = q_editor.Release(); + return output.Release(); +} + + + + bool +LOD_QSDecimator:: +Arm( +){ + MT_assert(!m_is_armed); + bool heap_result = BuildHeap(); + if (!heap_result) { + return false; + } + m_is_armed = true; + return true; +} + + bool +LOD_QSDecimator:: +Step( +){ + return CollapseEdge(); +} + + +LOD_QSDecimator:: +LOD_QSDecimator( + LOD_ManMesh2 &mesh, + LOD_ExternNormalEditor &face_editor, + LOD_ExternBufferEditor &extern_editor +) : + m_mesh(mesh), + m_face_editor(face_editor), + m_extern_editor(extern_editor), + m_is_armed (false) +{ + m_deg_edges.reserve(32); + m_deg_faces.reserve(32); + m_deg_vertices.reserve(32); + m_update_faces.reserve(32); + m_new_edges.reserve(32); + m_update_vertices.reserve(32); +}; + + bool +LOD_QSDecimator:: +CollapseEdge( +){ + + // find an edge to collapse + + // FIXME force an edge collapse + // or return false + + std::vector & edges = m_mesh.EdgeSet(); + std::vector & verts = m_mesh.VertexSet(); + std::vector & quadrics = m_quadric_editor->Quadrics(); + int size = edges.size(); + + if (size == 0) return false; + + const int heap_top = m_heap->Top(); + + if (heap_top == -1 || edges[heap_top].HeapKey() <= -MT_INFINITY) { + return false; + } + + // compute the target position + MT_Vector3 new_vertex = m_quadric_editor->TargetVertex(edges[heap_top]); + LOD_Quadric & q0 = quadrics[edges[heap_top].m_verts[0]]; + LOD_Quadric & q1 = quadrics[edges[heap_top].m_verts[1]]; + + LOD_Vertex &v0 = verts[edges[heap_top].m_verts[0]]; + LOD_Vertex &v1 = verts[edges[heap_top].m_verts[1]]; + + LOD_Quadric sum = q0; + sum += q1; + + + if (m_collapser->CollapseEdge( + heap_top, + m_mesh, + m_deg_edges, + m_deg_faces, + m_deg_vertices, + m_new_edges, + m_update_faces, + m_update_vertices + )) { + + // assign new vertex position + + v0.pos = new_vertex; + v1.pos = new_vertex; + + // sum the quadrics of v0 and v1 + q0 = sum; + q1 = sum; + + // ok update the primitive properties + + m_face_editor.Update(m_update_faces); + m_face_editor.UpdateVertexNormals(m_update_vertices); + + // update the external vertex buffer + m_extern_editor.CopyModifiedVerts(m_mesh,m_update_vertices); + + // update the external face buffer + m_extern_editor.CopyModifiedFaces(m_mesh,m_update_faces); + + // update the edge heap + UpdateHeap(m_deg_edges,m_new_edges); + + m_quadric_editor->Remove(m_deg_vertices); + m_face_editor.Remove(m_deg_faces); + m_face_editor.RemoveVertexNormals(m_deg_vertices); + + // delete the primitives + + DeletePrimitives(m_deg_edges,m_deg_faces,m_deg_vertices); + + } else { + // the edge could not be collapsed at the moment - so + // we adjust it's priority and add it back to the heap. + m_heap->Remove(&edges[0],0); + edges[heap_top].HeapKey() = - MT_INFINITY; + m_heap->Insert(&edges[0],heap_top); + } + + //clear all the temporary buffers + + m_deg_faces.clear(); + m_deg_edges.clear(); + m_deg_vertices.clear(); + + m_update_faces.clear(); + m_update_vertices.clear(); + m_new_edges.clear(); + + return true; + +} + + void +LOD_QSDecimator:: +DeletePrimitives( + const vector & degenerate_edges, + const vector & degenerate_faces, + const vector & degenerate_vertices +) { + + // assumes that the 3 vectors are sorted in descending order. + + // Delete Degnerate primitives + ////////////////////////////// + + + // delete the old edges - we have to be very careful here + // mesh.delete() swaps edges to be deleted with the last edge in + // the edge buffer. However the next edge to be deleted may have + // been the last edge in the buffer! + + // One way to solve this is to sort degenerate_edges in descending order. + // And then delete them in that order. + + // it is also vital that degenerate_edges contains no duplicates + + vector::const_iterator edge_it = degenerate_edges.begin(); + vector::const_iterator edge_end = degenerate_edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + m_mesh.DeleteEdge(*edge_it,m_heap); + } + + + + vector::const_iterator face_it = degenerate_faces.begin(); + vector::const_iterator face_end = degenerate_faces.end(); + + for (;face_it != face_end; ++face_it) { + m_mesh.DeleteFace(m_extern_editor,*face_it); + } + + vector::const_iterator vertex_it = degenerate_vertices.begin(); + vector::const_iterator vertex_end = degenerate_vertices.end(); + + for (;vertex_it != vertex_end; ++vertex_it) { + m_mesh.DeleteVertex(m_extern_editor,*vertex_it); + } +} + + + bool +LOD_QSDecimator:: +BuildHeap( +){ + // build the quadrics + + if (m_quadric_editor->BuildQuadrics(m_face_editor,true) == false) return false; + + + m_heap = CTR_UHeap::New(); + // load in edge pointers to the heap + + std::vector & edge_set= m_mesh.EdgeSet(); + std::vector::const_iterator edge_end = edge_set.end(); + std::vector::iterator edge_start = edge_set.begin(); + + std::vector & heap_vector = m_heap->HeapVector(); + + for (unsigned int i = 0; i < edge_set.size(); ++i) { + edge_set[i].HeapPos() = i; + heap_vector.push_back(i); + } + + m_heap->MakeHeap(&edge_set[0]); + + return true; +} + + void +LOD_QSDecimator:: +UpdateHeap( + std::vector °_edges, + std::vector &new_edges +){ + // first of all compute values for the new edges + // and bung them on the heap. + + std::vector & edge_set= m_mesh.EdgeSet(); + + std::vector::const_iterator edge_it = new_edges.begin(); + std::vector::const_iterator end_it = new_edges.end(); + + + // insert all the new edges + /////////////////////////// + + // compute edge costs ffor the new edges + + m_quadric_editor->ComputeEdgeCosts(new_edges); + + // inser the new elements into the heap + + for (; edge_it != end_it; ++edge_it) { + m_heap->Insert(&edge_set[0],*edge_it); + } + + + // remove all the old values from the heap + + edge_it = deg_edges.begin(); + end_it = deg_edges.end(); + + for (; edge_it != end_it; ++edge_it) { + LOD_Edge &e = edge_set[*edge_it]; + m_heap->Remove(&edge_set[0],e.HeapPos()); + + e.HeapPos() = 0xffffffff; + + } +} + diff --git a/intern/decimation/intern/LOD_QSDecimator.h b/intern/decimation/intern/LOD_QSDecimator.h new file mode 100644 index 00000000000..0492e0bf09e --- /dev/null +++ b/intern/decimation/intern/LOD_QSDecimator.h @@ -0,0 +1,128 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_QSDecimator_H +#define NAN_INCLUDED_LOD_QSDecimator_H + +#include "MEM_NonCopyable.h" +#include "LOD_ManMesh2.h" +#include "LOD_ExternNormalEditor.h" +#include "LOD_EdgeCollapser.h" +#include "LOD_QuadricEditor.h" + +class LOD_ExternBufferEditor; + +class LOD_QSDecimator : public MEM_NonCopyable { + +public : + + static + LOD_QSDecimator * + New( + LOD_ManMesh2 &mesh, + LOD_ExternNormalEditor &face_editor, + LOD_ExternBufferEditor &extern_editor + ); + + + bool + Arm( + ); + + + bool + Step( + ); + +private : + + LOD_QSDecimator( + LOD_ManMesh2 &mesh, + LOD_ExternNormalEditor &face_editor, + LOD_ExternBufferEditor &extern_editor + ); + + bool + CollapseEdge( + ); + + bool + BuildHeap( + ); + + void + UpdateHeap( + std::vector °_edges, + std::vector &new_edges + ); + + void + DeletePrimitives( + const std::vector & degenerate_edges, + const std::vector & degenerate_faces, + const std::vector & degenerate_vertices + ); + + +private : + + // owned by this class + ////////////////////// + + MEM_SmartPtr m_collapser; + MEM_SmartPtr > m_heap; + MEM_SmartPtr m_quadric_editor; + + bool m_is_armed; + + // arguments to New(...) + //////////////////////// + + LOD_ManMesh2 & m_mesh; + LOD_ExternNormalEditor &m_face_editor; + LOD_ExternBufferEditor & m_extern_editor; + + // temporary buffers + //////////////////// + + std::vector m_deg_faces; + std::vector m_deg_edges; + std::vector m_deg_vertices; + + std::vector m_update_faces; + std::vector m_new_edges; + std::vector m_update_vertices; + + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_Quadric.h b/intern/decimation/intern/LOD_Quadric.h new file mode 100644 index 00000000000..f06b0af65b0 --- /dev/null +++ b/intern/decimation/intern/LOD_Quadric.h @@ -0,0 +1,166 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_Quadric_h +#define NAN_INCLUDED_LOD_Quadric_h + +#include "MT_Vector3.h" +#include "MT_Matrix3x3.h" + + +class LOD_Quadric { + +private: + MT_Scalar a2, ab, ac, ad; + MT_Scalar b2, bc, bd; + MT_Scalar c2, cd; + MT_Scalar d2; + + void init(MT_Scalar a, MT_Scalar b, MT_Scalar c, MT_Scalar d); + +public: + + LOD_Quadric( + ) { + Clear(); + }; + + LOD_Quadric( + const MT_Vector3 & vec, + const MT_Scalar & offset + ) { + a2 = vec[0] *vec[0]; + b2 = vec[1] *vec[1]; + c2 = vec[2] *vec[2]; + + ab = vec[0]*vec[1]; + ac = vec[0]*vec[2]; + bc = vec[1]*vec[2]; + + MT_Vector3 temp = vec*offset; + ad = temp[0]; + bd = temp[1]; + cd = temp[2]; + + d2 = offset*offset; + }; + + MT_Matrix3x3 + Tensor( + ) const { + // return a symmetric matrix + + return MT_Matrix3x3( + a2,ab,ac, + ab,b2,bc, + ac,bc,c2 + ); + }; + + + MT_Vector3 + Vector( + ) const { + return MT_Vector3(ad, bd, cd); + }; + + void + Clear( + MT_Scalar val=0.0 + ) { + a2=ab=ac=ad=b2=bc=bd=c2=cd=d2=val; + }; + + LOD_Quadric & + operator=( + const LOD_Quadric& Q + ) { + + a2 = Q.a2; ab = Q.ab; ac = Q.ac; ad = Q.ad; + b2 = Q.b2; bc = Q.bc; bd = Q.bd; + c2 = Q.c2; cd = Q.cd; + d2 = Q.d2; + return *this; + }; + + LOD_Quadric& + operator+=( + const LOD_Quadric& Q + ) { + a2 += Q.a2; ab += Q.ab; ac += Q.ac; ad += Q.ad; + b2 += Q.b2; bc += Q.bc; bd += Q.bd; + c2 += Q.c2; cd += Q.cd; + d2 += Q.d2; + return *this; + }; + + LOD_Quadric& + operator*=( + const MT_Scalar & s + ) { + a2 *= s; ab *= s; ac *= s; ad *= s; + b2 *= s; bc *= s; bd *= s; + c2 *= s; cd *= s; + d2 *= s; + return *this; + }; + + + MT_Scalar + Evaluate( + const MT_Vector3 &v + ) const { + // compute the LOD_Quadric error + + return v[0]*v[0]*a2 + 2*v[0]*v[1]*ab + 2*v[0]*v[2]*ac + 2*v[0]*ad + +v[1]*v[1]*b2 + 2*v[1]*v[2]*bc + 2*v[1]*bd + +v[2]*v[2]*c2 + 2*v[2]*cd + + d2; + }; + + bool + Optimize( + MT_Vector3& v + ) const { + + MT_Scalar det = Tensor().determinant(); + if (MT_fuzzyZero(det)) { + return false; + } + + v = -((Tensor().inverse()) * Vector()); + return true; + }; + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_QuadricEditor.cpp b/intern/decimation/intern/LOD_QuadricEditor.cpp new file mode 100644 index 00000000000..c1e5614b01d --- /dev/null +++ b/intern/decimation/intern/LOD_QuadricEditor.cpp @@ -0,0 +1,282 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "LOD_QuadricEditor.h" +#include "LOD_ExternNormalEditor.h" + +// Creation +/////////// + +using namespace std; + + +LOD_QuadricEditor:: +LOD_QuadricEditor( + LOD_ManMesh2 &mesh +) : + m_quadrics(NULL), + m_mesh(mesh) +{ +}; + + LOD_QuadricEditor * +LOD_QuadricEditor:: +New( + LOD_ManMesh2 &mesh +){ + //same number of quadrics as vertices in the mesh + + MEM_SmartPtr output(new LOD_QuadricEditor(mesh)); + + if (output == NULL) { + return NULL; + } + return output.Release(); +} + + +// Property editor interface +//////////////////////////// + + void +LOD_QuadricEditor:: +Remove( + std::vector &sorted_vertices +){ + vector & quadrics = *m_quadrics; + + vector::const_iterator it_start = sorted_vertices.begin(); + vector::const_iterator it_end = sorted_vertices.end(); + + for (; it_start != it_end; ++it_start) { + + if (quadrics.size() > 0) { + LOD_Quadric temp = quadrics[*it_start]; + + quadrics[*it_start] = quadrics.back(); + quadrics.back() = temp; + + quadrics.pop_back(); + } + } +}; + + +// Editor specific methods +////////////////////////// + + bool +LOD_QuadricEditor:: +BuildQuadrics( + LOD_ExternNormalEditor& normal_editor, + bool preserve_boundaries +){ + if (m_quadrics != NULL) delete(m_quadrics); + + m_quadrics =new vector (m_mesh.VertexSet().size()); + if (m_quadrics == NULL) return false; + + // iterate through the face set of the mesh + // compute a quadric based upon that face and + // add it to each of it's vertices quadrics. + + const vector &faces = m_mesh.FaceSet(); + const vector &verts = m_mesh.VertexSet(); + vector &edges = m_mesh.EdgeSet(); + + const vector &normals = normal_editor.Normals(); + vector::const_iterator normal_it = normals.begin(); + + vector::const_iterator face_it = faces.begin(); + vector::const_iterator face_end = faces.end(); + + vector & quadrics = *m_quadrics; + + + for (; face_it != face_end; ++face_it, ++normal_it) { + + MT_Vector3 normal = *normal_it; + MT_Scalar offset = -normal.dot(verts[face_it->m_verts[0]].pos); + + LOD_Quadric q(normal,offset); + + quadrics[face_it->m_verts[0]] += q; + quadrics[face_it->m_verts[1]] += q; + quadrics[face_it->m_verts[2]] += q; + } + + if (preserve_boundaries) { + + // iterate through the edge set and add a boundary quadric to + // each of the boundary edges vertices. + + vector::const_iterator edge_it = edges.begin(); + vector::const_iterator edge_end = edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + if (edge_it->BoundaryEdge()) { + + // compute a plane perpendicular to the edge and the normal + // of the edges single polygon. + const MT_Vector3 & v0 = verts[edge_it->m_verts[0]].pos; + const MT_Vector3 & v1 = verts[edge_it->m_verts[1]].pos; + + MT_Vector3 edge_vector = v1 - v0; + + LOD_FaceInd edge_face = edge_it->OpFace(LOD_EdgeInd::Empty()); + edge_vector = edge_vector.cross(normals[edge_face]); + + if (!edge_vector.fuzzyZero()) { + edge_vector.normalize(); + + LOD_Quadric boundary_q(edge_vector, - edge_vector.dot(v0)); + boundary_q *= 100; + + quadrics[edge_it->m_verts[0]] += boundary_q; + quadrics[edge_it->m_verts[1]] += boundary_q; + } + } + } + } + + + // initiate the heap keys of the edges by computing the edge costs. + + vector::iterator edge_it = edges.begin(); + vector::const_iterator edge_end = edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + + MT_Vector3 target = TargetVertex(*edge_it); + + LOD_Edge &e = *edge_it; + LOD_Quadric q0 = quadrics[e.m_verts[0]]; + const LOD_Quadric &q1 = quadrics[e.m_verts[1]]; + + e.HeapKey() = -float(q0.Evaluate(target) + q1.Evaluate(target)); + } + + return true; + +}; + + MT_Vector3 +LOD_QuadricEditor:: +TargetVertex( + LOD_Edge & e +){ + + // compute an edge contration target for edge ei + // this is computed by summing it's vertices quadrics and + // optimizing the result. + vector &verts = m_mesh.VertexSet(); + + vector &quadrics = *m_quadrics; + + LOD_VertexInd v0 = e.m_verts[0]; + LOD_VertexInd v1 = e.m_verts[1]; + + LOD_Quadric q0 = quadrics[v0]; + q0 += quadrics[v1]; + + MT_Vector3 result; + + if (q0.Optimize(result)) { + return result; + } else { + // the quadric was degenerate -> just take the average of + // v0 and v1 + + return ((verts[v0].pos + verts[v1].pos) * 0.5); + } +}; + + void +LOD_QuadricEditor:: +ComputeEdgeCosts( + vector &edges +){ + + // for each we compute the target vertex and then compute + // the quadric error e = Q1(v') + Q2(v') + vector &edge_set = m_mesh.EdgeSet(); + + vector &quadrics = *m_quadrics; + + vector::const_iterator edge_it = edges.begin(); + vector::const_iterator edge_end = edges.end(); + + for (; edge_it != edge_end; ++edge_it) { + + MT_Vector3 target = TargetVertex(edge_set[*edge_it]); + + LOD_Edge &e = edge_set[*edge_it]; + LOD_Quadric q0 = quadrics[e.m_verts[0]]; + const LOD_Quadric &q1 = quadrics[e.m_verts[1]]; + + e.HeapKey() = -float(q0.Evaluate(target) + q1.Evaluate(target)); + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/decimation/intern/LOD_QuadricEditor.h b/intern/decimation/intern/LOD_QuadricEditor.h new file mode 100644 index 00000000000..41e7d227d54 --- /dev/null +++ b/intern/decimation/intern/LOD_QuadricEditor.h @@ -0,0 +1,119 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_LOD_QuadricEditor_h +#define NAN_INCLUDED_LOD_QuadricEditor_h + +#include "MEM_NonCopyable.h" +#include "LOD_ManMesh2.h" +#include "MT_Vector3.h" +#include "LOD_Quadric.h" + +class LOD_ExternNormalEditor; + + +class LOD_QuadricEditor : public MEM_NonCopyable +{ + +public : + + // Creation + /////////// + + static + LOD_QuadricEditor * + New( + LOD_ManMesh2 &mesh + ); + + // Property editor interface + //////////////////////////// + + void + Remove( + std::vector &sorted_vertices + ); + + void + Update( + std::vector &sorted_vertices + ); + + + std::vector & + Quadrics( + ) const { + return *m_quadrics; + }; + + + // Editor specific methods + ////////////////////////// + + bool + BuildQuadrics( + LOD_ExternNormalEditor& normal_editor, + bool preserve_boundaries + ); + + + void + ComputeEdgeCosts( + std::vector &edges + ); + + MT_Vector3 + TargetVertex( + LOD_Edge &e + ); + + ~LOD_QuadricEditor( + ){ + delete(m_quadrics); + }; + + +private : + + std::vector * m_quadrics; + + LOD_ManMesh2 &m_mesh; + +private : + + LOD_QuadricEditor(LOD_ManMesh2 &mesh); + + + +}; + +#endif + diff --git a/intern/decimation/intern/LOD_decimation.cpp b/intern/decimation/intern/LOD_decimation.cpp new file mode 100644 index 00000000000..0f6500b829d --- /dev/null +++ b/intern/decimation/intern/LOD_decimation.cpp @@ -0,0 +1,158 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +// implementation of external c api +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "../extern/LOD_decimation.h" +#include "LOD_DecimationClass.h" + +using namespace std; + + int +LOD_LoadMesh( + LOD_Decimation_InfoPtr info +) { + if (info == NULL) return 0; + if ( + info->vertex_buffer == NULL || + info->vertex_normal_buffer == NULL || + info->triangle_index_buffer == NULL + ) { + return 0; + } + + + // create the intern object to hold all + // the decimation classes + + MEM_SmartPtr intern(LOD_DecimationClass::New(info)); + + if (intern == NULL) return 0; + + MEM_SmartPtr > intern_vertex_buffer(new vector(info->vertex_num)); + if (intern_vertex_buffer == NULL) return 0; + + vector::iterator intern_vertex_it(intern_vertex_buffer->begin()); + + // now load in the vertices to the mesh + + const int vertex_stride = 3; + + float * vertex_ptr = info->vertex_buffer; + const float * vertex_end = vertex_ptr + info->vertex_num*vertex_stride; + + LOD_ManMesh2 &mesh = intern->Mesh(); + + for (;vertex_ptr < vertex_end; vertex_ptr += vertex_stride,++intern_vertex_it) { + intern_vertex_it->pos = MT_Vector3(vertex_ptr); + } + + mesh.SetVertices(intern_vertex_buffer); + + // load in the triangles + + const int triangle_stride = 3; + + int * triangle_ptr = info->triangle_index_buffer; + const int * triangle_end = triangle_ptr + info->face_num*triangle_stride; + + try { + + for (;triangle_ptr < triangle_end; triangle_ptr += triangle_stride) { + mesh.AddTriangle(triangle_ptr); + } + } + + catch (...) { + return 0; + } + + // ok we have built the mesh + + intern->m_e_decimation_state = LOD_DecimationClass::e_loaded; + + info->intern = (void *) (intern.Release()); + + return 1; +} + + int +LOD_PreprocessMesh( + LOD_Decimation_InfoPtr info +) { + if (info == NULL) return 0; + if (info->intern == NULL) return 0; + + LOD_DecimationClass *intern = (LOD_DecimationClass *) info->intern; + if (intern->m_e_decimation_state != LOD_DecimationClass::e_loaded) return 0; + + // arm the various internal classes so that we are ready to step + // through decimation + + intern->FaceEditor().BuildNormals(); + if (intern->Decimator().Arm() == false) return 0; + + // ok preprocessing done + intern->m_e_decimation_state = LOD_DecimationClass::e_preprocessed; + + return 1; +} + + int +LOD_CollapseEdge( + LOD_Decimation_InfoPtr info +){ + if (info == NULL) return 0; + if (info->intern == NULL) return 0; + LOD_DecimationClass *intern = (LOD_DecimationClass *) info->intern; + if (intern->m_e_decimation_state != LOD_DecimationClass::e_preprocessed) return 0; + + bool step_result = intern->Decimator().Step(); + + return step_result == true ? 1 : 0; +} + + + int +LOD_FreeDecimationData( + LOD_Decimation_InfoPtr info +){ + if (info == NULL) return 0; + if (info->intern == NULL) return 0; + LOD_DecimationClass *intern = (LOD_DecimationClass *) info->intern; + delete(intern); + info->intern = NULL; + return 1; +} + diff --git a/intern/decimation/intern/Makefile b/intern/decimation/intern/Makefile new file mode 100644 index 00000000000..d7c9d89d9c7 --- /dev/null +++ b/intern/decimation/intern/Makefile @@ -0,0 +1,45 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# decimation intern Makefile +# + +LIBNAME = decimation +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(NAN_LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include + + diff --git a/intern/decimation/make/msvc_6_0/decimation.dsp b/intern/decimation/make/msvc_6_0/decimation.dsp new file mode 100644 index 00000000000..013e9e077fb --- /dev/null +++ b/intern/decimation/make/msvc_6_0/decimation.dsp @@ -0,0 +1,186 @@ +# Microsoft Developer Studio Project File - Name="decimation" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=decimation - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "decimation.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "decimation.mak" CFG="decimation - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "decimation - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "decimation - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "decimation - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\decimation" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\decimation" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /Ob2 /I "..\..\..\..\..\lib\windows\container\include\\" /I "..\..\..\..\..\lib\windows\memutil\include\\" /I "..\..\..\..\..\lib\windows\moto\include\\" /I"..\..\..\moto\include" /I"..\..\..\memutil" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\decimation\libdecimation.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\decimation\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\decimation\*.lib ..\..\..\..\..\lib\windows\decimation\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "decimation - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\decimation\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\decimation\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\container\include\\" /I "..\..\..\..\..\lib\windows\memutil\include\\" /I "..\..\..\..\..\lib\windows\moto\include\\" /I"..\..\..\moto\include" /I"..\..\..\memutil" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\decimation\debug\libdecimation.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\decimation\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\decimation\debug\*.lib ..\..\..\..\..\lib\windows\decimation\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\decimation\debug\vc60.* ..\..\..\..\..\lib\windows\decimation\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "decimation - Win32 Release" +# Name "decimation - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\LOD_decimation.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_DecimationClass.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_EdgeCollapser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_EdgeCollapser.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ExternBufferEditor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ExternNormalEditor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ExternNormalEditor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_FaceNormalEditor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_FaceNormalEditor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ManMesh2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_ManMesh2.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_MeshBounds.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_MeshException.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_MeshPrimitives.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_MeshPrimitives.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_QSDecimator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_QSDecimator.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_Quadric.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_QuadricEditor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\LOD_QuadricEditor.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\extern\LOD_decimation.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/decimation/make/msvc_6_0/decimation.dsw b/intern/decimation/make/msvc_6_0/decimation.dsw new file mode 100644 index 00000000000..f874b324725 --- /dev/null +++ b/intern/decimation/make/msvc_6_0/decimation.dsw @@ -0,0 +1,33 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "decimation"=.\decimation.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + + + + + diff --git a/intern/decimation/make/msvc_7_0/decimation.sln b/intern/decimation/make/msvc_7_0/decimation.sln new file mode 100644 index 00000000000..8760ff74f8a --- /dev/null +++ b/intern/decimation/make/msvc_7_0/decimation.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "decimation", "decimation.vcproj", "{95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}.Debug.ActiveCfg = Debug|Win32 + {95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}.Debug.Build.0 = Debug|Win32 + {95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}.Release.ActiveCfg = Release|Win32 + {95ED18F3-8A76-4DB9-BDAC-12C7592EFE44}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/decimation/make/msvc_7_0/decimation.vcproj b/intern/decimation/make/msvc_7_0/decimation.vcproj new file mode 100644 index 00000000000..41bd355db5d --- /dev/null +++ b/intern/decimation/make/msvc_7_0/decimation.vcproj @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/elbeem/CMakeLists.txt b/intern/elbeem/CMakeLists.txt new file mode 100644 index 00000000000..86a60180b05 --- /dev/null +++ b/intern/elbeem/CMakeLists.txt @@ -0,0 +1,40 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC ${PNG_INC} ${ZLIB_INC} ${SDL_INC}) + +FILE(GLOB SRC intern/*.cpp) + +ADD_DEFINITIONS(-DNOGUI -DELBEEM_BLENDER=1) +IF(WINDOWS) + ADD_DEFINITIONS(-DUSE_MSVC6FIXES) +ENDIF(WINDOWS) + +BLENDERLIB_NOLIST(bf_elbeem "${SRC}" "${INC}") +#, libtype='blender', priority=0 ) diff --git a/intern/elbeem/COPYING b/intern/elbeem/COPYING new file mode 100644 index 00000000000..2600c731161 --- /dev/null +++ b/intern/elbeem/COPYING @@ -0,0 +1,358 @@ + All code distributed as part of El'Beem is covered by the following + version of the GNU General Public License. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + Copyright (c) 2003-2005 Nils Thuerey. All rights reserved. + + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/intern/elbeem/COPYING_trimesh2 b/intern/elbeem/COPYING_trimesh2 new file mode 100644 index 00000000000..a214195fd60 --- /dev/null +++ b/intern/elbeem/COPYING_trimesh2 @@ -0,0 +1,303 @@ +This distribution includes source to "miniball", "freeGLUT", +and "GLUI", which are covered under their own licenses. + +All other code distributed as part of trimesh2 is covered +by the following license: + + +Copyright (c) 2004 Szymon Rusinkiewicz. +All rights reserved. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/intern/elbeem/Makefile b/intern/elbeem/Makefile new file mode 100644 index 00000000000..3e0333fb3cd --- /dev/null +++ b/intern/elbeem/Makefile @@ -0,0 +1,58 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# elbeem main makefile. +# + +include nan_definitions.mk + +unexport NAN_QUIET + +LIBNAME = elbeem +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not ready yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_ELBEEM) ] || mkdir $(NAN_ELBEEM) + @[ -d $(NAN_ELBEEM)/include ] || mkdir $(NAN_ELBEEM)/include + @[ -d $(NAN_ELBEEM)/lib ] || mkdir $(NAN_ELBEEM)/lib + @[ -d $(NAN_ELBEEM)/lib/debug ] || mkdir $(NAN_ELBEEM)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libelbeem.a $(NAN_ELBEEM)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libelbeem.a $(NAN_ELBEEM)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_ELBEEM)/lib/libelbeem.a + ranlib $(NAN_ELBEEM)/lib/debug/libelbeem.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_ELBEEM)/include/ + diff --git a/intern/elbeem/SConscript b/intern/elbeem/SConscript new file mode 100644 index 00000000000..bb6637ba32d --- /dev/null +++ b/intern/elbeem/SConscript @@ -0,0 +1,13 @@ +#!/usr/bin/python +import sys +import os +Import('env') + +sources = env.Glob('intern/*.cpp') + +defs = 'NOGUI ELBEEM_BLENDER=1' +if env['OURPLATFORM']=='win32-vc': + defs += ' USE_MSVC6FIXES' +incs = env['BF_PNG_INC'] + ' ' + env['BF_ZLIB_INC'] + ' ' +env['BF_SDL_INC'] + +env.BlenderLib ('bf_elbeem', sources, Split(incs), Split(defs), libtype='blender', priority=0 ) diff --git a/intern/elbeem/extern/LBM_fluidsim.h b/intern/elbeem/extern/LBM_fluidsim.h new file mode 100644 index 00000000000..0f7e0e1ef5d --- /dev/null +++ b/intern/elbeem/extern/LBM_fluidsim.h @@ -0,0 +1,77 @@ +/** + * BKE_fluidsim.h + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef LBM_FLUIDSIM_H +#define LBM_FLUIDSIM_H + +struct Mesh; +struct DerivedMesh; +struct Object; +struct fluidsimDerivedMesh; + +extern double fluidsimViscosityPreset[6]; +extern char* fluidsimViscosityPresetString[6]; + +/* allocates and initializes fluidsim data */ +struct FluidsimSettings* fluidsimSettingsNew(struct Object *srcob); + +/* frees internal data itself */ +void fluidsimSettingsFree(struct FluidsimSettings* sb); + +/* duplicate internal data */ +struct FluidsimSettings* fluidsimSettingsCopy(struct FluidsimSettings* sb); + +/* export blender geometry to fluid solver */ +void fluidsimBake(struct Object* ob); + +/* read & write bobj / bobj.gz files (e.g. for fluid sim surface meshes) */ +void writeBobjgz(char *filename, struct Object *ob, int useGlobalCoords, int append, float time); +struct Mesh* readBobjgz(char *filename, struct Mesh *orgmesh, float* bbstart, float *bbsize); + +/* create derived mesh for fluid sim objects */ +// WARNING - currently implemented in DerivedMesh.c! +void loadFluidsimMesh(struct Object *srcob, int useRenderParams); + +/* run simulation with given config file */ +// WARNING - implemented in intern/elbeem/blendercall.cpp +int performElbeemSimulation(char *cfgfilename); + +/* init axis aligned BB for mesh object */ +// implemented in source/blender/blenkernel/intern/DerivedMesh.c +void fluidsimGetAxisAlignedBB(struct Mesh *mesh, float obmat[][4], + /*RET*/ float start[3], /*RET*/ float size[3], /*RET*/ struct Mesh **bbmesh ); + + +#endif + + diff --git a/intern/elbeem/extern/elbeem.h b/intern/elbeem/extern/elbeem.h new file mode 100644 index 00000000000..b3feda8bbe8 --- /dev/null +++ b/intern/elbeem/extern/elbeem.h @@ -0,0 +1,240 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * All code distributed as part of El'Beem is covered by the version 2 of the + * GNU General Public License. See the file COPYING for details. + * Copyright 2003-2006 Nils Thuerey + * + * API header + */ +#ifndef ELBEEM_API_H +#define ELBEEM_API_H + + +// simulation run callback function type (elbeemSimulationSettings->runsimCallback) +// best use with FLUIDSIM_CBxxx defines below. +// >parameters +// return values: 0=continue, 1=stop, 2=abort +// data pointer: user data pointer from elbeemSimulationSettings->runsimUserData +// status integer: 1=running simulation, 2=new frame saved +// frame integer: if status is 1, contains current frame number +typedef int (*elbeemRunSimulationCallback)(void *data, int status, int frame); +#define FLUIDSIM_CBRET_CONTINUE 0 +#define FLUIDSIM_CBRET_STOP 1 +#define FLUIDSIM_CBRET_ABORT 2 +#define FLUIDSIM_CBSTATUS_STEP 1 +#define FLUIDSIM_CBSTATUS_NEWFRAME 2 + + +// global settings for the simulation +typedef struct elbeemSimulationSettings { + /* version number */ + short version; + /* id number of simulation domain, needed if more than a + * single domain should be simulated */ + short domainId; + + /* geometrical extent */ + float geoStart[3], geoSize[3]; + + /* resolutions */ + short resolutionxyz; + short previewresxyz; + /* size of the domain in real units (meters along largest resolution x,y,z extent) */ + float realsize; + + /* fluid properties */ + double viscosity; + /* gravity strength */ + float gravity[3]; + /* anim start end time */ + float animStart, aniFrameTime; + /* no. of frames to simulate & output */ + short noOfFrames; + /* g star param (LBM compressibility) */ + float gstar; + /* activate refinement? */ + short maxRefine; + /* probability for surface particle generation (0.0=off) */ + float generateParticles; + /* amount of tracer particles to generate (0=off) */ + int numTracerParticles; + + /* store output path, and file prefix for baked fluid surface */ + char outputPath[160+80]; + + /* channel for frame time, visc & gravity animations */ + int channelSizeFrameTime; + float *channelFrameTime; + int channelSizeViscosity; + float *channelViscosity; + int channelSizeGravity; + float *channelGravity; // vector + + /* boundary types and settings for domain walls */ + short domainobsType; + float domainobsPartslip; + /* generate speed vectors for vertices (e.g. for image based motion blur)*/ + short generateVertexVectors; + /* strength of surface smoothing */ + float surfaceSmoothing; + /* no. of surface subdivisions */ + int surfaceSubdivs; + + /* global transformation to apply to fluidsim mesh */ + float surfaceTrafo[4*4]; + + /* development variables, testing for upcoming releases...*/ + float farFieldSize; + + /* callback function to notify calling program of performed simulation steps + * or newly available frame data, if NULL it is ignored */ + elbeemRunSimulationCallback runsimCallback; + /* pointer passed to runsimCallback for user data storage */ + void* runsimUserData; + +} elbeemSimulationSettings; + + +// defines for elbeemMesh->type below +#define OB_FLUIDSIM_FLUID 4 +#define OB_FLUIDSIM_OBSTACLE 8 +#define OB_FLUIDSIM_INFLOW 16 +#define OB_FLUIDSIM_OUTFLOW 32 + +// defines for elbeemMesh->obstacleType below +#define FLUIDSIM_OBSTACLE_NOSLIP 1 +#define FLUIDSIM_OBSTACLE_PARTSLIP 2 +#define FLUIDSIM_OBSTACLE_FREESLIP 3 + +#define OB_VOLUMEINIT_VOLUME 1 +#define OB_VOLUMEINIT_SHELL 2 +#define OB_VOLUMEINIT_BOTH (OB_VOLUMEINIT_SHELL|OB_VOLUMEINIT_VOLUME) + +// a single mesh object +typedef struct elbeemMesh { + /* obstacle,fluid or inflow... */ + short type; + /* id of simulation domain it belongs to */ + short parentDomainId; + + /* vertices */ + int numVertices; + float *vertices; // = float[n][3]; + /* animated vertices */ + int channelSizeVertices; + float *channelVertices; // = float[channelSizeVertices* (n*3+1) ]; + + /* triangles */ + int numTriangles; + int *triangles; // = int[][3]; + + /* animation channels */ + int channelSizeTranslation; + float *channelTranslation; + int channelSizeRotation; + float *channelRotation; + int channelSizeScale; + float *channelScale; + + /* active channel */ + int channelSizeActive; + float *channelActive; + /* initial velocity channel (e.g. for inflow) */ + int channelSizeInitialVel; + float *channelInitialVel; // vector + /* use initial velocity in object coordinates? (e.g. for rotation) */ + short localInivelCoords; + /* boundary types and settings */ + short obstacleType; + float obstaclePartslip; + /* amount of force transfer from fluid to obj, 0=off, 1=normal */ + float obstacleImpactFactor; + /* init volume, shell or both? use OB_VOLUMEINIT_xxx defines above */ + short volumeInitType; + + /* name of the mesh, mostly for debugging */ + char *name; +} elbeemMesh; + +// API functions + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +// reset elbeemSimulationSettings struct with defaults +void elbeemResetSettings(struct elbeemSimulationSettings*); + +// start fluidsim init (returns !=0 upon failure) +int elbeemInit(void); + +// start fluidsim init (returns !=0 upon failure) +int elbeemAddDomain(struct elbeemSimulationSettings*); + +// get failure message during simulation or init +// if an error occured (the string is copied into buffer, +// max. length = 256 chars ) +void elbeemGetErrorString(char *buffer); + +// reset elbeemMesh struct with zeroes +void elbeemResetMesh(struct elbeemMesh*); + +// add mesh as fluidsim object +int elbeemAddMesh(struct elbeemMesh*); + +// do the actual simulation +int elbeemSimulate(void); + +// continue a previously stopped simulation +int elbeemContinueSimulation(void); + + +// helper functions + +// simplify animation channels +// returns if the channel and its size changed +int elbeemSimplifyChannelFloat(float *channel, int *size); +int elbeemSimplifyChannelVec3(float *channel, int *size); + +// helper functions implemented in utilities.cpp + +/* set elbeem debug output level (0=off to 10=full on) */ +void elbeemSetDebugLevel(int level); +/* elbeem debug output function, prints if debug level >0 */ +void elbeemDebugOut(char *msg); + +/* estimate how much memory a given setup will require */ +double elbeemEstimateMemreq(int res, + float sx, float sy, float sz, + int refine, char *retstr); + + + +#ifdef __cplusplus +} +#endif // __cplusplus + + + +/******************************************************************************/ +// internal defines, do not use for initializing elbeemMesh +// structs, for these use OB_xxx defines above + +/*! fluid geometry init types */ +#define FGI_FLAGSTART 16 +#define FGI_FLUID (1<<(FGI_FLAGSTART+ 0)) +#define FGI_NO_FLUID (1<<(FGI_FLAGSTART+ 1)) +#define FGI_BNDNO (1<<(FGI_FLAGSTART+ 2)) +#define FGI_BNDFREE (1<<(FGI_FLAGSTART+ 3)) +#define FGI_BNDPART (1<<(FGI_FLAGSTART+ 4)) +#define FGI_NO_BND (1<<(FGI_FLAGSTART+ 5)) +#define FGI_MBNDINFLOW (1<<(FGI_FLAGSTART+ 6)) +#define FGI_MBNDOUTFLOW (1<<(FGI_FLAGSTART+ 7)) + +// all boundary types at once +#define FGI_ALLBOUNDS ( FGI_BNDNO | FGI_BNDFREE | FGI_BNDPART | FGI_MBNDINFLOW | FGI_MBNDOUTFLOW ) + + +#endif // ELBEEM_API_H diff --git a/intern/elbeem/intern/Makefile b/intern/elbeem/intern/Makefile new file mode 100644 index 00000000000..49f0b936e6b --- /dev/null +++ b/intern/elbeem/intern/Makefile @@ -0,0 +1,53 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# elbeem intern Makefile +# + +LIBNAME = elbeem +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +unexport NAN_QUIET + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -DNOGUI -DELBEEM_BLENDER +CPPFLAGS += -I. +CPPFLAGS += -I../extern +CPPFLAGS += $(NAN_SDLCFLAGS) +CPPFLAGS += -I$(NAN_PNG)/include +CPPFLAGS += -I$(NAN_PNG)/include/libpng + +# zlib +ifeq ($(OS),$(findstring $(OS), "solaris windows")) + CPPFLAGS += -I$(NAN_ZLIB)/include +endif diff --git a/intern/elbeem/intern/attributes.cpp b/intern/elbeem/intern/attributes.cpp new file mode 100644 index 00000000000..8e337a92a4e --- /dev/null +++ b/intern/elbeem/intern/attributes.cpp @@ -0,0 +1,359 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * DEPRECATED - replaced by elbeem API, only channels are still used + * + *****************************************************************************/ + +#include "attributes.h" +#include "ntl_matrices.h" +#include "elbeem.h" + + + +/****************************************************************************** + * attribute conversion functions + *****************************************************************************/ + +bool Attribute::initChannel(int elemSize) { + elemSize=0; // remove warning + return false; +} +string Attribute::getAsString(bool debug) { + debug=false; // remove warning + return string(""); +} +int Attribute::getAsInt() { + return 0; +} +bool Attribute::getAsBool() { + return false; +} +double Attribute::getAsFloat() { + return 0.; +} +ntlVec3d Attribute::getAsVec3d() { + return ntlVec3d(0.); +} +void Attribute::getAsMat4Gfx(ntlMat4Gfx *mat) { + mat=NULL; // remove warning +} +string Attribute::getCompleteString() { + return string(""); +} + + +/****************************************************************************** + * channel returns + *****************************************************************************/ + +AnimChannel Attribute::getChannelFloat() { + return AnimChannel(); +} +AnimChannel Attribute::getChannelInt() { + return AnimChannel(); +} +AnimChannel Attribute::getChannelVec3d() { + return AnimChannel(); +} +AnimChannel +Attribute::getChannelSetVec3f() { + return AnimChannel(); +} + +/****************************************************************************** + * check if there were unknown params + *****************************************************************************/ +bool AttributeList::checkUnusedParams() { + return false; +} +void AttributeList::setAllUsed() { +} + +/****************************************************************************** + * Attribute list read functions + *****************************************************************************/ +int AttributeList::readInt(string name, int defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} +bool AttributeList::readBool(string name, bool defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} +double AttributeList::readFloat(string name, double defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} +string AttributeList::readString(string name, string defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} +ntlVec3d AttributeList::readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return defaultValue; +} + +void AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed, ntlMat4Gfx *mat) { + *mat = defaultValue; + name=source=target=string(""); needed=false; mat=NULL; // remove warning +} + +// set that a parameter can be given, and will be ignored... +bool AttributeList::ignoreParameter(string name, string source) { + name=source=(""); // remove warning + return false; +} + +// read channels +AnimChannel AttributeList::readChannelInt(string name, int defaultValue, string source, string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelFloat(string name, double defaultValue, string source, string target, bool needed ) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelVec3d(string name, ntlVec3d defaultValue, string source, string target, bool needed ) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelSetVec3f(string name, ntlSetVec3f defaultValue, string source, string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelSinglePrecFloat(string name, float defaultValue, string source, string target, bool needed ) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} +AnimChannel AttributeList::readChannelVec3f(string name, ntlVec3f defaultValue, string source, string target, bool needed) { + name=source=target=string(""); needed=false; // remove warning + return AnimChannel(defaultValue); +} + +/****************************************************************************** + * destructor + *****************************************************************************/ +AttributeList::~AttributeList() { +}; + + +/****************************************************************************** + * debugging + *****************************************************************************/ + +//! debug function, prints value +void Attribute::print() { +} + +//! debug function, prints all attribs +void AttributeList::print() { +} + + +/****************************************************************************** + * import attributes from other attribute list + *****************************************************************************/ +void AttributeList::import(AttributeList *oal) { + oal=NULL; // remove warning +} + + +/****************************************************************************** + * channel max finding + *****************************************************************************/ +ntlVec3f channelFindMaxVf (AnimChannel channel) { + ntlVec3f ret(0.0); + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret=channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} +ntlVec3d channelFindMaxVd (AnimChannel channel) { + ntlVec3d ret(0.0); + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret=channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} +int channelFindMaxi (AnimChannel channel) { + int ret = 0; + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret= (int)channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} +float channelFindMaxf (AnimChannel channel) { + float ret = 0.0; + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret=channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} +double channelFindMaxd (AnimChannel channel) { + double ret = 0.0; + float maxLen = 0.0; + for(size_t i=0; imaxLen) { ret=channel.accessValues()[i]; maxLen=nlen; } + } + return ret; +} + +/****************************************************************************** + // unoptimized channel simplification functions, use elbeem.cpp functions + // warning - currently only with single precision + *****************************************************************************/ + +template +static bool channelSimplifyScalarT(AnimChannel &channel) { + int size = channel.getSize(); + if(size<=1) return false; + float *nchannel = new float[2*size]; + // convert to array + for(size_t i=0; i vals; + vector times; + for(int i=0; i(vals, times); + } + delete [] nchannel; + return ret; +} +bool channelSimplifyi (AnimChannel &channel) { return channelSimplifyScalarT(channel); } +bool channelSimplifyf (AnimChannel &channel) { return channelSimplifyScalarT(channel); } +bool channelSimplifyd (AnimChannel &channel) { return channelSimplifyScalarT(channel); } +template +static bool channelSimplifyVecT(AnimChannel &channel) { + int size = channel.getSize(); + if(size<=1) return false; + float *nchannel = new float[4*size]; + // convert to array + for(size_t i=0; i vals; + vector times; + for(int i=0; i(vals, times); + } + delete [] nchannel; + return ret; +} +bool channelSimplifyVf (AnimChannel &channel) { + return channelSimplifyVecT(channel); +} +bool channelSimplifyVd (AnimChannel &channel) { + return channelSimplifyVecT(channel); +} + +//! debug function, prints channel as string +template +string AnimChannel::printChannel() { + std::ostringstream ostr; + ostr << " CHANNEL #"<< mValue.size() <<" = { "; + for(size_t i=0;i tmp1; + AnimChannel< double > tmp2; + AnimChannel< string > tmp3; + AnimChannel< ntlVector3Dim > tmp4; + AnimChannel< ntlVector3Dim > tmp5; + tmp1.debugPrintChannel(); + tmp2.debugPrintChannel(); + tmp3.debugPrintChannel(); + tmp4.debugPrintChannel(); + tmp5.debugPrintChannel(); +} + + +ntlSetVec3f::ntlSetVec3f(double v ) { + mVerts.clear(); + mVerts.push_back( ntlVec3f(v) ); +} +const ntlSetVec3f& +ntlSetVec3f::operator=(double v ) { + mVerts.clear(); + mVerts.push_back( ntlVec3f(v) ); + return *this; +} + +std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& vs ) { + os<< "{"; + for(int j=0;j<(int)vs.mVerts.size();j++) os< class ntlMatrix4x4; +class ntlSetVec3f; +std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& i ); + + + +//! An animated attribute channel +template +class AnimChannel +{ + public: + // default constructor + AnimChannel() : + mValue(), mTimes() { mInited = false; debugPrintChannel(); } + + // null init constructor + AnimChannel(Scalar null) : + mValue(1), mTimes(1) { mValue[0]=null; mTimes[0]=0.0; mInited = true; debugPrintChannel(); } + + // proper init + AnimChannel(vector &v, vector &t) : + mValue(v), mTimes(t) { mInited = true; debugPrintChannel(); } + + // desctructor, nothing to do + ~AnimChannel() { }; + + // get interpolated value at time t + Scalar get(double t) const { + if(!mInited) { Scalar null; null=(Scalar)(0.0); return null; } + if(t<=mTimes[0]) { return mValue[0]; } + if(t>=mTimes[mTimes.size()-1]) { return mValue[mTimes.size()-1]; } + for(size_t i=0; it)) { + // interpolate + double d = mTimes[i+1]-mTimes[i]; + double f = (t-mTimes[i])/d; + //return (Scalar)(mValue[i] * (1.0-f) + mValue[i+1] * f); + Scalar ret,tmp; + ret = mValue[i]; + ret *= 1.-f; + tmp = mValue[i+1]; + tmp *= f; + ret += tmp; + return ret; + } + } + // whats this...? + return mValue[0]; + }; + + // get uninterpolated value at time t + Scalar getConstant(double t) const { + //errMsg("DEBB","getc"<=mTimes[mTimes.size()-1]) { return mValue[mTimes.size()-1]; } + for(size_t i=0; it)) { return mValue[i]; } + } + // whats this...? + return mValue[0]; + }; + + // reset to null value + void reset(Scalar null) { + mValue.clear(); + mTimes.clear(); + mValue.push_back(null); + mTimes.push_back(0.0); + } + + //! debug function, prints channel as string + string printChannel(); + //! debug function, prints to stdout if DEBUG_CHANNELS flag is enabled, used in constructors + void debugPrintChannel(); + //! valid init? + bool isInited() const { return mInited; } + + //! get number of entries (value and time sizes have to be equal) + int getSize() const { return mValue.size(); }; + //! raw access of value vector + vector &accessValues() { return mValue; } + //! raw access of time vector + vector &accessTimes() { return mTimes; } + + protected: + + /*! inited at least once? */ + bool mInited; + /*! anim channel attribute values */ + vector mValue; + /*! anim channel attr times */ + vector mTimes; +}; + + +// helper class (not templated) for animated meshes +class ntlSetVec3f { + public: + ntlSetVec3f(): mVerts() {}; + ntlSetVec3f(double v); + ntlSetVec3f(vector &v) { mVerts = v; }; + + const ntlSetVec3f& operator=(double v ); + ntlSetVec3f& operator+=( double v ); + ntlSetVec3f& operator+=( const ntlSetVec3f &v ); + ntlSetVec3f& operator*=( double v ); + ntlSetVec3f& operator*=( const ntlSetVec3f &v ); + + vector mVerts; +}; + + +// warning: DEPRECATED - replaced by elbeem API +class Attribute +{ + public: + Attribute(string mn, vector &value, int setline,bool channel) { + mn = string(""); setline=0; channel=false; value.clear(); // remove warnings + }; + Attribute(Attribute &a) { a.getCompleteString(); }; + ~Attribute() { }; + + void setUsed(bool set){ set=false; } + bool getUsed() { return true; } + void setIsChannel(bool set){ set=false; } + bool getIsChannel() { return false; } + + string getAsString(bool debug=false); + int getAsInt(); + bool getAsBool(); + double getAsFloat(); + ntlVec3d getAsVec3d(); + void getAsMat4Gfx(ntlMatrix4x4 *mat); + + AnimChannel getChannelInt(); + AnimChannel getChannelFloat(); + AnimChannel getChannelVec3d(); + AnimChannel getChannelSetVec3f(); + + string getCompleteString(); + void print(); + + protected: + + bool initChannel(int elemSize); +}; + + +// warning: DEPRECATED - replaced by elbeem API +//! The list of configuration attributes +class AttributeList +{ + public: + AttributeList(string name) { name=string(""); }; + ~AttributeList(); + void addAttr(string name, vector &value, int line, bool isChannel) { + name=string(""); value.clear(); line=0; isChannel=false; // remove warnings + }; + bool exists(string name) { name=string(""); return false; } + void setAllUsed(); + bool checkUnusedParams(); + void import(AttributeList *oal); + int readInt(string name, int defaultValue, string source,string target, bool needed); + bool readBool(string name, bool defaultValue, string source,string target, bool needed); + double readFloat(string name, double defaultValue, string source,string target, bool needed); + string readString(string name, string defaultValue, string source,string target, bool needed); + ntlVec3d readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed); + void readMat4Gfx(string name, ntlMatrix4x4 defaultValue, string source,string target, bool needed, ntlMatrix4x4 *mat); + AnimChannel readChannelInt( string name, int defaultValue=0, string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelFloat( string name, double defaultValue=0, string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelVec3d( string name, ntlVec3d defaultValue=ntlVec3d(0.), string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelSetVec3f(string name, ntlSetVec3f defaultValue=ntlSetVec3f(0.), string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelVec3f( string name, ntlVec3f defaultValue=ntlVec3f(0.), string source=string("src"), string target=string("dst"), bool needed=false ); + AnimChannel readChannelSinglePrecFloat( string name, float defaultValue=0., string source=string("src"), string target=string("dst"), bool needed=false ); + bool ignoreParameter(string name, string source); + void print(); + protected: +}; + +ntlVec3f channelFindMaxVf (AnimChannel channel); +ntlVec3d channelFindMaxVd (AnimChannel channel); +int channelFindMaxi (AnimChannel channel); +float channelFindMaxf (AnimChannel channel); +double channelFindMaxd (AnimChannel channel); + +// unoptimized channel simplification functions, use elbeem.cpp functions +bool channelSimplifyVf (AnimChannel &channel); +bool channelSimplifyVd (AnimChannel &channel); +bool channelSimplifyi (AnimChannel &channel); +bool channelSimplifyf (AnimChannel &channel); +bool channelSimplifyd (AnimChannel &channel); + +//! output channel values? on=1/off=0 +#define DEBUG_PCHANNELS 0 + +//! debug function, prints to stdout if DEBUG_PCHANNELS flag is enabled, used in constructors +template +void AnimChannel::debugPrintChannel() { } + + +#define NTL_ATTRIBUTES_H +#endif + diff --git a/intern/elbeem/intern/elbeem.cpp b/intern/elbeem/intern/elbeem.cpp new file mode 100644 index 00000000000..b2779f51c3b --- /dev/null +++ b/intern/elbeem/intern/elbeem.cpp @@ -0,0 +1,386 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * All code distributed as part of El'Beem is covered by the version 2 of the + * GNU General Public License. See the file COPYING for details. + * Copyright 2003-2006 Nils Thuerey + * + * Main program functions + */ + +#include "elbeem.h" +#include "ntl_blenderdumper.h" +extern "C" void elbeemCheckDebugEnv(void); + +#include "ntl_world.h" +#include "ntl_geometrymodel.h" + +/*****************************************************************************/ +// region of interest global vars +// currently used by e.g. fsgr solver +double guiRoiSX = 0.0; +double guiRoiSY = 0.0; +double guiRoiSZ = 0.0; +double guiRoiEX = 1.0; +double guiRoiEY = 1.0; +double guiRoiEZ = 1.0; +int guiRoiMaxLev=6, guiRoiMinLev=0; + +//! global raytracer pointer (=world) +ntlWorld *gpWorld = NULL; + + +// API + +// reset elbeemSimulationSettings struct with defaults +extern "C" +void elbeemResetSettings(elbeemSimulationSettings *set) { + if(!set) return; + set->version = 3; + set->domainId = 0; + for(int i=0 ; i<3; i++) set->geoStart[i] = 0.0; + for(int i=0 ; i<3; i++) set->geoSize[i] = 1.0; + set->resolutionxyz = 64; + set->previewresxyz = 24; + set->realsize = 1.0; + set->viscosity = 0.000001; + + for(int i=0 ; i<2; i++) set->gravity[i] = 0.0; + set->gravity[2] = -9.81; + + set->animStart = 0; + set->aniFrameTime = 0.01; + set->noOfFrames = 10; + set->gstar = 0.005; + set->maxRefine = -1; + set->generateParticles = 0.0; + set->numTracerParticles = 0; + strcpy(set->outputPath,"./elbeemdata_"); + + set->channelSizeFrameTime=0; + set->channelFrameTime=NULL; + set->channelSizeViscosity=0; + set->channelViscosity=NULL; + set->channelSizeGravity=0; + set->channelGravity=NULL; + + set->domainobsType= FLUIDSIM_OBSTACLE_NOSLIP; + set->domainobsPartslip= 0.; + set->generateVertexVectors = 0; + set->surfaceSmoothing = 1.; + set->surfaceSubdivs = 1; + + set->farFieldSize = 0.; + set->runsimCallback = NULL; + set->runsimUserData = NULL; + + // init identity + for(int i=0; i<16; i++) set->surfaceTrafo[i] = 0.0; + for(int i=0; i<4; i++) set->surfaceTrafo[i*4+i] = 1.0; +} + +// start fluidsim init +extern "C" +int elbeemInit() { + setElbeemState( SIMWORLD_INITIALIZING ); + setElbeemErrorString("[none]"); + resetGlobalColorSetting(); + + elbeemCheckDebugEnv(); + debMsgStd("performElbeemSimulation",DM_NOTIFY,"El'Beem Simulation Init Start as Plugin, debugLevel:"<addDomain(settings); + return 0; +} + +// error message access +extern "C" +void elbeemGetErrorString(char *buffer) { + if(!buffer) return; + strncpy(buffer,getElbeemErrorString(),256); +} + +// reset elbeemMesh struct with zeroes +extern "C" +void elbeemResetMesh(elbeemMesh *mesh) { + if(!mesh) return; + // init typedef struct elbeemMesh + mesh->type = 0; + + mesh->parentDomainId = 0; + + /* vertices */ + mesh->numVertices = 0; + mesh->vertices = NULL; + + mesh->channelSizeVertices = 0; + mesh->channelVertices = NULL; + + /* triangles */ + mesh->numTriangles = 0; + mesh->triangles = NULL; + + /* animation channels */ + mesh->channelSizeTranslation = 0; + mesh->channelTranslation = NULL; + mesh->channelSizeRotation = 0; + mesh->channelRotation = NULL; + mesh->channelSizeScale = 0; + mesh->channelScale = NULL; + + /* active channel */ + mesh->channelSizeActive = 0; + mesh->channelActive = NULL; + + mesh->channelSizeInitialVel = 0; + mesh->channelInitialVel = NULL; + + mesh->localInivelCoords = 0; + + mesh->obstacleType= FLUIDSIM_OBSTACLE_NOSLIP; + mesh->obstaclePartslip= 0.; + mesh->obstacleImpactFactor= 1.; + + mesh->volumeInitType= OB_VOLUMEINIT_VOLUME; + + /* name of the mesh, mostly for debugging */ + mesh->name = "[unnamed]"; +} + +int globalMeshCounter = 1; +// add mesh as fluidsim object +extern "C" +int elbeemAddMesh(elbeemMesh *mesh) { + int initType = -1; + if(getElbeemState() != SIMWORLD_INITIALIZING) { errFatal("elbeemAddMesh","World and domain not initialized, call elbeemInit and elbeemAddDomain before...", SIMWORLD_INITERROR); } + + switch(mesh->type) { + case OB_FLUIDSIM_OBSTACLE: + if (mesh->obstacleType==FLUIDSIM_OBSTACLE_PARTSLIP) initType = FGI_BNDPART; + else if(mesh->obstacleType==FLUIDSIM_OBSTACLE_FREESLIP) initType = FGI_BNDFREE; + else /*if(mesh->obstacleType==FLUIDSIM_OBSTACLE_NOSLIP)*/ initType = FGI_BNDNO; + break; + case OB_FLUIDSIM_FLUID: initType = FGI_FLUID; break; + case OB_FLUIDSIM_INFLOW: initType = FGI_MBNDINFLOW; break; + case OB_FLUIDSIM_OUTFLOW: initType = FGI_MBNDOUTFLOW; break; + } + // invalid type? + if(initType<0) return 1; + + ntlGeometryObjModel *obj = new ntlGeometryObjModel( ); + gpWorld->getRenderGlobals()->getSimScene()->addGeoClass( obj ); + obj->initModel( + mesh->numVertices, mesh->vertices, mesh->numTriangles, mesh->triangles, + mesh->channelSizeVertices, mesh->channelVertices ); + if(mesh->name) obj->setName(string(mesh->name)); + else { + char meshname[100]; + snprintf(meshname,100,"mesh%04d",globalMeshCounter); + obj->setName(string(meshname)); + } + globalMeshCounter++; + obj->setGeoInitId( mesh->parentDomainId+1 ); + obj->setGeoInitIntersect(true); + obj->setGeoInitType(initType); + obj->setGeoPartSlipValue(mesh->obstaclePartslip); + obj->setGeoImpactFactor(mesh->obstacleImpactFactor); + if((mesh->volumeInitTypevolumeInitType>VOLUMEINIT_BOTH)) mesh->volumeInitType = VOLUMEINIT_VOLUME; + obj->setVolumeInit(mesh->volumeInitType); + // use channel instead, obj->setInitialVelocity( ntlVec3Gfx(mesh->iniVelocity[0], mesh->iniVelocity[1], mesh->iniVelocity[2]) ); + obj->initChannels( + mesh->channelSizeTranslation, mesh->channelTranslation, + mesh->channelSizeRotation, mesh->channelRotation, + mesh->channelSizeScale, mesh->channelScale, + mesh->channelSizeActive, mesh->channelActive, + mesh->channelSizeInitialVel, mesh->channelInitialVel + ); + obj->setLocalCoordInivel( mesh->localInivelCoords ); + + debMsgStd("elbeemAddMesh",DM_MSG,"Added elbeem mesh: "<getName()<<" type="<getIsAnimated(), 9 ); + return 0; +} + +// do the actual simulation +extern "C" +int elbeemSimulate(void) { + if(!gpWorld) return 1; + + gpWorld->finishWorldInit(); + if( isSimworldOk() ) { + myTime_t timestart = getTime(); + gpWorld->renderAnimation(); + myTime_t timeend = getTime(); + + if(getElbeemState() != SIMWORLD_STOP) { + // ok, we're done... + delete gpWorld; + gpWorld = NULL; + debMsgStd("elbeemSimulate",DM_NOTIFY, "El'Beem simulation done, time: "<renderAnimation(); + myTime_t timeend = getTime(); + + if(getElbeemState() != SIMWORLD_STOP) { + // ok, we're done... + delete gpWorld; + gpWorld = NULL; + debMsgStd("elbeemContinueSimulation",DM_NOTIFY, "El'Beem simulation done, time: "< gKeepVal; + +#define SIMPLIFY_FLOAT_EPSILON (1e-6f) +#define SIMPLIFY_DOUBLE_EPSILON (1e-12f) +#define SFLOATEQ(x,y) (ABS((x)-(y)) < SIMPLIFY_FLOAT_EPSILON) +#define SDOUBLEEQ(x,y) (ABS((x)-(y)) < SIMPLIFY_DOUBLE_EPSILON) +#define SVECFLOATEQ(x,y) ( \ + (ABS((x)[0]-(y)[0]) < SIMPLIFY_FLOAT_EPSILON) && \ + (ABS((x)[1]-(y)[1]) < SIMPLIFY_FLOAT_EPSILON) && \ + (ABS((x)[2]-(y)[2]) < SIMPLIFY_FLOAT_EPSILON) ) + +// helper function - simplify animation channels +extern "C" +int elbeemSimplifyChannelFloat(float *channel, int* size) { + bool changed = false; + int nsize = *size; + int orgsize = *size; + if(orgsize<1) return false; + gKeepVal.resize( orgsize ); + for(int i=0; irunsimCallback) +// best use with FLUIDSIM_CBxxx defines below. +// >parameters +// return values: 0=continue, 1=stop, 2=abort +// data pointer: user data pointer from elbeemSimulationSettings->runsimUserData +// status integer: 1=running simulation, 2=new frame saved +// frame integer: if status is 1, contains current frame number +typedef int (*elbeemRunSimulationCallback)(void *data, int status, int frame); +#define FLUIDSIM_CBRET_CONTINUE 0 +#define FLUIDSIM_CBRET_STOP 1 +#define FLUIDSIM_CBRET_ABORT 2 +#define FLUIDSIM_CBSTATUS_STEP 1 +#define FLUIDSIM_CBSTATUS_NEWFRAME 2 + + +// global settings for the simulation +typedef struct elbeemSimulationSettings { + /* version number */ + short version; + /* id number of simulation domain, needed if more than a + * single domain should be simulated */ + short domainId; + + /* geometrical extent */ + float geoStart[3], geoSize[3]; + + /* resolutions */ + short resolutionxyz; + short previewresxyz; + /* size of the domain in real units (meters along largest resolution x,y,z extent) */ + float realsize; + + /* fluid properties */ + double viscosity; + /* gravity strength */ + float gravity[3]; + /* anim start end time */ + float animStart, aniFrameTime; + /* no. of frames to simulate & output */ + short noOfFrames; + /* g star param (LBM compressibility) */ + float gstar; + /* activate refinement? */ + short maxRefine; + /* probability for surface particle generation (0.0=off) */ + float generateParticles; + /* amount of tracer particles to generate (0=off) */ + int numTracerParticles; + + /* store output path, and file prefix for baked fluid surface */ + char outputPath[160+80]; + + /* channel for frame time, visc & gravity animations */ + int channelSizeFrameTime; + float *channelFrameTime; + int channelSizeViscosity; + float *channelViscosity; + int channelSizeGravity; + float *channelGravity; // vector + + /* boundary types and settings for domain walls */ + short domainobsType; + float domainobsPartslip; + /* generate speed vectors for vertices (e.g. for image based motion blur)*/ + short generateVertexVectors; + /* strength of surface smoothing */ + float surfaceSmoothing; + /* no. of surface subdivisions */ + int surfaceSubdivs; + + /* global transformation to apply to fluidsim mesh */ + float surfaceTrafo[4*4]; + + /* development variables, testing for upcoming releases...*/ + float farFieldSize; + + /* callback function to notify calling program of performed simulation steps + * or newly available frame data, if NULL it is ignored */ + elbeemRunSimulationCallback runsimCallback; + /* pointer passed to runsimCallback for user data storage */ + void* runsimUserData; + +} elbeemSimulationSettings; + + +// defines for elbeemMesh->type below +#define OB_FLUIDSIM_FLUID 4 +#define OB_FLUIDSIM_OBSTACLE 8 +#define OB_FLUIDSIM_INFLOW 16 +#define OB_FLUIDSIM_OUTFLOW 32 + +// defines for elbeemMesh->obstacleType below +#define FLUIDSIM_OBSTACLE_NOSLIP 1 +#define FLUIDSIM_OBSTACLE_PARTSLIP 2 +#define FLUIDSIM_OBSTACLE_FREESLIP 3 + +#define OB_VOLUMEINIT_VOLUME 1 +#define OB_VOLUMEINIT_SHELL 2 +#define OB_VOLUMEINIT_BOTH (OB_VOLUMEINIT_SHELL|OB_VOLUMEINIT_VOLUME) + +// a single mesh object +typedef struct elbeemMesh { + /* obstacle,fluid or inflow... */ + short type; + /* id of simulation domain it belongs to */ + short parentDomainId; + + /* vertices */ + int numVertices; + float *vertices; // = float[n][3]; + /* animated vertices */ + int channelSizeVertices; + float *channelVertices; // = float[channelSizeVertices* (n*3+1) ]; + + /* triangles */ + int numTriangles; + int *triangles; // = int[][3]; + + /* animation channels */ + int channelSizeTranslation; + float *channelTranslation; + int channelSizeRotation; + float *channelRotation; + int channelSizeScale; + float *channelScale; + + /* active channel */ + int channelSizeActive; + float *channelActive; + /* initial velocity channel (e.g. for inflow) */ + int channelSizeInitialVel; + float *channelInitialVel; // vector + /* use initial velocity in object coordinates? (e.g. for rotation) */ + short localInivelCoords; + /* boundary types and settings */ + short obstacleType; + float obstaclePartslip; + /* amount of force transfer from fluid to obj, 0=off, 1=normal */ + float obstacleImpactFactor; + /* init volume, shell or both? use OB_VOLUMEINIT_xxx defines above */ + short volumeInitType; + + /* name of the mesh, mostly for debugging */ + const char *name; +} elbeemMesh; + +// API functions + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + +// reset elbeemSimulationSettings struct with defaults +void elbeemResetSettings(struct elbeemSimulationSettings*); + +// start fluidsim init (returns !=0 upon failure) +int elbeemInit(void); + +// start fluidsim init (returns !=0 upon failure) +int elbeemAddDomain(struct elbeemSimulationSettings*); + +// get failure message during simulation or init +// if an error occured (the string is copied into buffer, +// max. length = 256 chars ) +void elbeemGetErrorString(char *buffer); + +// reset elbeemMesh struct with zeroes +void elbeemResetMesh(struct elbeemMesh*); + +// add mesh as fluidsim object +int elbeemAddMesh(struct elbeemMesh*); + +// do the actual simulation +int elbeemSimulate(void); + +// continue a previously stopped simulation +int elbeemContinueSimulation(void); + + +// helper functions + +// simplify animation channels +// returns if the channel and its size changed +int elbeemSimplifyChannelFloat(float *channel, int *size); +int elbeemSimplifyChannelVec3(float *channel, int *size); + +// helper functions implemented in utilities.cpp + +/* set elbeem debug output level (0=off to 10=full on) */ +void elbeemSetDebugLevel(int level); +/* elbeem debug output function, prints if debug level >0 */ +void elbeemDebugOut(char *msg); + +/* estimate how much memory a given setup will require */ +double elbeemEstimateMemreq(int res, + float sx, float sy, float sz, + int refine, char *retstr); + + + +#ifdef __cplusplus +} +#endif // __cplusplus + + + +/******************************************************************************/ +// internal defines, do not use for initializing elbeemMesh +// structs, for these use OB_xxx defines above + +/*! fluid geometry init types */ +#define FGI_FLAGSTART 16 +#define FGI_FLUID (1<<(FGI_FLAGSTART+ 0)) +#define FGI_NO_FLUID (1<<(FGI_FLAGSTART+ 1)) +#define FGI_BNDNO (1<<(FGI_FLAGSTART+ 2)) +#define FGI_BNDFREE (1<<(FGI_FLAGSTART+ 3)) +#define FGI_BNDPART (1<<(FGI_FLAGSTART+ 4)) +#define FGI_NO_BND (1<<(FGI_FLAGSTART+ 5)) +#define FGI_MBNDINFLOW (1<<(FGI_FLAGSTART+ 6)) +#define FGI_MBNDOUTFLOW (1<<(FGI_FLAGSTART+ 7)) + +// all boundary types at once +#define FGI_ALLBOUNDS ( FGI_BNDNO | FGI_BNDFREE | FGI_BNDPART | FGI_MBNDINFLOW | FGI_MBNDOUTFLOW ) + + +#endif // ELBEEM_API_H diff --git a/intern/elbeem/intern/isosurface.cpp b/intern/elbeem/intern/isosurface.cpp new file mode 100644 index 00000000000..9925565b85d --- /dev/null +++ b/intern/elbeem/intern/isosurface.cpp @@ -0,0 +1,1126 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Marching Cubes surface mesh generation + * + *****************************************************************************/ + +#include "isosurface.h" +#include "mcubes_tables.h" +#include "particletracer.h" +#include +#include + +// just use default rounding for platforms where its not available +#ifndef round +#define round(x) (x) +#endif + +/****************************************************************************** + * Constructor + *****************************************************************************/ +IsoSurface::IsoSurface(double iso) : + ntlGeometryObject(), + mSizex(-1), mSizey(-1), mSizez(-1), + mpData(NULL), + mIsoValue( iso ), + mPoints(), + mUseFullEdgeArrays(false), + mpEdgeVerticesX(NULL), mpEdgeVerticesY(NULL), mpEdgeVerticesZ(NULL), + mEdgeArSize(-1), + mIndices(), + + mStart(0.0), mEnd(0.0), mDomainExtent(0.0), + mInitDone(false), + mSmoothSurface(0.0), mSmoothNormals(0.0), + mAcrossEdge(), mAdjacentFaces(), + mCutoff(-1), mCutArray(NULL), // off by default + mpIsoParts(NULL), mPartSize(0.), mSubdivs(0), + mFlagCnt(1), + mSCrad1(0.), mSCrad2(0.), mSCcenter(0.) +{ +} + + +/****************************************************************************** + * The real init... + *****************************************************************************/ +void IsoSurface::initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent) +{ + // range 1-10 (max due to subd array in triangulate) + if(mSubdivs<1) mSubdivs=1; + if(mSubdivs>10) mSubdivs=10; + + // init solver and size + mSizex = setx; + mSizey = sety; + if(setz == 1) {// 2D, create thin 2D surface + setz = 5; + } + mSizez = setz; + mDomainExtent = extent; + + /* check triangulation size (for raytraing) */ + if( ( mStart[0] >= mEnd[0] ) && ( mStart[1] >= mEnd[1] ) && ( mStart[2] >= mEnd[2] ) ){ + // extent was not set, use normalized one from parametrizer + mStart = ntlVec3Gfx(0.0) - extent*0.5; + mEnd = ntlVec3Gfx(0.0) + extent*0.5; + } + + // init + mIndices.clear(); + mPoints.clear(); + + int nodes = mSizez*mSizey*mSizex; + mpData = new float[nodes]; + for(int i=0;i0) && (kmSizex-2-coAdd-mCutoff) || + (j>mSizey-2-coAdd-mCutoff) ) { + if(mCutArray) { + if(k < mCutArray[j*this->mSizex+i]) continue; + } else { continue; } + } + + // Create the triangles... + for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) { + mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] ); + mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] ); + mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] ); + } + + }//i + }// j + + // copy edge arrays + if(!mUseFullEdgeArrays) { + for(int j=0;j<(mSizey-0);j++) + for(int i=0;i<(mSizex-0);i++) { + //int edgek = 0; + const int dst = ISOLEVEL_INDEX( i+0, j+0, 0); + const int src = ISOLEVEL_INDEX( i+0, j+0, 1); + mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ]; + mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ]; + mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ]; + mpEdgeVerticesX[ src ]=-1; + mpEdgeVerticesY[ src ]=-1; + mpEdgeVerticesZ[ src ]=-1; + } + } // */ + + } // k + + // precalculate normals using an approximation of the scalar field gradient + for(int ni=0;ni<(int)mPoints.size();ni++) { normalize( mPoints[ni].n ); } + + } else { // subdivs + +#define EDGEAR_INDEX(Ai,Aj,Ak, Bi,Bj) ((mSizex*mSizey*mSubdivs*mSubdivs*(Ak))+\ + (mSizex*mSubdivs*((Aj)*mSubdivs+(Bj)))+((Ai)*mSubdivs)+(Bi)) + +#define ISOTRILININT(fi,fj,fk) ( \ + (1.-(fi))*(1.-(fj))*(1.-(fk))*orgval[0] + \ + ( (fi))*(1.-(fj))*(1.-(fk))*orgval[1] + \ + ( (fi))*( (fj))*(1.-(fk))*orgval[2] + \ + (1.-(fi))*( (fj))*(1.-(fk))*orgval[3] + \ + (1.-(fi))*(1.-(fj))*( (fk))*orgval[4] + \ + ( (fi))*(1.-(fj))*( (fk))*orgval[5] + \ + ( (fi))*( (fj))*( (fk))*orgval[6] + \ + (1.-(fi))*( (fj))*( (fk))*orgval[7] ) + + // use subdivisions + gfxReal subdfac = 1./(gfxReal)(mSubdivs); + gfxReal orgGsx = gsx; + gfxReal orgGsy = gsy; + gfxReal orgGsz = gsz; + gsx *= subdfac; + gsy *= subdfac; + gsz *= subdfac; + if(mUseFullEdgeArrays) { + errMsg("IsoSurface::triangulate","Disabling mUseFullEdgeArrays!"); + } + + // subdiv local arrays + gfxReal orgval[8]; + gfxReal subdAr[2][11][11]; // max 10 subdivs! + ParticleObject* *arppnt = new ParticleObject*[mSizez*mSizey*mSizex]; + + // construct pointers + // part test + int pInUse = 0; + int pUsedTest = 0; + // reset particles + // reset list array + for(int k=0;k<(mSizez);k++) + for(int j=0;j<(mSizey);j++) + for(int i=0;i<(mSizex);i++) { + arppnt[ISOLEVEL_INDEX(i,j,k)] = NULL; + } + if(mpIsoParts) { + for(vector::iterator pit= mpIsoParts->getParticlesBegin(); + pit!= mpIsoParts->getParticlesEnd(); pit++) { + if( (*pit).getActive()==false ) continue; + if( (*pit).getType()!=PART_DROP) continue; + (*pit).setNext(NULL); + } + // build per node lists + for(vector::iterator pit= mpIsoParts->getParticlesBegin(); + pit!= mpIsoParts->getParticlesEnd(); pit++) { + if( (*pit).getActive()==false ) continue; + if( (*pit).getType()!=PART_DROP) continue; + // check lifetime ignored here + ParticleObject *p = &(*pit); + const ntlVec3Gfx ppos = p->getPos(); + const int pi= (int)round(ppos[0])+0; + const int pj= (int)round(ppos[1])+0; + int pk= (int)round(ppos[2])+0;// no offset necessary + // 2d should be handled by solver. if(LBMDIM==2) { pk = 0; } + + if(pi<0) continue; + if(pj<0) continue; + if(pk<0) continue; + if(pi>mSizex-1) continue; + if(pj>mSizey-1) continue; + if(pk>mSizez-1) continue; + ParticleObject* &pnt = arppnt[ISOLEVEL_INDEX(pi,pj,pk)]; + if(pnt) { + // append + ParticleObject* listpnt = pnt; + while(listpnt) { + if(!listpnt->getNext()) { + listpnt->setNext(p); listpnt = NULL; + } else { + listpnt = listpnt->getNext(); + } + } + } else { + // start new list + pnt = p; + } + pInUse++; + } + } // mpIsoParts + + debMsgStd("IsoSurface::triangulate",DM_MSG,"Starting. Parts in use:"<=mSizez-1) continue; + for(int poj=-poDistOffset; poj<1+poDistOffset; poj++) { + if(j+poj<0) continue; + if(j+poj>=mSizey-1) continue; + for(int poi=-poDistOffset; poi<1+poDistOffset; poi++) { + if(i+poi<0) continue; + if(i+poi>=mSizex-1) continue; + ParticleObject *p; + p = arppnt[ISOLEVEL_INDEX(i+poi,j+poj,k+pok)]; + while(p) { // */ + /* + for(vector::iterator pit= mpIsoParts->getParticlesBegin(); + pit!= mpIsoParts->getParticlesEnd(); pit++) { { { { + // debug test! , full list slow! + if(( (*pit).getActive()==false ) || ( (*pit).getType()!=PART_DROP)) continue; + ParticleObject *p; + p = &(*pit); // */ + + pUsedTest++; + ntlVec3Gfx ppos = p->getPos(); + const int spi= (int)round( (ppos[0]+1.-(gfxReal)i) *(gfxReal)mSubdivs-1.5); + const int spj= (int)round( (ppos[1]+1.-(gfxReal)j) *(gfxReal)mSubdivs-1.5); + const int spk= (int)round( (ppos[2]+1.-(gfxReal)k) *(gfxReal)mSubdivs-1.5)-sdkOffset; // why -2? + // 2d should be handled by solver. if(LBMDIM==2) { spk = 0; } + + gfxReal pfLen = p->getSize()*1.5*mPartSize; // test, was 1.1 + const gfxReal minPfLen = subdfac*0.8; + if(pfLengetSize()<<" ps"< 1) { continue; } // */ + for(int swj=-icellpsize; swj<=icellpsize; swj++) { + if(spj+swj< 0) { continue; } + if(spj+swj>mSubdivs+0) { continue; } // */ + for(int swi=-icellpsize; swi<=icellpsize; swi++) { + if(spi+swi< 0) { continue; } + if(spi+swi>mSubdivs+0) { continue; } // */ + ntlVec3Gfx cellp = ntlVec3Gfx( + (1.5+(gfxReal)(spi+swi)) *subdfac + (gfxReal)(i-1), + (1.5+(gfxReal)(spj+swj)) *subdfac + (gfxReal)(j-1), + (1.5+(gfxReal)(spk+swk)+sdkOffset) *subdfac + (gfxReal)(k-1) + ); + //if(swi==0 && swj==0 && swk==0) subdAr[spk][spj][spi] = 1.; // DEBUG + // clip domain boundaries again + if(cellp[0]<1.) { continue; } + if(cellp[1]<1.) { continue; } + if(cellp[2]<1.) { continue; } + if(cellp[0]>(gfxReal)mSizex-3.) { continue; } + if(cellp[1]>(gfxReal)mSizey-3.) { continue; } + if(cellp[2]>(gfxReal)mSizez-3.) { continue; } + gfxReal len = norm(cellp-ppos); + gfxReal isoadd = 0.; + const gfxReal baseIsoVal = mIsoValue*1.1; + if(len1.) { continue; } + subdAr[spk+swk][spj+swj][spi+swi] = arval + isoadd; + } } } + + p = p->getNext(); + } + } } } // poDist loops */ + + py = mStart[1]+(((double)j-0.5)*orgGsy)-gsy; + for(int sj=0;sj 0) { + + // where to look up if this point already exists + const int edgek = 0; + const int baseIn = EDGEAR_INDEX( i+0, j+0, edgek+0, si,sj); + eVert[ 0] = &mpEdgeVerticesX[ baseIn ]; + eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ]; + eVert[ 2] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ]; + eVert[ 3] = &mpEdgeVerticesY[ baseIn ]; + + eVert[ 4] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ]; + eVert[ 5] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+1,sj+0) ]; // with subdivs + eVert[ 6] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+1) ]; + eVert[ 7] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ]; + + eVert[ 8] = &mpEdgeVerticesZ[ baseIn ]; + eVert[ 9] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+0) ]; // with subdivs + eVert[10] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+1) ]; + eVert[11] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ]; + + // grid positions + pos[0] = ntlVec3Gfx(px ,py ,pz); + pos[1] = ntlVec3Gfx(px+gsx,py ,pz); + pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz); // with subdivs + pos[3] = ntlVec3Gfx(px ,py+gsy,pz); + pos[4] = ntlVec3Gfx(px ,py ,pz+gsz); + pos[5] = ntlVec3Gfx(px+gsx,py ,pz+gsz); + pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz); // with subdivs + pos[7] = ntlVec3Gfx(px ,py+gsy,pz+gsz); + + // check all edges + for(int e=0;e<12;e++) { + if (mcEdgeTable[cubeIndex] & (1<0) { + //smoSubdfac = 1./(float)(mSubdivs); + smoSubdfac = pow(0.55,(double)mSubdivs); // slightly stronger + } + if(mSmoothSurface>0. || mSmoothNormals>0.) debMsgStd("IsoSurface::triangulate",DM_MSG,"Smoothing...",10); + if(mSmoothSurface>0.0) { + smoothSurface(mSmoothSurface*smoSubdfac, (mSmoothNormals<=0.0) ); + } + if(mSmoothNormals>0.0) { + smoothNormals(mSmoothNormals*smoSubdfac); + } + + myTime_t tritimeend = getTime(); + debMsgStd("IsoSurface::triangulate",DM_MSG,"took "<< getTimeString(tritimeend-tritimestart)<<", S("<getNumParticles(), 10); +} + + + + + +/****************************************************************************** + * Get triangles for rendering + *****************************************************************************/ +void IsoSurface::getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ) +{ + if(!mInitDone) { + debugOut("IsoSurface::getTriangles warning: Not initialized! ", 10); + return; + } + t = 0.; + //return; // DEBUG + + /* triangulate field */ + triangulate(); + //errMsg("TRIS"," "<size()<<" ns"<size()<<" ts"<size() ); + //errMsg("NM"," ovs"<push_back( mPoints[i].v ); + } + for(int i=0;i<(int)mPoints.size();i++) { + normals->push_back( mPoints[i].n ); + } + + //errMsg("N2"," ivi"<size()<<" ns"<size()<<" ts"<size() ); + //errMsg("N2"," ovs"< 0) { + flag |= (1<< (geoiId+4)); + flag |= mGeoInitType; + } + + tri.setFlags( flag ); + + /* triangle normal missing */ + tri.setNormal( ntlVec3Gfx(0.0) ); + tri.setSmoothNormals( smooth ); + tri.setObjectId( objectId ); + triangles->push_back( tri ); + } + //errMsg("N3"," ivi"<size()<<" ns"<size()<<" ts"<size() ); + return; +} + + + +inline ntlVec3Gfx IsoSurface::getNormal(int i, int j,int k) { + // WARNING - this requires a security boundary layer... + ntlVec3Gfx ret(0.0); + ret[0] = *getData(i-1,j ,k ) - + *getData(i+1,j ,k ); + ret[1] = *getData(i ,j-1,k ) - + *getData(i ,j+1,k ); + ret[2] = *getData(i ,j ,k-1 ) - + *getData(i ,j ,k+1 ); + return ret; +} + + + + +/****************************************************************************** + * + * Surface improvement, inspired by trimesh2 library + * (http://www.cs.princeton.edu/gfx/proj/trimesh2/) + * + *****************************************************************************/ + +void IsoSurface::setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc) { + mSCrad1 = radi1*radi1; + mSCrad2 = radi2*radi2; + mSCcenter = mscc; +} + +// compute normals for all generated triangles +void IsoSurface::computeNormals() { + for(int i=0;i<(int)mPoints.size();i++) { + mPoints[i].n = ntlVec3Gfx(0.); + } + + for(int i=0;i<(int)mIndices.size();i+=3) { + const int t1 = mIndices[i]; + const int t2 = mIndices[i+1]; + const int t3 = mIndices[i+2]; + const ntlVec3Gfx p1 = mPoints[t1].v; + const ntlVec3Gfx p2 = mPoints[t2].v; + const ntlVec3Gfx p3 = mPoints[t3].v; + const ntlVec3Gfx n1=p1-p2; + const ntlVec3Gfx n2=p2-p3; + const ntlVec3Gfx n3=p3-p1; + const gfxReal len1 = normNoSqrt(n1); + const gfxReal len2 = normNoSqrt(n2); + const gfxReal len3 = normNoSqrt(n3); + const ntlVec3Gfx norm = cross(n1,n2); + mPoints[t1].n += norm * (1./(len1*len3)); + mPoints[t2].n += norm * (1./(len1*len2)); + mPoints[t3].n += norm * (1./(len2*len3)); + } + + for(int i=0;i<(int)mPoints.size();i++) { + normalize(mPoints[i].n); + } +} + +// Diffuse a vector field at 1 vertex, weighted by +// a gaussian of width 1/sqrt(invsigma2) +bool IsoSurface::diffuseVertexField(ntlVec3Gfx *field, const int pointerScale, int src, float invsigma2, ntlVec3Gfx &target) +{ + if((neighbors[src].size()<1) || (pointareas[src]<=0.0)) return 0; + const ntlVec3Gfx srcp = mPoints[src].v; + const ntlVec3Gfx srcn = mPoints[src].n; + if(mSCrad1>0.0 && mSCrad2>0.0) { + ntlVec3Gfx dp = mSCcenter-srcp; dp[2] = 0.0; // only xy-plane + float rd = normNoSqrt(dp); + if(rd > mSCrad2) { + return 0; + } else if(rd > mSCrad1) { + // optimize? + float org = 1.0/sqrt(invsigma2); + org *= (1.0- (rd-mSCrad1) / (mSCrad2-mSCrad1)); + invsigma2 = 1.0/(org*org); + //errMsg("TRi","p"<= 9.0f) continue; + + // aggressive smoothing factor + float smstr = nvdot * pointareas[bbn]; + // Accumulate weight times field at neighbor + target += *(field+pointerScale*bbn)*smstr; + smstrSum += smstr; + + for(int i = 0; i < (int)neighbors[bbn].size(); i++) { + const int nn = neighbors[bbn][i]; + if (flags[nn] == flag) continue; + mDboundary.push_back(nn); + } + } + target /= smstrSum; + return 1; +} + + +// perform smoothing of the surface (and possible normals) +void IsoSurface::smoothSurface(float sigma, bool normSmooth) +{ + int nv = mPoints.size(); + if ((int)flags.size() != nv) flags.resize(nv); + int nf = mIndices.size()/3; + + { // need neighbors + vector numneighbors(mPoints.size()); + int i; + for (i = 0; i < (int)mIndices.size()/3; i++) { + numneighbors[mIndices[i*3+0]]++; + numneighbors[mIndices[i*3+1]]++; + numneighbors[mIndices[i*3+2]]++; + } + + neighbors.clear(); + neighbors.resize(mPoints.size()); + for (i = 0; i < (int)mPoints.size(); i++) { + neighbors[i].clear(); + neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries + } + + for (i = 0; i < (int)mIndices.size()/3; i++) { + for (int j = 0; j < 3; j++) { + vector &me = neighbors[ mIndices[i*3+j]]; + int n1 = mIndices[i*3+((j+1)%3)]; + int n2 = mIndices[i*3+((j+2)%3)]; + if (std::find(me.begin(), me.end(), n1) == me.end()) + me.push_back(n1); + if (std::find(me.begin(), me.end(), n2) == me.end()) + me.push_back(n2); + } + } + } // need neighbor + + { // need pointarea + pointareas.clear(); + pointareas.resize(nv); + cornerareas.clear(); + cornerareas.resize(nf); + + for (int i = 0; i < nf; i++) { + // Edges + ntlVec3Gfx e[3] = { + mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v, + mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v, + mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v }; + + // Compute corner weights + float area = 0.5f * norm( cross(e[0], e[1])); + float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) }; + float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]), + l2[1] * (l2[2] + l2[0] - l2[1]), + l2[2] * (l2[0] + l2[1] - l2[2]) }; + if (ew[0] <= 0.0f) { + cornerareas[i][1] = -0.25f * l2[2] * area / + dot(e[0] , e[2]); + cornerareas[i][2] = -0.25f * l2[1] * area / + dot(e[0] , e[1]); + cornerareas[i][0] = area - cornerareas[i][1] - + cornerareas[i][2]; + } else if (ew[1] <= 0.0f) { + cornerareas[i][2] = -0.25f * l2[0] * area / + dot(e[1] , e[0]); + cornerareas[i][0] = -0.25f * l2[2] * area / + dot(e[1] , e[2]); + cornerareas[i][1] = area - cornerareas[i][2] - + cornerareas[i][0]; + } else if (ew[2] <= 0.0f) { + cornerareas[i][0] = -0.25f * l2[1] * area / + dot(e[2] , e[1]); + cornerareas[i][1] = -0.25f * l2[0] * area / + dot(e[2] , e[0]); + cornerareas[i][2] = area - cornerareas[i][0] - + cornerareas[i][1]; + } else { + float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]); + for (int j = 0; j < 3; j++) + cornerareas[i][j] = ewscale * (ew[(j+1)%3] + + ew[(j+2)%3]); + } + + // NT important, check this... +#ifndef WIN32 + if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6; + if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6; + if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6; +#else // WIN32 + // FIXME check as well... + if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6; + if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6; + if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6; +#endif // WIN32 + + pointareas[mIndices[i*3+0]] += cornerareas[i][0]; + pointareas[mIndices[i*3+1]] += cornerareas[i][1]; + pointareas[mIndices[i*3+2]] += cornerareas[i][2]; + } + + } // need pointarea + // */ + + float invsigma2 = 1.0f / (sigma*sigma); + + vector dflt(nv); + for (int i = 0; i < nv; i++) { + if(diffuseVertexField( &mPoints[0].v, 2, + i, invsigma2, dflt[i])) { + // Just keep the displacement + dflt[i] -= mPoints[i].v; + } else { dflt[i] = 0.0; } //?mPoints[i].v; } + } + + // Slightly better small-neighborhood approximation + for (int i = 0; i < nf; i++) { + ntlVec3Gfx c = mPoints[mIndices[i*3+0]].v + + mPoints[mIndices[i*3+1]].v + + mPoints[mIndices[i*3+2]].v; + c /= 3.0f; + for (int j = 0; j < 3; j++) { + int v = mIndices[i*3+j]; + ntlVec3Gfx d =(c - mPoints[v].v) * 0.5f; + dflt[v] += d * (cornerareas[i][j] / + pointareas[mIndices[i*3+j]] * + exp(-0.5f * invsigma2 * normNoSqrt(d)) ); + } + } + + // Filter displacement field + vector dflt2(nv); + for (int i = 0; i < nv; i++) { + if(diffuseVertexField( &dflt[0], 1, + i, invsigma2, dflt2[i])) { } + else { /*mPoints[i].v=0.0;*/ dflt2[i] = 0.0; }//dflt2[i]; } + } + + // Update vertex positions + for (int i = 0; i < nv; i++) { + mPoints[i].v += dflt[i] - dflt2[i]; // second Laplacian + } + + // when normals smoothing off, this cleans up quite well + // costs ca. 50% additional time though + float nsFac = 1.5f; + if(normSmooth) { float ninvsigma2 = 1.0f / (nsFac*nsFac*sigma*sigma); + for (int i = 0; i < nv; i++) { + if( diffuseVertexField( &mPoints[0].n, 2, i, ninvsigma2, dflt[i]) ) { + normalize(dflt[i]); + } else { + dflt[i] = mPoints[i].n; + } + } + for (int i = 0; i < nv; i++) { + mPoints[i].n = dflt[i]; + } + } // smoothNormals copy */ + + //errMsg("SMSURF","done v:"< numneighbors(mPoints.size()); + int i; + for (i = 0; i < (int)mIndices.size()/3; i++) { + numneighbors[mIndices[i*3+0]]++; + numneighbors[mIndices[i*3+1]]++; + numneighbors[mIndices[i*3+2]]++; + } + + neighbors.clear(); + neighbors.resize(mPoints.size()); + for (i = 0; i < (int)mPoints.size(); i++) { + neighbors[i].clear(); + neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries + } + + for (i = 0; i < (int)mIndices.size()/3; i++) { + for (int j = 0; j < 3; j++) { + vector &me = neighbors[ mIndices[i*3+j]]; + int n1 = mIndices[i*3+((j+1)%3)]; + int n2 = mIndices[i*3+((j+2)%3)]; + if (std::find(me.begin(), me.end(), n1) == me.end()) + me.push_back(n1); + if (std::find(me.begin(), me.end(), n2) == me.end()) + me.push_back(n2); + } + } + } // need neighbor + + { // need pointarea + int nf = mIndices.size()/3, nv = mPoints.size(); + pointareas.clear(); + pointareas.resize(nv); + cornerareas.clear(); + cornerareas.resize(nf); + + for (int i = 0; i < nf; i++) { + // Edges + ntlVec3Gfx e[3] = { + mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v, + mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v, + mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v }; + + // Compute corner weights + float area = 0.5f * norm( cross(e[0], e[1])); + float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) }; + float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]), + l2[1] * (l2[2] + l2[0] - l2[1]), + l2[2] * (l2[0] + l2[1] - l2[2]) }; + if (ew[0] <= 0.0f) { + cornerareas[i][1] = -0.25f * l2[2] * area / + dot(e[0] , e[2]); + cornerareas[i][2] = -0.25f * l2[1] * area / + dot(e[0] , e[1]); + cornerareas[i][0] = area - cornerareas[i][1] - + cornerareas[i][2]; + } else if (ew[1] <= 0.0f) { + cornerareas[i][2] = -0.25f * l2[0] * area / + dot(e[1] , e[0]); + cornerareas[i][0] = -0.25f * l2[2] * area / + dot(e[1] , e[2]); + cornerareas[i][1] = area - cornerareas[i][2] - + cornerareas[i][0]; + } else if (ew[2] <= 0.0f) { + cornerareas[i][0] = -0.25f * l2[1] * area / + dot(e[2] , e[1]); + cornerareas[i][1] = -0.25f * l2[0] * area / + dot(e[2] , e[0]); + cornerareas[i][2] = area - cornerareas[i][0] - + cornerareas[i][1]; + } else { + float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]); + for (int j = 0; j < 3; j++) + cornerareas[i][j] = ewscale * (ew[(j+1)%3] + + ew[(j+2)%3]); + } + + // NT important, check this... +#ifndef WIN32 + if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6; + if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6; + if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6; +#else // WIN32 + // FIXME check as well... + if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6; + if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6; + if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6; +#endif // WIN32 + + pointareas[mIndices[i*3+0]] += cornerareas[i][0]; + pointareas[mIndices[i*3+1]] += cornerareas[i][1]; + pointareas[mIndices[i*3+2]] += cornerareas[i][2]; + } + + } // need pointarea + + int nv = mPoints.size(); + if ((int)flags.size() != nv) flags.resize(nv); + float invsigma2 = 1.0f / (sigma*sigma); + + vector nflt(nv); + for (int i = 0; i < nv; i++) { + if(diffuseVertexField( &mPoints[0].n, 2, i, invsigma2, nflt[i])) { + normalize(nflt[i]); + } else { nflt[i]=mPoints[i].n; } + } + + // copy results + for (int i = 0; i < nv; i++) { mPoints[i].n = nflt[i]; } +} + + diff --git a/intern/elbeem/intern/isosurface.h b/intern/elbeem/intern/isosurface.h new file mode 100644 index 00000000000..9902b40199c --- /dev/null +++ b/intern/elbeem/intern/isosurface.h @@ -0,0 +1,230 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Marching Cubes "displayer" + * + *****************************************************************************/ + +#ifndef ISOSURFACE_H + +#include "ntl_geometryobject.h" +#include "ntl_bsptree.h" + +#define ISO_STRICT_DEBUG 0 +#define ISOSTRICT_EXIT *((int *)0)=0; + +/* access some 3d array */ +#define ISOLEVEL_INDEX(ii,ij,ik) ((mSizex*mSizey*(ik))+(mSizex*(ij))+((ii))) + +class ParticleTracer; + +/* struct for a small cube in the scalar field */ +typedef struct { + ntlVec3Gfx pos[8]; + double value[8]; + int i,j,k; +} IsoLevelCube; + + +typedef struct { + ntlVec3Gfx v; // vertex + ntlVec3Gfx n; // vertex normal +} IsoLevelVertex; + +//! class to triangulate a scalar field, e.g. for +// the fluid surface, templated by scalar field access object +class IsoSurface : + public ntlGeometryObject //, public S +{ + + public: + + /*! Constructor */ + IsoSurface(double iso); + /*! Destructor */ + virtual ~IsoSurface(); + + /*! Init ararys etc. */ + virtual void initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent); + + /*! Reset all values */ + void resetAll(gfxReal val); + + /*! triangulate the scalar field given by pointer*/ + void triangulate( void ); + + /*! set particle pointer */ + void setParticles(ParticleTracer *pnt,float psize){ mpIsoParts = pnt; mPartSize=psize; }; + /*! set # of subdivisions, this has to be done before init! */ + void setSubdivs(int s) { + if(mInitDone) errFatal("IsoSurface::setSubdivs","Changing subdivs after init!", SIMWORLD_INITERROR); + if(s<1) s=1; if(s>10) s=10; + mSubdivs = s; } + int getSubdivs() { return mSubdivs;} + /*! set full edge settings, this has to be done before init! */ + void setUseFulledgeArrays(bool set) { + if(mInitDone) errFatal("IsoSurface::setUseFulledgeArrays","Changing usefulledge after init!", SIMWORLD_INITERROR); + mUseFullEdgeArrays = set;} + + protected: + + /* variables ... */ + + //! size + int mSizex, mSizey, mSizez; + + //! data pointer + float *mpData; + + //! Level of the iso surface + double mIsoValue; + + //! Store all the triangles vertices + vector mPoints; + + //! use full arrays? (not for farfield) + bool mUseFullEdgeArrays; + //! Store indices of calculated points along the cubie edges + int *mpEdgeVerticesX; + int *mpEdgeVerticesY; + int *mpEdgeVerticesZ; + int mEdgeArSize; + + + //! vector for all the triangles (stored as 3 indices) + vector mIndices; + + //! start and end vectors for the triangulation region to create triangles in + ntlVec3Gfx mStart, mEnd; + + //! normalized domain extent from parametrizer/visualizer + ntlVec3Gfx mDomainExtent; + + //! initialized? + bool mInitDone; + + //! amount of surface smoothing + float mSmoothSurface; + //! amount of normal smoothing + float mSmoothNormals; + + //! grid data + vector mAcrossEdge; + vector< vector > mAdjacentFaces; + + //! cutoff border area + int mCutoff; + //! cutoff heigh values + int *mCutArray; + //! particle pointer + ParticleTracer *mpIsoParts; + //! particle size + float mPartSize; + //! no of subdivisions + int mSubdivs; + + //! trimesh vars + vector flags; + int mFlagCnt; + vector cornerareas; + vector pointareas; + vector< vector > neighbors; + + public: + // miscelleanous access functions + + //! set geometry start (for renderer) + void setStart(ntlVec3Gfx set) { mStart = set; }; + ntlVec3Gfx getStart() { return mStart; }; + //! set geometry end (for renderer) + void setEnd(ntlVec3Gfx set) { mEnd = set; }; + ntlVec3Gfx getEnd() { return mEnd; }; + //! set iso level value for surface reconstruction + inline void setIsolevel(double set) { mIsoValue = set; }; + //! set loop subdiv num + inline void setSmoothSurface(float set) { mSmoothSurface = set; }; + inline void setSmoothNormals(float set) { mSmoothNormals = set; }; + inline float getSmoothSurface() { return mSmoothSurface; } + inline float getSmoothNormals() { return mSmoothNormals; } + + // geometry object functions + virtual void getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ); + + //! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB + virtual inline ntlVec3Gfx *getBBStart() { return &mStart; } + virtual inline ntlVec3Gfx *getBBEnd() { return &mEnd; } + + //! access data array + inline float* getData(){ return mpData; } + inline float* getData(int ii, int jj, int kk){ +#if ISO_STRICT_DEBUG==1 + if(ii<0){ errMsg("IsoStrict"," invX- |"<mSizex-1){ errMsg("IsoStrict"," invX+ |"<mSizey-1){ errMsg("IsoStrict"," invY+ |"<mSizez-1){ errMsg("IsoStrict"," invZ+ |"<mSizex-1){ errMsg("IsoStrict"," invX+ |"<mSizey-1){ errMsg("IsoStrict"," invY+ |"<mSizez-1){ errMsg("IsoStrict"," invZ+ |"< mDboundary; + float mSCrad1, mSCrad2; + ntlVec3Gfx mSCcenter; +}; + + +#define ISOSURFACE_H +#endif + + diff --git a/intern/elbeem/intern/loop_tools.h b/intern/elbeem/intern/loop_tools.h new file mode 100644 index 00000000000..3c15a609210 --- /dev/null +++ b/intern/elbeem/intern/loop_tools.h @@ -0,0 +1,109 @@ + +// advance pointer in main loop +#define ADVANCE_POINTERS(p) \ + ccel += (QCELLSTEP*(p)); \ + tcel += (QCELLSTEP*(p)); \ + pFlagSrc+= (p); \ + pFlagDst+= (p); \ + i+= (p); + +#define MAX_CALC_ARR 4 + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// init region vars +#define GRID_REGION_INIT() \ + const int istart = -1+gridLoopBound; \ + const int iend = mLevel[mMaxRefine].lSizex-1-gridLoopBound; \ + LbmFloat calcCurrentMass=0; \ + LbmFloat calcCurrentVolume=0; \ + int calcCellsFilled=0; \ + int calcCellsEmptied=0; \ + int calcNumUsedCells=0; \ + + + + +// ----------------------------------------------------------------------------------- +// serial stuff +#if PARALLEL!=1 + +#define PERFORM_USQRMAXCHECK USQRMAXCHECK(usqr,ux,uy,uz, mMaxVlen, mMxvx,mMxvy,mMxvz); +#define LIST_EMPTY(x) mListEmpty.push_back( x ); +#define LIST_FULL(x) mListFull.push_back( x ); +#define FSGR_ADDPART(x) mpParticles->addFullParticle( x ); + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +#define GRID_REGION_START() \ + { /* main_region */ \ + int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \ + if(gridLoopBound>0){ kstart=getForZMin1(), kend=getForZMax1(mMaxRefine); } \ + int kdir = 1; \ + int jstart = gridLoopBound; \ + int jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \ + const int id=0; \ + LbmFloat *ccel = NULL, *tcel = NULL; \ + CellFlagType *pFlagSrc=NULL, *pFlagDst=NULL; \ + if(mLevel[mMaxRefine].setCurr==1) { \ + kdir = -1; \ + int temp = kend; \ + kend = kstart-1; \ + kstart = temp-1; \ + temp = id; /* dummy remove warning */ \ + } \ + + + + +#define unused_GRID_REGION_END() \ + } /* main_region */ \ + // end unusedGRID_REGION_END + + +// ----------------------------------------------------------------------------------- +#else // PARALLEL==1 + +#include "paraloop.h" + +#endif // PARALLEL==1 + + +// ----------------------------------------------------------------------------------- + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +#define GRID_LOOP_START() \ + for(int k=kstart;k!=kend;k+=kdir) { \ + pFlagSrc = &RFLAG(lev, istart, jstart, k, SRCS(lev)); \ + pFlagDst = &RFLAG(lev, istart, jstart, k, TSET(lev)); \ + ccel = RACPNT(lev, istart, jstart, k, SRCS(lev)); \ + tcel = RACPNT(lev, istart, jstart, k, TSET(lev)); \ + for(int j=jstart;j!=jend;++j) { \ + /* for(int i=0;i>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +#define GRID_LOOPREG_END() \ + \ + } /* i */ \ + int i=0; \ + ADVANCE_POINTERS(2*gridLoopBound); \ + } /* j */ \ + /* COMPRESSGRIDS!=1 */ \ + /* int i=0; */ \ + /* ADVANCE_POINTERS(mLevel[lev].lSizex*2); */ \ + } /* all cell loop k,j,i */ \ + if(doReduce) { } /* dummy remove warning */ \ + } /* main_region */ \ + \ + + + +// old loop for COMPRESSGRIDS==0 +#define old__GRID_LOOP_START() \ + for(int k=kstart;k +#include + +#include "utilities.h" +#include "ntl_matrices.h" +#include "ntl_blenderdumper.h" +#include "ntl_world.h" +#include "solver_interface.h" + +#include + + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +ntlBlenderDumper::ntlBlenderDumper() : ntlWorld() +{ + // same as normal constructor here +} +ntlBlenderDumper::ntlBlenderDumper(string filename, bool commandlineMode) : + ntlWorld(filename,commandlineMode) +{ + // init world +} + + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlBlenderDumper::~ntlBlenderDumper() +{ + debMsgStd("ntlBlenderDumper",DM_NOTIFY, "ntlBlenderDumper done", 10); +} + +// required globals +extern bool glob_mpactive; +extern int glob_mpnum, glob_mpindex; + +/****************************************************************************** + * Only dump time dep. objects to file + *****************************************************************************/ +int ntlBlenderDumper::renderScene( void ) +{ + char nrStr[5]; /* nr conversion */ + ntlRenderGlobals *glob = mpGlob; + ntlScene *scene = mpGlob->getSimScene(); + bool debugOut = false; + bool debugRender = false; +#if ELBEEM_PLUGIN==1 + debugOut = false; +#endif // ELBEEM_PLUGIN==1 + + vector gmName; // gm names + vector gmMat; // materials for gm + int numGMs = 0; // no. of .obj models created + + if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Dumping geometry data", 1); + long startTime = getTime(); + snprintf(nrStr, 5, "%04d", glob->getAniCount() ); + + // local scene vars + vector Triangles; + vector Vertices; + vector VertNormals; + + // check geo objects + int idCnt = 0; // give IDs to objects + for (vector::iterator iter = scene->getGeoClasses()->begin(); + iter != scene->getGeoClasses()->end(); iter++) { + if(!(*iter)->getVisible()) continue; + int tid = (*iter)->getTypeId(); + + if(tid & GEOCLASSTID_OBJECT) { + // normal geom. objects -> ignore + } + if(tid & GEOCLASSTID_SHADER) { + ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); //dynamic_cast(*iter); + string outname = geoshad->getOutFilename(); + if(outname.length()<1) outname = mpGlob->getOutFilename(); + geoshad->notifyShaderOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname); + + for (vector::iterator siter = geoshad->getObjectsBegin(); + siter != geoshad->getObjectsEnd(); + siter++) { + if(debugOut) debMsgStd("ntlBlenderDumper::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName(), 8); + + (*siter)->notifyOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname, this->mSimulationTime); + bool doDump = false; + bool isPreview = false; + // only dump final&preview surface meshes + if( (*siter)->getName().find( "final" ) != string::npos) { + doDump = true; + } else if( (*siter)->getName().find( "preview" ) != string::npos) { + doDump = true; + isPreview = true; + } + if(!doDump) continue; + + // dont quit, some objects need notifyOfDump call + if((glob_mpactive) && (glob_mpindex>0)) { + continue; //return 0; + } + + // only dump geo shader objects + Triangles.clear(); + Vertices.clear(); + VertNormals.clear(); + (*siter)->initialize( mpGlob ); + (*siter)->getTriangles(this->mSimulationTime, &Triangles, &Vertices, &VertNormals, idCnt); + idCnt ++; + + // WARNING - this is dirty, but simobjs are the only geoshaders right now + SimulationObject *sim = (SimulationObject *)geoshad; + LbmSolverInterface *lbm = sim->getSolver(); + + + // always dump mesh, even empty ones... + + // dump to binary file + std::ostringstream boutfilename(""); + //boutfilename << ecrpath.str() << outname <<"_"<< (*siter)->getName() <<"_" << nrStr << ".obj"; + boutfilename << outname <<"_"<< (*siter)->getName() <<"_" << nrStr; + if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"B-Dumping: "<< (*siter)->getName() + <<", triangles:"<getDumpVelocities())) { + std::ostringstream bvelfilename; + bvelfilename << boutfilename.str(); + bvelfilename << ".bvel.gz"; + gzf = gzopen(bvelfilename.str().c_str(), "wb9"); + if(gzf) { + int numVerts; + if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; } + numVerts = Vertices.size(); + gzwrite(gzf, &numVerts, sizeof(numVerts)); + for(size_t i=0; igetVelocityAt( Vertices[i][0], Vertices[i][1], Vertices[i][2] ); + // translation not necessary, test rotation & scaling? + for(int j=0; j<3; j++) { + float vertp = v[j]; + //if(i<20) errMsg("ntlBlenderDumper","DUMP_VEL final "< *trafo; + trafo = lbm->getDomainTrafo(); + if(trafo) { + // transform into source space + for(size_t i=0; i rottrafo; + rottrafo.initId(); + if(lbm->getDomainTrafo()) { + // dont modifiy original! + rottrafo = *lbm->getDomainTrafo(); + ntlVec3Gfx rTrans,rScale,rRot,rShear; + rottrafo.decompose(rTrans,rScale,rRot,rShear); + rottrafo.initRotationXYZ(rRot[0],rRot[1],rRot[2]); + // only rotate here... + for(size_t i=0; i0) { + if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Objects dumped: "<0)) { + // ok, nothing to do anyway... + } else { + errFatal("ntlBlenderDumper::renderScene","No objects to dump! Aborting...",SIMWORLD_INITERROR); + return 1; + } + } + + // debug timing + long stopTime = getTime(); + debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Scene #"<setAniCount( glob->getAniCount() +1 ); + } + + return 0; +} + + + diff --git a/intern/elbeem/intern/ntl_blenderdumper.h b/intern/elbeem/intern/ntl_blenderdumper.h new file mode 100644 index 00000000000..df66ad7662e --- /dev/null +++ b/intern/elbeem/intern/ntl_blenderdumper.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Replaces std. raytracer, and only dumps time dep. objects to disc, header + * + *****************************************************************************/ +#ifndef NTL_BLENDERDUMPER_H +#include "ntl_world.h" + +class ntlBlenderDumper : + public ntlWorld +{ +public: + /*! Constructor */ + ntlBlenderDumper(); + ntlBlenderDumper(string filename, bool commandlineMode); + /*! Destructor */ + virtual ~ntlBlenderDumper( void ); + + /*! render scene (a single pictures) */ + virtual int renderScene( void ); + +protected: + +}; + +#define NTL_BLENDERDUMPER_H +#endif + diff --git a/intern/elbeem/intern/ntl_bsptree.cpp b/intern/elbeem/intern/ntl_bsptree.cpp new file mode 100644 index 00000000000..c444ec70692 --- /dev/null +++ b/intern/elbeem/intern/ntl_bsptree.cpp @@ -0,0 +1,942 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Tree container for fast triangle intersects + * + *****************************************************************************/ + + +#include "ntl_bsptree.h" +#include "utilities.h" + +#include + +/*! Static global variable for sorting direction */ +int globalSortingAxis; +/*! Access to points array for sorting */ +vector *globalSortingPoints; + +#define TREE_DOUBLEI 300 + +/* try axis selection? */ +bool chooseAxis = 0; +/* do median search? */ +int doSort = 0; + + +//! struct for a single node in the bsp tree +class BSPNode { + public: + BSPNode() {}; + + ntlVec3Gfx min,max; /* AABB for node */ + vector *members; /* stored triangles */ + BSPNode *child[2]; /* pointer to children nodes */ + char axis; /* division axis */ + char cloneVec; /* is this vector a clone? */ + + //! check if node is a leaf + inline bool isLeaf() const { + return (child[0] == NULL); + } +}; + + +//! an element node stack +class BSPStackElement { + public: + //! tree node + BSPNode *node; + //! min and maximum distance along axis + gfxReal mindist, maxdist; +}; + +//! bsp tree stack +class BSPStack { + public: + //! current stack element + int stackPtr; + //! stack storage + BSPStackElement elem[ BSP_STACK_SIZE ]; +}; + +//! triangle bounding box for quick tree subdivision +class TriangleBBox { + public: + //! start and end of triangle bounding box + ntlVec3Gfx start, end; +}; + + +/****************************************************************************** + * calculate tree statistics + *****************************************************************************/ +void calcStats(BSPNode *node, int depth, int &noLeafs, gfxReal &avgDepth, gfxReal &triPerLeaf,int &totalTris) +{ + if(node->members != NULL) { + totalTris += node->members->size(); + } + //depth = 15; // DBEUG! + + if( (node->child[0]==NULL) && (node->child[1]==NULL) ) { + // leaf + noLeafs++; + avgDepth += depth; + triPerLeaf += node->members->size(); + } else { + for(int i=0;i<2;i++) + calcStats(node->child[i], depth+1, noLeafs, avgDepth, triPerLeaf, totalTris); + } +} + + + +/****************************************************************************** + * triangle comparison function for median search + *****************************************************************************/ +bool lessTriangleAverage(const ntlTriangle *x, const ntlTriangle *y) +{ + return x->getAverage(globalSortingAxis) < y->getAverage(globalSortingAxis); +} + + +/****************************************************************************** + * triangle AABB intersection + *****************************************************************************/ +bool ntlTree::checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri) +{ + // test only BB of triangle + TriangleBBox *bbox = &mpTBB[ tri->getBBoxId() ]; + if( bbox->end[0] < min[0] ) return false; + if( bbox->start[0] > max[0] ) return false; + if( bbox->end[1] < min[1] ) return false; + if( bbox->start[1] > max[1] ) return false; + if( bbox->end[2] < min[2] ) return false; + if( bbox->start[2] > max[2] ) return false; + return true; +} + + + + + + + +/****************************************************************************** + * Default constructor + *****************************************************************************/ +ntlTree::ntlTree() : + mStart(0.0), mEnd(0.0), mMaxDepth( 5 ), mMaxListLength( 5 ), mpRoot( NULL) , + mpNodeStack( NULL), mpVertices( NULL ), mpVertNormals( NULL ), mpTriangles( NULL ), + mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0) +{ + errFatal( "ntlTree","Uninitialized BSP Tree!\n",SIMWORLD_INITERROR ); + return; +} + + +/****************************************************************************** + * Constructor with init + *****************************************************************************/ +//ntlTree::ntlTree(int depth, int objnum, vector *vertices, vector *normals, vector *trilist) : +ntlTree::ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask) : + mStart(0.0), mEnd(0.0), mMaxDepth( depth ), mMaxListLength( objnum ), mpRoot( NULL) , + mpNodeStack( NULL), mpTBB( NULL ), + mTriangleMask( 0xFFFF ), + mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0) +{ + // init scene data pointers + mpVertices = scene->getVertexPointer(); + mpVertNormals = scene->getVertexNormalPointer(); + mpTriangles = scene->getTrianglePointer(); + mTriangleMask = triFlagMask; + + if(mpTriangles == NULL) { + errFatal( "ntlTree Cons","no triangle list!\n",SIMWORLD_INITERROR); + return; + } + if(mpTriangles->size() == 0) { + warnMsg( "ntlTree::ntlTree","No triangles ("<< mpTriangles->size() <<")!\n"); + mStart = mEnd = ntlVec3Gfx(0,0,0); + return; + } + if(depth>=BSP_STACK_SIZE) { + errFatal( "ntlTree::ntlTree","Depth to high ("<< mMaxDepth <<")!\n", SIMWORLD_INITERROR ); + return; + } + + /* check triangles (a bit inefficient, but we dont know which vertices belong + to this tree), and generate bounding boxes */ + mppTriangles = new vector; + int noOfTriangles = mpTriangles->size(); + mpTBB = new TriangleBBox[ noOfTriangles ]; + int bbCount = 0; + mStart = mEnd = (*mpVertices)[ mpTriangles->front().getPoints()[0] ]; + //errMsg("TreeDebug","Start"); + for (vector::iterator iter = mpTriangles->begin(); + iter != mpTriangles->end(); + iter++ ) { + //errorOut(" d "<< convertFlags2String((int)(*iter).getFlags()) <<" "<< convertFlags2String( (int)mTriangleMask)<<" add? "<<( ((int)(*iter).getFlags() & (int)mTriangleMask) != 0 ) ); + // discard triangles that dont match mask + if( ((int)(*iter).getFlags() & (int)mTriangleMask) == 0 ) { + continue; + } + + // test? TODO + ntlVec3Gfx tnormal = (*mpVertNormals)[ (*iter).getPoints()[0] ]+ + (*mpVertNormals)[ (*iter).getPoints()[1] ]+ + (*mpVertNormals)[ (*iter).getPoints()[2] ]; + ntlVec3Gfx triangleNormal = (*iter).getNormal(); + if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) continue; + if( equal( tnormal, ntlVec3Gfx(0.0)) ) continue; + // */ + + ntlVec3Gfx bbs, bbe; + //errMsg("TreeDebug","Triangle"); + for(int i=0;i<3;i++) { + int index = (*iter).getPoints()[i]; + ntlVec3Gfx tp = (*mpVertices)[ index ]; + //errMsg("TreeDebug"," Point "< mEnd[0]) mEnd[0]= tp[0]; + if(tp[1] < mStart[1]) mStart[1]= tp[1]; + if(tp[1] > mEnd[1]) mEnd[1]= tp[1]; + if(tp[2] < mStart[2]) mStart[2]= tp[2]; + if(tp[2] > mEnd[2]) mEnd[2]= tp[2]; + if(i==0) { + bbs = bbe = tp; + } else { + if( tp[0] < bbs[0] ) bbs[0] = tp[0]; + if( tp[0] > bbe[0] ) bbe[0] = tp[0]; + if( tp[1] < bbs[1] ) bbs[1] = tp[1]; + if( tp[1] > bbe[1] ) bbe[1] = tp[1]; + if( tp[2] < bbs[2] ) bbs[2] = tp[2]; + if( tp[2] > bbe[2] ) bbe[2] = tp[2]; + } + } + mppTriangles->push_back( &(*iter) ); + //errMsg("TreeDebug","Triangle "<<(*mpVertices)[(*iter).getPoints()[0]]<<" "<<(*mpVertices)[(*iter).getPoints()[1]]<<" "<<(*mpVertices)[(*iter).getPoints()[2]]<<" "); + + // add BB + mpTBB[ bbCount ].start = bbs; + mpTBB[ bbCount ].end = bbe; + (*iter).setBBoxId( bbCount ); + bbCount++; + } + + + + /* slighlty enlarge bounding tolerance for tree + to avoid problems with triangles paralell to slabs */ + mStart -= ntlVec3Gfx( getVecEpsilon() ); + mEnd += ntlVec3Gfx( getVecEpsilon() ); + + /* init root node and stack */ + mpNodeStack = new BSPStack; + mpRoot = new BSPNode; + mpRoot->min = mStart; + mpRoot->max = mEnd; + mpRoot->axis = AXIS_X; + mpRoot->members = mppTriangles; + mpRoot->child[0] = mpRoot->child[1] = NULL; + mpRoot->cloneVec = 0; + globalSortingPoints = mpVertices; + mpTriDist = new char[ mppTriangles->size() ]; + mNumNodes = 1; + mAbortSubdiv = 0; + + /* create tree */ + debugOutInter( "Generating BSP Tree... (Nodes "<< mCurrentNodes << + ", Depth "<members->size() <<" "<min<<" - "<max ); + + if(depth>mCurrentDepth) mCurrentDepth = depth; + node->child[0] = node->child[1] = NULL; + if( ( (int)node->members->size() > mMaxListLength) && + (depth < mMaxDepth ) + && (node->cloneVec<10) + && (!mAbortSubdiv) + ) { + + gfxReal planeDiv = 0.499999; // position of plane division + + // determine next subdivision axis + int newaxis = 0; + gfxReal extX = node->max[0]-node->min[0]; + gfxReal extY = node->max[1]-node->min[1]; + gfxReal extZ = node->max[2]-node->min[2]; + + if( extY>extX ) { + if( extZ>extY ) { + newaxis = 2; + } else { + newaxis = 1; + } + } else { + if( extZ>extX ) { + newaxis = 2; + } else { + newaxis = 0; + } + } + axis = node->axis = newaxis; + + // init child nodes + for( int i=0; i<2; i++) { + /* status output */ + mCurrentNodes++; + if(mCurrentNodes % 13973 ==0) { + debugOutInter( "NTL Generating BSP Tree ("<child[i] = new BSPNode; + node->child[i]->min = node->min; + node->child[i]->max = node->max; + node->child[i]->max = node->max; + node->child[i]->child[0] = NULL; + node->child[i]->child[1] = NULL; + node->child[i]->members = NULL; + nextAxis = (axis+1)%3; + node->child[i]->axis = nextAxis; + mNumNodes++; + // abort when using 256MB only for tree... + if(mNumNodes*sizeof(BSPNode)> 1024*1024*512) mAbortSubdiv = 1; + + /* current division plane */ + if(!i) { + node->child[i]->min[axis] = node->min[axis]; + node->child[i]->max[axis] = node->min[axis] + planeDiv* + (node->max[axis]-node->min[axis]); + } else { + node->child[i]->min[axis] = node->min[axis] + planeDiv* + (node->max[axis]-node->min[axis]); + node->child[i]->max[axis] = node->max[axis]; + } + } + + + /* process the two children */ + int thisTrisFor[2] = {0,0}; + int thisTriDoubles[2] = {0,0}; + for(int t=0;t<(int)node->members->size();t++) mpTriDist[t] = 0; + for( int i=0; i<2; i++) { + /* distribute triangles */ + int t = 0; + for (vector::iterator iter = node->members->begin(); + iter != node->members->end(); iter++ ) { + + /* add triangle, check bounding box axis */ + TriangleBBox *bbox = &mpTBB[ (*iter)->getBBoxId() ]; + bool isintersect = true; + if( bbox->end[axis] < node->child[i]->min[axis] ) isintersect = false; + else if( bbox->start[axis] > node->child[i]->max[axis] ) isintersect = false; + if(isintersect) { + // add flag to vector + mpTriDist[t] |= (1<child[i]->members = new vector( thisTrisFor[i] ); + node->child[i]->cloneVec = 0; + } + + int tind0 = 0; + int tind1 = 0; + if( (!haveCloneVec[0]) || (!haveCloneVec[1]) ){ + int t = 0; // triangle index counter + for (vector::iterator iter = node->members->begin(); + iter != node->members->end(); iter++ ) { + if(!haveCloneVec[0]) { + if( (mpTriDist[t] & 1) == 1) { + (*node->child[0]->members)[tind0] = (*iter); // dont use push_back for preinited size! + tind0++; + } + } + if(!haveCloneVec[1]) { + if( (mpTriDist[t] & 2) == 2) { + (*node->child[1]->members)[tind1] = (*iter); // dont use push_back for preinited size! + tind1++; + } + } + t++; + } /* end of loop over all triangles */ + } + + // subdivide children + for( int i=0; i<2; i++) { + /* recurse */ + subdivide( node->child[i], depth+1, nextAxis ); + } + + /* if we are here, this are childs, so we dont need the members any more... */ + /* delete unecessary members */ + if( (!haveCloneVec[0]) && (!haveCloneVec[1]) && (node->cloneVec == 0) ){ + delete node->members; + } + node->members = NULL; + + } /* subdivision necessary */ +} + +/****************************************************************** + * triangle intersection with triangle pointer, + * returns t,u,v by references + */ +#if GFX_PRECISION==1 +// float values +//! the minimal triangle determinant length +#define RAY_TRIANGLE_EPSILON (1e-07) + +#else +// double values +//! the minimal triangle determinant length +#define RAY_TRIANGLE_EPSILON (1e-15) + +#endif + + +/****************************************************************************** + * intersect ray with BSPtree + *****************************************************************************/ +inline void ntlRay::intersectTriangle(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const +{ + /* (cf. moeller&haines, page 305) */ + t = GFX_REAL_MAX; + ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ]; + ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0; + ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0; + ntlVec3Gfx p = cross( mDirection, e2 ); + gfxReal divisor = dot(e1, p); + if((divisor > -RAY_TRIANGLE_EPSILON)&&(divisor < RAY_TRIANGLE_EPSILON)) return; + + gfxReal invDivisor = 1/divisor; + ntlVec3Gfx s = mOrigin - e0; + u = invDivisor * dot(s, p); + if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return; + + ntlVec3Gfx q = cross( s,e1 ); + v = invDivisor * dot(mDirection, q); + if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return; + + t = invDivisor * dot(e2, q); +} +void ntlTree::intersect(const ntlRay &ray, gfxReal &distance, + ntlVec3Gfx &normal, + ntlTriangle *&tri, + int flags, bool forceNonsmooth) const +{ + gfxReal mint = GFX_REAL_MAX; /* current minimal t */ + ntlVec3Gfx retnormal; /* intersection (interpolated) normal */ + gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */ + + BSPNode *curr, *nearChild, *farChild; /* current node and children */ + gfxReal planedist, mindist, maxdist; + ntlVec3Gfx pos; + + ntlTriangle *hit = NULL; + tri = NULL; + + ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist); + + if((maxdist < 0.0) || + (!mpRoot) || + (mindist == GFX_REAL_MAX) || + (maxdist == GFX_REAL_MAX) ) { + distance = -1.0; + return; + } + mindist -= getVecEpsilon(); + maxdist += getVecEpsilon(); + + /* stack init */ + mpNodeStack->elem[0].node = NULL; + mpNodeStack->stackPtr = 1; + + curr = mpRoot; + mint = GFX_REAL_MAX; + while(curr != NULL) { + + while( !curr->isLeaf() ) { + planedist = distanceToPlane(curr, curr->child[0]->max, ray ); + getChildren(curr, ray.getOrigin(), nearChild, farChild ); + + // check ray direction for small plane distances + if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) { + // ray origin on intersection plane + planedist = 0.0; + if(ray.getDirection()[curr->axis]>getVecEpsilon() ) { + // larger coords + curr = curr->child[1]; + } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) { + // smaller coords + curr = curr->child[0]; + } else { + // paralell, order doesnt really matter are min/max/plane ok? + mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0]; + mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; + mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; + (mpNodeStack->stackPtr)++; + curr = curr->child[1]; + maxdist = planedist; + } + } else { + // normal ray + if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) { + curr = nearChild; + } else if(planedist < mindist) { + curr = farChild; + } else { + mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild; + mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; + mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; + (mpNodeStack->stackPtr)++; + + curr = nearChild; + maxdist = planedist; + } + } + } + + + /* intersect with current node */ + for (vector::iterator iter = curr->members->begin(); + iter != curr->members->end(); iter++ ) { + + /* check for triangle flags before intersecting */ + if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) { + + if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) { + // was already intersected... + } else { + // we still need to intersect this triangle + gfxReal u=0.0,v=0.0, t=-1.0; + ray.intersectTriangle( mpVertices, (*iter), t,u,v); + (*iter)->setLastRay( ray.getID() ); + + if( (t > 0.0) && (t0.0) && (mint < GFX_REAL_MAX) ) { + pos = ray.getOrigin() + ray.getDirection()*mint; + + if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) && + (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) && + (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) ) + { + + if(forceNonsmooth) { + // calculate triangle normal + ntlVec3Gfx e0,e1,e2; + e0 = (*mpVertices)[ hit->getPoints()[0] ]; + e1 = (*mpVertices)[ hit->getPoints()[1] ]; + e2 = (*mpVertices)[ hit->getPoints()[2] ]; + retnormal = cross( -(e2-e0), (e1-e0) ); + } else { + // calculate interpolated normal + retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ + (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + } + normalize(retnormal); + normal = retnormal; + distance = mint; + tri = hit; + return; + } + } + + (mpNodeStack->stackPtr)--; + curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node; + mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist; + maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist; + } /* traverse tree */ + + if(mint == GFX_REAL_MAX) { + distance = -1.0; + } else { + // intersection outside the BSP bounding volumes might occur due to roundoff... + //retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + if(forceNonsmooth) { + // calculate triangle normal + ntlVec3Gfx e0,e1,e2; + e0 = (*mpVertices)[ hit->getPoints()[0] ]; + e1 = (*mpVertices)[ hit->getPoints()[1] ]; + e2 = (*mpVertices)[ hit->getPoints()[2] ]; + retnormal = cross( -(e2-e0), (e1-e0) ); + } else { + // calculate interpolated normal + retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ + (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + } + + normalize(retnormal); + normal = retnormal; + distance = mint; + tri = hit; + } + return; +} + +inline void ntlRay::intersectTriangleX(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const +{ + /* (cf. moeller&haines, page 305) */ + t = GFX_REAL_MAX; + ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ]; + ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0; + ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0; + + //ntlVec3Gfx p = cross( mDirection, e2 ); + //ntlVector3Dim cp( (-), (- (1.0 *v[2])), ((1.0 *v[1]) -) ); + ntlVec3Gfx p(0.0, -e2[2], e2[1]); + + gfxReal divisor = dot(e1, p); + if((divisor > -RAY_TRIANGLE_EPSILON)&&(divisor < RAY_TRIANGLE_EPSILON)) return; + + gfxReal invDivisor = 1/divisor; + ntlVec3Gfx s = mOrigin - e0; + u = invDivisor * dot(s, p); + if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return; + + ntlVec3Gfx q = cross( s,e1 ); + //v = invDivisor * dot(mDirection, q); + v = invDivisor * q[0]; + if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return; + + t = invDivisor * dot(e2, q); +} +void ntlTree::intersectX(const ntlRay &ray, gfxReal &distance, + ntlVec3Gfx &normal, + ntlTriangle *&tri, + int flags, bool forceNonsmooth) const +{ + gfxReal mint = GFX_REAL_MAX; /* current minimal t */ + ntlVec3Gfx retnormal; /* intersection (interpolated) normal */ + gfxReal mintu=0.0, mintv=0.0; /* u,v for min t intersection */ + + BSPNode *curr, *nearChild, *farChild; /* current node and children */ + gfxReal planedist, mindist, maxdist; + ntlVec3Gfx pos; + + ntlTriangle *hit = NULL; + tri = NULL; + + ray.intersectCompleteAABB(mStart,mEnd,mindist,maxdist); // +X + + if((maxdist < 0.0) || + (!mpRoot) || + (mindist == GFX_REAL_MAX) || + (maxdist == GFX_REAL_MAX) ) { + distance = -1.0; + return; + } + mindist -= getVecEpsilon(); + maxdist += getVecEpsilon(); + + /* stack init */ + mpNodeStack->elem[0].node = NULL; + mpNodeStack->stackPtr = 1; + + curr = mpRoot; + mint = GFX_REAL_MAX; + while(curr != NULL) { // +X + + while( !curr->isLeaf() ) { + planedist = distanceToPlane(curr, curr->child[0]->max, ray ); + getChildren(curr, ray.getOrigin(), nearChild, farChild ); + + // check ray direction for small plane distances + if( (planedist>-getVecEpsilon() )&&(planedist< getVecEpsilon() ) ) { + // ray origin on intersection plane + planedist = 0.0; + if(ray.getDirection()[curr->axis]>getVecEpsilon() ) { + // larger coords + curr = curr->child[1]; + } else if(ray.getDirection()[curr->axis]<-getVecEpsilon() ) { + // smaller coords + curr = curr->child[0]; + } else { + // paralell, order doesnt really matter are min/max/plane ok? + mpNodeStack->elem[ mpNodeStack->stackPtr ].node = curr->child[0]; + mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; + mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; + (mpNodeStack->stackPtr)++; + curr = curr->child[1]; + maxdist = planedist; + } + } else { + // normal ray + if( (planedist>maxdist) || (planedist<0.0-getVecEpsilon() ) ) { + curr = nearChild; + } else if(planedist < mindist) { + curr = farChild; + } else { + mpNodeStack->elem[ mpNodeStack->stackPtr ].node = farChild; + mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist = planedist; + mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist = maxdist; + (mpNodeStack->stackPtr)++; + + curr = nearChild; + maxdist = planedist; + } + } + } // +X + + + /* intersect with current node */ + for (vector::iterator iter = curr->members->begin(); + iter != curr->members->end(); iter++ ) { + + /* check for triangle flags before intersecting */ + if((!flags) || ( ((*iter)->getFlags() & flags) > 0 )) { + + if( ((*iter)->getLastRay() == ray.getID() )&&((*iter)->getLastRay()>0) ) { + // was already intersected... + } else { + // we still need to intersect this triangle + gfxReal u=0.0,v=0.0, t=-1.0; + ray.intersectTriangleX( mpVertices, (*iter), t,u,v); + (*iter)->setLastRay( ray.getID() ); + + if( (t > 0.0) && (t0.0) && (mint < GFX_REAL_MAX) ) { + pos = ray.getOrigin() + ray.getDirection()*mint; + + if( (pos[0] >= curr->min[0]) && (pos[0] <= curr->max[0]) && + (pos[1] >= curr->min[1]) && (pos[1] <= curr->max[1]) && + (pos[2] >= curr->min[2]) && (pos[2] <= curr->max[2]) ) + { + + if(forceNonsmooth) { + // calculate triangle normal + ntlVec3Gfx e0,e1,e2; + e0 = (*mpVertices)[ hit->getPoints()[0] ]; + e1 = (*mpVertices)[ hit->getPoints()[1] ]; + e2 = (*mpVertices)[ hit->getPoints()[2] ]; + retnormal = cross( -(e2-e0), (e1-e0) ); + } else { + // calculate interpolated normal + retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ + (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + } + normalize(retnormal); + normal = retnormal; + distance = mint; + tri = hit; + return; + } + } // +X + + (mpNodeStack->stackPtr)--; + curr = mpNodeStack->elem[ mpNodeStack->stackPtr ].node; + mindist = mpNodeStack->elem[ mpNodeStack->stackPtr ].mindist; + maxdist = mpNodeStack->elem[ mpNodeStack->stackPtr ].maxdist; + } /* traverse tree */ + + if(mint == GFX_REAL_MAX) { + distance = -1.0; + } else { + + // intersection outside the BSP bounding volumes might occur due to roundoff... + if(forceNonsmooth) { + // calculate triangle normal + ntlVec3Gfx e0,e1,e2; + e0 = (*mpVertices)[ hit->getPoints()[0] ]; + e1 = (*mpVertices)[ hit->getPoints()[1] ]; + e2 = (*mpVertices)[ hit->getPoints()[2] ]; + retnormal = cross( -(e2-e0), (e1-e0) ); + } else { + // calculate interpolated normal + retnormal = (*mpVertNormals)[ hit->getPoints()[0] ] * (1.0-mintu-mintv)+ + (*mpVertNormals)[ hit->getPoints()[1] ]*mintu + + (*mpVertNormals)[ hit->getPoints()[2] ]*mintv; + } + + normalize(retnormal); + normal = retnormal; + distance = mint; + tri = hit; + } // +X + return; +} + + + +/****************************************************************************** + * distance to plane function for nodes + *****************************************************************************/ +gfxReal ntlTree::distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const +{ + return ( (plane[curr->axis]-ray.getOrigin()[curr->axis]) / ray.getDirection()[curr->axis] ); +} + + +/****************************************************************************** + * return ordering of children nodes relatice to origin point + *****************************************************************************/ +void ntlTree::getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&node_near, BSPNode *&node_far) const +{ + if(curr->child[0]->max[ curr->axis ] >= origin[ curr->axis ]) { + node_near = curr->child[0]; + node_far = curr->child[1]; + } else { + node_near = curr->child[1]; + node_far = curr->child[0]; + } +} + + +/****************************************************************************** + * delete a node of the tree with all sub nodes + * dont delete root members + *****************************************************************************/ +void ntlTree::deleteNode(BSPNode *curr) +{ + if(!curr) return; + + if(curr->child[0] != NULL) + deleteNode(curr->child[0]); + if(curr->child[1] != NULL) + deleteNode(curr->child[1]); + + if(curr->members != NULL) delete curr->members; + delete curr; +} + + + +/****************************************************************** + * intersect only front or backsides + * currently unused + */ +inline void ntlRay::intersectTriangleFront(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const +{ + t = GFX_REAL_MAX; + ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ]; + ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0; + ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0; + ntlVec3Gfx p = cross( mDirection, e2 ); + gfxReal a = dot(e1, p); + //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return; + if(a < RAY_TRIANGLE_EPSILON) return; // cull backsides + + gfxReal f = 1/a; + ntlVec3Gfx s = mOrigin - e0; + u = f * dot(s, p); + if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return; + + ntlVec3Gfx q = cross( s,e1 ); + v = f * dot(mDirection, q); + if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return; + + t = f * dot(e2, q); +} +inline void ntlRay::intersectTriangleBack(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const +{ + t = GFX_REAL_MAX; + ntlVec3Gfx e0 = (*mpV)[ tri->getPoints()[0] ]; + ntlVec3Gfx e1 = (*mpV)[ tri->getPoints()[1] ] - e0; + ntlVec3Gfx e2 = (*mpV)[ tri->getPoints()[2] ] - e0; + ntlVec3Gfx p = cross( mDirection, e2 ); + gfxReal a = dot(e1, p); + //if((a > -RAY_TRIANGLE_EPSILON)&&(a < RAY_TRIANGLE_EPSILON)) return; + if(a > -RAY_TRIANGLE_EPSILON) return; // cull frontsides + + gfxReal f = 1/a; + ntlVec3Gfx s = mOrigin - e0; + u = f * dot(s, p); + if( (u<0.0-RAY_TRIANGLE_EPSILON) || (u>1.0+RAY_TRIANGLE_EPSILON) ) return; + + ntlVec3Gfx q = cross( s,e1 ); + v = f * dot(mDirection, q); + if( (v<0.0-RAY_TRIANGLE_EPSILON) || ((u+v)>1.0+RAY_TRIANGLE_EPSILON) ) return; + + t = f * dot(e2, q); +} + + + diff --git a/intern/elbeem/intern/ntl_bsptree.h b/intern/elbeem/intern/ntl_bsptree.h new file mode 100644 index 00000000000..35bc7c61837 --- /dev/null +++ b/intern/elbeem/intern/ntl_bsptree.h @@ -0,0 +1,125 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Tree container for fast triangle intersects + * + *****************************************************************************/ +#ifndef NTL_TREE_H +#define NTL_TREE_H + +#include "ntl_vector3dim.h" +#include "ntl_ray.h" + + +#define AXIS_X 0 +#define AXIS_Y 1 +#define AXIS_Z 2 + +#define BSP_STACK_SIZE 50 + + +//! bsp tree stack classes, defined in ntl_bsptree.cpp, +// detailed definition unnecesseary here +class BSPNode; +class BSPStackElement; +class BSPStack; +class TriangleBBox; +class ntlScene; +class ntlTriangle; + + +//! Class for a bsp tree for triangles +class ntlTree +{ + public: + + //! Default constructor + ntlTree(); + //! Constructor with init + ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask); + //! Destructor + ~ntlTree(); + + //! subdivide tree + void subdivide(BSPNode *node, int depth, int axis); + + //! intersect ray with BSPtree + void intersect(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const; + //! intersect along +X ray + void intersectX(const ntlRay &ray, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags, bool forceNonsmooth) const; + + //! Returns number of nodes + int getCurrentNodes( void ) { return mCurrentNodes; } + + protected: + + // check if a triangle is in a node + bool checkAABBTriangle(ntlVec3Gfx &min, ntlVec3Gfx &max, ntlTriangle *tri); + + + // VARs + + //! distance to plane function for nodes + gfxReal distanceToPlane(BSPNode *curr, ntlVec3Gfx plane, ntlRay ray) const; + + //! return ordering of children nodes relatice to origin point + void getChildren(BSPNode *curr, ntlVec3Gfx origin, BSPNode *&node_near, BSPNode *&node_far) const; + + //! delete a node of the tree with all sub nodes, dont delete root members + void deleteNode(BSPNode *curr); + + //inline bool isLeaf(BSPNode *node) const { return (node->child[0] == NULL); } + + + //! AABB for tree + ntlVec3Gfx mStart,mEnd; + + //! maximum depth of tree + int mMaxDepth; + + //! maximum number of objects in one node + int mMaxListLength; + + //! root node pointer + BSPNode *mpRoot; + //! count no. of node + int mNumNodes; + int mAbortSubdiv; + + //! stack for the node pointers + BSPStack *mpNodeStack; + //stack nodestack; + + //! pointer to vertex array + vector *mpVertices; + + //! pointer to vertex array + vector *mpVertNormals; + + //! vector for all the triangles + vector *mpTriangles; + vector *mppTriangles; + + //! temporary array for triangle distribution to nodes + char *mpTriDist; + + //! temporary array for triangle bounding boxes + TriangleBBox *mpTBB; + + //! triangle mask - include only triangles that match mask + int mTriangleMask; + + //! Status vars (max depth, # of current nodes) + int mCurrentDepth, mCurrentNodes; + + //! duplicated triangles, inited during subdivide + int mTriDoubles; + +}; + + +#endif + + diff --git a/intern/elbeem/intern/ntl_geometryclass.h b/intern/elbeem/intern/ntl_geometryclass.h new file mode 100644 index 00000000000..9282371d183 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometryclass.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Base class for geometry shaders and objects + * + *****************************************************************************/ + + +#ifndef NTL_GEOMETRYCLASS_H +#define NTL_GEOMETRYCLASS_H + +#include "attributes.h" + +//! geometry class type ids +#define GEOCLASSTID_OBJECT 1 +#define GEOCLASSTID_SHADER 2 +#define GEOCLASSTID_BOX (GEOCLASSTID_OBJECT| 4) +#define GEOCLASSTID_OBJMODEL (GEOCLASSTID_OBJECT| 8) +#define GEOCLASSTID_SPHERE (GEOCLASSTID_OBJECT| 16) + +class ntlGeometryClass +{ + + public: + + //! Default constructor + inline ntlGeometryClass() : + mVisible( 1 ), mName( "[ObjNameUndef]" ), + mObjectId(-1), mpAttrs( NULL ), mGeoInitId(-1) + { + mpAttrs = new AttributeList("objAttrs"); + mpSwsAttrs = new AttributeList("swsAttrs"); + }; + + //! Default destructor + virtual ~ntlGeometryClass() { + delete mpAttrs; + }; + + //! Return type id + virtual int getTypeId() = 0; + + /*! Set the object name */ + inline void setName(string set) { mName = set; } + /*! Get the object name */ + inline string getName( void ) { return mName; } + + /*! Sets the visibility attribute + * visibility can be determined at shader _and_ object level , hiding a shader + * means comepletely decativating it */ + inline void setVisible(int set) { mVisible=set; } + /*! Returns the visibility attribute */ + inline int getVisible() const { return mVisible; } + + /*! Sets the attribute list pointer */ + inline void setAttributeList(AttributeList *set) { mpAttrs=set; } + /*! Returns the attribute list pointer */ + inline AttributeList *getAttributeList() { return mpAttrs; } + + /*! Get/Sets the attribute list pointer */ + inline void setSwsAttributeList(AttributeList *set) { mpSwsAttrs=set; } + inline AttributeList *getSwsAttributeList() { return mpSwsAttrs; } + + /*! for easy GUI detection get start of axis aligned bounding box, return NULL of no BB */ + virtual inline ntlVec3Gfx *getBBStart() { return NULL; } + virtual inline ntlVec3Gfx *getBBEnd() { return NULL; } + + /*! Set/get the object id*/ + inline void setObjectId(int set) { mObjectId=set; } + inline int getObjectId() const { return mObjectId; } + + /*! GUI - this function is called for selected objects to display debugging information with OpenGL */ + virtual void drawDebugDisplay() { /* do nothing by default */ } + /*! GUI - this function is called for selected objects to display interactive information with OpenGL */ + virtual void drawInteractiveDisplay() { /* do nothing by default */ } + /*! GUI - handle mouse movement for selection */ + virtual void setMousePos(int ,int , ntlVec3Gfx , ntlVec3Gfx ) { /* do nothing by default */ } + /*! GUI - notify object that mouse was clicked at last pos */ + virtual void setMouseClick() { /* do nothing by default */ } + + /*! Returns the geo init id */ + inline void setGeoInitId(int set) { mGeoInitId=set; } + /*! Returns the geo init id */ + inline int getGeoInitId() const { return mGeoInitId; } + + protected: + + /*! Object visible on/off */ + int mVisible; + + /*! Name of this object */ + string mName; + + /*! global scene object id */ + int mObjectId; + + /*! configuration attributes */ + AttributeList *mpAttrs; + /*! sws configuration attributes */ + AttributeList *mpSwsAttrs; + + /* fluid init data */ + /*! id of fluid init (is used in solver initialization), additional data stored only for objects */ + int mGeoInitId; + + private: + +}; + + + +#endif + diff --git a/intern/elbeem/intern/ntl_geometrymodel.cpp b/intern/elbeem/intern/ntl_geometrymodel.cpp new file mode 100644 index 00000000000..0d769cf6ef8 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometrymodel.cpp @@ -0,0 +1,478 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * A simple box object + * + *****************************************************************************/ + +#include "ntl_geometrymodel.h" +#include "ntl_ray.h" +#include "ntl_world.h" +#include "zlib.h" + +#ifdef WIN32 +#ifndef strncasecmp +#define strncasecmp(a,b,c) strcmp(a,b) +#endif +#endif // WIN32 + + +/****************************************************************************** + * Default Constructor + *****************************************************************************/ +ntlGeometryObjModel::ntlGeometryObjModel( void ) : + ntlGeometryObject(), + mvStart( 0.0 ), mvEnd( 1.0 ), + mLoaded( false ), + mTriangles(), mVertices(), mNormals(), + mcAniVerts(), mcAniNorms(), + mcAniTimes(), mAniTimeScale(1.), mAniTimeOffset(0.) +{ +} + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlGeometryObjModel::~ntlGeometryObjModel() +{ + if(!mLoaded) { + errMsg("ntlGeometryObjModel","delete obj..."); + } +} + + +/*! is the mesh animated? */ +bool ntlGeometryObjModel::getMeshAnimated() { + const bool ret = (mcAniVerts.getSize()>1); + //errMsg("getMeshAnimated","ret="< (*sverts)[i][j]) { start[j]= (*sverts)[i][j]; } + if(end[j] < (*sverts)[i][j]) { end[j] = (*sverts)[i][j]; } + } + //errMsg("getExtends","check "<getMaterials() ); + return; + } + + ntlGeometryObject::initialize(glob); + mFilename = mpAttrs->readString("filename", mFilename,"ntlGeometryObjModel", "mFilename", true); + + if(mFilename == "") { + errMsg("ntlGeometryObjModel::initialize","Filename not given!"); + return; + } + + const char *suffix = strrchr(mFilename.c_str(), '.'); + if (suffix) { + if (!strncasecmp(suffix, ".obj", 4)) { + errMsg("ntlGeometryObjModel::initialize",".obj files not supported!"); + return; + } else if (!strncasecmp(suffix, ".gz", 3)) { + //mType = 1; // assume its .bobj.gz + } else if (!strncasecmp(suffix, ".bobj", 5)) { + //mType = 1; + } + } + + if(getAttributeList()->exists("ani_times") || (!mcAniTimes.isInited()) ) { + mcAniTimes = mpAttrs->readChannelFloat("ani_times"); + } + mAniTimeScale = mpAttrs->readFloat("ani_timescale", mAniTimeScale,"ntlGeometryObjModel", "mAniTimeScale", false); + mAniTimeOffset = mpAttrs->readFloat("ani_timeoffset", mAniTimeOffset,"ntlGeometryObjModel", "mAniTimeOffset", false); + + // continue with standard obj + if(loadBobjModel(mFilename)==0) mLoaded=1; + if(!mLoaded) { + debMsgStd("ntlGeometryObjModel",DM_WARNING,"Unable to load object file '"<mIsAnimated = true; + } +} + +/****************************************************************************** + * init model from given vertex and triangle arrays + *****************************************************************************/ + +int ntlGeometryObjModel::initModel(int numVertices, float *vertices, int numTriangles, int *triangles, + int channelSize, float *channelVertices) +{ + mVertices.clear(); + mVertices.resize( numVertices ); + mNormals.resize( numVertices ); + for(int i=0; i=numVertices) { mTriangles[3*i+j]=0; triangleErrs++; } + } + } + if(triangleErrs>0) { + errMsg("ntlGeometryObjModel::initModel","Triangle errors occurred ("<0)) { + vector aniverts; + vector aninorms; + vector anitimes; + aniverts.clear(); + aninorms.clear(); + anitimes.clear(); + for(int frame=0; framemIsAnimated = true; + } + + // inited, no need to parse attribs etc. + mLoaded = 1; + return 0; +} + +/*! init triangle divisions */ +void ntlGeometryObjModel::calcTriangleDivs(vector &verts, vector &tris, gfxReal fsTri) { + // warning - copied from geomobj calc! + errMsg("ntlGeometryObjModel","calcTriangleDivs special!"); + mTriangleDivs1.resize( tris.size() ); + mTriangleDivs2.resize( tris.size() ); + mTriangleDivs3.resize( tris.size() ); + for(size_t i=0; i fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); } + if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); } + //if(normNoSqrt(side3) > fsTri*fsTri) { divs3 = (int)(norm(side3)/fsTri); } + + // special handling + // warning, requires objmodel triangle treatment (no verts dups) + if(getMeshAnimated()) { + vector &sverts = mcAniVerts.accessValues(); + for(int s=0; s<(int)sverts.size(); s++) { + p0 = sverts[s].mVerts[ tris[i].getPoints()[0] ]; + p1 = sverts[s].mVerts[ tris[i].getPoints()[1] ]; + p2 = sverts[s].mVerts[ tris[i].getPoints()[2] ]; + side1 = p1 - p0; side2 = p2 - p0; side3 = p1 - p2; + int tdivs1=0, tdivs2=0, tdivs3=0; + if(normNoSqrt(side1) > fsTri*fsTri) { tdivs1 = (int)(norm(side1)/fsTri); } + if(normNoSqrt(side2) > fsTri*fsTri) { tdivs2 = (int)(norm(side2)/fsTri); } + if(tdivs1>divs1) divs1=tdivs1; + if(tdivs2>divs2) divs2=tdivs2; + if(tdivs3>divs3) divs3=tdivs3; + } + } // */ + mTriangleDivs1[i] = divs1; + mTriangleDivs2[i] = divs2; + mTriangleDivs3[i] = divs3; + } +} + + +/****************************************************************************** + * load model from .obj file + *****************************************************************************/ + +int ntlGeometryObjModel::loadBobjModel(string filename) +{ + bool haveAniSets=false; + vector aniverts; + vector aninorms; + vector anitimes; + + const bool debugPrint=false; + const bool debugPrintFull=false; + gzFile gzf; + gzf = gzopen(filename.c_str(), "rb"); + if (!gzf) { + errFatal("ntlGeometryObjModel::loadBobjModel","Reading GZ_BOBJ, Unable to open '"<< filename <<"'...\n", SIMWORLD_INITERROR ); + return 1; + } + + int numVerts; + if(sizeof(numVerts)!=4) { // paranoia check + errMsg("Reading GZ_BOBJ"," Invalid int size, check compiler settings: int has to be 4 byte long"); + goto gzreaderror; + } + gzread(gzf, &numVerts, sizeof(numVerts) ); + if(numVerts<0 || numVerts>1e9) { + errMsg("Reading GZ_BOBJ"," invalid num vertices "<< numVerts); + goto gzreaderror; + } + mVertices.clear(); + mVertices.resize( numVerts ); + for(int i=0; i1e9) { + errMsg("Reading GZ_BOBJ","invalid num normals "<< numVerts); + goto gzreaderror; + } + mNormals.clear(); + mNormals.resize( numVerts ); + for(int i=0; i1e9) { + errMsg("Reading GZ_BOBJ","invalid num normals "<< numTris); + goto gzreaderror; + } + mTriangles.resize( 3*numTris ); + for(int i=0; i0) { + // finally init channels and stop reading file + mcAniVerts = AnimChannel(aniverts,anitimes); + mcAniNorms = AnimChannel(aninorms,anitimes); + } + goto gzreaddone; + } + bytesRead += gzread(gzf, &numVerts2, sizeof(numVerts2) ); + haveAniSets=true; + // continue to read new set + vector vertset; + vector normset; + vertset.resize(numVerts); + normset.resize(numVerts); + //vertset[0] = check; + if(debugPrintFull) errMsg("FUL1V"," "<<0<<" "<< vertset[0] ); + + for(int i=0; i1) anitime = mcAniTimes.get(anitime); + anitime = anitime*mAniTimeScale+mAniTimeOffset; + + anitimes.push_back( anitime ); + aniverts.push_back( ntlSetVec3f(mVertices) ); + aninorms.push_back( ntlSetVec3f(mNormals) ); + if(debugPrint) errMsg("ANI_NV","new set "<1) anitime = mcAniTimes.get(anitime); + anitime = anitime*mAniTimeScale+mAniTimeOffset; + + anitimes.push_back( anitime ); + aniverts.push_back( ntlSetVec3f(vertset) ); + aninorms.push_back( ntlSetVec3f(normset) ); + if(debugPrint) errMsg("ANI_NV","new set "< *triangles, + vector *vertices, + vector *normals, int objectId ) +{ + if(!mLoaded) { // invalid type... + return; + } + if(mcAniVerts.getSize()>1) { mVertices = mcAniVerts.get(t).mVerts; } + if(mcAniNorms.getSize()>1) { mNormals = mcAniNorms.get(t).mVerts; } + + int startvert = vertices->size(); + vertices->resize( vertices->size() + mVertices.size() ); + normals->resize( normals->size() + mVertices.size() ); + for(int i=0; i<(int)mVertices.size(); i++) { + (*vertices)[startvert+i] = mVertices[i]; + (*normals)[startvert+i] = mNormals[i]; + } + + triangles->reserve(triangles->size() + mTriangles.size()/3 ); + for(int i=0; i<(int)mTriangles.size(); i+=3) { + int trip[3]; + trip[0] = startvert+mTriangles[i+0]; + trip[1] = startvert+mTriangles[i+1]; + trip[2] = startvert+mTriangles[i+2]; + + //sceneAddTriangle( + //mVertices[trip[0]], mVertices[trip[1]], mVertices[trip[2]], + //mNormals[trip[0]], mNormals[trip[1]], mNormals[trip[2]], + //ntlVec3Gfx(0.0), 1 , triangles,vertices,normals ); /* normal unused */ + sceneAddTriangleNoVert( trip, ntlVec3Gfx(0.0), 1 , triangles ); /* normal unused */ + } + objectId = -1; // remove warning + // bobj + return; +} + + + + + diff --git a/intern/elbeem/intern/ntl_geometrymodel.h b/intern/elbeem/intern/ntl_geometrymodel.h new file mode 100644 index 00000000000..572440f28dc --- /dev/null +++ b/intern/elbeem/intern/ntl_geometrymodel.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * A model laoded from Wavefront .obj file + * + *****************************************************************************/ +#ifndef NTL_GEOMODEL_H +#define NTL_GEOMODEL_H + +#include "ntl_geometryobject.h" + +/*! A simple box object generatedd by 12 triangles */ +class ntlGeometryObjModel : public ntlGeometryObject +{ + public: + /* Init constructor */ + ntlGeometryObjModel( void ); + /* Init constructor */ + //ntlGeometryObjModel( ntlVec3Gfx start, ntlVec3Gfx end ); + /* Destructor */ + virtual ~ntlGeometryObjModel( void ); + + //! Return type id + virtual int getTypeId() { return GEOCLASSTID_OBJMODEL; } + + /*! Filename setting etc. */ + virtual void initialize(ntlRenderGlobals *glob); + + /*! is the mesh animated? */ + virtual bool getMeshAnimated(); + + /* create triangles from obj */ + virtual void getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ); + + /*! load model from .bobj file, returns !=0 upon error */ + int loadBobjModel(string filename); + /*! init model from given vertex and triangle arrays */ + int initModel(int numVertices, float *vertices, int numTriangles, int *triangles, + int channelSize, float *channelVertices); + /*! init triangle divisions */ + virtual void calcTriangleDivs(vector &verts, vector &tris, gfxReal fsTri); + + /*! calculate max extends of (ani) mesh */ + void getExtends(ntlVec3Gfx &start, ntlVec3Gfx &end); + + private: + + /*! Start and end points of box */ + ntlVec3Gfx mvStart, mvEnd; + + /*! was the model loaded? */ + bool mLoaded; + + /*! filename of the obj file */ + string mFilename; + + /*! for bobj models */ + vector mTriangles; + vector mVertices; + vector mNormals; + + /*! animated channels for vertices, if given will override getris by default */ + AnimChannel mcAniVerts; + AnimChannel mcAniNorms; + /*! map entrie of anim mesh to sim times */ + AnimChannel mcAniTimes; + /*! timing mapping & offset for config files */ + double mAniTimeScale, mAniTimeOffset; + + public: + + /* Access methods */ + /*! Access start vector */ + inline ntlVec3Gfx getStart( void ){ return mvStart; } + inline void setStart( const ntlVec3Gfx &set ){ mvStart = set; } + /*! Access end vector */ + inline ntlVec3Gfx getEnd( void ){ return mvEnd; } + inline void setEnd( const ntlVec3Gfx &set ){ mvEnd = set; } + + inline bool getLoaded( void ){ return mLoaded; } + inline void setLoaded( bool set ){ mLoaded = set; } + + /*! set data file name */ + inline void setFilename(string set) { mFilename = set; } +}; + +#endif + diff --git a/intern/elbeem/intern/ntl_geometryobject.cpp b/intern/elbeem/intern/ntl_geometryobject.cpp new file mode 100644 index 00000000000..f2ebd572682 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometryobject.cpp @@ -0,0 +1,792 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * a geometry object + * all other geometry objects are derived from this one + * + *****************************************************************************/ + + +#include "ntl_geometryobject.h" +#include "ntl_world.h" +#include "ntl_matrices.h" + +// for FGI +#include "elbeem.h" + +#define TRI_UVOFFSET (1./4.) +//#define TRI_UVOFFSET (1./3.) + + +/*****************************************************************************/ +/* Default constructor */ +/*****************************************************************************/ +ntlGeometryObject::ntlGeometryObject() : + mIsInitialized(false), mpMaterial( NULL ), + mMaterialName( "default" ), + mCastShadows( 1 ), mReceiveShadows( 1 ), + mGeoInitType( 0 ), + mInitialVelocity(0.0), mcInitialVelocity(0.0), mLocalCoordInivel(false), + mGeoInitIntersect(false), + mGeoPartSlipValue(0.0), + mcGeoImpactFactor(1.), + mVolumeInit(VOLUMEINIT_VOLUME), + mInitialPos(0.), + mcTrans(0.), mcRot(0.), mcScale(1.), + mIsAnimated(false), + mMovPoints(), mMovNormals(), + mHaveCachedMov(false), + mCachedMovPoints(), mCachedMovNormals(), + mTriangleDivs1(), mTriangleDivs2(), mTriangleDivs3(), + mMovPntsInited(-100.0), mMaxMovPnt(-1), + mcGeoActive(1.) +{ +}; + + +/*****************************************************************************/ +/* Default destructor */ +/*****************************************************************************/ +ntlGeometryObject::~ntlGeometryObject() +{ +} + +/*! is the mesh animated? */ +bool ntlGeometryObject::getMeshAnimated() { + // off by default, on for e.g. ntlGeometryObjModel + return false; +} + +/*! init object anim flag */ +bool ntlGeometryObject::checkIsAnimated() { + if( (mcTrans.accessValues().size()>1) // VALIDATE + || (mcRot.accessValues().size()>1) + || (mcScale.accessValues().size()>1) + || (mcGeoActive.accessValues().size()>1) + // mcGeoImpactFactor only needed when moving + || (mcInitialVelocity.accessValues().size()>1) + ) { + mIsAnimated = true; + } + + // fluid objects always have static init! + if(mGeoInitType==FGI_FLUID) { + mIsAnimated=false; + } + //errMsg("ntlGeometryObject::checkIsAnimated","obj="<getMaterials() ); + + this->mGeoInitId = mpAttrs->readInt("geoinitid", this->mGeoInitId,"ntlGeometryObject", "mGeoInitId", false); + mGeoInitIntersect = mpAttrs->readInt("geoinit_intersect", mGeoInitIntersect,"ntlGeometryObject", "mGeoInitIntersect", false); + string ginitStr = mpAttrs->readString("geoinittype", "", "ntlGeometryObject", "mGeoInitType", false); + if(this->mGeoInitId>=0) { + bool gotit = false; + for(int i=0; ireadInt("geoinitactive", 1,"ntlGeometryObject", "geoActive", false); + if(!geoActive) { + // disable geo init again... + this->mGeoInitId = -1; + } + mInitialVelocity = vec2G( mpAttrs->readVec3d("initial_velocity", vec2D(mInitialVelocity),"ntlGeometryObject", "mInitialVelocity", false)); + if(getAttributeList()->exists("initial_velocity") || (!mcInitialVelocity.isInited()) ) { + mcInitialVelocity = mpAttrs->readChannelVec3f("initial_velocity"); + } + // always use channel + if(!mcInitialVelocity.isInited()) { mcInitialVelocity = AnimChannel(mInitialVelocity); } + mLocalCoordInivel = mpAttrs->readBool("geoinit_localinivel", mLocalCoordInivel,"ntlGeometryObject", "mLocalCoordInivel", false); + + mGeoPartSlipValue = mpAttrs->readFloat("geoinit_partslip", mGeoPartSlipValue,"ntlGeometryObject", "mGeoPartSlipValue", false); + bool mOnlyThinInit = false; // deprecated! + mOnlyThinInit = mpAttrs->readBool("geoinit_onlythin", mOnlyThinInit,"ntlGeometryObject", "mOnlyThinInit", false); + if(mOnlyThinInit) mVolumeInit = VOLUMEINIT_SHELL; + mVolumeInit = mpAttrs->readInt("geoinit_volumeinit", mVolumeInit,"ntlGeometryObject", "mVolumeInit", false); + if((mVolumeInitVOLUMEINIT_BOTH)) mVolumeInit = VOLUMEINIT_VOLUME; + + // moving obs correction factor + float impactfactor=1.; + impactfactor = (float)mpAttrs->readFloat("impactfactor", impactfactor,"ntlGeometryObject", "impactfactor", false); + if(getAttributeList()->exists("impactfactor") || (!mcGeoImpactFactor.isInited()) ) { + mcGeoImpactFactor = mpAttrs->readChannelSinglePrecFloat("impactfactor"); + } + + // override cfg types + mVisible = mpAttrs->readBool("visible", mVisible,"ntlGeometryObject", "mVisible", false); + mReceiveShadows = mpAttrs->readBool("recv_shad", mReceiveShadows,"ntlGeometryObject", "mReceiveShadows", false); + mCastShadows = mpAttrs->readBool("cast_shad", mCastShadows,"ntlGeometryObject", "mCastShadows", false); + + // read mesh animation channels + ntlVec3d translation(0.0); + translation = mpAttrs->readVec3d("translation", translation,"ntlGeometryObject", "translation", false); + if(getAttributeList()->exists("translation") || (!mcTrans.isInited()) ) { + mcTrans = mpAttrs->readChannelVec3f("translation"); + } + ntlVec3d rotation(0.0); + rotation = mpAttrs->readVec3d("rotation", rotation,"ntlGeometryObject", "rotation", false); + if(getAttributeList()->exists("rotation") || (!mcRot.isInited()) ) { + mcRot = mpAttrs->readChannelVec3f("rotation"); + } + ntlVec3d scale(1.0); + scale = mpAttrs->readVec3d("scale", scale,"ntlGeometryObject", "scale", false); + if(getAttributeList()->exists("scale") || (!mcScale.isInited()) ) { + mcScale = mpAttrs->readChannelVec3f("scale"); + } + + float geoactive=1.; + geoactive = (float)mpAttrs->readFloat("geoactive", geoactive,"ntlGeometryObject", "geoactive", false); + if(getAttributeList()->exists("geoactive") || (!mcGeoActive.isInited()) ) { + mcGeoActive = mpAttrs->readChannelSinglePrecFloat("geoactive"); + } + // always use channel + if(!mcGeoActive.isInited()) { mcGeoActive = AnimChannel(geoactive); } + + checkIsAnimated(); + + mIsInitialized = true; + debMsgStd("ntlGeometryObject::initialize",DM_MSG,"GeoObj '"<getName()<<"': visible="<mVisible<<" gid="<mGeoInitId<<" gtype="<getName()<<" frame:"< *mat) +{ + /* search the list... */ + int i=0; + for (vector::iterator iter = mat->begin(); + iter != mat->end(); iter++) { + if( mMaterialName == (*iter)->getName() ) { + //warnMsg("ntlGeometryObject::searchMaterial","for obj '"<getName()<<"' "< *triangles, + vector *vertices, + vector *normals) { + ntlTriangle tri; + int tempVert; + + if(normals->size() != vertices->size()) { + errFatal("ntlGeometryObject::sceneAddTriangle","For '"<mName<<"': Vertices and normals sizes to not match!!!",SIMWORLD_GENERICERROR); + + } else { + + vertices->push_back( p1 ); + normals->push_back( pn1 ); + tempVert = normals->size()-1; + tri.getPoints()[0] = tempVert; + + vertices->push_back( p2 ); + normals->push_back( pn2 ); + tempVert = normals->size()-1; + tri.getPoints()[1] = tempVert; + + vertices->push_back( p3 ); + normals->push_back( pn3 ); + tempVert = normals->size()-1; + tri.getPoints()[2] = tempVert; + + + /* init flags from ntl_ray.h */ + int flag = 0; + if(getVisible()){ flag |= TRI_GEOMETRY; } + if(getCastShadows() ) { + flag |= TRI_CASTSHADOWS; } + + /* init geo init id */ + int geoiId = getGeoInitId(); + //if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME) && (!mIsAnimated)) { + if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) { + flag |= (1<< (geoiId+4)); + flag |= mGeoInitType; + } + /*errMsg("ntlScene::addTriangle","DEBUG flag="<mObjectId ); + triangles->push_back( tri ); + } /* normals check*/ +} + +void ntlGeometryObject::sceneAddTriangleNoVert(int *trips, + ntlVec3Gfx trin, bool smooth, + vector *triangles) { + ntlTriangle tri; + + tri.getPoints()[0] = trips[0]; + tri.getPoints()[1] = trips[1]; + tri.getPoints()[2] = trips[2]; + + // same as normal sceneAddTriangle + + /* init flags from ntl_ray.h */ + int flag = 0; + if(getVisible()){ flag |= TRI_GEOMETRY; } + if(getCastShadows() ) { + flag |= TRI_CASTSHADOWS; } + + /* init geo init id */ + int geoiId = getGeoInitId(); + if((geoiId > 0) && (mVolumeInit&VOLUMEINIT_VOLUME)) { + flag |= (1<< (geoiId+4)); + flag |= mGeoInitType; + } + /*errMsg("ntlScene::addTriangle","DEBUG flag="<mObjectId ); + triangles->push_back( tri ); +} + + +/******************************************************************************/ +/* Init channels from float arrays (for elbeem API) */ +/******************************************************************************/ + +#define ADD_CHANNEL_VEC(dst,nvals,val) \ + vals.clear(); time.clear(); elbeemSimplifyChannelVec3(val,&nvals); \ + for(int i=0; i<(nvals); i++) { \ + vals.push_back(ntlVec3Gfx((val)[i*4+0], (val)[i*4+1],(val)[i*4+2] )); \ + time.push_back( (val)[i*4+3] ); \ + } \ + (dst) = AnimChannel< ntlVec3Gfx >(vals,time); + +#define ADD_CHANNEL_FLOAT(dst,nvals,val) \ + valsfloat.clear(); time.clear(); elbeemSimplifyChannelFloat(val,&nvals); \ + for(int i=0; i<(nvals); i++) { \ + valsfloat.push_back( (val)[i*2+0] ); \ + time.push_back( (val)[i*2+1] ); \ + } \ + (dst) = AnimChannel< float >(valsfloat,time); + +void ntlGeometryObject::initChannels( + int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale, + int nAct, float *act, int nIvel, float *ivel + ) { + const bool debugInitc=true; + if(debugInitc) { debMsgStd("ntlGeometryObject::initChannels",DM_MSG,"nt:"< vals; + vector valsfloat; + vector time; + if((trans)&&(nTrans>0)) { ADD_CHANNEL_VEC(mcTrans, nTrans, trans); } + if((rot)&&(nRot>0)) { ADD_CHANNEL_VEC(mcRot, nRot, rot); } + if((scale)&&(nScale>0)) { ADD_CHANNEL_VEC(mcScale, nScale, scale); } + if((act)&&(nAct>0)) { ADD_CHANNEL_FLOAT(mcGeoActive, nAct, act); } + if((ivel)&&(nIvel>0)) { ADD_CHANNEL_VEC(mcInitialVelocity, nIvel, ivel); } + + checkIsAnimated(); + if(debugInitc) { + debMsgStd("ntlGeometryObject::initChannels",DM_MSG,getName()<< + " nt:"< *verts, vector *norms, int vstart, int vend, int forceTrafo) { + if( (mcTrans.accessValues().size()>1) // VALIDATE + || (mcRot.accessValues().size()>1) + || (mcScale.accessValues().size()>1) + || (forceTrafo) + || (!mHaveCachedMov) + ) { + // transformation is animated, continue + ntlVec3Gfx pos = getTranslation(t); + ntlVec3Gfx scale = mcScale.get(t); + ntlVec3Gfx rot = mcRot.get(t); + ntlMat4Gfx rotMat; + rotMat.initRotationXYZ(rot[0],rot[1],rot[2]); + pos += mInitialPos; + errMsg("ntlGeometryObject::applyTransformation","obj="< &verts, vector &tris, gfxReal fsTri) { + mTriangleDivs1.resize( tris.size() ); + mTriangleDivs2.resize( tris.size() ); + mTriangleDivs3.resize( tris.size() ); + + //fsTri *= 2.; // DEBUG! , wrong init! + + for(size_t i=0; i fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); } + if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); } + + mTriangleDivs1[i] = divs1; + mTriangleDivs2[i] = divs2; + mTriangleDivs3[i] = divs3; + } +} + +/*! Prepare points for moving objects */ +void ntlGeometryObject::initMovingPoints(double time, gfxReal featureSize) { + if((mMovPntsInited==featureSize)&&(!getMeshAnimated())) return; + const bool debugMoinit=false; + + vector triangles; + vector vertices; + vector vnormals; + int objectId = 1; + this->getTriangles(time, &triangles,&vertices,&vnormals,objectId); + + mMovPoints.clear(); + mMovNormals.clear(); + if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","Object "<maxpart) maxpart = ABS(maxscale[1]); + if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); + float scaleFac = 1.0/(maxpart); + // TODO - better reinit from time to time? + const gfxReal fsTri = featureSize*0.5 *scaleFac; + if(debugMoinit) errMsg("ntlGeometryObject::initMovingPoints","maxscale:"< fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); } + if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); } + errMsg("ntlGeometryObject::initMovingPoints","tri:"< "< 0) { + for(int u=0; u<=divs1; u++) { + for(int v=0; v<=divs2; v++) { + const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0); + const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0); + if(uf+vf>1.0) continue; + countp+=2; + } + } + } + } + errMsg("ntlGeometryObject::initMovingPoints","Object "< 0) { + for(int u=0; u<=divs1; u++) { + for(int v=0; v<=divs2; v++) { + const gfxReal uf = (gfxReal)(u+TRI_UVOFFSET) / (gfxReal)(divs1+0.0); + const gfxReal vf = (gfxReal)(v+TRI_UVOFFSET) / (gfxReal)(divs2+0.0); + if(uf+vf>1.0) continue; + ntlVec3Gfx p = + vertices[ trips[0] ] * (1.0-uf-vf)+ + vertices[ trips[1] ] * uf + + vertices[ trips[2] ] * vf; + //ntlVec3Gfx n = vnormals[ + //trips[0] ] * (1.0-uf-vf)+ + //vnormals[ trips[1] ]*uf + + //vnormals[ trips[2] ]*vf; + //normalize(n); + // discard inflow backsides + + mMovPoints.push_back(p + trinorm); // NEW!? + mMovPoints.push_back(p - trinorm); + mMovNormals.push_back(trinormOrg); + mMovNormals.push_back(trinormOrg); + //errMsg("TRINORM","p"<dist) { + mMaxMovPnt = i; + dist = normNoSqrt(mMovPoints[0]); + } + } + + if( (this-getMeshAnimated()) + || (mcTrans.accessValues().size()>1) // VALIDATE + || (mcRot.accessValues().size()>1) + || (mcScale.accessValues().size()>1) + ) { + // also do trafo... + } else { + mCachedMovPoints = mMovPoints; + mCachedMovNormals = mMovNormals; + //applyTransformation(time, &mCachedMovPoints, &mCachedMovNormals, 0, mCachedMovPoints.size(), true); + applyTransformation(time, &mCachedMovPoints, NULL, 0, mCachedMovPoints.size(), true); + mHaveCachedMov = true; + debMsgStd("ntlGeometryObject::initMovingPoints",DM_MSG,"Object "<"< &srcmovPoints, + double dsttime, vector &dstmovPoints, + vector *dstmovNormals, + gfxReal featureSize, + ntlVec3Gfx geostart, ntlVec3Gfx geoend + ) { + const bool debugMoinit=false; + + vector srctriangles; + vector srcvertices; + vector unused_normals; + vector dsttriangles; + vector dstvertices; + vector dstnormals; + int objectId = 1; + // TODO optimize? , get rid of normals? + unused_normals.clear(); + this->getTriangles(srctime, &srctriangles,&srcvertices,&unused_normals,objectId); + unused_normals.clear(); + this->getTriangles(dsttime, &dsttriangles,&dstvertices,&dstnormals,objectId); + + srcmovPoints.clear(); + dstmovPoints.clear(); + if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","Object "<maxpart) maxpart = ABS(maxscale[1]); + if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); + float scaleFac = 1.0/(maxpart); + // TODO - better reinit from time to time? + const gfxReal fsTri = featureSize*0.5 *scaleFac; + if(debugMoinit) errMsg("ntlGeometryObject::initMovingPointsAnim","maxscale:"< 0) { + int *srctrips = srctriangles[i].getPoints(); + int *dsttrips = dsttriangles[i].getPoints(); + const ntlVec3Gfx srcp0 = srcvertices[ srctrips[0] ]; + const ntlVec3Gfx srcside1 = srcvertices[ srctrips[1] ] - srcp0; + const ntlVec3Gfx srcside2 = srcvertices[ srctrips[2] ] - srcp0; + const ntlVec3Gfx dstp0 = dstvertices[ dsttrips[0] ]; + const ntlVec3Gfx dstside1 = dstvertices[ dsttrips[1] ] - dstp0; + const ntlVec3Gfx dstside2 = dstvertices[ dsttrips[2] ] - dstp0; + const ntlVec3Gfx src_trinorm = getNormalized(cross(srcside1,srcside2))*0.25*featureSize; + const ntlVec3Gfx dst_trinormOrg = getNormalized(cross(dstside1,dstside2)); + const ntlVec3Gfx dst_trinorm = dst_trinormOrg *0.25*featureSize; + //errMsg("ntlGeometryObject::initMovingPointsAnim","Tri1 "<1.0) continue; + ntlVec3Gfx srcp = + srcvertices[ srctrips[0] ] * (1.0-uf-vf)+ + srcvertices[ srctrips[1] ] * uf + + srcvertices[ srctrips[2] ] * vf; + ntlVec3Gfx dstp = + dstvertices[ dsttrips[0] ] * (1.0-uf-vf)+ + dstvertices[ dsttrips[1] ] * uf + + dstvertices[ dsttrips[2] ] * vf; + + // cutoffDomain + if((srcp[0]geoend[0] ) && (dstp[0]>geoend[0] )) continue; + if((srcp[1]>geoend[1] ) && (dstp[1]>geoend[1] )) continue; + if((srcp[2]>geoend[2] ) && (dstp[2]>geoend[2] )) continue; + + srcmovPoints.push_back(srcp+src_trinorm); // SURFENHTEST + srcmovPoints.push_back(srcp-src_trinorm); + + dstmovPoints.push_back(dstp+dst_trinorm); // SURFENHTEST + dstmovPoints.push_back(dstp-dst_trinorm); + if(dstmovNormals) { + (*dstmovNormals).push_back(dst_trinormOrg); + (*dstmovNormals).push_back(dst_trinormOrg); } + } + } + } + } + + // find max point not necessary + debMsgStd("ntlGeometryObject::initMovingPointsAnim",DM_MSG,"Object "<"< &ret, vector *norms) { + if(mHaveCachedMov) { + ret = mCachedMovPoints; + if(norms) { + *norms = mCachedMovNormals; + //errMsg("ntlGeometryObject","getMovingPoints - Normals currently unused!"); + } + //errMsg ("ntlGeometryObject::getMovingPoints","Object "< verts1,verts2; + verts1.push_back(mMovPoints[mMaxMovPnt]); + verts2 = verts1; + applyTransformation(t1,&verts1,NULL, 0,verts1.size(), true); + applyTransformation(t2,&verts2,NULL, 0,verts2.size(), true); + + vel = (verts2[0]-verts1[0]); // /(t2-t1); + //errMsg("ntlGeometryObject::calculateMaxVel","t1="< off + return act; +} + +void ntlGeometryObject::setInitialVelocity(ntlVec3Gfx set) { + mInitialVelocity=set; + mcInitialVelocity = AnimChannel(set); +} +ntlVec3Gfx ntlGeometryObject::getInitialVelocity(double t) { + ntlVec3Gfx v = mcInitialVelocity.get(t); //return mInitialVelocity; + if(!mLocalCoordInivel) return v; + + ntlVec3Gfx rot = mcRot.get(t); + ntlMat4Gfx rotMat; + rotMat.initRotationXYZ(rot[0],rot[1],rot[2]); + v = rotMat * v; + return v; +} + + diff --git a/intern/elbeem/intern/ntl_geometryobject.h b/intern/elbeem/intern/ntl_geometryobject.h new file mode 100644 index 00000000000..a5afd6b2207 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometryobject.h @@ -0,0 +1,211 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * a geometry object + * all other geometry objects are derived from this one + * + *****************************************************************************/ +#ifndef NTL_GEOMETRYOBJECT_H +#define NTL_GEOMETRYOBJECT_H + +#include "ntl_geometryclass.h" +#include "ntl_lighting.h" +#include "ntl_ray.h" +class ntlRenderGlobals; +class ntlTriangle; + +#define DUMP_FULLGEOMETRY 1 +#define DUMP_PARTIAL 2 + +#define VOLUMEINIT_VOLUME 1 +#define VOLUMEINIT_SHELL 2 +#define VOLUMEINIT_BOTH (VOLUMEINIT_SHELL|VOLUMEINIT_VOLUME) + +class ntlGeometryObject : public ntlGeometryClass +{ + + public: + //! Default constructor + ntlGeometryObject(); + //! Default destructor + virtual ~ntlGeometryObject(); + + //! Return type id + virtual int getTypeId() { return GEOCLASSTID_OBJECT; } + + /*! Init attributes etc. of this object */ + virtual void initialize(ntlRenderGlobals *glob); + + /*! Get the triangles from this object */ + virtual void getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ) = 0; + + /*! notify object that dump is in progress (e.g. for particles) */ + virtual void notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime); + + /*! Search the material for this object from the material list */ + void searchMaterial(vector *mat); + + /* Acces methods */ + /*! Set the property of this object */ + inline void setMaterial(ntlMaterial *p) { mpMaterial = p; } + /*! Get the surface property of this object */ + inline ntlMaterial *getMaterial( void ) { return mpMaterial; } + /*! Set the object property name */ + inline void setMaterialName(string set) { mMaterialName = set; } + /*! Get the object property name */ + inline string getMaterialName( void ) { return mMaterialName; } + + /*! Sets the receive shadows attribute */ + inline void setReceiveShadows(int set) { mReceiveShadows=set; } + /*! Returns the receive shadows attribute */ + inline int getReceiveShadows() const { return mReceiveShadows; } + + /*! Sets the cast shadows attribute */ + inline void setCastShadows(int set) { mCastShadows=set; } + /*! Returns the cast shadows attribute */ + inline int getCastShadows() const { return mCastShadows; } + + /*! Returns the geo init typ */ + inline void setGeoInitType(int set) { mGeoInitType=set; } + /*! Returns the geo init typ */ + inline int getGeoInitType() const { return mGeoInitType; } + + /*! Set/get the intersect init flag */ + inline bool getGeoInitIntersect() const { return mGeoInitIntersect; } + inline void setGeoInitIntersect(bool set) { mGeoInitIntersect=set; } + + /*! Set/get the part slip value*/ + inline float getGeoPartSlipValue() const { return mGeoPartSlipValue; } + inline void setGeoPartSlipValue(float set) { mGeoPartSlipValue=set; } + + /*! Set/get the impact corr factor channel */ + inline float getGeoImpactFactor(double t) { return mcGeoImpactFactor.get(t); } + inline void setGeoImpactFactor(float set) { mcGeoImpactFactor = AnimChannel(set); } + + /*! Set/get the part slip value*/ + inline int getVolumeInit() const { return mVolumeInit; } + inline void setVolumeInit(int set) { mVolumeInit=set; } + + /*! Set/get the cast initial veocity attribute */ + void setInitialVelocity(ntlVec3Gfx set); + ntlVec3Gfx getInitialVelocity(double t); + + /*! Set/get the local inivel coords flag */ + inline bool getLocalCoordInivel() const { return mLocalCoordInivel; } + inline void setLocalCoordInivel(bool set) { mLocalCoordInivel=set; } + + /*! Init channels from float arrays (for elbeem API) */ + void initChannels( + int nTrans, float *trans, int nRot, float *rot, int nScale, float *scale, + int nAct, float *act, int nIvel, float *ivel + ); + + /*! is the object animated? */ + inline bool getIsAnimated() const { return mIsAnimated; } + /*! init object anim flag */ + bool checkIsAnimated(); + /*! is the mesh animated? */ + virtual bool getMeshAnimated(); + /*! init triangle divisions */ + virtual void calcTriangleDivs(vector &verts, vector &tris, gfxReal fsTri); + + /*! apply object translation at time t*/ + void applyTransformation(double t, vector *verts, vector *norms, int vstart, int vend, int forceTrafo); + + /*! Prepare points for moving objects */ + void initMovingPoints(double time, gfxReal featureSize); + /*! Prepare points for animated objects */ + void initMovingPointsAnim( + double srctime, vector &srcpoints, + double dsttime, vector &dstpoints, + vector *dstnormals, + gfxReal featureSize, ntlVec3Gfx geostart, ntlVec3Gfx geoend ); + /*! Prepare points for moving objects (copy into ret) */ + void getMovingPoints(vector &ret, vector *norms = NULL); + /*! Calculate max. velocity on object from t1 to t2 */ + ntlVec3Gfx calculateMaxVel(double t1, double t2); + /*! get translation at time t*/ + ntlVec3Gfx getTranslation(double t); + /*! get active flag time t*/ + float getGeoActive(double t); + + /*! add triangle to scene and init flags */ + // helper function for getTriangles + void sceneAddTriangle( + ntlVec3Gfx p1,ntlVec3Gfx p2,ntlVec3Gfx p3, + ntlVec3Gfx pn1,ntlVec3Gfx pn2,ntlVec3Gfx pn3, + ntlVec3Gfx trin, bool smooth, + vector *triangles, + vector *vertices, + vector *vertNormals); + void sceneAddTriangleNoVert(int *trips, + ntlVec3Gfx trin, bool smooth, + vector *triangles); + + protected: + + /* initialized for scene? */ + bool mIsInitialized; + + /*! Point to a property object describing the surface of this object */ + ntlMaterial *mpMaterial; + + /*! Name of the surcace property */ + string mMaterialName; + + /*! Cast shadows on/off */ + int mCastShadows; + /*! REceive shadows on/off */ + int mReceiveShadows; + + /* fluid init data */ + /*! fluid object type (fluid, obstacle, accelerator etc.) */ + int mGeoInitType; + /*! initial velocity for fluid objects */ + ntlVec3Gfx mInitialVelocity; + AnimChannel mcInitialVelocity; + /*! use object local inflow? */ + bool mLocalCoordInivel; + /*! perform more accurate intersecting geo init for this object? */ + bool mGeoInitIntersect; + /*! part slip bc value */ + float mGeoPartSlipValue; + /*! obstacle impact correction factor */ + AnimChannel mcGeoImpactFactor; + /*! only init as thin object, dont fill? */ + int mVolumeInit; + + /*! initial offset for rot/scale */ + ntlVec3Gfx mInitialPos; + /*! animated channels for postition, rotation and scale */ + AnimChannel mcTrans, mcRot, mcScale; + /*! easy check for animation */ + bool mIsAnimated; + + /*! moving point/normal storage */ + vector mMovPoints; + vector mMovNormals; + /*! cached points for non moving objects/timeslots */ + bool mHaveCachedMov; + vector mCachedMovPoints; + vector mCachedMovNormals; + /*! precomputed triangle divisions */ + vector mTriangleDivs1,mTriangleDivs2,mTriangleDivs3; + /*! inited? */ + float mMovPntsInited; + /*! point with max. distance from center */ + int mMaxMovPnt; + + /*! animated channels for in/outflow on/off */ + AnimChannel mcGeoActive; + + public: + +}; + +#endif + diff --git a/intern/elbeem/intern/ntl_geometryshader.h b/intern/elbeem/intern/ntl_geometryshader.h new file mode 100644 index 00000000000..3ecb82e0556 --- /dev/null +++ b/intern/elbeem/intern/ntl_geometryshader.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Interface for a geometry shader + * + *****************************************************************************/ +#ifndef NTL_GEOMETRYSHADER_H +#define NTL_GEOMETRYSHADER_H + +#include "ntl_geometryclass.h" +class ntlGeometryObject; +class ntlRenderGlobals; + +class ntlGeometryShader : + public ntlGeometryClass +{ + + public: + + //! Default constructor + inline ntlGeometryShader() : + ntlGeometryClass(), mOutFilename("") + {}; + //! Default destructor + virtual ~ntlGeometryShader() {}; + + //! Return type id + virtual int getTypeId() { return GEOCLASSTID_SHADER; } + + /*! Initialize object, should return !=0 upon error */ + virtual int initializeShader() = 0; + + /*! Do further object initialization after all geometry has been constructed, should return !=0 upon error */ + virtual int postGeoConstrInit(ntlRenderGlobals *glob) { glob=NULL; /*unused*/ return 0; }; + + /*! Get start iterator for all objects */ + virtual vector::iterator getObjectsBegin() { return mObjects.begin(); } + /*! Get end iterator for all objects */ + virtual vector::iterator getObjectsEnd() { return mObjects.end(); } + + /*! notify object that dump is in progress (e.g. for field dump) */ + virtual void notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) = 0; + + /*! get ouput filename, returns global render outfile if empty */ + string getOutFilename( void ) { return mOutFilename; } + + protected: + + //! vector for the objects + vector mObjects; + + + /*! surface output name for this simulation */ + string mOutFilename; +}; + +#endif + diff --git a/intern/elbeem/intern/ntl_lighting.cpp b/intern/elbeem/intern/ntl_lighting.cpp new file mode 100644 index 00000000000..b11c1fdd4ed --- /dev/null +++ b/intern/elbeem/intern/ntl_lighting.cpp @@ -0,0 +1,181 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * a light object + * + *****************************************************************************/ + + +#include "ntl_lighting.h" +#include "ntl_ray.h" +#include "ntl_world.h" + + +/****************************************************************************** + * Default Constructor + *****************************************************************************/ +ntlLightObject::ntlLightObject(ntlRenderGlobals *glob) : + mpGlob( glob ), + mActive( 1 ), + mCastShadows( 1 ), + mcColor( ntlColor(1.0) ), + mvPosition( ntlVec3Gfx(0.0) ) +{ + // nothing to do... +} + + +/****************************************************************************** + * Constructor with parameters + *****************************************************************************/ +ntlLightObject::ntlLightObject(ntlRenderGlobals *glob, const ntlColor& col) : + mpGlob( glob ), + mActive( 1 ), + mCastShadows( 1 ), + mcColor( col ) +{ + // nothing to do... +} + + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlLightObject::~ntlLightObject() +{ + // nothing to do... +} + + + +/****************************************************************************** + * Determine color contribution of a lightsource (Phong model) + * Specular part is returned in seperate parameter and added later + *****************************************************************************/ +const ntlColor +ntlLightObject::getShadedColor(const ntlRay &reflectedRay, const ntlVec3Gfx lightDir, + ntlMaterial *surf, ntlColor &highlight) const +{ + gfxReal ldot = dot(lightDir, reflectedRay.getNormal()); /* equals cos( angle(L,N) ) */ + ntlColor reflected_color = ntlColor(0.0); /* adds up to total reflected color */ + if(mpGlob->getDebugOut() > 5) errorOut("Lighting dir:"< 0.0) { + //ldot *= -1.0; + reflected_color += surf->getDiffuseRefl() * (getColor() * ldot ); + + /* specular part */ + /* specular reflection only makes sense, when the light is facing the surface, + as the highlight is supposed to be a reflection of the lightsource, it cannot + be reflected on surfaces with ldot<=0, as this means the arc between light + and normal is more than 90 degrees. If this isn't done, ugly moiree patterns appear + in the highlights, and refractions have strange patterns due to highlights on the + inside of the surface */ + gfxReal spec = dot(reflectedRay.getDirection(), lightDir); // equals cos( angle(R,L) ) + if((spec > 0.0) && (surf->getSpecular()>0)) { + spec = pow( spec, surf->getSpecExponent() ); /* phong exponent */ + highlight += getColor() * surf->getSpecular() * spec; + //errorOut( " "<< surf->getName() <<" S "<getSpecular()<<" "<getSpecExponent() ); + } + + } + + return ntlColor(reflected_color); +} + + +// omni light implementation + + +/****************************************************************************** + *! prepare shadow maps if necessary + *****************************************************************************/ +void ntlLightObject::prepare( bool doCaustics ) +{ + doCaustics = false; // unused + if(!mActive) { return; } +} + + +/****************************************************************************** + * Illuminate the given point on an object + *****************************************************************************/ +ntlColor ntlLightObject::illuminatePoint(ntlRay &reflectedRay, ntlGeometryObject *closest, + ntlColor &highlight ) +{ + /* is this light active? */ + if(!mActive) { return ntlColor(0.0); } + + gfxReal visibility = 1.0; // how much of light is visible + ntlVec3Gfx intersectionPos = reflectedRay.getOrigin(); + ntlColor current_color = ntlColor(0.0); + ntlMaterial *clossurf = closest->getMaterial(); + + ntlVec3Gfx lightDir = (mvPosition - intersectionPos); + gfxReal lightDirNorm = normalize(lightDir); + + // where is the lightsource ? + ntlRay rayOfLight(intersectionPos, lightDir, 0, 1.0, mpGlob ); + + if( (1) && (mCastShadows)&&(closest->getReceiveShadows()) ) { + ntlTriangle *tri; + ntlVec3Gfx triNormal; + gfxReal trit; + mpGlob->getRenderScene()->intersectScene(rayOfLight, trit, triNormal, tri, TRI_CASTSHADOWS); + if(( trit>0 )&&( tritgetDebugOut() > 5) errorOut("Omni lighting with "<0.0) { + ntlColor highTemp(0.0); // temporary highlight color to multiply highTemp with offFac + current_color = getShadedColor(reflectedRay, lightDir, clossurf, highTemp) * visibility; + highlight += highTemp * visibility; + if(mpGlob->getDebugOut() > 5) errorOut("Omni lighting color "< +class ntlMatrix4x4 +{ +public: + // Constructor + inline ntlMatrix4x4(void ); + // Copy-Constructor + inline ntlMatrix4x4(const ntlMatrix4x4 &v ); + // construct a vector from one Scalar + inline ntlMatrix4x4(Scalar); + // construct a vector from three Scalars + inline ntlMatrix4x4(Scalar, Scalar, Scalar); + + // Assignment operator + inline const ntlMatrix4x4& operator= (const ntlMatrix4x4& v); + // Assignment operator + inline const ntlMatrix4x4& operator= (Scalar s); + // Assign and add operator + inline const ntlMatrix4x4& operator+= (const ntlMatrix4x4& v); + // Assign and add operator + inline const ntlMatrix4x4& operator+= (Scalar s); + // Assign and sub operator + inline const ntlMatrix4x4& operator-= (const ntlMatrix4x4& v); + // Assign and sub operator + inline const ntlMatrix4x4& operator-= (Scalar s); + // Assign and mult operator + inline const ntlMatrix4x4& operator*= (const ntlMatrix4x4& v); + // Assign and mult operator + inline const ntlMatrix4x4& operator*= (Scalar s); + // Assign and div operator + inline const ntlMatrix4x4& operator/= (const ntlMatrix4x4& v); + // Assign and div operator + inline const ntlMatrix4x4& operator/= (Scalar s); + + + // unary operator + inline ntlMatrix4x4 operator- () const; + + // binary operator add + inline ntlMatrix4x4 operator+ (const ntlMatrix4x4&) const; + // binary operator add + inline ntlMatrix4x4 operator+ (Scalar) const; + // binary operator sub + inline ntlMatrix4x4 operator- (const ntlMatrix4x4&) const; + // binary operator sub + inline ntlMatrix4x4 operator- (Scalar) const; + // binary operator mult + inline ntlMatrix4x4 operator* (const ntlMatrix4x4&) const; + // binary operator mult + inline ntlVector3Dim operator* (const ntlVector3Dim&) const; + // binary operator mult + inline ntlMatrix4x4 operator* (Scalar) const; + // binary operator div + inline ntlMatrix4x4 operator/ (Scalar) const; + + // init function + //! init identity matrix + inline void initId(); + //! init rotation matrix + inline void initTranslation(Scalar x, Scalar y, Scalar z); + //! init rotation matrix + inline void initRotationX(Scalar rot); + inline void initRotationY(Scalar rot); + inline void initRotationZ(Scalar rot); + inline void initRotationXYZ(Scalar rotx,Scalar roty, Scalar rotz); + //! init scaling matrix + inline void initScaling(Scalar scale); + inline void initScaling(Scalar x, Scalar y, Scalar z); + //! from 16 value array (init id if all 0) + inline void initArrayCheck(Scalar *array); + + //! decompose matrix + void decompose(ntlVector3Dim &trans,ntlVector3Dim &scale,ntlVector3Dim &rot,ntlVector3Dim &shear); + + //! public to avoid [][] operators + Scalar value[4][4]; //< Storage of vector values + + +protected: + +}; + + + +//------------------------------------------------------------------------------ +// TYPEDEFS +//------------------------------------------------------------------------------ + +// a 3D vector for graphics output, typically float? +//typedef ntlMatrix4x4 ntlVec3Gfx; + +//typedef ntlMatrix4x4 ntlMat4d; +typedef ntlMatrix4x4 ntlMat4d; + +// a 3D vector with single precision +typedef ntlMatrix4x4 ntlMat4f; + +// a 3D vector with grafix precision +typedef ntlMatrix4x4 ntlMat4Gfx; + +// a 3D integer vector +typedef ntlMatrix4x4 ntlMat4i; + + + + + +//------------------------------------------------------------------------------ +// STREAM FUNCTIONS +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Outputs the object in human readable form using the format + [x,y,z] + */ +template +std::ostream& +operator<<( std::ostream& os, const ntlMatrix4x4& m ) +{ + for(int i=0; i<4; i++) { + os << '|' << m.value[i][0] << ", " << m.value[i][1] << ", " << m.value[i][2] << ", " << m.value[i][3] << '|'; + } + return os; +} + + + +/************************************************************************* + Reads the contents of the object from a stream using the same format + as the output operator. + */ +template +std::istream& +operator>>( std::istream& is, ntlMatrix4x4& m ) +{ + char c; + char dummy[3]; + + for(int i=0; i<4; i++) { + is >> c >> m.value[i][0] >> dummy >> m.value[i][1] >> dummy >> m.value[i][2] >> dummy >> m.value[i][3] >> c; + } + return is; +} + + +//------------------------------------------------------------------------------ +// VECTOR inline FUNCTIONS +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Constructor. + */ +template +inline ntlMatrix4x4::ntlMatrix4x4( void ) +{ +#ifdef MATRIX_INIT_ZERO + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] = 0.0; + } + } +#endif +} + + + +/************************************************************************* + Copy-Constructor. + */ +template +inline ntlMatrix4x4::ntlMatrix4x4( const ntlMatrix4x4 &v ) +{ + value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3]; + value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3]; + value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3]; + value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3]; +} + + + +/************************************************************************* + Constructor for a vector from a single Scalar. All components of + the vector get the same value. + \param s The value to set + \return The new vector + */ +template +inline ntlMatrix4x4::ntlMatrix4x4(Scalar s ) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] = s; + } + } +} + + + +/************************************************************************* + Copy a ntlMatrix4x4 componentwise. + \param v vector with values to be copied + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator=( const ntlMatrix4x4 &v ) +{ + value[0][0] = v.value[0][0]; value[0][1] = v.value[0][1]; value[0][2] = v.value[0][2]; value[0][3] = v.value[0][3]; + value[1][0] = v.value[1][0]; value[1][1] = v.value[1][1]; value[1][2] = v.value[1][2]; value[1][3] = v.value[1][3]; + value[2][0] = v.value[2][0]; value[2][1] = v.value[2][1]; value[2][2] = v.value[2][2]; value[2][3] = v.value[2][3]; + value[3][0] = v.value[3][0]; value[3][1] = v.value[3][1]; value[3][2] = v.value[3][2]; value[3][3] = v.value[3][3]; + return *this; +} + + +/************************************************************************* + Copy a Scalar to each component. + \param s The value to copy + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] = s; + } + } + return *this; +} + + +/************************************************************************* + Add another ntlMatrix4x4 componentwise. + \param v vector with values to be added + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator+=( const ntlMatrix4x4 &v ) +{ + value[0][0] += v.value[0][0]; value[0][1] += v.value[0][1]; value[0][2] += v.value[0][2]; value[0][3] += v.value[0][3]; + value[1][0] += v.value[1][0]; value[1][1] += v.value[1][1]; value[1][2] += v.value[1][2]; value[1][3] += v.value[1][3]; + value[2][0] += v.value[2][0]; value[2][1] += v.value[2][1]; value[2][2] += v.value[2][2]; value[2][3] += v.value[2][3]; + value[3][0] += v.value[3][0]; value[3][1] += v.value[3][1]; value[3][2] += v.value[3][2]; value[3][3] += v.value[3][3]; + return *this; +} + + +/************************************************************************* + Add a Scalar value to each component. + \param s Value to add + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator+=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] += s; + } + } + return *this; +} + + +/************************************************************************* + Subtract another vector componentwise. + \param v vector of values to subtract + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator-=( const ntlMatrix4x4 &v ) +{ + value[0][0] -= v.value[0][0]; value[0][1] -= v.value[0][1]; value[0][2] -= v.value[0][2]; value[0][3] -= v.value[0][3]; + value[1][0] -= v.value[1][0]; value[1][1] -= v.value[1][1]; value[1][2] -= v.value[1][2]; value[1][3] -= v.value[1][3]; + value[2][0] -= v.value[2][0]; value[2][1] -= v.value[2][1]; value[2][2] -= v.value[2][2]; value[2][3] -= v.value[2][3]; + value[3][0] -= v.value[3][0]; value[3][1] -= v.value[3][1]; value[3][2] -= v.value[3][2]; value[3][3] -= v.value[3][3]; + return *this; +} + + +/************************************************************************* + Subtract a Scalar value from each component. + \param s Value to subtract + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator-=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] -= s; + } + } + return *this; +} + + +/************************************************************************* + Multiply with another vector componentwise. + \param v vector of values to multiply with + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator*=( const ntlMatrix4x4 &v ) +{ + ntlMatrix4x4 nv(0.0); + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + + for(int k=0;k<4;k++) + nv.value[i][j] += (value[i][k] * v.value[k][j]); + } + } + *this = nv; + return *this; +} + + +/************************************************************************* + Multiply each component with a Scalar value. + \param s Value to multiply with + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator*=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] *= s; + } + } + return *this; +} + + + +/************************************************************************* + Divide each component by a Scalar value. + \param s Value to divide by + \return Reference to self + */ +template +inline const ntlMatrix4x4& +ntlMatrix4x4::operator/=(Scalar s) +{ + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] /= s; + } + } + return *this; +} + + +//------------------------------------------------------------------------------ +// unary operators +//------------------------------------------------------------------------------ + + +/************************************************************************* + Build componentwise the negative this vector. + \return The new (negative) vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator-() const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = -value[i][j]; + } + } + return nv; +} + + + +//------------------------------------------------------------------------------ +// binary operators +//------------------------------------------------------------------------------ + + +/************************************************************************* + Build a vector with another vector added componentwise. + \param v The second vector to add + \return The sum vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator+( const ntlMatrix4x4 &v ) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] + v.value[i][j]; + } + } + return nv; +} + + +/************************************************************************* + Build a vector with a Scalar value added to each component. + \param s The Scalar value to add + \return The sum vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator+(Scalar s) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] + s; + } + } + return nv; +} + + +/************************************************************************* + Build a vector with another vector subtracted componentwise. + \param v The second vector to subtract + \return The difference vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator-( const ntlMatrix4x4 &v ) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] - v.value[i][j]; + } + } + return nv; +} + + +/************************************************************************* + Build a vector with a Scalar value subtracted componentwise. + \param s The Scalar value to subtract + \return The difference vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator-(Scalar s ) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] - s; + } + } + return nv; +} + + + +/************************************************************************* + Build a ntlMatrix4x4 with a Scalar value multiplied to each component. + \param s The Scalar value to multiply with + \return The product vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator*(Scalar s) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] * s; + } + } + return nv; +} + + + + +/************************************************************************* + Build a vector divided componentwise by a Scalar value. + \param s The Scalar value to divide by + \return The ratio vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator/(Scalar s) const +{ + ntlMatrix4x4 nv; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + nv[i][j] = value[i][j] / s; + } + } + return nv; +} + + + + + +/************************************************************************* + Build a vector with another vector multiplied by componentwise. + \param v The second vector to muliply with + \return The product vector + */ +template +inline ntlMatrix4x4 +ntlMatrix4x4::operator*( const ntlMatrix4x4& v) const +{ + ntlMatrix4x4 nv(0.0); + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + + for(int k=0;k<4;k++) + nv.value[i][j] += (value[i][k] * v.value[k][j]); + } + } + return nv; +} + + +template +inline ntlVector3Dim +ntlMatrix4x4::operator*( const ntlVector3Dim& v) const +{ + ntlVector3Dim nvec(0.0); + for(int i=0; i<3; i++) { + for(int j=0; j<3; j++) { + nvec[i] += (v[j] * value[i][j]); + } + } + // assume normalized w coord + for(int i=0; i<3; i++) { + nvec[i] += (1.0 * value[i][3]); + } + return nvec; +} + + + +//------------------------------------------------------------------------------ +// Other helper functions +//------------------------------------------------------------------------------ + +//! init identity matrix +template +inline void ntlMatrix4x4::initId() +{ + (*this) = (Scalar)(0.0); + value[0][0] = + value[1][1] = + value[2][2] = + value[3][3] = (Scalar)(1.0); +} + +//! init rotation matrix +template +inline void ntlMatrix4x4::initTranslation(Scalar x, Scalar y, Scalar z) +{ + //(*this) = (Scalar)(0.0); + this->initId(); + value[0][3] = x; + value[1][3] = y; + value[2][3] = z; +} + +//! init rotation matrix +template +inline void +ntlMatrix4x4::initRotationX(Scalar rot) +{ + double drot = (double)(rot/360.0*2.0*M_PI); + //? while(drot < 0.0) drot += (M_PI*2.0); + + this->initId(); + value[1][1] = (Scalar) cos(drot); + value[1][2] = (Scalar) sin(drot); + value[2][1] = (Scalar)(-sin(drot)); + value[2][2] = (Scalar) cos(drot); +} +template +inline void +ntlMatrix4x4::initRotationY(Scalar rot) +{ + double drot = (double)(rot/360.0*2.0*M_PI); + //? while(drot < 0.0) drot += (M_PI*2.0); + + this->initId(); + value[0][0] = (Scalar) cos(drot); + value[0][2] = (Scalar)(-sin(drot)); + value[2][0] = (Scalar) sin(drot); + value[2][2] = (Scalar) cos(drot); +} +template +inline void +ntlMatrix4x4::initRotationZ(Scalar rot) +{ + double drot = (double)(rot/360.0*2.0*M_PI); + //? while(drot < 0.0) drot += (M_PI*2.0); + + this->initId(); + value[0][0] = (Scalar) cos(drot); + value[0][1] = (Scalar) sin(drot); + value[1][0] = (Scalar)(-sin(drot)); + value[1][1] = (Scalar) cos(drot); +} +template +inline void +ntlMatrix4x4::initRotationXYZ( Scalar rotx, Scalar roty, Scalar rotz) +{ + ntlMatrix4x4 val; + ntlMatrix4x4 rot; + this->initId(); + + // org + /*rot.initRotationX(rotx); + (*this) *= rot; + rot.initRotationY(roty); + (*this) *= rot; + rot.initRotationZ(rotz); + (*this) *= rot; + // org */ + + // blender + rot.initRotationZ(rotz); + (*this) *= rot; + rot.initRotationY(roty); + (*this) *= rot; + rot.initRotationX(rotx); + (*this) *= rot; + // blender */ +} + +//! init scaling matrix +template +inline void +ntlMatrix4x4::initScaling(Scalar scale) +{ + this->initId(); + value[0][0] = scale; + value[1][1] = scale; + value[2][2] = scale; +} +//! init scaling matrix +template +inline void +ntlMatrix4x4::initScaling(Scalar x, Scalar y, Scalar z) +{ + this->initId(); + value[0][0] = x; + value[1][1] = y; + value[2][2] = z; +} + + +//! from 16 value array (init id if all 0) +template +inline void +ntlMatrix4x4::initArrayCheck(Scalar *array) +{ + bool allZero = true; + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + value[i][j] = array[i*4+j]; + if(array[i*4+j]!=0.0) allZero=false; + } + } + if(allZero) this->initId(); +} + +//! decompose matrix +template +void +ntlMatrix4x4::decompose(ntlVector3Dim &trans,ntlVector3Dim &scale,ntlVector3Dim &rot,ntlVector3Dim &shear) { + ntlVec3Gfx row[3],temp; + + for(int i = 0; i < 3; i++) { + trans[i] = this->value[3][i]; + } + + for(int i = 0; i < 3; i++) { + row[i][0] = this->value[i][0]; + row[i][1] = this->value[i][1]; + row[i][2] = this->value[i][2]; + } + + scale[0] = norm(row[0]); + normalize (row[0]); + + shear[0] = dot(row[0], row[1]); + row[1][0] = row[1][0] - shear[0]*row[0][0]; + row[1][1] = row[1][1] - shear[0]*row[0][1]; + row[1][2] = row[1][2] - shear[0]*row[0][2]; + + scale[1] = norm(row[1]); + normalize (row[1]); + + if(scale[1] != 0.0) + shear[0] /= scale[1]; + + shear[1] = dot(row[0], row[2]); + row[2][0] = row[2][0] - shear[1]*row[0][0]; + row[2][1] = row[2][1] - shear[1]*row[0][1]; + row[2][2] = row[2][2] - shear[1]*row[0][2]; + + shear[2] = dot(row[1], row[2]); + row[2][0] = row[2][0] - shear[2]*row[1][0]; + row[2][1] = row[2][1] - shear[2]*row[1][1]; + row[2][2] = row[2][2] - shear[2]*row[1][2]; + + scale[2] = norm(row[2]); + normalize (row[2]); + + if(scale[2] != 0.0) { + shear[1] /= scale[2]; + shear[2] /= scale[2]; + } + + temp = cross(row[1], row[2]); + if(dot(row[0], temp) < 0.0) { + for(int i = 0; i < 3; i++) { + scale[i] *= -1.0; + row[i][0] *= -1.0; + row[i][1] *= -1.0; + row[i][2] *= -1.0; + } + } + + if(row[0][2] < -1.0) row[0][2] = -1.0; + if(row[0][2] > +1.0) row[0][2] = +1.0; + + rot[1] = asin(-row[0][2]); + + if(fabs(cos(rot[1])) > VECTOR_EPSILON) { + rot[0] = atan2 (row[1][2], row[2][2]); + rot[2] = atan2 (row[0][1], row[0][0]); + } + else { + rot[0] = atan2 (row[1][0], row[1][1]); + rot[2] = 0.0; + } + + rot[0] = (180.0/M_PI)*rot[0]; + rot[1] = (180.0/M_PI)*rot[1]; + rot[2] = (180.0/M_PI)*rot[2]; +} + +#define NTL_MATRICES_H +#endif + diff --git a/intern/elbeem/intern/ntl_ray.cpp b/intern/elbeem/intern/ntl_ray.cpp new file mode 100644 index 00000000000..d6593b6b335 --- /dev/null +++ b/intern/elbeem/intern/ntl_ray.cpp @@ -0,0 +1,912 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * main renderer class + * + *****************************************************************************/ + + +#include "utilities.h" +#include "ntl_ray.h" +#include "ntl_world.h" +#include "ntl_geometryobject.h" +#include "ntl_geometryshader.h" + + +/* Minimum value for refl/refr to be traced */ +#define RAY_THRESHOLD 0.001 + +#if GFX_PRECISION==1 +// float values +//! Minimal contribution for rays to be traced on +#define RAY_MINCONTRIB (1e-04) + +#else +// double values +//! Minimal contribution for rays to be traced on +#define RAY_MINCONTRIB (1e-05) + +#endif + + + + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +ntlRay::ntlRay( void ) + : mOrigin(0.0) + , mDirection(0.0) + , mvNormal(0.0) + , mDepth(0) + , mpGlob(NULL) + , mIsRefracted(0) +{ + errFatal("ntlRay::ntlRay()","Don't use uninitialized rays !", SIMWORLD_GENERICERROR); + return; +} + + +/****************************************************************************** + * Copy - Constructor + *****************************************************************************/ +ntlRay::ntlRay( const ntlRay &r ) +{ + // copy it! initialization is not enough! + mOrigin = r.mOrigin; + mDirection = r.mDirection; + mvNormal = r.mvNormal; + mDepth = r.mDepth; + mIsRefracted = r.mIsRefracted; + mIsReflected = r.mIsReflected; + mContribution = r.mContribution; + mpGlob = r.mpGlob; + + // get new ID + if(mpGlob) { + mID = mpGlob->getCounterRays()+1; + mpGlob->setCounterRays( mpGlob->getCounterRays()+1 ); + } else { + mID = 0; + } +} + + +/****************************************************************************** + * Constructor with explicit parameters and global render object + *****************************************************************************/ +ntlRay::ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob) + : mOrigin( o ) + , mDirection( d ) + , mvNormal(0.0) + , mDepth( i ) + , mContribution( contrib ) + , mpGlob( glob ) + , mIsRefracted( 0 ) + , mIsReflected( 0 ) +{ + // get new ID + if(mpGlob) { + mID = mpGlob->getCounterRays()+1; + mpGlob->setCounterRays( mpGlob->getCounterRays()+1 ); + } else { + mID = 0; + } +} + + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlRay::~ntlRay() +{ + /* nothing to do... */ +} + + + +/****************************************************************************** + * AABB + *****************************************************************************/ +/* for AABB intersect */ +#define NUMDIM 3 +#define RIGHT 0 +#define LEFT 1 +#define MIDDLE 2 + +//! intersect ray with AABB +#ifndef ELBEEM_PLUGIN +void ntlRay::intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const +{ + char inside = true; /* inside box? */ + char hit = false; /* ray hits box? */ + int whichPlane; /* intersection plane */ + gfxReal candPlane[NUMDIM]; /* candidate plane */ + gfxReal quadrant[NUMDIM]; /* quadrants */ + gfxReal maxT[NUMDIM]; /* max intersection T for planes */ + ntlVec3Gfx coord; /* intersection point */ + ntlVec3Gfx dir = mDirection; + ntlVec3Gfx origin = mOrigin; + ntlVec3Gfx normal(0.0, 0.0, 0.0); + + t = GFX_REAL_MAX; + + /* check intersection planes for AABB */ + for(int i=0;i mEnd[i]) { + quadrant[i] = RIGHT; + candPlane[i] = mEnd[i]; + inside = false; + } else { + quadrant[i] = MIDDLE; + } + } + + /* inside AABB? */ + if(!inside) { + /* get t distances to planes */ + /* treat too small direction components as paralell */ + for(int i=0;i getVecEpsilon()) ) { + maxT[i] = (candPlane[i] - origin[i]) / dir[i]; + } else { + maxT[i] = -1; + } + } + + /* largest max t */ + whichPlane = 0; + for(int i=1;i= 0.0) { + + for(int i=0;i mEnd[i] +getVecEpsilon() ) ) { + /* no hit... */ + hit = false; + } + } + else { + coord[i] = candPlane[i]; + } + } + + /* AABB hit... */ + if( hit ) { + t = maxT[whichPlane]; + if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0; + else normal[whichPlane] = -1.0; + } + } + + + } else { + /* inside AABB... */ + t = 0.0; + coord = origin; + return; + } + + if(t == GFX_REAL_MAX) t = -1.0; + retnormal = normal; + retcoord = coord; +} + +//! intersect ray with AABB +void ntlRay::intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &retnormal,ntlVec3Gfx &retcoord) const +{ + char hit = false; /* ray hits box? */ + int whichPlane; /* intersection plane */ + gfxReal candPlane[NUMDIM]; /* candidate plane */ + gfxReal quadrant[NUMDIM]; /* quadrants */ + gfxReal maxT[NUMDIM]; /* max intersection T for planes */ + ntlVec3Gfx coord; /* intersection point */ + ntlVec3Gfx dir = mDirection; + ntlVec3Gfx origin = mOrigin; + ntlVec3Gfx normal(0.0, 0.0, 0.0); + + t = GFX_REAL_MAX; + for(int i=0;i mEnd[i]) { + quadrant[i] = RIGHT; + candPlane[i] = mStart[i]; + } else { + if(dir[i] > 0) { + quadrant[i] = LEFT; + candPlane [i] = mEnd[i]; + } else + if(dir[i] < 0) { + quadrant[i] = RIGHT; + candPlane[i] = mStart[i]; + } else { + quadrant[i] = MIDDLE; + } + } + } + + + /* get t distances to planes */ + /* treat too small direction components as paralell */ + for(int i=0;i getVecEpsilon()) ) { + maxT[i] = (candPlane[i] - origin[i]) / dir[i]; + } else { + maxT[i] = GFX_REAL_MAX; + } + } + + /* largest max t */ + whichPlane = 0; + for(int i=1;i maxT[i]) whichPlane = i; + } + + /* check final candidate */ + hit = true; + if(maxT[whichPlane] != GFX_REAL_MAX) { + + for(int i=0;i mEnd[i] +getVecEpsilon() ) ) { + /* no hit... */ + hit = false; + } + } + else { + coord[i] = candPlane[i]; + } + } + + /* AABB hit... */ + if( hit ) { + t = maxT[whichPlane]; + + if(quadrant[whichPlane]==RIGHT) normal[whichPlane] = 1.0; + else normal[whichPlane] = -1.0; + } + } + + + if(t == GFX_REAL_MAX) t = -1.0; + retnormal = normal; + retcoord = coord; +} +#endif // ELBEEM_PLUGIN + +//! intersect ray with AABB +void ntlRay::intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const +{ + char inside = true; /* inside box? */ + char hit = false; /* ray hits box? */ + int whichPlane; /* intersection plane */ + gfxReal candPlane[NUMDIM]; /* candidate plane */ + gfxReal quadrant[NUMDIM]; /* quadrants */ + gfxReal maxT[NUMDIM]; /* max intersection T for planes */ + ntlVec3Gfx coord; /* intersection point */ + ntlVec3Gfx dir = mDirection; + ntlVec3Gfx origin = mOrigin; + gfxReal t = GFX_REAL_MAX; + + /* check intersection planes for AABB */ + for(int i=0;i mEnd[i]) { + quadrant[i] = RIGHT; + candPlane[i] = mEnd[i]; + inside = false; + } else { + /* intersect with backside */ + if(dir[i] > 0) { + quadrant[i] = LEFT; + candPlane [i] = mStart[i]; + } else + if(dir[i] < 0) { + quadrant[i] = RIGHT; + candPlane[i] = mEnd[i]; + } else { + quadrant[i] = MIDDLE; + } + } + } + + /* get t distances to planes */ + for(int i=0;i getVecEpsilon()) ) { + maxT[i] = (candPlane[i] - origin[i]) / dir[i]; + } else { + maxT[i] = GFX_REAL_MAX; + } + } + + /* largest max t */ + whichPlane = 0; + for(int i=1;i mEnd[i] +getVecEpsilon() ) ) { + /* no hit... */ + hit = false; + } + } + else { coord[i] = candPlane[i]; } + } + + /* AABB hit... */ + if( hit ) { + t = maxT[whichPlane]; + } + } + tmin = t; + + /* now the backside */ + t = GFX_REAL_MAX; + for(int i=0;i mEnd[i]) { + quadrant[i] = RIGHT; + candPlane[i] = mStart[i]; + } else { + if(dir[i] > 0) { + quadrant[i] = LEFT; + candPlane [i] = mEnd[i]; + } else + if(dir[i] < 0) { + quadrant[i] = RIGHT; + candPlane[i] = mStart[i]; + } else { + quadrant[i] = MIDDLE; + } + } + } + + + /* get t distances to planes */ + for(int i=0;i getVecEpsilon()) ) { + maxT[i] = (candPlane[i] - origin[i]) / dir[i]; + } else { + maxT[i] = GFX_REAL_MAX; + } + } + + /* smallest max t */ + whichPlane = 0; + for(int i=1;i maxT[i]) whichPlane = i; + } + + /* check final candidate */ + hit = true; + if(maxT[whichPlane] != GFX_REAL_MAX) { + + for(int i=0;i mEnd[i] +getVecEpsilon() ) ) { + /* no hit... */ + hit = false; + } + } + else { + coord[i] = candPlane[i]; + } + } + + /* AABB hit... */ + if( hit ) { + t = maxT[whichPlane]; + } + } + + tmax = t; +} + + + +/****************************************************************************** + * Determine color of this ray by tracing through the scene + *****************************************************************************/ +const ntlColor ntlRay::shade() //const +{ +#ifndef ELBEEM_PLUGIN + ntlGeometryObject *closest = NULL; + gfxReal minT = GFX_REAL_MAX; + vector *lightlist = mpGlob->getLightList(); + mpGlob->setCounterShades( mpGlob->getCounterShades()+1 ); + bool intersectionInside = 0; + if(mpGlob->getDebugOut() > 5) errorOut(std::endl<<"New Ray: depth "<getRenderScene()->intersectScene(*this, minT, normal, tri, 0); + if(minT>0) { + closest = mpGlob->getRenderScene()->getObject( tri->getObjectId() ); + } + + /* object hit... */ + if (closest != NULL) { + + ntlVec3Gfx triangleNormal = tri->getNormal(); + if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) errorOut("ntlRay warning: trinagle normal= 0 "); // DEBUG + /* intersection on inside faces? if yes invert normal afterwards */ + gfxReal valDN; // = mDirection | normal; + valDN = dot(mDirection, triangleNormal); + if( valDN > 0.0) { + intersectionInside = 1; + normal = normal * -1.0; + triangleNormal = triangleNormal * -1.0; + } + + /* ... -> do reflection */ + ntlVec3Gfx intersectionPosition(mOrigin + (mDirection * (minT)) ); + ntlMaterial *clossurf = closest->getMaterial(); + /*if(mpGlob->getDebugOut() > 5) { + errorOut("Ray hit: at "<getRenderScene()->getVertex(tri->getPoints()[0])<<" t2:"<getRenderScene()->getVertex(tri->getPoints()[1])<<" t3:"<getScene()->getVertex(tri->getPoints()[2]) ); + errorOut(" trin:"<getNormal() ); + } // debug */ + + /* current transparence and reflectivity */ + gfxReal currTrans = clossurf->getTransparence(); + gfxReal currRefl = clossurf->getMirror(); + + /* correct intersectopm position */ + intersectionPosition += ( triangleNormal*getVecEpsilon() ); + /* reflection at normal */ + ntlVec3Gfx reflectedDir = getNormalized( reflectVector(mDirection, normal) ); + int badRefl = 0; + if(dot(reflectedDir, triangleNormal)<0.0 ) { + badRefl = 1; + if(mpGlob->getDebugOut() > 5) { errorOut("Ray Bad reflection...!"); } + } + + /* refraction direction, depending on in/outside hit */ + ntlVec3Gfx refractedDir; + int refRefl = 0; + /* refraction at normal is handled by inverting normal before */ + gfxReal myRefIndex = 1.0; + if((currTrans>RAY_THRESHOLD)||(clossurf->getFresnel())) { + if(intersectionInside) { + myRefIndex = 1.0/clossurf->getRefracIndex(); + } else { + myRefIndex = clossurf->getRefracIndex(); + } + + refractedDir = refractVector(mDirection, normal, myRefIndex , (gfxReal)(1.0) /* global ref index */, refRefl); + } + + /* calculate fresnel? */ + if(clossurf->getFresnel()) { + // for total reflection, just set trans to 0 + if(refRefl) { + currRefl = 1.0; currTrans = 0.0; + } else { + // calculate fresnel coefficients + clossurf->calculateFresnel( mDirection, normal, myRefIndex, currRefl,currTrans ); + } + } + + ntlRay reflectedRay(intersectionPosition, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob); + reflectedRay.setNormal( normal ); + ntlColor currentColor(0.0); + ntlColor highlightColor(0.0); + + /* first add reflected ambient color */ + currentColor += (clossurf->getAmbientRefl() * mpGlob->getAmbientLight() ); + + /* calculate lighting, not on the insides of objects... */ + if(!intersectionInside) { + for (vector::iterator iter = lightlist->begin(); + iter != lightlist->end(); + iter++) { + + /* let light illuminate point */ + currentColor += (*iter)->illuminatePoint( reflectedRay, closest, highlightColor ); + + } // for all lights + } + + // recurse ? + if ((mDepth < mpGlob->getRayMaxDepth() )&&(currRefl>RAY_THRESHOLD)) { + + if(badRefl) { + ntlVec3Gfx intersectionPosition2; + ntlGeometryObject *closest2 = NULL; + gfxReal minT2 = GFX_REAL_MAX; + ntlTriangle *tri2 = NULL; + ntlVec3Gfx normal2; + + ntlVec3Gfx refractionPosition2(mOrigin + (mDirection * minT) ); + refractionPosition2 -= (triangleNormal*getVecEpsilon() ); + + ntlRay reflectedRay2 = ntlRay(refractionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob); + mpGlob->getRenderScene()->intersectScene(reflectedRay2, minT2, normal2, tri2, 0); + if(minT2>0) { + closest2 = mpGlob->getRenderScene()->getObject( tri2->getObjectId() ); + } + + /* object hit... */ + if (closest2 != NULL) { + ntlVec3Gfx triangleNormal2 = tri2->getNormal(); + gfxReal valDN2; + valDN2 = dot(reflectedDir, triangleNormal2); + if( valDN2 > 0.0) { + triangleNormal2 = triangleNormal2 * -1.0; + intersectionPosition2 = ntlVec3Gfx(intersectionPosition + (reflectedDir * (minT2)) ); + /* correct intersection position and create new reflected ray */ + intersectionPosition2 += ( triangleNormal2*getVecEpsilon() ); + reflectedRay = ntlRay(intersectionPosition2, reflectedDir, mDepth+1, mContribution*currRefl, mpGlob); + } else { + // ray seems to work, continue normally ? + } + + } + + } + + // add mirror color multiplied by mirror factor of surface + if(mpGlob->getDebugOut() > 5) errorOut("Reflected ray from depth "< RAY_THRESHOLD) { + /* position at the other side of the surface, along ray */ + ntlVec3Gfx refraction_position(mOrigin + (mDirection * minT) ); + refraction_position += (mDirection * getVecEpsilon()); + refraction_position -= (triangleNormal*getVecEpsilon() ); + ntlColor refracCol(0.0); /* refracted color */ + + /* trace refracted ray */ + ntlRay transRay(refraction_position, refractedDir, mDepth+1, mContribution*currTrans, mpGlob); + transRay.setRefracted(1); + transRay.setNormal( normal ); + if(mDepth < mpGlob->getRayMaxDepth() ) { + // full reflection should make sure refracindex&fresnel are on... + if((0)||(!refRefl)) { + if(mpGlob->getDebugOut() > 5) errorOut("Refracted ray from depth "<getDebugOut() > 5) errorOut("Fully reflected ray from depth "<getTransAttCol(); + kr = exp( attCol[0] * minT ); + kg = exp( attCol[1] * minT ); + kb = exp( attCol[2] * minT ); + currentColor = currentColor * ntlColor(kr,kg,kb); + } + + /* done... */ + if(mpGlob->getDebugOut() > 5) { errorOut("Ray "< ray goes to infinity */ + return mpGlob->getBackgroundCol(); +} + + + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + * scene implementation + ****************************************************************************** + ****************************************************************************** + *****************************************************************************/ + + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +ntlScene::ntlScene( ntlRenderGlobals *glob, bool del ) : + mpGlob( glob ), mSceneDel(del), + mpTree( NULL ), + mDisplayListId( -1 ), + mSceneBuilt( false ), mFirstInitDone( false ) +{ +} + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlScene::~ntlScene() +{ + if(mpTree != NULL) delete mpTree; + + // cleanup lists, only if this is the rendering cleanup scene + if(mSceneDel) { + for (vector::iterator iter = mGeos.begin(); + iter != mGeos.end(); iter++) { + //errMsg("ntlScene::~ntlScene","Deleting obj "<<(*iter)->getName() ); + delete (*iter); + } + for (vector::iterator iter = mpGlob->getLightList()->begin(); + iter != mpGlob->getLightList()->end(); iter++) { + delete (*iter); + } + for (vector::iterator iter = mpGlob->getMaterials()->begin(); + iter != mpGlob->getMaterials()->end(); iter++) { + delete (*iter); + } + } + errMsg("ntlScene::~ntlScene","Deleted, ObjFree:"<::iterator iter = mGeos.begin(); + iter != mGeos.end(); iter++) { + bool geoinit = false; + int tid = (*iter)->getTypeId(); + if(tid & GEOCLASSTID_OBJECT) { + ntlGeometryObject *geoobj = (ntlGeometryObject*)(*iter); + geoinit = true; + mObjects.push_back( geoobj ); + if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added GeoObj "<getName()<<" Id:"<getObjectId(), 5 ); + } + //if(geoshad) { + if(tid & GEOCLASSTID_SHADER) { + ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); + geoinit = true; + if(!mFirstInitDone) { + // only on first init + geoshad->initializeShader(); + } + for (vector::iterator siter = geoshad->getObjectsBegin(); + siter != geoshad->getObjectsEnd(); + siter++) { + if(buildInfo) debMsgStd("ntlScene::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName()<<" Id:"<<(*siter)->getObjectId(), 5 ); + mObjects.push_back( (*siter) ); + } + } + + if(!geoinit) { + errFatal("ntlScene::BuildScene","Invalid geometry class!", SIMWORLD_INITERROR); + return; + } + } + } + + // collect triangles + mTriangles.clear(); + mVertices.clear(); + mVertNormals.clear(); + + /* for test mode deactivate transparencies etc. */ + if( mpGlob->getTestMode() ) { + debugOut("ntlScene::buildScene : Test Mode activated!", 2); + // assign random colors to dark materials + int matCounter = 0; + ntlColor stdCols[] = { ntlColor(0,0,1.0), ntlColor(0,1.0,0), ntlColor(1.0,0.7,0) , ntlColor(0.7,0,0.6) }; + int stdColNum = 4; + for (vector::iterator iter = mpGlob->getMaterials()->begin(); + iter != mpGlob->getMaterials()->end(); iter++) { + (*iter)->setTransparence(0.0); + (*iter)->setMirror(0.0); + (*iter)->setFresnel(false); + // too dark? + if( norm((*iter)->getDiffuseRefl()) <0.01) { + (*iter)->setDiffuseRefl( stdCols[matCounter] ); + matCounter ++; + matCounter = matCounter%stdColNum; + } + } + + // restrict output file size to 400 + float downscale = 1.0; + if(mpGlob->getResX() > 400){ downscale = 400.0/(float)mpGlob->getResX(); } + if(mpGlob->getResY() > 400){ + float downscale2 = 400.0/(float)mpGlob->getResY(); + if(downscale2setResX( (int)(mpGlob->getResX() * downscale) ); + mpGlob->setResY( (int)(mpGlob->getResY() * downscale) ); + + } + + /* collect triangles from objects */ + int idCnt = 0; // give IDs to objects + bool debugTriCollect = false; + if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Start...",5); + for (vector::iterator iter = mObjects.begin(); + iter != mObjects.end(); + iter++) { + /* only add visible objects */ + if(firstInit) { + if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collect init of "<<(*iter)->getName()<<" idCnt:"<initialize( mpGlob ); } + if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Collecting tris from "<<(*iter)->getName(), 4 ); + + int vstart = mVertNormals.size(); + (*iter)->setObjectId(idCnt); + (*iter)->getTriangles(time, &mTriangles, &mVertices, &mVertNormals, idCnt); + (*iter)->applyTransformation(time, &mVertices, &mVertNormals, vstart, mVertices.size(), false ); + + if(debugTriCollect) debMsgStd("ntlScene::buildScene",DM_MSG,"Done with "<<(*iter)->getName()<<" totTris:"<::iterator iter = mTriangles.begin(); + iter != mTriangles.end(); + iter++) { + + // calculate normal from triangle points + ntlVec3Gfx normal = + cross( (ntlVec3Gfx)( (mVertices[(*iter).getPoints()[2]] - mVertices[(*iter).getPoints()[0]]) *-1.0), // BLITZ minus sign right?? + (ntlVec3Gfx)(mVertices[(*iter).getPoints()[1]] - mVertices[(*iter).getPoints()[0]]) ); + normalize(normal); + (*iter).setNormal( normal ); + } + + + + // scene geometry built + mSceneBuilt = true; + + // init shaders that require complete geometry + if(!mFirstInitDone) { + // only on first init + for (vector::iterator iter = mGeos.begin(); + iter != mGeos.end(); iter++) { + if( (*iter)->getTypeId() & GEOCLASSTID_SHADER ) { + ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); + if(geoshad->postGeoConstrInit( mpGlob )) { + errFatal("ntlScene::buildScene","Init failed for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR ); + return; + } + } + } + mFirstInitDone = true; + } + + // check unused attributes (for classes and objects!) + for (vector::iterator iter = mObjects.begin(); iter != mObjects.end(); iter++) { + if((*iter)->getAttributeList()->checkUnusedParams()) { + (*iter)->getAttributeList()->print(); // DEBUG + errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR ); + return; + } + } + for (vector::iterator iter = mGeos.begin(); iter != mGeos.end(); iter++) { + if((*iter)->getAttributeList()->checkUnusedParams()) { + (*iter)->getAttributeList()->print(); // DEBUG + errFatal("ntlScene::buildScene","Unused params for object '"<< (*iter)->getName() <<"' !", SIMWORLD_INITERROR ); + return; + } + } + +} + +/****************************************************************************** + * Prepare the scene triangles and maps for raytracing + *****************************************************************************/ +void ntlScene::prepareScene(double time) +{ + /* init triangles... */ + buildScene(time, false); + // what for currently not used ??? + if(mpTree != NULL) delete mpTree; + mpTree = new ntlTree( +# if FSGR_STRICT_DEBUG!=1 + mpGlob->getTreeMaxDepth(), mpGlob->getTreeMaxTriangles(), +# else + mpGlob->getTreeMaxDepth()/3*2, mpGlob->getTreeMaxTriangles()*2, +# endif + this, TRI_GEOMETRY ); + + //debMsgStd("ntlScene::prepareScene",DM_MSG,"Stats - tris:"<< (int)mTriangles.size()<<" verts:"<setCounterSceneInter( mpGlob->getCounterSceneInter()+1 ); + mpTree->intersect(r, distance, normal, tri, flags, false); +} + + + + + diff --git a/intern/elbeem/intern/ntl_ray.h b/intern/elbeem/intern/ntl_ray.h new file mode 100644 index 00000000000..096d5fd61d3 --- /dev/null +++ b/intern/elbeem/intern/ntl_ray.h @@ -0,0 +1,416 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * ray class + * + *****************************************************************************/ +#ifndef NTL_RAY_H +#define NTL_RAY_H + +#include +#include "ntl_vector3dim.h" +#include "ntl_lighting.h" +#include "ntl_geometryobject.h" +#include "ntl_bsptree.h" + +class ntlTriangle; +class ntlRay; +class ntlTree; +class ntlScene; +class ntlRenderGlobals; + +//! store data for an intersection of a ray and a triangle +// NOT YET USED +class ntlIntersection { + public: + + ntlIntersection() : + distance(-1.0), normal(0.0), + ray(NULL), tri(NULL), flags(0) { }; + + gfxReal distance; + ntlVec3Gfx normal; + ntlRay *ray; + ntlTriangle *tri; + char flags; +}; + +//! the main ray class +class ntlRay +{ +public: + // CONSTRUCTORS + //! Initialize ray memebers, prints error message + ntlRay(); + //! Copy constructor, copy all members + ntlRay(const ntlRay &r); + //! Explicitly init member variables with global render object + ntlRay(const ntlVec3Gfx &o, const ntlVec3Gfx &d, unsigned int i, gfxReal contrib, ntlRenderGlobals *glob); + //! Destructor + ~ntlRay(); + + //! Set the refraction flag for refracted rays + inline void setRefracted(unsigned char set) { mIsRefracted = set; } + inline void setReflected(unsigned char set) { mIsReflected = set; } + + //! main ray recursion function + /*! + * First get closest object intersection, return background color if nothing + * was hit, else calculate shading and reflection components + * and return mixed color */ + const ntlColor shade() /*const*/; + + /*! Trace a photon through the scene */ + void tracePhoton(ntlColor) const; + + //! intersect ray with AABB + void intersectFrontAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const; + void intersectBackAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &t, ntlVec3Gfx &normal, ntlVec3Gfx &retcoord) const; + void intersectCompleteAABB(ntlVec3Gfx mStart, ntlVec3Gfx mEnd, gfxReal &tmin, gfxReal &tmax) const; + // intersection routines in bsptree.cpp + //! optimized intersect ray with triangle + inline void intersectTriangle(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const; + //! optimized intersect ray with triangle along +X axis dir + inline void intersectTriangleX(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const; + //! intersect only with front side + inline void intersectTriangleFront(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const; + //! intersect ray only with backsides + inline void intersectTriangleBack(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v) const; + + // access methods + //! Returns the ray origin + inline ntlVec3Gfx getOrigin() const { return ntlVec3Gfx(mOrigin); } + //! Returns the ray direction + inline ntlVec3Gfx getDirection() const { return ntlVec3Gfx(mDirection); } + /*! Returns the ray relfection normal */ + inline ntlVec3Gfx getNormal() const { return ntlVec3Gfx(mvNormal); } + //! Is this ray refracted? + inline unsigned char getRefracted() const { return mIsRefracted; } + inline unsigned char getReflected() const { return mIsReflected; } + /*! Get position along ray */ + inline ntlVec3Gfx getPositionAt(gfxReal t) const { return (mOrigin+(mDirection*t)); } + /*! Get render globals pointer of this ray */ + inline ntlRenderGlobals *getRenderglobals( void ) const { return mpGlob; } + /*! get this ray's ID */ + inline int getID( void ) const { return mID; } + + /*! Set origin of this ray */ + inline void setOrigin(ntlVec3Gfx set) { mOrigin = set; } + /*! Set direction of this ray */ + inline void setDirection(ntlVec3Gfx set) { mDirection = set; } + /*! Set normal of this ray */ + inline void setNormal(ntlVec3Gfx set) { mvNormal = set; } + +protected: + /* Calulates the Lambertian and Specular color for + * the given reflection and returns it */ + const ntlColor getShadedColor(ntlLightObject *light, const ntlRay &reflectedray, + const ntlVec3Gfx &normal, ntlMaterial *surf) const; + +private: + /*! Origin of ray */ + ntlVec3Gfx mOrigin; + /*! Normalized direction vector of ray */ + ntlVec3Gfx mDirection; + /*! For reflected/refracted rays, the normal is stored here */ + ntlVec3Gfx mvNormal; + /*! recursion depth */ + unsigned int mDepth; + /*! How much does this ray contribute to the surface color? abort if too small */ + gfxReal mContribution; + + /*! Global rendering settings */ + ntlRenderGlobals *mpGlob; + + /*! If this ray is a refracted one, this flag has to be set + * This is necessary to for example also give the background color + * to refracted rays. Otherwise things may look strange... + */ + unsigned char mIsRefracted; + unsigned char mIsReflected; + + /*! ID of this ray (from renderglobals */ + int mID; + +}; + + +/****************************************************************************** + * + * a single triangle + * + *****************************************************************************/ + +// triangle intersection code in bsptree.cpp +// intersectTriangle(vector *mpV, ntlTriangle *tri, gfxReal &t, gfxReal &u, gfxReal &v); + +/*! Triangle flag defines */ +#define TRI_GEOMETRY (1<<0) +#define TRI_CASTSHADOWS (1<<1) + + +class ntlTriangle +{ +public: + /* CONSTRUCTORS */ + /*! Default constructor */ + inline ntlTriangle( void ); + /*! Constructor with parameters */ + inline ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags); + /*! Copy - Constructor */ + inline ntlTriangle(const ntlTriangle &tri); + /*! Destructor */ + inline ~ntlTriangle() {} + + /* Access methods */ + + /*! Acces to points of triangle */ + inline int *getPoints( void ) { return mPoints; } + /*! Acces normal smoothing */ + inline bool getSmoothNormals( void ) const { return mSmoothNormals; } + inline void setSmoothNormals( bool set){ mSmoothNormals = set; } + /*! Access object */ + inline int getObjectId( void ) const { return mObjectId; } + inline void setObjectId( int set) { mObjectId = set; } + /*! Acces normal index */ + inline ntlVec3Gfx getNormal( void ) const { return mNormal; } + inline void setNormal( ntlVec3Gfx set ) { mNormal = set; } + /*! Acces flags */ + inline int getFlags( void ) const { return mFlags; } + inline void setFlags( int set ) { mFlags = set; } + /*! Access last intersection ray ID */ + inline int getLastRay( void ) const { return mLastRay; } + inline void setLastRay( int set ) { mLastRay = set; } + /*! Acces bbox id */ + inline int getBBoxId( void ) const { return mBBoxId; } + inline void setBBoxId( int set ) { mBBoxId = set; } + + /*! Get average of the three points for this axis */ + inline gfxReal getAverage( int axis ) const; + + /*! operator < for sorting, uses global sorting axis */ + inline friend bool operator<(const ntlTriangle &lhs, const ntlTriangle &rhs); + /*! operator > for sorting, uses global sorting axis */ + inline friend bool operator>(const ntlTriangle &lhs, const ntlTriangle &rhs); + +protected: + +private: + + /*! indices to the three points of the triangle */ + int mPoints[3]; + + /*! bounding box id (for tree generation), -1 if invalid */ + int mBBoxId; + + /*! Should the normals of this triangle get smoothed? */ + bool mSmoothNormals; + + /*! Id of parent object */ + int mObjectId; + + /*! Index to normal (for not smooth triangles) */ + //int mNormalIndex; ?? + ntlVec3Gfx mNormal; + + /*! Flags for object attributes cast shadows */ + int mFlags; + + /*! ID of last ray that an intersection was calculated for */ + int mLastRay; + +}; + + + + +/****************************************************************************** + * Default Constructor + *****************************************************************************/ +ntlTriangle::ntlTriangle( void ) : + mBBoxId(-1), + mLastRay( 0 ) +{ + mPoints[0] = mPoints[1] = mPoints[2] = 0; + mSmoothNormals = 0; + mObjectId = 0; + mNormal = ntlVec3Gfx(0.0); + mFlags = 0; +} + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +ntlTriangle::ntlTriangle(int *p, bool smooth, int obj, ntlVec3Gfx norm, int setflags) : + mBBoxId(-1), + mLastRay( 0 ) +{ + mPoints[0] = p[0]; + mPoints[1] = p[1]; + mPoints[2] = p[2]; + mSmoothNormals = smooth; + mObjectId = obj; + mNormal = norm; + mFlags = setflags; +} + + +/****************************************************************************** + * Copy Constructor + *****************************************************************************/ +ntlTriangle::ntlTriangle(const ntlTriangle &tri) : + mBBoxId(-1), + mLastRay( 0 ) +{ + mPoints[0] = tri.mPoints[0]; + mPoints[1] = tri.mPoints[1]; + mPoints[2] = tri.mPoints[2]; + mSmoothNormals = tri.mSmoothNormals; + mObjectId = tri.mObjectId; + mNormal = tri.mNormal; + mFlags = tri.mFlags; +} + + + + +/****************************************************************************** + * Triangle sorting functions + *****************************************************************************/ + +/* variables imported from ntl_bsptree.cc, necessary for using the stl sort funtion */ +/* Static global variable for sorting direction */ +extern int globalSortingAxis; +/* Access to points array for sorting */ +extern vector *globalSortingPoints; + + +gfxReal ntlTriangle::getAverage( int axis ) const +{ + return ( ( (*globalSortingPoints)[ mPoints[0] ][axis] + + (*globalSortingPoints)[ mPoints[1] ][axis] + + (*globalSortingPoints)[ mPoints[2] ][axis] )/3.0); +} + +bool operator<(const ntlTriangle &lhs,const ntlTriangle &rhs) +{ + return ( lhs.getAverage(globalSortingAxis) < + rhs.getAverage(globalSortingAxis) ); +} + +bool operator>(const ntlTriangle &lhs,const ntlTriangle &rhs) +{ + return ( lhs.getAverage(globalSortingAxis) > + rhs.getAverage(globalSortingAxis) ); +} + + + +/****************************************************************************** + * + * Scene object, that contains and manages all geometry objects + * + *****************************************************************************/ + + + +class ntlScene +{ +public: + /* CONSTRUCTORS */ + /*! Default constructor */ + ntlScene( ntlRenderGlobals *glob, bool del=true ); + /*! Default destructor */ + ~ntlScene(); + + /*! Add an object to the scene */ + inline void addGeoClass(ntlGeometryClass *geo) { + mGeos.push_back( geo ); + geo->setObjectId(mGeos.size()); + } + /*! Add a geo object to the scene, warning - only needed for hand init */ + inline void addGeoObject(ntlGeometryObject *geo) { mObjects.push_back( geo ); } + + /*! Acces a certain object */ + inline ntlGeometryObject *getObject(int id) { + if(!mSceneBuilt) { errFatal("ntlScene::getObject","Scene not inited!", SIMWORLD_INITERROR); } + return mObjects[id]; } + + /*! Acces object array */ + inline vector *getObjects() { + if(!mSceneBuilt) { errFatal("ntlScene::getObjects[]","Scene not inited!", SIMWORLD_INITERROR); } + return &mObjects; } + + /*! Acces geo class array */ + inline vector *getGeoClasses() { + if(!mSceneBuilt) { errFatal("ntlScene::getGeoClasses[]","Scene not inited!", SIMWORLD_INITERROR); } + return &mGeos; } + + /*! draw scene with opengl */ + //void draw(); + + /*! Build/first init the scene arrays */ + void buildScene(double time, bool firstInit); + + //! Prepare the scene triangles and maps for raytracing + void prepareScene(double time); + //! Do some memory cleaning, when frame is finished + void cleanupScene( void ); + + /*! Intersect a ray with the scene triangles */ + void intersectScene(const ntlRay &r, gfxReal &distance, ntlVec3Gfx &normal, ntlTriangle *&tri, int flags) const; + + /*! return a vertex */ + ntlVec3Gfx getVertex(int index) { return mVertices[index]; } + + // for tree generation + /*! return pointer to vertices vector */ + vector *getVertexPointer( void ) { return &mVertices; } + /*! return pointer to vertices vector */ + vector *getVertexNormalPointer( void ) { return &mVertNormals; } + /*! return pointer to vertices vector */ + vector *getTrianglePointer( void ) { return &mTriangles; } + +private: + + /*! Global settings */ + ntlRenderGlobals *mpGlob; + + /*! free objects? (only necessary for render scene, which contains all) */ + bool mSceneDel; + + /*! List of geometry classes */ + vector mGeos; + + /*! List of geometry objects */ + vector mObjects; + + /*! List of triangles */ + vector mTriangles; + /*! List of vertices */ + vector mVertices; + /*! List of normals */ + vector mVertNormals; + /*! List of triangle normals */ + vector mTriangleNormals; + + /*! Tree to store quickly intersect triangles */ + ntlTree *mpTree; + + /*! id of dislpay list for raytracer stuff */ + int mDisplayListId; + + /*! was the scene successfully built? only then getObject(i) requests are valid */ + bool mSceneBuilt; + + /*! shader/obj initializations are only done on first init */ + bool mFirstInitDone; + +}; + + +#endif + diff --git a/intern/elbeem/intern/ntl_vector3dim.h b/intern/elbeem/intern/ntl_vector3dim.h new file mode 100644 index 00000000000..912a37350c1 --- /dev/null +++ b/intern/elbeem/intern/ntl_vector3dim.h @@ -0,0 +1,1081 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Basic vector class used everywhere, either blitz or inlined GRAPA class + * + *****************************************************************************/ +#ifndef NTL_VECTOR3DIM_H +#define NTL_VECTOR3DIM_H + +// this serves as the main include file +// for all kinds of stuff that might be required +// under windos there seem to be strange +// errors when including the STL header too +// late... +#include +#include +#include +#include +#include +#include +#include +#include + +// hack for MSVC6.0 compiler +#ifdef _MSC_VER +#if _MSC_VER < 1300 +#define for if(false); else for +#define map std::map +#define vector std::vector +#define string std::string +// use this define for MSVC6 stuff hereafter +#define USE_MSVC6FIXES +#else // _MSC_VER < 1300 , 7.0 or higher +using std::map; +using std::vector; +using std::string; +#endif +#else // not MSVC6 +// for proper compilers... +using std::map; +using std::vector; +using std::string; +#endif // MSVC6 + +#ifdef __APPLE_CC__ +// apple +#else +#ifdef WIN32 + +// windows values missing, see below +#ifndef snprintf +#define snprintf _snprintf +#endif +#ifndef bool +#define bool int +#endif +#ifndef false +#define false 0 +#endif +#ifndef true +#define true 1 +#endif + +#else // WIN32 + +// floating point limits for linux,*bsd etc... +#include + +#endif // WIN32 +#endif // __APPLE_CC__ + +// windos, hardcoded limits for now... +// for e.g. MSVC compiler... +// some of these defines can be needed +// for linux systems as well (e.g. FLT_MAX) +#ifndef __FLT_MAX__ +# ifdef FLT_MAX // try to use it instead +# define __FLT_MAX__ FLT_MAX +# else // FLT_MAX +# define __FLT_MAX__ 3.402823466e+38f +# endif // FLT_MAX +#endif // __FLT_MAX__ +#ifndef __DBL_MAX__ +# ifdef DBL_MAX // try to use it instead +# define __DBL_MAX__ DBL_MAX +# else // DBL_MAX +# define __DBL_MAX__ 1.7976931348623158e+308 +# endif // DBL_MAX +#endif // __DBL_MAX__ + +#ifndef M_PI +#define M_PI 3.1415926536 +#define M_E 2.7182818284 +#endif + +// make sure elbeem plugin def is valid +#if ELBEEM_BLENDER==1 +#ifndef ELBEEM_PLUGIN +#define ELBEEM_PLUGIN 1 +#endif // !ELBEEM_PLUGIN +#endif // ELBEEM_BLENDER==1 + +// make sure GUI support is disabled for plugin use +#if ELBEEM_PLUGIN==1 +#ifndef NOGUI +#define NOGUI 1 +#endif // !NOGUI +#endif // ELBEEM_PLUGIN==1 + + +// basic inlined vector class +template +class ntlVector3Dim +{ +public: + // Constructor + inline ntlVector3Dim(void ); + // Copy-Constructor + inline ntlVector3Dim(const ntlVector3Dim &v ); + inline ntlVector3Dim(const float *); + inline ntlVector3Dim(const double *); + // construct a vector from one Scalar + inline ntlVector3Dim(Scalar); + // construct a vector from three Scalars + inline ntlVector3Dim(Scalar, Scalar, Scalar); + + // get address of array for OpenGL + Scalar *getAddress() { return value; } + + // Assignment operator + inline const ntlVector3Dim& operator= (const ntlVector3Dim& v); + // Assignment operator + inline const ntlVector3Dim& operator= (Scalar s); + // Assign and add operator + inline const ntlVector3Dim& operator+= (const ntlVector3Dim& v); + // Assign and add operator + inline const ntlVector3Dim& operator+= (Scalar s); + // Assign and sub operator + inline const ntlVector3Dim& operator-= (const ntlVector3Dim& v); + // Assign and sub operator + inline const ntlVector3Dim& operator-= (Scalar s); + // Assign and mult operator + inline const ntlVector3Dim& operator*= (const ntlVector3Dim& v); + // Assign and mult operator + inline const ntlVector3Dim& operator*= (Scalar s); + // Assign and div operator + inline const ntlVector3Dim& operator/= (const ntlVector3Dim& v); + // Assign and div operator + inline const ntlVector3Dim& operator/= (Scalar s); + + + // unary operator + inline ntlVector3Dim operator- () const; + + // binary operator add + inline ntlVector3Dim operator+ (const ntlVector3Dim&) const; + // binary operator add + inline ntlVector3Dim operator+ (Scalar) const; + // binary operator sub + inline ntlVector3Dim operator- (const ntlVector3Dim&) const; + // binary operator sub + inline ntlVector3Dim operator- (Scalar) const; + // binary operator mult + inline ntlVector3Dim operator* (const ntlVector3Dim&) const; + // binary operator mult + inline ntlVector3Dim operator* (Scalar) const; + // binary operator div + inline ntlVector3Dim operator/ (const ntlVector3Dim&) const; + // binary operator div + inline ntlVector3Dim operator/ (Scalar) const; + + // Projection normal to a vector + inline ntlVector3Dim getOrthogonalntlVector3Dim() const; + // Project into a plane + inline const ntlVector3Dim& projectNormalTo(const ntlVector3Dim &v); + + // minimize + inline const ntlVector3Dim &minimize(const ntlVector3Dim &); + // maximize + inline const ntlVector3Dim &maximize(const ntlVector3Dim &); + + // access operator + inline Scalar& operator[](unsigned int i); + // access operator + inline const Scalar& operator[](unsigned int i) const; + +protected: + +private: + Scalar value[3]; //< Storage of vector values +}; + + + + +//------------------------------------------------------------------------------ +// STREAM FUNCTIONS +//------------------------------------------------------------------------------ + + + +//! global string for formatting vector output in utilities.cpp +extern const char *globVecFormatStr; + +/************************************************************************* + Outputs the object in human readable form using the format + [x,y,z] + */ +template +std::ostream& +operator<<( std::ostream& os, const ntlVector3Dim& i ) +{ + char buf[256]; + snprintf(buf,256,globVecFormatStr,i[0],i[1],i[2]); + os << string(buf); + //os << '[' << i[0] << ", " << i[1] << ", " << i[2] << ']'; + return os; +} + + + +/************************************************************************* + Reads the contents of the object from a stream using the same format + as the output operator. + */ +template +std::istream& +operator>>( std::istream& is, ntlVector3Dim& i ) +{ + char c; + char dummy[3]; + is >> c >> i[0] >> dummy >> i[1] >> dummy >> i[2] >> c; + return is; +} + + +//------------------------------------------------------------------------------ +// VECTOR inline FUNCTIONS +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Constructor. + */ +template +inline ntlVector3Dim::ntlVector3Dim( void ) +{ + value[0] = value[1] = value[2] = 0; +} + + + +/************************************************************************* + Copy-Constructor. + */ +template +inline ntlVector3Dim::ntlVector3Dim( const ntlVector3Dim &v ) +{ + value[0] = v.value[0]; + value[1] = v.value[1]; + value[2] = v.value[2]; +} +template +inline ntlVector3Dim::ntlVector3Dim( const float *fvalue) +{ + value[0] = (Scalar)fvalue[0]; + value[1] = (Scalar)fvalue[1]; + value[2] = (Scalar)fvalue[2]; +} +template +inline ntlVector3Dim::ntlVector3Dim( const double *fvalue) +{ + value[0] = (Scalar)fvalue[0]; + value[1] = (Scalar)fvalue[1]; + value[2] = (Scalar)fvalue[2]; +} + + + +/************************************************************************* + Constructor for a vector from a single Scalar. All components of + the vector get the same value. + \param s The value to set + \return The new vector + */ +template +inline ntlVector3Dim::ntlVector3Dim(Scalar s ) +{ + value[0]= s; + value[1]= s; + value[2]= s; +} + + +/************************************************************************* + Constructor for a vector from three Scalars. + \param s1 The value for the first vector component + \param s2 The value for the second vector component + \param s3 The value for the third vector component + \return The new vector + */ +template +inline ntlVector3Dim::ntlVector3Dim(Scalar s1, Scalar s2, Scalar s3) +{ + value[0]= s1; + value[1]= s2; + value[2]= s3; +} + + +/************************************************************************* + Compute the vector product of two 3D vectors + \param v Second vector to compute the product with + \return A new vector with the product values + */ +/*template +inline ntlVector3Dim +ntlVector3Dim::operator^( const ntlVector3Dim &v ) const +{ + return ntlVector3Dim(value[1]*v.value[2] - value[2]*v.value[1], + value[2]*v.value[0] - value[0]*v.value[2], + value[0]*v.value[1] - value[1]*v.value[0]); +}*/ + + +/************************************************************************* + Copy a ntlVector3Dim componentwise. + \param v vector with values to be copied + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator=( const ntlVector3Dim &v ) +{ + value[0] = v.value[0]; + value[1] = v.value[1]; + value[2] = v.value[2]; + return *this; +} + + +/************************************************************************* + Copy a Scalar to each component. + \param s The value to copy + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator=(Scalar s) +{ + value[0] = s; + value[1] = s; + value[2] = s; + return *this; +} + + +/************************************************************************* + Add another ntlVector3Dim componentwise. + \param v vector with values to be added + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator+=( const ntlVector3Dim &v ) +{ + value[0] += v.value[0]; + value[1] += v.value[1]; + value[2] += v.value[2]; + return *this; +} + + +/************************************************************************* + Add a Scalar value to each component. + \param s Value to add + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator+=(Scalar s) +{ + value[0] += s; + value[1] += s; + value[2] += s; + return *this; +} + + +/************************************************************************* + Subtract another vector componentwise. + \param v vector of values to subtract + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator-=( const ntlVector3Dim &v ) +{ + value[0] -= v.value[0]; + value[1] -= v.value[1]; + value[2] -= v.value[2]; + return *this; +} + + +/************************************************************************* + Subtract a Scalar value from each component. + \param s Value to subtract + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator-=(Scalar s) +{ + value[0]-= s; + value[1]-= s; + value[2]-= s; + return *this; +} + + +/************************************************************************* + Multiply with another vector componentwise. + \param v vector of values to multiply with + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator*=( const ntlVector3Dim &v ) +{ + value[0] *= v.value[0]; + value[1] *= v.value[1]; + value[2] *= v.value[2]; + return *this; +} + + +/************************************************************************* + Multiply each component with a Scalar value. + \param s Value to multiply with + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator*=(Scalar s) +{ + value[0] *= s; + value[1] *= s; + value[2] *= s; + return *this; +} + + +/************************************************************************* + Divide by another ntlVector3Dim componentwise. + \param v vector of values to divide by + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator/=( const ntlVector3Dim &v ) +{ + value[0] /= v.value[0]; + value[1] /= v.value[1]; + value[2] /= v.value[2]; + return *this; +} + + +/************************************************************************* + Divide each component by a Scalar value. + \param s Value to divide by + \return Reference to self + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::operator/=(Scalar s) +{ + value[0] /= s; + value[1] /= s; + value[2] /= s; + return *this; +} + + +//------------------------------------------------------------------------------ +// unary operators +//------------------------------------------------------------------------------ + + +/************************************************************************* + Build componentwise the negative this vector. + \return The new (negative) vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator-() const +{ + return ntlVector3Dim(-value[0], -value[1], -value[2]); +} + + + +//------------------------------------------------------------------------------ +// binary operators +//------------------------------------------------------------------------------ + + +/************************************************************************* + Build a vector with another vector added componentwise. + \param v The second vector to add + \return The sum vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator+( const ntlVector3Dim &v ) const +{ + return ntlVector3Dim(value[0]+v.value[0], + value[1]+v.value[1], + value[2]+v.value[2]); +} + + +/************************************************************************* + Build a vector with a Scalar value added to each component. + \param s The Scalar value to add + \return The sum vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator+(Scalar s) const +{ + return ntlVector3Dim(value[0]+s, + value[1]+s, + value[2]+s); +} + + +/************************************************************************* + Build a vector with another vector subtracted componentwise. + \param v The second vector to subtract + \return The difference vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator-( const ntlVector3Dim &v ) const +{ + return ntlVector3Dim(value[0]-v.value[0], + value[1]-v.value[1], + value[2]-v.value[2]); +} + + +/************************************************************************* + Build a vector with a Scalar value subtracted componentwise. + \param s The Scalar value to subtract + \return The difference vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator-(Scalar s ) const +{ + return ntlVector3Dim(value[0]-s, + value[1]-s, + value[2]-s); +} + + + +/************************************************************************* + Build a vector with another vector multiplied by componentwise. + \param v The second vector to muliply with + \return The product vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator*( const ntlVector3Dim& v) const +{ + return ntlVector3Dim(value[0]*v.value[0], + value[1]*v.value[1], + value[2]*v.value[2]); +} + + +/************************************************************************* + Build a ntlVector3Dim with a Scalar value multiplied to each component. + \param s The Scalar value to multiply with + \return The product vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator*(Scalar s) const +{ + return ntlVector3Dim(value[0]*s, value[1]*s, value[2]*s); +} + + +/************************************************************************* + Build a vector divided componentwise by another vector. + \param v The second vector to divide by + \return The ratio vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator/(const ntlVector3Dim& v) const +{ + return ntlVector3Dim(value[0]/v.value[0], + value[1]/v.value[1], + value[2]/v.value[2]); +} + + + +/************************************************************************* + Build a vector divided componentwise by a Scalar value. + \param s The Scalar value to divide by + \return The ratio vector + */ +template +inline ntlVector3Dim +ntlVector3Dim::operator/(Scalar s) const +{ + return ntlVector3Dim(value[0]/s, + value[1]/s, + value[2]/s); +} + + + + + +/************************************************************************* + Get a particular component of the vector. + \param i Number of Scalar to get + \return Reference to the component + */ +template +inline Scalar& +ntlVector3Dim::operator[]( unsigned int i ) +{ + return value[i]; +} + + +/************************************************************************* + Get a particular component of a constant vector. + \param i Number of Scalar to get + \return Reference to the component + */ +template +inline const Scalar& +ntlVector3Dim::operator[]( unsigned int i ) const +{ + return value[i]; +} + + + +//------------------------------------------------------------------------------ +// BLITZ compatibility functions +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Compute the scalar product with another vector. + \param v The second vector to work with + \return The value of the scalar product + */ +template +inline Scalar dot(const ntlVector3Dim &t, const ntlVector3Dim &v ) +{ + //return t.value[0]*v.value[0] + t.value[1]*v.value[1] + t.value[2]*v.value[2]; + return ((t[0]*v[0]) + (t[1]*v[1]) + (t[2]*v[2])); +} + + +/************************************************************************* + Calculate the cross product of this and another vector + */ +template +inline ntlVector3Dim cross(const ntlVector3Dim &t, const ntlVector3Dim &v) +{ + ntlVector3Dim cp( + ((t[1]*v[2]) - (t[2]*v[1])), + ((t[2]*v[0]) - (t[0]*v[2])), + ((t[0]*v[1]) - (t[1]*v[0])) ); + return cp; +} + + + + +/************************************************************************* + Compute a vector that is orthonormal to self. Nothing else can be assumed + for the direction of the new vector. + \return The orthonormal vector + */ +template +ntlVector3Dim +ntlVector3Dim::getOrthogonalntlVector3Dim() const +{ + // Determine the component with max. absolute value + int max= (fabs(value[0]) > fabs(value[1])) ? 0 : 1; + max= (fabs(value[max]) > fabs(value[2])) ? max : 2; + + /************************************************************************* + Choose another axis than the one with max. component and project + orthogonal to self + */ + ntlVector3Dim vec(0.0); + vec[(max+1)%3]= 1; + vec.normalize(); + vec.projectNormalTo(this->getNormalized()); + return vec; +} + + +/************************************************************************* + Projects the vector into a plane normal to the given vector, which must + have unit length. Self is modified. + \param v The plane normal + \return The projected vector + */ +template +inline const ntlVector3Dim& +ntlVector3Dim::projectNormalTo(const ntlVector3Dim &v) +{ + Scalar sprod = dot(*this,v); + value[0]= value[0] - v.value[0] * sprod; + value[1]= value[1] - v.value[1] * sprod; + value[2]= value[2] - v.value[2] * sprod; + return *this; +} + + + +//------------------------------------------------------------------------------ +// Other helper functions +//------------------------------------------------------------------------------ + + + +/************************************************************************* + Minimize the vector, i.e. set each entry of the vector to the minimum + of both values. + \param pnt The second vector to compare with + \return Reference to the modified self + */ +template +inline const ntlVector3Dim & +ntlVector3Dim::minimize(const ntlVector3Dim &pnt) +{ + for (unsigned int i = 0; i < 3; i++) + value[i] = MIN(value[i],pnt[i]); + return *this; +} + + + +/************************************************************************* + Maximize the vector, i.e. set each entry of the vector to the maximum + of both values. + \param pnt The second vector to compare with + \return Reference to the modified self + */ +template +inline const ntlVector3Dim & +ntlVector3Dim::maximize(const ntlVector3Dim &pnt) +{ + for (unsigned int i = 0; i < 3; i++) + value[i] = MAX(value[i],pnt[i]); + return *this; +} + + + + +// ---- + +// a 3D vector with double precision +typedef ntlVector3Dim ntlVec3d; + +// a 3D vector with single precision +typedef ntlVector3Dim ntlVec3f; + +// a 3D integer vector +typedef ntlVector3Dim ntlVec3i; + +// Color uses single precision fp values +typedef ntlVec3f ntlColor; + +/* convert a float to double vector */ +template inline ntlVec3d vec2D(T v) { return ntlVec3d(v[0],v[1],v[2]); } +template inline ntlVec3f vec2F(T v) { return ntlVec3f(v[0],v[1],v[2]); } +template inline ntlColor vec2Col(T v) { return ntlColor(v[0],v[1],v[2]); } + + + +/************************************************************************/ +// graphics vector typing + + +// use which fp-precision for raytracing? 1=float, 2=double + +/* VECTOR_EPSILON is the minimal vector length + In order to be able to discriminate floating point values near zero, and + to be sure not to fail a comparison because of roundoff errors, use this + value as a threshold. */ + +// use which fp-precision for graphics? 1=float, 2=double +#ifdef PRECISION_GFX_SINGLE +#define GFX_PRECISION 1 +#else +#ifdef PRECISION_GFX_DOUBLE +#define GFX_PRECISION 2 +#else +// standard precision for graphics +#ifndef GFX_PRECISION +#define GFX_PRECISION 1 +#endif +#endif +#endif + +#if GFX_PRECISION==1 +typedef float gfxReal; +#define GFX_REAL_MAX __FLT_MAX__ +//#define vecF2Gfx(x) (x) +//#define vecGfx2F(x) (x) +//#define vecD2Gfx(x) vecD2F(x) +//#define vecGfx2D(x) vecF2D(x) +#define VECTOR_EPSILON (1e-5f) +#else +typedef double gfxReal; +#define GFX_REAL_MAX __DBL_MAX__ +//#define vecF2Gfx(x) vecD2F(x) +//#define vecGfx2F(x) vecF2D(x) +//#define vecD2Gfx(x) (x) +//#define vecGfx2D(x) (x) +#define VECTOR_EPSILON (1e-10) +#endif + +/* fixed double prec. type, for epxlicitly double values */ +typedef double gfxDouble; + +// a 3D vector for graphics output, typically float? +typedef ntlVector3Dim ntlVec3Gfx; + +template inline ntlVec3Gfx vec2G(T v) { return ntlVec3Gfx(v[0],v[1],v[2]); } + +/* get minimal vector length value that can be discriminated. */ +//inline double getVecEpsilon() { return (double)VECTOR_EPSILON; } +inline gfxReal getVecEpsilon() { return (gfxReal)VECTOR_EPSILON; } + +#define HAVE_GFXTYPES + + + + +/************************************************************************/ +// HELPER FUNCTIONS, independent of implementation +/************************************************************************/ + +#define VECTOR_TYPE ntlVector3Dim + + +/************************************************************************* + Compute the length (norm) of the vector. + \return The value of the norm + */ +template +inline Scalar norm( const VECTOR_TYPE &v) +{ + Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + return (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) ? 1. : sqrt(l); +} + + +/************************************************************************* + Same as getNorm but doesnt sqrt + */ +template +inline Scalar normNoSqrt( const VECTOR_TYPE &v) +{ + return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; +} + + +/************************************************************************* + Compute a normalized vector based on this vector. + \return The new normalized vector + */ +template +inline VECTOR_TYPE getNormalized( const VECTOR_TYPE &v) +{ + Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) + return v; /* normalized "enough"... */ + else if (l > VECTOR_EPSILON*VECTOR_EPSILON) + { + Scalar fac = 1./sqrt(l); + return VECTOR_TYPE(v[0]*fac, v[1]*fac, v[2]*fac); + } + else + return VECTOR_TYPE((Scalar)0); +} + + +/************************************************************************* + Compute the norm of the vector and normalize it. + \return The value of the norm + */ +template +inline Scalar normalize( VECTOR_TYPE &v) +{ + Scalar norm; + Scalar l = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + if (fabs(l-1.) < VECTOR_EPSILON*VECTOR_EPSILON) { + norm = 1.; + } else if (l > VECTOR_EPSILON*VECTOR_EPSILON) { + norm = sqrt(l); + Scalar fac = 1./norm; + v[0] *= fac; + v[1] *= fac; + v[2] *= fac; + } else { + v[0]= v[1]= v[2]= 0; + norm = 0.; + } + return (Scalar)norm; +} + + +/************************************************************************* + Compute a vector, that is self (as an incoming + vector) reflected at a surface with a distinct normal vector. Note + that the normal is reversed, if the scalar product with it is positive. + \param n The surface normal + \return The new reflected vector + */ +template +inline VECTOR_TYPE reflectVector(const VECTOR_TYPE &t, const VECTOR_TYPE &n) +{ + VECTOR_TYPE nn= (dot(t, n) > 0.0) ? (n*-1.0) : n; + return ( t - nn * (2.0 * dot(nn, t)) ); +} + + + +/************************************************************************* + * My own refraction calculation + * Taken from Glassner's book, section 5.2 (Heckberts method) + */ +template +inline VECTOR_TYPE refractVector(const VECTOR_TYPE &t, const VECTOR_TYPE &normal, Scalar nt, Scalar nair, int &refRefl) +{ + Scalar eta = nair / nt; + Scalar n = -dot(t, normal); + Scalar tt = 1.0 + eta*eta* (n*n-1.0); + if(tt<0.0) { + // we have total reflection! + refRefl = 1; + } else { + // normal reflection + tt = eta*n - sqrt(tt); + return( t*eta + normal*tt ); + } + return t; +} + /*double eta = nair / nt; + double n = -((*this) | normal); + double t = 1.0 + eta*eta* (n*n-1.0); + if(t<0.0) { + // we have total reflection! + refRefl = 1; + } else { + // normal reflection + t = eta*n - sqrt(t); + return( (*this)*eta + normal*t ); + } + return (*this);*/ + + +/************************************************************************* + Test two ntlVector3Dims for equality based on the equality of their + values within a small threshold. + \param c The second vector to compare + \return TRUE if both are equal + \sa getEpsilon() + */ +template +inline bool equal(const VECTOR_TYPE &v, const VECTOR_TYPE &c) +{ + return (ABS(v[0]-c[0]) + + ABS(v[1]-c[1]) + + ABS(v[2]-c[2]) < VECTOR_EPSILON); +} + + +/************************************************************************* + * Assume this vector is an RGB color, and convert it to HSV + */ +template +inline void rgbToHsv( VECTOR_TYPE &V ) +{ + Scalar h=0,s=0,v=0; + Scalar maxrgb, minrgb, delta; + // convert to hsv... + maxrgb = V[0]; + int maxindex = 1; + if(V[2] > maxrgb){ maxrgb = V[2]; maxindex = 2; } + if(V[1] > maxrgb){ maxrgb = V[1]; maxindex = 3; } + minrgb = V[0]; + if(V[2] < minrgb) minrgb = V[2]; + if(V[1] < minrgb) minrgb = V[1]; + + v = maxrgb; + delta = maxrgb-minrgb; + + if(maxrgb > 0) s = delta/maxrgb; + else s = 0; + + h = 0; + if(s > 0) { + if(maxindex == 1) { + h = ((V[1]-V[2])/delta) + 0.0; } + if(maxindex == 2) { + h = ((V[2]-V[0])/delta) + 2.0; } + if(maxindex == 3) { + h = ((V[0]-V[1])/delta) + 4.0; } + h *= 60.0; + if(h < 0.0) h += 360.0; + } + + V[0] = h; + V[1] = s; + V[2] = v; +} + +/************************************************************************* + * Assume this vector is HSV and convert to RGB + */ +template +inline void hsvToRgb( VECTOR_TYPE &V ) +{ + Scalar h = V[0], s = V[1], v = V[2]; + Scalar r=0,g=0,b=0; + Scalar p,q,t, fracth; + int floorh; + // ...and back to rgb + if(s == 0) { + r = g = b = v; } + else { + h /= 60.0; + floorh = (int)h; + fracth = h - floorh; + p = v * (1.0 - s); + q = v * (1.0 - (s * fracth)); + t = v * (1.0 - (s * (1.0 - fracth))); + switch (floorh) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } + } + + V[0] = r; + V[1] = g; + V[2] = b; +} + + + + +#endif /* NTL_VECTOR3DIM_HH */ diff --git a/intern/elbeem/intern/ntl_world.cpp b/intern/elbeem/intern/ntl_world.cpp new file mode 100644 index 00000000000..21d9d63aac0 --- /dev/null +++ b/intern/elbeem/intern/ntl_world.cpp @@ -0,0 +1,910 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Main renderer class + * + *****************************************************************************/ + + +#include +#include +#include "utilities.h" +#include "ntl_world.h" +#include "parametrizer.h" + +// for non-threaded renderViz +#ifndef NOGUI +#include "../gui/ntl_openglrenderer.h" +#include "../gui/guifuncs.h" +#include "../gui/frame.h" +#endif + + +/* external parser functions from cfgparser.cxx */ +#ifndef ELBEEM_PLUGIN +/* parse given file as config file */ +void parseFile(string filename); +/* set pointers for parsing */ +void setPointers( ntlRenderGlobals *setglob); +#endif // ELBEEM_PLUGIN + + +/****************************************************************************** + * Constructor + *****************************************************************************/ + +ntlWorld::ntlWorld() { + initDefaults(); +} + +ntlWorld::ntlWorld(string filename, bool commandlineMode) +{ +#ifndef ELBEEM_PLUGIN + + initDefaults(); +# ifdef NOGUI + commandlineMode = true; // remove warning... +# endif // NOGUI + + // load config + setPointers( getRenderGlobals() ); + parseFile( filename.c_str() ); +# ifndef NOGUI + // setup opengl display, save first animation step for start time + // init after parsing file... + if(!commandlineMode) { + mpOpenGLRenderer = new ntlOpenGLRenderer( mpGlob ); + } +# endif // NOGUI + finishWorldInit(); + +#else // ELBEEM_PLUGIN + errFatal("ntlWorld::init","Cfg file parsing not supported for API version! "<setName(string(simname)); + mpGlob->getSims()->push_back( sim ); + + // important - add to both, only render scene objects are free'd + mpGlob->getRenderScene()->addGeoClass( sim ); + mpGlob->getSimScene()->addGeoClass( sim ); + sim->setGeoStart(ntlVec3Gfx(settings->geoStart[0],settings->geoStart[1],settings->geoStart[2])); + sim->setGeoEnd(ntlVec3Gfx( + settings->geoStart[0]+settings->geoSize[0], + settings->geoStart[1]+settings->geoSize[1], + settings->geoStart[2]+settings->geoSize[2] )); + // further init in postGeoConstrInit/initializeLbmSimulation of SimulationObject + sim->copyElbeemSettings(settings); + + Parametrizer *param = sim->getParametrizer(); + param->setSize( settings->resolutionxyz ); + param->setDomainSize( settings->realsize ); + param->setAniStart( settings->animStart ); + param->setNormalizedGStar( settings->gstar ); + + // init domain channels + vector valf; + vector valv; + vector time; + +#define INIT_CHANNEL_FLOAT(channel,size) \ + valf.clear(); time.clear(); elbeemSimplifyChannelFloat(channel,&size); \ + for(int i=0; isetViscosity( settings->viscosity ); + if((settings->channelViscosity)&&(settings->channelSizeViscosity>0)) { + INIT_CHANNEL_FLOAT(settings->channelViscosity, settings->channelSizeViscosity); + param->initViscosityChannel(valf,time); } + + param->setGravity( ParamVec(settings->gravity[0], settings->gravity[1], settings->gravity[2]) ); + if((settings->channelGravity)&&(settings->channelSizeGravity>0)) { + INIT_CHANNEL_VEC(settings->channelGravity, settings->channelSizeGravity); + param->initGravityChannel(valv,time); } + + param->setAniFrameTimeChannel( settings->aniFrameTime ); + if((settings->channelFrameTime)&&(settings->channelSizeFrameTime>0)) { + INIT_CHANNEL_FLOAT(settings->channelFrameTime, settings->channelSizeFrameTime); + param->initAniFrameTimeChannel(valf,time); } + +#undef INIT_CHANNEL_FLOAT +#undef INIT_CHANNEL_VEC + + // might be set by previous domain + if(mpGlob->getAniFrames() < settings->noOfFrames) mpGlob->setAniFrames( settings->noOfFrames ); + // set additionally to SimulationObject->mOutFilename + mpGlob->setOutFilename( settings->outputPath ); + + return 0; +} + +void ntlWorld::initDefaults() +{ + mStopRenderVisualization = false; + mThreadRunning = false; + mSimulationTime = 0.0; + mFirstSim = 1; + mSingleStepDebug = false; + mFrameCnt = 0; + mpOpenGLRenderer = NULL; + + /* create scene storage */ + mpGlob = new ntlRenderGlobals(); + mpLightList = new vector; + mpPropList = new vector; + mpSims = new vector; + + mpGlob->setLightList(mpLightList); + mpGlob->setMaterials(mpPropList); + mpGlob->setSims(mpSims); + + /* init default material */ + ntlMaterial *def = GET_GLOBAL_DEFAULT_MATERIAL; + mpPropList->push_back( def ); + + /* init the scene object */ + ntlScene *renderscene = new ntlScene( mpGlob, true ); + mpGlob->setRenderScene( renderscene ); + // sim scene shouldnt delete objs, may only contain subset + ntlScene *simscene = new ntlScene( mpGlob, false ); + mpGlob->setSimScene( simscene ); +} + +void ntlWorld::finishWorldInit() +{ + if(! isSimworldOk() ) return; + + // init the scene for the first time + long sstartTime = getTime(); + + // first init sim scene for geo setup + mpGlob->getSimScene()->buildScene(0.0, true); + if(! isSimworldOk() ) return; + mpGlob->getRenderScene()->buildScene(0.0, true); + if(! isSimworldOk() ) return; + long sstopTime = getTime(); + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Scene build time: "<< getTimeString(sstopTime-sstartTime) <<" ", 10); + + // TODO check simulations, run first steps + mFirstSim = -1; + if(mpSims->size() > 0) { + + // use values from first simulation as master time scale + long startTime = getTime(); + + // remember first active sim + for(size_t i=0;isize();i++) { + if(!(*mpSims)[i]->getVisible()) continue; + if((*mpSims)[i]->getPanic()) continue; + + // check largest timestep + if(mFirstSim>=0) { + if( (*mpSims)[i]->getTimestep() > (*mpSims)[mFirstSim]->getTimestep() ) { + mFirstSim = i; + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim changed: "<=0) { + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime() ,10); + while(mSimulationTime < (*mpSims)[mFirstSim]->getStartTime() ) { + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime()<<" simtime:"<getStartTime(); + debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Time for start-sims:"<< getTimeString(stopTime-startTime) , 1); +#ifndef NOGUI + guiResetSimulationTimeRange( mSimulationTime ); +#endif + } else { + if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlWorld::ntlWorld",DM_WARNING,"No active simulations!", 1); + } + } + + if(! isSimworldOk() ) return; + setElbeemState( SIMWORLD_INITED ); +} + + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +ntlWorld::~ntlWorld() +{ + delete mpGlob->getRenderScene(); + delete mpGlob->getSimScene(); + delete mpGlob; + delete mpLightList; + delete mpPropList; + delete mpSims; +#ifndef NOGUI + if(mpOpenGLRenderer) delete mpOpenGLRenderer; +#endif // NOGUI + debMsgStd("ntlWorld",DM_NOTIFY, "ntlWorld done", 10); +} + +/******************************************************************************/ +/*! set single frame rendering to filename */ +void ntlWorld::setSingleFrameOut(string singleframeFilename) { + mpGlob->setSingleFrameMode(true); + mpGlob->setSingleFrameFilename(singleframeFilename); +} + +/****************************************************************************** + * render a whole animation (command line mode) + *****************************************************************************/ + +int ntlWorld::renderAnimation( void ) +{ + // only single pic currently + //debMsgStd("ntlWorld::renderAnimation : Warning only simulating...",1); + if(mpGlob->getAniFrames() < 0) { + debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No frames to render... ",1); + return 1; + } + + if(mFirstSim<0) { + debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No reference animation found...",1); + return 1; + } + + mThreadRunning = true; // not threaded, but still use the same flags + if(getElbeemState() == SIMWORLD_INITED) { + renderScene(); + } else if(getElbeemState() == SIMWORLD_STOP) { + // dont render now, just continue + setElbeemState( SIMWORLD_INITED ); + mFrameCnt--; // counted one too many from last abort... + } else { + debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"Not properly inited, stopping...",1); + return 1; + } + + if(mpSims->size() <= 0) { + debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1); + return 1; + } + + bool simok = true; + for( ; ((mFrameCntgetAniFrames()) && (!getStopRenderVisualization() ) && (simok)); mFrameCnt++) { + if(!advanceSims(mFrameCnt)) { + renderScene(); + } // else means sim panicked, so dont render... + else { simok=false; } + } + mThreadRunning = false; + return 0; +} + +/****************************************************************************** + * render a whole animation (visualization mode) + * this function is run in another thread, and communicates + * with the parent thread via a mutex + *****************************************************************************/ +int ntlWorld::renderVisualization( bool multiThreaded ) +{ +#ifndef NOGUI + if(getElbeemState() != SIMWORLD_INITED) { return 0; } + + if(multiThreaded) mThreadRunning = true; + // TODO, check global state? + while(!getStopRenderVisualization()) { + + if(mpSims->size() <= 0) { + debMsgStd("ntlWorld::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1); + stopSimulationThread(); + break; + } + + // determine stepsize + if(!mSingleStepDebug) { + long startTime = getTime(); + advanceSims(mFrameCnt); + mFrameCnt++; + long stopTime = getTime(); + debMsgStd("ntlWorld::renderVisualization",DM_MSG,"Time for t="<getTimestep(); + singleStepSims(targetTime); + + // check paniced sims (normally done by advanceSims + bool allPanic = true; + for(size_t i=0;isize();i++) { + if(!(*mpSims)[i]->getPanic()) allPanic = false; + } + if(allPanic) { + warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" ); + setStopRenderVisualization( true ); + } + if(! isSimworldOk() ) { + warnMsg("ntlWorld::advanceSims","World state error... stopping" ); + setStopRenderVisualization( true ); + } + } + + // save frame + if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime ); + + // for non-threaded check events + if(!multiThreaded) { + Fl::check(); + gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw(); + } + + } + mThreadRunning = false; + stopSimulationRestoreGui(); +#else + multiThreaded = false; // remove warning +#endif + return 0; +} +/*! render a single step for viz mode */ +int ntlWorld::singleStepVisualization( void ) +{ + mThreadRunning = true; + double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep(); + singleStepSims(targetTime); + mSimulationTime = (*mpSims)[0]->getCurrentTime(); + +#ifndef NOGUI + if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime ); + Fl::check(); + gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw(); + mThreadRunning = false; + stopSimulationRestoreGui(); +#else + mThreadRunning = false; +#endif // NOGUI + return 0; +} + +// dont use LBM_EPSILON here, time is always double-precision! +#define LBM_TIME_EPSILON 1e-10 + +/****************************************************************************** + * advance simulations by time t + *****************************************************************************/ +int ntlWorld::advanceSims(int framenum) +{ + bool done = false; + bool allPanic = true; + + // stop/quit, dont display/render + if(getElbeemState()==SIMWORLD_STOP) { + return 1; + } + + for(size_t i=0;isize();i++) { (*mpSims)[i]->setFrameNum(framenum); } + double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime(framenum); + + // time stopped? nothing else to do... + if( (*mpSims)[mFirstSim]->getFrameTime(framenum) <= 0.0 ){ + done=true; allPanic=false; + } + + int gstate = 0; + myTime_t advsstart = getTime(); + + // step all the sims, and check for panic + debMsgStd("ntlWorld::advanceSims",DM_MSG, " sims "<size()<<" t"<getCurrentTime() + (*mpSims)[mFirstSim]->getTimestep(); + singleStepSims(nextTargetTime); + + // check target times + done = true; + allPanic = false; + + if((*mpSims)[mFirstSim]->getTimestep() <1e-9 ) { + // safety check, avoid timesteps that are too small + errMsg("ntlWorld::advanceSims","Invalid time step, causing panic! curr:"<<(*mpSims)[mFirstSim]->getCurrentTime()<<" next:"<getTimestep() ); + allPanic = true; + } else { + for(size_t i=0;isize();i++) { + if(!(*mpSims)[i]->getVisible()) continue; + if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!? + debMsgStd("ntlWorld::advanceSims",DM_MSG, "Sim "<getCurrentTime()<<", nt:"<getPanic()<<", targett:"<getCurrentTime()) > LBM_TIME_EPSILON) done=false; + if(allPanic) done = true; + } + + if(allPanic) { + warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" ); + setStopRenderVisualization( true ); + return 1; + } + + myTime_t advsend = getTime(); + debMsgStd("ntlWorld::advanceSims",DM_MSG,"Overall steps so far took:"<< getTimeString(advsend-advsstart)<<" for sim time "<size();i++) { + SimulationObject *sim = (*mpSims)[i]; + if(!sim->getVisible()) continue; + if(sim->getPanic()) continue; + sim->prepareVisualization(); + } + + return 0; +} + +/* advance simulations by a single step */ +/* dont check target time, if *targetTime==NULL */ +void ntlWorld::singleStepSims(double targetTime) { + const bool debugTime = false; + //double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep(); + if(debugTime) errMsg("ntlWorld::singleStepSims","Target time: "<size();i++) { + SimulationObject *sim = (*mpSims)[i]; + if(!sim->getVisible()) continue; + if(sim->getPanic()) continue; + bool done = false; + while(!done) { + // try to prevent round off errs + if(debugTime) errMsg("ntlWorld::singleStepSims","Test sim "<getCurrentTime()<<" target:"<getCurrentTime())<<" stept:"<getTimestep()<<" leps:"<getCurrentTime()) > LBM_TIME_EPSILON) { + if(debugTime) errMsg("ntlWorld::singleStepSims","Stepping sim "<getCurrentTime()); // timedebug + sim->step(); + } else { + done = true; + } + } + } + + mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime(); +#ifndef NOGUI + if(mpOpenGLRenderer) mpOpenGLRenderer->notifyOfNextStep(mSimulationTime); +#endif // NOGUI +} + + + +extern bool glob_mpactive; +extern int glob_mpindex; + +/****************************************************************************** + * Render the current scene + * uses the global variables from the parser + *****************************************************************************/ +int ntlWorld::renderScene( void ) +{ +#ifndef ELBEEM_PLUGIN + char nrStr[5]; // nr conversion + std::ostringstream outfn_conv(""); // converted ppm with other suffix + ntlRenderGlobals *glob; // storage for global rendering parameters + myTime_t timeStart,totalStart,timeEnd; // measure user running time + myTime_t rendStart,rendEnd; // measure user rendering time + glob = mpGlob; + + // deactivate for all with index!=0 + if((glob_mpactive)&&(glob_mpindex>0)) return(0); + + /* check if picture already exists... */ + if(!glob->getSingleFrameMode() ) { + snprintf(nrStr, 5, "%04d", glob->getAniCount() ); + + if(glob_mpactive) { + outfn_conv << glob->getOutFilename() <<"_"<getOutFilename() <<"_" << nrStr << ".png"; + } + + //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) { + if(mpGlob->getFrameSkip()) { + struct stat statBuf; + if(stat(outfn_conv.str().c_str(),&statBuf) == 0) { + errorOut("ntlWorld::renderscene Warning: file "<setAniCount( glob->getAniCount() +1 ); + return(2); + } + } // RAY mode + } else { + // single frame rendering, overwrite if necessary... + outfn_conv << glob->getSingleFrameFilename(); + } + + /* start program */ + timeStart = getTime(); + + /* build scene geometry, calls buildScene(t,false) */ + glob->getRenderScene()->prepareScene(mSimulationTime); + + /* start program */ + totalStart = getTime(); + + + /* view parameters are currently not animated */ + /* calculate rays through projection plane */ + ntlVec3Gfx direction = glob->getLookat() - glob->getEye(); + /* calculate width of screen using perpendicular triangle diven by + * viewing direction and screen plane */ + gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI ); + + /* calculate vector orthogonal to up and viewing direction */ + ntlVec3Gfx upVec = glob->getUpVec(); + ntlVec3Gfx rightVec( cross(upVec,direction) ); + normalize(rightVec); + + /* calculate screen plane up vector, perpendicular to viewdir and right vec */ + upVec = ntlVec3Gfx( cross(rightVec,direction) ); + normalize(upVec); + + /* check if vectors are valid */ + if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) { + errMsg("ntlWorld::renderScene","Invalid viewpoint vectors! up="<getLookat() + upVec*((2.0*scanline-Yres)/Yres) + - rightVec; + + /* loop over all pixels in line */ + for (int sx=0 ; sx < Xres ; ++sx) { + + if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) { + // DEBUG!!! + glob->setDebugOut(10); + } else glob->setDebugOut(0); + + /* compute ray from eye through current pixel into scene... */ + ntlColor col; + if(aaDepth<0) { + ntlVec3Gfx dir(screenPos - glob->getEye()); + ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob ); + + /* ...and trace it */ + col = the_ray.shade(); + } else { + /* anti alias */ + int ai,aj; /* position in grid */ + int aOrg = sx*aaLength; /* grid offset x */ + int currStep = aaLength; /* step size */ + char colDiff = 1; /* do colors still differ too much? */ + ntlColor minCol,maxCol; /* minimum and maximum Color Values */ + minCol = ntlColor(1.0,1.0,1.0); + maxCol = ntlColor(0.0,0.0,0.0); + + while((colDiff) && (currStep>0)) { + colDiff = 0; + + for(aj = 0;aj<=aaLength;aj+= currStep) { + for(ai = 0;ai<=aaLength;ai+= currStep) { + + /* shade pixel if not done */ + if(aaUse[aj*aaArrayX +ai +aOrg] == 0) { + aaUse[aj*aaArrayX +ai +aOrg] = 1; + ntlVec3Gfx aaPos( screenPos + + (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) + + (upStep * (aj- aaLength/2)/(gfxReal)aaLength ) ); + + ntlVec3Gfx dir(aaPos - glob->getEye()); + ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob ); + + /* ...and trace it */ + ntlColor newCol= the_ray.shade(); + aaCol[aj*aaArrayX +ai +aOrg]= newCol; + } /* not used? */ + + } + } + + /* check color differences */ + for(aj = 0;aj aaSensRed ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - + aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - + aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) { + thisColDiff = 1; + } else + if( + (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - + aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - + aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - + aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) { + thisColDiff = 1; + } else + if( + (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) || + (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) { + thisColDiff = 1; + } + + //colDiff =1; + if(thisColDiff) { + /* set diff flag */ + colDiff = thisColDiff; + for(int bj=aj;bj<=aj+currStep;bj++) { + for(int bi=ai;bi<=ai+currStep;bi++) { + if(aaUse[bj*aaArrayX +bi +aOrg]==2) { + //if(showAAPic) + aaUse[bj*aaArrayX +bi +aOrg] = 0; + } + } + } + } else { + /* set all values */ + ntlColor avgCol = ( + aaCol[(aj+0 )*aaArrayX +(ai+0 ) +aOrg] + + aaCol[(aj+0 )*aaArrayX +(ai+currStep) +aOrg] + + aaCol[(aj+currStep)*aaArrayX +(ai+0 ) +aOrg] + + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25; + for(int bj=aj;bj<=aj+currStep;bj++) { + for(int bi=ai;bi<=ai+currStep;bi++) { + if(aaUse[bj*aaArrayX +bi +aOrg]==0) { + aaCol[bj*aaArrayX +bi +aOrg] = avgCol; + aaUse[bj*aaArrayX +bi +aOrg] = 2; + } + } + } + } /* smaller values set */ + + } + } + + /* half step size */ + currStep /= 2; + + } /* repeat until diff not too big */ + + /* get average color */ + gfxReal colNum = 0.0; + col = ntlColor(0.0, 0.0, 0.0); + for(aj = 0;aj<=aaLength;aj++) { + for(ai = 0;ai<=aaLength;ai++) { + col += aaCol[aj*aaArrayX +ai +aOrg]; + colNum += 1.0; + } + } + col /= colNum; + + } + + /* mark pixels with debugging */ + if( glob->getDebugOut() > 0) col = ntlColor(0,1,0); + + /* store pixel */ + if(!showAAPic) { + finalPic[(scanline-1)*picX+sx] = col; + } + screenPos += rightStep; + + } /* foreach x */ + + /* init aa array */ + if(showAAPic) { + for(int j=0;j<=aaArrayY-1;j++) { + for(int i=0;i<=aaArrayX-1;i++) { + if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0; + } + } + } + + for(int i=0;i= 1.0) col[cc] = 1.0; + } + *filler = (unsigned char)( col[0]*255.0 ); + filler++; + *filler = (unsigned char)( col[1]*255.0 ); + filler++; + *filler = (unsigned char)( col[2]*255.0 ); + filler++; + *filler = (unsigned char)( 255.0 ); + filler++; // alpha channel + } + } + + for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ]; + writePng(outfn_conv.str().c_str(), rows, w, h); + } + + + // next frame + glob->setAniCount( glob->getAniCount() +1 ); + + // done + timeEnd = getTime(); + + char resout[1024]; + snprintf(resout,1024, "NTL Done %s, frame %d/%d (took %s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n", + outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1), + getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(), + glob->getCounterShades(), + glob->getCounterSceneInter() ); + debMsgStd("ntlWorld::renderScene",DM_MSG, resout, 1 ); + + /* clean stuff up */ + delete [] aaCol; + delete [] aaUse; + delete [] finalPic; + glob->getRenderScene()->cleanupScene(); + + if(mpGlob->getSingleFrameMode() ) { + debMsgStd("ntlWorld::renderScene",DM_NOTIFY, "Single frame mode done...", 1 ); + return 1; + } +#endif // ELBEEM_PLUGIN + return 0; +} + + +/****************************************************************************** + * renderglobals + *****************************************************************************/ + + +/*****************************************************************************/ +/* Constructor with standard value init */ +ntlRenderGlobals::ntlRenderGlobals() : + mpRenderScene(NULL), mpSimScene(NULL), + mpLightList( NULL ), mpMaterials( NULL ), mpSims( NULL ), + mResX(320), mResY(200), mAADepth(-1), mMaxColVal(255), + mRayMaxDepth( 5 ), + mvEye(0.0,0.0,5.0), mvLookat(0.0,0.0,0.0), mvUpvec(0.0,1.0,0.0), + mAspect(320.0/200.0), + mFovy(45), mcBackgr(0.0,0.0,0.0), mcAmbientLight(0.0,0.0,0.0), + mDebugOut( 0 ), + mAniStart(0), mAniFrames( -1 ), mAniCount( 0 ), + mFrameSkip( 0 ), + mCounterRays( 0 ), mCounterShades( 0 ), mCounterSceneInter( 0 ), + mOutFilename( "pic" ), + mTreeMaxDepth( 30 ), mTreeMaxTriangles( 30 ), + mpOpenGlAttr(NULL), + mpBlenderAttr(NULL), + mTestSphereEnabled( false ), + mDebugPixelX( -1 ), mDebugPixelY( -1 ), mTestMode(false), + mSingleFrameMode(false), mSingleFrameFilename("") + //,mpRndDirections( NULL ), mpRndRoulette( NULL ) +{ + // create internal attribute list for opengl renderer + mpOpenGlAttr = new AttributeList("__ntlOpenGLRenderer"); + mpBlenderAttr = new AttributeList("__ntlBlenderAttr"); +}; + + +/*****************************************************************************/ +/* Destructor */ +ntlRenderGlobals::~ntlRenderGlobals() { + if(mpOpenGlAttr) delete mpOpenGlAttr; + if(mpBlenderAttr) delete mpBlenderAttr; +} + + +/*****************************************************************************/ +//! get the next random photon direction +//ntlVec3Gfx ntlRenderGlobals::getRandomDirection( void ) { + //return ntlVec3Gfx( + //(mpRndDirections->getGfxReal()-0.5), + //(mpRndDirections->getGfxReal()-0.5), + //(mpRndDirections->getGfxReal()-0.5) ); +//} + + diff --git a/intern/elbeem/intern/ntl_world.h b/intern/elbeem/intern/ntl_world.h new file mode 100644 index 00000000000..9c5324cfe8f --- /dev/null +++ b/intern/elbeem/intern/ntl_world.h @@ -0,0 +1,389 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Main renderer class + * + *****************************************************************************/ +#ifndef NTL_RAYTRACER_HH +#define NTL_RAYTRACER_HH + +#include "ntl_vector3dim.h" +#include "ntl_ray.h" +#include "ntl_lighting.h" +#include "ntl_geometryobject.h" +#include "simulation_object.h" +#include "elbeem.h" +class ntlOpenGLRenderer; +class ntlScene; +class SimulationObject; +class ntlRandomStream; + +class ntlWorld +{ + public: + /*! Constructor for API init */ + ntlWorld(); + /*! Constructor */ + ntlWorld(string filename, bool commandlineMode); + /*! Destructor */ + virtual ~ntlWorld( void ); + /*! default init for all contructors */ + void initDefaults(); + /*! common world contruction stuff once the scene is set up */ + void finishWorldInit(); + /*! add domain for API init */ + int addDomain(elbeemSimulationSettings *simSettings); + + /*! render a whole animation (command line mode) */ + int renderAnimation( void ); + /*! render a whole animation (visualization mode) */ + int renderVisualization( bool ); + /*! render a single step for viz mode */ + int singleStepVisualization( void ); + /*! advance simulations by time frame time */ + int advanceSims(int framenum); + /*! advance simulations by a single step */ + void singleStepSims(double targetTime); + + /*! set stop rend viz flag */ + void setStopRenderVisualization(bool set) { mStopRenderVisualization = set; } + /*! should the rendering viz thread be stopped? */ + bool getStopRenderVisualization() { return mStopRenderVisualization; } + + /*! render scene (a single pictures) */ + virtual int renderScene( void ); + + /*! set single frame rendering to filename */ + void setSingleFrameOut( string singleframeFilename ); + + /* access functions */ + + /*! set&get render globals */ + inline void setRenderGlobals( ntlRenderGlobals *set) { mpGlob = set; } + inline ntlRenderGlobals *getRenderGlobals( void ) { return mpGlob; } + + /*! set&get render globals */ + inline void setSimulationTime( double set) { mSimulationTime = set; } + inline double getSimulationTime( void ) { return mSimulationTime; } + + /*! set&get single step debug mode */ + inline void setSingleStepDebug( bool set) { mSingleStepDebug = set; } + inline bool getSingleStepDebug( void ) { return mSingleStepDebug; } + + /*! &get simulation object vector (debugging) */ + inline vector *getSimulations( void ) { return mpSims; } + + /*! get opengl renderer */ + inline ntlOpenGLRenderer *getOpenGLRenderer() { return mpOpenGLRenderer; } + + private: + + protected: + + /*! global render settings needed almost everywhere */ + ntlRenderGlobals *mpGlob; + + /*! a list of lights in the scene (geometry is store in ntl_scene) */ + vector *mpLightList; + /*! surface materials */ + vector *mpPropList; + /*! sims list */ + vector *mpSims; + + /*! opengl display */ + ntlOpenGLRenderer *mpOpenGLRenderer; + + /*! stop rend viz? */ + bool mStopRenderVisualization; + + /*! rend viz thread currently running? */ + bool mThreadRunning; + + /*! remember the current simulation time */ + double mSimulationTime; + + /*! first simulation that is valid */ + int mFirstSim; + + /*! single step mode for debugging */ + bool mSingleStepDebug; + + /*! count no. of frame for viz render */ + int mFrameCnt; +}; + + +//! Class that handles global rendering parameters +class ntlRenderGlobals +{ + public: + //! Standard constructor + ntlRenderGlobals(); + //! Destructor + ~ntlRenderGlobals(); + + //! Returns the renderscene manager (scene changes for each frame) + inline ntlScene *getRenderScene(void) { return mpRenderScene; } + //! Set the renderscene manager + inline void setRenderScene(ntlScene *set) { mpRenderScene = set;} + + //! Returns the simulation scene manager (static scene with sim objects) + inline ntlScene *getSimScene(void) { return mpSimScene; } + //! Set the simulation scene manager + inline void setSimScene(ntlScene *set) { mpSimScene = set;} + + //! Returns the light object list + inline vector *getLightList(void) { return mpLightList; } + //! Set the light list + inline void setLightList(vector *set) { mpLightList = set;} + + //! Returns the property object list + inline vector *getMaterials(void) { return mpMaterials; } + //! Set the property list + inline void setMaterials(vector *set) { mpMaterials = set;} + + //! Returns the list of simulations + inline vector *getSims(void) { return mpSims; } + //! Set the pointer to the list of simulations + inline void setSims(vector *set) { mpSims = set;} + + //! Set the x resolution + inline void setResX(unsigned int set) { mResX = set; } + //! Set the y resolution + inline void setResY(unsigned int set) { mResY = set; } + //! Set the anti-aliasing depth + inline void setAADepth(int set) { mAADepth = set; } + //! Set the max color value + inline void setMaxColVal(unsigned int set) { mMaxColVal = set; } + //! Set the maximum ray recursion + inline void setRayMaxDepth(unsigned int set) { mRayMaxDepth = set; } + //! Set the eye point + inline void setEye(ntlVec3Gfx set) { mvEye = set; } + //! Set the look at vector + inline void setLookat(ntlVec3Gfx set) { mvLookat = set; } + //! Set the up vector + inline void setUpVec(ntlVec3Gfx set) { mvUpvec = set; } + //! Set the image aspect + inline void setAspect(float set) { mAspect = set; } + //! Set the field of view + inline void setFovy(float set) { mFovy = set; } + //! Set the background color + inline void setBackgroundCol(ntlColor set) { mcBackgr = set; } + //! Set the ambient lighting color + inline void setAmbientLight(ntlColor set) { mcAmbientLight = set; } + //! Set the debug output var + inline void setDebugOut(int set) { mDebugOut = set; } + + //! Set the animation start time + inline void setAniStart(int set) { mAniStart = set; } + //! Set the animation number of frames + inline void setAniFrames(int set) { mAniFrames = set; } + //! Set the animation + inline void setAniCount(int set) { mAniCount = set; } + //! Set the ray counter + inline void setCounterRays(int set) { mCounterRays = set; } + //! Set the ray shades counter + inline void setCounterShades(int set) { mCounterShades = set; } + //! Set the scenen intersection counter + inline void setCounterSceneInter(int set) { mCounterSceneInter = set; } + //! Set if existing frames should be skipped + inline void setFrameSkip(int set) { mFrameSkip = set; } + + //! Set the outfilename + inline void setOutFilename(string set) { mOutFilename = set; } + + //! get Maximum depth for BSP tree + inline void setTreeMaxDepth( int set ) { mTreeMaxDepth = set; } + //! get Maxmimum nr of triangles per BSP tree node + inline void setTreeMaxTriangles( int set ) { mTreeMaxTriangles = set; } + + //! set the enable flag of the test sphere + inline void setTestSphereEnabled( bool set ) { mTestSphereEnabled = set; } + //! set the center of the test sphere + inline void setTestSphereCenter( ntlVec3Gfx set ) { mTestSphereCenter = set; } + //! set the radius of the test sphere + inline void setTestSphereRadius( gfxReal set ) { mTestSphereRadius = set; } + //! set the material name of the test sphere + inline void setTestSphereMaterialName( char* set ) { mTestSphereMaterialName = set; } + //! set debugging pixel coordinates + inline void setDebugPixel( int setx, int sety ) { mDebugPixelX = setx; mDebugPixelY = sety; } + //! set test mode flag + inline void setTestMode( bool set ) { mTestMode = set; } + //! set single frame mode flag + inline void setSingleFrameMode(bool set) {mSingleFrameMode = set; }; + //! set single frame mode filename + inline void setSingleFrameFilename(string set) {mSingleFrameFilename = set; }; + + + //! Return the x resolution + inline unsigned int getResX(void) { return mResX; } + //! Return the y resolution + inline unsigned int getResY(void) { return mResY; } + //! Return the anti-aliasing depth + inline int getAADepth(void) { return mAADepth; } + //! Return the max color value for ppm + inline unsigned int getMaxColVal(void) { return mMaxColVal; } + //! Return the maximum ray recursion + inline unsigned int getRayMaxDepth(void) { return mRayMaxDepth; } + //! Return the eye point + inline ntlVec3Gfx getEye(void) { return mvEye; } + //! Return the look at vector + inline ntlVec3Gfx getLookat(void) { return mvLookat; } + //! Return the up vector + inline ntlVec3Gfx getUpVec(void) { return mvUpvec; } + //! Return the image aspect + inline float getAspect(void) { return mAspect; } + //! Return the field of view + inline float getFovy(void) { return mFovy; } + //! Return the background color + inline ntlColor getBackgroundCol(void) { return mcBackgr; } + //! Return the ambient color + inline ntlColor getAmbientLight(void) { return mcAmbientLight; } + //! Return the debug mode setting + inline int getDebugOut(void) { return mDebugOut; } + + //! Return the animation start time + inline int getAniStart(void) { return mAniStart; } + //! Return the animation frame number + inline int getAniFrames(void) { return mAniFrames; } + //! Return the animation counter + inline int getAniCount(void) { return mAniCount; } + //! Return the ray counter + inline int getCounterRays(void) { return mCounterRays; } + //! Return the ray shades counter + inline int getCounterShades(void) { return mCounterShades; } + //! Return the scene intersection counter + inline int getCounterSceneInter(void) { return mCounterSceneInter; } + //! Check if existing frames should be skipped + inline int getFrameSkip( void ) { return mFrameSkip; } + + + //! Return the outfilename + inline string getOutFilename(void) { return mOutFilename; } + + //! get Maximum depth for BSP tree + inline int getTreeMaxDepth( void ) { return mTreeMaxDepth; } + //! get Maxmimum nr of triangles per BSP tree node + inline int getTreeMaxTriangles( void ) { return mTreeMaxTriangles; } + + //! get open gl attribute list + inline AttributeList* getOpenGlAttributes( void ) { return mpOpenGlAttr; } + //! get blender output attribute list + inline AttributeList* getBlenderAttributes( void ) { return mpBlenderAttr; } + + //! is the test sphere enabled? + inline bool getTestSphereEnabled( void ) { return mTestSphereEnabled; } + //! get the center of the test sphere + inline ntlVec3Gfx getTestSphereCenter( void ) { return mTestSphereCenter; } + //! get the radius of the test sphere + inline gfxReal getTestSphereRadius( void) { return mTestSphereRadius; } + //! get the materialname of the test sphere + inline char *getTestSphereMaterialName( void) { return mTestSphereMaterialName; } + //! get the debug pixel coordinate + inline int getDebugPixelX( void ) { return mDebugPixelX; } + //! get the debug pixel coordinate + inline int getDebugPixelY( void ) { return mDebugPixelY; } + //! get test mode flag + inline bool getTestMode( void ) { return mTestMode; } + //! set single frame mode flag + inline bool getSingleFrameMode() { return mSingleFrameMode; }; + //! set single frame mode filename + inline string getSingleFrameFilename() { return mSingleFrameFilename; }; + + +private: + + /*! Scene storage (dynamic rendering scene) */ + ntlScene *mpRenderScene; + /*! Scene storage (static sim scene, inited only once) */ + ntlScene *mpSimScene; + + //! List of light objects + vector *mpLightList; + //! List of surface properties + vector *mpMaterials; + /*! storage for simulations */ + vector *mpSims; + + //! resolution of the picture + unsigned int mResX, mResY; + //! Anti-Aliasing depth + int mAADepth; + //! max color value for ppm + unsigned int mMaxColVal; + /* Maximal ray recursion depth */ + int mRayMaxDepth; + //! The eye point + ntlVec3Gfx mvEye; + //! The look at point + ntlVec3Gfx mvLookat; + //! The up vector + ntlVec3Gfx mvUpvec; + //! The image aspect = Xres/Yres + float mAspect; + //! The horizontal field of view + float mFovy; + //! The background color + ntlColor mcBackgr; + //! The ambient color + ntlColor mcAmbientLight; + //! how much debug output is needed? off by default + char mDebugOut; + + + //! animation properties, start time + int mAniStart; + //! animation properties, number of frames to render + int mAniFrames; + //! animation status, current frame number + int mAniCount; + /*! Should existing picture frames be skipped? */ + int mFrameSkip; + + + //! count the total number of rays created (also used for ray ID's) + int mCounterRays; + //! count the total number of rays shaded + int mCounterShades; + //! count the total number of scene intersections + int mCounterSceneInter; + + /*! filename of output pictures (without suffix or numbers) */ + string mOutFilename; + + //! get Maximum depth for BSP tree + int mTreeMaxDepth; + //! get Maxmimum nr of triangles per BSP tree node + int mTreeMaxTriangles; + + //! attribute list for opengl renderer + AttributeList *mpOpenGlAttr; + //! attribute list for blender output + AttributeList *mpBlenderAttr; + + + //! Enable test sphere? + bool mTestSphereEnabled; + //! Center of the test sphere + ntlVec3Gfx mTestSphereCenter; + //! Radius of the test sphere + gfxReal mTestSphereRadius; + //! Materialname of the test sphere + char *mTestSphereMaterialName; + //! coordinates of the debugging pixel + int mDebugPixelX, mDebugPixelY; + + //! test mode for quick rendering activated?, inited in ntl_scene::buildScene + bool mTestMode; + + //! single frame flag + bool mSingleFrameMode; + //! filename for single frame mode + string mSingleFrameFilename; +}; + + + +#endif diff --git a/intern/elbeem/intern/parametrizer.cpp b/intern/elbeem/intern/parametrizer.cpp new file mode 100644 index 00000000000..dca0b48d265 --- /dev/null +++ b/intern/elbeem/intern/parametrizer.cpp @@ -0,0 +1,594 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Parameter calculator for the LBM Solver class + * + *****************************************************************************/ + +#include +#include "parametrizer.h" + +// debug output flag, has to be off for win32 for some reason... +#define DEBUG_PARAMCHANNELS 0 + +/*! param seen debug string array */ +const char *ParamStrings[] = { + "RelaxTime", + "Reynolds", + "Viscosity", + "SoundSpeed", + "DomainSize", + "GravityForce", + "TimeLength", + "Timestep", + "Size", + "TimeFactor", + "AniFrames", + "AniFrameTime", + "AniStart", + "SurfaceTension", + "Density", + "CellSize", + "GStar", + "MaxSpeed", + "SimMaxSpeed", + "FluidVolHeight", + "NormalizedGStar", + "PSERR", "PSERR", "PSERR", "PSERR" +}; + + + +/****************************************************************************** + * Default constructor + *****************************************************************************/ +Parametrizer::Parametrizer( void ) : + mcViscosity( 8.94e-7 ), + mSoundSpeed( 1500 ), + mDomainSize( 0.1 ), mCellSize( 0.01 ), + mcGravity( ParamVec(0.0) ), + mTimestep(0.0001), mDesiredTimestep(-1.0), + mMaxTimestep(-1.0), + mMinTimestep(-1.0), + mSizex(50), mSizey(50), mSizez(50), + mTimeFactor( 1.0 ), + mcAniFrameTime(0.0001), + mTimeStepScale(1.0), + mAniStart(0.0), + //mExtent(1.0, 1.0, 1.0), //mSurfaceTension( 0.0 ), + mDensity(1000.0), mGStar(0.0001), mFluidVolumeHeight(0.0), + mSimulationMaxSpeed(0.0), + mTadapMaxOmega(2.0), mTadapMaxSpeed(0.1), mTadapLevels(1), + mFrameNum(0), + mSeenValues( 0 ), mCalculatedValues( 0 ) +{ +} + + +/****************************************************************************** + * Destructor + *****************************************************************************/ +Parametrizer::~Parametrizer() +{ + /* not much to do... */ +} + +/****************************************************************************** + * Init from attr list + *****************************************************************************/ +void Parametrizer::parseAttrList() +{ + if(!mpAttrs) { + errFatal("Parametrizer::parseAttrList", "mpAttrs pointer not initialized!", SIMWORLD_INITERROR); + return; + } + + // unused + string mSetupType = ""; + mSetupType = mpAttrs->readString("p_setup",mSetupType, "Parametrizer","mSetupType", false); + + // real params + if(getAttributeList()->exists("p_viscosity")) { + mcViscosity = mpAttrs->readChannelFloat("p_viscosity"); seenThis( PARAM_VISCOSITY ); } + + mSoundSpeed = mpAttrs->readFloat("p_soundspeed",mSoundSpeed, "Parametrizer","mSoundSpeed", false); + if(getAttributeList()->exists("p_soundspeed")) seenThis( PARAM_SOUNDSPEED ); + + mDomainSize = mpAttrs->readFloat("p_domainsize",mDomainSize, "Parametrizer","mDomainSize", false); + if(getAttributeList()->exists("p_domainsize")) seenThis( PARAM_DOMAINSIZE ); + if(mDomainSize<=0.0) { + errMsg("Parametrizer::parseAttrList","Invalid real world domain size:"<exists("p_gravity")) { // || (!mcGravity.isInited()) ) { + mcGravity = mpAttrs->readChannelVec3d("p_gravity"); seenThis( PARAM_GRAVITY ); + } + + mTimestep = mpAttrs->readFloat("p_steptime",mTimestep, "Parametrizer","mTimestep", false); + if(getAttributeList()->exists("p_steptime")) seenThis( PARAM_STEPTIME ); + + mTimeFactor = mpAttrs->readFloat("p_timefactor",mTimeFactor, "Parametrizer","mTimeFactor", false); + if(getAttributeList()->exists("p_timefactor")) seenThis( PARAM_TIMEFACTOR ); + + if(getAttributeList()->exists("p_aniframetime")) { //|| (!mcAniFrameTime.isInited()) ) { + mcAniFrameTime = mpAttrs->readChannelFloat("p_aniframetime");seenThis( PARAM_ANIFRAMETIME ); + } + mTimeStepScale = mpAttrs->readFloat("p_timestepscale",mTimeStepScale, "Parametrizer","mTimeStepScale", false); + + mAniStart = mpAttrs->readFloat("p_anistart",mAniStart, "Parametrizer","mAniStart", false); + if(getAttributeList()->exists("p_anistart")) seenThis( PARAM_ANISTART ); + if(mAniStart<0.0) { + errMsg("Parametrizer::parseAttrList","Invalid start time:"<readFloat("p_surfacetension",mSurfaceTension, "Parametrizer","mSurfaceTension", false); + //if(getAttributeList()->exists("p_surfacetension")) seenThis( PARAM_SURFACETENSION ); + + mDensity = mpAttrs->readFloat("p_density",mDensity, "Parametrizer","mDensity", false); + if(getAttributeList()->exists("p_density")) seenThis( PARAM_DENSITY ); + + ParamFloat cellSize = 0.0; // unused, deprecated + cellSize = mpAttrs->readFloat("p_cellsize",cellSize, "Parametrizer","cellSize", false); + + mGStar = mpAttrs->readFloat("p_gstar",mGStar, "Parametrizer","mGStar", false); + if(getAttributeList()->exists("p_gstar")) seenThis( PARAM_GSTAR ); + + mNormalizedGStar = mpAttrs->readFloat("p_normgstar",mNormalizedGStar, "Parametrizer","mNormalizedGStar", false); + if(getAttributeList()->exists("p_normgstar")) seenThis( PARAM_NORMALIZEDGSTAR ); + + mTadapMaxOmega = mpAttrs->readFloat("p_tadapmaxomega",mTadapMaxOmega, "Parametrizer","mTadapMaxOmega", false); + mTadapMaxSpeed = mpAttrs->readFloat("p_tadapmaxspeed",mTadapMaxSpeed, "Parametrizer","mTadapMaxSpeed", false); +} + +/****************************************************************************** + *! advance to next render/output frame + *****************************************************************************/ +void Parametrizer::setFrameNum(int frame) { + mFrameNum = frame; +#if DEBUG_PARAMCHANNELS>0 + errMsg("DEBUG_PARAMCHANNELS","setFrameNum frame-num="<0 +} +/*! get time of an animation frame (renderer) */ +// also used by: mpParam->getCurrentAniFrameTime() , e.g. for velocity dump +ParamFloat Parametrizer::getAniFrameTime( int frame ) { + double frametime = (double)frame; + ParamFloat anift = mcAniFrameTime.get(frametime); + if(anift<0.0) { + ParamFloat resetv = 0.; + errMsg("Parametrizer::setFrameNum","Invalid frame time:"<0 + if((0)|| (DEBUG_PARAMCHANNELS)) errMsg("DEBUG_PARAMCHANNELS","getAniFrameTime frame="<0 + return anift; +} + +/****************************************************************************** + * scale a given speed vector in m/s to lattice values + *****************************************************************************/ +ParamVec Parametrizer::calculateAddForce(ParamVec vec, string usage) +{ + ParamVec ret = vec * (mTimestep*mTimestep) /mCellSize; + debMsgStd("Parametrizer::calculateVector", DM_MSG, "scaled vector = "<0 + errMsg("DEBUG_PARAMCHANNELS","calculateLatticeViscosity viscStar="<0 + return viscStar; +} + +/*! get no of steps for the given length in seconds */ +int Parametrizer::calculateStepsForSecs( ParamFloat s ) { + return (int)(s/mTimestep); +} + +/*! get start time of animation */ +int Parametrizer::calculateAniStart( void ) { + return (int)(mAniStart/mTimestep); +} + +/*! get no of steps for a single animation frame */ +int Parametrizer::calculateAniStepsPerFrame(int frame) { + if(!checkSeenValues(PARAM_ANIFRAMETIME)) { + errFatal("Parametrizer::calculateAniStepsPerFrame", "Missing ani frame time argument!", SIMWORLD_INITERROR); + return 1; + } + int value = (int)(getAniFrameTime(frame)/mTimestep); + if((value<0) || (value>1000000)) { + errFatal("Parametrizer::calculateAniStepsPerFrame", "Invalid step-time (="< ani-frame-time ("<0.0) { gStar = mGStar/mFluidVolumeHeight; } + return gStar; +} + +/****************************************************************************** + * function that tries to calculate all the missing values from the given ones + * prints errors and returns false if thats not possible + *****************************************************************************/ +bool Parametrizer::calculateAllMissingValues( double time, bool silent ) +{ + bool init = false; // did we init correctly? + int valuesChecked = 0; + int reqValues; + + // we always need the sizes + reqValues = PARAM_SIZE; + valuesChecked |= reqValues; + if(!checkSeenValues(reqValues)) { + errMsg("Parametrizer::calculateAllMissingValues"," Missing size argument!"); + return false; + } + + if(!checkSeenValues(PARAM_DOMAINSIZE)) { + errMsg("Parametrizer::calculateAllMissingValues"," Missing domain size argument!"); + return false; + } + int maxsize = mSizex; // get max size + if(mSizey>maxsize) maxsize = mSizey; + if(mSizez>maxsize) maxsize = mSizez; + maxsize = mSizez; // take along gravity dir for now! + mCellSize = ( mDomainSize * calculateCellSize() ); // sets mCellSize + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," max domain resolution="<<(maxsize)<<" cells , cellsize="<0.0) { + debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," height"<0.0) { + // explicitly set step time according to max velocity in sim + setDeltaT = mDesiredTimestep; + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," desired step time = "<0)) { + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," ani start steps = "<(set); + seenThis( PARAM_VISCOSITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcViscosity set = "<< mcViscosity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} +void Parametrizer::initViscosityChannel(vector val, vector time) { + mcViscosity = AnimChannel(val,time); + seenThis( PARAM_VISCOSITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcViscosity initc = "<< mcViscosity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} + +/*! set the external force */ +void Parametrizer::setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz) { + mcGravity = AnimChannel(ParamVec(setx,sety,setz)); + seenThis( PARAM_GRAVITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcGravity set = "<< mcGravity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} +void Parametrizer::setGravity(ParamVec set) { + mcGravity = AnimChannel(set); + seenThis( PARAM_GRAVITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcGravity set = "<< mcGravity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} +void Parametrizer::initGravityChannel(vector val, vector time) { + mcGravity = AnimChannel(val,time); + seenThis( PARAM_GRAVITY ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcGravity initc = "<< mcGravity.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} + +/*! set time of an animation frame (renderer) */ +void Parametrizer::setAniFrameTimeChannel(ParamFloat set) { + mcAniFrameTime = AnimChannel(set); + seenThis( PARAM_ANIFRAMETIME ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcAniFrameTime set = "<< mcAniFrameTime.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} +void Parametrizer::initAniFrameTimeChannel(vector val, vector time) { + mcAniFrameTime = AnimChannel(val,time); + seenThis( PARAM_ANIFRAMETIME ); +#if DEBUG_PARAMCHANNELS>0 + { errMsg("DebugChannels","Parametrizer::mcAniFrameTime initc = "<< mcAniFrameTime.printChannel() ); } +#endif // DEBUG_PARAMCHANNELS>0 +} + +// OLD interface stuff +// reactivate at some point? + + /*! surface tension, [kg/s^2] */ + //ParamFloat mSurfaceTension; + /*! set starting time of the animation (renderer) */ + //void setSurfaceTension(ParamFloat set) { mSurfaceTension = set; seenThis( PARAM_SURFACETENSION ); } + /*! get starting time of the animation (renderer) */ + //ParamFloat getSurfaceTension( void ) { return mSurfaceTension; } + /*if((checkSeenValues(PARAM_SURFACETENSION))&&(mSurfaceTension>0.0)) { + ParamFloat massDelta = 1.0; + ParamFloat densityStar = 1.0; + massDelta = mDensity / densityStar *mCellSize*mCellSize*mCellSize; + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," massDelta = "<0.0) { + ParamFloat maxSpeed = 1.0/6.0; // for rough reynolds approx + ParamFloat reynoldsApprox = -1.0; + ParamFloat gridSpeed = (maxSpeed*mCellSize/mTimestep); + reynoldsApprox = (mDomainSize*gridSpeed) / mViscosity; + if(!silent) debMsgStd("Parametrizer::calculateAllMissingValues",DM_MSG," reynolds number (D="<readFloat("p_relaxtime",mRelaxTime, "Parametrizer","mRelaxTime", false); + //if(getAttributeList()->exists("p_relaxtime")) seenThis( PARAM_RELAXTIME ); + //? mReynolds = mpAttrs->readFloat("p_reynolds",mReynolds, "Parametrizer","mReynolds", false); + //if(getAttributeList()->exists("p_reynolds")) seenThis( PARAM_REYNOLDS ); + + //mViscosity = mpAttrs->readFloat("p_viscosity",mViscosity, "Parametrizer","mViscosity", false); + //if(getAttributeList()->exists("p_viscosity") || (!mcViscosity.isInited()) ) { } + //if(getAttributeList()->exists("p_viscosity")) + + + //ParamFloat viscStar = calculateLatticeViscosity(time); + //RelaxTime = (6.0 * viscStar + 1) * 0.5; + + diff --git a/intern/elbeem/intern/parametrizer.h b/intern/elbeem/intern/parametrizer.h new file mode 100644 index 00000000000..e05db129d77 --- /dev/null +++ b/intern/elbeem/intern/parametrizer.h @@ -0,0 +1,310 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Parameter calculator for the LBM Solver class + * + *****************************************************************************/ +#ifndef MFFSLBM_PARAMETRIZER +#define MFFSLBM_PARAMETRIZER + + +/* LBM Files */ +#include "utilities.h" +#include "attributes.h" + +/* parametrizer accuracy */ +typedef double ParamFloat; +typedef ntlVec3d ParamVec; + +/*! flags to check which values are known */ +#define PARAM_RELAXTIME (1<< 0) +#define PARAM_REYNOLDS (1<< 1) +#define PARAM_VISCOSITY (1<< 2) +#define PARAM_SOUNDSPEED (1<< 3) +#define PARAM_DOMAINSIZE (1<< 4) +#define PARAM_GRAVITY (1<< 5) +#define PARAM_STEPTIME (1<< 7) +#define PARAM_SIZE (1<< 8) +#define PARAM_TIMEFACTOR (1<< 9) +#define PARAM_ANIFRAMETIME (1<<11) +#define PARAM_ANISTART (1<<12) +#define PARAM_SURFACETENSION (1<<13) +#define PARAM_DENSITY (1<<14) +#define PARAM_GSTAR (1<<16) +#define PARAM_SIMMAXSPEED (1<<18) +#define PARAM_FLUIDVOLHEIGHT (1<<19) +#define PARAM_NORMALIZEDGSTAR (1<<20) +#define PARAM_NUMIDS 21 + +//! output parameter debug message? +//#define PARAM_DEBUG 1 + + + +/*! Parameter calculator for the LBM Solver class */ +class Parametrizer { + + public: + /*! default contructor */ + Parametrizer(); + + /*! destructor */ + ~Parametrizer(); + + /*! Initilize variables fom attribute list */ + void parseAttrList( void ); + + /*! function that tries to calculate all the missing values from the given ones + * prints errors and returns false if thats not possible + * currently needs time value as well */ + bool calculateAllMissingValues( double time, bool silent ); + /*! is the parametrizer used at all? */ + bool isUsed() { return true; } + + /*! add this flag to the seen values */ + void seenThis(int seen) { mSeenValues = (mSeenValues | seen); +#ifdef PARAM_DEBUG + errorOut(" seen "< val, vector time); + + /*! set the external force */ + void setGravity(ParamFloat setx, ParamFloat sety, ParamFloat setz); + void setGravity(ParamVec set); + void initGravityChannel(vector val, vector time); + ParamVec getGravity(double time) { return mcGravity.get( time ); } + + /*! set time of an animation frame (renderer) */ + void setAniFrameTimeChannel(ParamFloat set); + void initAniFrameTimeChannel(vector val, vector time); + + /*! set the length of a single time step */ + void setTimestep(ParamFloat set) { mTimestep = set; seenThis( PARAM_STEPTIME ); } + /*! get the length of a single time step */ + ParamFloat getTimestep( void); + /*! set a desired step time for rescaling/adaptive timestepping */ + void setDesiredTimestep(ParamFloat set) { mDesiredTimestep = set; } + /*! get the length of a single time step */ + ParamFloat getMaxTimestep( void ) { return mMaxTimestep; } + /*! get the length of a single time step */ + ParamFloat getMinTimestep( void ) { return mMinTimestep; } + + /*! set the time scaling factor */ + void setTimeFactor(ParamFloat set) { mTimeFactor = set; seenThis( PARAM_TIMEFACTOR ); } + /*! get the time scaling factor */ + ParamFloat getTimeFactor( void ) { return mTimeFactor; } + + /*! init domain resoultion */ + void setSize(int ijk) { mSizex = ijk; mSizey = ijk; mSizez = ijk; seenThis( PARAM_SIZE ); } + void setSize(int i,int j, int k) { mSizex = i; mSizey = j; mSizez = k; seenThis( PARAM_SIZE ); } + + /*! set starting time of the animation (renderer) */ + void setAniStart(ParamFloat set) { mAniStart = set; seenThis( PARAM_ANISTART ); } + /*! get starting time of the animation (renderer) */ + ParamFloat getAniStart( void ) { return mAniStart; } + + /*! set fluid density */ + void setDensity(ParamFloat set) { mDensity = set; seenThis( PARAM_DENSITY ); } + /*! get fluid density */ + ParamFloat getDensity( void ) { return mDensity; } + + /*! set g star value */ + void setGStar(ParamFloat set) { mGStar = set; seenThis( PARAM_GSTAR ); } + /*! get g star value */ + ParamFloat getGStar( void ) { return mGStar; } + /*! get g star value with fhvol calculations */ + ParamFloat getCurrentGStar( void ); + /*! set normalized g star value */ + void setNormalizedGStar(ParamFloat set) { mNormalizedGStar = set; seenThis( PARAM_NORMALIZEDGSTAR ); } + /*! get normalized g star value */ + ParamFloat getNormalizedGStar( void ) { return mNormalizedGStar; } + + /*! set g star value */ + void setFluidVolumeHeight(ParamFloat set) { mFluidVolumeHeight = set; seenThis( PARAM_FLUIDVOLHEIGHT ); } + /*! get g star value */ + ParamFloat getFluidVolumeHeight( void ) { return mFluidVolumeHeight; } + + /*! set the size of a single lbm cell */ + void setDomainSize(ParamFloat set) { mDomainSize = set; seenThis( PARAM_DOMAINSIZE ); } + /*! get the size of a single lbm cell */ + ParamFloat getDomainSize( void ) { return mDomainSize; } + + /*! set the size of a single lbm cell (dont use, normally set by domainsize and resolution) */ + void setCellSize(ParamFloat set) { mCellSize = set; } + /*! get the size of a single lbm cell */ + ParamFloat getCellSize( void ) { return mCellSize; } + + /*! set active flag for parametrizer */ + //void setActive(bool set) { mActive = set; } + + /*! set attr list pointer */ + void setAttrList(AttributeList *set) { mpAttrs = set; } + /*! Returns the attribute list pointer */ + inline AttributeList *getAttributeList() { return mpAttrs; } + + /*! set maximum allowed speed for maxspeed setup */ + void setSimulationMaxSpeed(ParamFloat set) { mSimulationMaxSpeed = set; seenThis( PARAM_SIMMAXSPEED ); } + /*! get maximum allowed speed for maxspeed setup */ + ParamFloat getSimulationMaxSpeed( void ) { return mSimulationMaxSpeed; } + + /*! set maximum allowed omega for time adaptivity */ + void setTadapMaxOmega(ParamFloat set) { mTadapMaxOmega = set; } + /*! get maximum allowed omega for time adaptivity */ + ParamFloat getTadapMaxOmega( void ) { return mTadapMaxOmega; } + + /*! set maximum allowed speed for time adaptivity */ + void setTadapMaxSpeed(ParamFloat set) { mTadapMaxSpeed = set; } + /*! get maximum allowed speed for time adaptivity */ + ParamFloat getTadapMaxSpeed( void ) { return mTadapMaxSpeed; } + + /*! set maximum allowed omega for time adaptivity */ + void setTadapLevels(int set) { mTadapLevels = set; } + /*! get maximum allowed omega for time adaptivity */ + int getTadapLevels( void ) { return mTadapLevels; } + + /*! set */ + // void set(ParamFloat set) { m = set; seenThis( PARAM_ ); } + /*! get */ + // ParamFloat get( void ) { return m; } + + + + private: + + /*! kinematic viscosity of the fluid [m^2/s] */ + AnimChannel mcViscosity; + + /*! speed of sound of the fluid [m/s] */ + ParamFloat mSoundSpeed; + + /*! size of the domain [m] */ + ParamFloat mDomainSize; + + /*! size of a single cell in the grid [m] */ + ParamFloat mCellSize; + + /*! time step length [s] */ + ParamFloat mTimeStep; + + /*! external force as acceleration [m/s^2] */ + AnimChannel mcGravity; + + /*! length of one time step in the simulation */ + ParamFloat mTimestep; + /*! desired step time for rescaling/adaptive timestepping, only regarded if >0.0, reset after usage */ + ParamFloat mDesiredTimestep; + /*! minimal and maximal step times for current setup */ + ParamFloat mMaxTimestep, mMinTimestep; + + /*! domain resoultion, the same values as in lbmsolver */ + int mSizex, mSizey, mSizez; + + /*! time scaling factor (auto calc from accel, or set), equals the delta t in LBM */ + ParamFloat mTimeFactor; + + /*! for renderer - length of an animation step [s] */ + AnimChannel mcAniFrameTime; + /*! time step scaling factor for testing/debugging */ + ParamFloat mTimeStepScale; + + /*! for renderer - start time of the animation [s] */ + ParamFloat mAniStart; + + /*! extent of the domain in meters */ + //ParamVec mExtent; + + /*! fluid density [kg/m^3], default 1.0 g/cm^3 */ + ParamFloat mDensity; + + /*! max difference due to gravity (for caro setup) */ + ParamFloat mGStar; + /*! set gstar normalized! */ + ParamFloat mNormalizedGStar; + /*! fluid volume/height multiplier for GStar */ + ParamFloat mFluidVolumeHeight; + + /*! current max speed of the simulation (for adaptive time steps) */ + ParamFloat mSimulationMaxSpeed; + /*! maximum omega (for adaptive time steps) */ + ParamFloat mTadapMaxOmega; + /*! maximum allowed speed in lattice units e.g. 0.1 (for adaptive time steps, not directly used in parametrizer) */ + ParamFloat mTadapMaxSpeed; + /*! no. of levels for max omega (set by fsgr, not in cfg file) */ + int mTadapLevels; + + /*! remember current frame number */ + int mFrameNum; + + /*! values that are seen for this simulation */ + int mSeenValues; + + /*! values that are calculated from the seen ones for this simulation */ + int mCalculatedValues; + + /*! pointer to the attribute list */ + AttributeList *mpAttrs; +}; + + +#endif + diff --git a/intern/elbeem/intern/particletracer.cpp b/intern/elbeem/intern/particletracer.cpp new file mode 100644 index 00000000000..c9da808543a --- /dev/null +++ b/intern/elbeem/intern/particletracer.cpp @@ -0,0 +1,468 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Particle Viewer/Tracer + * + *****************************************************************************/ + +#include +//#include "../libs/my_gl.h" +//#include "../libs/my_glu.h" + +/* own lib's */ +#include "particletracer.h" +#include "ntl_matrices.h" +#include "ntl_ray.h" +#include "ntl_matrices.h" + +#include + + +// particle object id counter +int ParticleObjectIdCnt = 1; + +/****************************************************************************** + * Standard constructor + *****************************************************************************/ +ParticleTracer::ParticleTracer() : + ntlGeometryObject(), + mParts(), + //mTrailLength(1), mTrailInterval(1),mTrailIntervalCounter(0), + mPartSize(0.01), + mStart(-1.0), mEnd(1.0), + mSimStart(-1.0), mSimEnd(1.0), + mPartScale(0.1) , mPartHeadDist( 0.1 ), mPartTailDist( -0.1 ), mPartSegments( 4 ), + mValueScale(0), + mValueCutoffTop(0.0), mValueCutoffBottom(0.0), + mDumpParts(0), //mDumpText(0), + mDumpTextFile(""), + mDumpTextInterval(0.), mDumpTextLastTime(0.), mDumpTextCount(0), + mShowOnly(0), + mNumInitialParts(0), mpTrafo(NULL), + mInitStart(-1.), mInitEnd(-1.), + mPrevs(), mTrailTimeLast(0.), mTrailInterval(-1.), mTrailLength(0) +{ + debMsgStd("ParticleTracer::ParticleTracer",DM_MSG,"inited",10); +}; + +ParticleTracer::~ParticleTracer() { + debMsgStd("ParticleTracer::~ParticleTracer",DM_MSG,"destroyed",10); +} + +/*****************************************************************************/ +//! parse settings from attributes (dont use own list!) +/*****************************************************************************/ +void ParticleTracer::parseAttrList(AttributeList *att) +{ + AttributeList *tempAtt = mpAttrs; + mpAttrs = att; + + mNumInitialParts = mpAttrs->readInt("particles",mNumInitialParts, "ParticleTracer","mNumInitialParts", false); + //errMsg(" NUMP"," "<readFloat("part_scale",mPartScale, "ParticleTracer","mPartScale", false); + mPartHeadDist = mpAttrs->readFloat("part_headdist",mPartHeadDist, "ParticleTracer","mPartHeadDist", false); + mPartTailDist = mpAttrs->readFloat("part_taildist",mPartTailDist, "ParticleTracer","mPartTailDist", false); + mPartSegments = mpAttrs->readInt ("part_segments",mPartSegments, "ParticleTracer","mPartSegments", false); + mValueScale = mpAttrs->readInt ("part_valscale",mValueScale, "ParticleTracer","mValueScale", false); + mValueCutoffTop = mpAttrs->readFloat("part_valcutofftop",mValueCutoffTop, "ParticleTracer","mValueCutoffTop", false); + mValueCutoffBottom = mpAttrs->readFloat("part_valcutoffbottom",mValueCutoffBottom, "ParticleTracer","mValueCutoffBottom", false); + + mDumpParts = mpAttrs->readInt ("part_dump",mDumpParts, "ParticleTracer","mDumpParts", false); + // mDumpText deprecatd, use mDumpTextInterval>0. instead + mShowOnly = mpAttrs->readInt ("part_showonly",mShowOnly, "ParticleTracer","mShowOnly", false); + mDumpTextFile= mpAttrs->readString("part_textdumpfile",mDumpTextFile, "ParticleTracer","mDumpTextFile", false); + mDumpTextInterval= mpAttrs->readFloat("part_textdumpinterval",mDumpTextInterval, "ParticleTracer","mDumpTextInterval", false); + + string matPart; + matPart = mpAttrs->readString("material_part", "default", "ParticleTracer","material", false); + setMaterialName( matPart ); + + mInitStart = mpAttrs->readFloat("part_initstart",mInitStart, "ParticleTracer","mInitStart", false); + mInitEnd = mpAttrs->readFloat("part_initend", mInitEnd, "ParticleTracer","mInitEnd", false); + + // unused... + //int mTrailLength = 0; // UNUSED + //int mTrailInterval= 0; // UNUSED + mTrailLength = mpAttrs->readInt("traillength",mTrailLength, "ParticleTracer","mTrailLength", false); + mTrailInterval= mpAttrs->readFloat("trailinterval",mTrailInterval, "ParticleTracer","mTrailInterval", false); + + // restore old list + mpAttrs = tempAtt; +} + +/****************************************************************************** + * draw the particle array + *****************************************************************************/ +void ParticleTracer::draw() +{ +} + +/****************************************************************************** + * init trafo matrix + *****************************************************************************/ +void ParticleTracer::initTrafoMatrix() { + ntlVec3Gfx scale = ntlVec3Gfx( + (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), + (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), + (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2]) + ); + ntlVec3Gfx trans = mStart; + if(!mpTrafo) mpTrafo = new ntlMat4Gfx(0.0); + mpTrafo->initId(); + for(int i=0; i<3; i++) { mpTrafo->value[i][i] = scale[i]; } + for(int i=0; i<3; i++) { mpTrafo->value[i][3] = trans[i]; } +} + +/****************************************************************************** + * adapt time step by rescaling velocities + *****************************************************************************/ +void ParticleTracer::adaptPartTimestep(float factor) { + for(size_t i=0; i0.) { errMsg("ParticleTracer::cleanup","Skipping cleanup due to text dump..."); return; } + + for(int i=0; i<=last; i++) { + if( mParts[i].getActive()==false ) { + ParticleObject *p = &mParts[i]; + ParticleObject *p2 = &mParts[last]; + *p = *p2; last--; mParts.pop_back(); + } + } +} + +extern bool glob_mpactive; +extern int glob_mpindex,glob_mpnum; + +/****************************************************************************** + *! dump particles if desired + *****************************************************************************/ +void ParticleTracer::notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime) { + debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"obj:"<getName()<<" frame:"<0)) { + // dump to binary file + std::ostringstream boutfilename(""); + boutfilename << outfilename <<"_particles_" << frameNrStr; + if(glob_mpactive) { + if(glob_mpindex>0) { boutfilename << "mp"<getName() <<", particles:"<getType(); // export whole type info + int type = p->getFlags(); // debug export whole type & status info + ntlVec3Gfx pos = p->getPos(); + float size = p->getSize(); + + if(type&PART_FLOAT) { // WARNING same handling for dump! + // add one gridcell offset + //pos[2] += 1.0; + } + // display as drop for now externally + //else if(type&PART_TRACER) { type |= PART_DROP; } + + pos = (*mpTrafo) * pos; + + ntlVec3Gfx v = p->getVel(); + v[0] *= mpTrafo->value[0][0]; + v[1] *= mpTrafo->value[1][1]; + v[2] *= mpTrafo->value[2][2]; + // FIXME check: pos = (*mpTrafo) * pos; + gzwrite(gzf, &type, sizeof(type)); + gzwrite(gzf, &size, sizeof(size)); + for(int j=0; j<3; j++) { gzwrite(gzf, &pos[j], sizeof(float)); } + for(int j=0; j<3; j++) { gzwrite(gzf, &v[j], sizeof(float)); } + } + gzclose( gzf ); + } + } // dump? +} + +void ParticleTracer::checkDumpTextPositions(double simtime) { + // dfor partial & full dump + if(mDumpTextInterval>0.) { + debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"t="<0.) && (simtime>mDumpTextLastTime+mDumpTextInterval)) { + // dump to binary file + std::ostringstream boutfilename(""); + if(mDumpTextFile.length()>1) { + boutfilename << mDumpTextFile << ".cpart2"; + } else { + boutfilename << boutfilename <<"_particles" << ".cpart2"; + } + debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"T-Dumping: "<< this->getName() <<", particles:"<getPos(); + float size = p->getSize(); + float infl = 1.; + //if(!mParts[i].getActive()) { size=0.; } // switch "off" + if(!mParts[i].getActive()) { infl=0.; } // switch "off" + if(!mParts[i].getInFluid()) { infl=0.; } // switch "off" + if(mParts[i].getLifeTime()<0.) { infl=0.; } // not yet active... + + pos = (*mpTrafo) * pos; + ntlVec3Gfx v = p->getVel(); + v[0] *= mpTrafo->value[0][0]; + v[1] *= mpTrafo->value[1][1]; + v[2] *= mpTrafo->value[2][2]; + + fprintf( stf, "P %f %f %f \n", pos[0],pos[1],pos[2] ); + if(size!=1.0) fprintf( stf, "s %f \n", size ); + if(infl!=1.0) fprintf( stf, "i %f \n", infl ); + fprintf( stf, "\n" ); + } + + fprintf( stf, "# %d end ", mDumpTextCount ); + //gzclose( gzf ); + fclose( stf ); + + mDumpTextCount++; + } + + mDumpTextLastTime += mDumpTextInterval; + } + +} + + +void ParticleTracer::checkTrails(double time) { + if(mTrailLength<1) return; + if(time-mTrailTimeLast > mTrailInterval) { + + if( (int)mPrevs.size() < mTrailLength) mPrevs.resize( mTrailLength ); + for(int i=mPrevs.size()-1; i>0; i--) { + mPrevs[i] = mPrevs[i-1]; + //errMsg("TRAIL"," from "< *triangles, + vector *vertices, + vector *normals, int objectId ) +{ +#ifdef ELBEEM_PLUGIN + // suppress warnings... + vertices = NULL; triangles = NULL; + normals = NULL; objectId = 0; + time = 0.0; +#else // ELBEEM_PLUGIN + int pcnt = 0; + // currently not used in blender + objectId = 0; // remove, deprecated + if(mDumpParts>1) { + return; // only dump, no tri-gen + } + + const bool debugParts = false; + int tris = 0; + int segments = mPartSegments; + ntlVec3Gfx scale = ntlVec3Gfx( (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])); + ntlVec3Gfx trans = mStart; + time = 0.; // doesnt matter + + for(size_t t=0; t *dparts; + if(t==0) { + dparts = &mParts; + } else { + dparts = &mPrevs[t-1]; + } + //errMsg("TRAILT","prevs"<size() ); + + gfxReal partscale = mPartScale; + if(t>1) { + partscale *= (gfxReal)(mPrevs.size()+1-t) / (gfxReal)(mPrevs.size()+1); + } + gfxReal partNormSize = 0.01 * partscale; + //for(size_t i=0; isize(); i++) { + ParticleObject *p = &( (*dparts)[i] ); // mParts[i]; + + if(mShowOnly!=10) { + // 10=show only deleted + if( p->getActive()==false ) continue; + } else { + if( p->getActive()==true ) continue; + } + int type = p->getType(); + if(mShowOnly>0) { + switch(mShowOnly) { + case 1: if(!(type&PART_BUBBLE)) continue; break; + case 2: if(!(type&PART_DROP)) continue; break; + case 3: if(!(type&PART_INTER)) continue; break; + case 4: if(!(type&PART_FLOAT)) continue; break; + case 5: if(!(type&PART_TRACER)) continue; break; + } + } else { + // by default dont display inter + if(type&PART_INTER) continue; + } + + pcnt++; + ntlVec3Gfx pnew = p->getPos(); + if(type&PART_FLOAT) { // WARNING same handling for dump! + if(p->getStatus()&PART_IN) { pnew[2] += 0.8; } // offset for display + // add one gridcell offset + //pnew[2] += 1.0; + } +#if LBMDIM==2 + pnew[2] += 0.001; // DEBUG + pnew[2] += 0.009; // DEBUG +#endif + + ntlVec3Gfx pdir = p->getVel(); + gfxReal plen = normalize( pdir ); + if( plen < 1e-05) pdir = ntlVec3Gfx(-1.0 ,0.0 ,0.0); + ntlVec3Gfx pos = (*mpTrafo) * pnew; + gfxReal partsize = 0.0; + if(debugParts) errMsg("DebugParts"," i"< class ntlMatrix4x4; + +// particle types +#define PART_BUBBLE (1<< 1) +#define PART_DROP (1<< 2) +#define PART_INTER (1<< 3) +#define PART_FLOAT (1<< 4) +#define PART_TRACER (1<< 5) + +// particle state +#define PART_IN (1<< 8) +#define PART_OUT (1<< 9) +#define PART_INACTIVE (1<<10) +#define PART_OUTFLUID (1<<11) + +// defines for particle movement +#define MOVE_FLOATS 1 +#define FLOAT_JITTER 0.03 +//#define FLOAT_JITTER 0.0 + +extern int ParticleObjectIdCnt; + +//! A single particle +class ParticleObject +{ + public: + //! Standard constructor + inline ParticleObject(ntlVec3Gfx mp) : + mPos(mp),mVel(0.0), mSize(1.0), mStatus(0),mLifeTime(0),mpNext(NULL) + { mId = ParticleObjectIdCnt++; }; + //! Copy constructor + inline ParticleObject(const ParticleObject &a) : + mPos(a.mPos), mVel(a.mVel), mSize(a.mSize), + mStatus(a.mStatus), + mLifeTime(a.mLifeTime), mpNext(NULL) + { mId = ParticleObjectIdCnt++; }; + //! Destructor + inline ~ParticleObject() { /* empty */ }; + + //! add vector to position + inline void advance(float vx, float vy, float vz) { + mPos[0] += vx; mPos[1] += vy; mPos[2] += vz; } + inline void advanceVec(ntlVec3Gfx v) { + mPos[0] += v[0]; mPos[1] += v[1]; mPos[2] += v[2]; } + //! advance with own velocity + inline void advanceVel() { mPos += mVel; } + //! add acceleration to velocity + inline void addToVel(ntlVec3Gfx acc) { mVel += acc; } + + //! get/set vector to position + inline ntlVec3Gfx getPos() { return mPos; } + inline void setPos(ntlVec3Gfx set) { mPos=set; } + //! set velocity + inline void setVel(ntlVec3Gfx set) { mVel = set; } + //! set velocity + inline void setVel(gfxReal x, gfxReal y, gfxReal z) { mVel = ntlVec3Gfx(x,y,z); } + //! get velocity + inline ntlVec3Gfx getVel() { return mVel; } + + //! get/set size value + inline gfxReal getSize() { return mSize; } + inline void setSize(gfxReal set) { mSize=set; } + + //! get/set next pointer + inline ParticleObject* getNext() { return mpNext; } + inline void setNext(ParticleObject* set) { mpNext=set; } + + //! get whole flags + inline int getFlags() const { return mStatus; } + //! get status (higher byte) + inline int getStatus() const { return (mStatus&0xFF00); } + //! set status (higher byte) + inline void setStatus(int set) { mStatus = set|(mStatus&0x00FF); } + //! get type (lower byte) + inline int getType() const { return (mStatus&0x00FF); } + //! set type (lower byte) + inline void setType(int set) { mStatus = set|(mStatus&0xFF00); } + //! get active flag + inline bool getActive() const { return ((mStatus&PART_INACTIVE)==0); } + //! set active flag + inline void setActive(bool set) { + if(set) mStatus &= (~PART_INACTIVE); + else mStatus |= PART_INACTIVE; + } + //! get influid flag + inline bool getInFluid() const { return ((mStatus&PART_OUTFLUID)==0); } + //! set influid flag + inline void setInFluid(bool set) { + if(set) mStatus &= (~PART_OUTFLUID); + else mStatus |= PART_OUTFLUID; + } + //! get/set lifetime + inline float getLifeTime() const { return mLifeTime; } + //! set type (lower byte) + inline void setLifeTime(float set) { mLifeTime = set; } + + inline int getId() const { return mId; } + + static inline float getMass(float size) { + return 4.0/3.0 * M_PI* (size)*(size)*(size); // mass: 4/3 pi r^3 rho + } + + protected: + + /*! only for debugging */ + int mId; + /*! the particle position */ + ntlVec3Gfx mPos; + /*! the particle velocity */ + ntlVec3Gfx mVel; + /*! size / mass of particle */ + gfxReal mSize; + /*! particle status */ + int mStatus; + /*! count survived time steps */ + float mLifeTime; + + /* for list constructions */ + ParticleObject *mpNext; +}; + + +//! A whole particle array +class ParticleTracer : + public ntlGeometryObject +{ + public: + //! Standard constructor + ParticleTracer(); + //! Destructor + ~ParticleTracer(); + + //! add a particle at this position + void addParticle(float x, float y, float z); + //! add/copy a particle from inited struct + void addFullParticle(ParticleObject &np); + + //! draw the particle array + void draw(); + + //! parse settings from attributes (dont use own list!) + void parseAttrList( AttributeList *att ); + + //! adapt time step by rescaling velocities + void adaptPartTimestep(float factor); + + // access funcs + + //! get the number of particles + inline int getNumParticles() { return mParts.size(); } + //! set/get the number of particles + inline void setNumInitialParticles(int set) { mNumInitialParts=set; } + inline int getNumInitialParticles() { return mNumInitialParts; } + + //! iterate over all newest particles (for advancing positions) + inline vector::iterator getParticlesBegin() { return mParts.begin(); } + //! end iterator for newest particles + inline vector::iterator getParticlesEnd() { return mParts.end(); } + //! end iterator for newest particles + inline ParticleObject* getLast() { return &(mParts[ mParts.size()-1 ]); } + + /*! set geometry start (for renderer) */ + inline void setStart(ntlVec3Gfx set) { mStart = set; initTrafoMatrix(); } + /*! set geometry end (for renderer) */ + inline void setEnd(ntlVec3Gfx set) { mEnd = set; initTrafoMatrix(); } + /*! get values */ + inline ntlVec3Gfx getStart() { return mStart; } + /*! set geometry end (for renderer) */ + inline ntlVec3Gfx getEnd() { return mEnd; } + + /*! set simulation domain start */ + inline void setSimStart(ntlVec3Gfx set) { mSimStart = set; initTrafoMatrix(); } + /*! set simulation domain end */ + inline void setSimEnd(ntlVec3Gfx set) { mSimEnd = set; initTrafoMatrix(); } + + /*! set/get dump flag */ + inline void setDumpParts(bool set) { mDumpParts = set; } + inline bool getDumpParts() { return mDumpParts; } + /*! set/get dump text file */ + inline void setDumpTextFile(string set) { mDumpTextFile = set; } + inline string getDumpTextFile() { return mDumpTextFile; } + /*! set/get dump text interval */ + inline void setDumpTextInterval(float set) { mDumpTextInterval = set; } + inline float getDumpTextInterval() { return mDumpTextInterval; } + /*! set/get init times */ + inline void setInitStart(float set) { mInitStart = set; } + inline float getInitStart() { return mInitStart; } + inline void setInitEnd(float set) { mInitEnd = set; } + inline float getInitEnd() { return mInitEnd; } + + //! set the particle scaling factor + inline void setPartScale(float set) { mPartScale = set; } + + //! called after each frame to check if positions should be dumped + void checkDumpTextPositions(double simtime); + + // NTL geometry implementation + /*! Get the triangles from this object */ + virtual void getTriangles(double t, vector *triangles, + vector *vertices, + vector *normals, int objectId ); + + virtual void notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename,double simtime); + + // notify of next step for trails + void checkTrails(double time); + // free deleted particles + void cleanup(); + + protected: + + /*! the particle array (for multiple timesteps) */ + vector mParts; + + /*! size of the particles to display */ + float mPartSize; + + /*! start and end vectors for the triangulation region to create particles in */ + ntlVec3Gfx mStart, mEnd; + + /*! start and end vectors of the simulation domain */ + ntlVec3Gfx mSimStart, mSimEnd; + + /*! scaling param for particles */ + float mPartScale; + /*! head and tail distance for particle shapes */ + float mPartHeadDist, mPartTailDist; + /*! no of segments for particle cone */ + int mPartSegments; + /*! use length/absval of values to scale particles? */ + int mValueScale; + /*! value length maximal cutoff value, for mValueScale==2 */ + float mValueCutoffTop; + /*! value length minimal cutoff value, for mValueScale==2 */ + float mValueCutoffBottom; + + /*! dump particles (or certain types of) to disk? */ + int mDumpParts; + /*! text dump output file */ + string mDumpTextFile; + /*! text dump interval, start at t=0, dumping active if >0 */ + float mDumpTextInterval; + float mDumpTextLastTime; + int mDumpTextCount; + /*! show only a certain type (debugging) */ + int mShowOnly; + /*! no. of particles to init */ + int mNumInitialParts; + + //! transform matrix + ntlMatrix4x4 *mpTrafo; + /*! init sim/pos transformation */ + void initTrafoMatrix(); + + //! init time distribution start/end + float mInitStart, mInitEnd; + + /*! the particle array (for multiple timesteps) */ + vector< vector > mPrevs; + /* prev pos save interval */ + float mTrailTimeLast, mTrailInterval; + int mTrailLength; +}; + +#define NTL_PARTICLETRACER_H +#endif + diff --git a/intern/elbeem/intern/simulation_object.cpp b/intern/elbeem/intern/simulation_object.cpp new file mode 100644 index 00000000000..2ff600a36d4 --- /dev/null +++ b/intern/elbeem/intern/simulation_object.cpp @@ -0,0 +1,458 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Basic interface for all simulation modules + * + *****************************************************************************/ + +#include "simulation_object.h" +#include "solver_interface.h" +#include "ntl_bsptree.h" +#include "ntl_ray.h" +#include "ntl_world.h" +#include "solver_interface.h" +#include "particletracer.h" +#include "elbeem.h" +#include /* exit(3) - also in linux */ + +#ifdef _WIN32 +#else +#include +#endif + + +//! lbm factory functions +LbmSolverInterface* createSolver(); + + +/****************************************************************************** + * Constructor + *****************************************************************************/ +SimulationObject::SimulationObject() : + ntlGeometryShader(), + mGeoStart(-100.0), mGeoEnd(100.0), + mpGiTree(NULL), mpGiObjects(NULL), + mpGlob(NULL), + mPanic( false ), + mDebugType( 1 /* =FLUIDDISPNothing*/ ), + mpLbm(NULL), mpParam( NULL ), + mShowSurface(true), mShowParticles(false), + mSelectedCid( NULL ), + mpElbeemSettings( NULL ) + +{ + mpParam = new Parametrizer(); + //for(int i=0; igetSimScene(); + mpGiObjects = scene->getObjects(); + + if(mpGiTree != NULL) delete mpGiTree; + char treeFlag = (1<<(mGeoInitId+4)); + mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here... + scene, treeFlag ); + exit(1); // unused!? overriden by solver interface +} + +/*****************************************************************************/ +/*! destroy tree etc. when geometry init done */ +/*****************************************************************************/ +void SimulationObject::freeGeoTree() { + if(mpGiTree != NULL) delete mpGiTree; +} + + + +// copy & remember settings for later use +void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) { + mpElbeemSettings = new elbeemSimulationSettings; + *mpElbeemSettings = *settings; + + mGeoInitId = settings->domainId+1; + debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<readString("solver", mSolverType, "SimulationObject","mSolverType", false ); + + mpLbm = createSolver(); + /* check lbm pointer */ + if(mpLbm == NULL) { + errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR); + return 2; + } + debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<getIdString() <<" LBM solver! ", 2); + + mpParts = new ParticleTracer(); + + // for non-param simulations + mpLbm->setParametrizer( mpParam ); + mpParam->setAttrList( getAttributeList() ); + // not needed.. done in solver_init: mpParam->setSize ... in solver_interface + mpParam->parseAttrList(); + + mpLbm->setAttrList( getAttributeList() ); + mpLbm->setSwsAttrList( getSwsAttributeList() ); + mpLbm->parseAttrList(); + mpParts->parseAttrList( getAttributeList() ); + + if(! isSimworldOk() ) return 3; + mpParts->setName( getName() + "_part" ); + mpParts->initialize( glob ); + if(! isSimworldOk() ) return 4; + + // init material settings + string matMc("default"); + matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false ); + mShowSurface = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false ); + mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false ); + + checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" ); + mpLbm->setLbmInitId( mGeoInitId ); + mpLbm->setGeoStart( mGeoStart ); + mpLbm->setGeoEnd( mGeoEnd ); + mpLbm->setRenderGlobals( mpGlob ); + mpLbm->setName( getName() + "_lbm" ); + mpLbm->setParticleTracer( mpParts ); + if(mpElbeemSettings) { + // set further settings from API struct init + if(mpElbeemSettings->outputPath) this->mOutFilename = string(mpElbeemSettings->outputPath); + mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo ); + mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing); + mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs); + mpLbm->setSizeX(mpElbeemSettings->resolutionxyz); + mpLbm->setSizeY(mpElbeemSettings->resolutionxyz); + mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz); + mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz); + mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine); + mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles); + // set initial particles + mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles); + + string dinitType = string("no"); + if (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part"); + else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free"); + else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no"); + mpLbm->setDomainBound(dinitType); + mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip); + mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors); + mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize); + debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<generateVertexVectors<<","<getDumpVelocities(), 9 ); + + debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<getGenerateParticles(),10); + } + + if(! mpLbm->initializeSolverMemory() ) { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; } + if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; } + if(! mpLbm->initializeSolverGrids() ) { errMsg("SimulationObject::initialize","initializeSolverGrids failed"); mPanic=true; return 12; } + if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids status"); mPanic=true; return 13; } + if(! mpLbm->initializeSolverPostinit() ) { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; } + if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; } + + // print cell type stats + bool printStats = true; + if(glob_mpnum>0) printStats=false; // skip in this case + if(printStats) { + const int jmax = sizeof(CellFlagType)*8; + int totalCells = 0; + int flagCount[jmax]; + for(int j=0; jgetFirstCell(); + for(; mpLbm->noEndCell( cid ); + mpLbm->advanceCell( cid ) ) { + int flag = mpLbm->getCellFlag(cid,0); + int flag2 = mpLbm->getCellFlag(cid,1); + if(flag != flag2) { + diffInits++; + } + for(int j=0; jdeleteCellIterator( &cid ); + + char charNl = '\n'; + debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <0) { + out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1< 0) { + debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<setStart( mGeoStart );? mpParts->setEnd( mGeoEnd );? + mpParts->setStart( mpLbm->getGeoStart() ); + mpParts->setEnd( mpLbm->getGeoEnd() ); + mpParts->setCastShadows( false ); + mpParts->setReceiveShadows( false ); + mpParts->searchMaterial( glob->getMaterials() ); + + // this has to be inited here - before, the values might be unknown + IsoSurface *surf = mpLbm->getSurfaceGeoObj(); + if(surf) { + surf->setName( "final" ); // final surface mesh + // warning - this might cause overwriting effects for multiple sims and geom dump... + surf->setCastShadows( true ); + surf->setReceiveShadows( false ); + surf->searchMaterial( glob->getMaterials() ); + if(mShowSurface) mObjects.push_back( surf ); + } + +#ifdef ELBEEM_PLUGIN + mShowParticles=1; // for e.g. dumping +#endif // ELBEEM_PLUGIN + if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) { + mShowParticles=1; + mpParts->setDumpParts(true); + } + //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1); + //} // DEBUG ENABLE!!!!!!!!!! + if(mShowParticles) { + mObjects.push_back(mpParts); + } + + // add objects to display for debugging (e.g. levelset particles) + vector debugObjs = mpLbm->getDebugObjects(); + for(size_t i=0;isetCastShadows( false ); + debugObjs[i]->setReceiveShadows( false ); + debugObjs[i]->searchMaterial( glob->getMaterials() ); + mObjects.push_back( debugObjs[i] ); + debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<getName(), 10 ); + } + return 0; +} + +/*! set current frame */ +void SimulationObject::setFrameNum(int num) { + // advance parametrizer + mpParam->setFrameNum(num); +} + +/****************************************************************************** + * simluation interface: advance simulation another step (whatever delta time that might be) + *****************************************************************************/ +void SimulationObject::step( void ) +{ + if(mpParam->getCurrentAniFrameTime()>0.0) { + // dont advance for stopped time + mpLbm->step(); + mTime += mpParam->getTimestep(); +//if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); exit(1); } // PROFILE DEBUG TEST! + } + if(mpLbm->getPanic()) mPanic = true; + + checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0); + //if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) { + //int ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, FLUIDSIM_CBSTATUS_STEP, 0); + //errMsg("runSimulationCallback cbtest1"," "<getName()<<" ret="<prepareVisualization(); +} + + +/******************************************************************************/ +/* get current start simulation time */ +double SimulationObject::getStartTime( void ) { + //return mpParam->calculateAniStart(); + return mpParam->getAniStart(); +} +/* get time for a single animation frame */ +double SimulationObject::getFrameTime( int frame ) { + return mpParam->getAniFrameTime(frame); +} +/* get time for a single time step */ +double SimulationObject::getTimestep( void ) { + return mpParam->getTimestep(); +} + + +/****************************************************************************** + * return a pointer to the geometry object of this simulation + *****************************************************************************/ +//ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; } +vector::iterator +SimulationObject::getObjectsBegin() +{ + return mObjects.begin(); +} +vector::iterator +SimulationObject::getObjectsEnd() +{ + return mObjects.end(); +} + + + + + +/****************************************************************************** + * GUI - display debug info + *****************************************************************************/ + +void SimulationObject::drawDebugDisplay() { +#ifndef NOGUI + if(!getVisible()) return; + + //if( mDebugType > (MAX_DEBDISPSET-1) ){ errFatal("SimulationObject::drawDebugDisplay","Invalid debug type!", SIMWORLD_GENERICERROR); return; } + //mDebDispSet[ mDebugType ].on = true; + //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type ); + mpLbm->debugDisplay( mDebugType ); + + //::lbmMarkedCellDisplay<>( mpLbm ); + mpLbm->lbmMarkedCellDisplay(); +#endif +} + +/* GUI - display interactive info */ +void SimulationObject::drawInteractiveDisplay() +{ +#ifndef NOGUI + if(!getVisible()) return; + if(mSelectedCid) { + // in debugDisplayNode if dispset is on is ignored... + mpLbm->debugDisplayNode( FLUIDDISPGrid, mSelectedCid ); + } +#endif +} + + +/*******************************************************************************/ +// GUI - handle mouse movement for selection +/*******************************************************************************/ +void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir) +{ + normalize( dir ); + // assume 2D sim is in XY plane... + + double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5; + double zt = (zplane-org[2]) / dir[2]; + ntlVec3Gfx pos( + org[0]+ dir[0] * zt, + org[1]+ dir[1] * zt, 0.0); + + mSelectedCid = mpLbm->getCellAt( pos ); + //errMsg("SMP ", mName<< x<<" "<( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() ); + mpLbm->debugPrintNodeInfo( mSelectedCid ); + } +} + +/*! notify object that dump is in progress (e.g. for field dump) */ +void SimulationObject::notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) { + if(!mpLbm) return; + + mpLbm->notifySolverOfDump(dumptype, frameNr,frameNrStr,outfilename); + checkCallerStatus(FLUIDSIM_CBSTATUS_NEWFRAME, frameNr); +} + +/*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */ +int SimulationObject::checkCallerStatus(int status, int frame) { + //return 0; // DEBUG + int ret = 0; + if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) { + ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame); + if(ret!=FLUIDSIM_CBRET_CONTINUE) { + if(ret==FLUIDSIM_CBRET_STOP) { + debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1); + setElbeemState( SIMWORLD_STOP ); + } + else if(ret==FLUIDSIM_CBRET_ABORT) { + errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR ); + mPanic = 1; + } + else { + errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<getName()<<" ret="<::iterator getObjectsBegin(); + virtual vector::iterator getObjectsEnd(); + + + /*! simluation interface: advance simulation another step (whatever delta time that might be) */ + virtual void step( void ); + /*! prepare visualization of simulation for e.g. raytracing */ + virtual void prepareVisualization( void ); + + /*! GUI - display debug info */ + virtual void drawDebugDisplay(); + /*! GUI - display interactive info */ + virtual void drawInteractiveDisplay(); + /*! GUI - handle mouse movement for selection */ + virtual void setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir); + virtual void setMouseClick(); + + /*! get current start simulation time */ + double getStartTime( void ); + /*! get time for a single animation frame */ + double getFrameTime( int frame ); + /*! get time for a single time step in the simulation */ + double getTimestep( void ); + + //! access solver + LbmSolverInterface *getSolver(){ return mpLbm; } + + protected: + + /*! current time in the simulation */ + double mTime; + + /*! for display - start and end vectors for geometry */ + ntlVec3Gfx mGeoStart, mGeoEnd; + + /*! geometry init id */ + //? int mGeoInitId; + /*! tree object for geomerty initialization */ + ntlTree *mpGiTree; + /*! object vector for geo init */ + vector *mpGiObjects; + /*! remember globals */ + ntlRenderGlobals *mpGlob; + + /*! simulation panic on/off */ + bool mPanic; + + /*! debug info to display */ + int mDebugType; + + /*! pointer to the lbm solver */ + LbmSolverInterface *mpLbm; + + /*! parametrizer for lbm solver */ + Parametrizer *mpParam; + + /*! particle tracing object */ + ParticleTracer *mpParts; + + /*! show parts of the simulation toggles */ + bool mShowSurface; + bool mShowParticles; + + /*! debug display settings */ + int mDebDispSetting; + + /*! pointer to identifier of selected node */ + CellIdentifierInterface *mSelectedCid; + + /*! storage of API settings */ + elbeemSimulationSettings *mpElbeemSettings; + + public: + + // debug display setting funtions + + /*! set type of info to display */ + inline void setDebugDisplay(int disp) { mDebugType = disp; } + inline int getDebugDisplay() { return mDebugType; } + + /* miscelleanous access functions */ + + /*! init parametrizer for anim step length */ + void initParametrizer(Parametrizer *set) { mpParam = set; } + /*! init parametrizer for anim step length */ + Parametrizer *getParametrizer() { return mpParam; } + + /*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */ + // parameters same as elbeem runsimCallback + int checkCallerStatus(int status, int frame); + + /*! get bounding box of fluid for GUI */ + virtual inline ntlVec3Gfx *getBBStart() { return &mGeoStart; } + virtual inline ntlVec3Gfx *getBBEnd() { return &mGeoEnd; } + +}; + + +#endif + + + diff --git a/intern/elbeem/intern/solver_adap.cpp b/intern/elbeem/intern/solver_adap.cpp new file mode 100644 index 00000000000..ef516a578bd --- /dev/null +++ b/intern/elbeem/intern/solver_adap.cpp @@ -0,0 +1,1279 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Adaptivity functions + * + *****************************************************************************/ + +#include "solver_class.h" +#include "solver_relax.h" +#include "particletracer.h" + + + +/*****************************************************************************/ +//! coarse step functions +/*****************************************************************************/ + + + +void LbmFsgrSolver::coarseCalculateFluxareas(int lev) +{ + FSGR_FORIJK_BOUNDS(lev) { + if( RFLAG(lev, i,j,k,mLevel[lev].setCurr) & CFFluid) { + if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & CFGrFromCoarse) { + LbmFloat totArea = mFsgrCellArea[0]; // for l=0 + for(int l=1; lcDirNum; l++) { + int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, mLevel[lev+1].setCurr)& + (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused) + ) { + totArea += mFsgrCellArea[l]; + } + } // l + QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = totArea; + //continue; + } else + if( RFLAG(lev+1, i*2,j*2,k*2,mLevel[lev+1].setCurr) & (CFEmpty|CFUnused)) { + QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 1.0; + //continue; + } else { + QCELL(lev, i,j,k,mLevel[lev].setCurr, dFlux) = 0.0; + } + //errMsg("DFINI"," at l"<mSilent){ debMsgStd("coarseCalculateFluxareas",DM_MSG,"level "<getName().c_str(),"Debug")){ errMsg("DEBUG","DEBUG!!!!!!!!!!!!!!!!!!!!!!!"); } + + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;j remove + if( ((*pFlagSrc) & (CFGrFromCoarse)) ) { + bool invNb = false; + FORDF1 { if(RFLAG_NB(lev, i, j, k, SRCS(lev), l) & CFUnused) { invNb = true; } } + if(!invNb) { + // WARNING - this modifies source flag array... + *pFlagSrc = CFFluid|CFGrNorm; +#if ELBEEM_PLUGIN!=1 + errMsg("coarseAdvance","FC2NRM_CHECK Converted CFGrFromCoarse to Norm at "<mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) { + FORDF0 { RAC(tcel,l) = RAC(ccel,l); } + } else { + interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false); + this->mNumUsedCells++; + } + continue; // interpolateFineFromCoarse test! + } // interpolateFineFromCoarse test! old INTCFCOARSETEST==1 + + if( ((*pFlagSrc) & (CFFluid)) ) { + ccel = RACPNT(lev, i,j,k ,SRCS(lev)); + tcel = RACPNT(lev, i,j,k ,TSET(lev)); + + if( ((*pFlagSrc) & (CFGrFromFine)) ) { + FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...? + continue; // comes from fine grid + } + // also ignore CFGrFromCoarse + else if( ((*pFlagSrc) & (CFGrFromCoarse)) ) { + FORDF0 { RAC(tcel,l) = RAC(ccel,l); } // always copy...? + continue; + } + + OPTIMIZED_STREAMCOLLIDE; + *pFlagDst |= CFNoBndFluid; // test? + calcCurrentVolume += RAC(ccel,dFlux); + calcCurrentMass += RAC(ccel,dFlux)*rho; + //ebugMarkCell(lev+1, 2*i+1,2*j+1,2*k ); +#if FSGR_STRICT_DEBUG==1 + if(rho<-1.0){ debugMarkCell(lev, i,j,k ); + errMsg("INVRHOCELL_CHECK"," l"<mNumUsedCells++; + + } + } + pFlagSrc+=2; // after x + pFlagDst+=2; // after x + ccel += (QCELLSTEP*2); + tcel += (QCELLSTEP*2); + } + pFlagSrc+= mLevel[lev].lSizex*2; // after y + pFlagDst+= mLevel[lev].lSizex*2; // after y + ccel += (QCELLSTEP*mLevel[lev].lSizex*2); + tcel += (QCELLSTEP*mLevel[lev].lSizex*2); + } // all cell loop k,j,i + + + //errMsg("coarseAdvance","level "<mSilent){ errMsg("coarseAdvance","level "<mNumUsedCells++; + } // from fine & fluid + else { + if(RFLAG(lev+1, 2*i,2*j,2*k,srcSet) & CFGrFromCoarse) { + RFLAG(lev, i,j,k,dstSet) |= CFGrToFine; + } else { + RFLAG(lev, i,j,k,dstSet) &= (~CFGrToFine); + } + } + } // & fluid + }}} + if(!this->mSilent){ errMsg("coarseRestrictFromFine"," from l"<<(lev+1)<<",s"<mMaxRefine)) return false; + bool change = false; + { // refinement, PASS 1-3 + + //bool nbsok; + // FIXME remove TIMEINTORDER ? + LbmFloat interTime = 0.0; + // update curr from other, as streaming afterwards works on curr + // thus read only from srcSet, modify other + const int srcSet = mLevel[lev].setOther; + const int dstSet = mLevel[lev].setCurr; + const int srcFineSet = mLevel[lev+1].setCurr; + const bool debugRefinement = false; + + // use //template functions for 2D/3D + /*if(strstr(this->getName().c_str(),"Debug")) + if(lev+1==mMaxRefine) { // mixborder + for(int l=0;((lcDirNum) && (!removeFromFine)); l++) { // FARBORD + int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, srcFineSet)&CFBnd) { // NEWREFT + removeFromFine=true; + } + } + } // FARBORD */ + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;jcDirNum; l++) { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + //errMsg("performRefinement","On lev:"< remove + + if(RFLAG(lev, i,j,k, srcSet) & CFGrFromCoarse) { + + // from coarse cells without unused nbs are not necessary...! -> remove + bool invNb = false; + bool fluidNb = false; + for(int l=1; lcDirNum; l++) { + if(RFLAG_NB(lev, i, j, k, srcSet, l) & CFUnused) { invNb = true; } + if(RFLAG_NB(lev, i, j, k, srcSet, l) & (CFGrNorm)) { fluidNb = true; } + } + if(!invNb) { + // no unused cells around -> calculate normally from now on + RFLAG(lev, i,j,k, dstSet) = CFFluid|CFGrNorm; + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k); + change=true; + mNumFsgrChanges++; + } // from advance + if(!fluidNb) { + // no fluid cells near -> no transfer necessary + RFLAG(lev, i,j,k, dstSet) = CFUnused; + //RFLAG(lev, i,j,k, mLevel[lev].setOther) = CFUnused; // FLAGTEST + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k); + change=true; + mNumFsgrChanges++; + } // from advance + + + // dont allow double transfer + // this might require fixing the neighborhood + if(RFLAG(lev+1, 2*i,2*j,2*k, srcFineSet)&(CFGrFromCoarse)) { + // dont turn CFGrFromFine above interface cells into CFGrNorm + //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<0) RFLAG(lev-1, i/2,j/2,k/2, mLevel[lev-1].setCurr) &= (~CFGrToFine); // TODO add more of these? + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev, i, j, k); + change=true; + mNumFsgrChanges++; + for(int l=1; lcDirNum; l++) { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if(RFLAG(lev, ni,nj,nk, srcSet)&(CFGrNorm)) { //ok + for(int m=1; mcDirNum; m++) { + int mi= ni +this->dfVecX[m], mj= nj +this->dfVecY[m], mk= nk +this->dfVecZ[m]; + if(RFLAG(lev, mi, mj, mk, srcSet)&CFUnused) { + // norm cells in neighborhood with unused nbs have to be new border... + RFLAG(lev, ni,nj,nk, dstSet) = CFFluid|CFGrFromCoarse; + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk); + } + } + // these alreay have valid values... + } + else if(RFLAG(lev, ni,nj,nk, srcSet)&(CFUnused)) { //ok + // this should work because we have a valid neighborhood here for now + interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, interTime, CFFluid|CFGrFromCoarse, false); + if((LBMDIM==2)&&(debugRefinement)) debugMarkCell(lev,ni,nj,nk); + mNumFsgrChanges++; + } + } // l + } // double transer + + } // from coarse + + } } } + // PASS 2 */ + + + // fix dstSet from fine cells here + // warning - checks CFGrFromFine on dstset changed before! + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { // TEST + for(int j=1;jcDirNum; l++) { + int bi=(2*i)+this->dfVecX[l], bj=(2*j)+this->dfVecY[l], bk=(2*k)+this->dfVecZ[l]; + if(RFLAG(lev+1, bi, bj, bk, srcFineSet)&(CFGrFromCoarse)) { + //errMsg("performRefinement","Removing CFGrFromCoarse on lev"<<(lev+1)<<" "<cDirNum; l++) { + int bi=(2*i)+this->dfVecX[l], bj=(2*j)+this->dfVecY[l], bk=(2*k)+this->dfVecZ[l]; + if( (RFLAG(lev+1, bi, bj, bk, srcFineSet)&CFFluid ) && + (!(RFLAG(lev+1, bi, bj, bk, srcFineSet)&CFGrFromCoarse)) ) { + // all unused nbs now of coarse have to be from coarse + for(int m=1; mcDirNum; m++) { + int mi= bi +this->dfVecX[m], mj= bj +this->dfVecY[m], mk= bk +this->dfVecZ[m]; + if(RFLAG(lev+1, mi, mj, mk, srcFineSet)&CFUnused) { + //errMsg("performRefinement","Changing CFUnused on lev"<<(lev+1)<<" "<mSilent){ errMsg("performRefinement"," for l"<mInitDone) { + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;j from fine conversion + bool changeToFromFine = false; + const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine); + CellFlagType reqType = CFGrNorm; + if(lev+1==mMaxRefine) reqType = CFNoBndFluid; + if( (RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & reqType) && + (!(RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & (notAllowed)) ) ){ + changeToFromFine=true; } + if(changeToFromFine) { + change = true; + mNumFsgrChanges++; + RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrFromFine; + if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k); + // same as restr from fine func! not necessary ?! + // coarseRestrictFromFine part + coarseRestrictCell(lev, i,j,k,srcSet, dstFineSet); + } + } // only check empty cells + }}} // TEST! + } // PASS 5 */ + + // use //template functions for 2D/3D + /*if(strstr(this->getName().c_str(),"Debug")) + if((nbsok)&&(lev+1==mMaxRefine)) { // mixborder + for(int l=0;((lcDirNum) && (nbsok)); l++) { // FARBORD + int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&CFBnd) { // NEWREFT + nbsok=false; + } + } + } // FARBORD */ + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;j remove + // perform check from coarseAdvance here? + if(RFLAG(lev, i,j,k, srcSet) & CFGrFromFine) { + // remove from fine cells now that are completely in fluid + // FIXME? check that new from fine in performRefinement never get deleted here afterwards? + // or more general, one cell never changed more than once? + const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine); + //const CellFlagType notNbAllowed = (CFInter|CFBnd|CFGrFromFine); unused + CellFlagType reqType = CFGrNorm; + if(lev+1==mMaxRefine) reqType = CFNoBndFluid; + + nbsok = true; + for(int l=0; lcDirNum && nbsok; l++) { + int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l]; + if( (RFLAG(lev+1, ni,nj,nk, dstFineSet) & reqType) && + (!(RFLAG(lev+1, ni,nj,nk, dstFineSet) & (notAllowed)) ) ){ + // ok + } else { + nbsok=false; + } + // FARBORD + } + // dont turn CFGrFromFine above interface cells into CFGrNorm + // now check nbs on same level + for(int l=1; lcDirNum && nbsok; l++) { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if(RFLAG(lev, ni,nj,nk, srcSet)&(CFFluid)) { //ok + } else { + nbsok = false; + } + } // l + + if(nbsok) { + // conversion to coarse fluid cell + change = true; + mNumFsgrChanges++; + RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrNorm; + // dfs are already ok... + //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine changed to CFGrNorm at lev"<mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init center unused set l"<cDirNum; l++) { + int dstni=dstx+this->dfVecX[l], dstnj=dsty+this->dfVecY[l], dstnk=dstz+this->dfVecZ[l]; + if(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFFluid)) { + RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFFluid|CFGrFromCoarse; + } + if(RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet)&(CFInter)) { + //if(this->mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init CHECK Warning - deleting interface cell..."); + this->mFixMass += QCELL( dstlev, dstni,dstnj,dstnk, dstFineSet, dMass); + RFLAG(dstlev, dstni,dstnj,dstnk, dstFineSet) = CFFluid|CFGrFromCoarse; + } + } // l + + // again check nb flags of all surrounding cells to see if any from coarse + // can be convted to unused + for(int l=1; lcDirNum; l++) { + int dstni=dstx+this->dfVecX[l], dstnj=dsty+this->dfVecY[l], dstnk=dstz+this->dfVecZ[l]; + // have to be at least from coarse here... + //errMsg("performCoarsening","CFGrFromFine subcube init unused check l"<cDirNum; m++) { + int chkni=dstni+this->dfVecX[m], chknj=dstnj+this->dfVecY[m], chknk=dstnk+this->dfVecZ[m]; + if(RFLAG(dstlev, chkni,chknj,chknk, dstFineSet)&(CFUnused|CFGrFromCoarse)) { + // this nb cell is ok for deletion + } else { + delok=false; // keep it! + } + //errMsg("performCoarsening"," CHECK "<mInitDone) errMsg("performCoarsening","CFGrFromFine subcube init, dir:"<cDirNum; l++) { + int ni=(2*i)+this->dfVecX[l], nj=(2*j)+this->dfVecY[l], nk=(2*k)+this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, dstFineSet)& + (CFGrFromCoarse|CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused) + //(CFUnused|CFEmpty) //? (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused) + ) { + //LbmFloat area = 0.25; if(this->dfVecX[l]!=0) area *= 0.5; if(this->dfVecY[l]!=0) area *= 0.5; if(this->dfVecZ[l]!=0) area *= 0.5; + totArea += mFsgrCellArea[l]; + } + } // l + QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) = + QCELL(lev, i,j,k,srcSet, dFlux) = totArea; + } else { + QCELL(lev, i,j,k,mLevel[lev].setOther, dFlux) = + QCELL(lev, i,j,k,srcSet, dFlux) = 1.0; + } + //errMsg("DFINI"," at l"<getName().c_str(),"Debug")) + if((changeToFromFine)&&(lev+1==mMaxRefine)) { // mixborder + for(int l=0;((lcDirNum) && (changeToFromFine)); l++) { // FARBORD + int ni=2*i+2*this->dfVecX[l], nj=2*j+2*this->dfVecY[l], nk=2*k+2*this->dfVecZ[l]; + if(RFLAG(lev+1, ni,nj,nk, dstFineSet)&CFBnd) { // NEWREFT + changeToFromFine=false; } + } + }// FARBORD */ + //if(!this->mInitDone) { + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) { + for(int j=1;j from fine conversion + bool changeToFromFine = false; + const CellFlagType notAllowed = (CFInter|CFGrFromFine|CFGrToFine); + CellFlagType reqType = CFGrNorm; + if(lev+1==mMaxRefine) reqType = CFNoBndFluid; + + if( (RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & reqType) && + (!(RFLAG(lev+1, (2*i),(2*j),(2*k), dstFineSet) & (notAllowed)) ) ){ + // DEBUG + changeToFromFine=true; + } + + // FARBORD + + if(changeToFromFine) { + change = true; + mNumFsgrChanges++; + RFLAG(lev, i,j,k, srcSet) = CFFluid|CFGrFromFine; + if((LBMDIM==2)&&(debugCoarsening)) debugMarkCell(lev,i,j,k); + // same as restr from fine func! not necessary ?! + // coarseRestrictFromFine part + } + } // only check empty cells + + }}} // TEST! + //} // init done + // PASS 5 */ + } // coarsening, PASS 4,5 + + if(!this->mSilent){ errMsg("adaptGrid"," for l"<cDirNum); n++) { + int ni=2*i+1*this->dfVecX[n], nj=2*j+1*this->dfVecY[n], nk=2*k+1*this->dfVecZ[n]; + ccel = RACPNT(lev+1, ni,nj,nk,srcSet);// CFINTTEST + const LbmFloat weight = mGaussw[n]; + FORDF0{ + LbmFloat cdf = weight * RAC(ccel,l); +# if FSGR_STRICT_DEBUG==1 + if( cdf<-1.0 ){ errMsg("INVDFCREST_DFCHECK", PRINT_IJK<<" s"<dfDvecX[l]*cdf); + uy += (this->dfDvecY[l]*cdf); + uz += (this->dfDvecZ[l]*cdf); + } + + FORDF0{ feq[l] = this->getCollideEq(l, rho,ux,uy,uz); } + if(mLevel[lev ].lcsmago>0.0) { + const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feq); + omegaDst = this->getLesOmega(mLevel[lev ].omega,mLevel[lev ].lcsmago,Qo); + omegaSrc = this->getLesOmega(mLevel[lev+1].omega,mLevel[lev+1].lcsmago,Qo); + } else { + omegaDst = mLevel[lev+0].omega; /* NEWSMAGOT*/ + omegaSrc = mLevel[lev+1].omega; + } + dfScale = (mLevel[lev ].timestep/mLevel[lev+1].timestep)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); // yu + FORDF0{ + RAC(tcel, l) = feq[l]+ (df[l]-feq[l])*dfScale; + } +# else // OPT3D + // similar to OPTIMIZED_STREAMCOLLIDE_UNUSED + + //rho = ux = uy = uz = 0.0; + MSRC_C = CCELG_C(0) ; + MSRC_N = CCELG_N(0) ; + MSRC_S = CCELG_S(0) ; + MSRC_E = CCELG_E(0) ; + MSRC_W = CCELG_W(0) ; + MSRC_T = CCELG_T(0) ; + MSRC_B = CCELG_B(0) ; + MSRC_NE = CCELG_NE(0); + MSRC_NW = CCELG_NW(0); + MSRC_SE = CCELG_SE(0); + MSRC_SW = CCELG_SW(0); + MSRC_NT = CCELG_NT(0); + MSRC_NB = CCELG_NB(0); + MSRC_ST = CCELG_ST(0); + MSRC_SB = CCELG_SB(0); + MSRC_ET = CCELG_ET(0); + MSRC_EB = CCELG_EB(0); + MSRC_WT = CCELG_WT(0); + MSRC_WB = CCELG_WB(0); + for(int n=1;(ncDirNum); n++) { + ccel = RACPNT(lev+1, 2*i+1*this->dfVecX[n], 2*j+1*this->dfVecY[n], 2*k+1*this->dfVecZ[n] ,srcSet); + MSRC_C += CCELG_C(n) ; + MSRC_N += CCELG_N(n) ; + MSRC_S += CCELG_S(n) ; + MSRC_E += CCELG_E(n) ; + MSRC_W += CCELG_W(n) ; + MSRC_T += CCELG_T(n) ; + MSRC_B += CCELG_B(n) ; + MSRC_NE += CCELG_NE(n); + MSRC_NW += CCELG_NW(n); + MSRC_SE += CCELG_SE(n); + MSRC_SW += CCELG_SW(n); + MSRC_NT += CCELG_NT(n); + MSRC_NB += CCELG_NB(n); + MSRC_ST += CCELG_ST(n); + MSRC_SB += CCELG_SB(n); + MSRC_ET += CCELG_ET(n); + MSRC_EB += CCELG_EB(n); + MSRC_WT += CCELG_WT(n); + MSRC_WB += CCELG_WB(n); + } + rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T + + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT + + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB; + ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW + + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB; + uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW + + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB; + uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB + + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB; + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + \ + lcsmeq[dC] = EQC ; \ + COLL_CALCULATE_DFEQ(lcsmeq); \ + COLL_CALCULATE_NONEQTENSOR(lev+0, MSRC_ )\ + COLL_CALCULATE_CSMOMEGAVAL(lev+0, lcsmDstOmega); \ + COLL_CALCULATE_CSMOMEGAVAL(lev+1, lcsmSrcOmega); \ + \ + lcsmdfscale = (mLevel[lev+0].timestep/mLevel[lev+1].timestep)* (1.0/lcsmDstOmega-1.0)/ (1.0/lcsmSrcOmega-1.0); \ + RAC(tcel, dC ) = (lcsmeq[dC ] + (MSRC_C -lcsmeq[dC ] )*lcsmdfscale); + RAC(tcel, dN ) = (lcsmeq[dN ] + (MSRC_N -lcsmeq[dN ] )*lcsmdfscale); + RAC(tcel, dS ) = (lcsmeq[dS ] + (MSRC_S -lcsmeq[dS ] )*lcsmdfscale); + RAC(tcel, dE ) = (lcsmeq[dE ] + (MSRC_E -lcsmeq[dE ] )*lcsmdfscale); + RAC(tcel, dW ) = (lcsmeq[dW ] + (MSRC_W -lcsmeq[dW ] )*lcsmdfscale); + RAC(tcel, dT ) = (lcsmeq[dT ] + (MSRC_T -lcsmeq[dT ] )*lcsmdfscale); + RAC(tcel, dB ) = (lcsmeq[dB ] + (MSRC_B -lcsmeq[dB ] )*lcsmdfscale); + RAC(tcel, dNE) = (lcsmeq[dNE] + (MSRC_NE-lcsmeq[dNE] )*lcsmdfscale); + RAC(tcel, dNW) = (lcsmeq[dNW] + (MSRC_NW-lcsmeq[dNW] )*lcsmdfscale); + RAC(tcel, dSE) = (lcsmeq[dSE] + (MSRC_SE-lcsmeq[dSE] )*lcsmdfscale); + RAC(tcel, dSW) = (lcsmeq[dSW] + (MSRC_SW-lcsmeq[dSW] )*lcsmdfscale); + RAC(tcel, dNT) = (lcsmeq[dNT] + (MSRC_NT-lcsmeq[dNT] )*lcsmdfscale); + RAC(tcel, dNB) = (lcsmeq[dNB] + (MSRC_NB-lcsmeq[dNB] )*lcsmdfscale); + RAC(tcel, dST) = (lcsmeq[dST] + (MSRC_ST-lcsmeq[dST] )*lcsmdfscale); + RAC(tcel, dSB) = (lcsmeq[dSB] + (MSRC_SB-lcsmeq[dSB] )*lcsmdfscale); + RAC(tcel, dET) = (lcsmeq[dET] + (MSRC_ET-lcsmeq[dET] )*lcsmdfscale); + RAC(tcel, dEB) = (lcsmeq[dEB] + (MSRC_EB-lcsmeq[dEB] )*lcsmdfscale); + RAC(tcel, dWT) = (lcsmeq[dWT] + (MSRC_WT-lcsmeq[dWT] )*lcsmdfscale); + RAC(tcel, dWB) = (lcsmeq[dWB] + (MSRC_WB-lcsmeq[dWB] )*lcsmdfscale); +# endif // OPT3D==0 +} + +void LbmFsgrSolver::interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet, bool markNbs) { + LbmFloat rho=0.0, ux=0.0, uy=0.0, uz=0.0; + LbmFloat intDf[19] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + +#if OPT3D==1 + // for macro add + LbmFloat addDfFacT, addVal, usqr; + LbmFloat *addfcel, *dstcell; + LbmFloat lcsmqadd, lcsmqo, lcsmeq[LBM_DFNUM]; + LbmFloat lcsmDstOmega, lcsmSrcOmega, lcsmdfscale; +#endif // OPT3D==true + + // SET required nbs to from coarse (this might overwrite flag several times) + // this is not necessary for interpolateFineFromCoarse + if(markNbs) { + FORDF1{ + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if(RFLAG(lev,ni,nj,nk,dstSet)&CFUnused) { + // parents have to be inited! + interpolateCellFromCoarse(lev, ni, nj, nk, dstSet, t, CFFluid|CFGrFromCoarse, false); + } + } } + + // change flag of cell to be interpolated + RFLAG(lev,i,j,k, dstSet) = flagSet; + mNumInterdCells++; + + // interpolation lines... + int betx = i&1; + int bety = j&1; + int betz = k&1; + + if((!betx) && (!bety) && (!betz)) { + ADD_INT_DFS(lev-1, i/2 ,j/2 ,k/2 , 0.0, 1.0); + } + else if(( betx) && (!bety) && (!betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D1); + } + else if((!betx) && ( bety) && (!betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D1); + } + else if((!betx) && (!bety) && ( betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D1); + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D1); + } + else if(( betx) && ( bety) && (!betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D2); + } + else if((!betx) && ( bety) && ( betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D2); + } + else if(( betx) && (!bety) && ( betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D2); + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D2); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D2); + } + else if(( betx) && ( bety) && ( betz)) { + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2) , t, WO1D3); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2) , t, WO1D3); + ADD_INT_DFS(lev-1, (i/2) ,(j/2) ,(k/2)+1, t, WO1D3); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2) ,(k/2)+1, t, WO1D3); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2) , t, WO1D3); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2) , t, WO1D3); + ADD_INT_DFS(lev-1, (i/2) ,(j/2)+1,(k/2)+1, t, WO1D3); + ADD_INT_DFS(lev-1, (i/2)+1,(j/2)+1,(k/2)+1, t, WO1D3); + } + else { + CAUSE_PANIC; + errFatal("interpolateCellFromCoarse","Invalid!?", SIMWORLD_GENERICERROR); + } + + IDF_WRITEBACK; + return; +} + + + +// required globals +extern bool glob_mpactive; +extern int glob_mpnum, glob_mpindex; +#define MPTADAP_INTERV 4 + +/*****************************************************************************/ +/*! change the size of the LBM time step */ +/*****************************************************************************/ +void LbmFsgrSolver::adaptTimestep() { + LbmFloat massTOld=0.0, massTNew=0.0; + LbmFloat volTOld=0.0, volTNew=0.0; + + bool rescale = false; // do any rescale at all? + LbmFloat scaleFac = -1.0; // timestep scaling + if(mPanic) return; + + LbmFloat levOldOmega[FSGR_MAXNOOFLEVELS]; + LbmFloat levOldStepsize[FSGR_MAXNOOFLEVELS]; + for(int lev=mMaxRefine; lev>=0 ; lev--) { + levOldOmega[lev] = mLevel[lev].omega; + levOldStepsize[lev] = mLevel[lev].timestep; + } + + const LbmFloat reduceFac = 0.8; // modify time step by 20%, TODO? do multiple times for large changes? + LbmFloat diffPercent = 0.05; // dont scale if less than 5% + LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity + LbmFloat nextmax = mpParam->getSimulationMaxSpeed() + norm(mLevel[mMaxRefine].gravity); + + // sync nextmax +#if LBM_INCLUDE_TESTSOLVERS==1 + if(glob_mpactive) { + if(mLevel[mMaxRefine].lsteps % MPTADAP_INTERV != MPTADAP_INTERV-1) { + debMsgStd("LbmFsgrSolver::TAdp",DM_MSG, "mpact:"<getTimestep(); // newtr + if(nextmax > allowMax/reduceFac) { + mTimeMaxvelStepCnt++; } + else { mTimeMaxvelStepCnt=0; } + + // emergency, or 10 steps with high vel + if((mTimeMaxvelStepCnt>5) || (nextmax> (1.0/3.0)) || (mForceTimeStepReduce) ) { + newdt = mpParam->getTimestep() * reduceFac; + } else { + if(nextmaxgetTimestep() / reduceFac; + } + } // newtr + //errMsg("LbmFsgrSolver::adaptTimestep","nextmax="<getMaxTimestep()<<" min"<getMinTimestep()<<" diff"<getTimestep() ) // DEBUG + LbmFloat rhoAvg = mCurrentMass/mCurrentVolume; + if( (newdt<=mpParam->getMaxTimestep()) && (newdt>=mpParam->getMinTimestep()) + && (dtdiff>(mpParam->getTimestep()*diffPercent)) ) { + if((newdt>levOldStepsize[mMaxRefine])&&(mTimestepReduceLock)) { + // wait some more... + //debMsgNnl("LbmFsgrSolver::TAdp",DM_NOTIFY," Delayed... "<setDesiredTimestep( newdt ); + rescale = true; + if(!mSilent) { + debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"\n\n\n\n",10); + debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Timestep changing: new="<getSimulationMaxSpeed()<<" next:"<getTimestep(); + mpParam->setDesiredTimestep( newdt ); + } else + if( ((mStepCnt% tadtogInter)== (tadtogInter/4*3)-1) || + ((mStepCnt% tadtogInter)== (tadtogInter/4*4)-1) ){ + rescale = true; minCutoff = false; + newdt = mpParam->getTimestep()/tadtogSwitch ; + mpParam->setDesiredTimestep( newdt ); + } else { + rescale = false; minCutoff = false; + } + // */ + + // test mass rescale + + scaleFac = newdt/mpParam->getTimestep(); + if(rescale) { + // perform acutal rescaling... + mTimeMaxvelStepCnt=0; + mForceTimeStepReduce = false; + + // FIXME - approximate by averaging, take gravity direction here? + //mTimestepReduceLock = 4*(mLevel[mMaxRefine].lSizey+mLevel[mMaxRefine].lSizez+mLevel[mMaxRefine].lSizex)/3; + // use z as gravity direction + mTimestepReduceLock = 4*mLevel[mMaxRefine].lSizez; + + mTimeSwitchCounts++; + mpParam->calculateAllMissingValues( mSimulationTime, mSilent ); + recalculateObjectSpeeds(); + // calc omega, force for all levels + mLastOmega=1e10; mLastGravity=1e10; + initLevelOmegas(); + if(mpParam->getTimestep()getTimestep(); + if(mpParam->getTimestep()>mMaxTimestep) mMaxTimestep = mpParam->getTimestep(); + + // this might be called during init, before we have any particles + if(mpParticles) { mpParticles->adaptPartTimestep(scaleFac); } +#if LBM_INCLUDE_TESTSOLVERS==1 + if((mUseTestdata)&&(mpTest)) { + mpTest->adaptTimestep(scaleFac, mLevel[mMaxRefine].omega, mLevel[mMaxRefine].timestep, vec2L( mpParam->calculateGravity(mSimulationTime)) ); + mpTest->mGrav3d = mLevel[mMaxRefine].gravity; + } +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + + for(int lev=mMaxRefine; lev>=0 ; lev--) { + LbmFloat newSteptime = mLevel[lev].timestep; + LbmFloat dfScaleFac = (newSteptime/1.0)/(levOldStepsize[lev]/levOldOmega[lev]); + + if(!mSilent) { + debMsgStd("LbmFsgrSolver::TAdp",DM_NOTIFY,"Level: "<getCurrentGStar()<<", step:"<=0 ; lev--) { + int rescs=0; + int wss = 0, wse = 1; +#if COMPRESSGRIDS==1 + if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr; +#endif // COMPRESSGRIDS==1 + for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT + //for(int workSet = 0; workSet<=1; workSet++) { + FSGR_FORIJK1(lev) { + + //if( (RFLAG(lev, i,j,k, workSet) & CFFluid) || (RFLAG(lev, i,j,k, workSet) & CFInter) ) { + if( + (RFLAG(lev,i,j,k, workSet) & CFFluid) || + (RFLAG(lev,i,j,k, workSet) & CFInter) || + (RFLAG(lev,i,j,k, workSet) & CFGrFromCoarse) || + (RFLAG(lev,i,j,k, workSet) & CFGrFromFine) || + (RFLAG(lev,i,j,k, workSet) & CFGrNorm) + ) { + // these cells have to be scaled... + } else { + continue; + } + + // collide on current set + LbmFloat rho, ux,uy,uz; + rho=0.0; ux = uy = uz = 0.0; + for(int l=0; l (allowMax*allowMax) ) { + LbmFloat cfac = allowMax/sqrt(ux*ux+uy*uy+uz*uz); + ux *= cfac; + uy *= cfac; + uz *= cfac; + for(int l=0; l0) { errMsg("adaptTimestep","!!!!! Brute force rescaling was necessary !!!!!!!"); } + debMsgStd("adaptTimestep",DM_MSG,"Brute force rescale done. level:"< + +#if PARALLEL==1 +#include +#endif // PARALLEL=1 +#ifndef PARALLEL +#define PARALLEL 0 +#endif // PARALLEL + + +// general solver setting defines + +//! debug coordinate accesses and the like? (much slower) +// might be enabled by compilation +#ifndef FSGR_STRICT_DEBUG +#define FSGR_STRICT_DEBUG 0 +#endif // FSGR_STRICT_DEBUG + +//! debug coordinate accesses and the like? (much slower) +#define FSGR_OMEGA_DEBUG 0 + +//! OPT3D quick LES on/off, only debug/benchmarking +#define USE_LES 1 + +//! order of interpolation (0=always current/1=interpolate/2=always other) +//#define TIMEINTORDER 0 +// TODO remove interpol t param, also interTime + +// use optimized 3D code? +#if LBMDIM==2 +#define OPT3D 0 +#else +// determine with debugging... +# if FSGR_STRICT_DEBUG==1 +# define OPT3D 0 +# else // FSGR_STRICT_DEBUG==1 +// usually switch optimizations for 3d on, when not debugging +# define OPT3D 1 +// COMPRT +//# define OPT3D 0 +# endif // FSGR_STRICT_DEBUG==1 +#endif + +//! invalid mass value for unused mass data +#define MASS_INVALID -1000.0 + +// empty/fill cells without fluid/empty NB's by inserting them into the full/empty lists? +#define FSGR_LISTTRICK 1 +#define FSGR_LISTTTHRESHEMPTY 0.10 +#define FSGR_LISTTTHRESHFULL 0.90 +#define FSGR_MAGICNR 0.025 +//0.04 + +//! maxmimum no. of grid levels +#define FSGR_MAXNOOFLEVELS 5 + +// enable/disable fine grid compression for finest level +// make sure this is same as useGridComp in calculateMemreqEstimate +#if LBMDIM==3 +#define COMPRESSGRIDS 1 +#else +#define COMPRESSGRIDS 0 +#endif + +// helper for comparing floats with epsilon +#define GFX_FLOATNEQ(x,y) ( ABS((x)-(y)) > (VECTOR_EPSILON) ) +#define LBM_FLOATNEQ(x,y) ( ABS((x)-(y)) > (10.0*LBM_EPSILON) ) + + +// macros for loops over all DFs +#define FORDF0 for(int l= 0; l< LBM_DFNUM; ++l) +#define FORDF1 for(int l= 1; l< LBM_DFNUM; ++l) +// and with different loop var to prevent shadowing +#define FORDF0M for(int m= 0; m< LBM_DFNUM; ++m) +#define FORDF1M for(int m= 1; m< LBM_DFNUM; ++m) + +// iso value defines +// border for marching cubes +#define ISOCORR 3 + +#define LBM_INLINED inline + +// sirdude fix for solaris +#if !defined(linux) && defined(sun) +#ifndef expf +#define expf(a) exp((double)(a)) +#endif +#endif + +#if LBM_INCLUDE_TESTSOLVERS==1 +#include "solver_test.h" +#endif // LBM_INCLUDE_TESTSOLVERS==1 + +/*****************************************************************************/ +/*! cell access classes */ +class UniformFsgrCellIdentifier : + public CellIdentifierInterface , public LbmCellContents +{ + public: + //! which grid level? + int level; + //! location in grid + int x,y,z; + + //! reset constructor + UniformFsgrCellIdentifier() : + x(0), y(0), z(0) { }; + + // implement CellIdentifierInterface + virtual string getAsString() { + std::ostringstream ret; + ret <<"{ i"<2) ret<<",k"<x && y==cid->y && z==cid->z && level==cid->level ) return true; + return false; + } +}; + +//! information needed for each level in the simulation +class FsgrLevelData { +public: + int id; // level number + + //! node size on this level (geometric, in world coordinates, not simulation units!) + LbmFloat nodeSize; + //! node size on this level in simulation units + LbmFloat simCellSize; + //! quadtree node relaxation parameter + LbmFloat omega; + //! size this level was advanced to + LbmFloat time; + //! size of a single lbm step in time units on this level + LbmFloat timestep; + //! step count + int lsteps; + //! gravity force for this level + LbmVec gravity; + //! level array + LbmFloat *mprsCells[2]; + CellFlagType *mprsFlags[2]; + + //! smago params and precalculated values + LbmFloat lcsmago; + LbmFloat lcsmago_sqr; + LbmFloat lcnu; + + // LES statistics per level + double avgOmega; + double avgOmegaCnt; + + //! current set of dist funcs + int setCurr; + //! target/other set of dist funcs + int setOther; + + //! mass&volume for this level + LbmFloat lmass; + LbmFloat lvolume; + LbmFloat lcellfactor; + + //! local storage of mSizes + int lSizex, lSizey, lSizez; + int lOffsx, lOffsy, lOffsz; + +}; + + + +/*****************************************************************************/ +/*! class for solving a LBM problem */ +class LbmFsgrSolver : + public LbmSolverInterface // this means, the solver is a lbmData object and implements the lbmInterface +{ + + public: + //! Constructor + LbmFsgrSolver(); + //! Destructor + virtual ~LbmFsgrSolver(); + + //! initilize variables fom attribute list + virtual void parseAttrList(); + //! Initialize omegas and forces on all levels (for init/timestep change) + void initLevelOmegas(); + + // multi step solver init + /*! finish the init with config file values (allocate arrays...) */ + virtual bool initializeSolverMemory(); + /*! init solver arrays */ + virtual bool initializeSolverGrids(); + /*! prepare actual simulation start, setup viz etc */ + virtual bool initializeSolverPostinit(); + + //! notify object that dump is in progress (e.g. for field dump) + virtual void notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename); + +# if LBM_USE_GUI==1 + //! show simulation info (implement LbmSolverInterface pure virtual func) + virtual void debugDisplay(int set); +# endif + + // implement CellIterator interface + typedef UniformFsgrCellIdentifier stdCellId; + virtual CellIdentifierInterface* getFirstCell( ); + virtual void advanceCell( CellIdentifierInterface* ); + virtual bool noEndCell( CellIdentifierInterface* ); + virtual void deleteCellIterator( CellIdentifierInterface** ); + virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos ); + virtual int getCellSet ( CellIdentifierInterface* ); + virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* ); + virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* ); + virtual int getCellLevel ( CellIdentifierInterface* ); + virtual LbmFloat getCellDensity ( CellIdentifierInterface* ,int set); + virtual LbmVec getCellVelocity ( CellIdentifierInterface* ,int set); + virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir); + virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set); + virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set); + virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set); + virtual LbmFloat getEquilDf ( int ); + virtual ntlVec3Gfx getVelocityAt (float x, float y, float z); + // convert pointers + stdCellId* convertBaseCidToStdCid( CellIdentifierInterface* basecid); + + //! perform geometry init (if switched on) + bool initGeometryFlags(); + //! init part for all freesurface testcases + void initFreeSurfaces(); + //! init density gradient if enabled + void initStandingFluidGradient(); + + /*! init a given cell with flag, density, mass and equilibrium dist. funcs */ + LBM_INLINED void initEmptyCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass); + LBM_INLINED void initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel); + LBM_INLINED void changeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag); + LBM_INLINED void forceChangeFlag(int level, int xx,int yy,int zz,int set,CellFlagType newflag); + LBM_INLINED void initInterfaceVars(int level, int i,int j,int k,int workSet, bool initMass); + //! interpolate velocity and density at a given position + void interpolateCellValues(int level,int ei,int ej,int ek,int workSet, LbmFloat &retrho, LbmFloat &retux, LbmFloat &retuy, LbmFloat &retuz); + + /*! perform a single LBM step */ + void stepMain(); + //! advance fine grid + void fineAdvance(); + //! advance coarse grid + void coarseAdvance(int lev); + //! update flux area values on coarse grids + void coarseCalculateFluxareas(int lev); + // adaptively coarsen grid + bool adaptGrid(int lev); + // restrict fine grid DFs to coarse grid + void coarseRestrictFromFine(int lev); + + /* simulation object interface, just calls stepMain */ + virtual void step(); + /*! init particle positions */ + virtual int initParticles(); + /*! move all particles */ + virtual void advanceParticles(); + /*! move a particle at a boundary */ + void handleObstacleParticle(ParticleObject *p); + /*! check whether to add particle + bool checkAddParticle(); + void performAddParticle();*/ + + + /*! debug object display (used e.g. for preview surface) */ + virtual vector getDebugObjects(); + + // gui/output debugging functions +# if LBM_USE_GUI==1 + virtual void debugDisplayNode(int dispset, CellIdentifierInterface* cell ); + virtual void lbmDebugDisplay(int dispset); + virtual void lbmMarkedCellDisplay(); +# endif // LBM_USE_GUI==1 + virtual void debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet=-1); + + //! for raytracing, preprocess + void prepareVisualization( void ); + + protected: + + //! internal quick print function (for debugging) + void printLbmCell(int level, int i, int j, int k,int set); + // debugging use CellIterator interface to mark cell + void debugMarkCellCall(int level, int vi,int vj,int vk); + + // loop over grid, stream&collide update + void mainLoop(int lev); + // change time step size + void adaptTimestep(); + //! init mObjectSpeeds for current parametrization + void recalculateObjectSpeeds(); + //! init moving obstacles for next sim step sim + void initMovingObstacles(bool staticInit); + //! flag reinit step - always works on finest grid! + void reinitFlags( int workSet ); + //! mass dist weights + LbmFloat getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l); + //! compute surface normals: fluid, fluid more accurate, and for obstacles + void computeFluidSurfaceNormal(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret); + void computeFluidSurfaceNormalAcc(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret); + void computeObstacleSurfaceNormal(LbmFloat *cell, CellFlagType *cellflag, LbmFloat *snret); + void computeObstacleSurfaceNormalAcc(int i,int j,int k, LbmFloat *snret); + //! add point to mListNewInter list + LBM_INLINED void addToNewInterList( int ni, int nj, int nk ); + //! cell is interpolated from coarse level (inited into set, source sets are determined by t) + void interpolateCellFromCoarse(int lev, int i, int j,int k, int dstSet, LbmFloat t, CellFlagType flagSet,bool markNbs); + void coarseRestrictCell(int lev, int i,int j,int k, int srcSet, int dstSet); + + //! minimal and maximal z-coords (for 2D/3D loops) + LBM_INLINED int getForZMinBnd(); + LBM_INLINED int getForZMin1(); + LBM_INLINED int getForZMaxBnd(int lev); + LBM_INLINED int getForZMax1(int lev); + LBM_INLINED bool checkDomainBounds(int lev,int i,int j,int k); + LBM_INLINED bool checkDomainBoundsPos(int lev,LbmVec pos); + + // touch grid and flags once + void preinitGrids(); + // one relaxation step for standing fluid + void standingFluidPreinit(); + + + // member vars + + //! mass calculated during streaming step + LbmFloat mCurrentMass; + LbmFloat mCurrentVolume; + LbmFloat mInitialMass; + + //! count problematic cases, that occured so far... + int mNumProblems; + + // average mlsups, count how many so far... + double mAvgMLSUPS; + double mAvgMLSUPSCnt; + + //! Mcubes object for surface reconstruction + IsoSurface *mpPreviewSurface; + + //! use time adaptivity? + bool mTimeAdap; + //! force smaller timestep for next LBM step? (eg for mov obj) + bool mForceTimeStepReduce; + + //! fluid vol height + LbmFloat mFVHeight; + LbmFloat mFVArea; + bool mUpdateFVHeight; + + //! force quit for gfx + LbmFloat mGfxEndTime; + //! smoother surface initialization? + int mInitSurfaceSmoothing; + //! surface generation settings, default is all off (=0) + // each flag switches side on off, fssgNoObs is for obstacle sides + // -1 equals all on + typedef enum { + fssgNormal = 0, + fssgNoNorth = 1, + fssgNoSouth = 2, + fssgNoEast = 4, + fssgNoWest = 8, + fssgNoTop = 16, + fssgNoBottom = 32, + fssgNoObs = 64 + } fsSurfaceGen; + int mFsSurfGenSetting; + + //! lock time step down switching + int mTimestepReduceLock; + //! count no. of switches + int mTimeSwitchCounts; + // only switch of maxvel is higher for several steps... + int mTimeMaxvelStepCnt; + + //! total simulation time so far + LbmFloat mSimulationTime, mLastSimTime; + //! smallest and largest step size so far + LbmFloat mMinTimestep, mMaxTimestep; + //! track max. velocity + LbmFloat mMxvx, mMxvy, mMxvz, mMaxVlen; + + //! list of the cells to empty at the end of the step + vector mListEmpty; + //! list of the cells to make fluid at the end of the step + vector mListFull; + //! list of new interface cells to init + vector mListNewInter; + //! class for handling redist weights in reinit flag function + class lbmFloatSet { + public: + LbmFloat val[dTotalNum]; + LbmFloat numNbs; + }; + //! normalized vectors for all neighboring cell directions (for e.g. massdweight calc) + LbmVec mDvecNrm[27]; + + + //! debugging + bool checkSymmetry(string idstring); + //! kepp track of max/min no. of filled cells + int mMaxNoCells, mMinNoCells; + LONGINT mAvgNumUsedCells; + + //! precalculated objects speeds for current parametrization + vector mObjectSpeeds; + //! partslip bc. values for obstacle boundary conditions + vector mObjectPartslips; + //! moving object mass boundary condition values + vector mObjectMassMovnd; + + //! permanent movobj vert storage + vector mMOIVertices; + vector mMOIVerticesOld; + vector mMOINormals; + + //! get isofield weights + int mIsoWeightMethod; + float mIsoWeight[27]; + + // grid coarsening vars + + /*! vector for the data for each level */ + FsgrLevelData mLevel[FSGR_MAXNOOFLEVELS]; + + /*! minimal and maximal refinement levels */ + int mMaxRefine; + + /*! df scale factors for level up/down */ + LbmFloat mDfScaleUp, mDfScaleDown; + + /*! precomputed cell area values */ + LbmFloat mFsgrCellArea[27]; + /*! restriction interpolation weights */ + LbmFloat mGaussw[27]; + + /*! LES C_smago paramter for finest grid */ + float mInitialCsmago; + /*! LES stats for non OPT3D */ + LbmFloat mDebugOmegaRet; + /*! remember last init for animated params */ + LbmFloat mLastOmega; + LbmVec mLastGravity; + + //! fluid stats + int mNumInterdCells; + int mNumInvIfCells; + int mNumInvIfTotal; + int mNumFsgrChanges; + + //! debug function to disable standing f init + int mDisableStandingFluidInit; + //! init 2d with skipped Y/Z coords + bool mInit2dYZ; + //! debug function to force tadap syncing + int mForceTadapRefine; + //! border cutoff value + int mCutoff; + + // strict debug interface +# if FSGR_STRICT_DEBUG==1 + int debLBMGI(int level, int ii,int ij,int ik, int is); + CellFlagType& debRFLAG(int level, int xx,int yy,int zz,int set); + CellFlagType& debRFLAG_NB(int level, int xx,int yy,int zz,int set, int dir); + CellFlagType& debRFLAG_NBINV(int level, int xx,int yy,int zz,int set, int dir); + int debLBMQI(int level, int ii,int ij,int ik, int is, int l); + LbmFloat& debQCELL(int level, int xx,int yy,int zz,int set,int l); + LbmFloat& debQCELL_NB(int level, int xx,int yy,int zz,int set, int dir,int l); + LbmFloat& debQCELL_NBINV(int level, int xx,int yy,int zz,int set, int dir,int l); + LbmFloat* debRACPNT(int level, int ii,int ij,int ik, int is ); + LbmFloat& debRAC(LbmFloat* s,int l); +# endif // FSGR_STRICT_DEBUG==1 + + bool mUseTestdata; +# if LBM_INCLUDE_TESTSOLVERS==1 + // test functions + LbmTestdata *mpTest; + void initTestdata(); + void destroyTestdata(); + void handleTestdata(); + void set3dHeight(int ,int ); + + void initCpdata(); + void handleCpdata(); + void cpDebugDisplay(int dispset); + + int mMpNum,mMpIndex; + int mOrgSizeX; + LbmFloat mOrgStartX; + LbmFloat mOrgEndX; + void mrSetup(); + void mrExchange(); + void mrIsoExchange(); + LbmFloat mrInitTadap(LbmFloat max); + void gcFillBuffer( LbmGridConnector *gc, int *retSizeCnt, const int *bdfs); + void gcUnpackBuffer(LbmGridConnector *gc, int *retSizeCnt, const int *bdfs); + public: + // needed for testdata + void find3dHeight(int i,int j, LbmFloat prev, LbmFloat &ret, LbmFloat *retux, LbmFloat *retuy, LbmFloat *retuz); + // mptest + int getMpIndex() { return mMpIndex; }; +# endif // LBM_INCLUDE_TESTSOLVERS==1 + + // former LbmModelLBGK functions + // relaxation funtions - implemented together with relax macros + static inline LbmFloat getVelVecLen(int l, LbmFloat ux,LbmFloat uy,LbmFloat uz); + static inline LbmFloat getCollideEq(int l, LbmFloat rho, LbmFloat ux, LbmFloat uy, LbmFloat uz); + inline LbmFloat getLesNoneqTensorCoeff( LbmFloat df[], LbmFloat feq[] ); + inline LbmFloat getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo); + inline void collideArrays( int lev, int i, int j, int k, // position - more for debugging + LbmFloat df[], LbmFloat &outrho, // out only! + // velocity modifiers (returns actual velocity!) + LbmFloat &mux, LbmFloat &muy, LbmFloat &muz, + LbmFloat omega, LbmVec gravity, LbmFloat csmago, + LbmFloat *newOmegaRet, LbmFloat *newQoRet); + + + // former LBM models + //! shorten static const definitions +# define STCON static const + +# if LBMDIM==3 + + //! id string of solver + virtual string getIdString() { return string("FreeSurfaceFsgrSolver[BGK_D3Q19]"); } + + //! how many dimensions? UNUSED? replace by LBMDIM? + STCON int cDimension; + + // Wi factors for collide step + STCON LbmFloat cCollenZero; + STCON LbmFloat cCollenOne; + STCON LbmFloat cCollenSqrtTwo; + + //! threshold value for filled/emptied cells + STCON LbmFloat cMagicNr2; + STCON LbmFloat cMagicNr2Neg; + STCON LbmFloat cMagicNr; + STCON LbmFloat cMagicNrNeg; + + //! size of a single set of distribution functions + STCON int cDfNum; + //! direction vector contain vecs for all spatial dirs, even if not used for LBM model + STCON int cDirNum; + + //! distribution functions directions + typedef enum { + cDirInv= -1, + cDirC = 0, + cDirN = 1, + cDirS = 2, + cDirE = 3, + cDirW = 4, + cDirT = 5, + cDirB = 6, + cDirNE = 7, + cDirNW = 8, + cDirSE = 9, + cDirSW = 10, + cDirNT = 11, + cDirNB = 12, + cDirST = 13, + cDirSB = 14, + cDirET = 15, + cDirEB = 16, + cDirWT = 17, + cDirWB = 18 + } dfDir; + + /* Vector Order 3D: + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 + * 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1 + * 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1 + * 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1 + */ + + /*! name of the dist. function + only for nicer output */ + STCON char* dfString[ 19 ]; + + /*! index of normal dist func, not used so far?... */ + STCON int dfNorm[ 19 ]; + + /*! index of inverse dist func, not fast, but useful... */ + STCON int dfInv[ 19 ]; + + /*! index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefX[ 19 ]; + /*! index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefY[ 19 ]; + /*! index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefZ[ 19 ]; + + /*! dist func vectors */ + STCON int dfVecX[ 27 ]; + STCON int dfVecY[ 27 ]; + STCON int dfVecZ[ 27 ]; + + /*! arrays as before with doubles */ + STCON LbmFloat dfDvecX[ 27 ]; + STCON LbmFloat dfDvecY[ 27 ]; + STCON LbmFloat dfDvecZ[ 27 ]; + + /*! principal directions */ + STCON int princDirX[ 2*3 ]; + STCON int princDirY[ 2*3 ]; + STCON int princDirZ[ 2*3 ]; + + /*! vector lengths */ + STCON LbmFloat dfLength[ 19 ]; + + /*! equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */ + static LbmFloat dfEquil[ dTotalNum ]; + + /*! arrays for les model coefficients */ + static LbmFloat lesCoeffDiag[ (3-1)*(3-1) ][ 27 ]; + static LbmFloat lesCoeffOffdiag[ 3 ][ 27 ]; + +# else // end LBMDIM==3 , LBMDIM==2 + + //! id string of solver + virtual string getIdString() { return string("FreeSurfaceFsgrSolver[BGK_D2Q9]"); } + + //! how many dimensions? + STCON int cDimension; + + //! Wi factors for collide step + STCON LbmFloat cCollenZero; + STCON LbmFloat cCollenOne; + STCON LbmFloat cCollenSqrtTwo; + + //! threshold value for filled/emptied cells + STCON LbmFloat cMagicNr2; + STCON LbmFloat cMagicNr2Neg; + STCON LbmFloat cMagicNr; + STCON LbmFloat cMagicNrNeg; + + //! size of a single set of distribution functions + STCON int cDfNum; + STCON int cDirNum; + + //! distribution functions directions + typedef enum { + cDirInv= -1, + cDirC = 0, + cDirN = 1, + cDirS = 2, + cDirE = 3, + cDirW = 4, + cDirNE = 5, + cDirNW = 6, + cDirSE = 7, + cDirSW = 8 + } dfDir; + + /* Vector Order 2D: + * 0 1 2 3 4 5 6 7 8 + * 0, 0,0, 1,-1, 1,-1,1,-1 + * 0, 1,-1, 0,0, 1,1,-1,-1 */ + + /* name of the dist. function + only for nicer output */ + STCON char* dfString[ 9 ]; + + /* index of normal dist func, not used so far?... */ + STCON int dfNorm[ 9 ]; + + /* index of inverse dist func, not fast, but useful... */ + STCON int dfInv[ 9 ]; + + /* index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefX[ 9 ]; + /* index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefY[ 9 ]; + /* index of x reflected dist func for free slip, not valid for all DFs... */ + STCON int dfRefZ[ 9 ]; + + /* dist func vectors */ + STCON int dfVecX[ 9 ]; + STCON int dfVecY[ 9 ]; + /* Z, 2D values are all 0! */ + STCON int dfVecZ[ 9 ]; + + /* arrays as before with doubles */ + STCON LbmFloat dfDvecX[ 9 ]; + STCON LbmFloat dfDvecY[ 9 ]; + /* Z, 2D values are all 0! */ + STCON LbmFloat dfDvecZ[ 9 ]; + + /*! principal directions */ + STCON int princDirX[ 2*2 ]; + STCON int princDirY[ 2*2 ]; + STCON int princDirZ[ 2*2 ]; + + /* vector lengths */ + STCON LbmFloat dfLength[ 9 ]; + + /* equilibrium distribution functions, precalculated = getCollideEq(i, 0,0,0,0) */ + static LbmFloat dfEquil[ dTotalNum ]; + + /*! arrays for les model coefficients */ + static LbmFloat lesCoeffDiag[ (2-1)*(2-1) ][ 9 ]; + static LbmFloat lesCoeffOffdiag[ 2 ][ 9 ]; + +# endif // LBMDIM==2 +}; + +#undef STCON + + +/*****************************************************************************/ +// relaxation_macros + + + +// cell mark debugging +#if FSGR_STRICT_DEBUG==10 +#define debugMarkCell(lev,x,y,z) \ + errMsg("debugMarkCell",this->mName<<" step: "<mStepCnt<<" lev:"<<(lev)<<" marking "<dfVecX[dir],(yy)+this->dfVecY[dir],(zz)+this->dfVecZ[dir],set) ] +#define _RFLAG_NBINV(level,xx,yy,zz,set, dir) mLevel[level].mprsFlags[set][ LBMGI((level),(xx)+this->dfVecX[this->dfInv[dir]],(yy)+this->dfVecY[this->dfInv[dir]],(zz)+this->dfVecZ[this->dfInv[dir]],set) ] + +// array handling ----------------------------------------------------------------------------------------------- + +#define _LBMQI(level, ii,ij,ik, is, lunused) ( (mLevel[level].lOffsy*(ik)) + (mLevel[level].lOffsx*(ij)) + (ii) ) +#define _QCELL(level,xx,yy,zz,set,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx),(yy),(zz),(set), l)*dTotalNum +(l)]) +#define _QCELL_NB(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx)+this->dfVecX[dir],(yy)+this->dfVecY[dir],(zz)+this->dfVecZ[dir],set, l)*dTotalNum +(l)]) +#define _QCELL_NBINV(level,xx,yy,zz,set, dir,l) (mLevel[level].mprsCells[(set)][ LBMQI((level),(xx)+this->dfVecX[this->dfInv[dir]],(yy)+this->dfVecY[this->dfInv[dir]],(zz)+this->dfVecZ[this->dfInv[dir]],set, l)*dTotalNum +(l)]) + +#define QCELLSTEP dTotalNum +#define _RACPNT(level, ii,ij,ik, is ) &QCELL(level,ii,ij,ik,is,0) +#define _RAC(s,l) (s)[(l)] + + +#if FSGR_STRICT_DEBUG==1 + +#define LBMGI(level,ii,ij,ik, is) debLBMGI(level,ii,ij,ik, is) +#define RFLAG(level,xx,yy,zz,set) debRFLAG(level,xx,yy,zz,set) +#define RFLAG_NB(level,xx,yy,zz,set, dir) debRFLAG_NB(level,xx,yy,zz,set, dir) +#define RFLAG_NBINV(level,xx,yy,zz,set, dir) debRFLAG_NBINV(level,xx,yy,zz,set, dir) + +#define LBMQI(level,ii,ij,ik, is, l) debLBMQI(level,ii,ij,ik, is, l) +#define QCELL(level,xx,yy,zz,set,l) debQCELL(level,xx,yy,zz,set,l) +#define QCELL_NB(level,xx,yy,zz,set, dir,l) debQCELL_NB(level,xx,yy,zz,set, dir,l) +#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) debQCELL_NBINV(level,xx,yy,zz,set, dir,l) +#define RACPNT(level, ii,ij,ik, is ) debRACPNT(level, ii,ij,ik, is ) +#define RAC(s,l) debRAC(s,l) + +#else // FSGR_STRICT_DEBUG==1 + +#define LBMGI(level,ii,ij,ik, is) _LBMGI(level,ii,ij,ik, is) +#define RFLAG(level,xx,yy,zz,set) _RFLAG(level,xx,yy,zz,set) +#define RFLAG_NB(level,xx,yy,zz,set, dir) _RFLAG_NB(level,xx,yy,zz,set, dir) +#define RFLAG_NBINV(level,xx,yy,zz,set, dir) _RFLAG_NBINV(level,xx,yy,zz,set, dir) + +#define LBMQI(level,ii,ij,ik, is, l) _LBMQI(level,ii,ij,ik, is, l) +#define QCELL(level,xx,yy,zz,set,l) _QCELL(level,xx,yy,zz,set,l) +#define QCELL_NB(level,xx,yy,zz,set, dir,l) _QCELL_NB(level,xx,yy,zz,set, dir, l) +#define QCELL_NBINV(level,xx,yy,zz,set, dir,l) _QCELL_NBINV(level,xx,yy,zz,set, dir,l) +#define RACPNT(level, ii,ij,ik, is ) _RACPNT(level, ii,ij,ik, is ) +#define RAC(s,l) _RAC(s,l) + +#endif // FSGR_STRICT_DEBUG==1 + +// general defines ----------------------------------------------------------------------------------------------- + +// replace TESTFLAG +#define FLAGISEXACT(flag, compflag) ((flag & compflag)==compflag) + +#if LBMDIM==2 +#define dC 0 +#define dN 1 +#define dS 2 +#define dE 3 +#define dW 4 +#define dNE 5 +#define dNW 6 +#define dSE 7 +#define dSW 8 +#else +// direction indices +#define dC 0 +#define dN 1 +#define dS 2 +#define dE 3 +#define dW 4 +#define dT 5 +#define dB 6 +#define dNE 7 +#define dNW 8 +#define dSE 9 +#define dSW 10 +#define dNT 11 +#define dNB 12 +#define dST 13 +#define dSB 14 +#define dET 15 +#define dEB 16 +#define dWT 17 +#define dWB 18 +#endif +//? #define dWB 18 + +// default init for dFlux values +#define FLUX_INIT 0.5f * (float)(this->cDfNum) + +// only for non DF dir handling! +#define dNET 19 +#define dNWT 20 +#define dSET 21 +#define dSWT 22 +#define dNEB 23 +#define dNWB 24 +#define dSEB 25 +#define dSWB 26 + +//! fill value for boundary cells +#define BND_FILL 0.0 + +#define DFL1 (1.0/ 3.0) +#define DFL2 (1.0/18.0) +#define DFL3 (1.0/36.0) + +// loops over _all_ cells (including boundary layer) +#define FSGR_FORIJK_BOUNDS(leveli) \ + for(int k= getForZMinBnd(); k< getForZMaxBnd(leveli); ++k) \ + for(int j=0;jLBM_DFNUM)) { errFatal("LbmFsgrSolver::getCollideEq","Invalid DFEQ call "<dfEquil[l] * rho; } + RAC(ecel, dMass) = mass; + RAC(ecel, dFfrac) = mass/rho; + RAC(ecel, dFlux) = FLUX_INIT; + changeFlag(level, i,j,k, workSet, flag); + + workSet ^= 1; + changeFlag(level, i,j,k, workSet, flag); + return; +} + +void +LbmFsgrSolver::initVelocityCell(int level, int i,int j,int k, CellFlagType flag, LbmFloat rho, LbmFloat mass, LbmVec vel) { + LbmFloat *ecel; + int workSet = mLevel[level].setCurr; + + ecel = RACPNT(level, i,j,k, workSet); + FORDF0 { RAC(ecel, l) = getCollideEq(l, rho,vel[0],vel[1],vel[2]); } + RAC(ecel, dMass) = mass; + RAC(ecel, dFfrac) = mass/rho; + RAC(ecel, dFlux) = FLUX_INIT; + changeFlag(level, i,j,k, workSet, flag); + + workSet ^= 1; + changeFlag(level, i,j,k, workSet, flag); + return; +} + +int LbmFsgrSolver::getForZMinBnd() { + return 0; +} +int LbmFsgrSolver::getForZMin1() { + if(LBMDIM==2) return 0; + return 1; +} + +int LbmFsgrSolver::getForZMaxBnd(int lev) { + if(LBMDIM==2) return 1; + return mLevel[lev].lSizez -0; +} +int LbmFsgrSolver::getForZMax1(int lev) { + if(LBMDIM==2) return 1; + return mLevel[lev].lSizez -1; +} + +bool LbmFsgrSolver::checkDomainBounds(int lev,int i,int j,int k) { + if(i<0) return false; + if(j<0) return false; + if(k<0) return false; + if(i>mLevel[lev].lSizex-1) return false; + if(j>mLevel[lev].lSizey-1) return false; + if(k>mLevel[lev].lSizez-1) return false; + return true; +} +bool LbmFsgrSolver::checkDomainBoundsPos(int lev,LbmVec pos) { + const int i= (int)pos[0]; + if(i<0) return false; + if(i>mLevel[lev].lSizex-1) return false; + const int j= (int)pos[1]; + if(j<0) return false; + if(j>mLevel[lev].lSizey-1) return false; + const int k= (int)pos[2]; + if(k<0) return false; + if(k>mLevel[lev].lSizez-1) return false; + return true; +} + +void LbmFsgrSolver::initInterfaceVars(int level, int i,int j,int k,int workSet, bool initMass) { + LbmFloat *ccel = &QCELL(level ,i,j,k, workSet,0); + LbmFloat nrho = 0.0; + FORDF0 { nrho += RAC(ccel,l); } + if(initMass) { + RAC(ccel,dMass) = nrho; + RAC(ccel, dFfrac) = 1.; + } else { + // preinited, e.g. from reinitFlags + RAC(ccel, dFfrac) = RAC(ccel, dMass)/nrho; + RAC(ccel, dFlux) = FLUX_INIT; + } +} + + +#endif + + diff --git a/intern/elbeem/intern/solver_init.cpp b/intern/elbeem/intern/solver_init.cpp new file mode 100644 index 00000000000..abec4a89c89 --- /dev/null +++ b/intern/elbeem/intern/solver_init.cpp @@ -0,0 +1,2320 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Standard LBM Factory implementation + * + *****************************************************************************/ + + +#include "solver_class.h" +#include "solver_relax.h" +// for geo init FGI_ defines +#include "elbeem.h" + +// helper for 2d init +#define SWAPYZ(vec) { \ + const LbmFloat tmp = (vec)[2]; \ + (vec)[2] = (vec)[1]; (vec)[1] = tmp; } + + +/*****************************************************************************/ +//! common variables + +/*****************************************************************************/ +/*! 3D implementation D3Q19 */ +#if LBMDIM==3 + + //! how many dimensions? + const int LbmFsgrSolver::cDimension = 3; + + // Wi factors for collide step + const LbmFloat LbmFsgrSolver::cCollenZero = (1.0/3.0); + const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/18.0); + const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0); + + //! threshold value for filled/emptied cells + const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005; + const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005; + const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001; + const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001; + + //! size of a single set of distribution functions + const int LbmFsgrSolver::cDfNum = 19; + //! direction vector contain vecs for all spatial dirs, even if not used for LBM model + const int LbmFsgrSolver::cDirNum = 27; + + //const string LbmFsgrSolver::dfString[ cDfNum ] = { + const char* LbmFsgrSolver::dfString[ cDfNum ] = { + " C", " N"," S"," E"," W"," T"," B", + "NE","NW","SE","SW", + "NT","NB","ST","SB", + "ET","EB","WT","WB" + }; + + const int LbmFsgrSolver::dfNorm[ cDfNum ] = { + cDirC, cDirN, cDirS, cDirE, cDirW, cDirT, cDirB, + cDirNE, cDirNW, cDirSE, cDirSW, + cDirNT, cDirNB, cDirST, cDirSB, + cDirET, cDirEB, cDirWT, cDirWB + }; + + const int LbmFsgrSolver::dfInv[ cDfNum ] = { + cDirC, cDirS, cDirN, cDirW, cDirE, cDirB, cDirT, + cDirSW, cDirSE, cDirNW, cDirNE, + cDirSB, cDirST, cDirNB, cDirNT, + cDirWB, cDirWT, cDirEB, cDirET + }; + + const int LbmFsgrSolver::dfRefX[ cDfNum ] = { + 0, 0, 0, 0, 0, 0, 0, + cDirSE, cDirSW, cDirNE, cDirNW, + 0, 0, 0, 0, + cDirEB, cDirET, cDirWB, cDirWT + }; + + const int LbmFsgrSolver::dfRefY[ cDfNum ] = { + 0, 0, 0, 0, 0, 0, 0, + cDirNW, cDirNE, cDirSW, cDirSE, + cDirNB, cDirNT, cDirSB, cDirST, + 0, 0, 0, 0 + }; + + const int LbmFsgrSolver::dfRefZ[ cDfNum ] = { + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + cDirST, cDirSB, cDirNT, cDirNB, + cDirWT, cDirWB, cDirET, cDirEB + }; + + // Vector Order 3D: + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 + // 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1 + // 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1 + // 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1 + + const int LbmFsgrSolver::dfVecX[ cDirNum ] = { + 0, 0,0, 1,-1, 0,0, + 1,-1,1,-1, + 0,0,0,0, + 1,1,-1,-1, + 1,-1, 1,-1, + 1,-1, 1,-1, + }; + const int LbmFsgrSolver::dfVecY[ cDirNum ] = { + 0, 1,-1, 0,0,0,0, + 1,1,-1,-1, + 1,1,-1,-1, + 0,0,0,0, + 1, 1,-1,-1, + 1, 1,-1,-1 + }; + const int LbmFsgrSolver::dfVecZ[ cDirNum ] = { + 0, 0,0,0,0,1,-1, + 0,0,0,0, + 1,-1,1,-1, + 1,-1,1,-1, + 1, 1, 1, 1, + -1,-1,-1,-1 + }; + + const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = { + 0, 0,0, 1,-1, 0,0, + 1,-1,1,-1, + 0,0,0,0, + 1,1,-1,-1, + 1,-1, 1,-1, + 1,-1, 1,-1 + }; + const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = { + 0, 1,-1, 0,0,0,0, + 1,1,-1,-1, + 1,1,-1,-1, + 0,0,0,0, + 1, 1,-1,-1, + 1, 1,-1,-1 + }; + const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = { + 0, 0,0,0,0,1,-1, + 0,0,0,0, + 1,-1,1,-1, + 1,-1,1,-1, + 1, 1, 1, 1, + -1,-1,-1,-1 + }; + + /* principal directions */ + const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = { + 1,-1, 0,0, 0,0 + }; + const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = { + 0,0, 1,-1, 0,0 + }; + const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = { + 0,0, 0,0, 1,-1 + }; + + /*! arrays for les model coefficients, inited in lbmsolver constructor */ + LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ]; + LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ]; + + + const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= { + cCollenZero, + cCollenOne, cCollenOne, cCollenOne, + cCollenOne, cCollenOne, cCollenOne, + cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, + cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, + cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo + }; + + /* precalculated equilibrium dfs, inited in lbmsolver constructor */ + LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ]; + +#else // end LBMDIM==3 , LBMDIM==2 + +/*****************************************************************************/ +/*! 2D implementation D2Q9 */ + + //! how many dimensions? + const int LbmFsgrSolver::cDimension = 2; + + //! Wi factors for collide step + const LbmFloat LbmFsgrSolver::cCollenZero = (4.0/9.0); + const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/9.0); + const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0); + + //! threshold value for filled/emptied cells + const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005; + const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005; + const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001; + const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001; + + //! size of a single set of distribution functions + const int LbmFsgrSolver::cDfNum = 9; + const int LbmFsgrSolver::cDirNum = 9; + + //const string LbmFsgrSolver::dfString[ cDfNum ] = { + const char* LbmFsgrSolver::dfString[ cDfNum ] = { + " C", + " N", " S", " E", " W", + "NE", "NW", "SE","SW" + }; + + const int LbmFsgrSolver::dfNorm[ cDfNum ] = { + cDirC, + cDirN, cDirS, cDirE, cDirW, + cDirNE, cDirNW, cDirSE, cDirSW + }; + + const int LbmFsgrSolver::dfInv[ cDfNum ] = { + cDirC, + cDirS, cDirN, cDirW, cDirE, + cDirSW, cDirSE, cDirNW, cDirNE + }; + + const int LbmFsgrSolver::dfRefX[ cDfNum ] = { + 0, + 0, 0, 0, 0, + cDirSE, cDirSW, cDirNE, cDirNW + }; + + const int LbmFsgrSolver::dfRefY[ cDfNum ] = { + 0, + 0, 0, 0, 0, + cDirNW, cDirNE, cDirSW, cDirSE + }; + + const int LbmFsgrSolver::dfRefZ[ cDfNum ] = { + 0, 0, 0, 0, 0, + 0, 0, 0, 0 + }; + + // Vector Order 2D: + // 0 1 2 3 4 5 6 7 8 + // 0, 0,0, 1,-1, 1,-1,1,-1 + // 0, 1,-1, 0,0, 1,1,-1,-1 + + const int LbmFsgrSolver::dfVecX[ cDirNum ] = { + 0, + 0,0, 1,-1, + 1,-1,1,-1 + }; + const int LbmFsgrSolver::dfVecY[ cDirNum ] = { + 0, + 1,-1, 0,0, + 1,1,-1,-1 + }; + const int LbmFsgrSolver::dfVecZ[ cDirNum ] = { + 0, 0,0,0,0, 0,0,0,0 + }; + + const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = { + 0, + 0,0, 1,-1, + 1,-1,1,-1 + }; + const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = { + 0, + 1,-1, 0,0, + 1,1,-1,-1 + }; + const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = { + 0, 0,0,0,0, 0,0,0,0 + }; + + const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = { + 1,-1, 0,0 + }; + const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = { + 0,0, 1,-1 + }; + const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = { + 0,0, 0,0 + }; + + + /*! arrays for les model coefficients, inited in lbmsolver constructor */ + LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ]; + LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ]; + + + const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= { + cCollenZero, + cCollenOne, cCollenOne, cCollenOne, cCollenOne, + cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo + }; + + /* precalculated equilibrium dfs, inited in lbmsolver constructor */ + LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ]; + +// D2Q9 end +#endif // LBMDIM==2 + + +// required globals +extern bool glob_mpactive; +extern int glob_mpnum, glob_mpindex; + + +/****************************************************************************** + * Lbm Constructor + *****************************************************************************/ +LbmFsgrSolver::LbmFsgrSolver() : + //D(), + mCurrentMass(0.0), mCurrentVolume(0.0), + mNumProblems(0), + mAvgMLSUPS(0.0), mAvgMLSUPSCnt(0.0), + mpPreviewSurface(NULL), + mTimeAdap(true), mForceTimeStepReduce(false), + mFVHeight(0.0), mFVArea(1.0), mUpdateFVHeight(false), + mInitSurfaceSmoothing(0), mFsSurfGenSetting(0), + mTimestepReduceLock(0), + mTimeSwitchCounts(0), mTimeMaxvelStepCnt(0), + mSimulationTime(0.0), mLastSimTime(0.0), + mMinTimestep(0.0), mMaxTimestep(0.0), + mMaxNoCells(0), mMinNoCells(0), mAvgNumUsedCells(0), + mObjectSpeeds(), mObjectPartslips(), mObjectMassMovnd(), + mMOIVertices(), mMOIVerticesOld(), mMOINormals(), + mIsoWeightMethod(1), + mMaxRefine(1), + mDfScaleUp(-1.0), mDfScaleDown(-1.0), + mInitialCsmago(0.02), // set to 0.02 for mMaxRefine==0 below and default for fine level, coarser ones are 0.03 + mDebugOmegaRet(0.0), + mLastOmega(1e10), mLastGravity(1e10), + mNumInvIfTotal(0), mNumFsgrChanges(0), + mDisableStandingFluidInit(0), + mInit2dYZ(false), + mForceTadapRefine(-1), mCutoff(-1) +{ + // not much to do here... +#if LBM_INCLUDE_TESTSOLVERS==1 + mpTest = new LbmTestdata(); + mMpNum = mMpIndex = 0; + mOrgSizeX = 0; + mOrgStartX = 0.; + mOrgEndX = 0.; +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + mpIso = new IsoSurface( mIsoValue ); + + // init equilibrium dist. func + LbmFloat rho=1.0; + FORDF0 { + dfEquil[l] = this->getCollideEq( l,rho, 0.0, 0.0, 0.0); + } + dfEquil[dMass] = 1.; + dfEquil[dFfrac] = 1.; + dfEquil[dFlux] = FLUX_INIT; + + // init LES + int odm = 0; + for(int m=0; mlesCoeffDiag[m][l] = + this->lesCoeffOffdiag[m][l] = 0.0; + } + } + for(int m=0; mreadString("material_surf", matIso, "SimulationLbm","mpIso->material", false ); + mpIso->setMaterialName( matIso ); + mOutputSurfacePreview = mpSifAttrs->readInt("surfacepreview", mOutputSurfacePreview, "SimulationLbm","mOutputSurfacePreview", false ); + mTimeAdap = mpSifAttrs->readBool("timeadap", mTimeAdap, "SimulationLbm","mTimeAdap", false ); + mDomainBound = mpSifAttrs->readString("domainbound", mDomainBound, "SimulationLbm","mDomainBound", false ); + mDomainPartSlipValue = mpSifAttrs->readFloat("domainpartslip", mDomainPartSlipValue, "SimulationLbm","mDomainPartSlipValue", false ); + + mIsoWeightMethod= mpSifAttrs->readInt("isoweightmethod", mIsoWeightMethod, "SimulationLbm","mIsoWeightMethod", false ); + mInitSurfaceSmoothing = mpSifAttrs->readInt("initsurfsmooth", mInitSurfaceSmoothing, "SimulationLbm","mInitSurfaceSmoothing", false ); + mSmoothSurface = mpSifAttrs->readFloat("smoothsurface", mSmoothSurface, "SimulationLbm","mSmoothSurface", false ); + mSmoothNormals = mpSifAttrs->readFloat("smoothnormals", mSmoothNormals, "SimulationLbm","mSmoothNormals", false ); + mFsSurfGenSetting = mpSifAttrs->readInt("fssurfgen", mFsSurfGenSetting, "SimulationLbm","mFsSurfGenSetting", false ); + + // refinement + mMaxRefine = mRefinementDesired; + mMaxRefine = mpSifAttrs->readInt("maxrefine", mMaxRefine ,"LbmFsgrSolver", "mMaxRefine", false); + if(mMaxRefine<0) mMaxRefine=0; + if(mMaxRefine>FSGR_MAXNOOFLEVELS) mMaxRefine=FSGR_MAXNOOFLEVELS-1; + mDisableStandingFluidInit = mpSifAttrs->readInt("disable_stfluidinit", mDisableStandingFluidInit,"LbmFsgrSolver", "mDisableStandingFluidInit", false); + mInit2dYZ = mpSifAttrs->readBool("init2dyz", mInit2dYZ,"LbmFsgrSolver", "mInit2dYZ", false); + mForceTadapRefine = mpSifAttrs->readInt("forcetadaprefine", mForceTadapRefine,"LbmFsgrSolver", "mForceTadapRefine", false); + + // demo mode settings + mFVHeight = mpSifAttrs->readFloat("fvolheight", mFVHeight, "LbmFsgrSolver","mFVHeight", false ); + // FIXME check needed? + mFVArea = mpSifAttrs->readFloat("fvolarea", mFVArea, "LbmFsgrSolver","mFArea", false ); + + // debugging - skip some time... + double starttimeskip = 0.; + starttimeskip = mpSifAttrs->readFloat("forcestarttimeskip", starttimeskip, "LbmFsgrSolver","starttimeskip", false ); + mSimulationTime += starttimeskip; + if(starttimeskip>0.) debMsgStd("LbmFsgrSolver::parseStdAttrList",DM_NOTIFY,"Used starttimeskip="<parseTestdataAttrList(mpSifAttrs); +#ifdef ELBEEM_PLUGIN + mUseTestdata=1; // DEBUG +#endif // ELBEEM_PLUGIN + + mMpNum = mpSifAttrs->readInt("mpnum", mMpNum ,"LbmFsgrSolver", "mMpNum", false); + mMpIndex = mpSifAttrs->readInt("mpindex", mMpIndex ,"LbmFsgrSolver", "mMpIndex", false); + if(glob_mpactive) { + // used instead... + mMpNum = glob_mpnum; + mMpIndex = glob_mpindex; + } else { + glob_mpnum = mMpNum; + glob_mpindex = 0; + } + errMsg("LbmFsgrSolver::parseAttrList"," mpactive:"<0) { + mUseTestdata=1; // needed in this case... + } + + errMsg("LbmFsgrSolver::LBM_INCLUDE_TESTSOLVERS","Active, mUseTestdata:"<=2.) mUseTestdata=1; // equiv. to test solver check +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + + mInitialCsmago = mpSifAttrs->readFloat("csmago", mInitialCsmago, "SimulationLbm","mInitialCsmago", false ); + // deprecated! + float mInitialCsmagoCoarse = 0.0; + mInitialCsmagoCoarse = mpSifAttrs->readFloat("csmago_coarse", mInitialCsmagoCoarse, "SimulationLbm","mInitialCsmagoCoarse", false ); +#if USE_LES==1 +#else // USE_LES==1 + debMsgStd("LbmFsgrSolver", DM_WARNING, "LES model switched off!",2); + mInitialCsmago = 0.0; +#endif // USE_LES==1 +} + + +/****************************************************************************** + * Initialize omegas and forces on all levels (for init/timestep change) + *****************************************************************************/ +void LbmFsgrSolver::initLevelOmegas() +{ + // no explicit settings + mOmega = mpParam->calculateOmega(mSimulationTime); + mGravity = vec2L( mpParam->calculateGravity(mSimulationTime) ); + mSurfaceTension = 0.; //mpParam->calculateSurfaceTension(); // unused + if(mInit2dYZ) { SWAPYZ(mGravity); } + + // check if last init was ok + LbmFloat gravDelta = norm(mGravity-mLastGravity); + //errMsg("ChannelAnimDebug","t:"<1)&&(mInitialCsmagogetTimestep(); + mLevel[i].lcsmago = fineCsmago; //CSMAGO_INITIAL; + mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago; + mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0); + } + + // init all sub levels + for(int i=mMaxRefine-1; i>=0; i--) { + //mLevel[i].omega = 2.0 * (mLevel[i+1].omega-0.5) + 0.5; + double nomega = 0.5 * ( (1.0/(double)mLevel[i+1].omega) -0.5) + 0.5; + nomega = 1.0/nomega; + mLevel[i].omega = (LbmFloat)nomega; + mLevel[i].timestep = 2.0 * mLevel[i+1].timestep; + mLevel[i].lcsmago = coarseCsmago; + mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago; + mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0); + } + + // for lbgk + mLevel[ mMaxRefine ].gravity = mGravity / mLevel[ mMaxRefine ].omega; + for(int i=mMaxRefine-1; i>=0; i--) { + // should be the same on all levels... + // for lbgk + mLevel[i].gravity = (mLevel[i+1].gravity * mLevel[i+1].omega) * 2.0 / mLevel[i].omega; + } + + mLastOmega = mOmega; + mLastGravity = mGravity; + // debug? invalidate old values... + mGravity = -100.0; + mOmega = -100.0; + + for(int i=0; i<=mMaxRefine; i++) { + if(!mSilent) { + errMsg("LbmFsgrSolver", "Level init "<0) { + mDfScaleUp = (mLevel[0 ].timestep/mLevel[0+1].timestep)* (1.0/mLevel[0 ].omega-1.0)/ (1.0/mLevel[0+1].omega-1.0); // yu + mDfScaleDown = (mLevel[0+1].timestep/mLevel[0 ].timestep)* (1.0/mLevel[0+1].omega-1.0)/ (1.0/mLevel[0 ].omega-1.0); // yu + } +} + + +/****************************************************************************** + * Init Solver (values should be read from config file) + *****************************************************************************/ + +/*! finish the init with config file values (allocate arrays...) */ +bool LbmFsgrSolver::initializeSolverMemory() +{ + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init start... "<0) { + mSizex *= mCppfStage; + mSizey *= mCppfStage; + mSizez *= mCppfStage; + } + if(mFsSurfGenSetting==-1) { + // all on + mFsSurfGenSetting = + fssgNormal | fssgNoNorth | fssgNoSouth | fssgNoEast | + fssgNoWest | fssgNoTop | fssgNoBottom | fssgNoObs ; + } + + // size inits to force cubic cells and mult4 level dimensions + // and make sure we dont allocate too much... + bool memOk = false; + int orgSx = mSizex; + int orgSy = mSizey; + int orgSz = mSizez; + double sizeReduction = 1.0; + double memEstFromFunc = -1.0; + string memreqStr(""); + bool firstMInit = true; + int minitTries=0; + while(!memOk) { + minitTries++; + initGridSizes( mSizex, mSizey, mSizez, + mvGeoStart, mvGeoEnd, mMaxRefine, PARALLEL); + + // MPT +#if LBM_INCLUDE_TESTSOLVERS==1 + if(firstMInit) { + mrSetup(); + } +#endif // LBM_INCLUDE_TESTSOLVERS==1 + firstMInit=false; + + calculateMemreqEstimate( mSizex, mSizey, mSizez, + mMaxRefine, mFarFieldSize, &memEstFromFunc, &memreqStr ); + + double memLimit; + string memLimStr("-"); + if(sizeof(void*)==4) { + // 32bit system, limit to 2GB + memLimit = 2.0* 1024.0*1024.0*1024.0; + memLimStr = string("2GB"); + } else { + // 64bit, just take 16GB as limit for now... + memLimit = 16.0* 1024.0*1024.0*1024.0; + memLimStr = string("16GB"); + } + if(memEstFromFunc>memLimit) { + sizeReduction *= 0.9; + mSizex = (int)(orgSx * sizeReduction); + mSizey = (int)(orgSy * sizeReduction); + mSizez = (int)(orgSz * sizeReduction); + debMsgStd("LbmFsgrSolver::initialize",DM_WARNING,"initGridSizes: memory limit exceeded "<< + //memEstFromFunc<<"/"<setSize(mSizex, mSizey, mSizez); + if((minitTries>1)&&(glob_mpnum)) { errMsg("LbmFsgrSolver::initialize","Warning!!!!!!!!!!!!!!! Original gridsize changed........."); } + + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Definitions: " + <<"LBM_EPSILON="<setSimulationMaxSpeed(0.0); + if(mFVHeight>0.0) mpParam->setFluidVolumeHeight(mFVHeight); + mpParam->setTadapLevels( mMaxRefine+1 ); + + if(mForceTadapRefine>mMaxRefine) { + mpParam->setTadapLevels( mForceTadapRefine+1 ); + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Forcing a t-adap refine level of "<calculateAllMissingValues(mSimulationTime, false)) { + errFatal("LbmFsgrSolver::initialize","Fatal: failed to init parameters! Aborting...",SIMWORLD_INITERROR); + return false; + } + + + // init vectors + for(int i=0; i<=mMaxRefine; i++) { + mLevel[i].id = i; + mLevel[i].nodeSize = 0.0; + mLevel[i].simCellSize = 0.0; + mLevel[i].omega = 0.0; + mLevel[i].time = 0.0; + mLevel[i].timestep = 1.0; + mLevel[i].gravity = LbmVec(0.0); + mLevel[i].mprsCells[0] = NULL; + mLevel[i].mprsCells[1] = NULL; + mLevel[i].mprsFlags[0] = NULL; + mLevel[i].mprsFlags[1] = NULL; + + mLevel[i].avgOmega = 0.0; + mLevel[i].avgOmegaCnt = 0.0; + } + + // init sizes + mLevel[mMaxRefine].lSizex = mSizex; + mLevel[mMaxRefine].lSizey = mSizey; + mLevel[mMaxRefine].lSizez = mSizez; + for(int i=mMaxRefine-1; i>=0; i--) { + mLevel[i].lSizex = mLevel[i+1].lSizex/2; + mLevel[i].lSizey = mLevel[i+1].lSizey/2; + mLevel[i].lSizez = mLevel[i+1].lSizez/2; + } + + // safety check + if(sizeof(CellFlagType) != CellFlagTypeSize) { + errFatal("LbmFsgrSolver::initialize","Fatal Error: CellFlagType has wrong size! Is:"<getCellSize(); + mLevel[ mMaxRefine ].lcellfactor = 1.0; + LONGINT rcellSize = ((mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez) *dTotalNum); + // +4 for safety ? + mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4); + +#if COMPRESSGRIDS==0 + mLevel[ mMaxRefine ].mprsCells[0] = new LbmFloat[ rcellSize +4 ]; + mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +4 ]; + ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4); +#else // COMPRESSGRIDS==0 + LONGINT compressOffset = (mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*dTotalNum*2); + mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +compressOffset +4 ]; + mLevel[ mMaxRefine ].mprsCells[0] = mLevel[ mMaxRefine ].mprsCells[1]+compressOffset; + ownMemCheck += sizeof(LbmFloat) * (rcellSize +compressOffset +4); +#endif // COMPRESSGRIDS==0 + + LbmFloat lcfdimFac = 8.0; + if(LBMDIM==2) lcfdimFac = 4.0; + for(int i=mMaxRefine-1; i>=0; i--) { + mLevel[i].nodeSize = 2.0 * mLevel[i+1].nodeSize; + mLevel[i].simCellSize = 2.0 * mLevel[i+1].simCellSize; + mLevel[i].lcellfactor = mLevel[i+1].lcellfactor * lcfdimFac; + + if(LBMDIM==2){ mLevel[i].lSizez = 1; } // 2D + rcellSize = ((mLevel[i].lSizex*mLevel[i].lSizey*mLevel[i].lSizez) *dTotalNum); + mLevel[i].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + mLevel[i].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ]; + ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4); + mLevel[i].mprsCells[0] = new LbmFloat[ rcellSize +4 ]; + mLevel[i].mprsCells[1] = new LbmFloat[ rcellSize +4 ]; + ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4); + } + + // isosurface memory, use orig res values + if(mFarFieldSize>0.) { + ownMemCheck += (double)( (3*sizeof(int)+sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) ); + } else { + // ignore 3 int slices... + ownMemCheck += (double)( ( sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) ); + } + + // sanity check +#if ELBEEM_PLUGIN!=1 + if(ABS(1.0-ownMemCheck/memEstFromFunc)>0.01) { + errMsg("LbmFsgrSolver::initialize","Sanity Error - memory estimate is off! real:"<=0; i--) { + mLevel[i].lOffsx = mLevel[i].lSizex; + mLevel[i].lOffsy = mLevel[i].lOffsx*mLevel[i].lSizey; + mLevel[i].lOffsz = mLevel[i].lOffsy*mLevel[i].lSizez; + mLevel[i].setCurr = 0; + mLevel[i].setOther = 1; + mLevel[i].lsteps = 0; + mLevel[i].lmass = 0.0; + mLevel[i].lvolume = 0.0; + } + + // calc omega, force for all levels + initLevelOmegas(); + mMinTimestep = mpParam->getTimestep(); + mMaxTimestep = mpParam->getTimestep(); + + // init isosurf + mpIso->setIsolevel( mIsoValue ); +#if LBM_INCLUDE_TESTSOLVERS==1 + if(mUseTestdata) { + mpTest->setMaterialName( mpIso->getMaterialName() ); + delete mpIso; + mpIso = mpTest; + if(mpTest->mFarfMode>0) { // 3d off + mpTest->setIsolevel(-100.0); + } else { + mpTest->setIsolevel( mIsoValue ); + } + } +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + // approximate feature size with mesh resolution + float featureSize = mLevel[ mMaxRefine ].nodeSize*0.5; + // smooth vars defined in solver_interface, set by simulation object + // reset for invalid values... + if((mSmoothSurface<0.)||(mSmoothSurface>50.)) mSmoothSurface = 1.; + if((mSmoothNormals<0.)||(mSmoothNormals>50.)) mSmoothNormals = 1.; + mpIso->setSmoothSurface( mSmoothSurface * featureSize ); + mpIso->setSmoothNormals( mSmoothNormals * featureSize ); + + // init iso weight values mIsoWeightMethod + int wcnt = 0; + float totw = 0.0; + for(int ak=-1;ak<=1;ak++) + for(int aj=-1;aj<=1;aj++) + for(int ai=-1;ai<=1;ai++) { + switch(mIsoWeightMethod) { + case 1: // light smoothing + mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) ); + break; + case 2: // very light smoothing + mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) ); + mIsoWeight[wcnt] *= mIsoWeight[wcnt]; + break; + case 3: // no smoothing + if(ai==0 && aj==0 && ak==0) mIsoWeight[wcnt] = 1.0; + else mIsoWeight[wcnt] = 0.0; + break; + default: // strong smoothing (=0) + mIsoWeight[wcnt] = 1.0; + break; + } + totw += mIsoWeight[wcnt]; + wcnt++; + } + for(int i=0; i<27; i++) mIsoWeight[i] /= totw; + + LbmVec isostart = vec2L(mvGeoStart); + LbmVec isoend = vec2L(mvGeoEnd); + int twodOff = 0; // 2d slices + if(LBMDIM==2) { + LbmFloat sn,se; + sn = isostart[2]+(isoend[2]-isostart[2])*0.5 - ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5; + se = isostart[2]+(isoend[2]-isostart[2])*0.5 + ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5; + isostart[2] = sn; + isoend[2] = se; + twodOff = 2; + } + int isosx = mSizex+2; + int isosy = mSizey+2; + int isosz = mSizez+2+twodOff; + + // MPT +#if LBM_INCLUDE_TESTSOLVERS==1 + //if( strstr( this->getName().c_str(), "mpfluid1" ) != NULL) { + if( (mMpNum>0) && (mMpIndex==0) ) { + //? mpindex==0 + // restore original value for node0 + isosx = mOrgSizeX + 2; + isostart[0] = mOrgStartX; + isoend[0] = mOrgEndX; + } + errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<mGCMin.mSrcx,mpTest->mGCMin.mSrcy,mpTest->mGCMin.mSrcz)<<" dst" + << PRINT_VEC(mpTest->mGCMin.mDstx,mpTest->mGCMin.mDsty,mpTest->mGCMin.mDstz)<<" consize" + << PRINT_VEC(mpTest->mGCMin.mConSizex,mpTest->mGCMin.mConSizey,mpTest->mGCMin.mConSizez)<<" "); + errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<mGCMax.mSrcx,mpTest->mGCMax.mSrcy,mpTest->mGCMax.mSrcz)<<" dst" + << PRINT_VEC(mpTest->mGCMax.mDstx,mpTest->mGCMax.mDsty,mpTest->mGCMax.mDstz)<<" consize" + << PRINT_VEC(mpTest->mGCMax.mConSizex,mpTest->mGCMax.mConSizey,mpTest->mGCMax.mConSizez)<<" "); +#endif // LBM_INCLUDE_TESTSOLVERS==1 + + errMsg(" SETISO ", "iso "<setStart( vec2G(isostart) ); + mpIso->setEnd( vec2G(isoend) ); + LbmVec isodist = isoend-isostart; + + int isosubs = mIsoSubdivs; + if(mFarFieldSize>1.) { + errMsg("LbmFsgrSolver::initialize","Warning - resetting isosubdivs, using fulledge!"); + isosubs = 1; + mpIso->setUseFulledgeArrays(true); + } + mpIso->setSubdivs(isosubs); + + mpIso->initializeIsosurface( isosx,isosy,isosz, vec2G(isodist) ); + + // reset iso field + for(int ak=0;akgetData(ai,aj,ak) = 0.0; } + + + /* init array (set all invalid first) */ + preinitGrids(); + for(int lev=0; lev<=mMaxRefine; lev++) { + FSGR_FORIJK_BOUNDS(lev) { + RFLAG(lev,i,j,k,0) = RFLAG(lev,i,j,k,0) = 0; // reset for changeFlag usage + if(!mAllfluid) { + initEmptyCell(lev, i,j,k, CFEmpty, -1.0, -1.0); + } else { + initEmptyCell(lev, i,j,k, CFFluid, 1.0, 1.0); + } + } + } + + + if(LBMDIM==2) { + if(mOutputSurfacePreview) { + errMsg("LbmFsgrSolver::init","No preview in 2D allowed!"); + mOutputSurfacePreview = 0; } + } + if((glob_mpactive) && (glob_mpindex>0)) { + mOutputSurfacePreview = 0; + } + +#if LBM_USE_GUI==1 + if(mOutputSurfacePreview) { + errMsg("LbmFsgrSolver::init","No preview in GUI mode... mOutputSurfacePreview=0"); + mOutputSurfacePreview = 0; } +#endif // LBM_USE_GUI==1 + if(mOutputSurfacePreview) { + // same as normal one, but use reduced size + mpPreviewSurface = new IsoSurface( mIsoValue ); + mpPreviewSurface->setMaterialName( mpPreviewSurface->getMaterialName() ); + mpPreviewSurface->setIsolevel( mIsoValue ); + // usually dont display for rendering + mpPreviewSurface->setVisible( false ); + + mpPreviewSurface->setStart( vec2G(isostart) ); + mpPreviewSurface->setEnd( vec2G(isoend) ); + LbmVec pisodist = isoend-isostart; + LbmFloat pfac = mPreviewFactor; + mpPreviewSurface->initializeIsosurface( (int)(pfac*mSizex)+2, (int)(pfac*mSizey)+2, (int)(pfac*mSizez)+2, vec2G(pisodist) ); + //mpPreviewSurface->setName( getName() + "preview" ); + mpPreviewSurface->setName( "preview" ); + + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Preview with sizes "<<(pfac*mSizex)<<","<<(pfac*mSizey)<<","<<(pfac*mSizez)<<" enabled",10); + } + + // init defaults + mAvgNumUsedCells = 0; + mFixMass= 0.0; + return true; +} + +/*! init solver arrays */ +bool LbmFsgrSolver::initializeSolverGrids() { + /* init boundaries */ + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Boundary init...",10); + // init obstacles, and reinit time step size + initGeometryFlags(); + mLastSimTime = -1.0; + // TODO check for invalid cells? nitGenericTestCases(); + + // new - init noslip 1 everywhere... + // half fill boundary cells? + + CellFlagType domainBoundType = CFInvalid; + // TODO use normal object types instad... + if(mDomainBound.find(string("free")) != string::npos) { + domainBoundType = CFBnd | CFBndFreeslip; + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: FreeSlip, value:"<size()); + domainBoundType |= (domainobj<<24); + //for(int i=0; i<(int)(domainobj+0); i++) { + //errMsg("GEOIN","i"<getName()); + //if((*mpGiObjects)[i] == mpIso) { //check... + //} + //} + //errMsg("GEOIN"," dm "<<(domainBoundType>>24)); + + for(int k=0;kgetName().c_str(), "vorttfluid" ) != NULL) && (LBMDIM==2)) { + errMsg("VORTT","init"); + int level=mMaxRefine; + int cx = mLevel[level].lSizex/2; + int cyo = mLevel[level].lSizey/2; + int sx = mLevel[level].lSizex/8; + int sy = mLevel[level].lSizey/8; + LbmFloat rho = 1.; + LbmFloat rhomass = 1.; + LbmFloat uFactor = 0.15; + LbmFloat vdist = 1.0; + + int cy1=cyo-(int)(vdist*sy); + int cy2=cyo+(int)(vdist*sy); + + //for(int j=cy-sy;jcalculateCellSize(); + if(LBMDIM==2) cspv[2] = 1.0; + inmCellCnt = 1; + double nrmMass = (double)mInitialMass / (double)(inmCellCnt) *cspv[0]*cspv[1]*cspv[2] * 1000.0; + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Initial Mass:"<=0; lev--) { + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Coarsening level "<setParticles(mpParticles, mPartDropMassSub); + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Iso Settings, subdivs="<getSubdivs()<<", partsize="<getSmoothSurface()<<","<getSmoothNormals()<<") ",10); + debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init done ... ",10); + mInitDone = 1; + +#if LBM_INCLUDE_TESTSOLVERS==1 + initCpdata(); + initTestdata(); +#endif // ELBEEM_PLUGIN!=1 + // not inited? dont use... + if(mCutoff<0) mCutoff=0; + + initParticles(); + return true; +} + + + +// macros for mov obj init +#if LBMDIM==2 + +#define POS2GRID_CHECK(vec,n) \ + monTotal++;\ + int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \ + if(k!=0) continue; \ + const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \ + if(i<=0) continue; \ + if(i>=mLevel[level].lSizex-1) continue; \ + const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \ + if(j<=0) continue; \ + if(j>=mLevel[level].lSizey-1) continue; \ + +#else // LBMDIM -> 3 +#define POS2GRID_CHECK(vec,n) \ + monTotal++;\ + const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \ + if(i<=0) continue; \ + if(i>=mLevel[level].lSizex-1) continue; \ + const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \ + if(j<=0) continue; \ + if(j>=mLevel[level].lSizey-1) continue; \ + const int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \ + if(k<=0) continue; \ + if(k>=mLevel[level].lSizez-1) continue; \ + +#endif // LBMDIM + +// calculate object velocity from vert arrays in objvel vec +#define OBJVEL_CALC \ + LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { \ + const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; \ + USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); \ + if(usqr>maxusqr) { \ + /* cutoff at maxVelVal */ \ + for(int jj=0; jj<3; jj++) { \ + if(objvel[jj]>0.) objvel[jj] = maxVelVal; \ + if(objvel[jj]<0.) objvel[jj] = -maxVelVal; \ + } \ + } } \ + if(ntype&(CFBndFreeslip)) { \ + const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); \ + const LbmVec oldov=objvel; /*DEBUG*/ \ + objvel = vec2L((*pNormals)[n]) *dp; \ + /* if((j==24)&&(n%5==2)) errMsg("FSBT","n"<size()); + ntlVec3Gfx dvec = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0; + // 2d display as rectangles + ntlVec3Gfx iniPos(0.0); + if(LBMDIM==2) { + dvec[2] = 1.0; + iniPos = (mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))-(dvec*0.0); + } else { + iniPos = (mvGeoStart + ntlVec3Gfx( 0.0 ))-(dvec*0.0); + } + + if( (int)mObjectMassMovnd.size() < numobjs) { + for(int i=mObjectMassMovnd.size(); igetGeoInitId() != mLbmInitId) skip=true; + if( (!staticInit) && (!obj->getIsAnimated()) ) skip=true; + if( ( staticInit) && ( obj->getIsAnimated()) ) skip=true; + if(skip) continue; + debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<getName()<<" skip:"<getIsAnimated()<<" gid:"<getGeoInitId()<<" simgid:"<getGeoInitType()&FGI_ALLBOUNDS) || + (obj->getGeoInitType()&FGI_FLUID) && staticInit ) { + + otype = ntype = CFInvalid; + switch(obj->getGeoInitType()) { + /* case FGI_BNDPART: // old, use noslip for moving part/free objs + case FGI_BNDFREE: + if(!staticInit) { + errMsg("LbmFsgrSolver::initMovingObstacles","Warning - moving free/part slip objects NYI "<getName() ); + otype = ntype = CFBnd|CFBndNoslip; + } else { + if(obj->getGeoInitType()==FGI_BNDPART) otype = ntype = CFBnd|CFBndPartslip; + if(obj->getGeoInitType()==FGI_BNDFREE) otype = ntype = CFBnd|CFBndFreeslip; + } + break; + // off */ + case FGI_BNDPART: rhomass = BND_FILL; + otype = ntype = CFBnd|CFBndPartslip|(OId<<24); + break; + case FGI_BNDFREE: rhomass = BND_FILL; + otype = ntype = CFBnd|CFBndFreeslip|(OId<<24); + break; + // off */ + case FGI_BNDNO: rhomass = BND_FILL; + otype = ntype = CFBnd|CFBndNoslip|(OId<<24); + break; + case FGI_FLUID: + otype = ntype = CFFluid; + break; + case FGI_MBNDINFLOW: + otype = ntype = CFMbndInflow; + break; + case FGI_MBNDOUTFLOW: + otype = ntype = CFMbndOutflow; + break; + } + int wasActive = ((obj->getGeoActive(sourceTime)>0.)? 1:0); + int active = ((obj->getGeoActive(targetTime)>0.)? 1:0); + //errMsg("GEOACTT"," obj "<getName()<<" a:"<getGeoInitType()); continue; } + if((!active) && (otype&(CFMbndOutflow|CFMbndInflow)) ) continue; + + // copied from recalculateObjectSpeeds + mObjectSpeeds[OId] = vec2L(mpParam->calculateLattVelocityFromRw( vec2P( (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) ))); + debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG,"id"<getName()<<" inivel set to "<< mObjectSpeeds[OId]<<", unscaled:"<< (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) ,10 ); + + //vector tNormals; + vector *pNormals = NULL; + mMOINormals.clear(); + if(ntype&(CFBndFreeslip|CFBndPartslip)) { pNormals = &mMOINormals; } + + mMOIVertices.clear(); + if(obj->getMeshAnimated()) { + // do two full update + // TODO tNormals handling!? + mMOIVerticesOld.clear(); + obj->initMovingPointsAnim(sourceTime,mMOIVerticesOld, targetTime, mMOIVertices, pNormals, mLevel[mMaxRefine].nodeSize, mvGeoStart, mvGeoEnd); + monTrafo += mMOIVerticesOld.size(); + obj->applyTransformation(sourceTime, &mMOIVerticesOld,pNormals, 0, mMOIVerticesOld.size(), false ); + monTrafo += mMOIVertices.size(); + obj->applyTransformation(targetTime, &mMOIVertices,NULL /* no old normals needed */, 0, mMOIVertices.size(), false ); + } else { + // only do transform update + obj->getMovingPoints(mMOIVertices,pNormals); + mMOIVerticesOld = mMOIVertices; + // WARNING - assumes mSimulationTime is global!? + obj->applyTransformation(targetTime, &mMOIVertices,pNormals, 0, mMOIVertices.size(), false ); + monTrafo += mMOIVertices.size(); + + // correct flags from last position, but extrapolate + // velocity to next timestep + obj->applyTransformation(sourceTime, &mMOIVerticesOld, NULL /* no old normals needed */, 0, mMOIVerticesOld.size(), false ); + monTrafo += mMOIVerticesOld.size(); + } + + // object types + if(ntype&CFBnd){ + + // check if object is moving at all + if(obj->getIsAnimated()) { + ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime); + // FIXME? + if(normNoSqrt(objMaxVel)>0.0) { ntype |= CFBndMoving; } + // get old type - CHECK FIXME , timestep could have changed - cause trouble? + ntlVec3Gfx oldobjMaxVel = obj->calculateMaxVel(sourceTime - mpParam->getTimestep(),sourceTime); + if(normNoSqrt(oldobjMaxVel)>0.0) { otype |= CFBndMoving; } + } + if(obj->getMeshAnimated()) { ntype |= CFBndMoving; otype |= CFBndMoving; } + CellFlagType rflagnb[27]; + LbmFloat massCheck = 0.; + int massReinits=0; + bool fillCells = (mObjectMassMovnd[OId]<=-1.); + LbmFloat impactCorrFactor = obj->getGeoImpactFactor(targetTime); + + + // first pass - set new obs. cells + if(active) { + for(size_t n=0; n "< "< "<getName()<<" dccd massCheck="<getName()<<" verts"<getName()<<" inflow "<getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); } + RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho; + RAC(tcel, dFlux) = FLUX_INIT; + CellFlagType setFlag = CFInter; + changeFlag(level, i,j,k, workSet, setFlag); + mInitialMass += iniRho; + } + // second static init pass + if(staticInit) { + CellFlagType set2Flag = CFMbndInflow|(OId<<24); + for(size_t n=0; nsize()); + for(int o=0; ogetName()<<" type "<getGeoInitType()<<" anim"<getIsAnimated()<<" "<getVolumeInit() ,9); + if( + ((obj->getGeoInitType()&FGI_ALLBOUNDS) && (obj->getIsAnimated())) || + (obj->getVolumeInit()&VOLUMEINIT_SHELL) ) { + if(!obj->getMeshAnimated()) { + debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<getName()<<" type "<getGeoInitType()<<" anim"<getIsAnimated()<<" "<getVolumeInit() ,9); + obj->initMovingPoints(mSimulationTime, mLevel[mMaxRefine].nodeSize); + } + } + } + + // max speed init + ntlVec3Gfx maxMovobjVelRw = getGeoMaxMovementVelocity( mSimulationTime, mpParam->getTimestep() ); + ntlVec3Gfx maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P( maxMovobjVelRw )) ); + mpParam->setSimulationMaxSpeed( norm(maxMovobjVel) + norm(mLevel[level].gravity) ); + LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity + debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Maximum Velocity from geo init="<< maxMovobjVel <<" from mov. obj.="<setDesiredTimestep( newdt ); + mpParam->calculateAllMissingValues( mSimulationTime, mSilent ); + maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P(getGeoMaxMovementVelocity( + mSimulationTime, mpParam->getTimestep() )) )); + debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"New maximum Velocity from geo init="<< maxMovobjVel,5); + } + recalculateObjectSpeeds(); + // */ + + // init obstacles for first time step (requires obj speeds) + initMovingObstacles(true); + + /* set interface cells */ + ntlVec3Gfx pos,iniPos; // position of current cell + LbmFloat rhomass = 0.0; + CellFlagType ntype = CFInvalid; + int savedNodes = 0; + int OId = -1; + gfxReal distance; + + // 2d display as rectangles + if(LBMDIM==2) { + dvec[2] = 0.0; + iniPos =(mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))+(dvec*0.5); + //if(mInit2dYZ) { SWAPYZ(mGravity); for(int lev=0; lev<=mMaxRefine; lev++){ SWAPYZ( mLevel[lev].gravity ); } } + } else { + iniPos =(mvGeoStart + ntlVec3Gfx( 0.0 ))+(dvec*0.5); + } + + + // first init boundary conditions + // invalid cells are set to empty afterwards + // TODO use floop macros!? + for(int k= getForZMin1(); k< getForZMax1(level); ++k) { + for(int j=1;jgetGeoInitType() ){ + case FGI_MBNDINFLOW: + if(! pObj->getIsAnimated() ) { + rhomass = 1.0; + ntype = CFFluid | CFMbndInflow; + } else { + ntype = CFInvalid; + } + break; + case FGI_MBNDOUTFLOW: + if(! pObj->getIsAnimated() ) { + rhomass = 0.0; + ntype = CFEmpty|CFMbndOutflow; + } else { + ntype = CFInvalid; + } + break; + case FGI_BNDNO: + rhomass = BND_FILL; + ntype = CFBnd|CFBndNoslip; + break; + case FGI_BNDPART: + rhomass = BND_FILL; + ntype = CFBnd|CFBndPartslip; break; + case FGI_BNDFREE: + rhomass = BND_FILL; + ntype = CFBnd|CFBndFreeslip; break; + default: // warn here? + rhomass = BND_FILL; + ntype = CFBnd|CFBndNoslip; break; + } + } + if(ntype != CFInvalid) { + // initDefaultCell + if((ntype & CFMbndInflow) || (ntype & CFMbndOutflow) ) { } + ntype |= (OId<<24); // NEWTEST2 + initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] ); + } + + // walk along x until hit for following inits + if(distance<=-1.0) { distance = 100.0; } // FIXME dangerous + if(distance>=0.0) { + gfxReal dcnt=dvec[0]; + while(( dcnt< distance-dvec[0] )&&(i+1=0.0) { + gfxReal dcnt=dvec[0]; + while((dcnt< distance )&&(i+10 + + } + } + } // zmax + + // reset invalid to empty again + for(int k= getForZMin1(); k< getForZMax1(level); ++k) { + for(int j=1;j0) { + debMsgStd("Surface Smoothing init", DM_MSG, "Performing "<<(mInitSurfaceSmoothing)<<" smoothing timestep ",10); +#if COMPRESSGRIDS==1 + //errFatal("NYI","COMPRESSGRIDS mInitSurfaceSmoothing",SIMWORLD_INITERROR); return; +#endif // COMPRESSGRIDS==0 + } + for(int s=0; s1) { haveStandingFluid=(iindex); } \ + j = mLevel[mMaxRefine].lSizey; i=mLevel[mMaxRefine].lSizex; k=getForZMaxBnd(); \ + continue; \ + } + int gravIndex[3] = {0,0,0}; + int gravDir[3] = {1,1,1}; + int maxGravComp = 1; // by default y + int gravComp1 = 0; // by default y + int gravComp2 = 2; // by default y + if( ABS(mLevel[mMaxRefine].gravity[0]) > ABS(mLevel[mMaxRefine].gravity[1]) ){ maxGravComp = 0; gravComp1=1; gravComp2=2; } + if( ABS(mLevel[mMaxRefine].gravity[2]) > ABS(mLevel[mMaxRefine].gravity[0]) ){ maxGravComp = 2; gravComp1=0; gravComp2=1; } + + int gravIMin[3] = { 0 , 0 , 0 }; + int gravIMax[3] = { + mLevel[mMaxRefine].lSizex + 0, + mLevel[mMaxRefine].lSizey + 0, + mLevel[mMaxRefine].lSizez + 0 }; + if(LBMDIM==2) gravIMax[2] = 1; + + //int gravDir = 1; + if( mLevel[mMaxRefine].gravity[maxGravComp] > 0.0 ) { + // swap directions + int i=maxGravComp; + int tmp = gravIMin[i]; + gravIMin[i] = gravIMax[i] - 1; + gravIMax[i] = tmp - 1; + gravDir[i] = -1; + } +#define PRINTGDIRS \ + errMsg("Standing fp","X start="<>2); // not much use...? + //preinitSteps = 0; + debMsgStd("Standing fluid preinit", DM_MSG, "Performing "< /* getenv(3) - also in linux */ + + + +/****************************************************************************** + * Interface Constructor + *****************************************************************************/ +LbmSolverInterface::LbmSolverInterface() : + mPanic( false ), + mSizex(10), mSizey(10), mSizez(10), + mAllfluid(false), mStepCnt( 0 ), + mFixMass( 0.0 ), + mOmega( 1.0 ), + mGravity(0.0), + mSurfaceTension( 0.0 ), + mBoundaryEast( (CellFlagType)(CFBnd) ),mBoundaryWest( (CellFlagType)(CFBnd) ),mBoundaryNorth( (CellFlagType)(CFBnd) ), + mBoundarySouth( (CellFlagType)(CFBnd) ),mBoundaryTop( (CellFlagType)(CFBnd) ),mBoundaryBottom( (CellFlagType)(CFBnd) ), + mInitDone( false ), + mInitDensityGradient( false ), + mpSifAttrs( NULL ), mpSifSwsAttrs(NULL), mpParam( NULL ), mpParticles(NULL), + mNumParticlesLost(0), + mNumInvalidDfs(0), mNumFilledCells(0), mNumEmptiedCells(0), mNumUsedCells(0), mMLSUPS(0), + mDebugVelScale( 0.01 ), mNodeInfoString("+"), + mvGeoStart(-1.0), mvGeoEnd(1.0), mpSimTrafo(NULL), + mAccurateGeoinit(0), + mName("lbm_default") , + mpIso( NULL ), mIsoValue(0.499), + mSilent(false) , + mLbmInitId(1) , + mpGiTree( NULL ), + mpGiObjects( NULL ), mGiObjInside(), mpGlob( NULL ), + mRefinementDesired(0), + mOutputSurfacePreview(0), mPreviewFactor(0.25), + mSmoothSurface(1.0), mSmoothNormals(1.0), + mIsoSubdivs(1), mPartGenProb(0.), + mDumpVelocities(false), + mMarkedCells(), mMarkedCellIndex(0), + mDomainBound("noslip"), mDomainPartSlipValue(0.1), + mFarFieldSize(0.), + mPartDropMassSub(0.1), // good default + mPartUsePhysModel(false), + mTForceStrength(0.0), + mCppfStage(0), + mDumpRawText(false), + mDumpRawBinary(false), + mDumpRawBinaryZip(true) +{ +#if ELBEEM_PLUGIN==1 + if(gDebugLevel<=1) setSilent(true); +#endif + mpSimTrafo = new ntlMat4Gfx(0.0); + mpSimTrafo->initId(); + + if(getenv("ELBEEM_RAWDEBUGDUMP")) { + debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2); + mDumpRawText = true; + } + + if(getenv("ELBEEM_BINDEBUGDUMP")) { + debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2); + mDumpRawBinary = true; + } +} + +LbmSolverInterface::~LbmSolverInterface() +{ + if(mpSimTrafo) delete mpSimTrafo; +} + + +/****************************************************************************** + * initialize correct grid sizes given a geometric bounding box + * and desired grid resolutions, all params except maxrefine + * will be modified + *****************************************************************************/ +void initGridSizes(int &sizex, int &sizey, int &sizez, + ntlVec3Gfx &geoStart, ntlVec3Gfx &geoEnd, + int mMaxRefine, bool parallel) +{ + // fix size inits to force cubic cells and mult4 level dimensions + const int debugGridsizeInit = 1; + if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Called - size X:"<maxGridSize) maxGridSize = sizey; + if(sizez>maxGridSize) maxGridSize = sizez; + LbmFloat maxGeoSize = (geoEnd[0]-geoStart[0]); // get max size + if((geoEnd[1]-geoStart[1])>maxGeoSize) maxGeoSize = (geoEnd[1]-geoStart[1]); + if((geoEnd[2]-geoStart[2])>maxGeoSize) maxGeoSize = (geoEnd[2]-geoStart[2]); + // FIXME better divide max geo size by corresponding resolution rather than max? no prob for rx==ry==rz though + LbmFloat cellSize = (maxGeoSize / (LbmFloat)maxGridSize); + if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Start:"<=0; i--) { + currResx /= 2.0; + currResy /= 2.0; + currResz /= 2.0; + rcellSize = ((currResz*currResy*currResx) *ddTotalNum); + memCnt += (double)(sizeof(CellFlagType) * (rcellSize/ddTotalNum +4.0) *2.0); + memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0); + if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"refine "<0.) { + memCnt += (double)( (3*sizeof(int)+sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) ); + } else { + // ignore 3 int slices... + memCnt += (double)( ( sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) ); + } + if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"iso, mc:"<sfac){ memd /= sfac; sizeStr="KB"; } + if(memd>sfac){ memd /= sfac; sizeStr="MB"; } + if(memd>sfac){ memd /= sfac; sizeStr="GB"; } + if(memd>sfac){ memd /= sfac; sizeStr="TB"; } + + // return values + std::ostringstream ret; + if(memCnt< 1024.0*1024.0) { + // show full MBs + ret << (ceil(memd)); + } else { + // two digits for anything larger than MB + ret << (ceil(memd*100.0)/100.0); + } + ret << " "<< sizeStr; + *reqret = memCnt; + *reqstr = ret.str(); + //debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Required Grid memory: "<< memd <<" "<< sizeStr<<" ",4); +} + +void LbmSolverInterface::initDomainTrafo(float *mat) { + mpSimTrafo->initArrayCheck(mat); +} + +/*******************************************************************************/ +/*! parse a boundary flag string */ +CellFlagType LbmSolverInterface::readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed) { + string val = mpSifAttrs->readString(name, "", source, target, needed); + if(!strcmp(val.c_str(),"")) { + // no value given... + return CFEmpty; + } + if(!strcmp(val.c_str(),"bnd_no")) { + return (CellFlagType)( CFBnd ); + } + if(!strcmp(val.c_str(),"bnd_free")) { + return (CellFlagType)( CFBnd ); + } + if(!strcmp(val.c_str(),"fluid")) { + /* might be used for some in/out flow cases */ + return (CellFlagType)( CFFluid ); + } + errMsg("LbmSolverInterface::readBoundaryFlagInt","Invalid value '"<readMat4Gfx("domain_trafo" , (*mpSimTrafo), "ntlBlenderDumper","mpSimTrafo", false, mpSimTrafo ); + + LbmVec sizeVec(mSizex,mSizey,mSizez); + sizeVec = vec2L( mpSifAttrs->readVec3d("size", vec2P(sizeVec), "LbmSolverInterface", "sizeVec", false) ); + mSizex = (int)sizeVec[0]; + mSizey = (int)sizeVec[1]; + mSizez = (int)sizeVec[2]; + // param needs size in any case + // test solvers might not have mpPara, though + if(mpParam) mpParam->setSize(mSizex, mSizey, mSizez ); + + mInitDensityGradient = mpSifAttrs->readBool("initdensitygradient", mInitDensityGradient,"LbmSolverInterface", "mInitDensityGradient", false); + mIsoValue = mpSifAttrs->readFloat("isovalue", mIsoValue, "LbmOptSolver","mIsoValue", false ); + + mDebugVelScale = mpSifAttrs->readFloat("debugvelscale", mDebugVelScale,"LbmSolverInterface", "mDebugVelScale", false); + mNodeInfoString = mpSifAttrs->readString("nodeinfo", mNodeInfoString, "SimulationLbm","mNodeInfoString", false ); + + mDumpVelocities = mpSifAttrs->readBool("dump_velocities", mDumpVelocities, "SimulationLbm","mDumpVelocities", false ); + if(getenv("ELBEEM_DUMPVELOCITIES")) { + int get = atoi(getenv("ELBEEM_DUMPVELOCITIES")); + if((get==0)||(get==1)) { + mDumpVelocities = get; + debMsgStd("LbmSolverInterface::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_DUMPVELOCITIES to set mDumpVelocities to "<readFloat("farfieldsize", mFarFieldSize,"LbmSolverInterface", "mFarFieldSize", false); + // old compat + float sizeScale = mpSifAttrs->readFloat("test_scale", 0.,"LbmTestdata", "mSizeScale", false); + if((mFarFieldSize<=0.)&&(sizeScale>0.)) { mFarFieldSize=sizeScale; errMsg("LbmTestdata","Warning - using mSizeScale..."); } + + mPartDropMassSub = mpSifAttrs->readFloat("part_dropmass", mPartDropMassSub,"LbmSolverInterface", "mPartDropMassSub", false); + + mCppfStage = mpSifAttrs->readInt("cppfstage", mCppfStage,"LbmSolverInterface", "mCppfStage", false); + mPartGenProb = mpSifAttrs->readFloat("partgenprob", mPartGenProb,"LbmFsgrSolver", "mPartGenProb", false); + mPartUsePhysModel = mpSifAttrs->readBool("partusephysmodel", mPartUsePhysModel,"LbmFsgrSolver", "mPartUsePhysModel", false); + mIsoSubdivs = mpSifAttrs->readInt("isosubdivs", mIsoSubdivs,"LbmFsgrSolver", "mIsoSubdivs", false); +} + + +/*******************************************************************************/ +/*! geometry initialization */ +/*******************************************************************************/ + +/*****************************************************************************/ +/*! init tree for certain geometry init */ +void LbmSolverInterface::initGeoTree() { + if(mpGlob == NULL) { errFatal("LbmSolverInterface::initGeoTree","Requires globals!",SIMWORLD_INITERROR); return; } + ntlScene *scene = mpGlob->getSimScene(); + mpGiObjects = scene->getObjects(); + mGiObjInside.resize( mpGiObjects->size() ); + mGiObjDistance.resize( mpGiObjects->size() ); + mGiObjSecondDist.resize( mpGiObjects->size() ); + for(size_t i=0; isize(); i++) { + if((*mpGiObjects)[i]->getGeoInitIntersect()) mAccurateGeoinit=true; + //debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"id:"<getName() <<" gid:"<<(*mpGiObjects)[i]->getGeoInitId(), 9 ); + } + debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Accurate geo init: "<size() ,10); + + if(mpGiTree != NULL) delete mpGiTree; + char treeFlag = (1<<(this->mLbmInitId+4)); + mpGiTree = new ntlTree( +# if FSGR_STRICT_DEBUG!=1 + 15, 8, // TREEwarning - fixed values for depth & maxtriangles here... +# else // FSGR_STRICT_DEBUG==1 + 10, 20, // reduced/slower debugging values +# endif // FSGR_STRICT_DEBUG==1 + scene, treeFlag ); +} + +/*****************************************************************************/ +/*! destroy tree etc. when geometry init done */ +void LbmSolverInterface::freeGeoTree() { + if(mpGiTree != NULL) { + delete mpGiTree; + mpGiTree = NULL; + } +} + + +int globGeoInitDebug = 0; +int globGICPIProblems = 0; +/*****************************************************************************/ +/*! check for a certain flag type at position org */ +bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance, int shootDir) { + // shift ve ctors to avoid rounding errors + org += ntlVec3Gfx(0.0001); + OId = -1; + + // select shooting direction + ntlVec3Gfx dir = ntlVec3Gfx(1., 0., 0.); + if(shootDir==1) dir = ntlVec3Gfx(0., 1., 0.); + else if(shootDir==2) dir = ntlVec3Gfx(0., 0., 1.); + else if(shootDir==-2) dir = ntlVec3Gfx(0., 0., -1.); + else if(shootDir==-1) dir = ntlVec3Gfx(0., -1., 0.); + + ntlRay ray(org, dir, 0, 1.0, mpGlob); + bool done = false; + bool inside = false; + + vector giObjFirstHistSide; + giObjFirstHistSide.resize( mpGiObjects->size() ); + for(size_t i=0; iintersectX(ray,distance,normal, triIns, flags, true); + else mpGiTree->intersect(ray,distance,normal, triIns, flags, true); + if(triIns) { + ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance; + LbmFloat orientation = dot(normal, dir); + OId = triIns->getObjectId(); + if(orientation<=0.0) { + // outside hit + normal *= -1.0; + mGiObjInside[OId]++; + if(giObjFirstHistSide[OId]==0) giObjFirstHistSide[OId] = 1; + if(globGeoInitDebug) errMsg("IIO"," oid:"<0) { + bool mess = false; + if((mGiObjInside[i]%2)==1) { + if(giObjFirstHistSide[i] != -1) mess=true; + } else { + if(giObjFirstHistSide[i] != 1) mess=true; + } + if(mess) { + //errMsg("IIIproblem","At "<0.0)) { + if( (distance<0.0) || // first intersection -> good + ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one + ) { + distance = mGiObjDistance[i]; + OId = i; + inside = true; + } + } + } + if(!inside) { + distance = firstHit; + OId = firstOId; + } + if(globGeoInitDebug) errMsg("CHIII","i"<intersectX(ray,distance,normal, triIns, flags, true); + else mpGiTree->intersect(ray,distance,normal, triIns, flags, true); + if(triIns) { + // check outside intersect + LbmFloat orientation = dot(normal, dir); + if(orientation<=0.0) return false; + + OId = triIns->getObjectId(); + return true; + } + return false; + } +} +bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance, const gfxReal halfCellsize, bool &thinHit, bool recurse) { + // shift ve ctors to avoid rounding errors + org += ntlVec3Gfx(0.0001); //? + OId = -1; + ntlRay ray(org, dir, 0, 1.0, mpGlob); + //int insCnt = 0; + bool done = false; + bool inside = false; + for(size_t i=0; iintersect(ray,distance,normal, triIns, flags, true); + if(triIns) { + ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance; + LbmFloat orientation = dot(normal, dir); + OId = triIns->getObjectId(); + if(orientation<=0.0) { + // outside hit + normal *= -1.0; + //mGiObjDistance[OId] = -1.0; + //errMsg("IIO"," oid:"<0.0)) { + if( (distance<0.0) || // first intersection -> good + ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one + ) { + distance = mGiObjDistance[i]; + OId = i; + inside = true; + } + } + } + // now check for thin hits + if(!inside) { + distance = -1.0; + for(size_t i=0; i=2)&&(mGiObjDistance[i]>0.0)&&(mGiObjSecondDist[i]>0.0)&& + (mGiObjDistance[i]<1.0*halfCellsize)&&(mGiObjSecondDist[i]<2.0*halfCellsize) ) { + if( (distance<0.0) || // first intersection -> good + ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one + ) { + distance = mGiObjDistance[i]; + OId = i; + inside = true; + thinHit = true; + } + } + } + } + if(!inside) { + // check for hit in this cell, opposite to current dir (only recurse once) + if(recurse) { + gfxReal r_distance; + int r_OId; + bool ret = geoInitCheckPointInside(org, dir*-1.0, flags, r_OId, r_distance, halfCellsize, thinHit, false); + if((ret)&&(thinHit)) { + OId = r_OId; + distance = 0.0; + return true; + } + } + } + // really no hit... + if(!inside) { + distance = firstHit; + OId = firstOId; + /*if((mGiObjDistance[OId]>0.0)&&(mGiObjSecondDist[OId]>0.0)) { + const gfxReal thisdist = mGiObjSecondDist[OId]-mGiObjDistance[OId]; + // dont walk over this cell... + if(thisdistintersect(ray,distance,normal, triIns, flags, true); + if(triIns) { + // check outside intersect + LbmFloat orientation = dot(normal, dir); + if(orientation<=0.0) return false; + + OId = triIns->getObjectId(); + return true; + } + return false; + } +} + + +/*****************************************************************************/ +ntlVec3Gfx LbmSolverInterface::getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize) { + ntlVec3Gfx max(0.0); + if(mpGlob == NULL) return max; + // mpGiObjects has to be inited here... + + for(int i=0; i< (int)mpGiObjects->size(); i++) { + //errMsg("LbmSolverInterface::getGeoMaxMovementVelocity","i="<getName() ); // DEBUG + if( (*mpGiObjects)[i]->getGeoInitType() & (FGI_FLUID|FGI_MBNDINFLOW) ){ + //ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime); + ntlVec3Gfx orgvel = (*mpGiObjects)[i]->calculateMaxVel( simtime, simtime+stepsize ); + if( normNoSqrt(orgvel) > normNoSqrt(max) ) { max = orgvel; } + //errMsg("MVT","i"<getInitialVelocity(simtime)<<" o"<getInitialVelocity(simtime); + if( normNoSqrt(inivel) > normNoSqrt(max) ) { max = inivel; } + } + } + errMsg("LbmSolverInterface::getGeoMaxMovementVelocity", "max="<< max ); // DEBUG + return max; +} + + + + +/*******************************************************************************/ +/*! cell iteration functions */ +/*******************************************************************************/ + + + + +/*****************************************************************************/ +//! add cell to mMarkedCells list +void +LbmSolverInterface::addCellToMarkedList( CellIdentifierInterface *cid ) { + for(size_t i=0; iequal(cid) ) return; + //mMarkedCells[i]->setEnd(false); + } + mMarkedCells.push_back( cid ); + //cid->setEnd(true); +} + +/*****************************************************************************/ +//! marked cell iteration methods +CellIdentifierInterface* +LbmSolverInterface::markedGetFirstCell( ) { + if(mMarkedCells.size() > 0){ return mMarkedCells[0]; } + return NULL; +} + +CellIdentifierInterface* +LbmSolverInterface::markedAdvanceCell() { + mMarkedCellIndex++; + if(mMarkedCellIndex>=(int)mMarkedCells.size()) return NULL; + return mMarkedCells[mMarkedCellIndex]; +} + +void LbmSolverInterface::markedClearList() { + // FIXME free cids? + mMarkedCells.clear(); +} + +/*******************************************************************************/ +/*! string helper functions */ +/*******************************************************************************/ + + + +// 32k +string convertSingleFlag2String(CellFlagType cflag) { + CellFlagType flag = cflag; + if(flag == CFUnused ) return string("cCFUnused"); + if(flag == CFEmpty ) return string("cCFEmpty"); + if(flag == CFBnd ) return string("cCFBnd"); + if(flag == CFBndNoslip ) return string("cCFBndNoSlip"); + if(flag == CFBndFreeslip ) return string("cCFBndFreeSlip"); + if(flag == CFBndPartslip ) return string("cCFBndPartSlip"); + if(flag == CFNoInterpolSrc ) return string("cCFNoInterpolSrc"); + if(flag == CFFluid ) return string("cCFFluid"); + if(flag == CFInter ) return string("cCFInter"); + if(flag == CFNoNbFluid ) return string("cCFNoNbFluid"); + if(flag == CFNoNbEmpty ) return string("cCFNoNbEmpty"); + if(flag == CFNoDelete ) return string("cCFNoDelete"); + if(flag == CFNoBndFluid ) return string("cCFNoBndFluid"); + if(flag == CFGrNorm ) return string("cCFGrNorm"); + if(flag == CFGrFromFine ) return string("cCFGrFromFine"); + if(flag == CFGrFromCoarse ) return string("cCFGrFromCoarse"); + if(flag == CFGrCoarseInited ) return string("cCFGrCoarseInited"); + if(flag == CFMbndInflow ) return string("cCFMbndInflow"); + if(flag == CFMbndOutflow ) return string("cCFMbndOutflow"); + if(flag == CFInvalid ) return string("cfINVALID"); + + std::ostringstream mult; + int val = 0; + if(flag != 0) { + while(! (flag&1) ) { + flag = flag>>1; + val++; + } + } else { + val = -1; + } + if(val>=24) { + mult << "cfOID_" << (flag>>24) <<"_TYPE"; + } else { + mult << "cfUNKNOWN_" << val <<"_TYPE"; + } + return mult.str(); +} + +//! helper function to convert flag to string (for debuggin) +string convertCellFlagType2String( CellFlagType cflag ) { + int flag = cflag; + + const int jmax = sizeof(CellFlagType)*8; + bool somefound = false; + std::ostringstream mult; + mult << "["; + for(int j=0; j +#include "../gui/guifuncs.h" +#endif + +#include +#include "utilities.h" +#include "ntl_bsptree.h" +#include "ntl_geometryobject.h" +#include "parametrizer.h" +#include "attributes.h" +#include "isosurface.h" +class ParticleTracer; +class ParticleObject; + +// use which fp-precision for LBM? 1=float, 2=double +#ifdef PRECISION_LBM_SINGLE +#define LBM_PRECISION 1 +#else +#ifdef PRECISION_LBM_DOUBLE +#define LBM_PRECISION 2 +#else +// default to floats +#define LBM_PRECISION 1 +#endif +#endif + +#if LBM_PRECISION==1 +/* low precision for LBM solver */ +typedef float LbmFloat; +typedef ntlVec3f LbmVec; +#define LBM_EPSILON (1e-5) +#else +/* standard precision for LBM solver */ +typedef double LbmFloat; +typedef ntlVec3d LbmVec; +#define LBM_EPSILON (1e-10) +#endif + +// long integer, needed e.g. for memory calculations +#ifndef USE_MSVC6FIXES +#define LONGINT long long int +#else +#define LONGINT _int64 +#endif + + +// default to 3dim +#ifndef LBMDIM +#define LBMDIM 3 +#endif // LBMDIM + +#if LBMDIM==2 +#define LBM_DFNUM 9 +#else +#define LBM_DFNUM 19 +#endif + +// conversions (lbm and parametrizer) +template inline LbmVec vec2L(T v) { return LbmVec(v[0],v[1],v[2]); } +template inline ParamVec vec2P(T v) { return ParamVec(v[0],v[1],v[2]); } + +template class ntlMatrix4x4; + + +// bubble id type +typedef int BubbleId; + +// basic cell type distinctions +#define CFUnused (1<< 0) +#define CFEmpty (1<< 1) +#define CFBnd (1<< 2) +#define CFMbndInflow (1<< 3) +#define CFMbndOutflow (1<< 4) +#define CFFluid (1<< 5) +#define CFInter (1<< 6) +// additional for fluid (needed separately for adaptive grids) +#define CFNoBndFluid (1<< 7) +#define CFNoDelete (1<< 8) + +// additional bnd add flags +#define CFBndNoslip (1<< 9) +#define CFBndFreeslip (1<<10) +#define CFBndPartslip (1<<11) +#define CFBndMoving (1<<12) + +// additional for fluid/interface +// force symmetry for flag reinit +#define CFNoInterpolSrc (1<<13) +#define CFNoNbFluid (1<<14) +#define CFNoNbEmpty (1<<15) + +// cell treated normally on coarser grids +#define CFGrNorm (1<<16) +#define CFGrCoarseInited (1<<17) + +// (the following values shouldnt overlap to ensure +// proper coarsening) +// border cells to be interpolated from finer grid +#define CFGrFromFine (1<<18) +// 32k aux border marker +#define CFGrToFine (1<<19) +// also needed on finest level +#define CFGrFromCoarse (1<<20) +// additional refinement tags (coarse grids only?) +// */ + +// above 24 is used to encode in/outflow object type +#define CFPersistMask (0xFF000000 | CFMbndInflow | CFMbndOutflow) +#define CFNoPersistMask (~CFPersistMask) + + +// nk +#define CFInvalid (CellFlagType)(1<<31) + +// use 32bit flag types +//#ifdef __x86_64__ + //typedef int cfINT32; +//#else + //typedef long cfINT32; +//#endif // defined (_IA64) +//#define CellFlagType cfINT32 +#define CellFlagType int +#define CellFlagTypeSize 4 + + +// aux. field indices (same for 2d) +#define dFfrac 19 +#define dMass 20 +#define dFlux 21 +// max. no. of cell values for 3d +#define dTotalNum 22 + + +/*****************************************************************************/ +/*! a single lbm cell */ +/* the template is only needed for + * dimension dependend constants e.g. + * number of df's in model */ +class LbmCellContents { + public: + LbmFloat df[ 27 ]; // be on the safe side here... + LbmFloat rho; + LbmVec vel; + LbmFloat mass; + CellFlagType flag; + BubbleId bubble; + LbmFloat ffrac; +}; + +/* struct for the coordinates of a cell in the grid */ +typedef struct { + int x,y,z; + int flag; // special handling? +} LbmPoint; + +/* struct for the coordinates of a cell in the grid */ +typedef struct { + char active; // bubble in use, oder may be overwritten? + LbmFloat volume; // volume of this bubble (0 vor atmosphere) + LbmFloat mass; // "mass" of bubble + int i,j,k; // index of a cell in the bubble +} LbmBubble; + + + + +//! choose which data to display +#define FLUIDDISPINVALID 0 +#define FLUIDDISPNothing 1 +#define FLUIDDISPCelltypes 2 +#define FLUIDDISPVelocities 3 +#define FLUIDDISPCellfills 4 +#define FLUIDDISPDensity 5 +#define FLUIDDISPGrid 6 +#define FLUIDDISPSurface 7 + + + +/*****************************************************************************/ +//! cell identifier interface +class CellIdentifierInterface { + public: + //! reset constructor + CellIdentifierInterface():mEnd(false) { }; + //! virtual destructor + virtual ~CellIdentifierInterface() {}; + + //! return node as string (with some basic info) + virtual string getAsString() = 0; + + //! compare cids + virtual bool equal(CellIdentifierInterface* other) = 0; + + //! set/get end flag for grid traversal (not needed for marked cells) + inline void setEnd(bool set){ mEnd = set; } + inline bool getEnd( ) { return mEnd; } + + //! has the grid been traversed? + bool mEnd; + +}; + + + +/*****************************************************************************/ +/*! class defining abstract function interface */ +/* has to provide iterating functionality */ +class LbmSolverInterface +{ + public: + //! Constructor + LbmSolverInterface(); + //! Destructor + virtual ~LbmSolverInterface(); + //! id string of solver + virtual string getIdString() = 0; + + // multi step solver init + /*! finish the init with config file values (allocate arrays...) */ + virtual bool initializeSolverMemory() =0; + /*! init solver arrays */ + virtual bool initializeSolverGrids() =0; + /*! prepare actual simulation start, setup viz etc */ + virtual bool initializeSolverPostinit() =0; + + /*! notify object that dump is in progress (e.g. for field dump) */ + virtual void notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) = 0; + + /*! parse a boundary flag string */ + CellFlagType readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed); + /*! parse standard attributes */ + void parseStdAttrList(); + /*! initilize variables fom attribute list (should at least call std parse) */ + virtual void parseAttrList() = 0; + + virtual void step() = 0; + virtual void prepareVisualization() { /* by default off */ }; + + /*! particle handling */ + virtual int initParticles() = 0; + virtual void advanceParticles() = 0; + /*! get surface object (NULL if no surface) */ + IsoSurface* getSurfaceGeoObj() { return mpIso; } + + /*! debug object display */ + virtual vector getDebugObjects() { vector empty(0); return empty; } + +#if LBM_USE_GUI==1 + /*! show simulation info */ + virtual void debugDisplay(int) = 0; +#endif + + /*! init tree for certain geometry init */ + void initGeoTree(); + /*! destroy tree etc. when geometry init done */ + void freeGeoTree(); + /*! check for a certain flag type at position org (needed for e.g. quadtree refinement) */ + bool geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance,int shootDir=0); + bool geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance, + const gfxReal halfCellsize, bool &thinHit, bool recurse); + /*! set render globals, for scene/tree access */ + void setRenderGlobals(ntlRenderGlobals *glob) { mpGlob = glob; }; + /*! get max. velocity of all objects to initialize as fluid regions, and of all moving objects */ + ntlVec3Gfx getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize); + + /* rt interface functions */ + unsigned int getIsoVertexCount() { return mpIso->getIsoVertexCount(); } + unsigned int getIsoIndexCount() { return mpIso->getIsoIndexCount(); } + char* getIsoVertexArray() { return mpIso->getIsoVertexArray(); } + unsigned int *getIsoIndexArray() { return mpIso->getIsoIndexArray(); } + void triangulateSurface() { mpIso->triangulate(); } + + /* access functions */ + + /*! return grid sizes */ + int getSizeX( void ) { return mSizex; } + int getSizeY( void ) { return mSizey; } + int getSizeZ( void ) { return mSizez; } + /*! return grid sizes */ + void setSizeX( int ns ) { mSizex = ns; } + void setSizeY( int ns ) { mSizey = ns; } + void setSizeZ( int ns ) { mSizez = ns; } + /*! access fluid only simulation flag */ + void setAllfluid(bool set) { mAllfluid=set; } + bool getAllfluid() { return mAllfluid; } + + /*! set attr list pointer */ + void setAttrList(AttributeList *set) { mpSifAttrs = set; } + /*! Returns the attribute list pointer */ + inline AttributeList *getAttributeList() { return mpSifAttrs; } + /*! set sws attr list pointer */ + void setSwsAttrList(AttributeList *set) { mpSifSwsAttrs = set; } + inline AttributeList *getSwsAttributeList() { return mpSifSwsAttrs; } + + /*! set parametrizer pointer */ + inline void setParametrizer(Parametrizer *set) { mpParam = set; } + /*! get parametrizer pointer */ + inline Parametrizer *getParametrizer() { return mpParam; } + /*! get/set particle pointer */ + inline void setParticleTracer(ParticleTracer *set) { mpParticles = set; } + inline ParticleTracer *getParticleTracer() { return mpParticles; } + + /*! set density gradient init from e.g. init test cases */ + inline void setInitDensityGradient(bool set) { mInitDensityGradient = set; } + + /*! access geometry start vector */ + inline void setGeoStart(ntlVec3Gfx set) { mvGeoStart = set; } + inline ntlVec3Gfx getGeoStart() const { return mvGeoStart; } + + /*! access geometry end vector */ + inline void setGeoEnd(ntlVec3Gfx set) { mvGeoEnd = set; } + inline ntlVec3Gfx getGeoEnd() const { return mvGeoEnd; } + + /*! access geo init vars */ + inline void setLbmInitId(int set) { mLbmInitId = set; } + inline int getLbmInitId() const { return mLbmInitId; } + + /*! init domain transformation matrix from float array */ + void initDomainTrafo(float *mat); + /*! get domain transformation matrix to have object centered fluid vertices */ + inline ntlMatrix4x4 *getDomainTrafo() { return mpSimTrafo; } + + /*! access name string */ + inline void setName(string set) { mName = set; } + inline string getName() const { return mName; } + + /*! access string for node info debugging output */ + inline string getNodeInfoString() const { return mNodeInfoString; } + + /*! get panic flag */ + inline bool getPanic() { return mPanic; } + + //! set silent mode? + inline void setSilent(bool set){ mSilent = set; } + + //! set amount of surface/normal smoothing + inline void setSmoothing(float setss,float setns){ mSmoothSurface=setss; mSmoothNormals=setns; } + //! set amount of iso subdivisions + inline void setIsoSubdivs(int s){ mIsoSubdivs=s; } + //! set desired refinement + inline void setPreviewSize(int set){ mOutputSurfacePreview = set; } + //! set desired refinement + inline void setRefinementDesired(int set){ mRefinementDesired = set; } + + //! set/get dump velocities flag + inline void setDumpVelocities(bool set) { mDumpVelocities = set; } + inline bool getDumpVelocities() const { return mDumpVelocities; } + + //! set/get particle generation prob. + inline void setGenerateParticles(LbmFloat set) { mPartGenProb = set; } + inline LbmFloat getGenerateParticles() const { return mPartGenProb; } + + //! set/get dump velocities flag + inline void setDomainBound(string set) { mDomainBound = set; } + inline string getDomainBound() const { return mDomainBound; } + //! set/get dump velocities flag + inline void setDomainPartSlip(LbmFloat set) { mDomainPartSlipValue = set; } + inline LbmFloat getDomainPartSlip() const { return mDomainPartSlipValue; } + //! set/get far field size + inline void setFarFieldSize(LbmFloat set) { mFarFieldSize = set; } + inline LbmFloat getFarFieldSize() const { return mFarFieldSize; } + //! set/get cp stage + inline void setCpStage(int set) { mCppfStage = set; } + inline int getCpStage() const { return mCppfStage; } + //! set/get dump modes + inline void setDumpRawText(bool set) { mDumpRawText = set; } + inline bool getDumpRawText() const { return mDumpRawText; } + inline void setDumpRawBinary(bool set) { mDumpRawBinary = set; } + inline bool getDumpRawBinary() const { return mDumpRawBinary; } + inline void setDumpRawBinaryZip(bool set) { mDumpRawBinaryZip = set; } + inline bool getDumpRawBinaryZip() const { return mDumpRawBinaryZip; } + //! set/get debug vel scale + inline void setDebugVelScale(LbmFloat set) { mDebugVelScale = set; } + inline LbmFloat getDebugVelScale() const { return mDebugVelScale; } + + // cell iterator interface + + // cell id type + typedef CellIdentifierInterface* CellIdentifier; + + //! cell iteration methods + virtual CellIdentifierInterface* getFirstCell( ) = 0; + virtual void advanceCell( CellIdentifierInterface* ) = 0; + virtual bool noEndCell( CellIdentifierInterface* ) = 0; + //! clean up iteration, this should be called, when the iteration is not completely finished + virtual void deleteCellIterator( CellIdentifierInterface** ) = 0; + + //! find cell at a given position (returns NULL if not in domain) + virtual CellIdentifierInterface* getCellAt( ntlVec3Gfx pos ) = 0; + + //! return node information + virtual int getCellSet ( CellIdentifierInterface* ) = 0; + virtual ntlVec3Gfx getCellOrigin ( CellIdentifierInterface* ) = 0; + virtual ntlVec3Gfx getCellSize ( CellIdentifierInterface* ) = 0; + virtual int getCellLevel ( CellIdentifierInterface* ) = 0; + virtual LbmFloat getCellDensity ( CellIdentifierInterface*,int ) = 0; + virtual LbmVec getCellVelocity ( CellIdentifierInterface*,int ) = 0; + /*! get equilibrium distribution functions */ + virtual LbmFloat getEquilDf ( int ) = 0; + /*! redundant cell functions */ + virtual LbmFloat getCellDf ( CellIdentifierInterface* ,int set, int dir) = 0; + virtual LbmFloat getCellMass ( CellIdentifierInterface* ,int set) = 0; + virtual LbmFloat getCellFill ( CellIdentifierInterface* ,int set) = 0; + virtual CellFlagType getCellFlag ( CellIdentifierInterface* ,int set) = 0; + + /*! get velocity directly from position */ + virtual ntlVec3Gfx getVelocityAt(float x, float y, float z) = 0; + + // gui/output debugging functions +#if LBM_USE_GUI==1 + virtual void debugDisplayNode(int dispset, CellIdentifier cell ) = 0; + virtual void lbmDebugDisplay(int dispset) = 0; + virtual void lbmMarkedCellDisplay() = 0; +#endif // LBM_USE_GUI==1 + virtual void debugPrintNodeInfo(CellIdentifier cell, int forceSet=-1) = 0; + + // debugging cell marker functions + + //! add cell to mMarkedCells list + void addCellToMarkedList( CellIdentifierInterface *cid ); + //! marked cell iteration methods + CellIdentifierInterface* markedGetFirstCell( ); + CellIdentifierInterface* markedAdvanceCell(); + void markedClearList(); + + + protected: + + /*! abort simulation on error... */ + bool mPanic; + + + /*! Size of the array in x,y,z direction */ + int mSizex, mSizey, mSizez; + /*! only fluid in sim? */ + bool mAllfluid; + + + /*! step counter */ + int mStepCnt; + + /*! mass change from one step to the next, for extreme cases fix globally */ + LbmFloat mFixMass; + + // deprecated param vars + /*! omega for lbm */ + LbmFloat mOmega; + /*! gravity strength in neg. z direction */ + LbmVec mGravity; + /*! Surface tension of the fluid */ + LbmFloat mSurfaceTension; + + + /* boundary inits */ + CellFlagType mBoundaryEast, mBoundaryWest, + mBoundaryNorth, mBoundarySouth, + mBoundaryTop, mBoundaryBottom; + + /*! initialization from config file done? */ + int mInitDone; + + /*! init density gradient? */ + bool mInitDensityGradient; + + /*! pointer to the attribute list, only pointer to obj attrs */ + AttributeList *mpSifAttrs; + AttributeList *mpSifSwsAttrs; + + /*! get parameters from this parametrize in finishInit */ + Parametrizer *mpParam; + //! store particle tracer + ParticleTracer *mpParticles; + + /*! number of particles lost so far */ + int mNumParticlesLost; + /*! number of particles lost so far */ + int mNumInvalidDfs; + /*! no of filled/emptied cells per time step */ + int mNumFilledCells, mNumEmptiedCells; + /*! counter number of used cells for performance */ + int mNumUsedCells; + /*! MLSUPS counter */ + LbmFloat mMLSUPS; + /*! debug - velocity output scaling factor */ + LbmFloat mDebugVelScale; + /*! string for node info debugging output */ + string mNodeInfoString; + + // geo init vars + // TODO deprecate SimulationObject vars + + /*! for display - start and end vectors for geometry */ + ntlVec3Gfx mvGeoStart, mvGeoEnd; + //! domain vertex trafos + ntlMatrix4x4 *mpSimTrafo; + + /*! perform accurate geometry init? */ + bool mAccurateGeoinit; + + /*! name of this lbm object (for debug output) */ + string mName; + + //! Mcubes object for surface reconstruction + IsoSurface *mpIso; + /*! isolevel value for marching cubes surface reconstruction */ + LbmFloat mIsoValue; + + //! debug output? + bool mSilent; + + /*! geometry init id, passed from ntl_geomclass */ + int mLbmInitId; + /*! tree object for geomerty initialization */ + ntlTree *mpGiTree; + /*! object vector for geo init */ + vector *mpGiObjects; + /*! inside which objects? */ + vector mGiObjInside; + /*! inside which objects? */ + vector mGiObjDistance; + vector mGiObjSecondDist; + /*! remember globals */ + ntlRenderGlobals *mpGlob; + + //! use refinement/coarsening? + int mRefinementDesired; + + //! output surface preview? if >0 yes, and use as reduzed size + int mOutputSurfacePreview; + LbmFloat mPreviewFactor; + + /*! enable surface and normals smoothing? */ + float mSmoothSurface; + float mSmoothNormals; + /*! isosurface subdivisions */ + int mIsoSubdivs; + + //! particle generation probability + LbmFloat mPartGenProb; + + //! dump velocities? + bool mDumpVelocities; + + // list for marked cells + vector mMarkedCells; + int mMarkedCellIndex; + + //! domain boundary free/no slip type + string mDomainBound; + //! part slip value for domain + LbmFloat mDomainPartSlipValue; + + // size of far field area + LbmFloat mFarFieldSize; + // amount of drop mass to subtract + LbmFloat mPartDropMassSub; + // use physical drop model for particles? + bool mPartUsePhysModel; + + //! test vars + // strength of applied force + LbmFloat mTForceStrength; + int mCppfStage; + + //! dumping modes + bool mDumpRawText; + bool mDumpRawBinary; + bool mDumpRawBinaryZip; +}; + + +// helper function to create consistent grid resolutions +void initGridSizes(int &mSizex, int &mSizey, int &mSizez, + ntlVec3Gfx &mvGeoStart, ntlVec3Gfx &mvGeoEnd, + int mMaxRefine, bool parallel); +void calculateMemreqEstimate(int resx,int resy,int resz, int refine, + float farfieldsize, double *reqret, string *reqstr); + +//! helper function to convert flag to string (for debuggin) +string convertCellFlagType2String( CellFlagType flag ); +string convertSingleFlag2String(CellFlagType cflag); + +#endif // LBMINTERFACE_H diff --git a/intern/elbeem/intern/solver_main.cpp b/intern/elbeem/intern/solver_main.cpp new file mode 100644 index 00000000000..270e8867b3c --- /dev/null +++ b/intern/elbeem/intern/solver_main.cpp @@ -0,0 +1,1698 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Standard LBM Factory implementation + * + *****************************************************************************/ + +#include /* rand(3) - also in linux */ +#include "solver_class.h" +#include "solver_relax.h" +#include "particletracer.h" +#include "loop_tools.h" + +/*****************************************************************************/ +/*! perform a single LBM step */ +/*****************************************************************************/ + +double globdfcnt; +double globdfavg[19]; +double globdfmax[19]; +double globdfmin[19]; +extern int glob_mpindex,glob_mpnum; +extern bool globOutstrForce; + +// simulation object interface +void LbmFsgrSolver::step() { + stepMain(); +} + +// lbm main step +void messageOutputForce(string from); +void LbmFsgrSolver::stepMain() { + myTime_t timestart = getTime(); + + initLevelOmegas(); + markedClearList(); // DMC clearMarkedCellsList + + // safety check, counter reset + mNumUsedCells = 0; + mNumInterdCells = 0; + mNumInvIfCells = 0; + + //debugOutNnl("LbmFsgrSolver::step : "<mMaxNoCells) mMaxNoCells = mNumUsedCells; + if(mNumUsedCells0)&&(mInitialMass>0.0)) { + LbmFloat mscale = mInitialMass/mCurrentMass; + + mscale = 1.0; + const LbmFloat dchh = 0.001; + if(mCurrentMassmInitialMass) mscale = 1.0-dchh; + + // use mass rescaling? + // with float precision this seems to be nonsense... + const bool MREnable = false; + + const int MSInter = 2; + static int mscount = 0; + if( (MREnable) && ((mLevel[0].lsteps%MSInter)== (MSInter-1)) && ( ABS( (mInitialMass/mCurrentMass)-1.0 ) > 0.01) && ( dsbits & (1<<(mMaxRefine-0)) ) ){ + // example: FORCE RESCALE MASS! ini:1843.5, cur:1817.6, f=1.01425 step:22153 levstep:5539 msc:37 + // mass rescale MASS RESCALE check + errMsg("MDTDD","\n\n"); + errMsg("MDTDD","FORCE RESCALE MASS! " + <<"ini:"<=0 ; lev--) { + //for(int workSet = 0; workSet<=1; workSet++) { + int wss = 0; + int wse = 1; +#if COMPRESSGRIDS==1 + if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr; +#endif // COMPRESSGRIDS==1 + for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT + + FSGR_FORIJK1(lev) { + if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm)) + ) { + + FORDF0 { QCELL(lev, i,j,k,workSet, l) *= mscale; } + QCELL(lev, i,j,k,workSet, dMass) *= mscale; + QCELL(lev, i,j,k,workSet, dFfrac) *= mscale; + + } else { + continue; + } + } + } + mLevel[lev].lmass *= mscale; + } + } + + mCurrentMass *= mscale; + }// if mass scale test */ + else { + // use current mass after full step for initial setting + if((mMaxRefine>0)&&(mInitialMass<=0.0) && (levsteps == (mMaxRefine+1))) { + mInitialMass = mCurrentMass; + debMsgStd("MDTDD",DM_NOTIFY,"Second Initial Mass Init: "<checkDumpTextPositions(mSimulationTime); + mpParticles->checkTrails(mSimulationTime); + } + + // one of the last things to do - adapt timestep + // was in fineAdvance before... + if(mTimeAdap) { + adaptTimestep(); + } // time adaptivity + + +#ifndef WIN32 + // good indicator for instabilities + if( (!finite(mMxvx)) || (!finite(mMxvy)) || (!finite(mMxvz)) ) { CAUSE_PANIC; } + if( (!finite(mCurrentMass)) || (!finite(mCurrentVolume)) ) { CAUSE_PANIC; } +#endif // WIN32 + + // output total step time + myTime_t timeend2 = getTime(); + double mdelta = (lastMass-mCurrentMass); + if(ABS(mdelta)<1e-12) mdelta=0.; + double effMLSUPS = ((double)mNumUsedCells / ((timeend2-timestart)/(double)1000.0) ) / (1000000.0); + if(mInitDone) { + if(effMLSUPS>10000){ effMLSUPS = -1; } + else { mAvgMLSUPS += effMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups + } + + debMsgStd("LbmFsgrSolver::stepMain", DM_MSG, "mmpid:"<mPanic){ FSGR_FORIJK_BOUNDS(mMaxRefine) { \ + if(RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr)&(CFFluid|CFInter)) { \ + for(int l=0;lsetFluidVolumeHeight(mFVHeight); + } + + // advance time before timestep change + mSimulationTime += mpParam->getTimestep(); + // time adaptivity + mpParam->setSimulationMaxSpeed( sqrt(mMaxVlen / 1.5) ); + //if(mStartSymm) { checkSymmetry("step2"); } // DEBUG + if(!mSilent){ debMsgStd("fineAdvance",DM_NOTIFY," stepped from "<cDfNum; l++) { + LbmFloat df = QCELL(lev, i,j,k,workSet, l); + compRho += df; + compUx += (this->dfDvecX[l]*df); + compUy += (this->dfDvecY[l]*df); + compUz += (this->dfDvecZ[l]*df); + } + LbmVec u(compUx,compUy,compUz); + LbmFloat nu = norm(u); + if(nu>maxUlen) { + maxU = u; + maxUlen = nu; + mi=i; mj=j; mk=k; + } + if(compRho>maxRho) { + maxRho=compRho; + ri=i; rj=j; rk=k; + } + } else { + continue; + } + } + + errMsg("MAXVELCHECK"," at "<mFarfMode>0)) { return; } +# endif // ELBEEM_PLUGIN!=1 + + // main loop region + const bool doReduce = true; + const int gridLoopBound=1; + GRID_REGION_INIT(); +#if PARALLEL==1 +#include "paraloopstart.h" + GRID_REGION_START(); +#else // PARALLEL==1 + GRID_REGION_START(); +#endif // PARALLEL==1 + + // local to main + CellFlagType nbflag[LBM_DFNUM]; + int oldFlag, newFlag, nbored; + LbmFloat m[LBM_DFNUM]; + LbmFloat rho, ux, uy, uz, tmp, usqr; + + // smago vars + LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega; + + // ifempty cell conversion flags + bool iffilled, ifemptied; + LbmFloat nbfracs[LBM_DFNUM]; // ffracs of neighbors + int recons[LBM_DFNUM]; // reconstruct this DF? + int numRecons; // how many are reconstructed? + + LbmFloat mass=0., change=0., lcsmqo=0.; + rho= ux= uy= uz= usqr= tmp= 0.; + lcsmqadd = lcsmomega = 0.; + FORDF0{ lcsmeq[l] = 0.; } + + // --- + // now stream etc. + // use //template functions for 2D/3D + + GRID_LOOP_START(); + // loop start + // stream from current set to other, then collide and store + //errMsg("l2"," at "<>24; + if(!isValid) { + // make new if cell + const LbmVec vel(mObjectSpeeds[OId]); + // TODO add OPT3D treatment + FORDF0 { RAC(tcel, l) = this->getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); } + RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho; + RAC(tcel, dFlux) = FLUX_INIT; + changeFlag(lev, i,j,k, TSET(lev), CFInter); + calcCurrentMass += iniRho; + calcCurrentVolume += 1.0; + calcNumUsedCells++; + mInitialMass += iniRho; + // dont treat cell until next step + continue; + } + } + else // these are exclusive + if(oldFlag & (CFMbndOutflow)) { + int isnotValid = oldFlag & (CFFluid); + if(isnotValid) { + // remove fluid cells, shouldnt be here anyway + LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; } + mInitialMass -= fluidRho; + const LbmFloat iniRho = 0.0; + RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho; + RAC(tcel, dFlux) = FLUX_INIT; + changeFlag(lev, i,j,k, TSET(lev), CFInter); + + // same as ifemptied for if below + LbmPoint oemptyp; oemptyp.flag = 0; + oemptyp.x = i; oemptyp.y = j; oemptyp.z = k; + LIST_EMPTY(oemptyp); + calcCellsEmptied++; + continue; + } + } + + if(oldFlag & (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)) { + *pFlagDst = oldFlag; + continue; + } + /*if( oldFlag & CFNoBndFluid ) { // TEST ME FASTER? + OPTIMIZED_STREAMCOLLIDE; PERFORM_USQRMAXCHECK; + RAC(tcel,dFfrac) = 1.0; + *pFlagDst = (CellFlagType)oldFlag; // newFlag; + calcCurrentMass += rho; calcCurrentVolume += 1.0; + calcNumUsedCells++; + continue; + }// TEST ME FASTER? */ + + // only neighbor flags! not own flag + nbored = 0; + +#if OPT3D==0 + FORDF1 { + nbflag[l] = RFLAG_NB(lev, i,j,k,SRCS(lev),l); + nbored |= nbflag[l]; + } +#else + nbflag[dSB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dSB]; + nbflag[dWB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWB]; + nbflag[ dB] = *(pFlagSrc + (-mLevel[lev].lOffsy)); nbored |= nbflag[dB]; + nbflag[dEB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dEB]; + nbflag[dNB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNB]; + + nbflag[dSW] = *(pFlagSrc + (-mLevel[lev].lOffsx+-1)); nbored |= nbflag[dSW]; + nbflag[ dS] = *(pFlagSrc + (-mLevel[lev].lOffsx)); nbored |= nbflag[dS]; + nbflag[dSE] = *(pFlagSrc + (-mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dSE]; + + nbflag[ dW] = *(pFlagSrc + (-1)); nbored |= nbflag[dW]; + nbflag[ dE] = *(pFlagSrc + ( 1)); nbored |= nbflag[dE]; + + nbflag[dNW] = *(pFlagSrc + ( mLevel[lev].lOffsx+-1)); nbored |= nbflag[dNW]; + nbflag[ dN] = *(pFlagSrc + ( mLevel[lev].lOffsx)); nbored |= nbflag[dN]; + nbflag[dNE] = *(pFlagSrc + ( mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dNE]; + + nbflag[dST] = *(pFlagSrc + ( mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dST]; + nbflag[dWT] = *(pFlagSrc + ( mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWT]; + nbflag[ dT] = *(pFlagSrc + ( mLevel[lev].lOffsy)); nbored |= nbflag[dT]; + nbflag[dET] = *(pFlagSrc + ( mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dET]; + nbflag[dNT] = *(pFlagSrc + ( mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNT]; + // */ +#endif + + // pointer to destination cell + calcNumUsedCells++; + + // FLUID cells + if( oldFlag & CFFluid ) { + // only standard fluid cells (with nothing except fluid as nbs + + if(oldFlag&CFMbndInflow) { + // force velocity for inflow, necessary to have constant direction of flow + // FIXME , test also set interface cells? + const int OId = oldFlag>>24; + //? DEFAULT_STREAM; + //const LbmFloat fluidRho = 1.0; + // for submerged inflows, streaming would have to be performed... + LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; } + const LbmVec vel(mObjectSpeeds[OId]); + ux=vel[0], uy=vel[1], uz=vel[2]; + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); + FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); } + rho = fluidRho; + //errMsg("INFLOW_DEBUG","std at "<dfInv[(l)] ] + + // update mass + // only do boundaries for fluid cells, and interface cells without + // any fluid neighbors (assume that interface cells _with_ fluid + // neighbors are affected enough by these) + // which Df's have to be reconstructed? + // for fluid cells - just the f_i difference from streaming to empty cells ---- + numRecons = 0; + bool onlyBndnb = ((!(oldFlag&CFNoBndFluid))&&(oldFlag&CFNoNbFluid)&&(nbored&CFBndNoslip)); + //onlyBndnb = false; // DEBUG test off + + FORDF1 { // dfl loop + recons[l] = 0; + nbfracs[l] = 0.0; + // finally, "normal" interface cells ---- + if( nbflag[l]&(CFFluid|CFBnd) ) { // NEWTEST! FIXME check!!!!!!!!!!!!!!!!!! + change = nbdf(l) - MYDF(l); + } + // interface cells - distuingish cells that shouldn't fill/empty + else if( nbflag[l] & CFInter ) { + + LbmFloat mynbfac,nbnbfac; + // NEW TEST t1 + // t2 -> off + if((oldFlag&CFNoBndFluid)&&(nbflag[l]&CFNoBndFluid)) { + mynbfac = QCELL_NB(lev, i,j,k,SRCS(lev),l, dFlux) / QCELL(lev, i,j,k,SRCS(lev), dFlux); + nbnbfac = 1.0/mynbfac; + onlyBndnb = false; + } else { + mynbfac = nbnbfac = 1.0; // switch calc flux off + goto changeDefault; // NEWSURFT + //change = 0.; goto changeDone; // NEWSURFT + } + //mynbfac = nbnbfac = 1.0; // switch calc flux off t3 + + // perform interface case handling + if ((oldFlag|nbflag[l])&(CFNoNbFluid|CFNoNbEmpty)) { + switch (oldFlag&(CFNoNbFluid|CFNoNbEmpty)) { + case 0: + // we are a normal cell so... + switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { + case CFNoNbFluid: + // just fill current cell = empty neighbor + change = nbnbfac*nbdf(l) ; goto changeDone; + case CFNoNbEmpty: + // just empty current cell = fill neighbor + change = - mynbfac*MYDF(l) ; goto changeDone; + } + break; + + case CFNoNbFluid: + // we dont have fluid nb's so... + switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { + case 0: + case CFNoNbEmpty: + // we have no fluid nb's -> just empty + change = - mynbfac*MYDF(l) ; goto changeDone; + } + break; + + case CFNoNbEmpty: + // we dont have empty nb's so... + switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { + case 0: + case CFNoNbFluid: + // we have no empty nb's -> just fill + change = nbnbfac*nbdf(l); goto changeDone; + } + break; + }} // inter-inter exchange + + changeDefault: ; + // just do normal mass exchange... + change = ( nbnbfac*nbdf(l) - mynbfac*MYDF(l) ) ; + changeDone: ; + nbfracs[l] = QCELL_NB(lev, i,j,k, SRCS(lev),l, dFfrac); + if(nbfracs[l]<0.) nbfracs[l] = 0.; // NEWSURFT + change *= (myfrac + nbfracs[l]) * 0.5; + } // the other cell is interface + + // last alternative - reconstruction in this direction + else { + // empty + bnd case + recons[l] = 1; + numRecons++; + change = 0.0; + } + + // modify mass at SRCS + mass += change; + } // l + // normal interface, no if empty/fluid + + // computenormal + LbmFloat surfaceNormal[3]; + computeFluidSurfaceNormal(ccel,pFlagSrc, surfaceNormal); + + if( (ABS(surfaceNormal[0])+ABS(surfaceNormal[1])+ABS(surfaceNormal[2])) > LBM_EPSILON) { + // normal ok and usable... + FORDF1 { + if( (this->dfDvecX[l]*surfaceNormal[0] + this->dfDvecY[l]*surfaceNormal[1] + this->dfDvecZ[l]*surfaceNormal[2]) // dot Dvec,norml + > LBM_EPSILON) { + recons[l] = 2; + numRecons++; + } + } + } + + // calculate macroscopic cell values + LbmFloat oldUx, oldUy, oldUz; + LbmFloat oldRho; // OLD rho = ccel->rho; +# define REFERENCE_PRESSURE 1.0 // always atmosphere... +# if OPT3D==0 + oldRho=RAC(ccel,0); + oldUx = oldUy = oldUz = 0.0; + for(int l=1; lcDfNum; l++) { + oldRho += RAC(ccel,l); + oldUx += (this->dfDvecX[l]*RAC(ccel,l)); + oldUy += (this->dfDvecY[l]*RAC(ccel,l)); + oldUz += (this->dfDvecZ[l]*RAC(ccel,l)); + } + // reconstruct dist funcs from empty cells + FORDF1 { + if(recons[ l ]) { + m[ this->dfInv[l] ] = + this->getCollideEq(l, REFERENCE_PRESSURE, oldUx,oldUy,oldUz) + + this->getCollideEq(this->dfInv[l], REFERENCE_PRESSURE, oldUx,oldUy,oldUz) + - MYDF( l ); + } + } + ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on +# else // OPT3D==0 + oldRho = + RAC(ccel,dC) + RAC(ccel,dN ) + + RAC(ccel,dS ) + RAC(ccel,dE ) + + RAC(ccel,dW ) + RAC(ccel,dT ) + + RAC(ccel,dB ) + RAC(ccel,dNE) + + RAC(ccel,dNW) + RAC(ccel,dSE) + + RAC(ccel,dSW) + RAC(ccel,dNT) + + RAC(ccel,dNB) + RAC(ccel,dST) + + RAC(ccel,dSB) + RAC(ccel,dET) + + RAC(ccel,dEB) + RAC(ccel,dWT) + + RAC(ccel,dWB); + + oldUx = + RAC(ccel,dE) - RAC(ccel,dW) + + RAC(ccel,dNE) - RAC(ccel,dNW) + + RAC(ccel,dSE) - RAC(ccel,dSW) + + RAC(ccel,dET) + RAC(ccel,dEB) + - RAC(ccel,dWT) - RAC(ccel,dWB); + + oldUy = + RAC(ccel,dN) - RAC(ccel,dS) + + RAC(ccel,dNE) + RAC(ccel,dNW) + - RAC(ccel,dSE) - RAC(ccel,dSW) + + RAC(ccel,dNT) + RAC(ccel,dNB) + - RAC(ccel,dST) - RAC(ccel,dSB); + + oldUz = + RAC(ccel,dT) - RAC(ccel,dB) + + RAC(ccel,dNT) - RAC(ccel,dNB) + + RAC(ccel,dST) - RAC(ccel,dSB) + + RAC(ccel,dET) - RAC(ccel,dEB) + + RAC(ccel,dWT) - RAC(ccel,dWB); + + // now reconstruction + ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr + rho = REFERENCE_PRESSURE; + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on + if(recons[dN ]) { m[dS ] = EQN + EQS - MYDF(dN ); } + if(recons[dS ]) { m[dN ] = EQS + EQN - MYDF(dS ); } + if(recons[dE ]) { m[dW ] = EQE + EQW - MYDF(dE ); } + if(recons[dW ]) { m[dE ] = EQW + EQE - MYDF(dW ); } + if(recons[dT ]) { m[dB ] = EQT + EQB - MYDF(dT ); } + if(recons[dB ]) { m[dT ] = EQB + EQT - MYDF(dB ); } + if(recons[dNE]) { m[dSW] = EQNE + EQSW - MYDF(dNE); } + if(recons[dNW]) { m[dSE] = EQNW + EQSE - MYDF(dNW); } + if(recons[dSE]) { m[dNW] = EQSE + EQNW - MYDF(dSE); } + if(recons[dSW]) { m[dNE] = EQSW + EQNE - MYDF(dSW); } + if(recons[dNT]) { m[dSB] = EQNT + EQSB - MYDF(dNT); } + if(recons[dNB]) { m[dST] = EQNB + EQST - MYDF(dNB); } + if(recons[dST]) { m[dNB] = EQST + EQNB - MYDF(dST); } + if(recons[dSB]) { m[dNT] = EQSB + EQNT - MYDF(dSB); } + if(recons[dET]) { m[dWB] = EQET + EQWB - MYDF(dET); } + if(recons[dEB]) { m[dWT] = EQEB + EQWT - MYDF(dEB); } + if(recons[dWT]) { m[dEB] = EQWT + EQEB - MYDF(dWT); } + if(recons[dWB]) { m[dET] = EQWB + EQET - MYDF(dWB); } +# endif + + + // inflow bc handling + if(oldFlag & (CFMbndInflow)) { + // fill if cells in inflow region + if(myfrac<0.5) { + mass += 0.25; + mInitialMass += 0.25; + } + const int OId = oldFlag>>24; + const LbmVec vel(mObjectSpeeds[OId]); + ux=vel[0], uy=vel[1], uz=vel[2]; + //? usqr = 1.5 * (ux*ux + uy*uy + uz*uz); + //FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); } rho = fluidRho; + rho = REFERENCE_PRESSURE; + FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,ux,uy,uz); } + //errMsg("INFLOW_DEBUG","if at "<RWVEL_WINDTHRESH) && (lcsmqomSizez-SLOWDOWNREGION) ) { + LbmFloat nuz = uz; + if(k>mSizez-SLOWDOWNREGION) { + // special case + LbmFloat zfac = (LbmFloat)( k-(mSizez-SLOWDOWNREGION) ); + zfac /= (LbmFloat)(SLOWDOWNREGION); + nuz += (1.0) * zfac; // check max speed? OFF? + //errMsg("TOPT"," at "<0.025) { + const LbmFloat add = this->dfLength[l]*(-ux*this->dfDvecX[l]-uy*this->dfDvecY[l]-nuz*this->dfDvecZ[l])*jdf; + RAC(tcel,l) += add; } + } + //errMsg("TOPDOWNCORR"," jdf:"<0.0095)) { // add + if((prob0.012)) { // add + } else { doAdd = false; }// dont... + } + + + // remove noise + if(usqr<0.0001) doAdd=false; // TODO check!? + + // dont try to subtract from empty cells + // ensure cell has enough mass for new drop + LbmFloat newPartsize = 1.0; + if(mPartUsePhysModel) { + // 1-10 + newPartsize += 9.0* (rand()/(RAND_MAX+1.0)); + } else { + // 1-5, overall size has to be less than + // .62 (ca. 0.5) to make drops significantly smaller + // than a full cell! + newPartsize += 4.0* (rand()/(RAND_MAX+1.0)); + } + LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize); //PARTMASS(mPartDropMassSub*newPartsize); // mass: 4/3 pi r^3 rho + while(dropmass>mass) { + newPartsize -= 0.2; + dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize); + } + if(newPartsize<=1.) doAdd=false; + + if( (doAdd) ) { // init new particle + for(int s=0; s<1; s++) { // one part! + const LbmFloat posjitter = 0.05; + const LbmFloat posjitteroffs = posjitter*-0.5; + LbmFloat jpx = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); + LbmFloat jpy = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); + LbmFloat jpz = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); + + const LbmFloat jitterstr = 1.0; + const LbmFloat jitteroffs = jitterstr*-0.5; + LbmFloat jx = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); + LbmFloat jy = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); + LbmFloat jz = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); + + // average normal & velocity + // -> mostly along velocity dir, many into surface + // fluid velocity (not normalized!) + LbmVec flvelVel = LbmVec(ux,uy,uz); + LbmFloat flvelLen = norm(flvelVel); + // surface normal + LbmVec normVel = LbmVec(surfaceNormal[0],surfaceNormal[1],surfaceNormal[2]); + normalize(normVel); + LbmFloat normScale = (0.01+flvelLen); + // jitter vector, 0.2 * flvel + LbmVec jittVel = LbmVec(jx,jy,jz)*(0.05+flvelLen)*0.1; + // weighten velocities + const LbmFloat flvelWeight = 0.9; + LbmVec newpartVel = normVel*normScale*(1.-flvelWeight) + flvelVel*(flvelWeight) + jittVel; + + // offset towards surface (hide popping) + jpx += -normVel[0]*0.4; + jpy += -normVel[1]*0.4; + jpz += -normVel[2]*0.4; + + LbmFloat srci=i+0.5+jpx, srcj=j+0.5+jpy, srck=k+0.5+jpz; + int type=0; + type = PART_DROP; + +# if LBMDIM==2 + newpartVel[2]=0.; srck=0.5; +# endif // LBMDIM==2 + // subtract drop mass + mass -= dropmass; + // init new particle + { + ParticleObject np( ntlVec3Gfx(srci,srcj,srck) ); + np.setVel(newpartVel[0],newpartVel[1],newpartVel[2]); + np.setStatus(PART_IN); + np.setType(type); + //if((s%3)==2) np.setType(PART_FLOAT); + np.setSize(newPartsize); + //errMsg("NEWPART"," at "<= (rho * (1.0+FSGR_MAGICNR)) ) { iffilled = 1; } + // interface cell if empty? + if( (mass) <= (rho * ( -FSGR_MAGICNR)) ) { ifemptied = 1; } + + if(oldFlag & (CFMbndOutflow)) { + mInitialMass -= mass; + mass = myfrac = 0.0; + iffilled = 0; ifemptied = 1; + } + + // looks much nicer... LISTTRICK +# if FSGR_LISTTRICK==1 + //if((oldFlag&CFNoNbEmpty)&&(newFlag&CFNoNbEmpty)) { TEST_IF_CHECK; } + if(newFlag&CFNoBndFluid) { // test NEW TEST + if(!iffilled) { + // remove cells independent from amount of change... + if( (oldFlag & CFNoNbEmpty)&&(newFlag & CFNoNbEmpty)&& + ( (mass>(rho*FSGR_LISTTTHRESHFULL)) || ((nbored&CFInter)==0) )) { + //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","filled "< better cell conversions + RAC(tcel,dFfrac) = (mass/rho); + + // init new flux value + float flux = FLUX_INIT; // dxqn on + if(newFlag&CFNoBndFluid) { + //flux = 50.0; // extreme on + for(int nn=1; nncDfNum; nn++) { + if(nbflag[nn] & (CFFluid|CFInter|CFBnd)) { flux += this->dfLength[nn]; } + } + // optical hack - smooth slow moving + // surface regions + if(usqr< sssUsqrLimit) { + for(int nn=1; nncDfNum; nn++) { + if(nbfracs[nn]!=0.0) { + LbmFloat curSmooth = (sssUsqrLimit-usqr)*sssUsqrLimitInv; + if(curSmooth>1.0) curSmooth=1.0; + flux *= (1.0+ smoothStrength*curSmooth * (nbfracs[nn]-myfrac)) ; + } + } } + // NEW TEST */ + } + // flux = FLUX_INIT; // calc flux off + QCELL(lev, i,j,k,TSET(lev), dFlux) = flux; // */ + + // perform mass exchange with streamed values + QCELL(lev, i,j,k,TSET(lev), dMass) = mass; // MASST + // set new flag + *pFlagDst = (CellFlagType)newFlag; + calcCurrentMass += mass; + calcCurrentVolume += RAC(tcel,dFfrac); + + // interface cell handling done... + +#if PARALLEL!=1 + GRID_LOOPREG_END(); +#else // PARALLEL==1 +#include "paraloopend.h" // = GRID_LOOPREG_END(); +#endif // PARALLEL==1 + + // write vars from computations to class + mLevel[lev].lmass = calcCurrentMass; + mLevel[lev].lvolume = calcCurrentVolume; + mNumFilledCells = calcCellsFilled; + mNumEmptiedCells = calcCellsEmptied; + mNumUsedCells = calcNumUsedCells; +} + + + +void +LbmFsgrSolver::preinitGrids() +{ + const int lev = mMaxRefine; + const bool doReduce = false; + const int gridLoopBound=0; + + // preinit both grids + for(int s=0; s<2; s++) { + + GRID_REGION_INIT(); +#if PARALLEL==1 +#include "paraloopstart.h" +#endif // PARALLEL==1 + GRID_REGION_START(); + GRID_LOOP_START(); + for(int l=0; l-LBM_EPSILON) ret = 0.0; + else ret = scal * -1.0; + } + //errMsg("massd", PRINT_IJK<<" nv"<dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + //if((LBMDIM>2)&&( (ni<=0) || (nj<=0) || (nk<=0) || (ni>=mLevel[workLev].lSizex-1) || (nj>=mLevel[workLev].lSizey-1) || (nk>=mLevel[workLev].lSizez-1) )) { + if( (ni<=0) || (nj<=0) || + (ni>=mLevel[workLev].lSizex-1) || + (nj>=mLevel[workLev].lSizey-1) +# if LBMDIM==3 + || (nk<=0) || (nk>=mLevel[workLev].lSizez-1) +# endif // LBMDIM==1 + ) { + continue; } // new bc, dont treat cells on boundary NEWBC + if( RFLAG(workLev, ni,nj,nk, workSet) & CFEmpty ){ + + // preinit speed, get from average surrounding cells + // interpolate from non-workset to workset, sets are handled in function + + // new and empty interface cell, dont change old flag here! + addToNewInterList(ni,nj,nk); + + LbmFloat avgrho = 0.0; + LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0; + interpolateCellValues(workLev,ni,nj,nk,workSet, avgrho,avgux,avguy,avguz); + + // careful with l's... + FORDF0M { + QCELL(workLev,ni,nj,nk, workSet, m) = this->getCollideEq( m,avgrho, avgux, avguy, avguz ); + //QCELL(workLev,ni,nj,nk, workSet, l) = avgnbdf[l]; // CHECK FIXME test? + } + //errMsg("FNEW", PRINT_VEC(ni,nj,nk)<<" mss"< + let fill cells+surrounding interface cells have the higher importance */ + for( vector::iterator iter=mListEmpty.begin(); + iter != mListEmpty.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)){ errMsg("A"," ARGHARGRAG "); } // DEBUG + if(debugFlagreinit) errMsg("EMPT", PRINT_IJK<<" mss"<dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFFluid){ + // init fluid->interface + //RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(CFInter); + changeFlag(workLev,ni,nj,nk, workSet, CFInter); + /* new mass = current density */ + LbmFloat nbrho = QCELL(workLev,ni,nj,nk, workSet, dC); + for(int rl=1; rl< this->cDfNum ; ++rl) { nbrho += QCELL(workLev,ni,nj,nk, workSet, rl); } + QCELL(workLev,ni,nj,nk, workSet, dMass) = nbrho; + QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 1.0; + + // store point + addToNewInterList(ni,nj,nk); + } + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter){ + // test, also add to list... + addToNewInterList(ni,nj,nk); + } // NEW? + } + + /* for symmetry, set our flag right now */ + changeFlag(workLev,i,j,k, workSet, CFEmpty); + // mark cell not be changed mass... - not necessary, not in list anymore anyway! + } // emptylist + + + + // precompute weights to get rid of order dependancies + vector vWeights; + vWeights.resize( mListFull.size() + mListEmpty.size() ); + int weightIndex = 0; + int nbCount = 0; + LbmFloat nbWeights[LBM_DFNUM]; + LbmFloat nbTotWeights = 0.0; + for( vector::iterator iter=mListFull.begin(); + iter != mListFull.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + nbCount = 0; nbTotWeights = 0.0; + FORDF1 { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { + nbCount++; + if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT + else nbWeights[l] = getMassdWeight(1,i,j,k,workSet,l); // NEWSURFT + nbTotWeights += nbWeights[l]; + } else { + nbWeights[l] = -100.0; // DEBUG; + } + } + if(nbCount>0) { + //errMsg("FF I", PRINT_IJK<<" "<::iterator iter=mListEmpty.begin(); + iter != mListEmpty.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + nbCount = 0; nbTotWeights = 0.0; + FORDF1 { + int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { + nbCount++; + if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT + else nbWeights[l] = getMassdWeight(0,i,j,k,workSet,l); // NEWSURFT + nbTotWeights += nbWeights[l]; + } else { + nbWeights[l] = -100.0; // DEBUG; + } + } + if(nbCount>0) { + //errMsg("EE I", PRINT_IJK<<" "<::iterator iter=mListFull.begin(); + iter != mListFull.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + + LbmFloat myrho = QCELL(workLev,i,j,k, workSet, dC); + FORDF1 { myrho += QCELL(workLev,i,j,k, workSet, l); } // QCELL.rho + + LbmFloat massChange = QCELL(workLev,i,j,k, workSet, dMass) - myrho; + if(vWeights[weightIndex].numNbs>0.0) { + const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0]; + //errMsg("FF I", PRINT_IJK<<" "<dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { + LbmFloat change = -1.0; + if(nbTotWeightsp>0.0) { + //change = massChange * ( nbWeights[l]/nbTotWeightsp ); + change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp ); + } else { + change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs); + } + QCELL(workLev,ni,nj,nk, workSet, dMass) += change; + } + } + massChange = 0.0; + } else { + // Problem! no interface neighbors + mFixMass += massChange; + //TTT mNumProblems++; + //errMsg(" FULL PROBLEM ", PRINT_IJK<<" "<::iterator iter=mListEmpty.begin(); + iter != mListEmpty.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + + LbmFloat massChange = QCELL(workLev, i,j,k, workSet, dMass); + if(vWeights[weightIndex].numNbs>0.0) { + const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0]; + //errMsg("EE I", PRINT_IJK<<" "<dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; + if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { + LbmFloat change = -1.0; + if(nbTotWeightsp>0.0) { + change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp ); + } else { + change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs); + } + QCELL(workLev, ni,nj,nk, workSet, dMass) += change; + } + } + massChange = 0.0; + } else { + // Problem! no interface neighbors + mFixMass += massChange; + //TTT mNumProblems++; + //errMsg(" EMPT PROBLEM ", PRINT_IJK<<" "<::iterator iter=mListEmpty.begin(); + iter != mListEmpty.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + changeFlag(workLev,i,j,k, otherSet, CFEmpty); + } + + + // check if some of the new interface cells can be removed again + // never happens !!! not necessary + // calculate ffrac for new IF cells NEW + + // how many are really new interface cells? + int numNewIf = 0; + for( vector::iterator iter=mListNewInter.begin(); + iter != mListNewInter.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { + continue; + // FIXME remove from list? + } + numNewIf++; + } + + // redistribute mass, reinit flags + if(debugFlagreinit) errMsg("NEWIF", "total:"<::iterator iter=mListNewInter.begin(); + iter != mListNewInter.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + if((i<=0) || (j<=0) || + (i>=mLevel[workLev].lSizex-1) || + (j>=mLevel[workLev].lSizey-1) || + ((LBMDIM==3) && ((k<=0) || (k>=mLevel[workLev].lSizez-1) ) ) + ) { + continue; } // new bc, dont treat cells on boundary NEWBC + if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { + //errMsg("???"," "<::iterator iter=mListNewInter.begin(); + iter != mListNewInter.end(); iter++ ) { + int i=iter->x, j=iter->y, k=iter->z; + if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { continue; } + + initInterfaceVars(workLev, i,j,k, workSet, false); //int level, int i,int j,int k,int workSet, bool initMass) { + //LbmFloat nrho = 0.0; + //FORDF0 { nrho += QCELL(workLev, i,j,k, workSet, l); } + //QCELL(workLev,i,j,k, workSet, dFfrac) = QCELL(workLev,i,j,k, workSet, dMass)/nrho; + //QCELL(workLev,i,j,k, workSet, dFlux) = FLUX_INIT; + } + + if(mListNewInter.size()>0){ + //errMsg("FixMassDisted"," fm:"<mPanic=1; /* *((int*)(0x0)) = 1; crash*/ } +#else // FSGR_STRICT_DEBUG==1 +#define CAUSE_PANIC { this->mPanic=1; } /*set flag*/ +#endif // FSGR_STRICT_DEBUG==1 + +#if LBM_INCLUDE_TESTSOLVERS!=1 + +#define PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \ + ux += (grav)[0]; \ + uy += (grav)[1]; \ + uz += (grav)[2]; + +#define TEST_IF_CHECK + +#else // LBM_INCLUDE_TESTSOLVERS!=1 +// defined in test.h + +#define NEWDIRVELMOTEST 0 +#if NEWDIRVELMOTEST==1 +// off for non testing +#undef PRECOLLIDE_MODS +#define PRECOLLIDE_MODS(rho,ux,uy,uz, grav) \ + ux += (grav)[0]; \ + uy += (grav)[1]; \ + uz += (grav)[2]; \ + { \ + int lev = mMaxRefine, nomb=0; \ + LbmFloat bcnt = 0.,nux=0.,nuy=0.,nuz=0.; \ + for(int l=1; lcDfNum; l++) { \ + if(RFLAG_NB(lev, i,j,k,SRCS(lev),l)&CFBnd) { \ + if(RFLAG_NB(lev, i,j,k,SRCS(lev),l)&CFBndMoving) { \ + nux += QCELL_NB(lev, i,j,k,SRCS(lev),l, dMass); \ + nuy += QCELL_NB(lev, i,j,k,SRCS(lev),l, dFfrac); \ + bcnt += 1.; \ + } else { \ + nomb++; \ + } \ + } \ + } \ + if((bcnt>0.)&&(nomb==0)) { \ + ux = nux/bcnt; \ + uy = nuy/bcnt; \ + uz = nuz/bcnt; \ + } \ + } +#else // NEWDIRVELMOTEST==1 +// off for non testing +#endif // NEWDIRVELMOTEST==1 + +#endif // LBM_INCLUDE_TESTSOLVERS!=1 + + +/****************************************************************************** + * normal relaxation + *****************************************************************************/ + +// standard arrays +#define CSRC_C RAC(ccel , dC ) +#define CSRC_E RAC(ccel + (-1) *(dTotalNum), dE ) +#define CSRC_W RAC(ccel + (+1) *(dTotalNum), dW ) +#define CSRC_N RAC(ccel + (-mLevel[lev].lOffsx) *(dTotalNum), dN ) +#define CSRC_S RAC(ccel + (+mLevel[lev].lOffsx) *(dTotalNum), dS ) +#define CSRC_NE RAC(ccel + (-mLevel[lev].lOffsx-1) *(dTotalNum), dNE) +#define CSRC_NW RAC(ccel + (-mLevel[lev].lOffsx+1) *(dTotalNum), dNW) +#define CSRC_SE RAC(ccel + (+mLevel[lev].lOffsx-1) *(dTotalNum), dSE) +#define CSRC_SW RAC(ccel + (+mLevel[lev].lOffsx+1) *(dTotalNum), dSW) +#define CSRC_T RAC(ccel + (-mLevel[lev].lOffsy) *(dTotalNum), dT ) +#define CSRC_B RAC(ccel + (+mLevel[lev].lOffsy) *(dTotalNum), dB ) +#define CSRC_ET RAC(ccel + (-mLevel[lev].lOffsy-1) *(dTotalNum), dET) +#define CSRC_EB RAC(ccel + (+mLevel[lev].lOffsy-1) *(dTotalNum), dEB) +#define CSRC_WT RAC(ccel + (-mLevel[lev].lOffsy+1) *(dTotalNum), dWT) +#define CSRC_WB RAC(ccel + (+mLevel[lev].lOffsy+1) *(dTotalNum), dWB) +#define CSRC_NT RAC(ccel + (-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNT) +#define CSRC_NB RAC(ccel + (+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *(dTotalNum), dNB) +#define CSRC_ST RAC(ccel + (-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dST) +#define CSRC_SB RAC(ccel + (+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *(dTotalNum), dSB) + +#define XSRC_C(x) RAC(ccel + (x) *dTotalNum, dC ) +#define XSRC_E(x) RAC(ccel + ((x)-1) *dTotalNum, dE ) +#define XSRC_W(x) RAC(ccel + ((x)+1) *dTotalNum, dW ) +#define XSRC_N(x) RAC(ccel + ((x)-mLevel[lev].lOffsx) *dTotalNum, dN ) +#define XSRC_S(x) RAC(ccel + ((x)+mLevel[lev].lOffsx) *dTotalNum, dS ) +#define XSRC_NE(x) RAC(ccel + ((x)-mLevel[lev].lOffsx-1) *dTotalNum, dNE) +#define XSRC_NW(x) RAC(ccel + ((x)-mLevel[lev].lOffsx+1) *dTotalNum, dNW) +#define XSRC_SE(x) RAC(ccel + ((x)+mLevel[lev].lOffsx-1) *dTotalNum, dSE) +#define XSRC_SW(x) RAC(ccel + ((x)+mLevel[lev].lOffsx+1) *dTotalNum, dSW) +#define XSRC_T(x) RAC(ccel + ((x)-mLevel[lev].lOffsy) *dTotalNum, dT ) +#define XSRC_B(x) RAC(ccel + ((x)+mLevel[lev].lOffsy) *dTotalNum, dB ) +#define XSRC_ET(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-1) *dTotalNum, dET) +#define XSRC_EB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-1) *dTotalNum, dEB) +#define XSRC_WT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+1) *dTotalNum, dWT) +#define XSRC_WB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+1) *dTotalNum, dWB) +#define XSRC_NT(x) RAC(ccel + ((x)-mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNT) +#define XSRC_NB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy-mLevel[lev].lOffsx) *dTotalNum, dNB) +#define XSRC_ST(x) RAC(ccel + ((x)-mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dST) +#define XSRC_SB(x) RAC(ccel + ((x)+mLevel[lev].lOffsy+mLevel[lev].lOffsx) *dTotalNum, dSB) + + + +#define OMEGA(l) mLevel[(l)].omega + +#define EQC ( DFL1*(rho - usqr)) +#define EQN ( DFL2*(rho + uy*(4.5*uy + 3.0) - usqr)) +#define EQS ( DFL2*(rho + uy*(4.5*uy - 3.0) - usqr)) +#define EQE ( DFL2*(rho + ux*(4.5*ux + 3.0) - usqr)) +#define EQW ( DFL2*(rho + ux*(4.5*ux - 3.0) - usqr)) +#define EQT ( DFL2*(rho + uz*(4.5*uz + 3.0) - usqr)) +#define EQB ( DFL2*(rho + uz*(4.5*uz - 3.0) - usqr)) + +#define EQNE ( DFL3*(rho + (+ux+uy)*(4.5*(+ux+uy) + 3.0) - usqr)) +#define EQNW ( DFL3*(rho + (-ux+uy)*(4.5*(-ux+uy) + 3.0) - usqr)) +#define EQSE ( DFL3*(rho + (+ux-uy)*(4.5*(+ux-uy) + 3.0) - usqr)) +#define EQSW ( DFL3*(rho + (-ux-uy)*(4.5*(-ux-uy) + 3.0) - usqr)) +#define EQNT ( DFL3*(rho + (+uy+uz)*(4.5*(+uy+uz) + 3.0) - usqr)) +#define EQNB ( DFL3*(rho + (+uy-uz)*(4.5*(+uy-uz) + 3.0) - usqr)) +#define EQST ( DFL3*(rho + (-uy+uz)*(4.5*(-uy+uz) + 3.0) - usqr)) +#define EQSB ( DFL3*(rho + (-uy-uz)*(4.5*(-uy-uz) + 3.0) - usqr)) +#define EQET ( DFL3*(rho + (+ux+uz)*(4.5*(+ux+uz) + 3.0) - usqr)) +#define EQEB ( DFL3*(rho + (+ux-uz)*(4.5*(+ux-uz) + 3.0) - usqr)) +#define EQWT ( DFL3*(rho + (-ux+uz)*(4.5*(-ux+uz) + 3.0) - usqr)) +#define EQWB ( DFL3*(rho + (-ux-uz)*(4.5*(-ux-uz) + 3.0) - usqr)) + + +// this is a bit ugly, but necessary for the CSRC_ access... +#define MSRC_C m[dC ] +#define MSRC_N m[dN ] +#define MSRC_S m[dS ] +#define MSRC_E m[dE ] +#define MSRC_W m[dW ] +#define MSRC_T m[dT ] +#define MSRC_B m[dB ] +#define MSRC_NE m[dNE] +#define MSRC_NW m[dNW] +#define MSRC_SE m[dSE] +#define MSRC_SW m[dSW] +#define MSRC_NT m[dNT] +#define MSRC_NB m[dNB] +#define MSRC_ST m[dST] +#define MSRC_SB m[dSB] +#define MSRC_ET m[dET] +#define MSRC_EB m[dEB] +#define MSRC_WT m[dWT] +#define MSRC_WB m[dWB] + +// this is a bit ugly, but necessary for the ccel local access... +#define CCEL_C RAC(ccel, dC ) +#define CCEL_N RAC(ccel, dN ) +#define CCEL_S RAC(ccel, dS ) +#define CCEL_E RAC(ccel, dE ) +#define CCEL_W RAC(ccel, dW ) +#define CCEL_T RAC(ccel, dT ) +#define CCEL_B RAC(ccel, dB ) +#define CCEL_NE RAC(ccel, dNE) +#define CCEL_NW RAC(ccel, dNW) +#define CCEL_SE RAC(ccel, dSE) +#define CCEL_SW RAC(ccel, dSW) +#define CCEL_NT RAC(ccel, dNT) +#define CCEL_NB RAC(ccel, dNB) +#define CCEL_ST RAC(ccel, dST) +#define CCEL_SB RAC(ccel, dSB) +#define CCEL_ET RAC(ccel, dET) +#define CCEL_EB RAC(ccel, dEB) +#define CCEL_WT RAC(ccel, dWT) +#define CCEL_WB RAC(ccel, dWB) +// for coarse to fine interpol access +#define CCELG_C(f) (RAC(ccel, dC )*mGaussw[(f)]) +#define CCELG_N(f) (RAC(ccel, dN )*mGaussw[(f)]) +#define CCELG_S(f) (RAC(ccel, dS )*mGaussw[(f)]) +#define CCELG_E(f) (RAC(ccel, dE )*mGaussw[(f)]) +#define CCELG_W(f) (RAC(ccel, dW )*mGaussw[(f)]) +#define CCELG_T(f) (RAC(ccel, dT )*mGaussw[(f)]) +#define CCELG_B(f) (RAC(ccel, dB )*mGaussw[(f)]) +#define CCELG_NE(f) (RAC(ccel, dNE)*mGaussw[(f)]) +#define CCELG_NW(f) (RAC(ccel, dNW)*mGaussw[(f)]) +#define CCELG_SE(f) (RAC(ccel, dSE)*mGaussw[(f)]) +#define CCELG_SW(f) (RAC(ccel, dSW)*mGaussw[(f)]) +#define CCELG_NT(f) (RAC(ccel, dNT)*mGaussw[(f)]) +#define CCELG_NB(f) (RAC(ccel, dNB)*mGaussw[(f)]) +#define CCELG_ST(f) (RAC(ccel, dST)*mGaussw[(f)]) +#define CCELG_SB(f) (RAC(ccel, dSB)*mGaussw[(f)]) +#define CCELG_ET(f) (RAC(ccel, dET)*mGaussw[(f)]) +#define CCELG_EB(f) (RAC(ccel, dEB)*mGaussw[(f)]) +#define CCELG_WT(f) (RAC(ccel, dWT)*mGaussw[(f)]) +#define CCELG_WB(f) (RAC(ccel, dWB)*mGaussw[(f)]) + + +#if PARALLEL==1 +#define CSMOMEGA_STATS(dlev, domega) +#else // PARALLEL==1 +#if FSGR_OMEGA_DEBUG==1 +#define CSMOMEGA_STATS(dlev, domega) \ + mLevel[dlev].avgOmega += domega; mLevel[dlev].avgOmegaCnt+=1.0; +#else // FSGR_OMEGA_DEBUG==1 +#define CSMOMEGA_STATS(dlev, domega) +#endif // FSGR_OMEGA_DEBUG==1 +#endif // PARALLEL==1 + + +// used for main loops and grav init +// source set +#define SRCS(l) mLevel[(l)].setCurr +// target set +#define TSET(l) mLevel[(l)].setOther + +// handle mov. obj +#if FSGR_STRICT_DEBUG==1 + +#define LBMDS_ADDMOV(linv,l) \ + \ + if((nbflag[linv]&CFBndMoving)&&(!(nbflag[l]&CFBnd))){ \ + \ + LbmFloat dte=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,dFlux)-(mSimulationTime+this->mpParam->getTimestep()); \ + if( ABS(dte)< 1e-15 ) { \ + m[l]+=QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \ + } else { \ + const int sdx = i+this->dfVecX[linv], sdy = j+this->dfVecY[linv], sdz = k+this->dfVecZ[linv]; \ + \ + errMsg("INVALID_MOV_OBJ_TIME"," at "<dfInv[l] ); \ + } \ + } else { \ + m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l,l); \ + if(RFLAG(lev, i,j,k, mLevel[lev].setCurr)&CFFluid) { \ + if(!(nbf&(CFFluid|CFInter)) ) { \ + int ni=i+this->dfVecX[this->dfInv[l]], nj=j+this->dfVecY[this->dfInv[l]], nk=k+this->dfVecZ[this->dfInv[l]]; \ + errMsg("STREAMCHECK"," Invalid nbflag, streamed DF l"<dfVecX[this->dfInv[l]], j+this->dfVecY[this->dfInv[l]],k+this->dfVecZ[this->dfInv[l]], l); \ + } \ + } \ + + + + +// careful ux,uy,uz need to be inited before! +#define DEFAULT_COLLIDEG(grav) \ + this->collideArrays(lev, i,j,k, m, rho,ux,uy,uz, OMEGA(lev), grav, mLevel[lev].lcsmago, &mDebugOmegaRet, &lcsmqo ); \ + CSMOMEGA_STATS(lev,mDebugOmegaRet); \ + FORDF0 { RAC(tcel,l) = m[l]; } \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLLCHECK; \ + + + +#define OPTIMIZED_STREAMCOLLIDE \ + m[0] = RAC(ccel,0); \ + FORDF1 { \ + \ + if(RFLAG_NBINV(lev, i,j,k,SRCS(lev),l)&CFBnd) { errMsg("???", "bnd-err-nobndfl"); CAUSE_PANIC; \ + } else { m[l] = QCELL_NBINV(lev, i, j, k, SRCS(lev), l, l); } \ + STREAMCHECK(8, i+this->dfVecX[this->dfInv[l]], j+this->dfVecY[this->dfInv[l]],k+this->dfVecZ[this->dfInv[l]], l); \ + } \ + rho=m[0]; \ + DEFAULT_COLLIDEG(mLevel[lev].gravity) \ + + + +#define OPTIMIZED_STREAMCOLLIDE___UNUSED \ + \ + this->collideArrays(lev, i,j,k, m, rho,ux,uy,uz, OMEGA(lev), mLevel[lev].gravity, mLevel[lev].lcsmago , &mDebugOmegaRet, &lcsmqo ); \ + CSMOMEGA_STATS(lev,mDebugOmegaRet); \ + FORDF0 { RAC(tcel,l) = m[l]; } \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLLCHECK; \ + + + +#else // 3D, opt OPT3D==true + + +// default stream opt3d add moving bc val +#define DEFAULT_STREAM \ + m[dC] = RAC(ccel,dC); \ + \ + if((!nbored & CFBnd)) { \ + \ + m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \ + m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \ + m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \ + m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \ + m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \ + m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \ + } else { \ + \ + if(nbflag[dS ]&CFBnd) { m[dN ] = RAC(ccel,dS ); LBMDS_ADDMOV(dS ,dN ); } else { m[dN ] = CSRC_N ; } \ + if(nbflag[dN ]&CFBnd) { m[dS ] = RAC(ccel,dN ); LBMDS_ADDMOV(dN ,dS ); } else { m[dS ] = CSRC_S ; } \ + if(nbflag[dW ]&CFBnd) { m[dE ] = RAC(ccel,dW ); LBMDS_ADDMOV(dW ,dE ); } else { m[dE ] = CSRC_E ; } \ + if(nbflag[dE ]&CFBnd) { m[dW ] = RAC(ccel,dE ); LBMDS_ADDMOV(dE ,dW ); } else { m[dW ] = CSRC_W ; } \ + if(nbflag[dB ]&CFBnd) { m[dT ] = RAC(ccel,dB ); LBMDS_ADDMOV(dB ,dT ); } else { m[dT ] = CSRC_T ; } \ + if(nbflag[dT ]&CFBnd) { m[dB ] = RAC(ccel,dT ); LBMDS_ADDMOV(dT ,dB ); } else { m[dB ] = CSRC_B ; } \ + \ + \ + if(nbflag[dSW]&CFBnd) { if(nbflag[dSW]&CFBndNoslip){ m[dNE] = RAC(ccel,dSW); LBMDS_ADDMOV(dSW,dNE); }else{ DEFAULT_STREAM_FREESLIP(dNE,dSW,nbflag[dSW]);} } else { m[dNE] = CSRC_NE; } \ + if(nbflag[dSE]&CFBnd) { if(nbflag[dSE]&CFBndNoslip){ m[dNW] = RAC(ccel,dSE); LBMDS_ADDMOV(dSE,dNW); }else{ DEFAULT_STREAM_FREESLIP(dNW,dSE,nbflag[dSE]);} } else { m[dNW] = CSRC_NW; } \ + if(nbflag[dNW]&CFBnd) { if(nbflag[dNW]&CFBndNoslip){ m[dSE] = RAC(ccel,dNW); LBMDS_ADDMOV(dNW,dSE); }else{ DEFAULT_STREAM_FREESLIP(dSE,dNW,nbflag[dNW]);} } else { m[dSE] = CSRC_SE; } \ + if(nbflag[dNE]&CFBnd) { if(nbflag[dNE]&CFBndNoslip){ m[dSW] = RAC(ccel,dNE); LBMDS_ADDMOV(dNE,dSW); }else{ DEFAULT_STREAM_FREESLIP(dSW,dNE,nbflag[dNE]);} } else { m[dSW] = CSRC_SW; } \ + if(nbflag[dSB]&CFBnd) { if(nbflag[dSB]&CFBndNoslip){ m[dNT] = RAC(ccel,dSB); LBMDS_ADDMOV(dSB,dNT); }else{ DEFAULT_STREAM_FREESLIP(dNT,dSB,nbflag[dSB]);} } else { m[dNT] = CSRC_NT; } \ + if(nbflag[dST]&CFBnd) { if(nbflag[dST]&CFBndNoslip){ m[dNB] = RAC(ccel,dST); LBMDS_ADDMOV(dST,dNB); }else{ DEFAULT_STREAM_FREESLIP(dNB,dST,nbflag[dST]);} } else { m[dNB] = CSRC_NB; } \ + if(nbflag[dNB]&CFBnd) { if(nbflag[dNB]&CFBndNoslip){ m[dST] = RAC(ccel,dNB); LBMDS_ADDMOV(dNB,dST); }else{ DEFAULT_STREAM_FREESLIP(dST,dNB,nbflag[dNB]);} } else { m[dST] = CSRC_ST; } \ + if(nbflag[dNT]&CFBnd) { if(nbflag[dNT]&CFBndNoslip){ m[dSB] = RAC(ccel,dNT); LBMDS_ADDMOV(dNT,dSB); }else{ DEFAULT_STREAM_FREESLIP(dSB,dNT,nbflag[dNT]);} } else { m[dSB] = CSRC_SB; } \ + if(nbflag[dWB]&CFBnd) { if(nbflag[dWB]&CFBndNoslip){ m[dET] = RAC(ccel,dWB); LBMDS_ADDMOV(dWB,dET); }else{ DEFAULT_STREAM_FREESLIP(dET,dWB,nbflag[dWB]);} } else { m[dET] = CSRC_ET; } \ + if(nbflag[dWT]&CFBnd) { if(nbflag[dWT]&CFBndNoslip){ m[dEB] = RAC(ccel,dWT); LBMDS_ADDMOV(dWT,dEB); }else{ DEFAULT_STREAM_FREESLIP(dEB,dWT,nbflag[dWT]);} } else { m[dEB] = CSRC_EB; } \ + if(nbflag[dEB]&CFBnd) { if(nbflag[dEB]&CFBndNoslip){ m[dWT] = RAC(ccel,dEB); LBMDS_ADDMOV(dEB,dWT); }else{ DEFAULT_STREAM_FREESLIP(dWT,dEB,nbflag[dEB]);} } else { m[dWT] = CSRC_WT; } \ + if(nbflag[dET]&CFBnd) { if(nbflag[dET]&CFBndNoslip){ m[dWB] = RAC(ccel,dET); LBMDS_ADDMOV(dET,dWB); }else{ DEFAULT_STREAM_FREESLIP(dWB,dET,nbflag[dET]);} } else { m[dWB] = CSRC_WB; } \ + } \ + + + + + +#define COLL_CALCULATE_DFEQ(dstarray) \ + dstarray[dN ] = EQN ; dstarray[dS ] = EQS ; \ + dstarray[dE ] = EQE ; dstarray[dW ] = EQW ; \ + dstarray[dT ] = EQT ; dstarray[dB ] = EQB ; \ + dstarray[dNE] = EQNE; dstarray[dNW] = EQNW; dstarray[dSE] = EQSE; dstarray[dSW] = EQSW; \ + dstarray[dNT] = EQNT; dstarray[dNB] = EQNB; dstarray[dST] = EQST; dstarray[dSB] = EQSB; \ + dstarray[dET] = EQET; dstarray[dEB] = EQEB; dstarray[dWT] = EQWT; dstarray[dWB] = EQWB; \ + + + +#define COLL_CALCULATE_NONEQTENSOR(csolev, srcArray ) \ + lcsmqadd = (srcArray##NE - lcsmeq[ dNE ]); \ + lcsmqadd -= (srcArray##NW - lcsmeq[ dNW ]); \ + lcsmqadd -= (srcArray##SE - lcsmeq[ dSE ]); \ + lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \ + lcsmqo = (lcsmqadd* lcsmqadd); \ + lcsmqadd = (srcArray##ET - lcsmeq[ dET ]); \ + lcsmqadd -= (srcArray##EB - lcsmeq[ dEB ]); \ + lcsmqadd -= (srcArray##WT - lcsmeq[ dWT ]); \ + lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqadd = (srcArray##NT - lcsmeq[ dNT ]); \ + lcsmqadd -= (srcArray##NB - lcsmeq[ dNB ]); \ + lcsmqadd -= (srcArray##ST - lcsmeq[ dST ]); \ + lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqo *= 2.0; \ + lcsmqadd = (srcArray##E - lcsmeq[ dE ]); \ + lcsmqadd += (srcArray##W - lcsmeq[ dW ]); \ + lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \ + lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \ + lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \ + lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \ + lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \ + lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \ + lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \ + lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqadd = (srcArray##N - lcsmeq[ dN ]); \ + lcsmqadd += (srcArray##S - lcsmeq[ dS ]); \ + lcsmqadd += (srcArray##NE - lcsmeq[ dNE ]); \ + lcsmqadd += (srcArray##NW - lcsmeq[ dNW ]); \ + lcsmqadd += (srcArray##SE - lcsmeq[ dSE ]); \ + lcsmqadd += (srcArray##SW - lcsmeq[ dSW ]); \ + lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \ + lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \ + lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \ + lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqadd = (srcArray##T - lcsmeq[ dT ]); \ + lcsmqadd += (srcArray##B - lcsmeq[ dB ]); \ + lcsmqadd += (srcArray##NT - lcsmeq[ dNT ]); \ + lcsmqadd += (srcArray##NB - lcsmeq[ dNB ]); \ + lcsmqadd += (srcArray##ST - lcsmeq[ dST ]); \ + lcsmqadd += (srcArray##SB - lcsmeq[ dSB ]); \ + lcsmqadd += (srcArray##ET - lcsmeq[ dET ]); \ + lcsmqadd += (srcArray##EB - lcsmeq[ dEB ]); \ + lcsmqadd += (srcArray##WT - lcsmeq[ dWT ]); \ + lcsmqadd += (srcArray##WB - lcsmeq[ dWB ]); \ + lcsmqo += (lcsmqadd* lcsmqadd); \ + lcsmqo = sqrt(lcsmqo); \ + + + +// COLL_CALCULATE_CSMOMEGAVAL(csolev, lcsmomega); + +// careful - need lcsmqo +#define COLL_CALCULATE_CSMOMEGAVAL(csolev, dstomega ) \ + dstomega = 1.0/ \ + ( 3.0*( mLevel[(csolev)].lcnu+mLevel[(csolev)].lcsmago_sqr*( \ + -mLevel[(csolev)].lcnu + sqrt( mLevel[(csolev)].lcnu*mLevel[(csolev)].lcnu + 18.0*mLevel[(csolev)].lcsmago_sqr* lcsmqo ) \ + / (6.0*mLevel[(csolev)].lcsmago_sqr)) \ + ) +0.5 ); \ + + + +#define DEFAULT_COLLIDE_LES(grav) \ + rho = + MSRC_C + MSRC_N \ + + MSRC_S + MSRC_E \ + + MSRC_W + MSRC_T \ + + MSRC_B + MSRC_NE \ + + MSRC_NW + MSRC_SE \ + + MSRC_SW + MSRC_NT \ + + MSRC_NB + MSRC_ST \ + + MSRC_SB + MSRC_ET \ + + MSRC_EB + MSRC_WT \ + + MSRC_WB; \ + \ + ux = MSRC_E - MSRC_W \ + + MSRC_NE - MSRC_NW \ + + MSRC_SE - MSRC_SW \ + + MSRC_ET + MSRC_EB \ + - MSRC_WT - MSRC_WB ; \ + \ + uy = MSRC_N - MSRC_S \ + + MSRC_NE + MSRC_NW \ + - MSRC_SE - MSRC_SW \ + + MSRC_NT + MSRC_NB \ + - MSRC_ST - MSRC_SB ; \ + \ + uz = MSRC_T - MSRC_B \ + + MSRC_NT - MSRC_NB \ + + MSRC_ST - MSRC_SB \ + + MSRC_ET - MSRC_EB \ + + MSRC_WT - MSRC_WB ; \ + PRECOLLIDE_MODS(rho,ux,uy,uz, grav); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLL_CALCULATE_DFEQ(lcsmeq); \ + COLL_CALCULATE_NONEQTENSOR(lev, MSRC_); \ + COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \ + CSMOMEGA_STATS(lev,lcsmomega); \ + \ + RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \ + \ + RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \ + RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \ + RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \ + RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \ + RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \ + RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \ + \ + RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \ + RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \ + RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \ + RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \ + RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \ + RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \ + RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \ + RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \ + RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \ + RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \ + RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \ + RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \ + + + +#define DEFAULT_COLLIDE_NOLES(grav) \ + rho = + MSRC_C + MSRC_N \ + + MSRC_S + MSRC_E \ + + MSRC_W + MSRC_T \ + + MSRC_B + MSRC_NE \ + + MSRC_NW + MSRC_SE \ + + MSRC_SW + MSRC_NT \ + + MSRC_NB + MSRC_ST \ + + MSRC_SB + MSRC_ET \ + + MSRC_EB + MSRC_WT \ + + MSRC_WB; \ + \ + ux = MSRC_E - MSRC_W \ + + MSRC_NE - MSRC_NW \ + + MSRC_SE - MSRC_SW \ + + MSRC_ET + MSRC_EB \ + - MSRC_WT - MSRC_WB ; \ + \ + uy = MSRC_N - MSRC_S \ + + MSRC_NE + MSRC_NW \ + - MSRC_SE - MSRC_SW \ + + MSRC_NT + MSRC_NB \ + - MSRC_ST - MSRC_SB ; \ + \ + uz = MSRC_T - MSRC_B \ + + MSRC_NT - MSRC_NB \ + + MSRC_ST - MSRC_SB \ + + MSRC_ET - MSRC_EB \ + + MSRC_WT - MSRC_WB ; \ + PRECOLLIDE_MODS(rho, ux,uy,uz, grav); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + \ + RAC(tcel,dC ) = (1.0-OMEGA(lev))*MSRC_C + OMEGA(lev)*EQC ; \ + \ + RAC(tcel,dN ) = (1.0-OMEGA(lev))*MSRC_N + OMEGA(lev)*EQN ; \ + RAC(tcel,dS ) = (1.0-OMEGA(lev))*MSRC_S + OMEGA(lev)*EQS ; \ + RAC(tcel,dE ) = (1.0-OMEGA(lev))*MSRC_E + OMEGA(lev)*EQE ; \ + RAC(tcel,dW ) = (1.0-OMEGA(lev))*MSRC_W + OMEGA(lev)*EQW ; \ + RAC(tcel,dT ) = (1.0-OMEGA(lev))*MSRC_T + OMEGA(lev)*EQT ; \ + RAC(tcel,dB ) = (1.0-OMEGA(lev))*MSRC_B + OMEGA(lev)*EQB ; \ + \ + RAC(tcel,dNE) = (1.0-OMEGA(lev))*MSRC_NE + OMEGA(lev)*EQNE; \ + RAC(tcel,dNW) = (1.0-OMEGA(lev))*MSRC_NW + OMEGA(lev)*EQNW; \ + RAC(tcel,dSE) = (1.0-OMEGA(lev))*MSRC_SE + OMEGA(lev)*EQSE; \ + RAC(tcel,dSW) = (1.0-OMEGA(lev))*MSRC_SW + OMEGA(lev)*EQSW; \ + RAC(tcel,dNT) = (1.0-OMEGA(lev))*MSRC_NT + OMEGA(lev)*EQNT; \ + RAC(tcel,dNB) = (1.0-OMEGA(lev))*MSRC_NB + OMEGA(lev)*EQNB; \ + RAC(tcel,dST) = (1.0-OMEGA(lev))*MSRC_ST + OMEGA(lev)*EQST; \ + RAC(tcel,dSB) = (1.0-OMEGA(lev))*MSRC_SB + OMEGA(lev)*EQSB; \ + RAC(tcel,dET) = (1.0-OMEGA(lev))*MSRC_ET + OMEGA(lev)*EQET; \ + RAC(tcel,dEB) = (1.0-OMEGA(lev))*MSRC_EB + OMEGA(lev)*EQEB; \ + RAC(tcel,dWT) = (1.0-OMEGA(lev))*MSRC_WT + OMEGA(lev)*EQWT; \ + RAC(tcel,dWB) = (1.0-OMEGA(lev))*MSRC_WB + OMEGA(lev)*EQWB; \ + + + + + +#define OPTIMIZED_STREAMCOLLIDE_LES \ + \ + m[dC ] = CSRC_C ; \ + m[dN ] = CSRC_N ; m[dS ] = CSRC_S ; \ + m[dE ] = CSRC_E ; m[dW ] = CSRC_W ; \ + m[dT ] = CSRC_T ; m[dB ] = CSRC_B ; \ + m[dNE] = CSRC_NE; m[dNW] = CSRC_NW; m[dSE] = CSRC_SE; m[dSW] = CSRC_SW; \ + m[dNT] = CSRC_NT; m[dNB] = CSRC_NB; m[dST] = CSRC_ST; m[dSB] = CSRC_SB; \ + m[dET] = CSRC_ET; m[dEB] = CSRC_EB; m[dWT] = CSRC_WT; m[dWB] = CSRC_WB; \ + \ + rho = MSRC_C + MSRC_N + MSRC_S + MSRC_E + MSRC_W + MSRC_T \ + + MSRC_B + MSRC_NE + MSRC_NW + MSRC_SE + MSRC_SW + MSRC_NT \ + + MSRC_NB + MSRC_ST + MSRC_SB + MSRC_ET + MSRC_EB + MSRC_WT + MSRC_WB; \ + ux = MSRC_E - MSRC_W + MSRC_NE - MSRC_NW + MSRC_SE - MSRC_SW \ + + MSRC_ET + MSRC_EB - MSRC_WT - MSRC_WB; \ + uy = MSRC_N - MSRC_S + MSRC_NE + MSRC_NW - MSRC_SE - MSRC_SW \ + + MSRC_NT + MSRC_NB - MSRC_ST - MSRC_SB; \ + uz = MSRC_T - MSRC_B + MSRC_NT - MSRC_NB + MSRC_ST - MSRC_SB \ + + MSRC_ET - MSRC_EB + MSRC_WT - MSRC_WB; \ + PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLL_CALCULATE_DFEQ(lcsmeq); \ + COLL_CALCULATE_NONEQTENSOR(lev, MSRC_) \ + COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \ + CSMOMEGA_STATS(lev,lcsmomega); \ + \ + RAC(tcel,dC ) = (1.0-lcsmomega)*MSRC_C + lcsmomega*EQC ; \ + RAC(tcel,dN ) = (1.0-lcsmomega)*MSRC_N + lcsmomega*lcsmeq[ dN ]; \ + RAC(tcel,dS ) = (1.0-lcsmomega)*MSRC_S + lcsmomega*lcsmeq[ dS ]; \ + RAC(tcel,dE ) = (1.0-lcsmomega)*MSRC_E + lcsmomega*lcsmeq[ dE ]; \ + RAC(tcel,dW ) = (1.0-lcsmomega)*MSRC_W + lcsmomega*lcsmeq[ dW ]; \ + RAC(tcel,dT ) = (1.0-lcsmomega)*MSRC_T + lcsmomega*lcsmeq[ dT ]; \ + RAC(tcel,dB ) = (1.0-lcsmomega)*MSRC_B + lcsmomega*lcsmeq[ dB ]; \ + \ + RAC(tcel,dNE) = (1.0-lcsmomega)*MSRC_NE + lcsmomega*lcsmeq[ dNE]; \ + RAC(tcel,dNW) = (1.0-lcsmomega)*MSRC_NW + lcsmomega*lcsmeq[ dNW]; \ + RAC(tcel,dSE) = (1.0-lcsmomega)*MSRC_SE + lcsmomega*lcsmeq[ dSE]; \ + RAC(tcel,dSW) = (1.0-lcsmomega)*MSRC_SW + lcsmomega*lcsmeq[ dSW]; \ + \ + RAC(tcel,dNT) = (1.0-lcsmomega)*MSRC_NT + lcsmomega*lcsmeq[ dNT]; \ + RAC(tcel,dNB) = (1.0-lcsmomega)*MSRC_NB + lcsmomega*lcsmeq[ dNB]; \ + RAC(tcel,dST) = (1.0-lcsmomega)*MSRC_ST + lcsmomega*lcsmeq[ dST]; \ + RAC(tcel,dSB) = (1.0-lcsmomega)*MSRC_SB + lcsmomega*lcsmeq[ dSB]; \ + \ + RAC(tcel,dET) = (1.0-lcsmomega)*MSRC_ET + lcsmomega*lcsmeq[ dET]; \ + RAC(tcel,dEB) = (1.0-lcsmomega)*MSRC_EB + lcsmomega*lcsmeq[ dEB]; \ + RAC(tcel,dWT) = (1.0-lcsmomega)*MSRC_WT + lcsmomega*lcsmeq[ dWT]; \ + RAC(tcel,dWB) = (1.0-lcsmomega)*MSRC_WB + lcsmomega*lcsmeq[ dWB]; \ + + + +#define OPTIMIZED_STREAMCOLLIDE_UNUSED \ + \ + rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \ + + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \ + + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \ + ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \ + + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB; \ + uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \ + + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB; \ + uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \ + + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB; \ + PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + COLL_CALCULATE_DFEQ(lcsmeq); \ + COLL_CALCULATE_NONEQTENSOR(lev, CSRC_) \ + COLL_CALCULATE_CSMOMEGAVAL(lev, lcsmomega); \ + \ + RAC(tcel,dC ) = (1.0-lcsmomega)*CSRC_C + lcsmomega*EQC ; \ + RAC(tcel,dN ) = (1.0-lcsmomega)*CSRC_N + lcsmomega*lcsmeq[ dN ]; \ + RAC(tcel,dS ) = (1.0-lcsmomega)*CSRC_S + lcsmomega*lcsmeq[ dS ]; \ + RAC(tcel,dE ) = (1.0-lcsmomega)*CSRC_E + lcsmomega*lcsmeq[ dE ]; \ + RAC(tcel,dW ) = (1.0-lcsmomega)*CSRC_W + lcsmomega*lcsmeq[ dW ]; \ + RAC(tcel,dT ) = (1.0-lcsmomega)*CSRC_T + lcsmomega*lcsmeq[ dT ]; \ + RAC(tcel,dB ) = (1.0-lcsmomega)*CSRC_B + lcsmomega*lcsmeq[ dB ]; \ + \ + RAC(tcel,dNE) = (1.0-lcsmomega)*CSRC_NE + lcsmomega*lcsmeq[ dNE]; \ + RAC(tcel,dNW) = (1.0-lcsmomega)*CSRC_NW + lcsmomega*lcsmeq[ dNW]; \ + RAC(tcel,dSE) = (1.0-lcsmomega)*CSRC_SE + lcsmomega*lcsmeq[ dSE]; \ + RAC(tcel,dSW) = (1.0-lcsmomega)*CSRC_SW + lcsmomega*lcsmeq[ dSW]; \ + \ + RAC(tcel,dNT) = (1.0-lcsmomega)*CSRC_NT + lcsmomega*lcsmeq[ dNT]; \ + RAC(tcel,dNB) = (1.0-lcsmomega)*CSRC_NB + lcsmomega*lcsmeq[ dNB]; \ + RAC(tcel,dST) = (1.0-lcsmomega)*CSRC_ST + lcsmomega*lcsmeq[ dST]; \ + RAC(tcel,dSB) = (1.0-lcsmomega)*CSRC_SB + lcsmomega*lcsmeq[ dSB]; \ + \ + RAC(tcel,dET) = (1.0-lcsmomega)*CSRC_ET + lcsmomega*lcsmeq[ dET]; \ + RAC(tcel,dEB) = (1.0-lcsmomega)*CSRC_EB + lcsmomega*lcsmeq[ dEB]; \ + RAC(tcel,dWT) = (1.0-lcsmomega)*CSRC_WT + lcsmomega*lcsmeq[ dWT]; \ + RAC(tcel,dWB) = (1.0-lcsmomega)*CSRC_WB + lcsmomega*lcsmeq[ dWB]; \ + + + +#define OPTIMIZED_STREAMCOLLIDE_NOLES \ + \ + rho = CSRC_C + CSRC_N + CSRC_S + CSRC_E + CSRC_W + CSRC_T \ + + CSRC_B + CSRC_NE + CSRC_NW + CSRC_SE + CSRC_SW + CSRC_NT \ + + CSRC_NB + CSRC_ST + CSRC_SB + CSRC_ET + CSRC_EB + CSRC_WT + CSRC_WB; \ + ux = CSRC_E - CSRC_W + CSRC_NE - CSRC_NW + CSRC_SE - CSRC_SW \ + + CSRC_ET + CSRC_EB - CSRC_WT - CSRC_WB; \ + uy = CSRC_N - CSRC_S + CSRC_NE + CSRC_NW - CSRC_SE - CSRC_SW \ + + CSRC_NT + CSRC_NB - CSRC_ST - CSRC_SB; \ + uz = CSRC_T - CSRC_B + CSRC_NT - CSRC_NB + CSRC_ST - CSRC_SB \ + + CSRC_ET - CSRC_EB + CSRC_WT - CSRC_WB; \ + PRECOLLIDE_MODS(rho, ux,uy,uz, mLevel[lev].gravity); \ + usqr = 1.5 * (ux*ux + uy*uy + uz*uz); \ + RAC(tcel,dC ) = (1.0-OMEGA(lev))*CSRC_C + OMEGA(lev)*EQC ; \ + RAC(tcel,dN ) = (1.0-OMEGA(lev))*CSRC_N + OMEGA(lev)*EQN ; \ + RAC(tcel,dS ) = (1.0-OMEGA(lev))*CSRC_S + OMEGA(lev)*EQS ; \ + RAC(tcel,dE ) = (1.0-OMEGA(lev))*CSRC_E + OMEGA(lev)*EQE ; \ + RAC(tcel,dW ) = (1.0-OMEGA(lev))*CSRC_W + OMEGA(lev)*EQW ; \ + RAC(tcel,dT ) = (1.0-OMEGA(lev))*CSRC_T + OMEGA(lev)*EQT ; \ + RAC(tcel,dB ) = (1.0-OMEGA(lev))*CSRC_B + OMEGA(lev)*EQB ; \ + \ + RAC(tcel,dNE) = (1.0-OMEGA(lev))*CSRC_NE + OMEGA(lev)*EQNE; \ + RAC(tcel,dNW) = (1.0-OMEGA(lev))*CSRC_NW + OMEGA(lev)*EQNW; \ + RAC(tcel,dSE) = (1.0-OMEGA(lev))*CSRC_SE + OMEGA(lev)*EQSE; \ + RAC(tcel,dSW) = (1.0-OMEGA(lev))*CSRC_SW + OMEGA(lev)*EQSW; \ + \ + RAC(tcel,dNT) = (1.0-OMEGA(lev))*CSRC_NT + OMEGA(lev)*EQNT; \ + RAC(tcel,dNB) = (1.0-OMEGA(lev))*CSRC_NB + OMEGA(lev)*EQNB; \ + RAC(tcel,dST) = (1.0-OMEGA(lev))*CSRC_ST + OMEGA(lev)*EQST; \ + RAC(tcel,dSB) = (1.0-OMEGA(lev))*CSRC_SB + OMEGA(lev)*EQSB; \ + \ + RAC(tcel,dET) = (1.0-OMEGA(lev))*CSRC_ET + OMEGA(lev)*EQET; \ + RAC(tcel,dEB) = (1.0-OMEGA(lev))*CSRC_EB + OMEGA(lev)*EQEB; \ + RAC(tcel,dWT) = (1.0-OMEGA(lev))*CSRC_WT + OMEGA(lev)*EQWT; \ + RAC(tcel,dWB) = (1.0-OMEGA(lev))*CSRC_WB + OMEGA(lev)*EQWB; \ + + + + + +// LES switching for OPT3D +#if USE_LES==1 +#define DEFAULT_COLLIDEG(grav) DEFAULT_COLLIDE_LES(grav) +#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_LES +#else +#define DEFAULT_COLLIDEG(grav) DEFAULT_COLLIDE_NOLES(grav) +#define OPTIMIZED_STREAMCOLLIDE OPTIMIZED_STREAMCOLLIDE_NOLES +#endif + +#endif // 3D, opt OPT3D==true + +#define USQRMAXCHECK(Cusqr,Cux,Cuy,Cuz, CmMaxVlen,CmMxvx,CmMxvy,CmMxvz) \ + if(Cusqr>CmMaxVlen) { \ + CmMxvx = Cux; CmMxvy = Cuy; CmMxvz = Cuz; CmMaxVlen = Cusqr; \ + } /* stats */ + + + +/****************************************************************************** + * interpolateCellFromCoarse macros + *****************************************************************************/ + + +// WOXDY_N = Weight Order X Dimension Y _ number N +#define WO1D1 ( 1.0/ 2.0) +#define WO1D2 ( 1.0/ 4.0) +#define WO1D3 ( 1.0/ 8.0) + +#define WO2D1_1 (-1.0/16.0) +#define WO2D1_9 ( 9.0/16.0) + +#define WO2D2_11 (WO2D1_1 * WO2D1_1) +#define WO2D2_19 (WO2D1_9 * WO2D1_1) +#define WO2D2_91 (WO2D1_9 * WO2D1_1) +#define WO2D2_99 (WO2D1_9 * WO2D1_9) + +#define WO2D3_111 (WO2D1_1 * WO2D1_1 * WO2D1_1) +#define WO2D3_191 (WO2D1_9 * WO2D1_1 * WO2D1_1) +#define WO2D3_911 (WO2D1_9 * WO2D1_1 * WO2D1_1) +#define WO2D3_991 (WO2D1_9 * WO2D1_9 * WO2D1_1) +#define WO2D3_119 (WO2D1_1 * WO2D1_1 * WO2D1_9) +#define WO2D3_199 (WO2D1_9 * WO2D1_1 * WO2D1_9) +#define WO2D3_919 (WO2D1_9 * WO2D1_1 * WO2D1_9) +#define WO2D3_999 (WO2D1_9 * WO2D1_9 * WO2D1_9) + +#if FSGR_STRICT_DEBUG==1 +#define ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l) \ + if( (((1.0-(at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l) > -1.0 ))) || \ + ((( (at))>0.0) && (!(QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l) > -1.0 ))) ){ \ + errMsg("INVDFSCHECK", " l"<<(alev)<<" "<0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr )&(CFInter|CFFluid|CFGrCoarseInited) ))) || \ + ((( (at))>0.0) && (!(RFLAG((alev), (ai),(aj),(ak),mLevel[(alev)].setOther)&(CFInter|CFFluid|CFGrCoarseInited) ))) ){ \ + errMsg("INVFLAGCINTCHECK", " l"<<(alev)<<" at:"<<(at)<<" "<mPanic) { errMsg("interpolateCellFromCoarse", "ICFC_DFOUT cell "< only current +// t=0.5 -> mix +// t=1.0 -> only other +#if OPT3D==0 +#define ADD_INT_DFS(alev, ai,aj,ak, at, afac) \ + ADD_INT_FLAGCHECK(alev, ai,aj,ak, at, afac); \ + FORDF0{ \ + LbmFloat df = ( \ + QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setCurr , l)*(1.0-(at)) + \ + QCELL((alev), (ai),(aj),(ak),mLevel[(alev)].setOther, l)*( (at)) \ + ) ; \ + ADD_INT_DFSCHECK(alev, ai,aj,ak, at, afac, l); \ + df *= (afac); \ + rho += df; \ + ux += (this->dfDvecX[l]*df); \ + uy += (this->dfDvecY[l]*df); \ + uz += (this->dfDvecZ[l]*df); \ + intDf[l] += df; \ + } +// write interpolated dfs back to cell (correct non-eq. parts) +#define IDF_WRITEBACK_ \ + FORDF0{ \ + LbmFloat eq = getCollideEq(l, rho,ux,uy,uz);\ + QCELL(lev,i,j,k, dstSet, l) = (eq+ (intDf[l]-eq)*mDfScaleDown);\ + } \ + /* check that all values are ok */ \ + INTDEBOUT +#define IDF_WRITEBACK \ + LbmFloat omegaDst, omegaSrc;\ + /* smago new */ \ + LbmFloat feq[LBM_DFNUM]; \ + LbmFloat dfScale = mDfScaleDown; \ + FORDF0{ \ + feq[l] = getCollideEq(l, rho,ux,uy,uz); \ + } \ + if(mLevel[lev ].lcsmago>0.0) {\ + LbmFloat Qo = this->getLesNoneqTensorCoeff(intDf,feq); \ + omegaDst = this->getLesOmega(mLevel[lev+0].omega,mLevel[lev+0].lcsmago,Qo); \ + omegaSrc = this->getLesOmega(mLevel[lev-1].omega,mLevel[lev-1].lcsmago,Qo); \ + } else {\ + omegaDst = mLevel[lev+0].omega; \ + omegaSrc = mLevel[lev-1].omega;\ + } \ + \ + dfScale = (mLevel[lev+0].timestep/mLevel[lev-1].timestep)* (1.0/omegaDst-1.0)/ (1.0/omegaSrc-1.0); \ + FORDF0{ \ + /*errMsg("SMAGO"," org"<cDfNum; l++) { + if(this->lesCoeffOffdiag[m][l]==0.0) continue; + qadd += this->lesCoeffOffdiag[m][l]*(df[l]-feq[l]); + } + Qo += (qadd*qadd); + } + Qo *= 2.0; // off diag twice + for(int m=0; mcDfNum; l++) { + if(this->lesCoeffDiag[m][l]==0.0) continue; + qadd += this->lesCoeffDiag[m][l]*(df[l]-feq[l]); + } + Qo += (qadd*qadd); + } + Qo = sqrt(Qo); + return Qo; +}; + +inline LbmFloat LbmFsgrSolver::getLesOmega(LbmFloat omega, LbmFloat csmago, LbmFloat Qo) { + const LbmFloat tau = 1.0/omega; + const LbmFloat nu = (2.0*tau-1.0) * (1.0/6.0); + const LbmFloat C = csmago; + const LbmFloat Csqr = C*C; + LbmFloat S = -nu + sqrt( nu*nu + 18.0*Csqr*Qo ) / (6.0*Csqr); + return( 1.0/( 3.0*( nu+Csqr*S ) +0.5 ) ); +} + +#define DEBUG_CALCPRINTCELL(str,df) {\ + LbmFloat prho=df[0], pux=0., puy=0., puz=0.; \ + for(int dfl=1; dflcDfNum; dfl++) { \ + prho += df[dfl]; \ + pux += (this->dfDvecX[dfl]*df[dfl]); \ + puy += (this->dfDvecY[dfl]*df[dfl]); \ + puz += (this->dfDvecZ[dfl]*df[dfl]); \ + } \ + errMsg("DEBUG_CALCPRINTCELL",">"<cDfNum; l++) { + rho += df[l]; + ux += (this->dfDvecX[l]*df[l]); + uy += (this->dfDvecY[l]*df[l]); + uz += (this->dfDvecZ[l]*df[l]); + } + + + PRECOLLIDE_MODS(rho,ux,uy,uz, gravity); + for(l=0; lcDfNum; l++) { + feq[l] = getCollideEq(l,rho,ux,uy,uz); + } + + if(csmago>0.0) { + Qo = getLesNoneqTensorCoeff(df,feq); + omegaNew = getLesOmega(omega,csmago,Qo); + } else { + omegaNew = omega; // smago off... + } + if(newOmegaRet) *newOmegaRet = omegaNew; // return value for stats + if(newQoRet) *newQoRet = Qo; // return value of non-eq. stress tensor + + for(l=0; lcDfNum; l++) { + df[l] = (1.0-omegaNew ) * df[l] + omegaNew * feq[l]; + } + //if((i==16)&&(j==10)) DEBUG_CALCPRINTCELL( "2dcoll "< /* rand(3) */ + +#include +#ifndef sqrtf +#define sqrtf sqrt +#endif + +/****************************************************************************** + * helper functions + *****************************************************************************/ + +// try to enhance surface? +#define SURFACE_ENH 2 + +extern bool glob_mpactive; +extern bool glob_mpnum; +extern bool glob_mpindex; + +//! for raytracing +void LbmFsgrSolver::prepareVisualization( void ) { + int lev = mMaxRefine; + int workSet = mLevel[lev].setCurr; + + int mainGravDir=0; + LbmFloat mainGravLen = 0.; + FORDF1{ + LbmFloat thisGravLen = dot(LbmVec(dfVecX[l],dfVecY[l],dfVecZ[l]), getNormalized(mLevel[mMaxRefine].gravity) ); + if(thisGravLen>mainGravLen) { + mainGravLen = thisGravLen; + mainGravDir = l; + } + } + +#if LBMDIM==2 + // 2d, place in the middle of isofield slice (k=2) +# define ZKD1 0 + // 2d z offset = 2, lbmGetData adds 1, so use one here +# define ZKOFF 1 + // reset all values... + for(int k= 0; k< 5; ++k) + for(int j=0;jlbmGetData(i,j,ZKOFF)=0.0; + } +#else // LBMDIM==2 + // 3d, use normal bounds +# define ZKD1 1 +# define ZKOFF k + // reset all values... + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int j=0;jlbmGetData(i,j,ZKOFF)=0.0; + } +#endif // LBMDIM==2 + + // MPT, ignore + if((glob_mpactive) && (glob_mpnum>1) && (glob_mpindex==0)) { + mpIso->resetAll(0.); + } + + + LbmFloat minval = mIsoValue*1.05; // / mIsoWeight[13]; + // add up... + float val = 0.0; + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) + for(int j=1;j6)) { + *mpIso->lbmGetData(i,j,ZKOFF) += minval; + } else if((noslipbnd)&&(intercnt>0)) { + // necessary? + *mpIso->lbmGetData(i,j,ZKOFF) += mIsoValue*0.9; + } else { + // nothing to do... + } + + continue; + } else if(cflag&(CFNoNbEmpty|CFFluid)) { + // no empty nb interface cells are treated as full + val=1.0; + } else { + val = (QCELL(lev, i,j,k,workSet, dFfrac)); + } + + if(noslipbnd) { + if(vallbmGetData(i,j,ZKOFF) += minval-( val * mIsoWeight[13] ); + } +#endif // SURFACE_ENH>0 + + } else { // all others, unused? + continue; + } + + *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[0] ); + *mpIso->lbmGetData( i , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[1] ); + *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[2] ); + + *mpIso->lbmGetData( i-1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[3] ); + *mpIso->lbmGetData( i , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[4] ); + *mpIso->lbmGetData( i+1 , j ,ZKOFF-ZKD1) += ( val * mIsoWeight[5] ); + + *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[6] ); + *mpIso->lbmGetData( i , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[7] ); + *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF-ZKD1) += ( val * mIsoWeight[8] ); + + + *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[9] ); + *mpIso->lbmGetData( i , j-1 ,ZKOFF ) += ( val * mIsoWeight[10] ); + *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF ) += ( val * mIsoWeight[11] ); + + *mpIso->lbmGetData( i-1 , j ,ZKOFF ) += ( val * mIsoWeight[12] ); + *mpIso->lbmGetData( i , j ,ZKOFF ) += ( val * mIsoWeight[13] ); + *mpIso->lbmGetData( i+1 , j ,ZKOFF ) += ( val * mIsoWeight[14] ); + + *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[15] ); + *mpIso->lbmGetData( i , j+1 ,ZKOFF ) += ( val * mIsoWeight[16] ); + *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF ) += ( val * mIsoWeight[17] ); + + + *mpIso->lbmGetData( i-1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[18] ); + *mpIso->lbmGetData( i , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[19] ); + *mpIso->lbmGetData( i+1 , j-1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[20] ); + + *mpIso->lbmGetData( i-1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[21] ); + *mpIso->lbmGetData( i , j ,ZKOFF+ZKD1)+= ( val * mIsoWeight[22] ); + *mpIso->lbmGetData( i+1 , j ,ZKOFF+ZKD1) += ( val * mIsoWeight[23] ); + + *mpIso->lbmGetData( i-1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[24] ); + *mpIso->lbmGetData( i , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[25] ); + *mpIso->lbmGetData( i+1 , j+1 ,ZKOFF+ZKD1) += ( val * mIsoWeight[26] ); + } + + // TEST!? +#if SURFACE_ENH>=2 + + if(mFsSurfGenSetting&fssgNoObs) { + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) + for(int j=1;j=mLevel[mMaxRefine].lSizex) + //|| (nj>=mLevel[mMaxRefine].lSizey) + //|| (nk>=mLevel[mMaxRefine].lSizez) ) continue; + } + + if(nbored&CFInter) { + if(avgfcnt>0.) avgfill/=avgfcnt; + *mpIso->lbmGetData(i,j,ZKOFF) = avgfill; continue; + } + else if(nbored&CFFluid) { + *mpIso->lbmGetData(i,j,ZKOFF) = 1.; continue; + } + + } + } + + // move surface towards inner "row" of obstacle + // cells if necessary (all obs cells without fluid/inter + // nbs (=iso==0) next to obstacles...) + for(int k= getForZMin1(); k< getForZMax1(lev); ++k) + for(int j=1;jlbmGetData(i,j,ZKOFF)==0.)) { + int bndnbcnt=0; + FORDF1 { + const int ni = i+dfVecX[l]; + const int nj = j+dfVecY[l]; + const int nk = ZKOFF+dfVecZ[l]; + const CellFlagType nbflag = RFLAG(lev, ni,nj,nk, workSet); + if(nbflag&CFBnd) bndnbcnt++; + } + if(bndnbcnt>0) *mpIso->lbmGetData(i,j,ZKOFF)=mIsoValue*0.95; + } + } + } + // */ + + if(mFsSurfGenSetting&fssgNoNorth) + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int j=0;jlbmGetData(0, j,ZKOFF) = *mpIso->lbmGetData(1, j,ZKOFF); + } + if(mFsSurfGenSetting&fssgNoEast) + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int i=0;ilbmGetData(i,0, ZKOFF) = *mpIso->lbmGetData(i,1, ZKOFF); + } + if(mFsSurfGenSetting&fssgNoSouth) + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int j=0;jlbmGetData(mLevel[lev].lSizex-1,j,ZKOFF) = *mpIso->lbmGetData(mLevel[lev].lSizex-2,j,ZKOFF); + } + if(mFsSurfGenSetting&fssgNoWest) + for(int k= getForZMinBnd(); k< getForZMaxBnd(lev); ++k) + for(int i=0;ilbmGetData(i,mLevel[lev].lSizey-1,ZKOFF) = *mpIso->lbmGetData(i,mLevel[lev].lSizey-2,ZKOFF); + } + if(LBMDIM>2) { + if(mFsSurfGenSetting&fssgNoBottom) + for(int j=0;jlbmGetData(i,j,0 ) = *mpIso->lbmGetData(i,j,1 ); + } + if(mFsSurfGenSetting&fssgNoTop) + for(int j=0;jlbmGetData(i,j,mLevel[lev].lSizez-1) = *mpIso->lbmGetData(i,j,mLevel[lev].lSizez-2); + } + } +#endif // SURFACE_ENH>=2 + + + // update preview, remove 2d? + if((mOutputSurfacePreview)&&(LBMDIM==3)) { + int pvsx = (int)(mPreviewFactor*mSizex); + int pvsy = (int)(mPreviewFactor*mSizey); + int pvsz = (int)(mPreviewFactor*mSizez); + //float scale = (float)mSizex / previewSize; + LbmFloat scalex = (LbmFloat)mSizex/(LbmFloat)pvsx; + LbmFloat scaley = (LbmFloat)mSizey/(LbmFloat)pvsy; + LbmFloat scalez = (LbmFloat)mSizez/(LbmFloat)pvsz; + for(int k= 0; k< (pvsz-1); ++k) + for(int j=0;j< pvsy;j++) + for(int i=0;i< pvsx;i++) { + *mpPreviewSurface->lbmGetData(i,j,k) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley), (int)(k*scalez) ); + } + // set borders again... + for(int k= 0; k< (pvsz-1); ++k) { + for(int j=0;j< pvsy;j++) { + *mpPreviewSurface->lbmGetData(0,j,k) = *mpIso->lbmGetData( 0, (int)(j*scaley), (int)(k*scalez) ); + *mpPreviewSurface->lbmGetData(pvsx-1,j,k) = *mpIso->lbmGetData( mSizex-1, (int)(j*scaley), (int)(k*scalez) ); + } + for(int i=0;i< pvsx;i++) { + *mpPreviewSurface->lbmGetData(i,0,k) = *mpIso->lbmGetData( (int)(i*scalex), 0, (int)(k*scalez) ); + *mpPreviewSurface->lbmGetData(i,pvsy-1,k) = *mpIso->lbmGetData( (int)(i*scalex), mSizey-1, (int)(k*scalez) ); + } + } + for(int j=0;jlbmGetData(i,j,0) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , 0); + *mpPreviewSurface->lbmGetData(i,j,pvsz-1) = *mpIso->lbmGetData( (int)(i*scalex), (int)(j*scaley) , mSizez-1); + } + + if(mFarFieldSize>=1.2) { + // also remove preview border + for(int k= 0; k< (pvsz-1); ++k) { + for(int j=0;j< pvsy;j++) { + *mpPreviewSurface->lbmGetData(0,j,k) = + *mpPreviewSurface->lbmGetData(1,j,k) = + *mpPreviewSurface->lbmGetData(2,j,k); + *mpPreviewSurface->lbmGetData(pvsx-1,j,k) = + *mpPreviewSurface->lbmGetData(pvsx-2,j,k) = + *mpPreviewSurface->lbmGetData(pvsx-3,j,k); + //0.0; + } + for(int i=0;i< pvsx;i++) { + *mpPreviewSurface->lbmGetData(i,0,k) = + *mpPreviewSurface->lbmGetData(i,1,k) = + *mpPreviewSurface->lbmGetData(i,2,k); + *mpPreviewSurface->lbmGetData(i,pvsy-1,k) = + *mpPreviewSurface->lbmGetData(i,pvsy-2,k) = + *mpPreviewSurface->lbmGetData(i,pvsy-3,k); + //0.0; + } + } + for(int j=0;jlbmGetData(i,j,0) = + *mpPreviewSurface->lbmGetData(i,j,1) = + *mpPreviewSurface->lbmGetData(i,j,2); + *mpPreviewSurface->lbmGetData(i,j,pvsz-1) = + *mpPreviewSurface->lbmGetData(i,j,pvsz-2) = + *mpPreviewSurface->lbmGetData(i,j,pvsz-3); + //0.0; + } + } + } + + // MPT + #if LBM_INCLUDE_TESTSOLVERS==1 + mrIsoExchange(); + #endif // LBM_INCLUDE_TESTSOLVERS==1 + + return; +} + +/*! calculate speeds of fluid objects (or inflow) */ +void LbmFsgrSolver::recalculateObjectSpeeds() { + const bool debugRecalc = false; + int numobjs = (int)(this->mpGiObjects->size()); + // note - (numobjs + 1) is entry for domain settings + + if(debugRecalc) errMsg("recalculateObjectSpeeds","start, #obj:"<255-1) { + errFatal("LbmFsgrSolver::recalculateObjectSpeeds","More than 256 objects currently not supported...",SIMWORLD_INITERROR); + return; + } + mObjectSpeeds.resize(numobjs+1); + for(int i=0; i<(int)(numobjs+0); i++) { + mObjectSpeeds[i] = vec2L(this->mpParam->calculateLattVelocityFromRw( vec2P( (*this->mpGiObjects)[i]->getInitialVelocity(mSimulationTime) ))); + if(debugRecalc) errMsg("recalculateObjectSpeeds","id"<mpGiObjects)[i]->getInitialVelocity(mSimulationTime) ); + } + + // also reinit part slip values here + mObjectPartslips.resize(numobjs+1); + for(int i=0; i<=(int)(numobjs+0); i++) { + if(impGiObjects)[i]->getGeoPartSlipValue(); + } else { + // domain setting + mObjectPartslips[i] = this->mDomainPartSlipValue; + } + LbmFloat set = mObjectPartslips[i]; + + // as in setInfluenceVelocity + const LbmFloat dt = mLevel[mMaxRefine].timestep; + const LbmFloat dtInter = 0.01; + //LbmFloat facFv = 1.-set; + // mLevel[mMaxRefine].timestep + LbmFloat facNv = (LbmFloat)( 1.-pow( (double)(set), (double)(dt/dtInter)) ); + errMsg("mObjectPartslips","id:"< LbmFsgrSolver::getDebugObjects() { + vector debo; + if(this->mOutputSurfacePreview) { + debo.push_back( mpPreviewSurface ); + } +#if LBM_INCLUDE_TESTSOLVERS==1 + if(mUseTestdata) { + vector tdebo; + tdebo = mpTest->getDebugObjects(); + for(size_t i=0; isetStart( this->mvGeoStart + ntlVec3Gfx(mLevel[mMaxRefine].nodeSize*0.5) ); + partt->setEnd ( this->mvGeoEnd + ntlVec3Gfx(mLevel[mMaxRefine].nodeSize*0.5) ); + + partt->setSimStart( ntlVec3Gfx(0.0) ); + partt->setSimEnd ( ntlVec3Gfx(mSizex, mSizey, getForZMaxBnd(mMaxRefine)) ); + + while( (numgetNumInitialParticles()) && (tries<100*partt->getNumInitialParticles()) ) { + LbmFloat x,y,z,t; + x = 1.0+(( (LbmFloat)(mSizex-3.) ) * (rand()/(RAND_MAX+1.0)) ); + y = 1.0+(( (LbmFloat)(mSizey-3.) ) * (rand()/(RAND_MAX+1.0)) ); + z = 1.0+(( (LbmFloat) getForZMax1(mMaxRefine)-2. )* (rand()/(RAND_MAX+1.0)) ); + int i = (int)(x+0.5); + int j = (int)(y+0.5); + int k = (int)(z+0.5); + if(LBMDIM==2) { + k = 0; z = 0.5; // place in the middle of domain + } + + //if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFFluid) ) + //&& ( RFLAG(mMaxRefine, i,j,k, workSet)& CFNoNbFluid ) + //if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFFluid|CFInter|CFMbndInflow) ) { + if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFNoBndFluid|CFUnused) ) { + bool cellOk = true; + //? FORDF1 { if(!(RFLAG_NB(mMaxRefine,i,j,k,workSet, l) & CFFluid)) cellOk = false; } + if(!cellOk) continue; + // in fluid... + partt->addParticle(x,y,z); + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_TRACER); + + partt->getLast()->setSize(1.); + // randomize size + partt->getLast()->setSize(0.5 + (rand()/(RAND_MAX+1.0))); + + if( ( partt->getInitStart()>0.) + && ( partt->getInitEnd()>0.) + && ( partt->getInitEnd()>partt->getInitStart() )) { + t = partt->getInitStart()+ (partt->getInitEnd()-partt->getInitStart())*(rand()/(RAND_MAX+1.0)); + partt->getLast()->setLifeTime( -t ); + } + num++; + } + tries++; + } // */ + + /*FSGR_FORIJK1(mMaxRefine) { + if( (RFLAG(mMaxRefine,i,j,k, workSet) & (CFNoBndFluid)) ) { + LbmFloat rndn = (rand()/(RAND_MAX+1.0)); + if(rndn>0.0) { + ntlVec3Gfx pos( (LbmFloat)(i)-0.5, (LbmFloat)(j)-0.5, (LbmFloat)(k)-0.5 ); + if(LBMDIM==2) { pos[2]=0.5; } + partt->addParticle( pos[0],pos[1],pos[2] ); + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_TRACER); + partt->getLast()->setSize(1.0); + } + } + } // */ + + + // DEBUG TEST +#if LBM_INCLUDE_TESTSOLVERS==1 + if(mUseTestdata) { + const bool partDebug=false; + if(mpTest->mPartTestcase==0){ errMsg("LbmTestdata"," part init "<mPartTestcase); } + if(mpTest->mPartTestcase==-12){ + const int lev = mMaxRefine; + for(int i=5;i<15;i++) { + LbmFloat x,y,z; + y = 0.5+(LbmFloat)(i); + x = mLevel[lev].lSizex/20.0*10.0; + z = mLevel[lev].lSizez/20.0*2.0; + partt->addParticle(x,y,z); + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_BUBBLE); + partt->getLast()->setSize( (-4.0+(LbmFloat)i)/1.0 ); + if(partDebug) errMsg("PARTTT","SET "<getLast()->getPos() <<" s"<getLast()->getSize() ); + } + } + if(mpTest->mPartTestcase==-11){ + const int lev = mMaxRefine; + for(int i=5;i<15;i++) { + LbmFloat x,y,z; + y = 10.5+(LbmFloat)(i); + x = mLevel[lev].lSizex/20.0*10.0; + z = mLevel[lev].lSizez/20.0*40.0; + partt->addParticle(x,y,z); + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_DROP); + partt->getLast()->setSize( (-4.0+(LbmFloat)i)/1.0 ); + if(partDebug) errMsg("PARTTT","SET "<getLast()->getPos() <<" s"<getLast()->getSize() ); + } + } + // place floats on rectangular region FLOAT_JITTER_BND + if(mpTest->mPartTestcase==-10){ + const int lev = mMaxRefine; + const int sx = mLevel[lev].lSizex; + const int sy = mLevel[lev].lSizey; + //for(int j=-(int)(sy*0.25);j<-(int)(sy*0.25)+2;++j) { for(int i=-(int)(sx*0.25);i<-(int)(sy*0.25)+2;++i) { + //for(int j=-(int)(sy*1.25);j<(int)(2.25*sy);++j) { for(int i=-(int)(sx*1.25);i<(int)(2.25*sx);++i) { + for(int j=-(int)(sy*0.3);j<(int)(1.3*sy);++j) { for(int i=-(int)(sx*0.3);i<(int)(1.3*sx);++i) { + //for(int j=-(int)(sy*0.2);j<(int)(0.2*sy);++j) { for(int i= (int)(sx*0.5);i<= (int)(0.51*sx);++i) { + LbmFloat x,y,z; + x = 0.0+(LbmFloat)(i); + y = 0.0+(LbmFloat)(j); + //z = mLevel[lev].lSizez/10.0*2.5 - 1.0; + z = mLevel[lev].lSizez/20.0*9.5 - 1.0; + //z = mLevel[lev].lSizez/20.0*4.5 - 1.0; + partt->addParticle(x,y,z); + //if( (i>0)&&(i0)&&(jgetLast()->setStatus(PART_IN); } else { partt->getLast()->setStatus(PART_OUT); } + partt->getLast()->setStatus(PART_IN); + partt->getLast()->setType(PART_FLOAT); + partt->getLast()->setSize( 15.0 ); + if(partDebug) errMsg("PARTTT","SET "<getLast()->getPos() <<" s"<getLast()->getSize() ); + } + } } + } + // DEBUG TEST +#endif // LBM_INCLUDE_TESTSOLVERS + + + debMsgStd("LbmFsgrSolver::initParticles",DM_MSG,"Added "<mPartGenProb<<", tries:"<getNumParticles()) return 1; + + return 0; +} + +// helper function for particle debugging +/*static string getParticleStatusString(int state) { + std::ostringstream out; + if(state&PART_DROP) out << "dropp "; + if(state&PART_TRACER) out << "tracr "; + if(state&PART_BUBBLE) out << "bubbl "; + if(state&PART_FLOAT) out << "float "; + if(state&PART_INTER) out << "inter "; + + if(state&PART_IN) out << "inn "; + if(state&PART_OUT) out << "out "; + if(state&PART_INACTIVE) out << "INACT "; + if(state&PART_OUTFLUID) out << "outfluid "; + return out.str(); +} // */ + +#define P_CHANGETYPE(p, newtype) \ + p->setLifeTime(0.); \ + /* errMsg("PIT","U pit"<<(p)->getId()<<" pos:"<< (p)->getPos()<<" status:"<getFlags())<<" to "<< (newtype) ); */ \ + p->setType(newtype); + +// tracer defines +#define TRACE_JITTER 0.025 +#define TRACE_RAND (rand()/(RAND_MAX+1.0))*TRACE_JITTER-(TRACE_JITTER*0.5) +#define FFGET_NORM(var,dl) \ + if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFInter)){ (var) = QCELL_NB(lev,i,j,k,workSet,dl,dFfrac); } \ + else if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFFluid|CFUnused)){ (var) = 1.; } else (var) = 0.0; + +// float jitter +#define FLOAT_JITTER_BND (FLOAT_JITTER*2.0) +#define FLOAT_JITTBNDRAND(x) ((rand()/(RAND_MAX+1.0))*FLOAT_JITTER_BND*(1.-(x/(LbmFloat)maxdw))-(FLOAT_JITTER_BND*(1.-(x)/(LbmFloat)maxdw)*0.5)) + +#define DEL_PART { \ + /*errMsg("PIT","DEL AT "<< __LINE__<<" type:"<getType()<<" "); */ \ + p->setActive( false ); \ + continue; } + +void LbmFsgrSolver::advanceParticles() { + const int level = mMaxRefine; + const int workSet = mLevel[level].setCurr; + LbmFloat vx=0.0,vy=0.0,vz=0.0; + //int debugOutCounter=0; // debug output counter + + myTime_t parttstart = getTime(); + const LbmFloat cellsize = this->mpParam->getCellSize(); + const LbmFloat timestep = this->mpParam->getTimestep(); + //const LbmFloat viscAir = 1.79 * 1e-5; // RW2L kin. viscosity, mu + //const LbmFloat viscWater = 1.0 * 1e-6; // RW2L kin. viscosity, mu + const LbmFloat rhoAir = 1.2; // [kg m^-3] RW2L + const LbmFloat rhoWater = 1000.0; // RW2L + const LbmFloat minDropSize = 0.0005; // [m], = 2mm RW2L + const LbmVec velAir(0.); // [m / s] + + const LbmFloat r1 = 0.005; // r max + const LbmFloat r2 = 0.0005; // r min + const LbmFloat v1 = 9.0; // v max + const LbmFloat v2 = 2.0; // v min + const LbmVec rwgrav = vec2L( this->mpParam->getGravity(mSimulationTime) ); + const bool useff = (mFarFieldSize>1.2); // if(mpTest->mFarfMode>0){ + + // TODO scale bubble/part damping dep. on timestep, also drop bnd rev damping + const int cutval = mCutoff; // use full border!? + if(this->mStepCnt%50==49) { mpParticles->cleanup(); } + for(vector::iterator pit= mpParticles->getParticlesBegin(); + pit!= mpParticles->getParticlesEnd(); pit++) { + //if((*pit).getPos()[2]>10.) errMsg("PIT"," pit"<<(*pit).getId()<<" pos:"<< (*pit).getPos()<<" status:["<getLifeTime()<0.){ + if(p->getLifeTime() < -mSimulationTime) continue; + else p->setLifeTime(-mLevel[level].timestep); // zero for following update + } + int i,j,k; + p->setLifeTime(p->getLifeTime()+mLevel[level].timestep); + + // nearest neighbor, particle positions don't include empty bounds + ntlVec3Gfx pos = p->getPos(); + i= (int)pos[0]; j= (int)pos[1]; k= (int)pos[2];// no offset necessary + if(LBMDIM==2) { k = 0; } + + // only testdata handling, all for sws +#if LBM_INCLUDE_TESTSOLVERS==1 + if(useff && (mpTest->mFarfMode>0)) { + p->setStatus(PART_OUT); + mpTest->handleParticle(p, i,j,k); continue; + } +#endif // LBM_INCLUDE_TESTSOLVERS==1 + + // in out tests + if(p->getStatus()&PART_IN) { // IN + if( (imSizex-1-cutval)|| + (jmSizey-1-cutval) + //||(kmSizez-1-cutval) + ) { + if(!useff) { DEL_PART; + } else { + p->setStatus(PART_OUT); + } + } + } else { // OUT rough check + // check in again? + if( (i>=cutval)&&(i<=mSizex-1-cutval)&& + (j>=cutval)&&(j<=mSizey-1-cutval) + ) { + p->setStatus(PART_IN); + } + } + + if( (p->getType()==PART_BUBBLE) || + (p->getType()==PART_TRACER) ) { + + // no interpol + vx = vy = vz = 0.0; + if(p->getStatus()&PART_IN) { // IN + if(k>=cutval) { + if(k>mSizez-1-cutval) DEL_PART; + + if( RFLAG(level, i,j,k, workSet)&(CFFluid|CFUnused) ) { + // still ok + int partLev = level; + int si=i, sj=j, sk=k; + while(partLev>0 && RFLAG(partLev, si,sj,sk, workSet)&(CFUnused)) { + partLev--; + si/=2; + sj/=2; + sk/=2; + } + // get velocity from fluid cell + if( RFLAG(partLev, si,sj,sk, workSet)&(CFFluid) ) { + LbmFloat *ccel = RACPNT(partLev, si,sj,sk, workSet); + FORDF1{ + LbmFloat cdf = RAC(ccel, l); + // TODO update below + vx += (this->dfDvecX[l]*cdf); + vy += (this->dfDvecY[l]*cdf); + vz += (this->dfDvecZ[l]*cdf); + } + // remove gravity influence + const LbmFloat lesomega = mLevel[level].omega; // no les + vx -= mLevel[level].gravity[0] * lesomega*0.5; + vy -= mLevel[level].gravity[1] * lesomega*0.5; + vz -= mLevel[level].gravity[2] * lesomega*0.5; + } // fluid vel + + } else { // OUT + // out of bounds, deactivate... + // FIXME make fsgr treatment + if(p->getType()==PART_BUBBLE) { P_CHANGETYPE(p, PART_FLOAT ); continue; } + } + } else { + // below 3d region, just rise + } + } else { // OUT +# if LBM_INCLUDE_TESTSOLVERS==1 + if(useff) { mpTest->handleParticle(p, i,j,k); } + else DEL_PART; +# else // LBM_INCLUDE_TESTSOLVERS==1 + DEL_PART; +# endif // LBM_INCLUDE_TESTSOLVERS==1 + // TODO use x,y vel...? + } + + ntlVec3Gfx v = p->getVel(); // dampen... + if( (useff)&& (p->getType()==PART_BUBBLE) ) { + // test rise + + if(mPartUsePhysModel) { + LbmFloat radius = p->getSize() * minDropSize; + LbmVec velPart = vec2L(p->getVel()) *cellsize/timestep; // L2RW, lattice velocity + LbmVec velWater = LbmVec(vx,vy,vz) *cellsize/timestep;// L2RW, fluid velocity + LbmVec velRel = velWater - velPart; + //LbmFloat velRelNorm = norm(velRel); + LbmFloat pvolume = rhoAir * 4.0/3.0 * M_PI* radius*radius*radius; // volume: 4/3 pi r^3 + + LbmVec fb = -rwgrav* pvolume *rhoWater; + LbmVec fd = velRel*6.0*M_PI*radius* (1e-3); //viscWater; + LbmVec change = (fb+fd) *10.0*timestep *(timestep/cellsize); + /*if(debugOutCounter<0) { + errMsg("PIT","BTEST1 vol="<getVel())) * 6.0*M_PI*radius* (1e-3); //viscWater; + LbmFloat w = 0.99; + vz = (1.0-w)*vz + w*(p->getVel()[2]-0.5*(p->getSize()/5.0)*mLevel[level].gravity[2]); + v = ntlVec3Gfx(vx,vy,vz)+vec2G(fd2); + p->setVel( v ); + } else { + // non phys, half old, half fluid, use slightly slower acc + v = v*0.5 + ntlVec3Gfx(vx,vy,vz)* 0.5-vec2G(mLevel[level].gravity)*0.5; + p->setVel( v * 0.99 ); + } + p->advanceVel(); + + } else if(p->getType()==PART_TRACER) { + v = ntlVec3Gfx(vx,vy,vz); + CellFlagType fflag = RFLAG(level, i,j,k, workSet); + + if(fflag&(CFFluid|CFInter) ) { p->setInFluid(true); + } else { p->setInFluid(false); } + + if( (( fflag&CFFluid ) && ( fflag&CFNoBndFluid )) || + (( fflag&CFInter ) && (!(fflag&CFNoNbFluid)) ) ) { + // only real fluid +# if LBMDIM==3 + p->advance( TRACE_RAND,TRACE_RAND,TRACE_RAND); +# else + p->advance( TRACE_RAND,TRACE_RAND, 0.); +# endif + + } else { + // move inwards along normal, make sure normal is valid first + // todo use class funcs! + const int lev = level; + LbmFloat nx=0.,ny=0.,nz=0., nv1,nv2; + bool nonorm = false; + if(i<=0) { nx = -1.; nonorm = true; } + if(i>=mSizex-1) { nx = 1.; nonorm = true; } + if(j<=0) { ny = -1.; nonorm = true; } + if(j>=mSizey-1) { ny = 1.; nonorm = true; } +# if LBMDIM==3 + if(k<=0) { nz = -1.; nonorm = true; } + if(k>=mSizez-1) { nz = 1.; nonorm = true; } +# endif // LBMDIM==3 + if(!nonorm) { + FFGET_NORM(nv1,dE); FFGET_NORM(nv2,dW); + nx = 0.5* (nv2-nv1); + FFGET_NORM(nv1,dN); FFGET_NORM(nv2,dS); + ny = 0.5* (nv2-nv1); +# if LBMDIM==3 + FFGET_NORM(nv1,dT); FFGET_NORM(nv2,dB); + nz = 0.5* (nv2-nv1); +# else // LBMDIM==3 + nz = 0.; +# endif // LBMDIM==3 + } else { + v = p->getVel() + vec2G(mLevel[level].gravity); + } + p->advanceVec( (ntlVec3Gfx(nx,ny,nz)) * -0.1 ); // + vec2G(mLevel[level].gravity); + } + } + + p->setVel( v ); + p->advanceVel(); + } + + // drop handling + else if(p->getType()==PART_DROP) { + ntlVec3Gfx v = p->getVel(); // dampen... + + if(mPartUsePhysModel) { + LbmFloat radius = p->getSize() * minDropSize; + LbmVec velPart = vec2L(p->getVel()) *cellsize /timestep; // * cellsize / timestep; // L2RW, lattice velocity + LbmVec velRel = velAir - velPart; + //LbmVec velRelLat = velRel /cellsize*timestep; // L2RW + LbmFloat velRelNorm = norm(velRel); + // TODO calculate values in lattice units, compute CD?!??! + LbmFloat mb = rhoWater * 4.0/3.0 * M_PI* radius*radius*radius; // mass: 4/3 pi r^3 rho + const LbmFloat rw = (r1-radius)/(r1-r2); + const LbmFloat rmax = (0.5 + 0.5*rw); + const LbmFloat vmax = (v2 + (v1-v2)* (1.0-rw) ); + const LbmFloat cd = (rmax) * (velRelNorm)/(vmax); + + LbmVec fg = rwgrav * mb;// * (1.0-rhoAir/rhoWater); + LbmVec fd = velRel* velRelNorm* cd*M_PI *rhoAir *0.5 *radius*radius; + LbmVec change = (fg+ fd ) *timestep / mb *(timestep/cellsize); + //if(k>0) { errMsg("\nPIT","NTEST1 mb="<setVel( v*0.9 ); // restdamping + } else { + p->addToVel( vec2G(mLevel[level].gravity) ); + } + } // OLD + p->advanceVel(); + + if(p->getStatus()&PART_IN) { // IN + if(kgetSize(); + const LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*size); + bool orgcellok = false; + if( (oi<0)||(oi>mSizex-1)|| + (oj<0)||(oj>mSizey-1)|| + (ok<0)||(ok>mSizez-1) ) { + // org cell not ok! + } else if( RFLAG(level, oi,oj,ok, workSet) & (CFInter) ){ + orgcellok = true; + } else { + // search upward for interface + oi=i; oj=j; ok=k; + for(int kk=0; kk<5 && ok<=mSizez-2; kk++) { + ok++; // check sizez-2 due to this increment! + if( RFLAG(level, oi,oj,ok, workSet) & (CFInter) ){ + kk = 5; orgcellok = true; + } + } + } + + //errMsg("PTIMPULSE"," new v"< 0.166*0.166) { + v *= 1./sqrtf((float)vlensqr)*0.166; + } + // compute cell velocity + LbmFloat *tcel = RACPNT(level, oi,oj,ok, workSet); + LbmFloat velUx=0., velUy=0., velUz=0.; + FORDF0 { + velUx += (this->dfDvecX[l]*RAC(tcel,l)); + velUy += (this->dfDvecY[l]*RAC(tcel,l)); + velUz += (this->dfDvecZ[l]*RAC(tcel,l)); + } + // add impulse + /* + LbmFloat cellVelSqr = velUx*velUx+ velUy*velUy+ velUz*velUz; + //errMsg("PTIMPULSE"," new v"<getStatus() ); + } + } + myTime_t parttend = getTime(); + debMsgStd("LbmFsgrSolver::advanceParticles",DM_MSG,"Time for particle update:"<< getTimeString(parttend-parttstart)<<", #particles:"<getNumParticles() , 10 ); +} + +void LbmFsgrSolver::notifySolverOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) { + int workSet = mLevel[mMaxRefine].setCurr; + std::ostringstream name; + + // debug - raw dump of ffrac values, as text! + if(mDumpRawText) { + name << outfilename<< frameNrStr <<".dump"; + FILE *file = fopen(name.str().c_str(),"w"); + if(file) { + + for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) { + for(int j=0;j1.) val=1.; + } + if(RFLAG(mMaxRefine, i,j,k, workSet) & CFFluid) val = 1.; + fprintf(file, "%f ",val); // text + //errMsg("W", PRINT_IJK<<" val:"<1.) val=1.; + } + if(RFLAG(mMaxRefine, i,j,k, workSet) & CFFluid) val = 1.; + fwrite( &val, sizeof(val), 1, file); // binary + } + } + } + fclose(file); + } // file + } // unzipped + else { + // zipped, use iso values + prepareVisualization(); + name << outfilename<< frameNrStr <<".bdump.gz"; + gzFile gzf = gzopen(name.str().c_str(),"wb9"); + if(gzf) { + // write size + int s; + s=mSizex; gzwrite(gzf, &s, sizeof(s)); + s=mSizey; gzwrite(gzf, &s, sizeof(s)); + s=mSizez; gzwrite(gzf, &s, sizeof(s)); + + // write isovalues + for(int k= getForZMinBnd(); k< getForZMaxBnd(mMaxRefine); ++k) { + for(int j=0;jlbmGetData( i,j,k ); + gzwrite(gzf, &val, sizeof(val)); + } + } + } + gzclose(gzf); + } // gzf + } // zip + } // bin dump + + dumptype = 0; frameNr = 0; // get rid of warning +} + +/*! move a particle at a boundary */ +void LbmFsgrSolver::handleObstacleParticle(ParticleObject *p) { + //if(normNoSqrt(v)<=0.) continue; // skip stuck + /* + p->setVel( v * -1. ); // revert + p->advanceVel(); // move back twice... + if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFBndNoslip)) { + p->setVel( v * -0.5 ); // revert & dampen + } + p->advanceVel(); + // */ + // TODO mark/remove stuck parts!? + + const int level = mMaxRefine; + const int workSet = mLevel[level].setCurr; + LbmVec v = vec2L( p->getVel() ); + if(normNoSqrt(v)<=0.) { + p->setVel(vec2G(mLevel[level].gravity)); + } + + CellFlagType pflag = CFBnd; + ntlVec3Gfx posOrg(p->getPos()); + ntlVec3Gfx npos(0.); + int ni=1,nj=1,nk=1; + int tries = 0; + + // try to undo movement + p->advanceVec( (p->getVel()-vec2G(mLevel[level].gravity)) * -2.); + + npos = p->getPos(); ni= (int)npos[0]; + nj= (int)npos[1]; nk= (int)npos[2]; + if(LBMDIM==2) { nk = 0; } + //errMsg("BOUNDCPAR"," t"<setActive( false ); + return; + } + pflag = RFLAG(level, ni,nj,nk, workSet); + + // try to force particle out of boundary + bool haveNorm = false; + LbmVec bnormal; + if(pflag&CFBnd) { + npos = posOrg; ni= (int)npos[0]; + nj= (int)npos[1]; nk= (int)npos[2]; + if(LBMDIM==2) { nk = 0; } + + computeObstacleSurfaceNormalAcc(ni,nj,nk, &bnormal[0]); + haveNorm = true; + normalize(bnormal); + bnormal *= 0.25; + + tries = 1; + while(pflag&CFBnd && tries<=5) { + // use increasing step sizes + p->advanceVec( vec2G( bnormal *0.5 *(gfxReal)tries ) ); + npos = p->getPos(); + ni= (int)npos[0]; + nj= (int)npos[1]; + nk= (int)npos[2]; + + // delete out of domain + if(!checkDomainBounds(level,ni,nj,nk)) { + //errMsg("BOUNDCPAR"," DEL! "); + p->setActive( false ); + return; + } + pflag = RFLAG(level, ni,nj,nk, workSet); + tries++; + } + + // really stuck, delete... + if(pflag&CFBnd) { + p->setActive( false ); + return; + } + } + + // not in bound anymore! + if(!haveNorm) { + CellFlagType *bflag = &RFLAG(level, ni,nj,nk, workSet); + LbmFloat *bcell = RACPNT(level, ni,nj,nk, workSet); + computeObstacleSurfaceNormal(bcell,bflag, &bnormal[0]); + } + normalize(bnormal); + LbmVec normComp = bnormal * dot(vec2L(v),bnormal); + //errMsg("BOUNDCPAR","bnormal"<setVel(vec2G(v)); + p->advanceVel(); +} + +/*****************************************************************************/ +/*! internal quick print function (for debugging) */ +/*****************************************************************************/ +void +LbmFsgrSolver::printLbmCell(int level, int i, int j, int k, int set) { + stdCellId *newcid = new stdCellId; + newcid->level = level; + newcid->x = i; + newcid->y = j; + newcid->z = k; + + // this function is not called upon clicking, then its from setMouseClick + debugPrintNodeInfo( newcid, set ); + delete newcid; +} +void +LbmFsgrSolver::debugMarkCellCall(int level, int vi,int vj,int vk) { + stdCellId *newcid = new stdCellId; + newcid->level = level; + newcid->x = vi; + newcid->y = vj; + newcid->z = vk; + this->addCellToMarkedList( newcid ); +} + + +/*****************************************************************************/ +// implement CellIterator interface +/*****************************************************************************/ + + + +// values from guiflkt.cpp +extern double guiRoiSX, guiRoiSY, guiRoiSZ, guiRoiEX, guiRoiEY, guiRoiEZ; +extern int guiRoiMaxLev, guiRoiMinLev; +#define CID_SX (int)( (mLevel[cid->level].lSizex-1) * guiRoiSX ) +#define CID_SY (int)( (mLevel[cid->level].lSizey-1) * guiRoiSY ) +#define CID_SZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiSZ ) + +#define CID_EX (int)( (mLevel[cid->level].lSizex-1) * guiRoiEX ) +#define CID_EY (int)( (mLevel[cid->level].lSizey-1) * guiRoiEY ) +#define CID_EZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiEZ ) + +CellIdentifierInterface* +LbmFsgrSolver::getFirstCell( ) { + int level = mMaxRefine; + +#if LBMDIM==3 + if(mMaxRefine>0) { level = mMaxRefine-1; } // NO1HIGHESTLEV DEBUG +#endif + level = guiRoiMaxLev; + if(level>mMaxRefine) level = mMaxRefine; + + //errMsg("LbmFsgrSolver::getFirstCell","Celliteration started..."); + stdCellId *cid = new stdCellId; + cid->level = level; + cid->x = CID_SX; + cid->y = CID_SY; + cid->z = CID_SZ; + return cid; +} + +LbmFsgrSolver::stdCellId* +LbmFsgrSolver::convertBaseCidToStdCid( CellIdentifierInterface* basecid) { + //stdCellId *cid = dynamic_cast( basecid ); + stdCellId *cid = (stdCellId*)( basecid ); + return cid; +} + +void LbmFsgrSolver::advanceCell( CellIdentifierInterface* basecid) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + if(cid->getEnd()) return; + + //debugOut(" ADb "<x<<","<y<<","<z<<" e"<getEnd(), 10); + cid->x++; + if(cid->x > CID_EX){ cid->x = CID_SX; cid->y++; + if(cid->y > CID_EY){ cid->y = CID_SY; cid->z++; + if(cid->z > CID_EZ){ + cid->level--; + cid->x = CID_SX; + cid->y = CID_SY; + cid->z = CID_SZ; + if(cid->level < guiRoiMinLev) { + cid->level = guiRoiMaxLev; + cid->setEnd( true ); + } + } + } + } + //debugOut(" ADa "<x<<","<y<<","<z<<" e"<getEnd(), 10); +} + +bool LbmFsgrSolver::noEndCell( CellIdentifierInterface* basecid) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return (!cid->getEnd()); +} + +void LbmFsgrSolver::deleteCellIterator( CellIdentifierInterface** cid ) { + delete *cid; + *cid = NULL; +} + +CellIdentifierInterface* LbmFsgrSolver::getCellAt( ntlVec3Gfx pos ) { + //int cellok = false; + pos -= (this->mvGeoStart); + + LbmFloat mmaxsize = mLevel[mMaxRefine].nodeSize; + for(int level=mMaxRefine; level>=0; level--) { // finest first + //for(int level=0; level<=mMaxRefine; level++) { // coarsest first + LbmFloat nsize = mLevel[level].nodeSize; + int x,y,z; + // CHECK +- maxsize? + x = (int)((pos[0]+0.5*mmaxsize) / nsize ); + y = (int)((pos[1]+0.5*mmaxsize) / nsize ); + z = (int)((pos[2]+0.5*mmaxsize) / nsize ); + if(LBMDIM==2) z = 0; + + // double check... + if(x<0) continue; + if(y<0) continue; + if(z<0) continue; + if(x>=mLevel[level].lSizex) continue; + if(y>=mLevel[level].lSizey) continue; + if(z>=mLevel[level].lSizez) continue; + + // return fluid/if/border cells + if( ( (RFLAG(level, x,y,z, mLevel[level].setCurr)&(CFUnused)) ) || + ( (levellevel = level; + newcid->x = x; + newcid->y = y; + newcid->z = z; + //errMsg("cellAt",this->mName<<" "<level].setCurr; + //return mLevel[cid->level].setOther; +} + +int LbmFsgrSolver::getCellLevel ( CellIdentifierInterface* basecid) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return cid->level; +} + +ntlVec3Gfx LbmFsgrSolver::getCellOrigin ( CellIdentifierInterface* basecid) { + ntlVec3Gfx ret; + + stdCellId *cid = convertBaseCidToStdCid(basecid); + ntlVec3Gfx cs( mLevel[cid->level].nodeSize ); + if(LBMDIM==2) { cs[2] = 0.0; } + + if(LBMDIM==2) { + ret =(this->mvGeoStart + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], (this->mvGeoEnd[2]-this->mvGeoStart[2])*0.5 ) + + ntlVec3Gfx(0.0,0.0,cs[1]*-0.25)*cid->level ) + +getCellSize(basecid); + } else { + ret =(this->mvGeoStart + ntlVec3Gfx( cid->x *cs[0], cid->y *cs[1], cid->z *cs[2] )) + +getCellSize(basecid); + } + return (ret); +} + +ntlVec3Gfx LbmFsgrSolver::getCellSize ( CellIdentifierInterface* basecid) { + // return half size + stdCellId *cid = convertBaseCidToStdCid(basecid); + ntlVec3Gfx retvec( mLevel[cid->level].nodeSize * 0.5 ); + // 2d display as rectangles + if(LBMDIM==2) { retvec[2] = 0.0; } + return (retvec); +} + +LbmFloat LbmFsgrSolver::getCellDensity ( CellIdentifierInterface* basecid,int set) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + + // skip non-fluid cells + if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&(CFFluid|CFInter)) { + // ok go on... + } else { + return 0.; + } + + LbmFloat rho = 0.0; + FORDF0 { rho += QCELL(cid->level, cid->x,cid->y,cid->z, set, l); } // ORG + return ((rho-1.0) * mLevel[cid->level].simCellSize / mLevel[cid->level].timestep) +1.0; // ORG + /*if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) { // test + LbmFloat ux,uy,uz; + ux=uy=uz= 0.0; + int lev = cid->level; + LbmFloat df[27], feqOld[27]; + FORDF0 { + rho += QCELL(lev, cid->x,cid->y,cid->z, set, l); + ux += this->dfDvecX[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l); + uy += this->dfDvecY[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l); + uz += this->dfDvecZ[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l); + df[l] = QCELL(lev, cid->x,cid->y,cid->z, set, l); + } + FORDF0 { + feqOld[l] = getCollideEq(l, rho,ux,uy,uz); + } + // debugging mods + //const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feqOld); + //const LbmFloat modOmega = this->getLesOmega(mLevel[lev].omega, mLevel[lev].lcsmago,Qo); + //rho = (2.0-modOmega) *25.0; + //rho = Qo*100.0; + //if(cid->x==24){ errMsg("MODOMT"," at "<x,cid->y,cid->z)<<" = "<level, cid->x,cid->y,cid->z, set)&(CFFluid|CFInter)) { + // ok go on... + } else { + return LbmVec(0.0); + } + + LbmFloat ux,uy,uz; + ux=uy=uz= 0.0; + FORDF0 { + ux += this->dfDvecX[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l); + uy += this->dfDvecY[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l); + uz += this->dfDvecZ[l]* QCELL(cid->level, cid->x,cid->y,cid->z, set, l); + } + LbmVec vel(ux,uy,uz); + // TODO fix... + return (vel * mLevel[cid->level].simCellSize / mLevel[cid->level].timestep * this->mDebugVelScale); // normal +} + +LbmFloat LbmFsgrSolver::getCellDf( CellIdentifierInterface* basecid,int set, int dir) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return QCELL(cid->level, cid->x,cid->y,cid->z, set, dir); +} +LbmFloat LbmFsgrSolver::getCellMass( CellIdentifierInterface* basecid,int set) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return QCELL(cid->level, cid->x,cid->y,cid->z, set, dMass); +} +LbmFloat LbmFsgrSolver::getCellFill( CellIdentifierInterface* basecid,int set) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac); + if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFFluid) return 1.0; + return 0.0; + //return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac); +} +CellFlagType LbmFsgrSolver::getCellFlag( CellIdentifierInterface* basecid,int set) { + stdCellId *cid = convertBaseCidToStdCid(basecid); + return RFLAG(cid->level, cid->x,cid->y,cid->z, set); +} + +LbmFloat LbmFsgrSolver::getEquilDf( int l ) { + return this->dfEquil[l]; +} + + +ntlVec3Gfx LbmFsgrSolver::getVelocityAt (float xp, float yp, float zp) { + ntlVec3Gfx avgvel(0.0); + LbmFloat avgnum = 0.; + + // taken from getCellAt! + const int level = mMaxRefine; + const int workSet = mLevel[level].setCurr; + const LbmFloat nsize = mLevel[level].nodeSize; + const int x = (int)((-this->mvGeoStart[0]+xp-0.5*nsize) / nsize ); + const int y = (int)((-this->mvGeoStart[1]+yp-0.5*nsize) / nsize ); + int z = (int)((-this->mvGeoStart[2]+zp-0.5*nsize) / nsize ); + if(LBMDIM==2) z=0; + //errMsg("DUMPVEL","p"<dfVecX[l]; + const int j = y+this->dfVecY[l]; + const int k = z+this->dfVecZ[l]; + + if( (i<0) || (j<0) || (k<0) + || (i>=mLevel[level].lSizex) + || (j>=mLevel[level].lSizey) + || (k>=mLevel[level].lSizez) ) continue; + + if( (RFLAG(level, i,j,k, mLevel[level].setCurr)&(CFFluid|CFInter)) ) { + ntlVec3Gfx vel(0.0); + LbmFloat *ccel = RACPNT(level, i,j,k ,workSet); // omp + for(int n=1; ncDfNum; n++) { + vel[0] += (this->dfDvecX[n]*RAC(ccel,n)); + vel[1] += (this->dfDvecY[n]*RAC(ccel,n)); + vel[2] += (this->dfDvecZ[n]*RAC(ccel,n)); + } + + avgvel += vel; + avgnum += 1.0; + if(l==0) { // center slightly more weight + avgvel += vel; avgnum += 1.0; + } + } // */ + } + + if(avgnum>0.) { + ntlVec3Gfx retv = avgvel / avgnum; + retv *= nsize/mLevel[level].timestep; + // scale for current animation settings (frame time) + retv *= mpParam->getCurrentAniFrameTime(); + //errMsg("DUMPVEL","t"<getCurrentAniFrameTime() ); + return retv; + } + // no cells here...? + //errMsg("DUMPVEL"," at "<( set, this ); + lbmDebugDisplay( set ); +} +#endif + +/*****************************************************************************/ +// strict debugging functions +/*****************************************************************************/ +#if FSGR_STRICT_DEBUG==1 +#define STRICT_EXIT *((int *)0)=0; + +int LbmFsgrSolver::debLBMGI(int level, int ii,int ij,int ik, int is) { + if(level < 0){ errMsg("LbmStrict::debLBMGI"," invLev- l"< mMaxRefine){ errMsg("LbmStrict::debLBMGI"," invLev+ l"<mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<1){ errMsg("LbmStrict"," invS+ l"<this->cDirNum){ errMsg("LbmStrict"," invD+ l"<this->cDirNum){ errMsg("LbmStrict"," invD+ l"< mMaxRefine){ errMsg("LbmStrict::debLBMQI"," invLev+ l"<mLevel[level].lSizex-1){ errMsg("LbmStrict"," invX+ l"<mLevel[level].lSizey-1){ errMsg("LbmStrict"," invY+ l"<mLevel[level].lSizez-1){ errMsg("LbmStrict"," invZ+ l"<1){ errMsg("LbmStrict"," invS+ l"<this->cDfNum){ // dFfrac is an exception + if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<mInitDone) && (is!=mLevel[level].setCurr)){ STRICT_EXIT; } // COMPRT debug +#endif // COMPRESSGRIDS==1 + return _LBMQI(level, ii,ij,ik, is, l); +}; + +LbmFloat& LbmFsgrSolver::debQCELL(int level, int xx,int yy,int zz,int set,int l) { + //errMsg("LbmStrict","debQCELL debug: l"<this->cDfNum){ errMsg("LbmStrict"," invD+ l"<this->cDfNum){ errMsg("LbmStrict"," invD+ l"<dTotalNum){ errMsg("LbmStrict"," invD+ "<<" l"<this->cDfNum){ // dFfrac is an exception + //if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<getAsString() , 10); + ntlVec3Gfx org = this->getCellOrigin( cell ); + ntlVec3Gfx halfsize = this->getCellSize( cell ); + int set = this->getCellSet( cell ); + //debugOut(" DD: "<getAsString()<<" "<< (dispset->type) , 10); + + bool showcell = true; + int linewidth = 1; + ntlColor col(0.5); + LbmFloat cscale = 1.0; //dispset->scale; + +#define DRAWDISPCUBE(col,scale) \ + { glLineWidth( linewidth ); \ + glColor3f( (col)[0], (col)[1], (col)[2]); \ + ntlVec3Gfx s = org-(halfsize * (scale)); \ + ntlVec3Gfx e = org+(halfsize * (scale)); \ + drawCubeWire( s,e ); } + + CellFlagType flag = this->getCellFlag(cell, set ); + // always check types + if(flag& CFInvalid ) { if(!guiShowInvalid ) return; } + if(flag& CFUnused ) { if(!guiShowInvalid ) return; } + if(flag& CFEmpty ) { if(!guiShowEmpty ) return; } + if(flag& CFInter ) { if(!guiShowInterface) return; } + if(flag& CFNoDelete ) { if(!guiShowNoDelete ) return; } + if(flag& CFBnd ) { if(!guiShowBnd ) return; } + + // only dismiss one of these types + if(flag& CFGrFromCoarse) { if(!guiShowCoarseInner ) return; } // inner not really interesting + else + if(flag& CFGrFromFine) { if(!guiShowCoarseBorder ) return; } + else + if(flag& CFFluid ) { if(!guiShowFluid ) return; } + + switch(dispset) { + case FLUIDDISPNothing: { + showcell = false; + } break; + case FLUIDDISPCelltypes: { + cscale = 0.5; + + if(flag& CFNoDelete) { // debug, mark nodel cells + ntlColor ccol(0.7,0.0,0.0); + DRAWDISPCUBE(ccol, 0.1); + } + if(flag& CFPersistMask) { // mark persistent flags + ntlColor ccol(0.5); + DRAWDISPCUBE(ccol, 0.125); + } + if(flag& CFNoBndFluid) { // mark persistent flags + ntlColor ccol(0,0,1); + DRAWDISPCUBE(ccol, 0.075); + } + + if(flag& CFInvalid) { + cscale = 0.50; + col = ntlColor(0.0,0,0.0); + } + else if(flag& CFBnd) { + cscale = 0.59; + col = ntlColor(0.4); + } + + else if(flag& CFInter) { + cscale = 0.55; + col = ntlColor(0,1,1); + + } else if(flag& CFGrFromCoarse) { + // draw as - with marker + ntlColor col2(0.0,1.0,0.3); + DRAWDISPCUBE(col2, 0.1); + cscale = 0.5; + showcell=false; // DEBUG + } + else if(flag& CFFluid) { + cscale = 0.5; + if(flag& CFGrToFine) { + ntlColor col2(0.5,0.0,0.5); + DRAWDISPCUBE(col2, 0.1); + col = ntlColor(0,0,1); + } + if(flag& CFGrFromFine) { + ntlColor col2(1.0,1.0,0.0); + DRAWDISPCUBE(col2, 0.1); + col = ntlColor(0,0,1); + } else if(flag& CFGrFromCoarse) { + // draw as fluid with marker + ntlColor col2(0.0,1.0,0.3); + DRAWDISPCUBE(col2, 0.1); + col = ntlColor(0,0,1); + } else { + col = ntlColor(0,0,1); + } + } + else if(flag& CFEmpty) { + showcell=false; + } + + } break; + case FLUIDDISPVelocities: { + // dont use cube display + LbmVec vel = this->getCellVelocity( cell, set ); + glBegin(GL_LINES); + glColor3f( 0.0,0.0,0.0 ); + glVertex3f( org[0], org[1], org[2] ); + org += vec2G(vel * 10.0 * cscale); + glColor3f( 1.0,1.0,1.0 ); + glVertex3f( org[0], org[1], org[2] ); + glEnd(); + showcell = false; + } break; + case FLUIDDISPCellfills: { + cscale = 0.5; + if(flag& CFFluid) { + cscale = 0.75; + col = ntlColor(0,0,0.5); + } + else if(flag& CFInter) { + cscale = 0.75 * this->getCellMass(cell,set); + col = ntlColor(0,1,1); + } + else { + showcell=false; + } + + if( ABS(this->getCellMass(cell,set)) < 10.0 ) { + cscale = 0.75 * this->getCellMass(cell,set); + } else { + showcell = false; + } + if(cscale>0.0) { + col = ntlColor(0,1,1); + } else { + col = ntlColor(1,1,0); + } + // TODO + } break; + case FLUIDDISPDensity: { + LbmFloat rho = this->getCellDensity(cell,set); + cscale = rho*rho * 0.25; + col = ntlColor( MIN(0.5+cscale,1.0) , MIN(0.0+cscale,1.0), MIN(0.0+cscale,1.0) ); + cscale *= 2.0; + } break; + case FLUIDDISPGrid: { + cscale = 0.59; + col = ntlColor(1.0); + } break; + default: { + cscale = 0.5; + col = ntlColor(1.0,0.0,0.0); + } break; + } + + if(!showcell) return; + if(cscale==0.0) return; // dont draw zero values + DRAWDISPCUBE(col, cscale); +} + +//! debug display function +// D has to implement the CellIterator interface +void LbmFsgrSolver::lbmDebugDisplay(int dispset) { + // DEBUG always display testdata +#if LBM_INCLUDE_TESTSOLVERS==1 + if(mUseTestdata){ + cpDebugDisplay(dispset); + mpTest->testDebugDisplay(dispset); + } +#endif // LBM_INCLUDE_TESTSOLVERS==1 + if(dispset<=FLUIDDISPNothing) return; + //if(!dispset->on) return; + glDisable( GL_LIGHTING ); // dont light lines + +#if LBM_INCLUDE_TESTSOLVERS==1 + if((!mUseTestdata)|| (mUseTestdata)&&(mpTest->mFarfMode<=0)) { +#endif // LBM_INCLUDE_TESTSOLVERS==1 + + LbmFsgrSolver::CellIdentifier cid = this->getFirstCell(); + for(; this->noEndCell( cid ); + this->advanceCell( cid ) ) { + this->debugDisplayNode(dispset, cid ); + } + delete cid; + +#if LBM_INCLUDE_TESTSOLVERS==1 + } // 3d check +#endif // LBM_INCLUDE_TESTSOLVERS==1 + + glEnable( GL_LIGHTING ); // dont light lines +} + +//! debug display function +// D has to implement the CellIterator interface +void LbmFsgrSolver::lbmMarkedCellDisplay() { + //fluidDispSettings dispset; + // trick - display marked cells as grid displa -> white, big + int dispset = FLUIDDISPGrid; + glDisable( GL_LIGHTING ); // dont light lines + + LbmFsgrSolver::CellIdentifier cid = this->markedGetFirstCell(); + while(cid) { + this->debugDisplayNode(dispset, cid ); + cid = this->markedAdvanceCell(); + } + delete cid; + + glEnable( GL_LIGHTING ); // dont light lines +} + +#endif // LBM_USE_GUI==1 + +//! display a single node +void LbmFsgrSolver::debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet) { + //string printInfo, + // force printing of one set? default = -1 = off + bool printDF = false; + bool printRho = false; + bool printVel = false; + bool printFlag = false; + bool printGeom = false; + bool printMass=false; + bool printBothSets = false; + string printInfo = this->getNodeInfoString(); + + for(size_t i=0; igetCellOrigin( cell ); + ntlVec3Gfx halfsize = this->getCellSize( cell ); + int set = this->getCellSet( cell ); + debMsgStd("debugPrintNodeInfo",DM_NOTIFY, "Printing cell info '"<getAsString()<<" from "<getName()<<" currSet:"<=0) setmax = 1; + + for(int s=0; s=0) workset = forceSet; + debMsgStd(" ",DM_MSG, "Printing set:"<getCellDf(cell,workset,l), 1); + } + } + if(printRho) { + debMsgStd(" ",DM_MSG, " Rho: "<getCellDensity(cell,workset), 1); + } + if(printVel) { + debMsgStd(" ",DM_MSG, " Vel: "<getCellVelocity(cell,workset), 1); + } + if(printFlag) { + CellFlagType flag = this->getCellFlag(cell,workset); + debMsgStd(" ",DM_MSG, " Flg: "<< flag<<" "<getCellMass(cell,workset), 1); + } + // dirty... TODO fixme + debMsgStd(" ",DM_MSG, " Flx: "<getCellDf(cell,workset,dFlux), 1); + } +} + + diff --git a/intern/elbeem/intern/utilities.cpp b/intern/elbeem/intern/utilities.cpp new file mode 100644 index 00000000000..332052e91b6 --- /dev/null +++ b/intern/elbeem/intern/utilities.cpp @@ -0,0 +1,496 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Global C style utility funcions + * + *****************************************************************************/ + + +#include +#include +#include /* getenv(3), strtol(3) */ +#ifdef WIN32 +// for timing +#include +#else +#include +#include +#include +#endif + +#include "utilities.h" + +#ifndef NOPNG +#ifdef WIN32 +#include "png.h" +#else +#include +#endif +#endif // NOPNG +#include + +// global debug level +#ifdef DEBUG +int gDebugLevel = DEBUG; +#else // DEBUG +int gDebugLevel = 0; +#endif // DEBUG + +// global world state, acces with get/setElbeemState +int gElbeemState = SIMWORLD_INVALID; + +// access global state of elbeem simulator +void setElbeemState(int set) { + gElbeemState = set; +} +int getElbeemState(void) { + return gElbeemState; +} +int isSimworldOk(void) { + return (getElbeemState>=0); +} + +// last error as string, acces with get/setElbeemErrorString +char gElbeemErrorString[256] = {'-','\0' }; + +// access elbeem simulator error string +void setElbeemErrorString(const char* set) { + strncpy(gElbeemErrorString, set, 256); +} +char* getElbeemErrorString(void) { return gElbeemErrorString; } + + +//! for interval debugging output +myTime_t globalIntervalTime = 0; +//! color output setting for messages (0==off, else on) +#ifdef WIN32 +// switch off first call +#define DEF_globalColorSetting -1 +#else // WIN32 +// linux etc., on by default +#define DEF_globalColorSetting 1 +#endif // WIN32 +int globalColorSetting = DEF_globalColorSetting; // linux etc., on by default +int globalFirstEnvCheck = 0; +void resetGlobalColorSetting() { globalColorSetting = DEF_globalColorSetting; } + +// global string for formatting vector output, TODO test!? +const char *globVecFormatStr = "V[%f,%f,%f]"; + + +// global mp on/off switch +bool glob_mpactive = false; +// global access to mpi index, for debugging (e.g. in utilities.cpp) +int glob_mpnum = -1; +int glob_mpindex = -1; +int glob_mppn = -1; + + +//----------------------------------------------------------------------------- +// helper function that converts a string to integer, +// and returns an alternative value if the conversion fails +int convertString2Int(const char *str, int alt) +{ + int val; + char *endptr; + bool success=true; + + val = strtol(str, &endptr, 10); + if( (str==endptr) || + ((str!=endptr) && (*endptr != '\0')) ) success = false; + + if(!success) { + return alt; + } + return val; +} + +//----------------------------------------------------------------------------- +//! helper function that converts a flag field to a readable integer +string convertFlags2String(int flags) { + std::ostringstream ret; + ret <<"("; + int max = sizeof(int)*8; + for(int i=0; i4) && (filentemp[filentemp.length()-4]=='.')) { + filentemp[filentemp.length()-4] = '\0'; + } + std::ostringstream filennew; + filennew << filentemp.c_str(); + filennew << ".ppm.gz"; + + gzf = gzopen(filennew.str().c_str(), "wb9"); + if(!gzf) goto fail; + + gzprintf(gzf,"P6\n%d %d\n255\n",w,h); + // output binary pixels + for(int j=0;j0) { + ret << ms<<"m"<< ss<<"s" ; + } else { + if(ps>0) { + ret << ss<<"."; + if(ps<10) { ret <<"0"; } + ret <e[0]) || + (s[1]>e[1]) || + (s[2]>e[2]) ) { + errFatal("checkBoundingBox","Check by '"<0) { + myTime_t currTime = getTime(); + if((currTime - globalIntervalTime)>interval) { + globalIntervalTime = getTime(); + } else { + return; + } + } + + // colors off? + if( (globalColorSetting == -1) || // off for e.g. win32 + ((globalColorSetting==1) && ((id==DM_FATAL)||( getenv("ELBEEM_NOCOLOROUT") )) ) + ) { + // only reset once + col_std = col_black = col_dark_gray = col_bright_gray = + col_red = col_bright_red = col_green = + col_bright_green = col_bright_yellow = + col_yellow = col_cyan = col_bright_cyan = + col_purple = col_bright_purple = col_neutral = ""; + globalColorSetting = 0; + } + + std::ostringstream sout; + if(id==DM_DIRECT) { + sout << msg; + } else { + sout << col_cyan<< from; + switch(id) { + case DM_MSG: + sout << col_std << " message:"; + break; + case DM_NOTIFY: + sout << col_bright_cyan << " note:" << col_std; + break; + case DM_IMPORTANT: + sout << col_yellow << " important:" << col_std; + break; + case DM_WARNING: + sout << col_bright_red << " warning:" << col_std; + break; + case DM_ERROR: + sout << col_red << " error:" << col_red; + break; + case DM_FATAL: + sout << col_red << " fatal("<=0) { + mpin << "elbeem_log_"<< glob_mpindex <<".txt"; + } else { + mpin << "elbeem_log_ini.txt"; + } + fileout = 1; + strncpy(filen, mpin.str().c_str(),255); filen[255]='\0'; +#else + strncpy(filen, "elbeem_debug_log.txt",255); +#endif + +#ifdef WIN32 + // windows causes trouble with direct output + fileout = 1; +#endif // WIN32 + +#if PARALLEL==1 + fileout = 2;// buffer out, switch off again... + if(globOutstrForce) fileout=1; +#endif + if(getenv("ELBEEM_FORCESTDOUT")) { + fileout = 0;// always direct out + } + //fprintf(stdout,"out deb %d, %d, '%s',l%d \n",globOutstrForce,fileout, filen, globOutstr.str().size() ); + +#if PARALLEL==1 +#pragma omp critical +#endif // PARALLEL==1 + { + if(fileout==1) { + // debug level is >0 anyway, so write to file... + FILE *logf = fopen(filen,"a+"); + // dont complain anymore here... + if(logf) { + if(globOutstrForce) { + fprintf(logf, "%s",globOutstr.str().c_str() ); + globOutstr.str(""); // reset + } + fprintf(logf, "%s",sout.str().c_str() ); + fclose(logf); + } + } else if(fileout==2) { + globOutstr << sout.str(); + } else { + // normal stdout output + fprintf(stdout, "%s",sout.str().c_str() ); + if(id!=DM_DIRECT) fflush(stdout); + } + } // omp crit +} + +// helper functions from external program using elbeem lib (e.g. Blender) +/* set gDebugLevel according to env. var */ +extern "C" +void elbeemCheckDebugEnv(void) { + const char *strEnvName = "BLENDER_ELBEEMDEBUG"; + const char *strEnvName2 = "ELBEEM_DEBUGLEVEL"; + if(globalFirstEnvCheck) return; + + if(getenv(strEnvName)) { + gDebugLevel = atoi(getenv(strEnvName)); + if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<10) gDebugLevel = 0; // only use valid values + globalFirstEnvCheck = 1; +} + +/* elbeem debug output function */ +extern "C" +void elbeemDebugOut(char *msg) { + elbeemCheckDebugEnv(); + // external messages default to debug level 5... + if(gDebugLevel<5) return; + // delegate to messageOutputFunc + messageOutputFunc("[External]",DM_MSG,msg,0); +} + +/* set elbeem debug output level (0=off to 10=full on) */ +extern "C" +void elbeemSetDebugLevel(int level) { + if(level<0) level=0; + if(level>10) level=10; + gDebugLevel=level; +} + + +/* estimate how much memory a given setup will require */ +#include "solver_interface.h" + +extern "C" +double elbeemEstimateMemreq(int res, + float sx, float sy, float sz, + int refine, char *retstr) { + int resx = res, resy = res, resz = res; + // dont use real coords, just place from 0.0 to sizeXYZ + ntlVec3Gfx vgs(0.0), vge(sx,sy,sz); + initGridSizes( resx,resy,resz, vgs,vge, refine, 0); + + double memreq = -1.0; + string memreqStr(""); + // ignore farfield for now... + calculateMemreqEstimate(resx,resy,resz, refine, 0., &memreq, &memreqStr ); + + if(retstr) { + // copy at max. 32 characters + strncpy(retstr, memreqStr.c_str(), 32 ); + retstr[31] = '\0'; + } + return memreq; +} + + + diff --git a/intern/elbeem/intern/utilities.h b/intern/elbeem/intern/utilities.h new file mode 100644 index 00000000000..0f65408d23c --- /dev/null +++ b/intern/elbeem/intern/utilities.h @@ -0,0 +1,204 @@ +/****************************************************************************** + * + * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method + * Copyright 2003-2006 Nils Thuerey + * + * Global C style utility funcions + * + *****************************************************************************/ +#ifndef UTILITIES_H +#include "ntl_vector3dim.h" + +// Solaris requires ieeefp.h for finite(3C) +#if !defined(linux) && defined(sun) +#include +#endif + + +/* debugging outputs , debug level 0 (off) to 10 (max) */ +#ifdef ELBEEM_PLUGIN +#define DEBUG 0 +#else // ELBEEM_PLUGIN +#define DEBUG 10 +#endif // ELBEEM_PLUGIN +extern "C" int gDebugLevel; + + +// time measurements +typedef unsigned long myTime_t; + + +// state of the simulation world +// default +#define SIMWORLD_INVALID 0 +// performing init +#define SIMWORLD_INITIALIZING 1 +// after init, before starting simulation +#define SIMWORLD_INITED 2 +// stop of the simulation run, can be continued later +#define SIMWORLD_STOP 3 +// error during init +#define SIMWORLD_INITERROR -1 +// error during simulation +#define SIMWORLD_PANIC -2 +// general error +#define SIMWORLD_GENERICERROR -3 + +// access global state of elbeem simulator +void setElbeemState(int set); +int getElbeemState(void); +int isSimworldOk(void); + +// access elbeem simulator error string +void setElbeemErrorString(const char* set); +char* getElbeemErrorString(void); + + +/* debug output function */ +#define DM_MSG 1 +#define DM_NOTIFY 2 +#define DM_IMPORTANT 3 +#define DM_WARNING 4 +#define DM_ERROR 5 +#define DM_DIRECT 6 +#define DM_FATAL 7 +void messageOutputFunc(string from, int id, string msg, myTime_t interval); + +/* debugging messages defines */ +#ifdef DEBUG +#if LBM_PRECISION==2 +#define MSGSTREAM std::ostringstream msg; msg.precision(15); msg.width(17); +#else +#define MSGSTREAM std::ostringstream msg; msg.precision(7); msg.width(9); +#endif + +# define debMsgDirect(mStr) if(gDebugLevel>0) { std::ostringstream msg; msg << mStr; messageOutputFunc(string(""), DM_DIRECT, msg.str(), 0); } +# define debMsgStd(from,id,mStr,level) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), 0); } +# define debMsgNnl(from,id,mStr,level) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr ; messageOutputFunc(from, id, msg.str(), 0); } +# define debMsgInter(from,id,mStr,level, interval) if(gDebugLevel>=level) { MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, id, msg.str(), interval); } +# define debugOut(mStr,level) if(gDebugLevel>=level) { debMsgStd("D",DM_MSG,mStr,level); } +# define debugOutNnl(mStr,level) if(gDebugLevel>=level) { debMsgNnl("D",DM_MSG,mStr,level); } +# define debugOutInter(mStr,level, interval) debMsgInter("D",DM_MSG ,mStr,level, interval); +/* Error output function */ +#define errMsg(from,mStr) if(gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_ERROR, msg.str(), 0); } +#define warnMsg(from,mStr) if(gDebugLevel>0){ MSGSTREAM; msg << mStr <<"\n"; messageOutputFunc(from, DM_WARNING, msg.str(), 0); } + +#else +// no messages at all... +# define debMsgDirect(mStr) +# define debMsgStd(from,id,mStr,level) +# define debMsgNnl(from,id,mStr,level) +# define debMsgInter(from,id,mStr,level, interval) +# define debugOut(mStr,level) +# define debugOutNnl(mStr,level) +# define debugOutInter(mStr,level, interval) +# define errMsg(from,mStr) +# define warnMsg(from,mStr) +#endif + +#define errorOut(mStr) { errMsg("D",mStr); } + +// fatal errors - have to be handled +#define errFatal(from,mStr,errCode) { \ + setElbeemState(errCode); \ + MSGSTREAM; msg << mStr; \ + messageOutputFunc(from, DM_FATAL, msg.str(), 0); \ +} + + +//! helper function that converts a string to integer +int convertString2Int(const char *str, int alt); + +//! helper function that converts a flag field to a readable integer +string convertFlags2String(int flags); + +//! get the current system time +myTime_t getTime(); +//! convert time to readable string +string getTimeString(myTime_t usecs); + +//! helper to check if a bounding box was specified in the right way +bool checkBoundingBox(ntlVec3Gfx s, ntlVec3Gfx e, string checker); + +//! reset color output for elbeem init +void resetGlobalColorSetting(); + + +/*! print some vector from 3 values e.g. for ux,uy,uz */ +#define PRINT_VEC(x,y,z) " ["<<(x)<<","<<(y)<<","<<(z)<<"] " + +/*! print some vector from 3 values e.g. for ux,uy,uz */ +#define PRINT_VEC2D(x,y) " ["<<(x)<<","<<(y)<<"] " + +/*! print l'th neighbor of i,j,k as a vector, as we need ijk all the time */ +#define PRINT_IJK_NBL PRINT_VEC(i+D::dfVecX[l],j+D::dfVecY[l],k+D::dfVecZ[l]) + +/*! print i,j,k as a vector, as we need ijk all the time */ +#define PRINT_IJK PRINT_VEC(i,j,k) + +/*! print i,j,k as a vector, as we need ijk all the time */ +#define PRINT_IJ PRINT_VEC2D(i,j) + +/*! print some vector from 3 values e.g. for ux,uy,uz */ +#define PRINT_NTLVEC(v) " ["<<(v)[0]<<","<<(v)[1]<<","<<(v)[2]<<"] " + +/*! print some vector from 3 values e.g. for ux,uy,uz */ +#define PRINT_NTLVEC2D(v) " ["<<(v)[0]<<","<<(v)[1]<<"] " + +/*! print a triangle */ +#define PRINT_TRIANGLE(t,mpV) " { "< +inline T +MIN( T a, T b ) +{ return (a < b) ? a : b ; } + +/* maximum */ +template < class T > +inline T +MAX( T a, T b ) +{ return (a < b) ? b : a ; } + +/* absolute value */ +template < class T > +inline T +ABS( T a ) +{ return (0 < a) ? a : -a ; } + +/* sign of the value */ +template < class T > +inline T +SIGNUM( T a ) +{ return (0 < a) ? 1 : -1 ; } + +/* sign, returns -1,0,1 depending on sign/value=0 */ +template < class T > +inline T +SIGNUM0( T a ) +{ return (0 < a) ? 1 : ( a < 0 ? -1 : 0 ) ; } + +/* round to nearest integer */ +inline int +ROUND(double d) +{ return int(d + 0.5); } + +/* square function */ +template < class T > +inline T +SQUARE( T a ) +{ return a*a; } + + +#define UTILITIES_H +#endif diff --git a/intern/elbeem/make/msvc_6_0/elbeem.dsp b/intern/elbeem/make/msvc_6_0/elbeem.dsp new file mode 100644 index 00000000000..ef5daa29fa4 --- /dev/null +++ b/intern/elbeem/make/msvc_6_0/elbeem.dsp @@ -0,0 +1,290 @@ +# Microsoft Developer Studio Project File - Name="elbeem" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=elbeem - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "elbeem.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "elbeem.mak" CFG="elbeem - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "elbeem - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "elbeem - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "elbeem - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /I "../../../../../lib/windows/sdl/include" /I "../../../../../lib/windows/zlib/include" /I "../../../../../lib/windows/png/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "NOGUI" /D "ELBEEM_BLENDER" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Release\blender_elbeem.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy to lib ... xcopy /Y .\release\blender_elbeem.lib ..\..\..\..\..\lib\windows\elbeem\lib\*.* +# End Special Build Tool + +!ELSEIF "$(CFG)" == "elbeem - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../../../../lib/windows/sdl/include" /I "../../../../../lib/windows/zlib/include" /I "../../../../../lib/windows/png/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "NOGUI" /D "ELBEEM_BLENDER" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\blender_elbeem.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy to lib ... xcopy /Y .\debug\blender_elbeem.lib ..\..\..\..\..\lib\windows\elbeem\lib\debug\*.* +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "elbeem - Win32 Release" +# Name "elbeem - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\attributes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\elbeem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\isosurface.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_blenderdumper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_bsptree.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometrymodel.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometryobject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_lighting.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_ray.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_world.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\parametrizer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\particletracer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\simulation_object.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_adap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_interface.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_main.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_util.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\utilities.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\intern\attributes.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\isosurface.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\mcubes_tables.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_blenderdumper.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_bsptree.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometryclass.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometrymodel.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometryobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_geometryshader.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_lighting.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_lightobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_material.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_matrices.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_ray.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_renderglobals.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_rndstream.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_triangle.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_vector3dim.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\ntl_world.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\parametrizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\particletracer.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\simulation_object.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_class.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_dimenions.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_interface.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\solver_relax.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\utilities.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/elbeem/make/msvc_7_0/elbeem.vcproj b/intern/elbeem/make/msvc_7_0/elbeem.vcproj new file mode 100644 index 00000000000..9de4482e2fd --- /dev/null +++ b/intern/elbeem/make/msvc_7_0/elbeem.vcproj @@ -0,0 +1,367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt new file mode 100644 index 00000000000..1e1380df9a3 --- /dev/null +++ b/intern/ghost/CMakeLists.txt @@ -0,0 +1,60 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . ../string ${WINTAB_INC}) + +FILE(GLOB SRC intern/*.cpp) + +IF(APPLE) + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerX11.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemX11.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowX11.cpp") +ELSE(APPLE) + IF(WIN32) + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerX11.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemX11.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowX11.cpp") + ELSE(WIN32) + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowWin32.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_DisplayManagerCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_SystemCarbon.cpp") + LIST(REMOVE_ITEM SRC "${CMAKE_CURRENT_SOURCE_DIR}/intern/GHOST_WindowCarbon.cpp") + ENDIF(WIN32) +ENDIF(APPLE) + +BLENDERLIB(bf_ghost "${SRC}" "${INC}") +#, libtype=['core','player'], priority = [25,15] ) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h new file mode 100644 index 00000000000..4c4094409dd --- /dev/null +++ b/intern/ghost/GHOST_C-api.h @@ -0,0 +1,765 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_C-api.h + * GHOST C-API function and type declarations. + * The C-API wraps the C++ objects with the + */ + +#ifndef GHOST_C_API_H +#define GHOST_C_API_H + +#include "GHOST_Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Creates a "handle" for a C++ GHOST object. + * A handle is just an opaque pointer to an empty struct. + * In the API the pointer is casted to the actual C++ class. + * @param name Name of the handle to create. + */ +#define GHOST_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +GHOST_DECLARE_HANDLE(GHOST_SystemHandle); +GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle); +GHOST_DECLARE_HANDLE(GHOST_WindowHandle); +GHOST_DECLARE_HANDLE(GHOST_EventHandle); +GHOST_DECLARE_HANDLE(GHOST_RectangleHandle); +GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle); + + +/** + * Definition of a callback routine that receives events. + * @param event The event received. + * @param userdata The callback's user data, supplied to GHOST_CreateSystem. + */ +typedef int (*GHOST_EventCallbackProcPtr)(GHOST_EventHandle event, GHOST_TUserDataPtr userdata); + + +/** + * Creates the one and only system. + * @return a handle to the system. + */ +extern GHOST_SystemHandle GHOST_CreateSystem(void); + +/** + * Disposes the one and only system. + * @param systemhandle The handle to the system + * @return An indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle); + + +/** + * Creates an event consumer object + * @param eventCallback The event callback routine. + * @param userdata Pointer to user data returned to the callback routine. + */ +extern GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr userdata); + +/** + * Disposes an event consumer object + * @param consumerhandle Handle to the event consumer. + * @return An indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeEventConsumer(GHOST_EventConsumerHandle consumerhandle); + + +/** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @param systemhandle The handle to the system + * @return The number of milliseconds. + */ +extern GHOST_TUns64 GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle); + +/** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param systemhandle The handle to the system + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc (in milliseconds) + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ +extern GHOST_TimerTaskHandle GHOST_InstallTimer(GHOST_SystemHandle systemhandle, + GHOST_TUns64 delay, + GHOST_TUns64 interval, + GHOST_TimerProcPtr timerProc, + GHOST_TUserDataPtr userData); + +/** + * Removes a timer. + * @param systemhandle The handle to the system + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_RemoveTimer(GHOST_SystemHandle systemhandle, + GHOST_TimerTaskHandle timertaskhandle); + +/*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + +/** + * Returns the number of displays on this system. + * @param systemhandle The handle to the system + * @return The number of displays. + */ +extern GHOST_TUns8 GHOST_GetNumDisplays(GHOST_SystemHandle systemhandle); + +/** + * Returns the dimensions of the main display on this system. + * @param systemhandle The handle to the system + * @param width A pointer the width gets put in + * @param height A pointer the height gets put in + * @return void. + */ +extern void GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle, + GHOST_TUns32* width, + GHOST_TUns32* height); + +/** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param systemhandle The handle to the system + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @return A handle to the new window ( == NULL if creation failed). + */ +extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, + char* title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const int stereoVisual); + +/** + * Returns the window user data. + * @param windowhandle The handle to the window + * @return The window user data. + */ +extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle); + +/** + * Changes the window user data. + * @param windowhandle The handle to the window + * @param data The window user data. + */ +extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, + GHOST_TUserDataPtr userdata); + +/** + * Dispose a window. + * @param systemhandle The handle to the system + * @param window Handle to the window to be disposed. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle); + +/** + * Returns whether a window is valid. + * @param systemhandle The handle to the system + * @param window Handle to the window to be checked. + * @return Indication of validity. + */ +extern int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle); + +/** + * Begins full screen mode. + * @param systemhandle The handle to the system + * @param setting The new setting of the display. + * @return A handle to the window displayed in full screen. + * This window is invalid after full screen has been ended. + */ +extern GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle, + GHOST_DisplaySetting* setting, + const int stereoVisual); + +/** + * Ends full screen mode. + * @param systemhandle The handle to the system + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle); + +/** + * Returns current full screen mode status. + * @param systemhandle The handle to the system + * @return The current status. + */ +extern int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle); + +/*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + +/** + * Retrieves events from the system and stores them in the queue. + * @param systemhandle The handle to the system + * @param waitForEvent Boolean to indicate that ProcessEvents should + * wait (block) until the next event before returning. + * @return Indication of the presence of events. + */ +extern int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent); + +/** + * Retrieves events from the queue and send them to the event consumers. + * @param systemhandle The handle to the system + * @return Indication of the presence of events. + */ +extern int GHOST_DispatchEvents(GHOST_SystemHandle systemhandle); + +/** + * Adds the given event consumer to our list. + * @param systemhandle The handle to the system + * @param consumerhandle The event consumer to add. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, + GHOST_EventConsumerHandle consumerhandle); + + + +/*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + +/** + * Returns the current cursor shape. + * @param windowhandle The handle to the window + * @return The current cursor shape. + */ +extern GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle); + +/** + * Set the shape of the cursor. + * @param windowhandle The handle to the window + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TStandardCursor cursorshape); + +/** + * Set the shape of the cursor to a custom cursor. + * @param windowhandle The handle to the window + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY); +/** + * Set the shape of the cursor to a custom cursor of specified size. + * @param windowhandle The handle to the window + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @parm sizex, sizey The size of the cursor + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @param fg_color, bg_color Colors of the cursor + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCustomCursorShapeEx(GHOST_WindowHandle windowhandle, + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color ); + +/** + * Returns the visibility state of the cursor. + * @param windowhandle The handle to the window + * @return The visibility state of the cursor. + */ +extern int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle); + +/** + * Shows or hides the cursor. + * @param windowhandle The handle to the window + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, + int visible); + +/** + * Returns the current location of the cursor (location in screen coordinates) + * @param systemhandle The handle to the system + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32* x, + GHOST_TInt32* y); + +/** + * Updates the location of the cursor (location in screen coordinates). + * Not all operating systems allow the cursor to be moved (without the input device being moved). + * @param systemhandle The handle to the system + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + +/** + * Returns the state of a modifier key (ouside the message queue). + * @param systemhandle The handle to the system + * @param mask The modifier key state to retrieve. + * @param isDown Pointer to return modifier state in. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, + GHOST_TModifierKeyMask mask, + int* isDown); + +/** + * Returns the state of a mouse button (ouside the message queue). + * @param systemhandle The handle to the system + * @param mask The button state to retrieve. + * @param isDown Pointer to return button state in. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle, + GHOST_TButtonMask mask, + int* isDown); + +/** + * Returns the event type. + * @param eventhandle The handle to the event + * @return The event type. + */ +extern GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle); + +/** + * Returns the time this event was generated. + * @param eventhandle The handle to the event + * @return The event generation time. + */ +extern GHOST_TUns64 GHOST_GetEventTime(GHOST_EventHandle eventhandle); + +/** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @param eventhandle The handle to the event + * @return The generating window. + */ +extern GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle); + +/** + * Returns the event data. + * @param eventhandle The handle to the event + * @return The event data. + */ +extern GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle); + +/** + * Returns the timer callback. + * @param timertaskhandle The handle to the timertask + * @return The timer callback. + */ +extern GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle); + +/** + * Changes the timer callback. + * @param timertaskhandle The handle to the timertask + * @param timerProc The timer callback. + */ +extern void GHOST_SetTimerProc(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TimerProcPtr timerProc); + +/** + * Returns the timer user data. + * @param timertaskhandle The handle to the timertask + * @return The timer user data. + */ +extern GHOST_TUserDataPtr GHOST_GetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle); + +/** + * Changes the time user data. + * @param timertaskhandle The handle to the timertask + * @param data The timer user data. + */ +extern void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TUserDataPtr userData); + +/** + * Returns indication as to whether the window is valid. + * @param windowhandle The handle to the window + * @return The validity of the window. + */ +extern int GHOST_GetValid(GHOST_WindowHandle windowhandle) ; + +/** + * Returns the type of drawing context used in this window. + * @param windowhandle The handle to the window + * @return The current type of drawing context. + */ +extern GHOST_TDrawingContextType GHOST_GetDrawingContextType(GHOST_WindowHandle windowhandle); + +/** + * Tries to install a rendering context in this window. + * @param windowhandle The handle to the window + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ +extern GHOST_TSuccess GHOST_SetDrawingContextType(GHOST_WindowHandle windowhandle, + GHOST_TDrawingContextType type); + +/** + * Sets the title displayed in the title bar. + * @param windowhandle The handle to the window + * @param title The title to display in the title bar. + */ +extern void GHOST_SetTitle(GHOST_WindowHandle windowhandle, + char* title); + +/** + * Returns the title displayed in the title bar. The title + * should be free'd with free(). + * + * @param windowhandle The handle to the window + * @return The title, free with free(). + */ +extern char* GHOST_GetTitle(GHOST_WindowHandle windowhandle); + +/** + * Returns the window rectangle dimensions. + * These are screen coordinates. + * @param windowhandle The handle to the window + * @return A handle to the bounding rectangle of the window. + */ +extern GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle); + +/** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param windowhandle The handle to the window + * @return A handle to the bounding rectangle of the window. + */ +extern GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle); + +/** + * Disposes a rectangle object + * @param rectanglehandle Handle to the rectangle. + */ +void GHOST_DisposeRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Resizes client rectangle width. + * @param windowhandle The handle to the window + * @param width The new width of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientWidth(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width); + +/** + * Resizes client rectangle height. + * @param windowhandle The handle to the window + * @param height The new height of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientHeight(GHOST_WindowHandle windowhandle, + GHOST_TUns32 height); + +/** + * Resizes client rectangle. + * @param windowhandle The handle to the window + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetClientSize(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width, + GHOST_TUns32 height); + +/** + * Converts a point in screen coordinates to client rectangle coordinates + * @param windowhandle The handle to the window + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ +extern void GHOST_ScreenToClient(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) ; + +/** + * Converts a point in screen coordinates to client rectangle coordinates + * @param windowhandle The handle to the window + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ +extern void GHOST_ClientToScreen(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY); + +/** + * Returns the state of the window (normal, minimized, maximized). + * @param windowhandle The handle to the window + * @return The state of the window. + */ +extern GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle); + +/** + * Sets the state of the window (normal, minimized, maximized). + * @param windowhandle The handle to the window + * @param state The state of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle, + GHOST_TWindowState state); + +/** + * Sets the order of the window (bottom, top). + * @param windowhandle The handle to the window + * @param order The order of the window. + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, + GHOST_TWindowOrder order); + +/** + * Swaps front and back buffers of a window. + * @param windowhandle The handle to the window + * @return An intean success indicator. + */ +extern GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle); + +/** + * Activates the drawing context of this window. + * @param windowhandle The handle to the window + * @return An intean success indicator. + */ +extern GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle); + +/** + * Invalidates the contents of this window. + * @param windowhandle The handle to the window + * @return Indication of success. + */ +extern GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle); + +/** + * Returns the status of the tablet + * @param windowhandle The handle to the window + * @return Status of tablet + */ +extern const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle); + +/** + * Access to rectangle width. + * @param rectanglehandle The handle to the rectangle + * @return width of the rectangle + */ +extern GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Access to rectangle height. + * @param rectanglehandle The handle to the rectangle + * @return height of the rectangle + */ +extern GHOST_TInt32 GHOST_GetHeightRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Gets all members of the rectangle. + * @param rectanglehandle The handle to the rectangle + * @param l Pointer to return left coordinate in. + * @param t Pointer to return top coordinate in. + * @param r Pointer to return right coordinate in. + * @param b Pointer to return bottom coordinate in. + */ +extern void GHOST_GetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32* l, + GHOST_TInt32* t, + GHOST_TInt32* r, + GHOST_TInt32* b); + +/** + * Sets all members of the rectangle. + * @param rectanglehandle The handle to the rectangle + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ +extern void GHOST_SetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 l, + GHOST_TInt32 t, + GHOST_TInt32 r, + GHOST_TInt32 b); + +/** + * Returns whether this rectangle is empty. + * Empty rectangles are rectangles that have width==0 and/or height==0. + * @param rectanglehandle The handle to the rectangle + * @return intean value (true == empty rectangle) + */ +extern GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Returns whether this rectangle is valid. + * Valid rectangles are rectangles that have m_l <= m_r and m_t <= m_b. Thus, emapty rectangles are valid. + * @param rectanglehandle The handle to the rectangle + * @return intean value (true==valid rectangle) + */ +extern GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle); + +/** + * Grows (or shrinks the rectangle). + * The method avoids negative insets making the rectangle invalid + * @param rectanglehandle The handle to the rectangle + * @param i The amount of offset given to each extreme (negative values shrink the rectangle). + */ +extern void GHOST_InsetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 i); + +/** + * Does a union of the rectangle given and this rectangle. + * The result is stored in this rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r The rectangle that is input for the union operation. + */ +extern void GHOST_UnionRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); + +/** + * Grows the rectangle to included a point. + * @param rectanglehandle The handle to the rectangle + * @param x The x-coordinate of the point. + * @param y The y-coordinate of the point. + */ +extern void GHOST_UnionPointRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/** + * Returns whether the point is inside this rectangle. + * Point on the boundary is considered inside. + * @param rectanglehandle The handle to the rectangle + * @param x x-coordinate of point to test. + * @param y y-coordinate of point to test. + * @return intean value (true if point is inside). + */ +extern GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y); + +/** + * Returns whether the rectangle is inside this rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r rectangle to test. + * @return visibility (not, partially or fully visible). + */ +extern GHOST_TVisibility GHOST_GetRectangleVisibility(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); + +/** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location. + * @param rectanglehandle The handle to the rectangle + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + */ +extern void GHOST_SetCenterRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy); + +/** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location, + * with the width requested. + * @param rectanglehandle The handle to the rectangle + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + * @param w requested width of the rectangle + * @param h requested height of the rectangle + */ +extern void GHOST_SetRectangleCenter(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy, + GHOST_TInt32 w, + GHOST_TInt32 h); + +/** + * Clips a rectangle. + * Updates the rectangle given such that it will fit within this one. + * This can result in an empty rectangle. + * @param rectanglehandle The handle to the rectangle + * @param r the rectangle to clip + * @return whether clipping has occurred + */ +extern GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/intern/ghost/GHOST_IEvent.h b/intern/ghost/GHOST_IEvent.h new file mode 100644 index 00000000000..4ec47c6d732 --- /dev/null +++ b/intern/ghost/GHOST_IEvent.h @@ -0,0 +1,92 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_IEvent.h + * Declaration of GHOST_IEvent interface class. + */ + +#ifndef _GHOST_IEVENT_H_ +#define _GHOST_IEVENT_H_ + +#include "GHOST_Types.h" + +class GHOST_IWindow; + +/** + * Interface class for events received from GHOST. + * You should not need to inherit this class. The system will pass these events + * to the GHOST_IEventConsumer::processEvent() method of event consumers.
+ * Use the getType() method to retrieve the type of event and the getData() + * method to get the event data out. Using the event type you can cast the + * event data to the correct event dat structure. + * @see GHOST_IEventConsumer#processEvent + * @see GHOST_TEventType + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_IEvent +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IEvent() + { + } + + /** + * Returns the event type. + * @return The event type. + */ + virtual GHOST_TEventType getType() = 0; + + /** + * Returns the time this event was generated. + * @return The event generation time. + */ + virtual GHOST_TUns64 getTime() = 0; + + /** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @return The generating window. + */ + virtual GHOST_IWindow* getWindow() = 0; + + /** + * Returns the event data. + * @return The event data. + */ + virtual GHOST_TEventDataPtr getData() = 0; +}; + +#endif // _GHOST_IEVENT_H_ + diff --git a/intern/ghost/GHOST_IEventConsumer.h b/intern/ghost/GHOST_IEventConsumer.h new file mode 100644 index 00000000000..4186d4c1cab --- /dev/null +++ b/intern/ghost/GHOST_IEventConsumer.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_IEventConsumer.h + * Declaration of GHOST_IEventConsumer interface class. + */ + +#ifndef _GHOST_IEVENT_CONSUMER_H_ +#define _GHOST_IEVENT_CONSUMER_H_ + +#include "GHOST_IEvent.h" + +/** + * Interface class for objects interested in receiving events. + * Objects interested in events should inherit this class and implement the + * processEvent() method. They should then be registered with the system that + * they want to receive events. The system will call the processEvent() method + * for every installed event consumer to pass events. + * @see GHOST_ISystem#addEventConsumer + * @author Maarten Gribnau + * @date May 14, 2001 + */ +class GHOST_IEventConsumer +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IEventConsumer() + { + } + + /** + * This method is called by the system when it has events to dispatch. + * @see GHOST_ISystem#dispatchEvents + * @param event The event that can be handled or ignored. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event) = 0; +}; + +#endif // _GHOST_EVENT_CONSUMER_H_ + diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h new file mode 100644 index 00000000000..dffd81bdb13 --- /dev/null +++ b/intern/ghost/GHOST_ISystem.h @@ -0,0 +1,357 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_ISystem.h + * Main interface file for C++ Api with declaration of GHOST_ISystem interface + * class. + * Contains the doxygen documentation main page. + */ + +#ifndef _GHOST_ISYSTEM_H_ +#define _GHOST_ISYSTEM_H_ + +#include "GHOST_Types.h" +#include "GHOST_ITimerTask.h" +#include "GHOST_IWindow.h" + +class GHOST_IEventConsumer; + +/** + *! \mainpage GHOST Main Page + * + * \section intro Introduction + * + * GHOST is yet another acronym. It stands for "Generic Handy Operating System + * Toolkit". It has been created to replace the OpenGL utility tool kit + * GLUT. + * GLUT was used in Blender until the + * point that Blender needed to be ported to Apple's Mac OSX. Blender needed a + * number of modifications in GLUT to work but the GLUT sources for OSX were + * unavailable at the time. The decision was made to build our own replacement + * for GLUT. In those days, NaN Technologies BV was the company that developed + * Blender. + *

+ * Enough history. What does GHOST have to offer?
+ * In short: everything that Blender needed from GLUT to run on all it's supported + * operating systems and some extra's. + * This includes : + *
    + *
  • Time(r) management.
  • + *
  • Display/window management (windows are only created on the main display). + *
  • Event management.
  • + *
  • Cursor shape management (no custom cursors for now).
  • + *
  • Access to the state of the mouse buttons and the keyboard.
  • + *
  • Menus for windows with events generated when they are accessed (this is + * work in progress).
  • + *
+ * Font management has been moved to a separate library. + * + * \section platforms Platforms + * + * \section Building GHOST + * + * \section interface Interface + * GHOST has two programming interfaces: + *
    + *
  • The C-API. For programs written in C.
  • + *
  • The C++-API. For programs written in C++.
  • + *
+ * GHOST itself is writtem in C++ and the C-API is a wrapper around the C++ + * API. + * + * \subsection cplusplus_api The C++ API consists of the following files: + *
    + *
  • GHOST_IEvent.h
  • + *
  • GHOST_IEventConsumer.h
  • + *
  • GHOST_IMenu.h (in progress)
  • + *
  • GHOST_IMenuBar.h (in progress)
  • + *
  • GHOST_ISystem.h
  • + *
  • GHOST_ITimerTask.h
  • + *
  • GHOST_IWindow.h
  • + *
  • GHOST_Rect.h
  • + *
  • GHOST_Types.h
  • + *
+ * For an example of using the C++-API, have a look at the GHOST_C-Test.cpp + * program in the ?/ghost/test/gears/ directory. + * + * \subsection c_api The C-API + * To use GHOST in programs written in C, include the file GHOST_C-API.h in + * your program. This file includes the GHOST_Types.h file for all GHOST types + * and defines functions that give you access to the same functionality present + * in the C++ API.
+ * For an example of using the C-API, have a look at the GHOST_C-Test.c program + * in the ?/ghost/test/gears/ directory. + * + * \section work Work in progress + * + * \subsection menus Menu functionality + * Menu bars with pull-down menu's for windows are in development in the + * current version of GHOST. The file GHOST_MenuDependKludge.h contains a + * setting to turn menu functionality on or off. + */ + +/** + * Interface for classes that provide access to the operating system. + * There should be only one system class in an application. + * Therefore, the routines to create and dispose the system are static. + * Provides: + * -# Time(r) management. + * -# Display/window management (windows are only created on the main display). + * -# Event management. + * -# Cursor shape management (no custom cursors for now). + * -# Access to the state of the mouse buttons and the keyboard. + * -# Menus for windows with events generated when they are accessed (this is + * work in progress). + * @author Maarten Gribnau + * @date May 30, 2001 + */ +class GHOST_ISystem +{ +public: + /** + * Creates the one and only system. + * @return An indication of success. + */ + static GHOST_TSuccess createSystem(); + + /** + * Disposes the one and only system. + * @return An indication of success. + */ + static GHOST_TSuccess disposeSystem(); + + /** + * Returns a pointer to the one and only system (nil if it hasn't been created). + * @return A pointer to the system. + */ + static GHOST_ISystem* getSystem(); + +protected: + /** + * Constructor. + * Protected default constructor to force use of static createSystem member. + */ + GHOST_ISystem() {} + + /** + * Destructor. + * Protected default constructor to force use of static dispose member. + */ + virtual ~GHOST_ISystem() {} + +public: + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const = 0; + + /** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc (in milliseconds) + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ + virtual GHOST_ITimerTask* installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0) = 0; + + /** + * Removes a timer. + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeTimer(GHOST_ITimerTask* timerTask) = 0; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const = 0; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const = 0; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Create a stereo visual for quad buffered stereo. + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + const bool stereoVisual) = 0; + + /** + * Dispose a window. + * @param window Pointer to the window to be disposed. + * @return Indication of success. + */ + virtual GHOST_TSuccess disposeWindow(GHOST_IWindow* window) = 0; + + /** + * Returns whether a window is valid. + * @param window Pointer to the window to be checked. + * @return Indication of validity. + */ + virtual bool validWindow(GHOST_IWindow* window) = 0; + + /** + * Begins full screen mode. + * @param setting The new setting of the display. + * @param window Window displayed in full screen. + * This window is invalid after full screen has been ended. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual) = 0; + + /** + * Ends full screen mode. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void) = 0; + + /** + * Returns current full screen mode status. + * @return The current status. + */ + virtual bool getFullScreen(void) = 0; + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Retrieves events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent) = 0; + + /** + * Retrieves events from the queue and send them to the event consumers. + * @return Indication of the presence of events. + */ + virtual bool dispatchEvents() = 0; + + /** + * Adds the given event consumer to our list. + * @param consumer The event consumer to add. + * @return Indication of success. + */ + virtual GHOST_TSuccess addEventConsumer(GHOST_IEventConsumer* consumer) = 0; + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const = 0; + + /** + * Updates the location of the cursor (location in screen coordinates). + * Not all operating systems allow the cursor to be moved (without the input device being moved). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const = 0; + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of a modifier key (ouside the message queue). + * @param mask The modifier key state to retrieve. + * @param isDown The state of a modifier key (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const = 0; + + /** + * Returns the state of a mouse button (ouside the message queue). + * @param mask The button state to retrieve. + * @param isDown Button state. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const = 0; + +protected: + /** + * Initialize the system. + * @return Indication of success. + */ + virtual GHOST_TSuccess init() = 0; + + /** + * Shut the system down. + * @return Indication of success. + */ + virtual GHOST_TSuccess exit() = 0; + + /** The one and only system */ + static GHOST_ISystem* m_system; +}; + +#endif // _GHOST_ISYSTEM_H_ + diff --git a/intern/ghost/GHOST_ITimerTask.h b/intern/ghost/GHOST_ITimerTask.h new file mode 100644 index 00000000000..fa2f788823f --- /dev/null +++ b/intern/ghost/GHOST_ITimerTask.h @@ -0,0 +1,92 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_ITimerTask.h + * Declaration of GHOST_ITimerTask interface class. + */ + +#ifndef _GHOST_ITIMER_TASK_H_ +#define _GHOST_ITIMER_TASK_H_ + +#include "GHOST_Types.h" + + +/** + * Interface for a timer task. + * Timer tasks are created by the system and can be installed by the system. + * After installation, the timer callback-procedure or "timerProc" will be called + * periodically. You should not need to inherit this class. It is passed to the + * application in the timer-callback.
+ *
+ * Note that GHOST processes timers in the UI thread. You should ask GHOST + * process messages in order for the timer-callbacks to be called. + * @see GHOST_ISystem#installTimer + * @see GHOST_TimerProcPtr + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_ITimerTask +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_ITimerTask() + { + } + + /** + * Returns the timer callback. + * @return The timer callback. + */ + virtual GHOST_TimerProcPtr getTimerProc() const = 0; + + /** + * Changes the timer callback. + * @param timerProc The timer callback. + */ + virtual void setTimerProc(const GHOST_TimerProcPtr timerProc) = 0; + + /** + * Returns the timer user data. + * @return The timer user data. + */ + virtual GHOST_TUserDataPtr getUserData() const = 0; + + /** + * Changes the time user data. + * @param data The timer user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) = 0; +}; + +#endif // _GHOST_ITIMER_TASK_H_ + diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h new file mode 100644 index 00000000000..5f6bbe553c6 --- /dev/null +++ b/intern/ghost/GHOST_IWindow.h @@ -0,0 +1,261 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_IWindow.h + * Declaration of GHOST_IWindow interface class. + */ + +#ifndef _GHOST_IWINDOW_H_ +#define _GHOST_IWINDOW_H_ + +#include "STR_String.h" +#include "GHOST_Rect.h" +#include "GHOST_Types.h" + + +/** + * Interface for GHOST windows. + * + * You can create a window with the system's GHOST_ISystem::createWindow + * method. + * @see GHOST_ISystem#createWindow + * + * There are two coordinate systems: + *
    + *
  • The screen coordinate system. The origin of the screen is located in the + * upper left corner of the screen.
  • + *
  • The client rectangle coordinate system. The client rectangle of a window + * is the area that is drawable by the application (excluding title bars etc.). + *
  • + *
+ * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_IWindow +{ +public: + /** + * Destructor. + */ + virtual ~GHOST_IWindow() + { + } + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const = 0; + + /** + * Returns the type of drawing context used in this window. + * @return The current type of drawing context. + */ + virtual GHOST_TDrawingContextType getDrawingContextType() = 0; + + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) = 0; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title) = 0; + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const = 0; + + /** + * Returns the window rectangle dimensions. + * These are screen coordinates. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the client area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const = 0; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + + /** + * Swaps front and back buffers of a window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers() = 0; + + /** + * Activates the drawing context of this window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext() = 0; + + /** + * Invalidates the contents of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess invalidate() = 0; + + /** + * Returns the window user data. + * @return The window user data. + */ + virtual GHOST_TUserDataPtr getUserData() const = 0; + + /** + * Changes the window user data. + * @param data The window user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) = 0; + + /** + * Returns the tablet data (pressure etc). + * @return The tablet data (pressure etc). + */ + virtual const GHOST_TabletData* GetTabletData() = 0; + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current cursor shape. + * @return The current cursor shape. + */ + virtual GHOST_TStandardCursor getCursorShape() const = 0; + + /** + * Set the shape of the cursor. + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0; + + /** + * Set the shape of the cursor to a custom cursor. + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY) = 0; + + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color) = 0; + + /** + * Returns the visibility state of the cursor. + * @return The visibility state of the cursor. + */ + virtual bool getCursorVisibility() const = 0; + + /** + * Shows or hides the cursor. + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorVisibility(bool visible) = 0; +}; + +#endif // _GHOST_IWINDOW_H_ + diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h new file mode 100644 index 00000000000..6b303504572 --- /dev/null +++ b/intern/ghost/GHOST_Rect.h @@ -0,0 +1,234 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_Rect.h + * Declaration of GHOST_Rect rectangle class. + */ + +#ifndef _H_GHOST_Rect +#define _H_GHOST_Rect + +#include "GHOST_Types.h" + + +/** + * Implements rectangle functionality. + * The four extreme coordinates are stored as left, top, right and bottom. + * To be valid, a rectangle should have a left coordinate smaller than or equal to right. + * To be valid, a rectangle should have a top coordinate smaller than or equal to bottom. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +class GHOST_Rect { +public: + + /** + * Constructs a rectangle with the given values. + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ + GHOST_Rect(GHOST_TInt32 l=0, GHOST_TInt32 t=0, GHOST_TInt32 r=0, GHOST_TInt32 b=0) + : m_l(l), m_t(t), m_r(r), m_b(b) {} + + /** + * Copy constructor. + * @param r rectangle to copy + */ + GHOST_Rect(const GHOST_Rect& r) + : m_l(r.m_l), m_t(r.m_t), m_r(r.m_r), m_b(r.m_b) {} + + /** + * Destructor. + */ + virtual ~GHOST_Rect() {}; + + /** + * Access to rectangle width. + * @return width of the rectangle + */ + virtual inline GHOST_TInt32 getWidth() const; + + /** + * Access to rectangle height. + * @return height of the rectangle + */ + virtual inline GHOST_TInt32 getHeight() const; + + /** + * Sets all members of the rectangle. + * @param l requested left coordinate of the rectangle + * @param t requested top coordinate of the rectangle + * @param r requested right coordinate of the rectangle + * @param b requested bottom coordinate of the rectangle + */ + virtual inline void set(GHOST_TInt32 l, GHOST_TInt32 t, GHOST_TInt32 r, GHOST_TInt32 b); + + /** + * Returns whether this rectangle is empty. + * Empty rectangles are rectangles that have width==0 and/or height==0. + * @return boolean value (true==empty rectangle) + */ + virtual inline bool isEmpty() const; + + /** + * Returns whether this rectangle is valid. + * Valid rectangles are rectangles that have m_l <= m_r and m_t <= m_b. Thus, emapty rectangles are valid. + * @return boolean value (true==valid rectangle) + */ + virtual inline bool isValid() const; + + /** + * Grows (or shrinks the rectangle). + * The method avoids negative insets making the rectangle invalid + * @param i The amount of offset given to each extreme (negative values shrink the rectangle). + */ + virtual void inset(GHOST_TInt32 i); + + /** + * Does a union of the rectangle given and this rectangle. + * The result is stored in this rectangle. + * @param r The rectangle that is input for the union operation. + */ + virtual inline void unionRect(const GHOST_Rect& r); + + /** + * Grows the rectangle to included a point. + * @param x The x-coordinate of the point. + * @param y The y-coordinate of the point. + */ + virtual inline void unionPoint(GHOST_TInt32 x, GHOST_TInt32 y); + + /** + * Returns whether the point is inside this rectangle. + * Point on the boundary is considered inside. + * @param x x-coordinate of point to test. + * @param y y-coordinate of point to test. + * @return boolean value (true if point is inside). + */ + virtual inline bool isInside(GHOST_TInt32 x, GHOST_TInt32 y) const; + + /** + * Returns whether the rectangle is inside this rectangle. + * @param r rectangle to test. + * @return visibility (not, partially or fully visible). + */ + virtual GHOST_TVisibility getVisibility(GHOST_Rect& r) const; + + /** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location. + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + */ + virtual void setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy); + + /** + * Sets rectangle members. + * Sets rectangle members such that it is centered at the given location, + * with the width requested. + * @param cx requested center x-coordinate of the rectangle + * @param cy requested center y-coordinate of the rectangle + * @param w requested width of the rectangle + * @param h requested height of the rectangle + */ + virtual void setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy, GHOST_TInt32 w, GHOST_TInt32 h); + + /** + * Clips a rectangle. + * Updates the rectangle given such that it will fit within this one. + * This can result in an empty rectangle. + * @param r the rectangle to clip + * @return whether clipping has occurred + */ + virtual bool clip(GHOST_Rect& r) const; + + /** Left coordinate of the rectangle */ + GHOST_TInt32 m_l; + /** Top coordinate of the rectangle */ + GHOST_TInt32 m_t; + /** Right coordinate of the rectangle */ + GHOST_TInt32 m_r; + /** Bottom coordinate of the rectangle */ + GHOST_TInt32 m_b; +}; + + +inline GHOST_TInt32 GHOST_Rect::getWidth() const +{ + return m_r - m_l; +} + +inline GHOST_TInt32 GHOST_Rect::getHeight() const +{ + return m_b - m_t; +} + +inline void GHOST_Rect::set(GHOST_TInt32 l, GHOST_TInt32 t, GHOST_TInt32 r, GHOST_TInt32 b) +{ + m_l = l; m_t = t; m_r = r; m_b = b; +} + +inline bool GHOST_Rect::isEmpty() const +{ + return (getWidth() == 0) || (getHeight() == 0); +} + +inline bool GHOST_Rect::isValid() const +{ + return (m_l <= m_r) && (m_t <= m_b); +} + +inline void GHOST_Rect::unionRect(const GHOST_Rect& r) +{ + if (r.m_l < m_l) m_l = r.m_l; + if (r.m_r > m_r) m_r = r.m_r; + if (r.m_t < m_t) m_t = r.m_t; + if (r.m_b > m_b) m_b = r.m_b; +} + +inline void GHOST_Rect::unionPoint(GHOST_TInt32 x, GHOST_TInt32 y) +{ + if (x < m_l) m_l = x; + if (x > m_r) m_r = x; + if (y < m_t) m_t = y; + if (y > m_b) m_b = y; +} + +inline bool GHOST_Rect::isInside(GHOST_TInt32 x, GHOST_TInt32 y) const +{ + return (x >= m_l) && (x <= m_r) && (y >= m_t) && (y <= m_b); +} + +#endif // _H_GHOST_Rect + diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h new file mode 100644 index 00000000000..d5575354370 --- /dev/null +++ b/intern/ghost/GHOST_Types.h @@ -0,0 +1,372 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef _GHOST_TYPES_H_ +#define _GHOST_TYPES_H_ + +typedef char GHOST_TInt8; +typedef unsigned char GHOST_TUns8; +typedef short GHOST_TInt16; +typedef unsigned short GHOST_TUns16; +typedef int GHOST_TInt32; +typedef unsigned int GHOST_TUns32; + +#if defined(WIN32) && !defined(FREE_WINDOWS) +typedef __int64 GHOST_TInt64; +typedef unsigned __int64 GHOST_TUns64; +#else +typedef long long GHOST_TInt64; +typedef unsigned long long GHOST_TUns64; +#endif + +typedef void* GHOST_TUserDataPtr; + +typedef enum +{ + GHOST_kFailure = 0, + GHOST_kSuccess +} GHOST_TSuccess; + +/* Xtilt and Ytilt represent how much the pen is tilted away from + * vertically upright in either the X or Y direction, with X and Y the + * axes of the tablet surface. + * In other words, Xtilt and Ytilt are components of a vector created by projecting + * the pen's angle in 3D space vertically downwards on to the XY plane + * --Matt + */ +typedef struct GHOST_TabletData { + char Active; /* 0=None, 1=Stylus, 2=Eraser */ + float Pressure; /* range 0.0 (not touching) to 1.0 (full pressure) */ + float Xtilt; /* range 0.0 (upright) to 1.0 (tilted fully against the tablet surface) */ + float Ytilt; /* as above */ +} GHOST_TabletData; + + +typedef enum { + GHOST_kNotVisible = 0, + GHOST_kPartiallyVisible, + GHOST_kFullyVisible +} GHOST_TVisibility; + + +typedef enum { + GHOST_kFireTimeNever = 0xFFFFFFFF +} GHOST_TFireTimeConstant; + +typedef enum { + GHOST_kModifierKeyLeftShift = 0, + GHOST_kModifierKeyRightShift, + GHOST_kModifierKeyLeftAlt, + GHOST_kModifierKeyRightAlt, + GHOST_kModifierKeyLeftControl, + GHOST_kModifierKeyRightControl, + GHOST_kModifierKeyCommand, // APPLE only + GHOST_kModifierKeyNumMasks +} GHOST_TModifierKeyMask; + + +typedef enum { + GHOST_kWindowStateNormal = 0, + GHOST_kWindowStateMaximized, + GHOST_kWindowStateMinimized, + GHOST_kWindowStateFullScreen, + GHOST_kWindowState8Normal = 8, + GHOST_kWindowState8Maximized, + GHOST_kWindowState8Minimized, + GHOST_kWindowState8FullScreen +} GHOST_TWindowState; + + +typedef enum { + GHOST_kWindowOrderTop = 0, + GHOST_kWindowOrderBottom +} GHOST_TWindowOrder; + + +typedef enum { + GHOST_kDrawingContextTypeNone = 0, + GHOST_kDrawingContextTypeOpenGL +} GHOST_TDrawingContextType; + + +typedef enum { + GHOST_kButtonMaskLeft = 0, + GHOST_kButtonMaskMiddle, + GHOST_kButtonMaskRight, + GHOST_kButtonNumMasks +} GHOST_TButtonMask; + + +typedef enum { + GHOST_kEventUnknown = 0, + + GHOST_kEventCursorMove, /// Mouse move event + GHOST_kEventButtonDown, /// Mouse button event + GHOST_kEventButtonUp, /// Mouse button event + GHOST_kEventWheel, /// Mouse wheel event + + GHOST_kEventKeyDown, + GHOST_kEventKeyUp, +// GHOST_kEventKeyAuto, + + GHOST_kEventQuit, + + GHOST_kEventWindowClose, + GHOST_kEventWindowActivate, + GHOST_kEventWindowDeactivate, + GHOST_kEventWindowUpdate, + GHOST_kEventWindowSize, + + GHOST_kNumEventTypes +} GHOST_TEventType; + + +typedef enum { + GHOST_kStandardCursorFirstCursor = 0, + GHOST_kStandardCursorDefault = 0, + GHOST_kStandardCursorRightArrow, + GHOST_kStandardCursorLeftArrow, + GHOST_kStandardCursorInfo, + GHOST_kStandardCursorDestroy, + GHOST_kStandardCursorHelp, + GHOST_kStandardCursorCycle, + GHOST_kStandardCursorSpray, + GHOST_kStandardCursorWait, + GHOST_kStandardCursorText, + GHOST_kStandardCursorCrosshair, + GHOST_kStandardCursorUpDown, + GHOST_kStandardCursorLeftRight, + GHOST_kStandardCursorTopSide, + GHOST_kStandardCursorBottomSide, + GHOST_kStandardCursorLeftSide, + GHOST_kStandardCursorRightSide, + GHOST_kStandardCursorTopLeftCorner, + GHOST_kStandardCursorTopRightCorner, + GHOST_kStandardCursorBottomRightCorner, + GHOST_kStandardCursorBottomLeftCorner, + GHOST_kStandardCursorCustom, + GHOST_kStandardCursorNumCursors, + GHOST_kStandardCursorPencil +} GHOST_TStandardCursor; + + +typedef enum { + GHOST_kKeyUnknown = -1, + GHOST_kKeyBackSpace, + GHOST_kKeyTab, + GHOST_kKeyLinefeed, + GHOST_kKeyClear, + GHOST_kKeyEnter = 0x0D, + + GHOST_kKeyEsc = 0x1B, + GHOST_kKeySpace = ' ', + GHOST_kKeyQuote = 0x27, + GHOST_kKeyComma = ',', + GHOST_kKeyMinus = '-', + GHOST_kKeyPeriod = '.', + GHOST_kKeySlash = '/', + + // Number keys + GHOST_kKey0 = '0', + GHOST_kKey1, + GHOST_kKey2, + GHOST_kKey3, + GHOST_kKey4, + GHOST_kKey5, + GHOST_kKey6, + GHOST_kKey7, + GHOST_kKey8, + GHOST_kKey9, + + GHOST_kKeySemicolon = ';', + GHOST_kKeyEqual = '=', + + // Character keys + GHOST_kKeyA = 'A', + GHOST_kKeyB, + GHOST_kKeyC, + GHOST_kKeyD, + GHOST_kKeyE, + GHOST_kKeyF, + GHOST_kKeyG, + GHOST_kKeyH, + GHOST_kKeyI, + GHOST_kKeyJ, + GHOST_kKeyK, + GHOST_kKeyL, + GHOST_kKeyM, + GHOST_kKeyN, + GHOST_kKeyO, + GHOST_kKeyP, + GHOST_kKeyQ, + GHOST_kKeyR, + GHOST_kKeyS, + GHOST_kKeyT, + GHOST_kKeyU, + GHOST_kKeyV, + GHOST_kKeyW, + GHOST_kKeyX, + GHOST_kKeyY, + GHOST_kKeyZ, + + GHOST_kKeyLeftBracket = '[', + GHOST_kKeyRightBracket = ']', + GHOST_kKeyBackslash = 0x5C, + GHOST_kKeyAccentGrave = '`', + + + GHOST_kKeyLeftShift = 0x100, + GHOST_kKeyRightShift, + GHOST_kKeyLeftControl, + GHOST_kKeyRightControl, + GHOST_kKeyLeftAlt, + GHOST_kKeyRightAlt, + GHOST_kKeyCommand, // APPLE only! + GHOST_kKeyGrLess , // German PC only! + + GHOST_kKeyCapsLock, + GHOST_kKeyNumLock, + GHOST_kKeyScrollLock, + + GHOST_kKeyLeftArrow, + GHOST_kKeyRightArrow, + GHOST_kKeyUpArrow, + GHOST_kKeyDownArrow, + + GHOST_kKeyPrintScreen, + GHOST_kKeyPause, + + GHOST_kKeyInsert, + GHOST_kKeyDelete, + GHOST_kKeyHome, + GHOST_kKeyEnd, + GHOST_kKeyUpPage, + GHOST_kKeyDownPage, + + // Numpad keys + GHOST_kKeyNumpad0, + GHOST_kKeyNumpad1, + GHOST_kKeyNumpad2, + GHOST_kKeyNumpad3, + GHOST_kKeyNumpad4, + GHOST_kKeyNumpad5, + GHOST_kKeyNumpad6, + GHOST_kKeyNumpad7, + GHOST_kKeyNumpad8, + GHOST_kKeyNumpad9, + GHOST_kKeyNumpadPeriod, + GHOST_kKeyNumpadEnter, + GHOST_kKeyNumpadPlus, + GHOST_kKeyNumpadMinus, + GHOST_kKeyNumpadAsterisk, + GHOST_kKeyNumpadSlash, + + // Function keys + GHOST_kKeyF1, + GHOST_kKeyF2, + GHOST_kKeyF3, + GHOST_kKeyF4, + GHOST_kKeyF5, + GHOST_kKeyF6, + GHOST_kKeyF7, + GHOST_kKeyF8, + GHOST_kKeyF9, + GHOST_kKeyF10, + GHOST_kKeyF11, + GHOST_kKeyF12, + GHOST_kKeyF13, + GHOST_kKeyF14, + GHOST_kKeyF15, + GHOST_kKeyF16, + GHOST_kKeyF17, + GHOST_kKeyF18, + GHOST_kKeyF19, + GHOST_kKeyF20, + GHOST_kKeyF21, + GHOST_kKeyF22, + GHOST_kKeyF23, + GHOST_kKeyF24 +} GHOST_TKey; + + +typedef void* GHOST_TEventDataPtr; + +typedef struct { + /** The x-coordinate of the cursor position. */ + GHOST_TInt32 x; + /** The y-coordinate of the cursor position. */ + GHOST_TInt32 y; +} GHOST_TEventCursorData; + +typedef struct { + /** The mask of the mouse button. */ + GHOST_TButtonMask button; +} GHOST_TEventButtonData; + +typedef struct { + /** Displacement of a mouse wheel. */ + GHOST_TInt32 z; +} GHOST_TEventWheelData; + +typedef struct { + /** The key code. */ + GHOST_TKey key; + /** The ascii code for the key event ('\0' if none). */ + char ascii; +} GHOST_TEventKeyData; + +typedef struct { + /** Number of pixels on a line. */ + GHOST_TUns32 xPixels; + /** Number of lines. */ + GHOST_TUns32 yPixels; + /** Numberof bits per pixel. */ + GHOST_TUns32 bpp; + /** Refresh rate (in Hertz). */ + GHOST_TUns32 frequency; +} GHOST_DisplaySetting; + + +/** + * A timer task callback routine. + * @param task The timer task object. + * @param time The current time. + */ +#ifdef __cplusplus +class GHOST_ITimerTask; +typedef void (*GHOST_TimerProcPtr)(GHOST_ITimerTask* task, GHOST_TUns64 time); +#else +struct GHOST_TimerTaskHandle__; +typedef void (*GHOST_TimerProcPtr)(struct GHOST_TimerTaskHandle__* task, GHOST_TUns64 time); +#endif + +#endif // _GHOST_TYPES_H_ + diff --git a/intern/ghost/Makefile b/intern/ghost/Makefile new file mode 100644 index 00000000000..fe65afbfb93 --- /dev/null +++ b/intern/ghost/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# ghost main makefile. +# + +include nan_definitions.mk + +LIBNAME = ghost +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_GHOST) ] || mkdir $(NAN_GHOST) + @[ -d $(NAN_GHOST)/include ] || mkdir $(NAN_GHOST)/include + @[ -d $(NAN_GHOST)/lib ] || mkdir $(NAN_GHOST)/lib + @[ -d $(NAN_GHOST)/lib/debug ] || mkdir $(NAN_GHOST)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libghost.a $(NAN_GHOST)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libghost.a $(NAN_GHOST)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_GHOST)/lib/libghost.a + ranlib $(NAN_GHOST)/lib/debug/libghost.a +endif + @../tools/cpifdiff.sh *.h $(NAN_GHOST)/include/ + diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript new file mode 100644 index 00000000000..40968e816a9 --- /dev/null +++ b/intern/ghost/SConscript @@ -0,0 +1,32 @@ +#!/usr/bin/python +import sys +import os + +Import ('env') + +window_system = env['OURPLATFORM'] + +sources = env.Glob('intern/*.cpp') + +pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_Window'] + +if window_system in ('linux2', 'openbsd3', 'sunos5', 'freebsd6'): + for f in pf: + sources.remove('intern' + os.sep + f + 'Win32.cpp') + sources.remove('intern' + os.sep + f + 'Carbon.cpp') +elif window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross'): + for f in pf: + sources.remove('intern' + os.sep + f + 'X11.cpp') + sources.remove('intern' + os.sep + f + 'Carbon.cpp') +elif window_system == 'darwin': + for f in pf: + sources.remove('intern' + os.sep + f + 'Win32.cpp') + sources.remove('intern' + os.sep + f + 'X11.cpp') +else: + print "Unknown window system specified." + Exit() + +incs = '. ../string ' + env['BF_OPENGL_INC'] +if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross'): + incs = env['BF_WINTAB_INC'] + ' ' + incs +env.BlenderLib ('bf_ghost', sources, Split(incs), defines=['_USE_MATH_DEFINES'], libtype=['core','player'], priority = [25,15] ) diff --git a/intern/ghost/doc/ghost_interface.cfg b/intern/ghost/doc/ghost_interface.cfg new file mode 100644 index 00000000000..ebe4153ea3b --- /dev/null +++ b/intern/ghost/doc/ghost_interface.cfg @@ -0,0 +1,626 @@ +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. +PROJECT_NAME = "GHOST (Generic Handy Operating System Toolkit)" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. +PROJECT_NUMBER = 1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. +OUTPUT_DIRECTORY = ./interface + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, +# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian, +# Polish, Portuguese and Slovene. +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. +EXTRACT_STATIC = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. +ALWAYS_DETAILED_SEC = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. +INTERNAL_DOCS = NO + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a class diagram (in Html and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. +CLASS_DIAGRAMS = YES + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. +JAVADOC_AUTOBRIEF = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. +TAB_SIZE = 4 + +# The ENABLE_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. +ENABLED_SECTION = + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. +GENERATE_TESTLIST = YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. +ALIASES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. +INPUT = .. + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. +FILE_PATTERNS = *.h *.cpp *.c + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +EXCLUDE = + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). +EXAMPLE_PATH = ../test + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. +EXAMPLE_PATTERNS = *.h *.cpp *.c + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse. +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. +HTML_OUTPUT = html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. +GENERATE_HTMLHELP = YES + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side pannel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript and frames is required (for instance Netscape 4.0+ +# or Internet explorer 4.0+). +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using a WORD or other. +# programs which support those fields. +# Note: wordpad (write) and others do not support links. +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. +RTF_STYLESHEET_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) +MAN_EXTENSION = .3 + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Warning: This feature +# is still experimental and very incomplete. +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. +EXPAND_AS_DEFINED = + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. +ALLEXTERNALS = + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. +COLLABORATION_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other +# documented files. +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to +# YES then doxygen will generate a graph for each documented header file showing +# the documented files that directly or indirectly include this file +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. +GRAPHICAL_HIERARCHY = YES + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. +DOT_PATH = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. +GENERATE_LEGEND = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. +CGI_NAME= search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. +CGI_URL= + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. +DOC_URL= + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. +DOC_ABSPATH= + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. +BIN_ABSPATH= /bin + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. +EXT_DOC_PATHS= diff --git a/intern/ghost/intern/GHOST_Buttons.cpp b/intern/ghost/intern/GHOST_Buttons.cpp new file mode 100644 index 00000000000..def01b0786f --- /dev/null +++ b/intern/ghost/intern/GHOST_Buttons.cpp @@ -0,0 +1,81 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "GHOST_Buttons.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + + + +GHOST_Buttons::GHOST_Buttons() +{ + clear(); +} + + +bool GHOST_Buttons::get(GHOST_TButtonMask mask) const +{ + switch (mask) { + case GHOST_kButtonMaskLeft: + return m_ButtonLeft; + case GHOST_kButtonMaskMiddle: + return m_ButtonMiddle; + case GHOST_kButtonMaskRight: + return m_ButtonRight; + default: + return false; + } +} + +void GHOST_Buttons::set(GHOST_TButtonMask mask, bool down) +{ + switch (mask) { + case GHOST_kButtonMaskLeft: + m_ButtonLeft = down; break; + case GHOST_kButtonMaskMiddle: + m_ButtonMiddle = down; break; + case GHOST_kButtonMaskRight: + m_ButtonRight = down; break; + default: + break; + } +} + +void GHOST_Buttons::clear() +{ + m_ButtonLeft = false; + m_ButtonMiddle = false; + m_ButtonRight = false; +} + +GHOST_Buttons::~GHOST_Buttons() {} diff --git a/intern/ghost/intern/GHOST_Buttons.h b/intern/ghost/intern/GHOST_Buttons.h new file mode 100644 index 00000000000..e244d54b2c6 --- /dev/null +++ b/intern/ghost/intern/GHOST_Buttons.h @@ -0,0 +1,81 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_Buttons.h + * Declaration of GHOST_Buttons struct. + */ + +#ifndef _GHOST_BUTTONS_H_ +#define _GHOST_BUTTONS_H_ + +#include "GHOST_Types.h" + + +/** + * This struct stores the state of the mouse buttons. + * Buttons can be set using button masks. + * @author Maarten Gribnau + * @date May 15, 2001 + */ +struct GHOST_Buttons { + /** + * Constructor. + */ + GHOST_Buttons(); + + virtual ~GHOST_Buttons(); + + /** + * Returns the state of a single button. + * @param mask. Key button to return. + * @return The state of the button (pressed == true). + */ + virtual bool get(GHOST_TButtonMask mask) const; + + /** + * Updates the state of a single button. + * @param mask. Button state to update. + * @param down. The new state of the button. + */ + virtual void set(GHOST_TButtonMask mask, bool down); + + /** + * Sets the state of all buttons to up. + */ + virtual void clear(); + + GHOST_TUns8 m_ButtonLeft : 1; + GHOST_TUns8 m_ButtonMiddle : 1; + GHOST_TUns8 m_ButtonRight : 1; +}; + +#endif // _GHOST_BUTTONS_H_ + diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp new file mode 100644 index 00000000000..c2b8eca9573 --- /dev/null +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -0,0 +1,804 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * GHOST_C-Api.cpp + * + * C Api for GHOST + * + * Version: $Id$ + */ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "intern/GHOST_Debug.h" +#include "GHOST_C-api.h" +#include "GHOST_ISystem.h" +#include "GHOST_IEvent.h" +#include "GHOST_IEventConsumer.h" +#include "intern/GHOST_CallbackEventConsumer.h" + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + + +GHOST_SystemHandle GHOST_CreateSystem(void) +{ + GHOST_ISystem::createSystem(); + GHOST_ISystem* system = GHOST_ISystem::getSystem(); + + return (GHOST_SystemHandle)system; +} + + + +GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->disposeSystem(); +} + + +GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr userdata) +{ + return (GHOST_EventConsumerHandle) new GHOST_CallbackEventConsumer (eventCallback, userdata); +} + + +GHOST_TSuccess GHOST_DisposeEventConsumer(GHOST_EventConsumerHandle consumerhandle) +{ + delete ((GHOST_CallbackEventConsumer*)consumerhandle); + return GHOST_kSuccess; +} + + +GHOST_TUns64 GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getMilliSeconds(); +} + + + +GHOST_TimerTaskHandle GHOST_InstallTimer(GHOST_SystemHandle systemhandle, + GHOST_TUns64 delay, + GHOST_TUns64 interval, + GHOST_TimerProcPtr timerproc, + GHOST_TUserDataPtr userdata) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (GHOST_TimerTaskHandle) system->installTimer(delay, interval, timerproc, userdata); +} + + + +GHOST_TSuccess GHOST_RemoveTimer(GHOST_SystemHandle systemhandle, + GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return system->removeTimer(timertask); +} + + + +GHOST_TUns8 GHOST_GetNumDisplays(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getNumDisplays(); +} + + + +void GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle, + GHOST_TUns32* width, + GHOST_TUns32* height) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + system->getMainDisplayDimensions(*width, *height); +} + + + +GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, + char* title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const int stereoVisual) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + bool bstereoVisual; + + if(stereoVisual) + bstereoVisual = true; + else + bstereoVisual = false; + + return (GHOST_WindowHandle) system->createWindow(title, left, top, width, height, + state, type, bstereoVisual); +} + +GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getUserData(); +} +void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->setUserData(userdata); +} + +GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return system->disposeWindow(window); +} + + + +int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) system->validWindow(window); +} + + + +GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle, + GHOST_DisplaySetting* setting, + const int stereoVisual) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_IWindow* window = NULL; + bool bstereoVisual; + + if(stereoVisual) + bstereoVisual = true; + else + bstereoVisual = false; + + system->beginFullScreen(*setting, &window, bstereoVisual); + + return (GHOST_WindowHandle)window; +} + + + +GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->endFullScreen(); +} + + + +int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->getFullScreen(); +} + + + +int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->processEvents(waitForEvent?true:false); +} + + + +int GHOST_DispatchEvents(GHOST_SystemHandle systemhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return (int) system->dispatchEvents(); +} + + +GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, GHOST_EventConsumerHandle consumerhandle) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->addEventConsumer((GHOST_CallbackEventConsumer*)consumerhandle); +} + + + +GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getCursorShape(); +} + + + +GHOST_TSuccess GHOST_SetCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TStandardCursor cursorshape) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCursorShape(cursorshape); +} + +GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle, + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCustomCursorShape(bitmap, mask, hotX, hotY); +} + +GHOST_TSuccess GHOST_SetCustomCursorShapeEx(GHOST_WindowHandle windowhandle, + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCustomCursorShape(bitmap, mask, sizex, sizey, + hotX, hotY, fg_color, bg_color); +} + + + +int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) window->getCursorVisibility(); +} + + + +GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, + int visible) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setCursorVisibility(visible?true:false); +} + + + +GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32* x, + GHOST_TInt32* y) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->getCursorPosition(*x, *y); +} + + + +GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + + return system->setCursorPosition(x, y); +} + + + +GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, + GHOST_TModifierKeyMask mask, + int* isDown) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_TSuccess result; + bool isdown; + + result = system->getModifierKeyState(mask, isdown); + *isDown = (int) isdown; + + return result; +} + + + +GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle, + GHOST_TButtonMask mask, + int* isDown) +{ + GHOST_ISystem* system = (GHOST_ISystem*) systemhandle; + GHOST_TSuccess result; + bool isdown; + + result = system->getButtonState(mask, isdown); + *isDown = (int) isdown; + + return result; +} + + + +GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getType(); +} + + + +GHOST_TUns64 GHOST_GetEventTime(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getTime(); +} + + +GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return (GHOST_WindowHandle) event->getWindow(); +} + + +GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle) +{ + GHOST_IEvent* event = (GHOST_IEvent*) eventhandle; + + return event->getData(); +} + + + +GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return timertask->getTimerProc(); +} + + + +void GHOST_SetTimerProc(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TimerProcPtr timerproc) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + timertask->setTimerProc(timerproc); +} + + + +GHOST_TUserDataPtr GHOST_GetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + return timertask->getUserData(); +} + + + +void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, + GHOST_TUserDataPtr userdata) +{ + GHOST_ITimerTask* timertask = (GHOST_ITimerTask*) timertaskhandle; + + timertask->setUserData(userdata); +} + + + +int GHOST_GetValid(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return (int) window->getValid(); +} + + + +GHOST_TDrawingContextType GHOST_GetDrawingContextType(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getDrawingContextType(); +} + + + +GHOST_TSuccess GHOST_SetDrawingContextType(GHOST_WindowHandle windowhandle, + GHOST_TDrawingContextType type) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setDrawingContextType(type); +} + + + +void GHOST_SetTitle(GHOST_WindowHandle windowhandle, + char* title) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->setTitle(title); +} + + +char* GHOST_GetTitle(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + STR_String title; + + window->getTitle(title); + + char *ctitle = (char*) malloc(title.Length() + 1); + + if (ctitle == NULL) return NULL; + strcpy(ctitle, title.Ptr()); + + return ctitle; +} + + + +GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + GHOST_Rect* rectangle = NULL; + + rectangle = new GHOST_Rect(); + window->getWindowBounds(*rectangle); + + return (GHOST_RectangleHandle)rectangle; +} + + + +GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + GHOST_Rect* rectangle = NULL; + + rectangle = new GHOST_Rect(); + window->getClientBounds(*rectangle); + + return (GHOST_RectangleHandle)rectangle; +} + + + +void GHOST_DisposeRectangle(GHOST_RectangleHandle rectanglehandle) +{ + delete (GHOST_Rect*) rectanglehandle; +} + + + +GHOST_TSuccess GHOST_SetClientWidth(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientWidth(width); +} + + + +GHOST_TSuccess GHOST_SetClientHeight(GHOST_WindowHandle windowhandle, + GHOST_TUns32 height) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientHeight(height); +} + + + +GHOST_TSuccess GHOST_SetClientSize(GHOST_WindowHandle windowhandle, + GHOST_TUns32 width, + GHOST_TUns32 height) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setClientSize(width, height); +} + + + +void GHOST_ScreenToClient(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->screenToClient(inX, inY, *outX, *outY); +} + + + +void GHOST_ClientToScreen(GHOST_WindowHandle windowhandle, + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32* outX, + GHOST_TInt32* outY) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + window->clientToScreen(inX, inY, *outX, *outY); +} + + + +GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->getState(); +} + + + +GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle, + GHOST_TWindowState state) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setState(state); +} + + + +GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, + GHOST_TWindowOrder order) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->setOrder(order); +} + + + +GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->swapBuffers(); +} + + + +GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->activateDrawingContext(); +} + + + +GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; + + return window->invalidate(); +} + + +extern const GHOST_TabletData* GHOST_GetTabletData(GHOST_WindowHandle windowhandle) +{ + return ((GHOST_IWindow*)windowhandle)->GetTabletData(); +} + + +GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle) +{ + return ((GHOST_Rect*)rectanglehandle)->getWidth(); +} + + + +GHOST_TInt32 GHOST_GetHeightRectangle(GHOST_RectangleHandle rectanglehandle) +{ + return ((GHOST_Rect*)rectanglehandle)->getHeight(); +} + + + +void GHOST_GetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32* l, + GHOST_TInt32* t, + GHOST_TInt32* r, + GHOST_TInt32* b) +{ + GHOST_Rect *rect= (GHOST_Rect*) rectanglehandle; + + *l= rect->m_l; + *t= rect->m_t; + *r= rect->m_r; + *b= rect->m_b; +} + + +void GHOST_SetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 l, + GHOST_TInt32 t, + GHOST_TInt32 r, + GHOST_TInt32 b) +{ + ((GHOST_Rect*)rectanglehandle)->set(l, t, r, b); +} + + + +GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->isEmpty()) + result = GHOST_kSuccess; + + return result; +} + + + +GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if(((GHOST_Rect*)rectanglehandle)->isValid()) + result = GHOST_kSuccess; + + return result; +} + + + +void GHOST_InsetRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 i) +{ + ((GHOST_Rect*)rectanglehandle)->inset(i); +} + + + +void GHOST_UnionRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + ((GHOST_Rect*)rectanglehandle)->unionRect(*(GHOST_Rect*)anotherrectanglehandle); +} + + + +void GHOST_UnionPointRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + ((GHOST_Rect*)rectanglehandle)->unionPoint(x, y); +} + + + +GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 x, + GHOST_TInt32 y) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->isInside(x, y)) + result = GHOST_kSuccess; + + return result; +} + + + +GHOST_TVisibility GHOST_GetRectangleVisibility(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + GHOST_TVisibility visible = GHOST_kNotVisible; + + visible = ((GHOST_Rect*)rectanglehandle)->getVisibility(*(GHOST_Rect*)anotherrectanglehandle); + + return visible; +} + + + +void GHOST_SetCenterRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy) +{ + ((GHOST_Rect*)rectanglehandle)->setCenter(cx, cy); +} + + + +void GHOST_SetRectangleCenter(GHOST_RectangleHandle rectanglehandle, + GHOST_TInt32 cx, + GHOST_TInt32 cy, + GHOST_TInt32 w, + GHOST_TInt32 h) +{ + ((GHOST_Rect*)rectanglehandle)->setCenter(cx, cy, w, h); +} + + + +GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle, + GHOST_RectangleHandle anotherrectanglehandle) +{ + GHOST_TSuccess result = GHOST_kFailure; + + if (((GHOST_Rect*)rectanglehandle)->clip(*(GHOST_Rect*)anotherrectanglehandle)) + result = GHOST_kSuccess; + + return result; +} diff --git a/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp new file mode 100644 index 00000000000..2a5e7fb9b71 --- /dev/null +++ b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp @@ -0,0 +1,59 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date October 25, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_Debug.h" +#include "GHOST_C-api.h" +#include "GHOST_CallbackEventConsumer.h" + +GHOST_CallbackEventConsumer::GHOST_CallbackEventConsumer(GHOST_EventCallbackProcPtr eventCallback, + GHOST_TUserDataPtr userData) +{ + m_eventCallback = eventCallback; + m_userData = userData; +} + + +bool GHOST_CallbackEventConsumer::processEvent(GHOST_IEvent* event) +{ + return m_eventCallback((GHOST_EventHandle)event, m_userData) != 0; +} diff --git a/intern/ghost/intern/GHOST_CallbackEventConsumer.h b/intern/ghost/intern/GHOST_CallbackEventConsumer.h new file mode 100644 index 00000000000..eb54d1c0e14 --- /dev/null +++ b/intern/ghost/intern/GHOST_CallbackEventConsumer.h @@ -0,0 +1,82 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_CallbackEventConsumer.h + * Declaration of GHOST_CallbackEventConsumer class. + */ + +#ifndef _GHOST_CALLBACK_EVENT_CONSUMER_H_ +#define _GHOST_CALLBACK_EVENT_CONSUMER_H_ + +#include "GHOST_IEventConsumer.h" +#include "GHOST_C-api.h" + +/** + * Event consumer that will forward events to a call-back routine. + * Especially useful for the C-API. + * @author Maarten Gribnau + * @date October 25, 2001 + */ +class GHOST_CallbackEventConsumer : public GHOST_IEventConsumer +{ +public: + /** + * Constructor. + * @param eventCallback The call-back routine invoked. + * @param userData The data passed back though the call-back routine. + */ + GHOST_CallbackEventConsumer( + GHOST_EventCallbackProcPtr eventCallback, + GHOST_TUserDataPtr userData); + + /** + * Destructor. + */ + virtual ~GHOST_CallbackEventConsumer(void) + { + } + + /** + * This method is called by an event producer when an event is available. + * @param event The event that can be handled or ignored. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event); + +protected: + /** The call-back routine invoked. */ + GHOST_EventCallbackProcPtr m_eventCallback; + /** The data passed back though the call-back routine. */ + GHOST_TUserDataPtr m_userData; +}; + +#endif // _GHOST_CALLBACK_EVENT_CONSUMER_H_ + diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h new file mode 100644 index 00000000000..5a56c8ef6ea --- /dev/null +++ b/intern/ghost/intern/GHOST_Debug.h @@ -0,0 +1,68 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * @file GHOST_Debug.h + * Macro's used in GHOST debug target. + */ + +#ifndef _GHOST_DEBUG_H_ +#define _GHOST_DEBUG_H_ + +#ifdef WIN32 + #ifdef _DEBUG + #pragma warning (disable:4786) // suppress stl-MSVC debug info warning + #define GHOST_DEBUG + #endif // _DEBUG +#endif // WIN32 + +#ifdef GHOST_DEBUG + #include +#endif // GHOST_DEBUG + + +#ifdef GHOST_DEBUG + #define GHOST_PRINT(x) { std::cout << x; } + //#define GHOST_PRINTF(x) { printf(x); } +#else // GHOST_DEBUG + #define GHOST_PRINT(x) + //#define GHOST_PRINTF(x) +#endif // GHOST_DEBUG + + +#ifdef GHOST_DEBUG + #define GHOST_ASSERT(x, info) { if (!(x)) {GHOST_PRINT("assertion failed: "); GHOST_PRINT(info); GHOST_PRINT("\n"); } } +#else // GHOST_DEBUG + #define GHOST_ASSERT(x, info) +#endif // GHOST_DEBUG + +#endif // _GHOST_DEBUG_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp new file mode 100644 index 00000000000..f806daee86b --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManager.cpp @@ -0,0 +1,222 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date September 21, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_DisplayManager.h" +#include "GHOST_Debug.h" + + +GHOST_DisplayManager::GHOST_DisplayManager( + void) +: m_settingsInitialized(false) +{ +} + + +GHOST_DisplayManager::~GHOST_DisplayManager(void) +{ +} + + +GHOST_TSuccess +GHOST_DisplayManager::initialize( + void) +{ + GHOST_TSuccess success; + if (!m_settingsInitialized) { + success = initializeSettings(); + m_settingsInitialized = true; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getNumDisplays( + GHOST_TUns8& /*numDisplays*/) const +{ + // Don't know if we have a display... + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings) const +{ + GHOST_TSuccess success; + + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::getNumDisplaySettings(): m_settingsInitialized=false"); + GHOST_TUns8 numDisplays; + success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + if (display < numDisplays) { + numSettings = m_settings[display].size(); + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting) const +{ + GHOST_TSuccess success; + + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::getNumDisplaySettings(): m_settingsInitialized=false"); + GHOST_TUns8 numDisplays; + success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + if (display < numDisplays && ((GHOST_TUns8)index < m_settings[display].size())) { + setting = m_settings[display][index]; + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::getCurrentDisplaySetting( + GHOST_TUns8 /*display*/, + GHOST_DisplaySetting& /*setting*/) const +{ + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::setCurrentDisplaySetting( + GHOST_TUns8 /*display*/, + const GHOST_DisplaySetting& /*setting*/) +{ + return GHOST_kFailure; +} + + +GHOST_TSuccess +GHOST_DisplayManager::findMatch( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting, + GHOST_DisplaySetting& match) const +{ + GHOST_TSuccess success = GHOST_kSuccess; + GHOST_ASSERT(m_settingsInitialized, "GHOST_DisplayManager::findMatch(): m_settingsInitialized=false"); + + int criteria[4] = { setting.xPixels, setting.yPixels, setting.bpp, setting.frequency }; + int capabilities[4]; + double field, score; + double best = 1e12; // A big number + int found = 0; + + // Look at all the display modes + for (int i = 0; (i < (int)m_settings[display].size()); i++) { + // Store the capabilities of the display device + capabilities[0] = m_settings[display][i].xPixels; + capabilities[1] = m_settings[display][i].yPixels; + capabilities[2] = m_settings[display][i].bpp; + capabilities[3] = m_settings[display][i].frequency; + + // Match against all the fields of the display settings + score = 0; + for (int j = 0; j < 4; j++) { + field = capabilities[j] - criteria[j]; + score += field * field; + } + + if (score < best) { + found = i; + best = score; + } + } + + match = m_settings[display][found]; + + GHOST_PRINT("GHOST_DisplayManager::findMatch(): settings of match:\n"); + GHOST_PRINT(" setting.xPixels=" << match.xPixels << "\n"); + GHOST_PRINT(" setting.yPixels=" << match.yPixels << "\n"); + GHOST_PRINT(" setting.bpp=" << match.bpp << "\n"); + GHOST_PRINT(" setting.frequency=" << match.frequency << "\n"); + + return success; +} + + +GHOST_TSuccess +GHOST_DisplayManager::initializeSettings( + void) +{ + GHOST_TUns8 numDisplays; + GHOST_TSuccess success = getNumDisplays(numDisplays); + if (success == GHOST_kSuccess) { + for (GHOST_TUns8 display = 0; (display < numDisplays) && (success == GHOST_kSuccess); display++) { + GHOST_DisplaySettings displaySettings; + m_settings.push_back(displaySettings); + GHOST_TInt32 numSettings; + success = getNumDisplaySettings(display, numSettings); + if (success == GHOST_kSuccess) { + GHOST_TInt32 index; + GHOST_DisplaySetting setting; + for (index = 0; (index < numSettings) && (success == GHOST_kSuccess); index++) { + success = getDisplaySetting(display, index, setting); + m_settings[display].push_back(setting); + } + } + else { + break; + } + } + } + return success; +} diff --git a/intern/ghost/intern/GHOST_DisplayManager.h b/intern/ghost/intern/GHOST_DisplayManager.h new file mode 100644 index 00000000000..d7133f4401f --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManager.h @@ -0,0 +1,140 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_DisplayManager.h + * Declaration of GHOST_DisplayManager class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_H_ +#define _GHOST_DISPLAY_MANAGER_H_ + +#include "GHOST_Types.h" + +#ifdef WIN32 +#pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif // WIN32 + +#include + +/** + * Manages system displays (platform independent implementation). + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManager +{ +public: + enum { kMainDisplay = 0 }; + /** + * Constructor. + */ + GHOST_DisplayManager(void); + + /** + * Destructor. + */ + virtual ~GHOST_DisplayManager(void); + + /** + * Initializes the list with devices and settings. + * @return Indication of success. + */ + virtual GHOST_TSuccess initialize(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * The setting given to this method is matched againts the available diplay settings. + * The best match is activated (@see findMatch()). + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The setting of the display device to be matched and activated. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: + typedef std::vector GHOST_DisplaySettings; + + /** + * Finds the best display settings match. + * @param display The index of the display device. + * @param setting The setting to match. + * @param match The optimal display setting. + * @return Indication of success. + */ + GHOST_TSuccess findMatch(GHOST_TUns8 display, const GHOST_DisplaySetting& setting, GHOST_DisplaySetting& match) const; + + /** + * Retrieves settings for each display device and stores them. + * @return Indication of success. + */ + GHOST_TSuccess initializeSettings(void); + + /** Tells whether the list of display modes has been stored already. */ + bool m_settingsInitialized; + /** The list with display settings for the main display. */ + std::vector m_settings; +}; + + +#endif // _GHOST_DISPLAY_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp b/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp new file mode 100644 index 00000000000..9877d55d8a5 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCarbon.cpp @@ -0,0 +1,181 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date September 21, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_DisplayManagerCarbon.h" +#include "GHOST_Debug.h" + +// We do not support multiple monitors at the moment + + +GHOST_DisplayManagerCarbon::GHOST_DisplayManagerCarbon(void) +{ + if (::CGGetActiveDisplayList(0, NULL, &m_numDisplays) != CGDisplayNoErr) + { + m_numDisplays = 0; + m_displayIDs = NULL; + } + if (m_numDisplays > 0) + { + m_displayIDs = new CGDirectDisplayID [m_numDisplays]; + GHOST_ASSERT((m_displayIDs!=NULL), "GHOST_DisplayManagerCarbon::GHOST_DisplayManagerCarbon(): memory allocation failed"); + ::CGGetActiveDisplayList(m_numDisplays, m_displayIDs, &m_numDisplays); + } +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getNumDisplays(GHOST_TUns8& numDisplays) const +{ + numDisplays = (GHOST_TUns8) m_numDisplays; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getNumDisplaySettings(): only main display is supported"); + + CFArrayRef displayModes; + displayModes = ::CGDisplayAvailableModes(m_displayIDs[display]); + CFIndex numModes = ::CFArrayGetCount(displayModes); + numSettings = (GHOST_TInt32)numModes; + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getDisplaySetting(): only main display is supported"); + + CFArrayRef displayModes; + CGDirectDisplayID d = m_displayIDs[display]; + displayModes = ::CGDisplayAvailableModes(d); + //CFIndex numModes = ::CFArrayGetCount(displayModes);/*unused*/ + //GHOST_TInt32 numSettings = (GHOST_TInt32)numModes; /*unused*/ + CFDictionaryRef displayModeValues = (CFDictionaryRef)::CFArrayGetValueAtIndex(displayModes, index); + + setting.xPixels = getValue(displayModeValues, kCGDisplayWidth); + setting.yPixels = getValue(displayModeValues, kCGDisplayHeight); + setting.bpp = getValue(displayModeValues, kCGDisplayBitsPerPixel); + setting.frequency = getValue(displayModeValues, kCGDisplayRefreshRate); + +#ifdef GHOST_DEBUG + printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency); +#endif // GHOST_DEBUG + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::getCurrentDisplaySetting(): only main display is supported"); + + CFDictionaryRef displayModeValues = ::CGDisplayCurrentMode(m_displayIDs[display]); + + setting.xPixels = getValue(displayModeValues, kCGDisplayWidth); + setting.yPixels = getValue(displayModeValues, kCGDisplayHeight); + setting.bpp = getValue(displayModeValues, kCGDisplayBitsPerPixel); + setting.frequency = getValue(displayModeValues, kCGDisplayRefreshRate); + +#ifdef GHOST_DEBUG + printf("current display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency); +#endif // GHOST_DEBUG + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting) +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): only main display is supported"); + +#ifdef GHOST_DEBUG + printf("GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): requested settings:\n"); + printf(" setting.xPixels=%d\n", setting.xPixels); + printf(" setting.yPixels=%d\n", setting.yPixels); + printf(" setting.bpp=%d\n", setting.bpp); + printf(" setting.frequency=%d\n", setting.frequency); +#endif // GHOST_DEBUG + + CFDictionaryRef displayModeValues = ::CGDisplayBestModeForParametersAndRefreshRate( + m_displayIDs[display], + (size_t)setting.bpp, + (size_t)setting.xPixels, + (size_t)setting.yPixels, + (CGRefreshRate)setting.frequency, + NULL); + +#ifdef GHOST_DEBUG + printf("GHOST_DisplayManagerCarbon::setCurrentDisplaySetting(): switching to:\n"); + printf(" setting.xPixels=%d\n", getValue(displayModeValues, kCGDisplayWidth)); + printf(" setting.yPixels=%d\n", getValue(displayModeValues, kCGDisplayHeight)); + printf(" setting.bpp=%d\n", getValue(displayModeValues, kCGDisplayBitsPerPixel)); + printf(" setting.frequency=%d\n", getValue(displayModeValues, kCGDisplayRefreshRate)); +#endif // GHOST_DEBUG + + CGDisplayErr err = ::CGDisplaySwitchToMode(m_displayIDs[display], displayModeValues); + + return err == CGDisplayNoErr ? GHOST_kSuccess : GHOST_kFailure; +} + + +long GHOST_DisplayManagerCarbon::getValue(CFDictionaryRef values, CFStringRef key) const +{ + CFNumberRef numberValue = (CFNumberRef) CFDictionaryGetValue(values, key); + + if (!numberValue) + { + return -1; + } + + long intValue; + + if (!CFNumberGetValue(numberValue, kCFNumberLongType, &intValue)) + { + return -1; + } + + return intValue; +} + diff --git a/intern/ghost/intern/GHOST_DisplayManagerCarbon.h b/intern/ghost/intern/GHOST_DisplayManagerCarbon.h new file mode 100644 index 00000000000..42a1aa37a5a --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerCarbon.h @@ -0,0 +1,119 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_DisplayManagerCarbon.h + * Declaration of GHOST_DisplayManagerCarbon class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_CARBON_H_ +#define _GHOST_DISPLAY_MANAGER_CARBON_H_ + +#ifndef __APPLE__ +#error Apple only! +#endif // __APPLE__ + +#include "GHOST_DisplayManager.h" + +#define __CARBONSOUND__ +#include + +/** + * Manages system displays (Mac OSX/Carbon implementation). + * @see GHOST_DisplayManager + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManagerCarbon : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerCarbon(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: + /** + * Returns a value from a dictionary. + * @param values Dictionary to return value from. + * @param key Key to return value for. + * @return The value for this key. + */ + long getValue(CFDictionaryRef values, CFStringRef key) const; + + /** Cached number of displays. */ + CGDisplayCount m_numDisplays; + /** Cached display id's for each display. */ + CGDirectDisplayID* m_displayIDs; +}; + + +#endif // _GHOST_DISPLAY_MANAGER_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp new file mode 100644 index 00000000000..3fbacfb1db8 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp @@ -0,0 +1,191 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date September 21, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_DisplayManagerWin32.h" +#include "GHOST_Debug.h" + +// We do not support multiple monitors at the moment +#include +#define COMPILE_MULTIMON_STUBS +#ifndef FREE_WINDOWS +#include +#endif + + +GHOST_DisplayManagerWin32::GHOST_DisplayManagerWin32(void) +{ +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplays(GHOST_TUns8& numDisplays) const +{ + // We do not support multiple monitors at the moment + numDisplays = ::GetSystemMetrics(SM_CMONITORS); + return numDisplays > 0 ? GHOST_kSuccess : GHOST_kFailure; +} + + +/* + * When you call EnumDisplaySettings with iModeNum set to zero, the operating system + * initializes and caches information about the display device. When you call + * EnumDisplaySettings with iModeNum set to a non-zero value, the function returns + * the information that was cached the last time the function was called with iModeNum + * set to zero. + */ +GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getNumDisplaySettings(): only main displlay is supported"); + numSettings = 0; + DEVMODE dm; + while (::EnumDisplaySettings(NULL, numSettings, &dm)) { + numSettings++; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getDisplaySetting(): only main display is supported"); + GHOST_TSuccess success; + DEVMODE dm; + if (::EnumDisplaySettings(NULL, index, &dm)) { +#ifdef GHOST_DEBUG + printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency); +#endif // GHOST_DEBUG + setting.xPixels = dm.dmPelsWidth; + setting.yPixels = dm.dmPelsHeight; + setting.bpp = dm.dmBitsPerPel; + /* When you call the EnumDisplaySettings function, the dmDisplayFrequency member + * may return with the value 0 or 1. These values represent the display hardware's + * default refresh rate. This default rate is typically set by switches on a display + * card or computer motherboard, or by a configuration program that does not use + * Win32 display functions such as ChangeDisplaySettings. + */ + /* First, we tried to explicitly set the frequency to 60 if EnumDisplaySettings + * returned 0 or 1 but this doesn't work since later on an exact match will + * be searched. And this will never happen if we change it to 60. Now we rely + * on the default h/w setting. + */ + setting.frequency = dm.dmDisplayFrequency; + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::getCurrentDisplaySetting(): only main display is supported"); + return getDisplaySetting(kMainDisplay, ENUM_CURRENT_SETTINGS, setting); +} + + +GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting) +{ + GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerWin32::setCurrentDisplaySetting(): only main display is supported"); + + GHOST_DisplaySetting match; + GHOST_TSuccess success = findMatch(display, setting, match); + DEVMODE dm; + int i = 0; + while (::EnumDisplaySettings(NULL, i++, &dm)) { + if ((dm.dmBitsPerPel == match.bpp) && + (dm.dmPelsWidth == match.xPixels) && + (dm.dmPelsHeight == match.yPixels) && + (dm.dmDisplayFrequency == match.frequency)) { + break; + } + } + /* + dm.dmBitsPerPel = match.bpp; + dm.dmPelsWidth = match.xPixels; + dm.dmPelsHeight = match.yPixels; + dm.dmDisplayFrequency = match.frequency; + dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + dm.dmSize = sizeof(DEVMODE); + dm.dmDriverExtra = 0; + */ +#ifdef GHOST_DEBUG + printf("display change: Requested settings:\n"); + printf(" dmBitsPerPel=%d\n", dm.dmBitsPerPel); + printf(" dmPelsWidth=%d\n", dm.dmPelsWidth); + printf(" dmPelsHeight=%d\n", dm.dmPelsHeight); + printf(" dmDisplayFrequency=%d\n", dm.dmDisplayFrequency); +#endif // GHOST_DEBUG + + LONG status = ::ChangeDisplaySettings(&dm, CDS_FULLSCREEN); +#ifdef GHOST_DEBUG + switch (status) + { + case DISP_CHANGE_SUCCESSFUL: + printf("display change: The settings change was successful.\n"); + break; + case DISP_CHANGE_RESTART: + printf("display change: The computer must be restarted in order for the graphics mode to work.\n"); + break; + case DISP_CHANGE_BADFLAGS: + printf("display change: An invalid set of flags was passed in.\n"); + break; + case DISP_CHANGE_BADPARAM: + printf("display change: An invalid parameter was passed in. This can include an invalid flag or combination of flags.\n"); + break; + case DISP_CHANGE_FAILED: + printf("display change: The display driver failed the specified graphics mode.\n"); + break; + case DISP_CHANGE_BADMODE: + printf("display change: The graphics mode is not supported.\n"); + break; + case DISP_CHANGE_NOTUPDATED: + printf("display change: Windows NT: Unable to write settings to the registry.\n"); + break; + default: + printf("display change: Return value invalid\n"); + break; + } +#endif // GHOST_DEBUG + return status == DISP_CHANGE_SUCCESSFUL? GHOST_kSuccess : GHOST_kFailure; +} diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.h b/intern/ghost/intern/GHOST_DisplayManagerWin32.h new file mode 100644 index 00000000000..71fc56257f8 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.h @@ -0,0 +1,104 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_DisplayManagerWin32.h + * Declaration of GHOST_DisplayManagerWin32 class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_WIN32_H_ +#define _GHOST_DISPLAY_MANAGER_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include "GHOST_DisplayManager.h" + + +/** + * Manages system displays (WIN32 implementation). + * @author Maarten Gribnau + * @date September 21, 2001 + */ +class GHOST_DisplayManagerWin32 : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerWin32(void); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting); + +protected: +}; + + +#endif // _GHOST_DISPLAY_MANAGER_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp new file mode 100644 index 00000000000..9695e24e737 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp @@ -0,0 +1,128 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_DisplayManagerX11.h" +#include "GHOST_SystemX11.h" + + + +GHOST_DisplayManagerX11:: +GHOST_DisplayManagerX11( + GHOST_SystemX11 *system +) : + GHOST_DisplayManager(), + m_system(system) +{ + //nothing to do. +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getNumDisplays( + GHOST_TUns8& numDisplays +) const{ + numDisplays = m_system->getNumDisplays(); + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings +) const{ + + // We only have one X11 setting at the moment. + GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n"); + numSettings = GHOST_TInt32(1); + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting +) const { + + GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n"); + GHOST_ASSERT(index < 1, "Requested setting outside of valid range.\n"); + + Display * x_display = m_system->getXDisplay(); + + if (x_display == NULL) { + return GHOST_kFailure; + } + + setting.xPixels = DisplayWidth(x_display, DefaultScreen(x_display)); + setting.yPixels = DisplayHeight(x_display, DefaultScreen(x_display)); + setting.bpp = DefaultDepth(x_display,DefaultScreen(x_display)); + + // Don't think it's possible to get this value from X! + // So let's guess!! + setting.frequency = 60; + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +getCurrentDisplaySetting( + GHOST_TUns8 display, + GHOST_DisplaySetting& setting +) const { + return getDisplaySetting(display,GHOST_TInt32(0),setting); +} + + + GHOST_TSuccess +GHOST_DisplayManagerX11:: +setCurrentDisplaySetting( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting +){ + // This is never going to work robustly in X + // but it's currently part of the full screen interface + + // we fudge it for now. + + return GHOST_kSuccess; +} + + + + diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.h b/intern/ghost/intern/GHOST_DisplayManagerX11.h new file mode 100644 index 00000000000..18226a25e74 --- /dev/null +++ b/intern/ghost/intern/GHOST_DisplayManagerX11.h @@ -0,0 +1,126 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_DisplayManagerX11.h + * Declaration of GHOST_DisplayManagerX11 class. + */ + +#ifndef _GHOST_DISPLAY_MANAGER_X11_H_ +#define _GHOST_DISPLAY_MANAGER_X11_H_ + +#include "GHOST_DisplayManager.h" + + +class GHOST_SystemX11; + +/** + * Manages system displays (X11 implementation). + * @author Laurence Bourn + * @date October 26, 2001 + */ +class GHOST_DisplayManagerX11 : public GHOST_DisplayManager +{ +public: + /** + * Constructor. + */ + GHOST_DisplayManagerX11( + GHOST_SystemX11 *system + ); + + /** + * Returns the number of display devices on this system. + * @param numDisplays The number of displays on this system. + * @return Indication of success. + */ + GHOST_TSuccess + getNumDisplays( + GHOST_TUns8& numDisplays + ) const; + + /** + * Returns the number of display settings for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The number of settings of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getNumDisplaySettings( + GHOST_TUns8 display, + GHOST_TInt32& numSettings + ) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param index The setting index to be returned. + * @param setting The setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getDisplaySetting( + GHOST_TUns8 display, + GHOST_TInt32 index, + GHOST_DisplaySetting& setting + ) const; + + /** + * Returns the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + getCurrentDisplaySetting( + GHOST_TUns8 display, + GHOST_DisplaySetting& setting + ) const; + + /** + * Changes the current setting for this display device. + * @param display The index of the display to query with 0 <= display < getNumDisplays(). + * @param setting The current setting of the display device with this index. + * @return Indication of success. + */ + GHOST_TSuccess + setCurrentDisplaySetting( + GHOST_TUns8 display, + const GHOST_DisplaySetting& setting + ); + +private : + + GHOST_SystemX11 * m_system; +}; + + +#endif // + diff --git a/intern/ghost/intern/GHOST_Event.h b/intern/ghost/intern/GHOST_Event.h new file mode 100644 index 00000000000..e4844f9bab5 --- /dev/null +++ b/intern/ghost/intern/GHOST_Event.h @@ -0,0 +1,110 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_Event.h + * Declaration of GHOST_Event class. + */ + +#ifndef _GHOST_EVENT_H_ +#define _GHOST_EVENT_H_ + +#include "GHOST_IEvent.h" + + +/** + * Base class for events received the operating system. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_Event : public GHOST_IEvent +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param window The generating window (or NULL if system event). + */ + GHOST_Event(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window) + : m_type(type), m_time(msec), m_window(window), m_data(0) + { + } + + /** + * Returns the event type. + * @return The event type. + */ + virtual GHOST_TEventType getType() + { + return m_type; + } + + /** + * Returns the time this event was generated. + * @return The event generation time. + */ + virtual GHOST_TUns64 getTime() + { + return m_time; + } + + /** + * Returns the window this event was generated on, + * or NULL if it is a 'system' event. + * @return The generating window. + */ + virtual GHOST_IWindow* getWindow() + { + return m_window; + } + + /** + * Returns the event data. + * @return The event data. + */ + virtual GHOST_TEventDataPtr getData() + { + return m_data; + } + +protected: + /** Type of this event. */ + GHOST_TEventType m_type; + /** The time this event was generated. */ + GHOST_TUns64 m_time; + /** Pointer to the generating window. */ + GHOST_IWindow* m_window; + /** Pointer to the event data. */ + GHOST_TEventDataPtr m_data; +}; + +#endif // _GHOST_EVENT_H_ + diff --git a/intern/ghost/intern/GHOST_EventButton.h b/intern/ghost/intern/GHOST_EventButton.h new file mode 100644 index 00000000000..c808fd44430 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventButton.h @@ -0,0 +1,70 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventButton.h + * Declaration of GHOST_EventButton class. + */ + +#ifndef _GHOST_EVENT_BUTTON_H_ +#define _GHOST_EVENT_BUTTON_H_ + +#include "GHOST_Event.h" + +/** + * Mouse button event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventButton : public GHOST_Event +{ +public: + /** + * Constructor. + * @param time The time this event was generated. + * @param type The type of this event. + * @param x The x-coordinate of the location the cursor was at at the time of the event. + * @param y The y-coordinate of the location the cursor was at at the time of the event. + * @param buttons The state of the buttons was at at the time of the event. + */ + GHOST_EventButton(GHOST_TUns64 time, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TButtonMask button) + : GHOST_Event(time, type, window) + { + m_buttonEventData.button = button; + m_data = &m_buttonEventData; + } + +protected: + /** The button event data. */ + GHOST_TEventButtonData m_buttonEventData; +}; + +#endif // _GHOST_EVENT_BUTTON_H_ + diff --git a/intern/ghost/intern/GHOST_EventCursor.h b/intern/ghost/intern/GHOST_EventCursor.h new file mode 100644 index 00000000000..a174242653e --- /dev/null +++ b/intern/ghost/intern/GHOST_EventCursor.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventCursor.h + * Declaration of GHOST_EventCursor class. + */ + +#ifndef _GHOST_EVENT_CURSOR_H_ +#define _GHOST_EVENT_CURSOR_H_ + +#include "GHOST_Event.h" + +/** + * Cursor event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventCursor : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param x The x-coordinate of the location the cursor was at at the time of the event. + * @param y The y-coordinate of the location the cursor was at at the time of the event. + */ + GHOST_EventCursor(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TInt32 x, GHOST_TInt32 y) + : GHOST_Event(msec, type, window) + { + m_cursorEventData.x = x; + m_cursorEventData.y = y; + m_data = &m_cursorEventData; + } + +protected: + /** The x,y-coordinates of the cursor position. */ + GHOST_TEventCursorData m_cursorEventData; +}; + + +#endif // _GHOST_EVENT_CURSOR_H_ + diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h new file mode 100644 index 00000000000..b170d5a9a48 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventKey.h @@ -0,0 +1,84 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventKey.h + * Declaration of GHOST_EventKey class. + */ + +#ifndef _GHOST_EVENT_KEY_H_ +#define _GHOST_EVENT_KEY_H_ + +#include "GHOST_Event.h" + +/** + * Key event. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventKey : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of key event. + * @param key The key code of the key. + */ + GHOST_EventKey(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TKey key) + : GHOST_Event(msec, type, window) + { + m_keyEventData.key = key; + m_keyEventData.ascii = '\0'; + m_data = &m_keyEventData; + } + + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of key event. + * @param key The key code of the key. + * @param ascii The ascii code for the key event. + */ + GHOST_EventKey(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TKey key, char ascii) + : GHOST_Event(msec, type, window) + { + m_keyEventData.key = key; + m_keyEventData.ascii = ascii; + m_data = &m_keyEventData; + } + +protected: + /** The key event data. */ + GHOST_TEventKeyData m_keyEventData; +}; + +#endif // _GHOST_EVENT_KEY_H_ + diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp new file mode 100644 index 00000000000..ba20cce12fd --- /dev/null +++ b/intern/ghost/intern/GHOST_EventManager.cpp @@ -0,0 +1,261 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 14, 2001 + */ + +#include "GHOST_EventManager.h" +#include +#include "GHOST_Debug.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + + +GHOST_EventManager::GHOST_EventManager() +{ +} + + +GHOST_EventManager::~GHOST_EventManager() +{ + disposeEvents(); +} + + +GHOST_TUns32 GHOST_EventManager::getNumEvents() +{ + return (GHOST_TUns32) m_events.size(); +} + + +GHOST_TUns32 GHOST_EventManager::getNumEvents(GHOST_TEventType type) +{ + GHOST_TUns32 numEvents = 0; + TEventStack::iterator p; + for (p = m_events.begin(); p != m_events.end(); p++) { + if ((*p)->getType() == type) { + numEvents++; + } + } + return numEvents; +} + + +GHOST_IEvent* GHOST_EventManager::peekEvent() +{ + GHOST_IEvent* event = 0; + if (m_events.size() > 0) { + event = m_events.back(); + } + return event; +} + + +GHOST_TSuccess GHOST_EventManager::pushEvent(GHOST_IEvent* event) +{ + GHOST_TSuccess success; + GHOST_ASSERT(event, "invalid event"); + if (m_events.size() < m_events.max_size()) { + m_events.push_front(event); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +bool GHOST_EventManager::dispatchEvent(GHOST_IEvent* event) +{ + bool handled; + if (event) { + handled = true; + TConsumerVector::iterator iter; + for (iter = m_consumers.begin(); iter != m_consumers.end(); iter++) { + if ((*iter)->processEvent(event)) { + handled = false; + } + } + } + else { + handled = false; + } + return handled; +} + + +bool GHOST_EventManager::dispatchEvent() +{ + GHOST_IEvent* event = popEvent(); + bool handled = false; + if (event) { + handled = dispatchEvent(event); + delete event; + } + return handled; +} + + +bool GHOST_EventManager::dispatchEvents() +{ + bool handled; + if (getNumEvents()) { + handled = true; + while (getNumEvents()) { + if (!dispatchEvent()) { + handled = false; + } + } + } + else { + handled = false; + } + return handled; +} + + +GHOST_TSuccess GHOST_EventManager::addConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + GHOST_ASSERT(consumer, "invalid consumer"); + + // Check to see whether the consumer is already in our list + TConsumerVector::const_iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer); + + if (iter == m_consumers.end()) { + // Add the consumer + m_consumers.push_back(consumer); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_EventManager::removeConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + GHOST_ASSERT(consumer, "invalid consumer"); + + // Check to see whether the consumer is in our list + TConsumerVector::iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer); + + if (iter != m_consumers.end()) { + // Remove the consumer + m_consumers.erase(iter); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +void GHOST_EventManager::removeWindowEvents(GHOST_IWindow* window) +{ + TEventStack::iterator iter; + iter = m_events.begin(); + while (iter != m_events.end()) + { + GHOST_IEvent* event = *iter; + if (event->getWindow() == window) + { + GHOST_PRINT("GHOST_EventManager::removeWindowEvents(): removing event\n"); + /* + * Found an event for this window, remove it. + * The iterator will become invalid. + */ + delete event; + m_events.erase(iter); + iter = m_events.begin(); + } + else + { + iter++; + } + } +} + +void GHOST_EventManager::removeTypeEvents(GHOST_TEventType type, GHOST_IWindow* window) +{ + TEventStack::iterator iter; + iter = m_events.begin(); + while (iter != m_events.end()) + { + GHOST_IEvent* event = *iter; + if ((event->getType() == type) && (!window || (event->getWindow() == window))) + { + GHOST_PRINT("GHOST_EventManager::removeTypeEvents(): removing event\n"); + /* + * Found an event of this type for the window, remove it. + * The iterator will become invalid. + */ + delete event; + m_events.erase(iter); + iter = m_events.begin(); + } + else + { + iter++; + } + } +} + + +GHOST_IEvent* GHOST_EventManager::popEvent() +{ + GHOST_IEvent* event = peekEvent(); + if (event) { + m_events.pop_back(); + } + return event; +} + + +void GHOST_EventManager::disposeEvents() +{ + while (m_events.size() > 0) { + GHOST_ASSERT(m_events[0], "invalid event"); + delete m_events[0]; + m_events.pop_front(); + } +} diff --git a/intern/ghost/intern/GHOST_EventManager.h b/intern/ghost/intern/GHOST_EventManager.h new file mode 100644 index 00000000000..068ded8ddee --- /dev/null +++ b/intern/ghost/intern/GHOST_EventManager.h @@ -0,0 +1,181 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventManager.h + * Declaration of GHOST_EventManager class. + */ + +#ifndef _GHOST_EVENT_MANAGER_H_ +#define _GHOST_EVENT_MANAGER_H_ + +#ifdef WIN32 +#pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif // WIN32 + +#include +#include + +#include "GHOST_IEventConsumer.h" + + +/** + * Manages an event stack and a list of event consumers. + * The stack works on a FIFO (First In First Out) basis. + * Events are pushed on the front of the stack and retrieved from the back. + * Ownership of the event is transferred to the event manager as soon as an event is pushed. + * Ownership of the event is transferred from the event manager as soon as an event is popped. + * Events can be dispatched to the event consumers. + */ +class GHOST_EventManager +{ +public: + /** + * Constructor. + */ + GHOST_EventManager(); + + /** + * Destructor. + */ + virtual ~GHOST_EventManager(); + + /** + * Returns the number of events currently on the stack. + * @return The number of events on the stack. + */ + virtual GHOST_TUns32 getNumEvents(); + + /** + * Returns the number of events of a certain type currently on the stack. + * @param type The type of events to be counted. + * @return The number of events on the stack of this type. + */ + virtual GHOST_TUns32 getNumEvents(GHOST_TEventType type); + + /** + * Return the event at the top of the stack without removal. + * Do not delete the event! + * @return The event at the top of the stack. + */ + virtual GHOST_IEvent* peekEvent(); + + /** + * Pushes an event on the stack. + * To dispatch it, call dispatchEvent() or dispatchEvents(). + * Do not delete the event! + * @param event The event to push on the stack. + */ + virtual GHOST_TSuccess pushEvent(GHOST_IEvent* event); + + /** + * Dispatches the given event directly, bypassing the event stack. + * @return Indication as to whether any of the consumers handled the event. + */ + virtual bool dispatchEvent(GHOST_IEvent* event); + + /** + * Dispatches the event at the back of the stack. + * The event will be removed from the stack. + * @return Indication as to whether any of the consumers handled the event. + */ + virtual bool dispatchEvent(); + + /** + * Dispatches all the events on the stack. + * The event stack will be empty afterwards. + * @return Indication as to whether any of the consumers handled the events. + */ + virtual bool dispatchEvents(); + + /** + * Adds a consumer to the list of event consumers. + * @param consumer The consumer added to the list. + * @return Indication as to whether addition has succeeded. + */ + virtual GHOST_TSuccess addConsumer(GHOST_IEventConsumer* consumer); + + /** + * Removes a consumer from the list of event consumers. + * @param consumer The consumer removed from the list. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeConsumer(GHOST_IEventConsumer* consumer); + + /** + * Removes all events for a window from the stack. + * @param window The window to remove events for. + */ + virtual void + removeWindowEvents( + GHOST_IWindow* window + ); + + /** + * Removes all events of a certain type from the stack. + * The window parameter is optional. If non-null, the routine will remove + * events only associated with that window. + * @param type The type of events to be removed. + * @param window The window to remove the events for. + */ + virtual void + removeTypeEvents( + GHOST_TEventType type, + GHOST_IWindow* window = 0 + ); + +protected: + /** + * Returns the event at the top of the stack and removes it. + * Delete the event after use! + * @return The event at the top of the stack. + */ + virtual GHOST_IEvent* popEvent(); + + /** + * Removes all events from the stack. + */ + virtual void disposeEvents(); + + /** A stack with events. */ + typedef std::deque TEventStack; + + /** The event stack. */ + std::deque m_events; + + /** A vector with event consumers. */ + typedef std::vector TConsumerVector; + + /** The list with event consumers. */ + TConsumerVector m_consumers; +}; + +#endif // _GHOST_EVENT_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp new file mode 100644 index 00000000000..ad65d1fbb18 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventPrinter.cpp @@ -0,0 +1,282 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventPrinter.h + * Declaration of GHOST_EventPrinter class. + */ + +#include "GHOST_EventPrinter.h" +#include +#include "GHOST_EventKey.h" +#include "GHOST_Debug.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + + +bool GHOST_EventPrinter::processEvent(GHOST_IEvent* event) +{ + bool handled = true; + + GHOST_ASSERT(event, "event==0"); + + if (event->getType() == GHOST_kEventWindowUpdate) return false; + + //std::cout << "GHOST_EventPrinter::processEvent, time: " << (GHOST_TInt32)event->getTime() << ", type: "; + switch (event->getType()) { + case GHOST_kEventUnknown: + //std::cout << "GHOST_kEventUnknown"; handled = false; + break; + + case GHOST_kEventButtonUp: + { + GHOST_TEventButtonData* buttonData = (GHOST_TEventButtonData*)((GHOST_IEvent*)event)->getData(); + //std::cout << "GHOST_kEventCursorButtonUp, button: " << buttonData->button; + } + break; + case GHOST_kEventButtonDown: + { + GHOST_TEventButtonData* buttonData = (GHOST_TEventButtonData*)((GHOST_IEvent*)event)->getData(); + //std::cout << "GHOST_kEventButtonDown, button: " << buttonData->button; + } + break; + + case GHOST_kEventWheel: + { + GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*)((GHOST_IEvent*)event)->getData(); + //std::cout << "GHOST_kEventWheel, z: " << wheelData->z; + } + break; + + case GHOST_kEventCursorMove: + { + GHOST_TEventCursorData* cursorData = (GHOST_TEventCursorData*)((GHOST_IEvent*)event)->getData(); + //std::cout << "GHOST_kEventCursorMove, (x,y): (" << cursorData->x << "," << cursorData->y << ")"; + } + break; + + case GHOST_kEventKeyUp: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*)((GHOST_IEvent*)event)->getData(); + STR_String str; + getKeyString(keyData->key, str); + //std::cout << "GHOST_kEventKeyUp, key: " << str.Ptr(); + } + break; + case GHOST_kEventKeyDown: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*)((GHOST_IEvent*)event)->getData(); + STR_String str; + getKeyString(keyData->key, str); + //std::cout << "GHOST_kEventKeyDown, key: " << str.Ptr(); + } + break; + + case GHOST_kEventQuit: + //std::cout << "GHOST_kEventQuit"; + break; + case GHOST_kEventWindowClose: + //std::cout << "GHOST_kEventWindowClose"; + break; + case GHOST_kEventWindowActivate: + //std::cout << "GHOST_kEventWindowActivate"; + break; + case GHOST_kEventWindowDeactivate: + //std::cout << "GHOST_kEventWindowDeactivate"; + break; + case GHOST_kEventWindowUpdate: + //std::cout << "GHOST_kEventWindowUpdate"; + break; + case GHOST_kEventWindowSize: + //std::cout << "GHOST_kEventWindowSize"; + break; + + default: + //std::cout << "not found"; handled = false; + break; + } + //std::cout << "\n"; + return handled; +} + + +void GHOST_EventPrinter::getKeyString(GHOST_TKey key, STR_String& str) const +{ + if ((key >= GHOST_kKeyComma) && (key <= GHOST_kKeyRightBracket)) { + str = ((char)key); + } else if ((key >= GHOST_kKeyNumpad0) && (key <= GHOST_kKeyNumpad9)) { + int number = key - GHOST_kKeyNumpad0; + STR_String numberStr (number); + str = "Numpad"; + str += numberStr; +#if defined(__sun__) || defined(__sun) + } else if (key == 268828432) { /* solaris keyboards are messed up */ + /* This should really test XK_F11 but that doesn't work */ + str = "F11"; + } else if (key == 268828433) { /* solaris keyboards are messed up */ + /* This should really test XK_F12 but that doesn't work */ + str = "F12"; +#endif + } else if ((key >= GHOST_kKeyF1) && (key <= GHOST_kKeyF24)) { + int number = key - GHOST_kKeyF1 + 1; + STR_String numberStr (number); + str = "F"; + str += numberStr; + } else { + switch (key) + { + case GHOST_kKeyBackSpace: + str = "BackSpace"; + break; + case GHOST_kKeyTab: + str = "Tab"; + break; + case GHOST_kKeyLinefeed: + str = "Linefeed"; + break; + case GHOST_kKeyClear: + str = "Clear"; + break; + case GHOST_kKeyEnter: + str = "Enter"; + break; + case GHOST_kKeyEsc: + str = "Esc"; + break; + case GHOST_kKeySpace: + str = "Space"; + break; + case GHOST_kKeyQuote: + str = "Quote"; + break; + case GHOST_kKeyBackslash: + str = "\\"; + break; + case GHOST_kKeyAccentGrave: + str = "`"; + break; + case GHOST_kKeyLeftShift: + str = "LeftShift"; + break; + case GHOST_kKeyRightShift: + str = "RightShift"; + break; + case GHOST_kKeyLeftControl: + str = "LeftControl"; + break; + case GHOST_kKeyRightControl: + str = "RightControl"; + break; + case GHOST_kKeyLeftAlt: + str = "LeftAlt"; + break; + case GHOST_kKeyRightAlt: + str = "RightAlt"; + break; + case GHOST_kKeyCommand: + // APPLE only! + str = "Command"; + break; + case GHOST_kKeyGrLess: + // PC german! + str = "GrLess"; + break; + case GHOST_kKeyCapsLock: + str = "CapsLock"; + break; + case GHOST_kKeyNumLock: + str = "NumLock"; + break; + case GHOST_kKeyScrollLock: + str = "ScrollLock"; + break; + case GHOST_kKeyLeftArrow: + str = "LeftArrow"; + break; + case GHOST_kKeyRightArrow: + str = "RightArrow"; + break; + case GHOST_kKeyUpArrow: + str = "UpArrow"; + break; + case GHOST_kKeyDownArrow: + str = "DownArrow"; + break; + case GHOST_kKeyPrintScreen: + str = "PrintScreen"; + break; + case GHOST_kKeyPause: + str = "Pause"; + break; + case GHOST_kKeyInsert: + str = "Insert"; + break; + case GHOST_kKeyDelete: + str = "Delete"; + break; + case GHOST_kKeyHome: + str = "Home"; + break; + case GHOST_kKeyEnd: + str = "End"; + break; + case GHOST_kKeyUpPage: + str = "UpPage"; + break; + case GHOST_kKeyDownPage: + str = "DownPage"; + break; + case GHOST_kKeyNumpadPeriod: + str = "NumpadPeriod"; + break; + case GHOST_kKeyNumpadEnter: + str = "NumpadEnter"; + break; + case GHOST_kKeyNumpadPlus: + str = "NumpadPlus"; + break; + case GHOST_kKeyNumpadMinus: + str = "NumpadMinus"; + break; + case GHOST_kKeyNumpadAsterisk: + str = "NumpadAsterisk"; + break; + case GHOST_kKeyNumpadSlash: + str = "NumpadSlash"; + break; + default: + str = "unknown"; + break; + } + } +} + diff --git a/intern/ghost/intern/GHOST_EventPrinter.h b/intern/ghost/intern/GHOST_EventPrinter.h new file mode 100644 index 00000000000..9838d2fb6d5 --- /dev/null +++ b/intern/ghost/intern/GHOST_EventPrinter.h @@ -0,0 +1,67 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventPrinter.h + * Declaration of GHOST_EventPrinter class. + */ + +#ifndef _GHOST_EVENT_PRINTER_H_ +#define _GHOST_EVENT_PRINTER_H_ + +#include "GHOST_IEventConsumer.h" + +#include "STR_String.h" + +/** + * An Event consumer that prints all the events to standard out. + * Really useful when debugging. + */ +class GHOST_EventPrinter : public GHOST_IEventConsumer +{ +public: + /** + * Prints all the events received to std out. + * @param event The event that can be handled or not. + * @return Indication as to whether the event was handled. + */ + virtual bool processEvent(GHOST_IEvent* event); + +protected: + /** + * Converts GHOST key code to a readable string. + * @param key The GHOST key code to convert. + * @param str The GHOST key code converted to a readable string. + */ + void getKeyString(GHOST_TKey key, STR_String& str) const; +}; + +#endif // _GHOST_EVENT_PRINTER_H_ + diff --git a/intern/ghost/intern/GHOST_EventWheel.h b/intern/ghost/intern/GHOST_EventWheel.h new file mode 100644 index 00000000000..7776a1778db --- /dev/null +++ b/intern/ghost/intern/GHOST_EventWheel.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_EventWheel.h + * Declaration of GHOST_EventWheel class. + */ + +#ifndef _GHOST_EVENT_WHEEL_H_ +#define _GHOST_EVENT_WHEEL_H_ + +#include "GHOST_Event.h" + +/** + * Mouse wheel event. + * The displacement of the mouse wheel is counted in ticks. + * A positive value means the wheel is turned away from the user. + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_EventWheel : public GHOST_Event +{ +public: + /** + * Constructor. + * @param msec The time this event was generated. + * @param type The type of this event. + * @param z The displacement of the mouse wheel. + */ + GHOST_EventWheel(GHOST_TUns64 msec, GHOST_IWindow* window, GHOST_TInt32 z) + : GHOST_Event(msec, GHOST_kEventWheel, window) + { + m_wheelEventData.z = z; + m_data = &m_wheelEventData; + } + +protected: + /** The z-displacement of the mouse wheel. */ + GHOST_TEventWheelData m_wheelEventData; +}; + + +#endif // _GHOST_EVENT_WHEEL_H_ + diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp new file mode 100644 index 00000000000..677978973aa --- /dev/null +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -0,0 +1,102 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_ISystem.h" + +#ifdef WIN32 +# include "GHOST_SystemWin32.h" +#else +# ifdef __APPLE__ +# include "GHOST_SystemCarbon.h" +# else +# include "GHOST_SystemX11.h" +# endif +#endif + + +GHOST_ISystem* GHOST_ISystem::m_system = 0; + + +GHOST_TSuccess GHOST_ISystem::createSystem() +{ + GHOST_TSuccess success; + if (!m_system) { +#ifdef WIN32 + m_system = new GHOST_SystemWin32 (); +#else +# ifdef __APPLE__ + m_system = new GHOST_SystemCarbon (); +# else + m_system = new GHOST_SystemX11 (); +# endif +#endif + success = m_system != 0 ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + if (success) { + success = m_system->init(); + } + return success; +} + +GHOST_TSuccess GHOST_ISystem::disposeSystem() +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (m_system) { + delete m_system; + m_system = 0; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_ISystem* GHOST_ISystem::getSystem() +{ + return m_system; +} + diff --git a/intern/ghost/intern/GHOST_ModifierKeys.cpp b/intern/ghost/intern/GHOST_ModifierKeys.cpp new file mode 100644 index 00000000000..36293d87c26 --- /dev/null +++ b/intern/ghost/intern/GHOST_ModifierKeys.cpp @@ -0,0 +1,142 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_ModifierKeys.h" + + +GHOST_ModifierKeys::GHOST_ModifierKeys() +{ + clear(); +} + +GHOST_ModifierKeys::~GHOST_ModifierKeys() {} + + +GHOST_TKey GHOST_ModifierKeys::getModifierKeyCode(GHOST_TModifierKeyMask mask) +{ + GHOST_TKey key; + switch (mask) { + case GHOST_kModifierKeyLeftShift: key = GHOST_kKeyLeftShift; break; + case GHOST_kModifierKeyRightShift: key = GHOST_kKeyRightShift; break; + case GHOST_kModifierKeyLeftAlt: key = GHOST_kKeyLeftAlt; break; + case GHOST_kModifierKeyRightAlt: key = GHOST_kKeyRightAlt; break; + case GHOST_kModifierKeyLeftControl: key = GHOST_kKeyLeftControl; break; + case GHOST_kModifierKeyRightControl: key = GHOST_kKeyRightControl; break; + case GHOST_kModifierKeyCommand: key = GHOST_kKeyCommand; break; + default: + // Should not happen + key = GHOST_kKeyUnknown; + break; + } + return key; +} + + +bool GHOST_ModifierKeys::get(GHOST_TModifierKeyMask mask) const +{ + switch (mask) { + case GHOST_kModifierKeyLeftShift: + return m_LeftShift; + case GHOST_kModifierKeyRightShift: + return m_RightShift; + case GHOST_kModifierKeyLeftAlt: + return m_LeftAlt; + case GHOST_kModifierKeyRightAlt: + return m_RightAlt; + case GHOST_kModifierKeyLeftControl: + return m_LeftControl; + case GHOST_kModifierKeyRightControl: + return m_RightControl; + case GHOST_kModifierKeyCommand: + return m_Command; + default: + return false; + } +} + + +void GHOST_ModifierKeys::set(GHOST_TModifierKeyMask mask, bool down) +{ + switch (mask) { + case GHOST_kModifierKeyLeftShift: + m_LeftShift = down; break; + case GHOST_kModifierKeyRightShift: + m_RightShift = down; break; + case GHOST_kModifierKeyLeftAlt: + m_LeftAlt = down; break; + case GHOST_kModifierKeyRightAlt: + m_RightAlt = down; break; + case GHOST_kModifierKeyLeftControl: + m_LeftControl = down; break; + case GHOST_kModifierKeyRightControl: + m_RightControl = down; break; + case GHOST_kModifierKeyCommand: + m_Command = down; break; + default: + break; + } +} + + +void GHOST_ModifierKeys::clear() +{ + m_LeftShift = false; + m_RightShift = false; + m_LeftAlt = false; + m_RightAlt = false; + m_LeftControl = false; + m_RightControl = false; + m_Command = false; +} + + +bool GHOST_ModifierKeys::equals(const GHOST_ModifierKeys& keys) const +{ + return (m_LeftShift == keys.m_LeftShift) && + (m_RightShift == keys.m_RightShift) && + (m_LeftAlt == keys.m_LeftAlt) && + (m_RightAlt == keys.m_RightAlt) && + (m_LeftControl == keys.m_LeftControl) && + (m_RightControl == keys.m_RightControl) && + (m_Command == keys.m_Command); +} diff --git a/intern/ghost/intern/GHOST_ModifierKeys.h b/intern/ghost/intern/GHOST_ModifierKeys.h new file mode 100644 index 00000000000..6b26dd5829e --- /dev/null +++ b/intern/ghost/intern/GHOST_ModifierKeys.h @@ -0,0 +1,107 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_ModifierKeys.h + * Declaration of GHOST_ModifierKeys struct. + */ + +#ifndef _GHOST_MODIFIER_KEYS_H_ +#define _GHOST_MODIFIER_KEYS_H_ + +#include "GHOST_Types.h" + +/** + * Stores the state of modifier keys. + * Discriminates between left and right modifier keys. + * @author Maarten Gribnau + * @date May 17, 2001 + */ +struct GHOST_ModifierKeys +{ + /** + * Constructor. + */ + GHOST_ModifierKeys(); + + virtual ~GHOST_ModifierKeys(); + + /** + * Returns the modifier key's key code from a modifier key mask. + * @param mask The mask of the modifier key. + * @return The modifier key's key code. + */ + static GHOST_TKey getModifierKeyCode(GHOST_TModifierKeyMask mask); + + + /** + * Returns the state of a single modifier key. + * @param mask. Key state to return. + * @return The state of the key (pressed == true). + */ + virtual bool get(GHOST_TModifierKeyMask mask) const; + + /** + * Updates the state of a single modifier key. + * @param mask. Key state to update. + * @param down. The new state of the key. + */ + virtual void set(GHOST_TModifierKeyMask mask, bool down); + + /** + * Sets the state of all modifier keys to up. + */ + virtual void clear(); + + /** + * Determines whether to modifier key states are equal. + * @param keys. The modifier key state to compare to. + * @return Indication of equality. + */ + virtual bool equals(const GHOST_ModifierKeys& keys) const; + + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftShift : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightShift : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftAlt : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightAlt : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_LeftControl : 1; + /** Bitfield that stores the appropriate key state. */ + GHOST_TUns8 m_RightControl : 1; + /** Bitfield that stores the appropriate key state. APPLE only! */ + GHOST_TUns8 m_Command : 1; +}; + +#endif // _GHOST_MODIFIER_KEYS_H_ + diff --git a/intern/ghost/intern/GHOST_Rect.cpp b/intern/ghost/intern/GHOST_Rect.cpp new file mode 100644 index 00000000000..70773fe1497 --- /dev/null +++ b/intern/ghost/intern/GHOST_Rect.cpp @@ -0,0 +1,144 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_Rect.h" + + + +void GHOST_Rect::inset(GHOST_TInt32 i) +{ + if (i > 0) { + // Grow the rectangle + m_l -= i; + m_r += i; + m_t -= i; + m_b += i; + } + else if (i < 0) { + // Shrink the rectangle, check for insets larger than half the size + GHOST_TInt32 i2 = i * 2; + if (getWidth() > i2) { + m_l += i; + m_r -= i; + } + else { + m_l = m_l + ((m_r - m_l) / 2); + m_r = m_l; + } + if (getHeight() > i2) { + m_t += i; + m_b -= i; + } + else { + m_t = m_t + ((m_b - m_t) / 2); + m_b = m_t; + } + } +} + + +GHOST_TVisibility GHOST_Rect::getVisibility(GHOST_Rect& r) const +{ + bool lt = isInside(r.m_l, r.m_t); + bool rt = isInside(r.m_r, r.m_t); + bool lb = isInside(r.m_l, r.m_b); + bool rb = isInside(r.m_r, r.m_b); + GHOST_TVisibility v; + if (lt && rt && lb && rb) { + // All points inside, rectangle is inside this + v = GHOST_kFullyVisible; + } + else if (!(lt || rt || lb || rb)) { + // None of the points inside + // Check to see whether the rectangle is larger than this one + if ((r.m_l < m_l) && (r.m_t < m_t) && (r.m_r > m_r) && (r.m_b > m_b)) { + v = GHOST_kPartiallyVisible; + } + else { + v = GHOST_kNotVisible; + } + } + else { + // Some of the points inside, rectangle is partially inside + v = GHOST_kPartiallyVisible; + } + return v; +} + + +void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy) +{ + GHOST_TInt32 offset = cx - (m_l + (m_r - m_l)/2); + m_l += offset; + m_r += offset; + offset = cy - (m_t + (m_b - m_t)/2); + m_t += offset; + m_b += offset; +} + +void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy, GHOST_TInt32 w, GHOST_TInt32 h) +{ + long w_2, h_2; + + w_2 = w >> 1; + h_2 = h >> 1; + m_l = cx - w_2; + m_t = cy - h_2; + m_r = m_l + w; + m_b = m_t + h; +} + +bool GHOST_Rect::clip(GHOST_Rect& r) const +{ + bool clipped = false; + if (r.m_l < m_l) { + r.m_l = m_l; + clipped = true; + } + if (r.m_t < m_t) { + r.m_t = m_t; + clipped = true; + } + if (r.m_r > m_r) { + r.m_r = m_r; + clipped = true; + } + if (r.m_b > m_b) { + r.m_b = m_b; + clipped = true; + } + return clipped; +} + diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp new file mode 100644 index 00000000000..d91658787b9 --- /dev/null +++ b/intern/ghost/intern/GHOST_System.cpp @@ -0,0 +1,331 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_System.h" + +#include + +#include "GHOST_DisplayManager.h" +#include "GHOST_EventManager.h" +#include "GHOST_TimerTask.h" +#include "GHOST_TimerManager.h" +#include "GHOST_WindowManager.h" + + +GHOST_System::GHOST_System() +: m_displayManager(0), m_timerManager(0), m_windowManager(0), m_eventManager(0) +{ +} + + +GHOST_System::~GHOST_System() +{ + exit(); +} + + +GHOST_TUns64 GHOST_System::getMilliSeconds() const +{ + GHOST_TUns64 millis = ::clock(); + if (CLOCKS_PER_SEC != 1000) { + millis *= 1000; + millis /= CLOCKS_PER_SEC; + } + return millis; +} + + +GHOST_ITimerTask* GHOST_System::installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData) +{ + GHOST_TUns64 millis = getMilliSeconds(); + GHOST_TimerTask* timer = new GHOST_TimerTask(millis+delay, interval, timerProc, userData); + if (timer) { + if (m_timerManager->addTimer(timer) == GHOST_kSuccess) { + // Check to see whether we need to fire the timer right away + m_timerManager->fireTimers(millis); + } + else { + delete timer; + timer = 0; + } + } + return timer; +} + + +GHOST_TSuccess GHOST_System::removeTimer(GHOST_ITimerTask* timerTask) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (timerTask) { + success = m_timerManager->removeTimer((GHOST_TimerTask*)timerTask); + } + return success; +} + + +GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success; + + /* + * Remove all pending events for the window. + */ + if (m_windowManager->getWindowFound(window)) { + m_eventManager->removeWindowEvents(window); + } + if (window == m_windowManager->getFullScreenWindow()) { + success = endFullScreen(); + } + else { + if (m_windowManager->getWindowFound(window)) { + success = m_windowManager->removeWindow(window); + if (success) { + delete window; + } + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +bool GHOST_System::validWindow(GHOST_IWindow* window) +{ + return m_windowManager->getWindowFound(window); +} + + +GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(m_windowManager, "GHOST_System::beginFullScreen(): invalid window manager") + if (m_displayManager) { + if (!m_windowManager->getFullScreen()) { + m_displayManager->getCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + + //GHOST_PRINT("GHOST_System::beginFullScreen(): activating new display settings\n"); + success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, setting); + if (success == GHOST_kSuccess) { + //GHOST_PRINT("GHOST_System::beginFullScreen(): creating full-screen window\n"); + success = createFullScreenWindow((GHOST_Window**)window, stereoVisual); + if (success == GHOST_kSuccess) { + m_windowManager->beginFullScreen(*window, stereoVisual); + } + else { + m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + } + } + } + } + if (success == GHOST_kFailure) { + GHOST_PRINT("GHOST_System::beginFullScreen(): could not enter full-screen mode\n"); + } + return success; +} + + +GHOST_TSuccess GHOST_System::endFullScreen(void) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(m_windowManager, "GHOST_System::endFullScreen(): invalid window manager") + if (m_windowManager->getFullScreen()) { + //GHOST_IWindow* window = m_windowManager->getFullScreenWindow(); + //GHOST_PRINT("GHOST_System::endFullScreen(): leaving window manager full-screen mode\n"); + success = m_windowManager->endFullScreen(); + GHOST_ASSERT(m_displayManager, "GHOST_System::endFullScreen(): invalid display manager") + //GHOST_PRINT("GHOST_System::endFullScreen(): leaving full-screen mode\n"); + success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, m_preFullScreenSetting); + } + else { + success = GHOST_kFailure; + } + return success; +} + + +bool GHOST_System::getFullScreen(void) +{ + bool fullScreen; + if (m_windowManager) { + fullScreen = m_windowManager->getFullScreen(); + } + else { + fullScreen = false; + } + return fullScreen; +} + + +bool GHOST_System::dispatchEvents() +{ + bool handled; + if (m_eventManager) { + handled = m_eventManager->dispatchEvents(); + } + else { + handled = false; + } + + m_timerManager->fireTimers(getMilliSeconds()); + return handled; +} + + +GHOST_TSuccess GHOST_System::addEventConsumer(GHOST_IEventConsumer* consumer) +{ + GHOST_TSuccess success; + if (m_eventManager) { + success = m_eventManager->addConsumer(consumer); + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent* event) +{ + GHOST_TSuccess success; + if (m_eventManager) { + success = m_eventManager->pushEvent(event); + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const +{ + GHOST_ModifierKeys keys; + // Get the state of all modifier keys + GHOST_TSuccess success = getModifierKeys(keys); + if (success) { + // Isolate the state of the key requested + isDown = keys.get(mask); + } + return success; +} + + +GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool& isDown) const +{ + GHOST_Buttons buttons; + // Get the state of all mouse buttons + GHOST_TSuccess success = getButtons(buttons); + if (success) { + // Isolate the state of the mouse button requested + isDown = buttons.get(mask); + } + return success; +} + + +GHOST_TSuccess GHOST_System::init() +{ + m_timerManager = new GHOST_TimerManager (); + m_windowManager = new GHOST_WindowManager (); + m_eventManager = new GHOST_EventManager (); +#ifdef GHOST_DEBUG + if (m_eventManager) { + m_eventManager->addConsumer(&m_eventPrinter); + } +#endif // GHOST_DEBUG + + if (m_timerManager && m_windowManager && m_eventManager) { + return GHOST_kSuccess; + } else { + return GHOST_kFailure; + } +} + + +GHOST_TSuccess GHOST_System::exit() +{ + if (getFullScreen()) { + endFullScreen(); + } + if (m_displayManager) { + delete m_displayManager; + m_displayManager = 0; + } + if (m_windowManager) { + delete m_windowManager; + m_windowManager = 0; + } + if (m_timerManager) { + delete m_timerManager; + m_timerManager = 0; + } + if (m_eventManager) { + delete m_eventManager; + m_eventManager = 0; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window** window, const bool stereoVisual) +{ + GHOST_TSuccess success; + GHOST_ASSERT(m_displayManager, "GHOST_System::createFullScreenWindow(): invalid display manager") + GHOST_DisplaySetting settings; + + success = m_displayManager->getCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, settings); + if (success) { + //GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n"); + *window = (GHOST_Window*)createWindow( + STR_String (""), + 0, 0, settings.xPixels, settings.yPixels, + GHOST_kWindowStateFullScreen, + GHOST_kDrawingContextTypeOpenGL, + stereoVisual); + success = *window == 0 ? GHOST_kFailure : GHOST_kSuccess; + } + return success; +} diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h new file mode 100644 index 00000000000..85e7b2d6b44 --- /dev/null +++ b/intern/ghost/intern/GHOST_System.h @@ -0,0 +1,318 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_System.h + * Declaration of GHOST_System class. + */ + +#ifndef _GHOST_SYSTEM_H_ +#define _GHOST_SYSTEM_H_ + +#include "GHOST_ISystem.h" + +#include "GHOST_Debug.h" +#include "GHOST_Buttons.h" +#include "GHOST_ModifierKeys.h" +#include "GHOST_EventManager.h" +#ifdef GHOST_DEBUG +#include "GHOST_EventPrinter.h" +#endif // GHOST_DEBUG + +class GHOST_DisplayManager; +class GHOST_Event; +class GHOST_TimerManager; +class GHOST_Window; +class GHOST_WindowManager; + +/** + * Implementation of platform independent functionality of the GHOST_ISystem + * interface. + * GHOST_System is an abstract class because not all methods of GHOST_ISystem + * are implemented. + * @see GHOST_ISystem. + * @author Maarten Gribnau + * @date May 7, 2001 + */ +class GHOST_System : public GHOST_ISystem +{ +protected: + /** + * Constructor. + * Protected default constructor to force use of static createSystem member. + */ + GHOST_System(); + + /** + * Destructor. + * Protected default constructor to force use of static dispose member. + */ + virtual ~GHOST_System(); + +public: + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /** + * Installs a timer. + * Note that, on most operating systems, messages need to be processed in order + * for the timer callbacks to be invoked. + * @param delay The time to wait for the first call to the timerProc (in milliseconds) + * @param interval The interval between calls to the timerProc + * @param timerProc The callback invoked when the interval expires, + * @param userData Placeholder for user data. + * @return A timer task (0 if timer task installation failed). + */ + virtual GHOST_ITimerTask* installTimer(GHOST_TUns64 delay, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0); + + /** + * Removes a timer. + * @param timerTask Timer task to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeTimer(GHOST_ITimerTask* timerTask); + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Inherited from GHOST_ISystem but left pure virtual + * + * virtual GHOST_TUns8 getNumDisplays() const = 0; + * virtual void getMainDisplayDimensions(...) const = 0; + * virtual GHOST_IWindow* createWindow(..) + */ + + /** + * Dispose a window. + * @param window Pointer to the window to be disposed. + * @return Indication of success. + */ + virtual GHOST_TSuccess disposeWindow(GHOST_IWindow* window); + + /** + * Returns whether a window is valid. + * @param window Pointer to the window to be checked. + * @return Indication of validity. + */ + virtual bool validWindow(GHOST_IWindow* window); + + /** + * Begins full screen mode. + * @param setting The new setting of the display. + * @param window Window displayed in full screen. + * @param stereoVisual Stereo visual for quad buffered stereo. + * This window is invalid after full screen has been ended. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, + const bool stereoVisual); + + /** + * Ends full screen mode. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void); + + /** + * Returns current full screen mode status. + * @return The current status. + */ + virtual bool getFullScreen(void); + + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Inherited from GHOST_ISystem but left pure virtual + * + * virtual bool processEvents(bool waitForEvent) = 0; + */ + + + + /** + * Dispatches all the events on the stack. + * The event stack will be empty afterwards. + * @return Indication as to whether any of the consumers handled the events. + */ + virtual bool dispatchEvents(); + + /** + * Adds the given event consumer to our list. + * @param consumer The event consumer to add. + * @return Indication of success. + */ + virtual GHOST_TSuccess addEventConsumer(GHOST_IEventConsumer* consumer); + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** Inherited from GHOST_ISystem but left pure virtual + * GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const = 0; + * GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) + */ + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of a modifier key (ouside the message queue). + * @param mask The modifier key state to retrieve. + * @param isDown The state of a modifier key (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const; + + /** + * Returns the state of a mouse button (ouside the message queue). + * @param mask The button state to retrieve. + * @param isDown Button state. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const; + + /*************************************************************************************** + ** Other (internal) functionality. + ***************************************************************************************/ + + /** + * Pushes an event on the stack. + * To dispatch it, call dispatchEvent() or dispatchEvents(). + * Do not delete the event! + * @param event The event to push on the stack. + */ + virtual GHOST_TSuccess pushEvent(GHOST_IEvent* event); + + /** + * Returns the timer manager. + * @return The timer manager. + */ + inline virtual GHOST_TimerManager* getTimerManager() const; + + /** + * Returns a pointer to our event manager. + * @return A pointer to our event manager. + */ + virtual inline GHOST_EventManager* getEventManager() const; + + /** + * Returns a pointer to our window manager. + * @return A pointer to our window manager. + */ + virtual inline GHOST_WindowManager* getWindowManager() const; + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const = 0; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const = 0; + +protected: + /** + * Initialize the system. + * @return Indication of success. + */ + virtual GHOST_TSuccess init(); + + /** + * Shut the system down. + * @return Indication of success. + */ + virtual GHOST_TSuccess exit(); + + /** + * Creates a fullscreen window. + * @param window The window created. + * @return Indication of success. + */ + virtual GHOST_TSuccess createFullScreenWindow(GHOST_Window** window, + const bool stereoVisual); + + /** The display manager (platform dependant). */ + GHOST_DisplayManager* m_displayManager; + + /** The timer manager. */ + GHOST_TimerManager* m_timerManager; + + /** The window manager. */ + GHOST_WindowManager* m_windowManager; + + /** The event manager. */ + GHOST_EventManager* m_eventManager; + + /** Prints all the events. */ +#ifdef GHOST_DEBUG + GHOST_EventPrinter m_eventPrinter; +#endif // GHOST_DEBUG + + /** Settings of the display before the display went fullscreen. */ + GHOST_DisplaySetting m_preFullScreenSetting; +}; + +inline GHOST_TimerManager* GHOST_System::getTimerManager() const +{ + return m_timerManager; +} + +inline GHOST_EventManager* GHOST_System::getEventManager() const +{ + return m_eventManager; +} + +inline GHOST_WindowManager* GHOST_System::getWindowManager() const +{ + return m_windowManager; +} + +#endif // _GHOST_SYSTEM_H_ + diff --git a/intern/ghost/intern/GHOST_SystemCarbon.cpp b/intern/ghost/intern/GHOST_SystemCarbon.cpp new file mode 100644 index 00000000000..e1e3853e8a8 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCarbon.cpp @@ -0,0 +1,1067 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_SystemCarbon.h" + +#include "GHOST_DisplayManagerCarbon.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventWheel.h" +#include "GHOST_TimerManager.h" +#include "GHOST_TimerTask.h" +#include "GHOST_WindowManager.h" +#include "GHOST_WindowCarbon.h" + +#define GHOST_KEY_SWITCH(mac, ghost) { case (mac): ghostKey = (ghost); break; } + +const EventTypeSpec kEvents[] = +{ + { kEventClassAppleEvent, kEventAppleEvent }, + +/* + { kEventClassApplication, kEventAppActivated }, + { kEventClassApplication, kEventAppDeactivated }, +*/ + + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged }, + + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassMouse, kEventMouseWheelMoved }, + + { kEventClassWindow, kEventWindowClickZoomRgn } , /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowExpand } , /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowExpandAll }, /* for new zoom behaviour */ + + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassWindow, kEventWindowUpdate }, + { kEventClassWindow, kEventWindowBoundsChanged } + +}; + + + +static GHOST_TButtonMask convertButton(EventMouseButton button) +{ + switch (button) { + case kEventMouseButtonPrimary: + return GHOST_kButtonMaskLeft; + case kEventMouseButtonSecondary: + return GHOST_kButtonMaskRight; + case kEventMouseButtonTertiary: + default: + return GHOST_kButtonMaskMiddle; + } +} + +static GHOST_TKey convertKey(int rawCode) +{ + /* This bit of magic converts the rawCode into a virtual + * Mac key based on the current keyboard mapping, but + * without regard to the modifiers (so we don't get 'a' + * and 'A' for example. + */ + static UInt32 dummy= 0; + Handle transData = (Handle) GetScriptManagerVariable(smKCHRCache); + unsigned char vk = KeyTranslate(transData, rawCode, &dummy); + /* Map numpad based on rawcodes first, otherwise they + * look like non-numpad events. + * Added too: mapping the number keys, for french keyboards etc (ton) + */ + // printf("GHOST: vk: %d %c raw: %d\n", vk, vk, rawCode); + + switch (rawCode) { + case 18: return GHOST_kKey1; + case 19: return GHOST_kKey2; + case 20: return GHOST_kKey3; + case 21: return GHOST_kKey4; + case 23: return GHOST_kKey5; + case 22: return GHOST_kKey6; + case 26: return GHOST_kKey7; + case 28: return GHOST_kKey8; + case 25: return GHOST_kKey9; + case 29: return GHOST_kKey0; + + case 82: return GHOST_kKeyNumpad0; + case 83: return GHOST_kKeyNumpad1; + case 84: return GHOST_kKeyNumpad2; + case 85: return GHOST_kKeyNumpad3; + case 86: return GHOST_kKeyNumpad4; + case 87: return GHOST_kKeyNumpad5; + case 88: return GHOST_kKeyNumpad6; + case 89: return GHOST_kKeyNumpad7; + case 91: return GHOST_kKeyNumpad8; + case 92: return GHOST_kKeyNumpad9; + case 65: return GHOST_kKeyNumpadPeriod; + case 76: return GHOST_kKeyNumpadEnter; + case 69: return GHOST_kKeyNumpadPlus; + case 78: return GHOST_kKeyNumpadMinus; + case 67: return GHOST_kKeyNumpadAsterisk; + case 75: return GHOST_kKeyNumpadSlash; + } + + if ((vk >= 'a') && (vk <= 'z')) { + return (GHOST_TKey) (vk - 'a' + GHOST_kKeyA); + } else if ((vk >= '0') && (vk <= '9')) { + return (GHOST_TKey) (vk - '0' + GHOST_kKey0); + } else if (vk==16) { + switch (rawCode) { + case 122: return GHOST_kKeyF1; + case 120: return GHOST_kKeyF2; + case 99: return GHOST_kKeyF3; + case 118: return GHOST_kKeyF4; + case 96: return GHOST_kKeyF5; + case 97: return GHOST_kKeyF6; + case 98: return GHOST_kKeyF7; + case 100: return GHOST_kKeyF8; + case 101: return GHOST_kKeyF9; + case 109: return GHOST_kKeyF10; + case 103: return GHOST_kKeyF11; + case 111: return GHOST_kKeyF12; // Never get, is used for ejecting the CD! + } + } else { + switch (vk) { + case kUpArrowCharCode: return GHOST_kKeyUpArrow; + case kDownArrowCharCode: return GHOST_kKeyDownArrow; + case kLeftArrowCharCode: return GHOST_kKeyLeftArrow; + case kRightArrowCharCode: return GHOST_kKeyRightArrow; + + case kReturnCharCode: return GHOST_kKeyEnter; + case kBackspaceCharCode: return GHOST_kKeyBackSpace; + case kDeleteCharCode: return GHOST_kKeyDelete; + case kEscapeCharCode: return GHOST_kKeyEsc; + case kTabCharCode: return GHOST_kKeyTab; + case kSpaceCharCode: return GHOST_kKeySpace; + + case kHomeCharCode: return GHOST_kKeyHome; + case kEndCharCode: return GHOST_kKeyEnd; + case kPageUpCharCode: return GHOST_kKeyUpPage; + case kPageDownCharCode: return GHOST_kKeyDownPage; + + case '-': return GHOST_kKeyMinus; + case '=': return GHOST_kKeyEqual; + case ',': return GHOST_kKeyComma; + case '.': return GHOST_kKeyPeriod; + case '/': return GHOST_kKeySlash; + case ';': return GHOST_kKeySemicolon; + case '\'': return GHOST_kKeyQuote; + case '\\': return GHOST_kKeyBackslash; + case '[': return GHOST_kKeyLeftBracket; + case ']': return GHOST_kKeyRightBracket; + case '`': return GHOST_kKeyAccentGrave; + } + } + + // printf("GHOST: unknown key: %d %d\n", vk, rawCode); + + return GHOST_kKeyUnknown; +} + +/* MacOSX returns a Roman charset with kEventParamKeyMacCharCodes + * as defined here: http://developer.apple.com/documentation/mac/Text/Text-516.html + * I am not sure how international this works... + * For cross-platform convention, we'll use the Latin ascii set instead. + * As defined at: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html + * + */ +static unsigned char convertRomanToLatin(unsigned char ascii) +{ + + if(ascii<128) return ascii; + + switch(ascii) { + case 128: return 142; + case 129: return 143; + case 130: return 128; + case 131: return 201; + case 132: return 209; + case 133: return 214; + case 134: return 220; + case 135: return 225; + case 136: return 224; + case 137: return 226; + case 138: return 228; + case 139: return 227; + case 140: return 229; + case 141: return 231; + case 142: return 233; + case 143: return 232; + case 144: return 234; + case 145: return 235; + case 146: return 237; + case 147: return 236; + case 148: return 238; + case 149: return 239; + case 150: return 241; + case 151: return 243; + case 152: return 242; + case 153: return 244; + case 154: return 246; + case 155: return 245; + case 156: return 250; + case 157: return 249; + case 158: return 251; + case 159: return 252; + case 160: return 0; + case 161: return 176; + case 162: return 162; + case 163: return 163; + case 164: return 167; + case 165: return 183; + case 166: return 182; + case 167: return 223; + case 168: return 174; + case 169: return 169; + case 170: return 174; + case 171: return 180; + case 172: return 168; + case 173: return 0; + case 174: return 198; + case 175: return 216; + case 176: return 0; + case 177: return 177; + case 178: return 0; + case 179: return 0; + case 180: return 165; + case 181: return 181; + case 182: return 0; + case 183: return 0; + case 184: return 215; + case 185: return 0; + case 186: return 0; + case 187: return 170; + case 188: return 186; + case 189: return 0; + case 190: return 230; + case 191: return 248; + case 192: return 191; + case 193: return 161; + case 194: return 172; + case 195: return 0; + case 196: return 0; + case 197: return 0; + case 198: return 0; + case 199: return 171; + case 200: return 187; + case 201: return 201; + case 202: return 0; + case 203: return 192; + case 204: return 195; + case 205: return 213; + case 206: return 0; + case 207: return 0; + case 208: return 0; + case 209: return 0; + case 210: return 0; + + case 214: return 247; + + case 229: return 194; + case 230: return 202; + case 231: return 193; + case 232: return 203; + case 233: return 200; + case 234: return 205; + case 235: return 206; + case 236: return 207; + case 237: return 204; + case 238: return 211; + case 239: return 212; + case 240: return 0; + case 241: return 210; + case 242: return 218; + case 243: return 219; + case 244: return 217; + case 245: return 0; + case 246: return 0; + case 247: return 0; + case 248: return 0; + case 249: return 0; + case 250: return 0; + + + default: return 0; + } + +} + + +/***/ + +GHOST_SystemCarbon::GHOST_SystemCarbon() : + m_modifierMask(0) +{ + m_displayManager = new GHOST_DisplayManagerCarbon (); + GHOST_ASSERT(m_displayManager, "GHOST_SystemCarbon::GHOST_SystemCarbon(): m_displayManager==0\n"); + m_displayManager->initialize(); + + UnsignedWide micros; + ::Microseconds(µs); + m_start_time = UnsignedWideToUInt64(micros)/1000; + m_ignoreWindowSizedMessages = false; +} + +GHOST_SystemCarbon::~GHOST_SystemCarbon() +{ +} + + +GHOST_TUns64 GHOST_SystemCarbon::getMilliSeconds() const +{ + UnsignedWide micros; + ::Microseconds(µs); + UInt64 millis; + millis = UnsignedWideToUInt64(micros); + return (millis / 1000) - m_start_time; +} + + +GHOST_TUns8 GHOST_SystemCarbon::getNumDisplays() const +{ + // We do not support multiple monitors at the moment + return 1; +} + + +void GHOST_SystemCarbon::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const +{ + BitMap screenBits; + Rect bnds = GetQDGlobalsScreenBits(&screenBits)->bounds; + width = bnds.right - bnds.left; + height = bnds.bottom - bnds.top; +} + + +GHOST_IWindow* GHOST_SystemCarbon::createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + bool stereoVisual +) +{ + GHOST_IWindow* window = 0; + + window = new GHOST_WindowCarbon (title, left, top, width, height, state, type); + + if (window) { + if (window->getValid()) { + // Store the pointer to the window + GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); + m_windowManager->addWindow(window); + m_windowManager->setActiveWindow(window); + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); + } + else { + GHOST_PRINT("GHOST_SystemCarbon::createWindow(): window invalid\n"); + delete window; + window = 0; + } + } + else { + GHOST_PRINT("GHOST_SystemCarbon::createWindow(): could not create window\n"); + } + return window; +} + + +bool GHOST_SystemCarbon::processEvents(bool waitForEvent) +{ + bool anyProcessed = false; + EventRef event; + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent) { + GHOST_TUns64 curtime = getMilliSeconds(); + GHOST_TUns64 next = timerMgr->nextFireTime(); + double timeOut; + + if (next == GHOST_kFireTimeNever) { + timeOut = kEventDurationForever; + } else { + if (next<=curtime) + timeOut = 0.0; + else + timeOut = (double) (next - getMilliSeconds())/1000.0; + } + + ::ReceiveNextEvent(0, NULL, timeOut, false, &event); + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + if (getFullScreen()) { + // Check if the full-screen window is dirty + GHOST_IWindow* window = m_windowManager->getFullScreenWindow(); + if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) { + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); + anyProcessed = true; + } + } + + while (::ReceiveNextEvent(0, NULL, 0, true, &event)==noErr) { + OSStatus status= ::SendEventToEventTarget(event, ::GetEventDispatcherTarget()); + if (status==noErr) { + anyProcessed = true; + } else { + UInt32 i= ::GetEventClass(event); + + /* Ignore 'cgs ' class, no documentation on what they + * are, but we get a lot of them + */ + if (i!='cgs ') { + //printf("Missed - Class: '%.4s', Kind: %d\n", &i, ::GetEventKind(event)); + } + } + ::ReleaseEvent(event); + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + +GHOST_TSuccess GHOST_SystemCarbon::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const +{ + Point mouseLoc; + // Get the position of the mouse in the active port + ::GetGlobalMouse(&mouseLoc); + // Convert the coordinates to screen coordinates + x = (GHOST_TInt32)mouseLoc.h; + y = (GHOST_TInt32)mouseLoc.v; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCarbon::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const +{ + float xf=(float)x, yf=(float)y; + + CGAssociateMouseAndMouseCursorPosition(false); + CGSetLocalEventsSuppressionInterval(0); + CGWarpMouseCursorPosition(CGPointMake(xf, yf)); + CGAssociateMouseAndMouseCursorPosition(true); + +//this doesn't work properly, see game engine mouse-look scripts +// CGWarpMouseCursorPosition(CGPointMake(xf, yf)); + // this call below sends event, but empties other events (like shift) + // CGPostMouseEvent(CGPointMake(xf, yf), TRUE, 1, FALSE, 0); + + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemCarbon::getModifierKeys(GHOST_ModifierKeys& keys) const +{ + UInt32 modifiers = ::GetCurrentKeyModifiers(); + + keys.set(GHOST_kModifierKeyCommand, (modifiers & cmdKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & optionKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftShift, (modifiers & shiftKey) ? true : false); + keys.set(GHOST_kModifierKeyLeftControl, (modifiers & controlKey) ? true : false); + + return GHOST_kSuccess; +} + + /* XXX, incorrect for multibutton mice */ +GHOST_TSuccess GHOST_SystemCarbon::getButtons(GHOST_Buttons& buttons) const +{ + Boolean theOnlyButtonIsDown = ::Button(); + buttons.clear(); + buttons.set(GHOST_kButtonMaskLeft, theOnlyButtonIsDown); + return GHOST_kSuccess; +} + +#define FIRSTFILEBUFLG 512 +static bool g_hasFirstFile = false; +static char g_firstFileBuf[512]; + +extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) { + if (g_hasFirstFile) { + strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1); + buf[FIRSTFILEBUFLG - 1] = '\0'; + return 1; + } else { + return 0; + } +} + +OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon) +{ + //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon; + + return noErr; +} + +OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon) +{ + //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon; + AEDescList docs; + SInt32 ndocs; + OSErr err; + + err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs); + if (err != noErr) return err; + + err = AECountItems(&docs, &ndocs); + if (err==noErr) { + int i; + + for (i=0; ipushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) ); + + return noErr; +} + + +GHOST_TSuccess GHOST_SystemCarbon::init() +{ + GHOST_TSuccess success = GHOST_System::init(); + if (success) { + /* + * Initialize the cursor to the standard arrow shape (so that we can change it later on). + * This initializes the cursor's visibility counter to 0. + */ + ::InitCursor(); + + MenuRef windMenu; + ::CreateStandardWindowMenu(0, &windMenu); + ::InsertMenu(windMenu, 0); + ::DrawMenuBar(); + + ::InstallApplicationEventHandler(sEventHandlerProc, GetEventTypeCount(kEvents), kEvents, this, &m_handler); + + ::AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, sAEHandlerLaunch, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, sAEHandlerOpenDocs, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, sAEHandlerPrintDocs, (SInt32) this, false); + ::AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, sAEHandlerQuit, (SInt32) this, false); + } + return success; +} + + +GHOST_TSuccess GHOST_SystemCarbon::exit() +{ + return GHOST_System::exit(); +} + + +OSStatus GHOST_SystemCarbon::handleWindowEvent(EventRef event) +{ + WindowRef windowRef; + GHOST_WindowCarbon *window; + OSStatus err = eventNotHandledErr; + + // Check if the event was send to a GHOST window + ::GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &windowRef); + window = (GHOST_WindowCarbon*) ::GetWRefCon(windowRef); + if (!validWindow(window)) { + return err; + } + + //if (!getFullScreen()) { + err = noErr; + switch(::GetEventKind(event)) + { + case kEventWindowClose: + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) ); + break; + case kEventWindowActivated: + m_windowManager->setActiveWindow(window); + window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) ); + break; + case kEventWindowDeactivated: + m_windowManager->setWindowInactive(window); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) ); + break; + case kEventWindowUpdate: + //if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n"); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); + break; + case kEventWindowBoundsChanged: + if (!m_ignoreWindowSizedMessages) + { + window->updateDrawingContext(); + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); + } + break; + default: + err = eventNotHandledErr; + break; + } +// } + //else { + //window = (GHOST_WindowCarbon*) m_windowManager->getFullScreenWindow(); + //GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n"); + //::RemoveEventFromQueue(::GetMainEventQueue(), event); + //} + + return err; +} + +OSStatus GHOST_SystemCarbon::handleTabletEvent(EventRef event) +{ + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + TabletPointRec tabletPointRecord; + TabletProximityRec tabletProximityRecord; + UInt32 anInt32; + GHOST_TabletData& ct=((GHOST_WindowCarbon*)window)->GetCarbonTabletData(); + OSStatus err = eventNotHandledErr; + + ct.Pressure = 0; + ct.Xtilt = 0; + ct.Ytilt = 0; + + // is there an embedded tablet event inside this mouse event? + if(noErr == GetEventParameter(event, kEventParamTabletEventType, typeUInt32, NULL, sizeof(UInt32), NULL, (void *)&anInt32)) + { + // yes there is one! + // Embedded tablet events can either be a proximity or pointer event. + if(anInt32 == kEventTabletPoint) + { + //GHOST_PRINT("Embedded pointer event!\n"); + + // Extract the tablet Pointer Event. If there is no Tablet Pointer data + // in this event, then this call will return an error. Just ignore the + // error and go on. This can occur when a proximity event is embedded in + // a mouse event and you did not check the mouse event to see which type + // of tablet event was embedded. + if(noErr == GetEventParameter(event, kEventParamTabletPointRec, + typeTabletPointRec, NULL, + sizeof(TabletPointRec), + NULL, (void *)&tabletPointRecord)) + { + ct.Pressure = tabletPointRecord.pressure / 65535.0f; + ct.Xtilt = tabletPointRecord.tiltX / 32767.0f; /* can be positive or negative */ + ct.Ytilt = tabletPointRecord.tiltY / 32767.0f; /* can be positive or negative */ + } + } else { + //GHOST_PRINT("Embedded proximity event\n"); + + // Extract the Tablet Proximity record from the event. + if(noErr == GetEventParameter(event, kEventParamTabletProximityRec, + typeTabletProximityRec, NULL, + sizeof(TabletProximityRec), + NULL, (void *)&tabletProximityRecord)) + { + if (tabletProximityRecord.enterProximity) { + //pointer is entering tablet area proximity + + switch(tabletProximityRecord.pointerType) + { + case 1: /* stylus */ + ct.Active = 1; + break; + case 2: /* puck, not supported so far */ + ct.Active = 0; + break; + case 3: /* eraser */ + ct.Active = 2; + break; + default: + ct.Active = 0; + break; + } + } else { + // pointer is leaving - return to mouse + ct.Active = 0; + } + } + } + err = noErr; + } +} + +OSStatus GHOST_SystemCarbon::handleMouseEvent(EventRef event) +{ + OSStatus err = eventNotHandledErr; + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + UInt32 kind = ::GetEventKind(event); + + switch (kind) + { + case kEventMouseDown: + case kEventMouseUp: + // Handle Mac application responsibilities + if ((kind == kEventMouseDown) && handleMouseDown(event)) { + err = noErr; + } + else { + GHOST_TEventType type = (kind == kEventMouseDown) ? GHOST_kEventButtonDown : GHOST_kEventButtonUp; + EventMouseButton button; + + /* Window still gets mouse up after command-H */ + if (m_windowManager->getActiveWindow()) { + // handle any tablet events that may have come with the mouse event (optional) + handleTabletEvent(event); + + ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); + pushEvent(new GHOST_EventButton(getMilliSeconds(), type, window, convertButton(button))); + err = noErr; + } + } + break; + + case kEventMouseMoved: + case kEventMouseDragged: { + Point mousePos; + + if (window) { + //handle any tablet events that may have come with the mouse event (optional) + handleTabletEvent(event); + + ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos); + pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, mousePos.h, mousePos.v)); + err = noErr; + } + break; + } + case kEventMouseWheelMoved: + { + OSStatus status; + //UInt32 modifiers; + EventMouseWheelAxis axis; + SInt32 delta; + //status = ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers); + //GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + status = ::GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis); + GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + if (axis == kEventMouseWheelAxisY) + { + status = ::GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta); + GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed"); + /* + * Limit mouse wheel delta to plus and minus one. + */ + delta = delta > 0 ? 1 : -1; + pushEvent(new GHOST_EventWheel(getMilliSeconds(), window, delta)); + err = noErr; + } + } + break; + } + + return err; +} + + +OSStatus GHOST_SystemCarbon::handleKeyEvent(EventRef event) +{ + OSStatus err = eventNotHandledErr; + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + UInt32 kind = ::GetEventKind(event); + UInt32 modifiers; + UInt32 rawCode; + GHOST_TKey key; + unsigned char ascii; + + /* Can happen, very rarely - seems to only be when command-H makes + * the window go away and we still get an HKey up. + */ + if (!window) { + //::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode); + //key = convertKey(rawCode); + return err; + } + + err = noErr; + switch (kind) { + case kEventRawKeyDown: + case kEventRawKeyRepeat: + case kEventRawKeyUp: + ::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode); + ::GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ascii); + + key = convertKey(rawCode); + ascii= convertRomanToLatin(ascii); + + // if (key!=GHOST_kKeyUnknown) { + GHOST_TEventType type; + if (kind == kEventRawKeyDown) { + type = GHOST_kEventKeyDown; + } else if (kind == kEventRawKeyRepeat) { + type = GHOST_kEventKeyDown; /* XXX, fixme */ + } else { + type = GHOST_kEventKeyUp; + } + pushEvent( new GHOST_EventKey( getMilliSeconds(), type, window, key, ascii) ); +// } + break; + + case kEventRawKeyModifiersChanged: + /* ugh */ + ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + if ((modifiers & shiftKey) != (m_modifierMask & shiftKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & shiftKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) ); + } + if ((modifiers & controlKey) != (m_modifierMask & controlKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & controlKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) ); + } + if ((modifiers & optionKey) != (m_modifierMask & optionKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & optionKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); + } + if ((modifiers & cmdKey) != (m_modifierMask & cmdKey)) { + pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & cmdKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) ); + } + + m_modifierMask = modifiers; + break; + + default: + err = eventNotHandledErr; + break; + } + + return err; +} + + +bool GHOST_SystemCarbon::handleMouseDown(EventRef event) +{ + WindowPtr window; + short part; + BitMap screenBits; + bool handled = true; + GHOST_WindowCarbon* ghostWindow; + Point mousePos = {0 , 0}; + + ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos); + + part = ::FindWindow(mousePos, &window); + ghostWindow = (GHOST_WindowCarbon*) ::GetWRefCon(window); + + switch (part) { + case inMenuBar: + handleMenuCommand(::MenuSelect(mousePos)); + break; + + case inDrag: + /* + * The DragWindow() routine creates a lot of kEventWindowBoundsChanged + * events. By setting m_ignoreWindowSizedMessages these are suppressed. + * @see GHOST_SystemCarbon::handleWindowEvent(EventRef event) + */ + GHOST_ASSERT(validWindow(ghostWindow), "GHOST_SystemCarbon::handleMouseDown: invalid window"); + m_ignoreWindowSizedMessages = true; + ::DragWindow(window, mousePos, &GetQDGlobalsScreenBits(&screenBits)->bounds); + m_ignoreWindowSizedMessages = false; + break; + + case inContent: + if (window != ::FrontWindow()) { + ::SelectWindow(window); + /* + * We add a mouse down event on the newly actived window + */ + //GHOST_PRINT("GHOST_SystemCarbon::handleMouseDown(): adding mouse down event, " << ghostWindow << "\n"); + EventMouseButton button; + ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); + pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonDown, ghostWindow, convertButton(button))); + } else { + handled = false; + } + break; + + case inGoAway: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + if (::TrackGoAway(window, mousePos)) + { + // todo: add option-close, because itØs in the HIG + // if (event.modifiers & optionKey) { + // Close the clean documents, others will be confirmed one by one. + //} + // else { + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, ghostWindow)); + //} + } + break; + + case inGrow: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + ::ResizeWindow(window, mousePos, NULL, NULL); + break; + + case inZoomIn: + case inZoomOut: + GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); + if (::TrackBox(window, mousePos, part)) { + int macState; + + macState = ghostWindow->getMac_windowState(); + if ( macState== 0) + ::ZoomWindow(window, part, true); + else + if (macState == 2) { // always ok + ::ZoomWindow(window, part, true); + ghostWindow->setMac_windowState(1); + } else { // need to force size again + // GHOST_TUns32 scr_x,scr_y; /*unused*/ + Rect outAvailableRect; + + ghostWindow->setMac_windowState(2); + ::GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect); + + //this->getMainDisplayDimensions(scr_x,scr_y); + ::SizeWindow (window, outAvailableRect.right-outAvailableRect.left,outAvailableRect.bottom-outAvailableRect.top-1,false); + ::MoveWindow (window, outAvailableRect.left, outAvailableRect.top,true); + } + + } + break; + + default: + handled = false; + break; + } + + return handled; +} + + +bool GHOST_SystemCarbon::handleMenuCommand(GHOST_TInt32 menuResult) +{ + short menuID; + short menuItem; + UInt32 command; + bool handled; + OSErr err; + + menuID = HiWord(menuResult); + menuItem = LoWord(menuResult); + + err = ::GetMenuItemCommandID(::GetMenuHandle(menuID), menuItem, &command); + + handled = false; + + if (err || command == 0) { + } + else { + switch(command) { + } + } + + ::HiliteMenu(0); + return handled; +} + +OSStatus GHOST_SystemCarbon::sEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) +{ + GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) userData; + OSStatus err = eventNotHandledErr; + + switch (::GetEventClass(event)) + { + case kEventClassAppleEvent: + EventRecord eventrec; + if (ConvertEventRefToEventRecord(event, &eventrec)) { + err = AEProcessAppleEvent(&eventrec); + } + break; + case kEventClassMouse: + err = sys->handleMouseEvent(event); + break; + case kEventClassWindow: + err = sys->handleWindowEvent(event); + break; + case kEventClassKeyboard: + err = sys->handleKeyEvent(event); + break; + } + + return err; +} diff --git a/intern/ghost/intern/GHOST_SystemCarbon.h b/intern/ghost/intern/GHOST_SystemCarbon.h new file mode 100644 index 00000000000..93022aa78ff --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemCarbon.h @@ -0,0 +1,258 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_SystemCarbon.h + * Declaration of GHOST_SystemCarbon class. + */ + +#ifndef _GHOST_SYSTEM_CARBON_H_ +#define _GHOST_SYSTEM_CARBON_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +#define __CARBONSOUND__ +#include + +#include "GHOST_System.h" + +class GHOST_EventCursor; +class GHOST_EventKey; +class GHOST_EventWindow; + +/** + * OSX/Carbon Implementation of GHOST_System class. + * @see GHOST_System. + * @author Maarten Gribnau + * @date May 21, 2001 + */ +class GHOST_SystemCarbon : public GHOST_System { +public: + /** + * Constructor. + */ + GHOST_SystemCarbon::GHOST_SystemCarbon(); + + /** + * Destructor. + */ + GHOST_SystemCarbon::~GHOST_SystemCarbon(); + + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * Based on ANSI clock() routine. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual + ); + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Gets events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent); + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const; + + /** + * Updates the location of the cursor (location in screen coordinates). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const; + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const; + +protected: + /** + * Initializes the system. + * For now, it justs registers the window class (WNDCLASS). + * @return A success value. + */ + virtual GHOST_TSuccess init(); + + /** + * Closes the system down. + * @return A success value. + */ + virtual GHOST_TSuccess exit(); + + + /** + * Handles a tablet event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleTabletEvent(EventRef event); + /** + * Handles a mouse event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleMouseEvent(EventRef event); + + /** + * Handles a key event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleKeyEvent(EventRef event); + + /** + * Handles a window event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleWindowEvent(EventRef event); + + /** + * Handles all basic Mac application stuff for a mouse down event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + bool handleMouseDown(EventRef event); + + /** + * Handles a Mac menu command. + * @param menuResult A Mac menu/item identifier. + * @return Indication whether the event was handled. + */ + bool handleMenuCommand(GHOST_TInt32 menuResult); + + /** + * Callback for Carbon when it has events. + */ + static OSStatus sEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData); + + /** Apple Event Handlers */ + static OSErr sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + static OSErr sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon); + + /** + * Callback for Mac Timer tasks that expire. + * @param tmTask Pointer to the timer task that expired. + */ + //static void s_timerCallback(TMTaskPtr tmTask); + + /** Event handler reference. */ + EventHandlerRef m_handler; + + /** Start time at initialization. */ + GHOST_TUns64 m_start_time; + + /** State of the modifiers. */ + UInt32 m_modifierMask; + + /** Ignores window size messages (when window is dragged). */ + bool m_ignoreWindowSizedMessages; +}; + +#endif // _GHOST_SYSTEM_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp new file mode 100644 index 00000000000..ec6d0d355b5 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -0,0 +1,871 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 7, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning + +#include "GHOST_SystemWin32.h" + +/* + * According to the docs the mouse wheel message is supported from windows 98 + * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the + * wheel detent value are undefined. + */ +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A +#endif // WM_MOUSEWHEEL +#ifndef WHEEL_DELTA +#define WHEEL_DELTA 120 /* Value for rolling one detent */ +#endif // WHEEL_DELTA + + +#include "GHOST_Debug.h" +#include "GHOST_DisplayManagerWin32.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventWheel.h" +#include "GHOST_TimerTask.h" +#include "GHOST_TimerManager.h" +#include "GHOST_WindowManager.h" +#include "GHOST_WindowWin32.h" + +// Key code values not found in winuser.h +#ifndef VK_MINUS +#define VK_MINUS 0xBD +#endif // VK_MINUS +#ifndef VK_SEMICOLON +#define VK_SEMICOLON 0xBA +#endif // VK_SEMICOLON +#ifndef VK_PERIOD +#define VK_PERIOD 0xBE +#endif // VK_PERIOD +#ifndef VK_COMMA +#define VK_COMMA 0xBC +#endif // VK_COMMA +#ifndef VK_QUOTE +#define VK_QUOTE 0xDE +#endif // VK_QUOTE +#ifndef VK_BACK_QUOTE +#define VK_BACK_QUOTE 0xC0 +#endif // VK_BACK_QUOTE +#ifndef VK_SLASH +#define VK_SLASH 0xBF +#endif // VK_SLASH +#ifndef VK_BACK_SLASH +#define VK_BACK_SLASH 0xDC +#endif // VK_BACK_SLASH +#ifndef VK_EQUALS +#define VK_EQUALS 0xBB +#endif // VK_EQUALS +#ifndef VK_OPEN_BRACKET +#define VK_OPEN_BRACKET 0xDB +#endif // VK_OPEN_BRACKET +#ifndef VK_CLOSE_BRACKET +#define VK_CLOSE_BRACKET 0xDD +#endif // VK_CLOSE_BRACKET +#ifndef VK_GR_LESS +#define VK_GR_LESS 0xE2 +#endif // VK_GR_LESS + + +GHOST_SystemWin32::GHOST_SystemWin32() +: m_hasPerformanceCounter(false), m_freq(0), m_start(0), + m_seperateLeftRight(false), + m_seperateLeftRightInitialized(false) +{ + m_displayManager = new GHOST_DisplayManagerWin32 (); + GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n"); + m_displayManager->initialize(); +} + +GHOST_SystemWin32::~GHOST_SystemWin32() +{ +} + + +GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const +{ + // Hardware does not support high resolution timers. We will use GetTickCount instead then. + if (!m_hasPerformanceCounter) { + return ::GetTickCount(); + } + + // Retrieve current count + __int64 count = 0; + ::QueryPerformanceCounter((LARGE_INTEGER*)&count); + + // Calculate the time passed since system initialization. + __int64 delta = 1000*(count-m_start); + + GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq); + return t; +} + + +GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const +{ + GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n"); + GHOST_TUns8 numDisplays; + m_displayManager->getNumDisplays(numDisplays); + return numDisplays; +} + + +void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const +{ + width = ::GetSystemMetrics(SM_CXSCREEN); + height= ::GetSystemMetrics(SM_CYSCREEN); +} + + +GHOST_IWindow* GHOST_SystemWin32::createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + bool stereoVisual) +{ + GHOST_Window* window = 0; + window = new GHOST_WindowWin32 (title, left, top, width, height, state, type, stereoVisual); + if (window) { + if (window->getValid()) { + // Store the pointer to the window +// if (state != GHOST_kWindowStateFullScreen) { + m_windowManager->addWindow(window); +// } + } + else { + delete window; + window = 0; + } + } + return window; +} + + +bool GHOST_SystemWin32::processEvents(bool waitForEvent) +{ + MSG msg; + bool anyProcessed = false; + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) { +#if 1 + ::Sleep(1); +#else + GHOST_TUns64 next = timerMgr->nextFireTime(); + + if (next == GHOST_kFireTimeNever) { + ::WaitMessage(); + } else { + ::SetTimer(NULL, 0, next - getMilliSeconds(), NULL); + ::WaitMessage(); + ::KillTimer(NULL, 0); + } +#endif + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + // Process all the events waiting for us + while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + anyProcessed = true; + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + +GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const +{ + POINT point; + bool success = ::GetCursorPos(&point) == TRUE; + x = point.x; + y = point.y; + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const +{ + return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const +{ + /* + GetKeyState and GetAsyncKeyState only work with Win95, Win98, NT4, + Terminal Server and Windows 2000. + But on WinME it always returns zero. These two functions are simply + skipped by Millenium Edition! + + Official explanation from Microsoft: + Intentionally disabled. + It didn't work all that well on some newer hardware, and worked less + well with the passage of time, so it was fully disabled in ME. + */ + if (m_seperateLeftRight && m_seperateLeftRightInitialized) { + bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0; + keys.set(GHOST_kModifierKeyLeftShift, down); + down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0; + keys.set(GHOST_kModifierKeyRightShift, down); + down = HIBYTE(::GetKeyState(VK_LMENU)) != 0; + keys.set(GHOST_kModifierKeyLeftAlt, down); + down = HIBYTE(::GetKeyState(VK_RMENU)) != 0; + keys.set(GHOST_kModifierKeyRightAlt, down); + down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0; + keys.set(GHOST_kModifierKeyLeftControl, down); + down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0; + keys.set(GHOST_kModifierKeyRightControl, down); + } + else { + bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0; + keys.set(GHOST_kModifierKeyLeftShift, down); + keys.set(GHOST_kModifierKeyRightShift, down); + down = HIBYTE(::GetKeyState(VK_MENU)) != 0; + keys.set(GHOST_kModifierKeyLeftAlt, down); + keys.set(GHOST_kModifierKeyRightAlt, down); + down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0; + keys.set(GHOST_kModifierKeyLeftControl, down); + keys.set(GHOST_kModifierKeyRightControl, down); + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const +{ + /* Check for swapped buttons (left-handed mouse buttons) + * GetAsyncKeyState() will give back the state of the physical mouse buttons. + */ + bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE; + + bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0; + buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down); + + down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0; + buttons.set(GHOST_kButtonMaskMiddle, down); + + down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0; + buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down); + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_SystemWin32::init() +{ + GHOST_TSuccess success = GHOST_System::init(); + + // Determine whether this system has a high frequency performance counter. */ + m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE; + if (m_hasPerformanceCounter) { + GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n") + ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start); + } + else { + GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n") + } + + if (success) { + WNDCLASS wc; + wc.style= CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc= s_wndProc; + wc.cbClsExtra= 0; + wc.cbWndExtra= 0; + wc.hInstance= ::GetModuleHandle(0); + wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON"); + + if (!wc.hIcon) { + ::LoadIcon(NULL, IDI_APPLICATION); + } + wc.hCursor = ::LoadCursor(0, IDC_ARROW); + wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = 0; + wc.lpszClassName= GHOST_WindowWin32::getWindowClassName(); + + // Use RegisterClassEx for setting small icon + if (::RegisterClass(&wc) == 0) { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_TSuccess GHOST_SystemWin32::exit() +{ + return GHOST_System::exit(); +} + + +GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const +{ + GHOST_TKey key; + bool isExtended = (lParam&(1<<24))?true:false; + + if ((wParam >= '0') && (wParam <= '9')) { + // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) + key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0); + } + else if ((wParam >= 'A') && (wParam <= 'Z')) { + // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) + key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA); + } + else if ((wParam >= VK_F1) && (wParam <= VK_F24)) { + key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1); + } + else { + switch (wParam) { + case VK_RETURN: + key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter; + break; + + case VK_BACK: key = GHOST_kKeyBackSpace; break; + case VK_TAB: key = GHOST_kKeyTab; break; + case VK_ESCAPE: key = GHOST_kKeyEsc; break; + case VK_SPACE: key = GHOST_kKeySpace; break; + case VK_PRIOR: key = GHOST_kKeyUpPage; break; + case VK_NEXT: key = GHOST_kKeyDownPage; break; + case VK_END: key = GHOST_kKeyEnd; break; + case VK_HOME: key = GHOST_kKeyHome; break; + case VK_INSERT: key = GHOST_kKeyInsert; break; + case VK_DELETE: key = GHOST_kKeyDelete; break; + case VK_LEFT: key = GHOST_kKeyLeftArrow; break; + case VK_RIGHT: key = GHOST_kKeyRightArrow; break; + case VK_UP: key = GHOST_kKeyUpArrow; break; + case VK_DOWN: key = GHOST_kKeyDownArrow; break; + case VK_NUMPAD0: key = GHOST_kKeyNumpad0; break; + case VK_NUMPAD1: key = GHOST_kKeyNumpad1; break; + case VK_NUMPAD2: key = GHOST_kKeyNumpad2; break; + case VK_NUMPAD3: key = GHOST_kKeyNumpad3; break; + case VK_NUMPAD4: key = GHOST_kKeyNumpad4; break; + case VK_NUMPAD5: key = GHOST_kKeyNumpad5; break; + case VK_NUMPAD6: key = GHOST_kKeyNumpad6; break; + case VK_NUMPAD7: key = GHOST_kKeyNumpad7; break; + case VK_NUMPAD8: key = GHOST_kKeyNumpad8; break; + case VK_NUMPAD9: key = GHOST_kKeyNumpad9; break; + case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen; break; + case VK_PAUSE: key = GHOST_kKeyPause; break; + case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk; break; + case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus; break; + case VK_DECIMAL: key = GHOST_kKeyNumpadPeriod; break; + case VK_DIVIDE: key = GHOST_kKeyNumpadSlash; break; + case VK_ADD: key = GHOST_kKeyNumpadPlus; break; + + case VK_SEMICOLON: key = GHOST_kKeySemicolon; break; + case VK_EQUALS: key = GHOST_kKeyEqual; break; + case VK_COMMA: key = GHOST_kKeyComma; break; + case VK_MINUS: key = GHOST_kKeyMinus; break; + case VK_PERIOD: key = GHOST_kKeyPeriod; break; + case VK_SLASH: key = GHOST_kKeySlash; break; + case VK_BACK_QUOTE: key = GHOST_kKeyAccentGrave; break; + case VK_OPEN_BRACKET: key = GHOST_kKeyLeftBracket; break; + case VK_BACK_SLASH: key = GHOST_kKeyBackslash; break; + case VK_CLOSE_BRACKET: key = GHOST_kKeyRightBracket; break; + case VK_QUOTE: key = GHOST_kKeyQuote; break; + case VK_GR_LESS: key = GHOST_kKeyGrLess; break; + + // Process these keys separately because we need to distinguish right from left modifier keys + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + + // Ignore these keys + case VK_NUMLOCK: + case VK_SCROLL: + case VK_CAPITAL: + default: + key = GHOST_kKeyUnknown; + break; + } + } + return key; +} + + +void GHOST_SystemWin32::processModifierKeys(GHOST_IWindow *window) +{ + GHOST_ModifierKeys oldModifiers, newModifiers; + // Retrieve old state of the modifier keys + ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers); + // Retrieve current state of the modifier keys + ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers); + + // Compare the old and the new + if (!newModifiers.equals(oldModifiers)) { + // Create events for the masks that changed + for (int i = 0; i < GHOST_kModifierKeyNumMasks; i++) { + if (newModifiers.get((GHOST_TModifierKeyMask)i) != oldModifiers.get((GHOST_TModifierKeyMask)i)) { + // Convert the mask to a key code + GHOST_TKey key = GHOST_ModifierKeys::getModifierKeyCode((GHOST_TModifierKeyMask)i); + bool keyDown = newModifiers.get((GHOST_TModifierKeyMask)i); + GHOST_EventKey* event; + if (key != GHOST_kKeyUnknown) { + // Create an event + event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key); + pushEvent(event); + } + } + } + } + + // Store new modifier keys state + ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers); +} + + +GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask) +{ + return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask); +} + + +GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *window) +{ + GHOST_TInt32 x, y; + getSystem()->getCursorPosition(x, y); + return new GHOST_EventCursor (getSystem()->getMilliSeconds(), type, window, x, y); +} + + +GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) +{ + // short fwKeys = LOWORD(wParam); // key flags + int zDelta = (short) HIWORD(wParam); // wheel rotation + zDelta /= WHEEL_DELTA; + // short xPos = (short) LOWORD(lParam); // horizontal position of pointer + // short yPos = (short) HIWORD(lParam); // vertical position of pointer + return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta); +} + + +GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam) +{ + GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam); + GHOST_EventKey* event; + if (key != GHOST_kKeyUnknown) { + MSG keyMsg; + char ascii = '\0'; + + /* Eat any character related messages */ + if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) { + ascii = (char) keyMsg.wParam; + } + + event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii); + } + else { + event = 0; + } + return event; +} + + +GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window) +{ + return new GHOST_Event(getSystem()->getMilliSeconds(), type, window); +} + + +LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + GHOST_Event* event = 0; + LRESULT lResult; + GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem()); + GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized") + + if (hwnd) { + GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA); + if (window) { + switch (msg) { + //////////////////////////////////////////////////////////////////////// + // Keyboard events, processed + //////////////////////////////////////////////////////////////////////// + case WM_KEYDOWN: + /* The WM_KEYDOWN message is posted to the window with the keyboard focus when a + * nonsystem key is pressed. A nonsystem key is a key that is pressed when the alt + * key is not pressed. + */ + case WM_SYSKEYDOWN: + /* The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when + * the user presses the F10 key (which activates the menu bar) or holds down the + * alt key and then presses another key. It also occurs when no window currently + * has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the + * active window. The window that receives the message can distinguish between these + * two contexts by checking the context code in the lKeyData parameter. + */ + switch (wParam) { + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + if (!system->m_seperateLeftRightInitialized) { + // Check whether this system supports seperate left and right keys + switch (wParam) { + case VK_SHIFT: + system->m_seperateLeftRight = + (HIBYTE(::GetKeyState(VK_LSHIFT)) != 0) || + (HIBYTE(::GetKeyState(VK_RSHIFT)) != 0) ? + true : false; + break; + case VK_CONTROL: + system->m_seperateLeftRight = + (HIBYTE(::GetKeyState(VK_LCONTROL)) != 0) || + (HIBYTE(::GetKeyState(VK_RCONTROL)) != 0) ? + true : false; + break; + case VK_MENU: + system->m_seperateLeftRight = + (HIBYTE(::GetKeyState(VK_LMENU)) != 0) || + (HIBYTE(::GetKeyState(VK_RMENU)) != 0) ? + true : false; + break; + } + system->m_seperateLeftRightInitialized = true; + } + system->processModifierKeys(window); + // Bypass call to DefWindowProc + return 0; + default: + event = processKeyEvent(window, true, wParam, lParam); + if (!event) { + GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ") + GHOST_PRINT(msg) + GHOST_PRINT(" key ignored\n") + } + break; + } + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + switch (wParam) { + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + system->processModifierKeys(window); + // Bypass call to DefWindowProc + return 0; + default: + event = processKeyEvent(window, false, wParam, lParam); + if (!event) { + GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ") + GHOST_PRINT(msg) + GHOST_PRINT(" key ignored\n") + } + break; + } + break; + + //////////////////////////////////////////////////////////////////////// + // Keyboard events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_CHAR: + /* The WM_CHAR message is posted to the window with the keyboard focus when + * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR + * contains the character code of the key that was pressed. + */ + case WM_DEADCHAR: + /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a + * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR + * specifies a character code generated by a dead key. A dead key is a key that + * generates a character, such as the umlaut (double-dot), that is combined with + * another character to form a composite character. For example, the umlaut-O + * character (Ù) is generated by typing the dead key for the umlaut character, and + * then typing the O key. + */ + case WM_SYSDEADCHAR: + /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when + * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. + * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, + * a dead key that is pressed while holding down the alt key. + */ + break; + //////////////////////////////////////////////////////////////////////// + // Tablet events, processed + //////////////////////////////////////////////////////////////////////// + case WT_PACKET: + ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam); + break; + case WT_CSRCHANGE: + case WT_PROXIMITY: + ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent(); + break; + //////////////////////////////////////////////////////////////////////// + // Mouse events, processed + //////////////////////////////////////////////////////////////////////// + case WM_LBUTTONDOWN: + window->registerMouseClickEvent(true); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft); + break; + case WM_MBUTTONDOWN: + window->registerMouseClickEvent(true); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle); + break; + case WM_RBUTTONDOWN: + window->registerMouseClickEvent(true); + event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight); + break; + case WM_LBUTTONUP: + window->registerMouseClickEvent(false); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft); + break; + case WM_MBUTTONUP: + window->registerMouseClickEvent(false); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle); + break; + case WM_RBUTTONUP: + window->registerMouseClickEvent(false); + event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight); + break; + case WM_MOUSEMOVE: + event = processCursorEvent(GHOST_kEventCursorMove, window); + break; + case WM_MOUSEWHEEL: + /* The WM_MOUSEWHEEL message is sent to the focus window + * when the mouse wheel is rotated. The DefWindowProc + * function propagates the message to the window's parent. + * There should be no internal forwarding of the message, + * since DefWindowProc propagates it up the parent chain + * until it finds a window that processes it. + */ + event = processWheelEvent(window, wParam, lParam); + break; + case WM_SETCURSOR: + /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor + * to move within a window and mouse input is not captured. + * This means we have to set the cursor shape every time the mouse moves! + * The DefWindowProc function uses this message to set the cursor to an + * arrow if it is not in the client area. + */ + if (LOWORD(lParam) == HTCLIENT) { + // Load the current cursor + window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); + // Bypass call to DefWindowProc + return 0; + } + else { + // Outside of client area show standard cursor + window->loadCursor(true, GHOST_kStandardCursorDefault); + } + break; + + //////////////////////////////////////////////////////////////////////// + // Mouse events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_NCMOUSEMOVE: + /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved + * within the nonclient area of the window. This message is posted to the window + * that contains the cursor. If a window has captured the mouse, this message is not posted. + */ + case WM_NCHITTEST: + /* The WM_NCHITTEST message is sent to a window when the cursor moves, or + * when a mouse button is pressed or released. If the mouse is not captured, + * the message is sent to the window beneath the cursor. Otherwise, the message + * is sent to the window that has captured the mouse. + */ + break; + + //////////////////////////////////////////////////////////////////////// + // Window events, processed + //////////////////////////////////////////////////////////////////////// + case WM_CLOSE: + /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */ + event = processWindowEvent(GHOST_kEventWindowClose, window); + break; + case WM_ACTIVATE: + /* The WM_ACTIVATE message is sent to both the window being activated and the window being + * deactivated. If the windows use the same input queue, the message is sent synchronously, + * first to the window procedure of the top-level window being deactivated, then to the window + * procedure of the top-level window being activated. If the windows use different input queues, + * the message is sent asynchronously, so the window is activated immediately. + */ + event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window); + break; + case WM_PAINT: + /* An application sends the WM_PAINT message when the system or another application + * makes a request to paint a portion of an application's window. The message is sent + * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage + * function when the application obtains a WM_PAINT message by using the GetMessage or + * PeekMessage function. + */ + event = processWindowEvent(GHOST_kEventWindowUpdate, window); + ::ValidateRect(hwnd, NULL); + break; + case WM_SIZE: + /* The WM_SIZE message is sent to a window after its size has changed. + * The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + event = processWindowEvent(GHOST_kEventWindowSize, window); + case WM_CAPTURECHANGED: + window->lostMouseCapture(); + break; + + //////////////////////////////////////////////////////////////////////// + // Window events, ignored + //////////////////////////////////////////////////////////////////////// + case WM_WINDOWPOSCHANGED: + /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place + * in the Z order has changed as a result of a call to the SetWindowPos function or + * another window-management function. + * The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + case WM_MOVE: + /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ + case WM_ERASEBKGND: + /* An application sends the WM_ERASEBKGND message when the window background must be + * erased (for example, when a window is resized). The message is sent to prepare an + * invalidated portion of a window for painting. + */ + case WM_NCPAINT: + /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */ + case WM_NCACTIVATE: + /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed + * to indicate an active or inactive state. + */ + case WM_DESTROY: + /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window + * procedure of the window being destroyed after the window is removed from the screen. + * This message is sent first to the window being destroyed and then to the child windows + * (if any) as they are destroyed. During the processing of the message, it can be assumed + * that all child windows still exist. + */ + case WM_NCDESTROY: + /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The + * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY + * message. WM_DESTROY is used to free the allocated memory object associated with the window. + */ + case WM_KILLFOCUS: + /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */ + case WM_SHOWWINDOW: + /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */ + case WM_WINDOWPOSCHANGING: + /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in + * the Z order is about to change as a result of a call to the SetWindowPos function or + * another window-management function. + */ + case WM_SETFOCUS: + /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */ + case WM_MOVING: + /* The WM_MOVING message is sent to a window that the user is moving. By processing + * this message, an application can monitor the size and position of the drag rectangle + * and, if needed, change its size or position. + */ + case WM_ENTERSIZEMOVE: + /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving + * or sizing modal loop. The window enters the moving or sizing modal loop when the user + * clicks the window's title bar or sizing border, or when the window passes the + * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the + * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when + * DefWindowProc returns. + */ + break; + + //////////////////////////////////////////////////////////////////////// + // Other events + //////////////////////////////////////////////////////////////////////// + case WM_GETTEXT: + /* An application sends a WM_GETTEXT message to copy the text that + * corresponds to a window into a buffer provided by the caller. + */ + case WM_ACTIVATEAPP: + /* The WM_ACTIVATEAPP message is sent when a window belonging to a + * different application than the active window is about to be activated. + * The message is sent to the application whose window is being activated + * and to the application whose window is being deactivated. + */ + case WM_TIMER: + /* The WIN32 docs say: + * The WM_TIMER message is posted to the installing thread's message queue + * when a timer expires. You can process the message by providing a WM_TIMER + * case in the window procedure. Otherwise, the default window procedure will + * call the TimerProc callback function specified in the call to the SetTimer + * function used to install the timer. + * + * In GHOST, we let DefWindowProc call the timer callback. + */ + break; + } + } + else { + // Event found for a window before the pointer to the class has been set. + GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n") + /* These are events we typically miss at this point: + WM_GETMINMAXINFO 0x24 + WM_NCCREATE 0x81 + WM_NCCALCSIZE 0x83 + WM_CREATE 0x01 + We let DefWindowProc do the work. + */ + } + } + else { + // Events without valid hwnd + GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n") + } + + if (event) { + system->pushEvent(event); + lResult = 0; + } + else { + lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); + } + return lResult; +} diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h new file mode 100644 index 00000000000..218fc5794eb --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -0,0 +1,291 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_SystemWin32.h + * Declaration of GHOST_SystemWin32 class. + */ + +#ifndef _GHOST_SYSTEM_WIN32_H_ +#define _GHOST_SYSTEM_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include + +#include "GHOST_System.h" + +#if defined(__CYGWIN32__) +# define __int64 long long +#endif + + +class GHOST_EventButton; +class GHOST_EventCursor; +class GHOST_EventKey; +class GHOST_EventWheel; +class GHOST_EventWindow; + +/** + * WIN32 Implementation of GHOST_System class. + * @see GHOST_System. + * @author Maarten Gribnau + * @date May 10, 2001 + */ +class GHOST_SystemWin32 : public GHOST_System { +public: + /** + * Constructor. + */ + GHOST_SystemWin32(); + + /** + * Destructor. + */ + virtual ~GHOST_SystemWin32(); + + /*************************************************************************************** + ** Time(r) functionality + ***************************************************************************************/ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * This overloaded method uses the high frequency timer if available. + * @return The number of milliseconds. + */ + virtual GHOST_TUns64 getMilliSeconds() const; + + /*************************************************************************************** + ** Display/window management functionality + ***************************************************************************************/ + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + virtual GHOST_TUns8 getNumDisplays() const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @return The new window (or 0 if creation failed). + */ + virtual GHOST_IWindow* createWindow( + const STR_String& title, + GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, GHOST_TDrawingContextType type, + const bool stereoVisual); + + /*************************************************************************************** + ** Event management functionality + ***************************************************************************************/ + + /** + * Gets events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + virtual bool processEvents(bool waitForEvent); + + + /*************************************************************************************** + ** Cursor management functionality + ***************************************************************************************/ + + /** + * Returns the current location of the cursor (location in screen coordinates) + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const; + + /** + * Updates the location of the cursor (location in screen coordinates). + * @param x The x-coordinate of the cursor. + * @param y The y-coordinate of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const; + + /*************************************************************************************** + ** Access to mouse button and keyboard states. + ***************************************************************************************/ + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const; + +protected: + /** + * Initializes the system. + * For now, it justs registers the window class (WNDCLASS). + * @return A success value. + */ + virtual GHOST_TSuccess init(); + + /** + * Closes the system down. + * @return A success value. + */ + virtual GHOST_TSuccess exit(); + + /** + * Converts raw WIN32 key codes from the wndproc to GHOST keys. + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + * @return The GHOST key (GHOST_kKeyUnknown if no match). + */ + virtual GHOST_TKey convertKey(WPARAM wParam, LPARAM lParam) const; + + /** + * Creates modifier key event(s) and updates the key data stored locally (m_modifierKeys). + * With the modifier keys, we want to distinguish left and right keys. + * Sometimes this is not possible (Windows ME for instance). Then, we want + * events generated for both keys. + * @param window The window receiving the event (the active window). + */ + void processModifierKeys(GHOST_IWindow *window); + + /** + * Creates mouse button event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @param mask The button mask of this event. + * @return The event created. + */ + static GHOST_EventButton* processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask); + + /** + * Creates cursor event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @return The event created. + */ + static GHOST_EventCursor* processCursorEvent(GHOST_TEventType type, GHOST_IWindow *window); + + /** + * Creates a mouse wheel event. + * @param window The window receiving the event (the active window). + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + */ + static GHOST_EventWheel* processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam); + + /** + * Creates a key event and updates the key data stored locally (m_modifierKeys). + * In most cases this is a straightforward conversion of key codes. + * For the modifier keys however, we want to distinguish left and right keys. + * @param window The window receiving the event (the active window). + * @param wParam The wParam from the wndproc + * @param lParam The lParam from the wndproc + */ + static GHOST_EventKey* processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam); + + /** + * Creates a window event. + * @param type The type of event to create. + * @param window The window receiving the event (the active window). + * @return The event created. + */ + static GHOST_Event* processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window); + + /** + * Returns the local state of the modifier keys (from the message queue). + * @param keys The state of the keys. + */ + inline virtual void retrieveModifierKeys(GHOST_ModifierKeys& keys) const; + + /** + * Stores the state of the modifier keys locally. + * For internal use only! + * @param keys The new state of the modifier keys. + */ + inline virtual void storeModifierKeys(const GHOST_ModifierKeys& keys); + + /** + * Windows call back routine for our window class. + */ + static LRESULT WINAPI s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + /** The current state of the modifier keys. */ + GHOST_ModifierKeys m_modifierKeys; + /** State variable set at initialization. */ + bool m_hasPerformanceCounter; + /** High frequency timer variable. */ + __int64 m_freq; + /** High frequency timer variable. */ + __int64 m_start; + /** Stores the capability of this system to distinguish left and right modifier keys. */ + bool m_seperateLeftRight; + /** Stores the initialization state of the member m_leftRightDistinguishable. */ + bool m_seperateLeftRightInitialized; + +}; + +inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const +{ + keys = m_modifierKeys; +} + +inline void GHOST_SystemWin32::storeModifierKeys(const GHOST_ModifierKeys& keys) +{ + m_modifierKeys = keys; +} + +#endif // _GHOST_SYSTEM_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp new file mode 100644 index 00000000000..14383ad3624 --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -0,0 +1,878 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_SystemX11.h" +#include "GHOST_WindowX11.h" +#include "GHOST_WindowManager.h" +#include "GHOST_TimerManager.h" +#include "GHOST_EventCursor.h" +#include "GHOST_EventKey.h" +#include "GHOST_EventButton.h" +#include "GHOST_EventWheel.h" +#include "GHOST_DisplayManagerX11.h" + +#include "GHOST_Debug.h" + +#include +#include + +#ifdef __sgi + +#if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS) +#include +#else +#define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how) +#endif + +#endif + +// For timing + +#include +#include + +#include + +using namespace std; + +GHOST_SystemX11:: +GHOST_SystemX11( +) : + GHOST_System(), + m_start_time(0) +{ + m_display = XOpenDisplay(NULL); + + if (!m_display) return; + +#ifdef __sgi + m_delete_window_atom + = XSGIFastInternAtom(m_display, + "WM_DELETE_WINDOW", + SGI_XA_WM_DELETE_WINDOW, False); +#else + m_delete_window_atom + = XInternAtom(m_display, "WM_DELETE_WINDOW", True); +#endif + + // compute the initial time + timeval tv; + if (gettimeofday(&tv,NULL) == -1) { + GHOST_ASSERT(false,"Could not instantiate timer!"); + } + + m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000); +} + + GHOST_TSuccess +GHOST_SystemX11:: +init( +){ + GHOST_TSuccess success = GHOST_System::init(); + + if (success) { + m_keyboard_vector = new char[32]; + + m_displayManager = new GHOST_DisplayManagerX11(this); + + if (m_keyboard_vector && m_displayManager) { + return GHOST_kSuccess; + } + } + + return GHOST_kFailure; +} + + + + GHOST_TUns64 +GHOST_SystemX11:: +getMilliSeconds( +) const { + timeval tv; + if (gettimeofday(&tv,NULL) == -1) { + GHOST_ASSERT(false,"Could not compute time!"); + } + + return GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time; +} + + GHOST_TUns8 +GHOST_SystemX11:: +getNumDisplays( +) const { + return GHOST_TUns8(1); +} + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + void +GHOST_SystemX11:: +getMainDisplayDimensions( + GHOST_TUns32& width, + GHOST_TUns32& height +) const { + if (m_display) { + width = DisplayWidth(m_display, DefaultScreen(m_display)); + height = DisplayHeight(m_display, DefaultScreen(m_display)); + } +} + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @return The new window (or 0 if creation failed). + */ + GHOST_IWindow* +GHOST_SystemX11:: +createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + bool stereoVisual +){ + GHOST_WindowX11 * window = 0; + + if (!m_display) return 0; + + window = new GHOST_WindowX11 ( + this,m_display,title, left, top, width, height, state, type, stereoVisual + ); + + if (window) { + + // Install a new protocol for this window - so we can overide + // the default window closure mechanism. + + XSetWMProtocols(m_display, window->getXWindow(), &m_delete_window_atom, 1); + + if (window->getValid()) { + // Store the pointer to the window + m_windowManager->addWindow(window); + + pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) ); + } + else { + delete window; + window = 0; + } + } + return window; + +} + + GHOST_WindowX11 * +GHOST_SystemX11:: +findGhostWindow( + Window xwind +) const { + + if (xwind == 0) return NULL; + + // It is not entirely safe to do this as the backptr may point + // to a window that has recently been removed. + // We should always check the window manager's list of windows + // and only process events on these windows. + + vector & win_vec = m_windowManager->getWindows(); + + vector::iterator win_it = win_vec.begin(); + vector::const_iterator win_end = win_vec.end(); + + for (; win_it != win_end; ++win_it) { + GHOST_WindowX11 * window = static_cast(*win_it); + if (window->getXWindow() == xwind) { + return window; + } + } + return NULL; + +} + +static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep) { + int fd = ConnectionNumber(display); + fd_set fds; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + if (maxSleep == -1) { + select(fd + 1, &fds, NULL, NULL, NULL); + } else { + timeval tv; + + tv.tv_sec = maxSleep/1000; + tv.tv_usec = (maxSleep - tv.tv_sec*1000)*1000; + + select(fd + 1, &fds, NULL, NULL, &tv); + } +} + + bool +GHOST_SystemX11:: +processEvents( + bool waitForEvent +){ + // Get all the current events -- translate them into + // ghost events and call base class pushEvent() method. + + bool anyProcessed = false; + + do { + GHOST_TimerManager* timerMgr = getTimerManager(); + + if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) { + GHOST_TUns64 next = timerMgr->nextFireTime(); + + if (next==GHOST_kFireTimeNever) { + SleepTillEvent(m_display, -1); + } else { + SleepTillEvent(m_display, next - getMilliSeconds()); + } + } + + if (timerMgr->fireTimers(getMilliSeconds())) { + anyProcessed = true; + } + + while (XPending(m_display)) { + XEvent xevent; + XNextEvent(m_display, &xevent); + processEvent(&xevent); + anyProcessed = true; + } + + if (generateWindowExposeEvents()) { + anyProcessed = true; + } + } while (waitForEvent && !anyProcessed); + + return anyProcessed; +} + + void +GHOST_SystemX11::processEvent(XEvent *xe) +{ + GHOST_WindowX11 * window = findGhostWindow(xe->xany.window); + GHOST_Event * g_event = NULL; + + if (!window) { + return; + } + + switch (xe->type) { + case Expose: + { + XExposeEvent & xee = xe->xexpose; + + if (xee.count == 0) { + // Only generate a single expose event + // per read of the event queue. + + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowUpdate, + window + ); + } + break; + } + + case MotionNotify: + { + XMotionEvent &xme = xe->xmotion; + + g_event = new + GHOST_EventCursor( + getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xme.x_root, + xme.y_root + ); + break; + } + + case KeyPress: + case KeyRelease: + { + XKeyEvent *xke = &(xe->xkey); + + KeySym key_sym = XLookupKeysym(xke,0); + char ascii; + + GHOST_TKey gkey = convertXKey(key_sym); + GHOST_TEventType type = (xke->type == KeyPress) ? + GHOST_kEventKeyDown : GHOST_kEventKeyUp; + + if (!XLookupString(xke, &ascii, 1, NULL, NULL)) { + ascii = '\0'; + } + + g_event = new + GHOST_EventKey( + getMilliSeconds(), + type, + window, + gkey, + ascii + ); + + break; + } + + case ButtonPress: + { + /* process wheel mouse events and break */ + if (xe->xbutton.button == 4) { + g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1); + break; + } + if (xe->xbutton.button == 5) { + g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1); + break; + } + } + case ButtonRelease: + { + + XButtonEvent & xbe = xe->xbutton; + GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft; + + switch (xbe.button) { + case Button1 : gbmask = GHOST_kButtonMaskLeft; break; + case Button3 : gbmask = GHOST_kButtonMaskRight; break; + default: + case Button2 : gbmask = GHOST_kButtonMaskMiddle; break; + } + + GHOST_TEventType type = (xbe.type == ButtonPress) ? + GHOST_kEventButtonDown : GHOST_kEventButtonUp; + + g_event = new + GHOST_EventButton( + getMilliSeconds(), + type, + window, + gbmask + ); + break; + } + + // change of size, border, layer etc. + case ConfigureNotify: + { + /* XConfigureEvent & xce = xe->xconfigure; */ + + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowSize, + window + ); + break; + } + + case FocusIn: + case FocusOut: + { + XFocusChangeEvent &xfe = xe->xfocus; + + // May have to look at the type of event and filter some + // out. + + GHOST_TEventType gtype = (xfe.type == FocusIn) ? + GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate; + + g_event = new + GHOST_Event( + getMilliSeconds(), + gtype, + window + ); + break; + + } + case ClientMessage: + { + XClientMessageEvent & xcme = xe->xclient; + +#ifndef __sgi + if (xcme.data.l[0] == m_delete_window_atom) { + g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowClose, + window + ); + } else { + /* Unknown client message, ignore */ + } +#endif + break; + } + + // We're not interested in the following things.(yet...) + case NoExpose : + case GraphicsExpose : + + case EnterNotify: + case LeaveNotify: + // XCrossingEvents pointer leave enter window. + break; + case MapNotify: + case UnmapNotify: + break; + case MappingNotify: + case ReparentNotify: + break; + + default: { + if(xe->type == window->GetXTablet().MotionEvent) + { + XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe; + window->GetXTablet().CommonData.Pressure= + data->axis_data[2]/((float)window->GetXTablet().PressureLevels); + + /* the (short) cast and the &0xffff is bizarre and unexplained anywhere, + * but I got garbage data without it. Found it in the xidump.c source --matt */ + window->GetXTablet().CommonData.Xtilt= + (short)(data->axis_data[3]&0xffff)/((float)window->GetXTablet().XtiltLevels); + window->GetXTablet().CommonData.Ytilt= + (short)(data->axis_data[4]&0xffff)/((float)window->GetXTablet().YtiltLevels); + } + else if(xe->type == window->GetXTablet().ProxInEvent) + { + XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe; + if(data->deviceid == window->GetXTablet().StylusID) + window->GetXTablet().CommonData.Active= 1; + else if(data->deviceid == window->GetXTablet().EraserID) + window->GetXTablet().CommonData.Active= 2; + } + else if(xe->type == window->GetXTablet().ProxOutEvent) + window->GetXTablet().CommonData.Active= 0; + + break; + } + } + + if (g_event) { + pushEvent(g_event); + } +} + + + GHOST_TSuccess +GHOST_SystemX11:: +getModifierKeys( + GHOST_ModifierKeys& keys +) const { + + // analyse the masks retuned from XQueryPointer. + + memset(m_keyboard_vector,0,sizeof(m_keyboard_vector)); + + XQueryKeymap(m_display,m_keyboard_vector); + + // now translate key symobols into keycodes and + // test with vector. + + const KeyCode shift_l = XKeysymToKeycode(m_display,XK_Shift_L); + const KeyCode shift_r = XKeysymToKeycode(m_display,XK_Shift_R); + const KeyCode control_l = XKeysymToKeycode(m_display,XK_Control_L); + const KeyCode control_r = XKeysymToKeycode(m_display,XK_Control_R); + const KeyCode alt_l = XKeysymToKeycode(m_display,XK_Alt_L); + const KeyCode alt_r = XKeysymToKeycode(m_display,XK_Alt_R); + + // Shift + if ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftShift,true); + } else { + keys.set(GHOST_kModifierKeyLeftShift,false); + } + if ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) { + + keys.set(GHOST_kModifierKeyRightShift,true); + } else { + keys.set(GHOST_kModifierKeyRightShift,false); + } + + // control (weep) + if ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftControl,true); + } else { + keys.set(GHOST_kModifierKeyLeftControl,false); + } + if ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) { + keys.set(GHOST_kModifierKeyRightControl,true); + } else { + keys.set(GHOST_kModifierKeyRightControl,false); + } + + // Alt (yawn) + if ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) { + keys.set(GHOST_kModifierKeyLeftAlt,true); + } else { + keys.set(GHOST_kModifierKeyLeftAlt,false); + } + if ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) { + keys.set(GHOST_kModifierKeyRightAlt,true); + } else { + keys.set(GHOST_kModifierKeyRightAlt,false); + } + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_SystemX11:: +getButtons( + GHOST_Buttons& buttons +) const { + + Window root_return, child_return; + int rx,ry,wx,wy; + unsigned int mask_return; + + if (XQueryPointer( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + &root_return, + &child_return, + &rx,&ry, + &wx,&wy, + &mask_return + ) == False) { + return GHOST_kFailure; + } else { + + if (mask_return & Button1Mask) { + buttons.set(GHOST_kButtonMaskLeft,true); + } else { + buttons.set(GHOST_kButtonMaskLeft,false); + } + + if (mask_return & Button2Mask) { + buttons.set(GHOST_kButtonMaskMiddle,true); + } else { + buttons.set(GHOST_kButtonMaskMiddle,false); + } + + if (mask_return & Button3Mask) { + buttons.set(GHOST_kButtonMaskRight,true); + } else { + buttons.set(GHOST_kButtonMaskRight,false); + } + } + + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_SystemX11:: +getCursorPosition( + GHOST_TInt32& x, + GHOST_TInt32& y +) const { + + Window root_return, child_return; + int rx,ry,wx,wy; + unsigned int mask_return; + + if (XQueryPointer( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + &root_return, + &child_return, + &rx,&ry, + &wx,&wy, + &mask_return + ) == False) { + return GHOST_kFailure; + } else { + x = rx; + y = ry; + } + return GHOST_kSuccess; +} + + + GHOST_TSuccess +GHOST_SystemX11:: +setCursorPosition( + GHOST_TInt32 x, + GHOST_TInt32 y +) const { + + // This is a brute force move in screen coordinates + // XWarpPointer does relative moves so first determine the + // current pointer position. + + int cx,cy; + if (getCursorPosition(cx,cy) == GHOST_kFailure) { + return GHOST_kFailure; + } + + int relx = x-cx; + int rely = y-cy; + + XWarpPointer(m_display,None,None,0,0,0,0,relx,rely); + XFlush(m_display); + + return GHOST_kSuccess; +} + + + void +GHOST_SystemX11:: +addDirtyWindow( + GHOST_WindowX11 * bad_wind +){ + + GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)"); + + m_dirty_windows.push_back(bad_wind); +} + + + bool +GHOST_SystemX11:: +generateWindowExposeEvents( +){ + + vector::iterator w_start = m_dirty_windows.begin(); + vector::const_iterator w_end = m_dirty_windows.end(); + bool anyProcessed = false; + + for (;w_start != w_end; ++w_start) { + GHOST_Event * g_event = new + GHOST_Event( + getMilliSeconds(), + GHOST_kEventWindowUpdate, + *w_start + ); + + (*w_start)->validate(); + + if (g_event) { + pushEvent(g_event); + anyProcessed = true; + } + } + + m_dirty_windows.clear(); + return anyProcessed; +} + +#define GXMAP(k,x,y) case x: k = y; break; + + GHOST_TKey +GHOST_SystemX11:: +convertXKey( + KeySym key +){ + GHOST_TKey type; + + if ((key >= XK_A) && (key <= XK_Z)) { + type = GHOST_TKey( key - XK_A + int(GHOST_kKeyA)); + } else if ((key >= XK_a) && (key <= XK_z)) { + type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA)); + } else if ((key >= XK_0) && (key <= XK_9)) { + type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0)); + } else if ((key >= XK_F1) && (key <= XK_F24)) { + type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1)); +#if defined(__sun) || defined(__sun__) + /* This is a bit of a hack, but it looks like sun + Used F11 and friends for its special keys Stop,again etc.. + So this little patch enables F11 and F12 to work as expected + following link has documentation on it: + http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4734408 + also from /usr/include/X11/Sunkeysym.h +#define SunXK_F36 0x1005FF10 // Labeled F11 +#define SunXK_F37 0x1005FF11 // Labeled F12 + + mein@cs.umn.edu + */ + + } else if (key == 268828432) { + type = GHOST_kKeyF11; + } else if (key == 268828433) { + type = GHOST_kKeyF12; +#endif + } else { + switch(key) { + GXMAP(type,XK_BackSpace, GHOST_kKeyBackSpace); + GXMAP(type,XK_Tab, GHOST_kKeyTab); + GXMAP(type,XK_Return, GHOST_kKeyEnter); + GXMAP(type,XK_Escape, GHOST_kKeyEsc); + GXMAP(type,XK_space, GHOST_kKeySpace); + + GXMAP(type,XK_Linefeed, GHOST_kKeyLinefeed); + GXMAP(type,XK_semicolon, GHOST_kKeySemicolon); + GXMAP(type,XK_period, GHOST_kKeyPeriod); + GXMAP(type,XK_comma, GHOST_kKeyComma); + GXMAP(type,XK_quoteright, GHOST_kKeyQuote); + GXMAP(type,XK_quoteleft, GHOST_kKeyAccentGrave); + GXMAP(type,XK_minus, GHOST_kKeyMinus); + GXMAP(type,XK_slash, GHOST_kKeySlash); + GXMAP(type,XK_backslash, GHOST_kKeyBackslash); + GXMAP(type,XK_equal, GHOST_kKeyEqual); + GXMAP(type,XK_bracketleft, GHOST_kKeyLeftBracket); + GXMAP(type,XK_bracketright, GHOST_kKeyRightBracket); + GXMAP(type,XK_Pause, GHOST_kKeyPause); + + GXMAP(type,XK_Shift_L, GHOST_kKeyLeftShift); + GXMAP(type,XK_Shift_R, GHOST_kKeyRightShift); + GXMAP(type,XK_Control_L, GHOST_kKeyLeftControl); + GXMAP(type,XK_Control_R, GHOST_kKeyRightControl); + GXMAP(type,XK_Alt_L, GHOST_kKeyLeftAlt); + GXMAP(type,XK_Alt_R, GHOST_kKeyRightAlt); + + GXMAP(type,XK_Insert, GHOST_kKeyInsert); + GXMAP(type,XK_Delete, GHOST_kKeyDelete); + GXMAP(type,XK_Home, GHOST_kKeyHome); + GXMAP(type,XK_End, GHOST_kKeyEnd); + GXMAP(type,XK_Page_Up, GHOST_kKeyUpPage); + GXMAP(type,XK_Page_Down, GHOST_kKeyDownPage); + + GXMAP(type,XK_Left, GHOST_kKeyLeftArrow); + GXMAP(type,XK_Right, GHOST_kKeyRightArrow); + GXMAP(type,XK_Up, GHOST_kKeyUpArrow); + GXMAP(type,XK_Down, GHOST_kKeyDownArrow); + + GXMAP(type,XK_Caps_Lock, GHOST_kKeyCapsLock); + GXMAP(type,XK_Scroll_Lock, GHOST_kKeyScrollLock); + GXMAP(type,XK_Num_Lock, GHOST_kKeyNumLock); + + /* keypad events */ + + GXMAP(type,XK_KP_0, GHOST_kKeyNumpad0); + GXMAP(type,XK_KP_1, GHOST_kKeyNumpad1); + GXMAP(type,XK_KP_2, GHOST_kKeyNumpad2); + GXMAP(type,XK_KP_3, GHOST_kKeyNumpad3); + GXMAP(type,XK_KP_4, GHOST_kKeyNumpad4); + GXMAP(type,XK_KP_5, GHOST_kKeyNumpad5); + GXMAP(type,XK_KP_6, GHOST_kKeyNumpad6); + GXMAP(type,XK_KP_7, GHOST_kKeyNumpad7); + GXMAP(type,XK_KP_8, GHOST_kKeyNumpad8); + GXMAP(type,XK_KP_9, GHOST_kKeyNumpad9); + GXMAP(type,XK_KP_Decimal, GHOST_kKeyNumpadPeriod); + + GXMAP(type,XK_KP_Insert, GHOST_kKeyNumpad0); + GXMAP(type,XK_KP_End, GHOST_kKeyNumpad1); + GXMAP(type,XK_KP_Down, GHOST_kKeyNumpad2); + GXMAP(type,XK_KP_Page_Down, GHOST_kKeyNumpad3); + GXMAP(type,XK_KP_Left, GHOST_kKeyNumpad4); + GXMAP(type,XK_KP_Begin, GHOST_kKeyNumpad5); + GXMAP(type,XK_KP_Right, GHOST_kKeyNumpad6); + GXMAP(type,XK_KP_Home, GHOST_kKeyNumpad7); + GXMAP(type,XK_KP_Up, GHOST_kKeyNumpad8); + GXMAP(type,XK_KP_Page_Up, GHOST_kKeyNumpad9); + GXMAP(type,XK_KP_Delete, GHOST_kKeyNumpadPeriod); + + GXMAP(type,XK_KP_Enter, GHOST_kKeyNumpadEnter); + GXMAP(type,XK_KP_Add, GHOST_kKeyNumpadPlus); + GXMAP(type,XK_KP_Subtract, GHOST_kKeyNumpadMinus); + GXMAP(type,XK_KP_Multiply, GHOST_kKeyNumpadAsterisk); + GXMAP(type,XK_KP_Divide, GHOST_kKeyNumpadSlash); + + /* some extra sun cruft (NICE KEYBOARD!) */ +#ifdef __sun__ + GXMAP(type,0xffde, GHOST_kKeyNumpad1); + GXMAP(type,0xffe0, GHOST_kKeyNumpad3); + GXMAP(type,0xffdc, GHOST_kKeyNumpad5); + GXMAP(type,0xffd8, GHOST_kKeyNumpad7); + GXMAP(type,0xffda, GHOST_kKeyNumpad9); + + GXMAP(type,0xffd6, GHOST_kKeyNumpadSlash); + GXMAP(type,0xffd7, GHOST_kKeyNumpadAsterisk); +#endif + + default : + type = GHOST_kKeyUnknown; + break; + } + } + + return type; +} + +#undef GXMAP diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h new file mode 100644 index 00000000000..c8d8d73404a --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -0,0 +1,245 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_SystemX11.h + * Declaration of GHOST_SystemX11 class. + */ + +#ifndef _GHOST_SYSTEM_X11_H_ +#define _GHOST_SYSTEM_X11_H_ + +#include +#include + +#include "GHOST_System.h" +#include "../GHOST_Types.h" + +class GHOST_WindowX11; + +/** + * X11 Implementation of GHOST_System class. + * @see GHOST_System. + * @author Laurence Bourn + * @date October 26, 2001 + */ + +class GHOST_SystemX11 : public GHOST_System { +public: + + /** + * Constructor + * this class should only be instanciated by GHOST_ISystem. + */ + + GHOST_SystemX11( + ); + + GHOST_TSuccess + init( + ); + + + /** + * @section Interface Inherited from GHOST_ISystem + */ + + /** + * Returns the system time. + * Returns the number of milliseconds since the start of the system process. + * @return The number of milliseconds. + */ + GHOST_TUns64 + getMilliSeconds( + ) const; + + + /** + * Returns the number of displays on this system. + * @return The number of displays. + */ + GHOST_TUns8 + getNumDisplays( + ) const; + + /** + * Returns the dimensions of the main display on this system. + * @return The dimension of the main display. + */ + void + getMainDisplayDimensions( + GHOST_TUns32& width, + GHOST_TUns32& height + ) const; + + /** + * Create a new window. + * The new window is added to the list of windows managed. + * Never explicitly delete the window, use disposeWindow() instead. + * @param title The name of the window (displayed in the title bar of the window if the OS supports it). + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state of the window when opened. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Create a stereo visual for quad buffered stereo. + * @return The new window (or 0 if creation failed). + */ + GHOST_IWindow* + createWindow( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual + ); + + /** + * @section Interface Inherited from GHOST_ISystem + */ + + /** + * Retrieves events from the system and stores them in the queue. + * @param waitForEvent Flag to wait for an event (or return immediately). + * @return Indication of the presence of events. + */ + bool + processEvents( + bool waitForEvent + ); + + /** + * @section Interface Inherited from GHOST_System + */ + GHOST_TSuccess + getCursorPosition( + GHOST_TInt32& x, + GHOST_TInt32& y + ) const; + + GHOST_TSuccess + setCursorPosition( + GHOST_TInt32 x, + GHOST_TInt32 y + ) const; + + /** + * Returns the state of all modifier keys. + * @param keys The state of all modifier keys (true == pressed). + * @return Indication of success. + */ + GHOST_TSuccess + getModifierKeys( + GHOST_ModifierKeys& keys + ) const ; + + /** + * Returns the state of the mouse buttons (ouside the message queue). + * @param buttons The state of the buttons. + * @return Indication of success. + */ + GHOST_TSuccess + getButtons( + GHOST_Buttons& buttons + ) const; + + /** + * @section + * Flag a window as dirty. This will + * generate a GHOST window update event on a call to processEvents() + */ + + void + addDirtyWindow( + GHOST_WindowX11 * bad_wind + ); + + + /** + * return a pointer to the X11 display structure + */ + + Display * + getXDisplay( + ) { + return m_display; + } + + +private : + + Display * m_display; + + /** + * Atom used to detect window close events + */ + Atom m_delete_window_atom; + + /// The vector of windows that need to be updated. + std::vector m_dirty_windows; + + /// Start time at initialization. + GHOST_TUns64 m_start_time; + + /// A vector of keyboard key masks + char *m_keyboard_vector; + + /** + * Return the ghost window associated with the + * X11 window xwind + */ + + GHOST_WindowX11 * + findGhostWindow( + Window xwind + ) const ; + + void + processEvent( + XEvent *xe + ); + + bool + generateWindowExposeEvents( + ); + + GHOST_TKey + convertXKey( + KeySym key + ); + +}; + +#endif + diff --git a/intern/ghost/intern/GHOST_TimerManager.cpp b/intern/ghost/intern/GHOST_TimerManager.cpp new file mode 100644 index 00000000000..9f50b350baa --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerManager.cpp @@ -0,0 +1,167 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_TimerManager.h" + +#include + +#include "GHOST_TimerTask.h" + + +GHOST_TimerManager::GHOST_TimerManager() +{ +} + + +GHOST_TimerManager::~GHOST_TimerManager() +{ + disposeTimers(); +} + + +GHOST_TUns32 GHOST_TimerManager::getNumTimers() +{ + return (GHOST_TUns32)m_timers.size(); +} + + +bool GHOST_TimerManager::getTimerFound(GHOST_TimerTask* timer) +{ + TTimerVector::const_iterator iter = std::find(m_timers.begin(), m_timers.end(), timer); + return iter != m_timers.end(); +} + + +GHOST_TSuccess GHOST_TimerManager::addTimer(GHOST_TimerTask* timer) +{ + GHOST_TSuccess success; + if (!getTimerFound(timer)) { + // Add the timer task + m_timers.push_back(timer); + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_TimerManager::removeTimer(GHOST_TimerTask* timer) +{ + GHOST_TSuccess success; + TTimerVector::iterator iter = std::find(m_timers.begin(), m_timers.end(), timer); + if (iter != m_timers.end()) { + // Remove the timer task + m_timers.erase(iter); + delete timer; + timer = 0; + success = GHOST_kSuccess; + } + else { + success = GHOST_kFailure; + } + return success; +} + +GHOST_TUns64 GHOST_TimerManager::nextFireTime() +{ + GHOST_TUns64 smallest = GHOST_kFireTimeNever; + TTimerVector::iterator iter; + + for (iter = m_timers.begin(); iter != m_timers.end(); iter++) { + GHOST_TUns64 next = (*iter)->getNext(); + + if (nextgetNext(); + + // Check if the timer should be fired + if (time > next) { + // Fire the timer + GHOST_TimerProcPtr timerProc = task->getTimerProc(); + GHOST_TUns64 start = task->getStart(); + timerProc(task, time - start); + + // Update the time at which we will fire it again + GHOST_TUns64 interval = task->getInterval(); + GHOST_TUns64 numCalls = (next - start) / interval; + numCalls++; + next = start + numCalls * interval; + task->setNext(next); + + return true; + } else { + return false; + } +} + + +void GHOST_TimerManager::disposeTimers() +{ + while (m_timers.size() > 0) { + delete m_timers[0]; + m_timers.erase(m_timers.begin()); + } +} diff --git a/intern/ghost/intern/GHOST_TimerManager.h b/intern/ghost/intern/GHOST_TimerManager.h new file mode 100644 index 00000000000..ff42f95fc0f --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerManager.h @@ -0,0 +1,132 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_TimerManager.h + * Declaration of GHOST_TimerManager class. + */ + +#ifndef _GHOST_TIMER_MANAGER_H_ +#define _GHOST_TIMER_MANAGER_H_ + +#ifdef WIN32 +#pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif // WIN32 + +#include + +#include "GHOST_Types.h" + +class GHOST_TimerTask; + + +/** + * Manages a list of timer tasks. + * Timer tasks added are owned by the manager. + * Don't delete timer task objects. + * @author Maarten Gribnau + * @date May 31, 2001 + */ +class GHOST_TimerManager +{ +public: + /** + * Constructor. + */ + GHOST_TimerManager(); + + /** + * Destructor. + */ + virtual ~GHOST_TimerManager(); + + /** + * Returns the number of timer tasks. + * @return The number of events on the stack. + */ + virtual GHOST_TUns32 getNumTimers(); + + /** + * Returns whther this timer task ins in our list. + * @return Indication of presence. + */ + virtual bool getTimerFound(GHOST_TimerTask* timer); + + /** + * Adds a timer task to the list. + * It is only added when it not already present in the list. + * @param timer The timer task added to the list. + * @return Indication as to whether addition has succeeded. + */ + virtual GHOST_TSuccess addTimer(GHOST_TimerTask* timer); + + /** + * Removes a timer task from the list. + * It is only removed when it is found in the list. + * @param timer The timer task to be removed from the list. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeTimer(GHOST_TimerTask* timer); + + /** + * Finds the soonest time the next timer would fire. + * @return The soonest time the next timer would fire, + * or GHOST_kFireTimeNever if no timers exist. + */ + virtual GHOST_TUns64 nextFireTime(); + + /** + * Checks all timer tasks to see if they are expired and fires them if needed. + * @param time The current time. + * @return True if any timers were fired. + */ + virtual bool fireTimers(GHOST_TUns64 time); + + /** + * Checks this timer task to see if they are expired and fires them if needed. + * @param time The current time. + * @param task The timer task to check and optionally fire. + * @return True if the timer fired. + */ + virtual bool fireTimer(GHOST_TUns64 time, GHOST_TimerTask* task); + +protected: + /** + * Deletes all timers. + */ + void disposeTimers(); + + typedef std::vector TTimerVector; + /** The list with event consumers. */ + TTimerVector m_timers; +}; + +#endif // _GHOST_TIMER_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_TimerTask.h b/intern/ghost/intern/GHOST_TimerTask.h new file mode 100644 index 00000000000..49bbe5e09ab --- /dev/null +++ b/intern/ghost/intern/GHOST_TimerTask.h @@ -0,0 +1,191 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_TimerTask.h + * Declaration of GHOST_TimerTask class. + */ + +#ifndef _GHOST_TIMER_TASK_H_ +#define _GHOST_TIMER_TASK_H_ + +#include "GHOST_ITimerTask.h" + + +/** + * Implementation of a timer task. + * @author Maarten Gribnau + * @date May 28, 2001 + */ +class GHOST_TimerTask : public GHOST_ITimerTask +{ +public: + /** + * Constructor. + * @param start The timer start time. + * @param interval The interval between calls to the timerProc + * @param timerProc The callbak invoked when the interval expires. + * @param data The timer user data. + */ + GHOST_TimerTask(GHOST_TUns64 start, GHOST_TUns64 interval, GHOST_TimerProcPtr timerProc, GHOST_TUserDataPtr userData = 0) + : m_start(start), m_interval(interval), m_next(start), m_timerProc(timerProc), m_userData(userData), m_auxData(0) + { + } + + /** + * Returns the timer start time. + * @return The timer start time. + */ + inline virtual GHOST_TUns64 getStart() const + { + return m_start; + } + + /** + * Changes the timer start time. + * @param start The timer start time. + */ + virtual void setStart(GHOST_TUns64 start) + { + m_start = start; + } + + /** + * Returns the timer interval. + * @return The timer interval. + */ + inline virtual GHOST_TUns64 getInterval() const + { + return m_interval; + } + + /** + * Changes the timer interval. + * @param interval The timer interval. + */ + virtual void setInterval(GHOST_TUns64 interval) + { + m_interval = interval; + } + + /** + * Returns the time the timerProc will be called. + * @return The time the timerProc will be called. + */ + inline virtual GHOST_TUns64 getNext() const + { + return m_next; + } + + /** + * Changes the time the timerProc will be called. + * @param next The time the timerProc will be called. + */ + virtual void setNext(GHOST_TUns64 next) + { + m_next = next; + } + + /** + * Returns the timer callback. + * @return the timer callback. + */ + inline virtual GHOST_TimerProcPtr getTimerProc() const + { + return m_timerProc; + } + + /** + * Changes the timer callback. + * @param The timer callback. + */ + inline virtual void setTimerProc(const GHOST_TimerProcPtr timerProc) + { + m_timerProc = timerProc; + } + + /** + * Returns the timer user data. + * @return The timer user data. + */ + inline virtual GHOST_TUserDataPtr getUserData() const + { + return m_userData; + } + + /** + * Changes the time user data. + * @param data The timer user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) + { + m_userData = userData; + } + + /** + * Returns the auxiliary storage room. + * @return The auxiliary storage room. + */ + inline virtual GHOST_TUns32 getAuxData() const + { + return m_auxData; + } + + /** + * Changes the auxiliary storage room. + * @param auxData The auxiliary storage room. + */ + virtual void setAuxData(GHOST_TUns32 auxData) + { + m_auxData = auxData; + } + +protected: + /** The time the timer task was started. */ + GHOST_TUns64 m_start; + + /** The interval between calls. */ + GHOST_TUns64 m_interval; + + /** The time the timerProc will be called. */ + GHOST_TUns64 m_next; + + /** The callback invoked when the timer expires. */ + GHOST_TimerProcPtr m_timerProc; + + /** The timer task user data. */ + GHOST_TUserDataPtr m_userData; + + /** Auxiliary storage room. */ + GHOST_TUns32 m_auxData; +}; + +#endif // _GHOST_TIMER_TASK_H_ + diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp new file mode 100644 index 00000000000..f4f7c581814 --- /dev/null +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -0,0 +1,129 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_Window.h" + + +GHOST_Window::GHOST_Window( + const STR_String& /*title*/, + GHOST_TInt32 /*left*/, GHOST_TInt32 /*top*/, GHOST_TUns32 width, GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual) +: + m_drawingContextType(type), + m_cursorVisible(true), + m_cursorShape(GHOST_kStandardCursorDefault), + m_stereoVisual(stereoVisual) +{ + m_fullScreen = state == GHOST_kWindowStateFullScreen; + if (m_fullScreen) { + m_fullScreenWidth = width; + m_fullScreenHeight = height; + } +} + + +GHOST_Window::~GHOST_Window() +{ +} + + +GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (type != m_drawingContextType) { + success = removeDrawingContext(); + if (success) { + success = installDrawingContext(type); + m_drawingContextType = type; + } + else { + m_drawingContextType = GHOST_kDrawingContextTypeNone; + } + } + return success; +} + +GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible) +{ + if (setWindowCursorVisibility(visible)) { + m_cursorVisible = visible; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +GHOST_TSuccess GHOST_Window::setCursorShape(GHOST_TStandardCursor cursorShape) +{ + if (setWindowCursorShape(cursorShape)) { + m_cursorShape = cursorShape; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + +GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], + int hotX, int hotY) +{ + return setCustomCursorShape( (GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, + 16, 16, hotX, hotY, 0, 1 ); +} + +GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, + int fg_color, int bg_color ) +{ + if (setWindowCustomCursorShape(bitmap, mask, sizex, sizey,hotX, hotY, fg_color, bg_color)) { + m_cursorShape = GHOST_kStandardCursorCustom; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +} + diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h new file mode 100644 index 00000000000..acf28177b37 --- /dev/null +++ b/intern/ghost/intern/GHOST_Window.h @@ -0,0 +1,284 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_Window.h + * Declaration of GHOST_Window class. + */ + +#ifndef _GHOST_WINDOW_H_ +#define _GHOST_WINDOW_H_ + +#include "GHOST_IWindow.h" + +class STR_String; + +/** + * Platform independent implementation of GHOST_IWindow. + * Dimensions are given in screen coordinates that are relative to the + * upper-left corner of the screen. + * Implements part of the GHOST_IWindow interface and adds some methods to + * be implemented by childs of this class. + * @author Maarten Gribnau + * @date May 7, 2001 + */ +class GHOST_Window : public GHOST_IWindow +{ +public: + /** + * @section Interface inherited from GHOST_IWindow left for derived class + * implementation. + * virtual bool getValid() const = 0; + * virtual void setTitle(const STR_String& title) = 0; + * virtual void getTitle(STR_String& title) const = 0; + * virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + * virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + * virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + * virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + * virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + * virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual GHOST_TWindowState getState() const = 0; + * virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + * virtual GHOST_TWindowOrder getOrder(void) = 0; + * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + * virtual GHOST_TSuccess swapBuffers() = 0; + * virtual GHOST_TSuccess activateDrawingContext() = 0; + * virtual GHOST_TSuccess invalidate() = 0; + */ + + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param heigh The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_Window( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false); + + /** + * @section Interface inherited from GHOST_IWindow left for derived class + * implementation. + * virtual bool getValid() const = 0; + * virtual void setTitle(const STR_String& title) = 0; + * virtual void getTitle(STR_String& title) const = 0; + * virtual void getWindowBounds(GHOST_Rect& bounds) const = 0; + * virtual void getClientBounds(GHOST_Rect& bounds) const = 0; + * virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0; + * virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height) = 0; + * virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) = 0; + * virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const = 0; + * virtual GHOST_TWindowState getState() const = 0; + * virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; + * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + * virtual GHOST_TSuccess swapBuffers() = 0; + * virtual GHOST_TSuccess activateDrawingContext() = 0; + * virtual GHOST_TSuccess invalidate() = 0; + */ + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_Window(); + + /** + * Returns the current cursor shape. + * @return The current cursor shape. + */ + inline virtual GHOST_TStandardCursor getCursorShape() const; + + /** + * Set the shape of the cursor. + * @param cursor The new cursor shape type id. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape); + + /** + * Set the shape of the cursor to a custom cursor. + * @param bitmap The bitmap data for the cursor. + * @param mask The mask data for the cursor. + * @param hotX The X coordinate of the cursor hotspot. + * @param hotY The Y coordinate of the cursor hotspot. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY); + + virtual GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, int sizey, + int hotX, int hotY, + int fg_color, int bg_color); + + /** + * Returns the visibility state of the cursor. + * @return The visibility state of the cursor. + */ + inline virtual bool getCursorVisibility() const; + + /** + * Shows or hides the cursor. + * @param visible The new visibility state of the cursor. + * @return Indication of success. + */ + virtual GHOST_TSuccess setCursorVisibility(bool visible); + + /** + * Returns the type of drawing context used in this window. + * @return The current type of drawing context. + */ + inline virtual GHOST_TDrawingContextType getDrawingContextType(); + + /** + * Tries to install a rendering context in this window. + * Child classes do not need to overload this method. + * They should overload the installDrawingContext and removeDrawingContext instead. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type); + + /** + * Returns the window user data. + * @return The window user data. + */ + inline virtual GHOST_TUserDataPtr getUserData() const + { + return m_userData; + } + + /** + * Changes the window user data. + * @param data The window user data. + */ + virtual void setUserData(const GHOST_TUserDataPtr userData) + { + m_userData = userData; + } + +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type) = 0; + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeDrawingContext() = 0; + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible) = 0; + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) = 0; + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], + int hotX, int hotY) = 0; + + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int szx, int szy, int hotX, int hotY, int fg, int bg) = 0; + /** The the of drawing context installed in this window. */ + GHOST_TDrawingContextType m_drawingContextType; + + /** The window user data */ + GHOST_TUserDataPtr m_userData; + + /** The current visibility of the cursor */ + bool m_cursorVisible; + + /** The current shape of the cursor */ + GHOST_TStandardCursor m_cursorShape; + + /** Stores wether this is a full screen window. */ + bool m_fullScreen; + + /** Stereo visual created. Only necessary for 'real' stereo support, + * ie quad buffered stereo. This is not always possible, depends on + * the graphics h/w + */ + bool m_stereoVisual; + + /** Full-screen width */ + GHOST_TUns32 m_fullScreenWidth; + /** Full-screen height */ + GHOST_TUns32 m_fullScreenHeight; +}; + + +inline GHOST_TDrawingContextType GHOST_Window::getDrawingContextType() +{ + return m_drawingContextType; +} + +inline bool GHOST_Window::getCursorVisibility() const +{ + return m_cursorVisible; +} + +inline GHOST_TStandardCursor GHOST_Window::getCursorShape() const +{ + return m_cursorShape; +} + +#endif // _GHOST_WINDOW_H + diff --git a/intern/ghost/intern/GHOST_WindowCarbon.cpp b/intern/ghost/intern/GHOST_WindowCarbon.cpp new file mode 100644 index 00000000000..04debe36191 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCarbon.cpp @@ -0,0 +1,742 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_WindowCarbon.h" +#include "GHOST_Debug.h" + +AGLContext GHOST_WindowCarbon::s_firstaglCtx = NULL; +#ifdef GHOST_DRAW_CARBON_GUTTER +const GHOST_TInt32 GHOST_WindowCarbon::s_sizeRectSize = 16; +#endif //GHOST_DRAW_CARBON_GUTTER + +static const GLint sPreferredFormatWindow[8] = { +AGL_RGBA, +AGL_DOUBLEBUFFER, +AGL_ACCELERATED, +AGL_DEPTH_SIZE, 32, +AGL_AUX_BUFFERS, 1, +AGL_NONE, +}; + +static const GLint sPreferredFormatFullScreen[9] = { +AGL_RGBA, +AGL_DOUBLEBUFFER, +AGL_ACCELERATED, +AGL_FULLSCREEN, +AGL_DEPTH_SIZE, 32, +AGL_AUX_BUFFERS, 1, +AGL_NONE, +}; + + + +WindowRef ugly_hack=NULL; + +const EventTypeSpec kWEvents[] = { + { kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */ +}; + +static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) { + WindowRef mywindow; + GHOST_WindowCarbon *ghost_window; + OSStatus err; + int theState; + + if (::GetEventKind(event) == kEventWindowZoom) { + err = ::GetEventParameter (event,kEventParamDirectObject,typeWindowRef,NULL,sizeof(mywindow),NULL, &mywindow); + ghost_window = (GHOST_WindowCarbon *) GetWRefCon(mywindow); + theState = ghost_window->getMac_windowState(); + if (theState == 1) + ghost_window->setMac_windowState(2); + else if (theState == 2) + ghost_window->setMac_windowState(1); + + } + return eventNotHandledErr; +} + +GHOST_WindowCarbon::GHOST_WindowCarbon( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual +) : + GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone), + m_windowRef(0), + m_grafPtr(0), + m_aglCtx(0), + m_customCursor(0), + m_fullScreenDirty(false) +{ + Str255 title255; + OSStatus err; + + //fprintf(stderr," main screen top %i left %i height %i width %i\n", top, left, height, width); + + if (state >= GHOST_kWindowState8Normal ) { + if(state == GHOST_kWindowState8Normal) state= GHOST_kWindowStateNormal; + else if(state == GHOST_kWindowState8Maximized) state= GHOST_kWindowStateMaximized; + else if(state == GHOST_kWindowState8Minimized) state= GHOST_kWindowStateMinimized; + else if(state == GHOST_kWindowState8FullScreen) state= GHOST_kWindowStateFullScreen; + + // state = state - 8; this was the simple version of above code, doesnt work in gcc 4.0 + + setMac_windowState(1); + } else + setMac_windowState(0); + + if (state != GHOST_kWindowStateFullScreen) { + Rect bnds = { top, left, top+height, left+width }; + // Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/ + gen2mac(title, title255); + + err = ::CreateNewWindow( kDocumentWindowClass, + kWindowStandardDocumentAttributes+kWindowLiveResizeAttribute, + &bnds, + &m_windowRef); + + if ( err != noErr) { + fprintf(stderr," error creating window %i \n",err); + } else { + + ::SetWRefCon(m_windowRef,(SInt32)this); + setTitle(title); + err = InstallWindowEventHandler (m_windowRef, myWEventHandlerProc, GetEventTypeCount(kWEvents), kWEvents,NULL,NULL); + if ( err != noErr) { + fprintf(stderr," error creating handler %i \n",err); + } else { + // ::TransitionWindow (m_windowRef,kWindowZoomTransitionEffect,kWindowShowTransitionAction,NULL); + ::ShowWindow(m_windowRef); + ::MoveWindow (m_windowRef, left, top,true); + + } + } + if (m_windowRef) { + m_grafPtr = ::GetWindowPort(m_windowRef); + setDrawingContextType(type); + updateDrawingContext(); + activateDrawingContext(); + } + if(ugly_hack==NULL) { + ugly_hack= m_windowRef; + // when started from commandline, window remains in the back... also for play anim + ProcessSerialNumber psn; + GetCurrentProcess(&psn); + SetFrontProcess(&psn); + } + } + else { + /* + Rect bnds = { top, left, top+height, left+width }; + gen2mac("", title255); + m_windowRef = ::NewCWindow( + nil, // Storage + &bnds, // Bounding rectangle of the window + title255, // Title of the window + 0, // Window initially visible + plainDBox, // procID + (WindowRef)-1L, // Put window before all other windows + 0, // Window has minimize box + (SInt32)this); // Store a pointer to the class in the refCon + */ + //GHOST_PRINT("GHOST_WindowCarbon::GHOST_WindowCarbon(): creating full-screen OpenGL context\n"); + setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);;installDrawingContext(GHOST_kDrawingContextTypeOpenGL); + updateDrawingContext(); + activateDrawingContext(); + + m_tablet.Active = 0; + } +} + + +GHOST_WindowCarbon::~GHOST_WindowCarbon() +{ + if (m_customCursor) delete m_customCursor; + + if(ugly_hack==m_windowRef) ugly_hack= NULL; + + // printf("GHOST_WindowCarbon::~GHOST_WindowCarbon(): removing drawing context\n"); + if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone); + if (m_windowRef) { + ::DisposeWindow(m_windowRef); + m_windowRef = 0; + } +} + +bool GHOST_WindowCarbon::getValid() const +{ + bool valid; + if (!m_fullScreen) { + valid = (m_windowRef != 0) && (m_grafPtr != 0) && ::IsValidWindowPtr(m_windowRef); + } + else { + valid = true; + } + return valid; +} + + +void GHOST_WindowCarbon::setTitle(const STR_String& title) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setTitle(): window invalid") + Str255 title255; + gen2mac(title, title255); + ::SetWTitle(m_windowRef, title255); +} + + +void GHOST_WindowCarbon::getTitle(STR_String& title) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getTitle(): window invalid") + Str255 title255; + ::GetWTitle(m_windowRef, title255); + mac2gen(title255, title); +} + + +void GHOST_WindowCarbon::getWindowBounds(GHOST_Rect& bounds) const +{ + OSStatus success; + Rect rect; + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getWindowBounds(): window invalid") + success = ::GetWindowBounds(m_windowRef, kWindowStructureRgn, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +void GHOST_WindowCarbon::getClientBounds(GHOST_Rect& bounds) const +{ + Rect rect; + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getClientBounds(): window invalid") + ::GetPortBounds(m_grafPtr, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; + + // Subtract gutter height from bottom +#ifdef GHOST_DRAW_CARBON_GUTTER + if ((bounds.m_b - bounds.m_t) > s_sizeRectSize) + { + bounds.m_b -= s_sizeRectSize; + } + else + { + bounds.m_t = bounds.m_b; + } +#endif //GHOST_DRAW_CARBON_GUTTER +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientWidth(GHOST_TUns32 width) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientWidth(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (((GHOST_TUns32)cBnds.getWidth()) != width) { + ::SizeWindow(m_windowRef, width, cBnds.getHeight(), true); + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientHeight(GHOST_TUns32 height) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientHeight(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); +#ifdef GHOST_DRAW_CARBON_GUTTER + if (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize) { + ::SizeWindow(m_windowRef, cBnds.getWidth(), height+s_sizeRectSize, true); + } +#else //GHOST_DRAW_CARBON_GUTTER + if (((GHOST_TUns32)cBnds.getHeight()) != height) { + ::SizeWindow(m_windowRef, cBnds.getWidth(), height, true); + } +#endif //GHOST_DRAW_CARBON_GUTTER + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setClientSize(): window invalid") + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); +#ifdef GHOST_DRAW_CARBON_GUTTER + if ((((GHOST_TUns32)cBnds.getWidth()) != width) || + (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize)) { + ::SizeWindow(m_windowRef, width, height+s_sizeRectSize, true); + } +#else //GHOST_DRAW_CARBON_GUTTER + if ((((GHOST_TUns32)cBnds.getWidth()) != width) || + (((GHOST_TUns32)cBnds.getHeight()) != height)) { + ::SizeWindow(m_windowRef, width, height, true); + } +#endif //GHOST_DRAW_CARBON_GUTTER + return GHOST_kSuccess; +} + + +GHOST_TWindowState GHOST_WindowCarbon::getState() const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::getState(): window invalid") + GHOST_TWindowState state; + if (::IsWindowVisible(m_windowRef)) { + state = GHOST_kWindowStateMinimized; + } + else if (::IsWindowInStandardState(m_windowRef, nil, nil)) { + state = GHOST_kWindowStateMaximized; + } + else { + state = GHOST_kWindowStateNormal; + } + return state; +} + + +void GHOST_WindowCarbon::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::screenToClient(): window invalid") + Point point; + point.h = inX; + point.v = inY; + GrafPtr oldPort; + ::GetPort(&oldPort); + ::SetPort(m_grafPtr); + ::GlobalToLocal(&point); + ::SetPort(oldPort); + outX = point.h; + outY = point.v; +} + + +void GHOST_WindowCarbon::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::clientToScreen(): window invalid") + Point point; + point.h = inX; + point.v = inY; + GrafPtr oldPort; + ::GetPort(&oldPort); + ::SetPort(m_grafPtr); + ::LocalToGlobal(&point); + ::SetPort(oldPort); + outX = point.h; + outY = point.v; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setState(GHOST_TWindowState state) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setState(): window invalid") + switch (state) { + case GHOST_kWindowStateMinimized: + ::HideWindow(m_windowRef); + break; + case GHOST_kWindowStateMaximized: + case GHOST_kWindowStateNormal: + default: + ::ShowWindow(m_windowRef); + break; + } + return GHOST_kSuccess; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setOrder(GHOST_TWindowOrder order) +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::setOrder(): window invalid") + if (order == GHOST_kWindowOrderTop) { + //::BringToFront(m_windowRef); is wrong, front window should be active for input too + ::SelectWindow(m_windowRef); + } + else { + /* doesnt work if you do this with a mouseclick */ + ::SendBehind(m_windowRef, nil); + } + return GHOST_kSuccess; +} + +/*#define WAIT_FOR_VSYNC 1*/ +#ifdef WAIT_FOR_VSYNC +#include +#endif + +GHOST_TSuccess GHOST_WindowCarbon::swapBuffers() +{ +#ifdef WAIT_FOR_VSYNC +/* wait for vsync, to avoid tearing artifacts */ +long VBL = 1; +CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL); +#endif + + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglSwapBuffers(m_aglCtx); + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + +GHOST_TSuccess GHOST_WindowCarbon::updateDrawingContext() +{ + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglUpdateContext(m_aglCtx); + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + +GHOST_TSuccess GHOST_WindowCarbon::activateDrawingContext() +{ + GHOST_TSuccess succeeded = GHOST_kSuccess; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_aglCtx) { + ::aglSetCurrentContext(m_aglCtx); +#ifdef GHOST_DRAW_CARBON_GUTTER + // Restrict drawing to non-gutter area + ::aglEnable(m_aglCtx, AGL_BUFFER_RECT); + GHOST_Rect bnds; + getClientBounds(bnds); + GLint b[4] = + { + bnds.m_l, + bnds.m_t+s_sizeRectSize, + bnds.m_r-bnds.m_l, + bnds.m_b-bnds.m_t + }; + GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b); +#endif //GHOST_DRAW_CARBON_GUTTER + } + else { + succeeded = GHOST_kFailure; + } + } + return succeeded; +} + + +GHOST_TSuccess GHOST_WindowCarbon::installDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success = GHOST_kFailure; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + { + if (!getValid()) break; + + AGLPixelFormat pixelFormat; + if (!m_fullScreen) { + pixelFormat = ::aglChoosePixelFormat(0, 0, sPreferredFormatWindow); + m_aglCtx = ::aglCreateContext(pixelFormat, s_firstaglCtx); + if (!m_aglCtx) break; + if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; + success = ::aglSetDrawable(m_aglCtx, m_grafPtr) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + //GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL\n"); +GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,sPreferredFormatFullScreen); + m_aglCtx = ::aglCreateContext(pixelFormat, 0); + if (!m_aglCtx) break; + if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; + //GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): created OpenGL context\n"); + //::CGGetActiveDisplayList(0, NULL, &m_numDisplays) + success = ::aglSetFullScreen(m_aglCtx, m_fullScreenWidth, m_fullScreenHeight, 75, 0) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + /* + if (success == GHOST_kSuccess) { + GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL succeeded\n"); + } + else { + GHOST_PRINT("GHOST_WindowCarbon::installDrawingContext(): init full-screen OpenGL failed\n"); + } + */ + } + ::aglDestroyPixelFormat(pixelFormat); + } + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + break; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowCarbon::removeDrawingContext() +{ + GHOST_TSuccess success = GHOST_kFailure; + switch (m_drawingContextType) { + case GHOST_kDrawingContextTypeOpenGL: + if (m_aglCtx) { + aglSetCurrentContext(NULL); + aglSetDrawable(m_aglCtx, NULL); + //aglDestroyContext(m_aglCtx); + if (s_firstaglCtx == m_aglCtx) s_firstaglCtx = NULL; + success = ::aglDestroyContext(m_aglCtx) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; + m_aglCtx = 0; + } + break; + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + default: + break; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowCarbon::invalidate() +{ + GHOST_ASSERT(getValid(), "GHOST_WindowCarbon::invalidate(): window invalid") + if (!m_fullScreen) { + Rect rect; + ::GetPortBounds(m_grafPtr, &rect); + ::InvalWindowRect(m_windowRef, &rect); + } + else { + //EventRef event; + //OSStatus status = ::CreateEvent(NULL, kEventClassWindow, kEventWindowUpdate, 0, 0, &event); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): created event " << status << " \n"); + //status = ::SetEventParameter(event, kEventParamDirectObject, typeWindowRef, sizeof(WindowRef), this); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): set event parameter " << status << " \n"); + //status = ::PostEventToQueue(::GetMainEventQueue(), event, kEventPriorityStandard); + //status = ::SendEventToEventTarget(event, ::GetApplicationEventTarget()); + //GHOST_PRINT("GHOST_WindowCarbon::invalidate(): added event to queue " << status << " \n"); + m_fullScreenDirty = true; + } + return GHOST_kSuccess; +} + + +void GHOST_WindowCarbon::gen2mac(const STR_String& in, Str255 out) const +{ + STR_String tempStr = in; + int num = tempStr.Length(); + if (num > 255) num = 255; + ::memcpy(out+1, tempStr.Ptr(), num); + out[0] = num; +} + + +void GHOST_WindowCarbon::mac2gen(const Str255 in, STR_String& out) const +{ + char tmp[256]; + ::memcpy(tmp, in+1, in[0]); + tmp[in[0]] = '\0'; + out = tmp; +} + +void GHOST_WindowCarbon::loadCursor(bool visible, GHOST_TStandardCursor cursor) const +{ + static bool systemCursorVisible = true; + + if (visible != systemCursorVisible) { + if (visible) { + ::ShowCursor(); + systemCursorVisible = true; + } + else { + ::HideCursor(); + systemCursorVisible = false; + } + } + + if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { + ::SetCursor( m_customCursor ); + } else { + int carbon_cursor; + +#define GCMAP(ghostCursor, carbonCursor) case ghostCursor: carbon_cursor = carbonCursor; break + switch (cursor) { + default: + GCMAP( GHOST_kStandardCursorDefault, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorRightArrow, kThemeAliasArrowCursor); + GCMAP( GHOST_kStandardCursorLeftArrow, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorInfo, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorDestroy, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorHelp, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorCycle, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorSpray, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorWait, kThemeWatchCursor); + GCMAP( GHOST_kStandardCursorText, kThemeIBeamCursor); + GCMAP( GHOST_kStandardCursorCrosshair, kThemeCrossCursor); + GCMAP( GHOST_kStandardCursorUpDown, kThemeClosedHandCursor); + GCMAP( GHOST_kStandardCursorLeftRight, kThemeClosedHandCursor); + GCMAP( GHOST_kStandardCursorTopSide, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomSide, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorLeftSide, kThemeResizeLeftCursor); + GCMAP( GHOST_kStandardCursorRightSide, kThemeResizeRightCursor); + GCMAP( GHOST_kStandardCursorTopLeftCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorTopRightCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomRightCorner, kThemeArrowCursor); + GCMAP( GHOST_kStandardCursorBottomLeftCorner, kThemeArrowCursor); + }; +#undef GCMAP + + ::SetThemeCursor(carbon_cursor); + } +} + + +bool GHOST_WindowCarbon::getFullScreenDirty() +{ + return m_fullScreen && m_fullScreenDirty; +} + + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCursorVisibility(bool visible) +{ + if (::FrontWindow() == m_windowRef) { + loadCursor(visible, getCursorShape()); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCursorShape(GHOST_TStandardCursor shape) +{ + if (m_customCursor) { + delete m_customCursor; + m_customCursor = 0; + } + + if (::FrontWindow() == m_windowRef) { + loadCursor(getCursorVisibility(), shape); + } + + return GHOST_kSuccess; +} + +#if 0 +/** Reverse the bits in a GHOST_TUns8 */ +static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) +{ + ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA); + ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC); + ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0); + return ch; +} +#endif + + +/** Reverse the bits in a GHOST_TUns16 */ +static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) +{ + shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); + shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); + shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); + shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); + return shrt; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) +{ + int y; + + if (m_customCursor) { + delete m_customCursor; + m_customCursor = 0; + } + + m_customCursor = new Cursor; + if (!m_customCursor) return GHOST_kFailure; + + for (y=0; y<16; y++) { +#if !defined(__LITTLE_ENDIAN__) + m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8)); + m_customCursor->mask[y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8)); +#else + m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8)); + m_customCursor->mask[y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8)); +#endif + + } + + m_customCursor->hotSpot.h = hotX; + m_customCursor->hotSpot.v = hotY; + + if (::FrontWindow() == m_windowRef) { + loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowCarbon::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], int hotX, int hotY) +{ + return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1); +} + + +void GHOST_WindowCarbon::setMac_windowState(short value) +{ + mac_windowState = value; +} + +short GHOST_WindowCarbon::getMac_windowState() +{ + return mac_windowState; +} diff --git a/intern/ghost/intern/GHOST_WindowCarbon.h b/intern/ghost/intern/GHOST_WindowCarbon.h new file mode 100644 index 00000000000..5b81470a030 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowCarbon.h @@ -0,0 +1,314 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_WindowCarbon.h + * Declaration of GHOST_WindowCarbon class. + */ + +#ifndef _GHOST_WINDOW_CARBON_H_ +#define _GHOST_WINDOW_CARBON_H_ + +#ifndef __APPLE__ +#error Apple OSX only! +#endif // __APPLE__ + +#include "GHOST_Window.h" +#include "STR_String.h" + +#define __CARBONSOUND__ +#include + +#include + + +/** + * Window on Mac OSX/Carbon. + * Carbon windows have a size widget in the lower right corner of the window. + * To force it to be visible, the height of the client rectangle is reduced so + * that applications do not draw in that area. GHOST will manage that area + * which is called the gutter. + * When OpenGL contexts are active, GHOST will use AGL_BUFFER_RECT to prevent + * OpenGL drawing outside the reduced client rectangle. + * @author Maarten Gribnau + * @date May 23, 2001 + */ +class GHOST_WindowCarbon : public GHOST_Window { +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_WindowCarbon( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_WindowCarbon(); + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title); + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const; + + /** + * Returns the window rectangle dimensions. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the cleient area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width); + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height); + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height); + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state); + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); + + /** + * Swaps front and back buffers of a window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Updates the drawing context of this window. Needed + * whenever the window is changed. + * @return Indication of success. + */ + GHOST_TSuccess updateDrawingContext(); + + /** + * Activates the drawing context of this window. + * @return A boolean success indicator. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + virtual void loadCursor(bool visible, GHOST_TStandardCursor cursor) const; + + /** + * Returns the dirty state of the window when in full-screen mode. + * @return Whether it is dirty. + */ + virtual bool getFullScreenDirty(); + + /* accessor for fullscreen window */ + virtual void setMac_windowState(short value); + virtual short getMac_windowState(); + + + const GHOST_TabletData* GetTabletData() + { return &m_tablet; } + + GHOST_TabletData& GetCarbonTabletData() + { return m_tablet; } +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + virtual GHOST_TSuccess removeDrawingContext(); + + /** + * Invalidates the contents of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess invalidate(); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, + int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color); + + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); + + /** + * Converts a string object to a Mac Pascal string. + * @param in The string object to be converted. + * @param out The converted string. + */ + virtual void gen2mac(const STR_String& in, Str255 out) const; + + /** + * Converts a Mac Pascal string to a string object. + * @param in The string to be converted. + * @param out The converted string object. + */ + virtual void mac2gen(const Str255 in, STR_String& out) const; + + WindowRef m_windowRef; + CGrafPtr m_grafPtr; + AGLContext m_aglCtx; + + /** The first created OpenGL context (for sharing display lists) */ + static AGLContext s_firstaglCtx; + + Cursor* m_customCursor; + + GHOST_TabletData m_tablet; + + /** When running in full-screen this tells whether to refresh the window. */ + bool m_fullScreenDirty; + + /** specific MacOs X full screen window setting as we use partially system mechanism + values : 0 not maximizable default + 1 normal state + 2 maximized state + + this will be reworked when rebuilding GHOST carbon to use new OS X apis + in order to be unified with GHOST fullscreen/maximised settings + + (lukep) + **/ + + short mac_windowState; + + + /** + * The width/height of the size rectangle in the lower right corner of a + * Mac/Carbon window. This is also the height of the gutter area. + */ +#ifdef GHOST_DRAW_CARBON_GUTTER + static const GHOST_TInt32 s_sizeRectSize; +#endif // GHOST_DRAW_CARBON_GUTTER +}; + +#endif // _GHOST_WINDOW_CARBON_H_ + diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp new file mode 100644 index 00000000000..775260a9503 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowManager.cpp @@ -0,0 +1,198 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 11, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_WindowManager.h" +#include +#include "GHOST_Debug.h" +#include "GHOST_Window.h" + + +GHOST_WindowManager::GHOST_WindowManager() : + m_fullScreenWindow(0), + m_activeWindow(0), + m_activeWindowBeforeFullScreen(0) +{ +} + + +GHOST_WindowManager::~GHOST_WindowManager() +{ +} + + +GHOST_TSuccess GHOST_WindowManager::addWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (window) { + if (!getWindowFound(window)) { + // Store the pointer to the window + m_windows.push_back(window); + success = GHOST_kSuccess; + } + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::removeWindow(const GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (window) { + if (window == m_fullScreenWindow) { + endFullScreen(); + } + else { + vector::iterator result = find(m_windows.begin(), m_windows.end(), window); + if (result != m_windows.end()) { + setWindowInactive(window); + m_windows.erase(result); + success = GHOST_kSuccess; + } + } + } + return success; +} + + +bool GHOST_WindowManager::getWindowFound(const GHOST_IWindow* window) const +{ + bool found = false; + if (window) { + if (getFullScreen() && (window == m_fullScreenWindow)) { + found = true; + } + else { + vector::const_iterator result = find(m_windows.begin(), m_windows.end(), window); + if (result != m_windows.end()) { + found = true; + } + } + } + return found; +} + + +bool GHOST_WindowManager::getFullScreen(void) const +{ + return m_fullScreenWindow != 0; +} + + +GHOST_IWindow* GHOST_WindowManager::getFullScreenWindow(void) const +{ + return m_fullScreenWindow; +} + + +GHOST_TSuccess GHOST_WindowManager::beginFullScreen(GHOST_IWindow* window, + bool stereoVisual) +{ + GHOST_TSuccess success = GHOST_kFailure; + GHOST_ASSERT(window, "GHOST_WindowManager::beginFullScreen(): invalid window"); + GHOST_ASSERT(window->getValid(), "GHOST_WindowManager::beginFullScreen(): invalid window"); + if (!getFullScreen()) { + m_fullScreenWindow = window; + m_activeWindowBeforeFullScreen = getActiveWindow(); + setActiveWindow(m_fullScreenWindow); + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::endFullScreen(void) +{ + GHOST_TSuccess success = GHOST_kFailure; + if (getFullScreen()) { + if (m_fullScreenWindow != 0) { + //GHOST_PRINT("GHOST_WindowManager::endFullScreen(): deleting full-screen window\n"); + setWindowInactive(m_fullScreenWindow); + delete m_fullScreenWindow; + //GHOST_PRINT("GHOST_WindowManager::endFullScreen(): done\n"); + m_fullScreenWindow = 0; + if (m_activeWindowBeforeFullScreen) { + setActiveWindow(m_activeWindowBeforeFullScreen); + } + } + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowManager::setActiveWindow(GHOST_IWindow* window) +{ + GHOST_TSuccess success = GHOST_kSuccess; + if (window != m_activeWindow) { + if (getWindowFound(window)) { + m_activeWindow = window; + } + else { + success = GHOST_kFailure; + } + } + return success; +} + + +GHOST_IWindow* GHOST_WindowManager::getActiveWindow(void) const +{ + return m_activeWindow; +} + + +void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow* window) +{ + if (window == m_activeWindow) { + m_activeWindow = 0; + } +} + + + std::vector & +GHOST_WindowManager:: +getWindows( +){ + return m_windows; +} + diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h new file mode 100644 index 00000000000..f2ad003d801 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowManager.h @@ -0,0 +1,164 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_WindowManager.h + * Declaration of GHOST_WindowManager class. + */ + +#ifndef _GHOST_WINDOW_MANAGER_H_ +#define _GHOST_WINDOW_MANAGER_H_ + +#ifdef WIN32 +#pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif // WIN32 + +#include + +#include "GHOST_Rect.h" +#include "GHOST_IWindow.h" + + +/** + * Manages system windows (platform independent implementation). + * @author Maarten Gribnau + * @date May 11, 2001 + */ +class GHOST_WindowManager +{ +public: + /** + * Constructor. + */ + GHOST_WindowManager(); + + /** + * Destructor. + */ + virtual ~GHOST_WindowManager(); + + /** + * Add a window to our list. + * It is only added if it is not already in the list. + * @param window Pointer to the window to be added. + * @return Indication of success. + */ + virtual GHOST_TSuccess addWindow(GHOST_IWindow* window); + + /** + * Remove a window from our list. + * @param window Pointer to the window to be removed. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeWindow(const GHOST_IWindow* window); + + /** + * Returns whether the window is in our list. + * @param window Pointer to the window to query. + * @return A boolean indicator. + */ + virtual bool getWindowFound(const GHOST_IWindow* window) const; + + /** + * Returns whether one of the windows is fullscreen. + * @return A boolean indicator. + */ + virtual bool getFullScreen(void) const; + + /** + * Returns pointer to the full-screen window. + * @return The fll-screen window (0 if not in full-screen). + */ + virtual GHOST_IWindow* getFullScreenWindow(void) const; + + /** + * Activates fullscreen mode for a window. + * @param window The window displayed fullscreen. + * @return Indication of success. + */ + virtual GHOST_TSuccess beginFullScreen(GHOST_IWindow* window, const bool stereoVisual); + + /** + * Closes fullscreen mode down. + * @return Indication of success. + */ + virtual GHOST_TSuccess endFullScreen(void); + + /** + * Sets new window as active window (the window receiving events). + * There can be only one window active which should be in the current window list. + * @param window The new active window. + */ + virtual GHOST_TSuccess setActiveWindow(GHOST_IWindow* window); + + /** + * Returns the active window (the window receiving events). + * There can be only one window active which should be in the current window list. + * @return window The active window (or NULL if there is none). + */ + virtual GHOST_IWindow* getActiveWindow(void) const; + + + /** + * Set this window to be inactive (not receiving events). + * @param window The window to decativate. + */ + virtual void setWindowInactive(const GHOST_IWindow* window); + + + /** + * Return a vector of the windows currently managed by this + * class. + * @warning It is very dangerous to mess with the contents of + * this vector. Please do not destroy or add windows use the + * interface above for this, + */ + + std::vector & + getWindows( + ); + + +protected: + /** The list of windows managed */ + std::vector m_windows; + + /** Window in fullscreen state. There can be only one of this which is not in or window list. */ + GHOST_IWindow* m_fullScreenWindow; + + /** The active window. */ + GHOST_IWindow* m_activeWindow; + + /** Window that was active before entering fullscreen state. */ + GHOST_IWindow* m_activeWindowBeforeFullScreen; +}; + +#endif // _GHOST_WINDOW_MANAGER_H_ + diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp new file mode 100644 index 00000000000..ef7294c2354 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -0,0 +1,886 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "GHOST_WindowWin32.h" +#include +#include + +// MSVC6 still doesn't define M_PI +#ifndef M_PI +#define M_PI 3.1415926536 +#endif + +LPCSTR GHOST_WindowWin32::s_windowClassName = "GHOST_WindowClass"; +const int GHOST_WindowWin32::s_maxTitleLength = 128; +HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL; + +static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd); +static int EnumPixelFormats(HDC hdc); + +/* + * Color and depth bit values are not to be trusted. + * For instance, on TNT2: + * When the screen color depth is set to 16 bit, we get 5 color bits + * and 16 depth bits. + * When the screen color depth is set to 32 bit, we get 8 color bits + * and 24 depth bits. + * Just to be safe, we request high waulity settings. + */ +static PIXELFORMATDESCRIPTOR sPreferredFormat = { + sizeof(PIXELFORMATDESCRIPTOR), /* size */ + 1, /* version */ + PFD_SUPPORT_OPENGL | + PFD_DRAW_TO_WINDOW | + PFD_SWAP_COPY | /* support swap copy */ + PFD_DOUBLEBUFFER, /* support double-buffering */ + PFD_TYPE_RGBA, /* color type */ + 32, /* prefered color depth */ + 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ + 0, /* no alpha buffer */ + 0, /* alpha bits (ignored) */ + 0, /* no accumulation buffer */ + 0, 0, 0, 0, /* accum bits (ignored) */ + 32, /* depth buffer */ + 0, /* no stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, 0, 0 /* no layer, visible, damage masks */ +}; + +GHOST_WindowWin32::GHOST_WindowWin32( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual) +: + GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone, + stereoVisual), + m_hDC(0), + m_hGlRc(0), + m_hasMouseCaptured(false), + m_nPressedButtons(0), + m_customCursor(0), + m_tabletData(NULL), + m_tablet(0), + m_wintab(NULL), + m_maxPressure(0) +{ + if (state != GHOST_kWindowStateFullScreen) { + /* Convert client size into window size */ + width += GetSystemMetrics(SM_CXSIZEFRAME)*2; + height += GetSystemMetrics(SM_CYSIZEFRAME)*2 + GetSystemMetrics(SM_CYCAPTION); + + m_hWnd = ::CreateWindow( + s_windowClassName, // pointer to registered class name + title, // pointer to window name + WS_OVERLAPPEDWINDOW, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + 0, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data + } + else { + m_hWnd = ::CreateWindow( + s_windowClassName, // pointer to registered class name + title, // pointer to window name + WS_POPUP | WS_MAXIMIZE, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + 0, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data + } + if (m_hWnd) { + // Store a pointer to this class in the window structure + LONG result = ::SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this); + + // Store the device context + m_hDC = ::GetDC(m_hWnd); + + // Show the window + int nCmdShow; + switch (state) { + case GHOST_kWindowStateMaximized: + nCmdShow = SW_SHOWMAXIMIZED; + break; + case GHOST_kWindowStateMinimized: + nCmdShow = SW_SHOWMINIMIZED; + break; + case GHOST_kWindowStateNormal: + default: + nCmdShow = SW_SHOWNORMAL; + break; + } + setDrawingContextType(type); + ::ShowWindow(m_hWnd, nCmdShow); + // Force an initial paint of the window + ::UpdateWindow(m_hWnd); + } + + m_wintab = ::LoadLibrary("Wintab32.dll"); + if (m_wintab) { + GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" ); + GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" ); + + // let's see if we can initialize tablet here + /* check if WinTab available. */ + if (fpWTInfo && fpWTInfo(0, 0, NULL)) { + // Now init the tablet + LOGCONTEXT lc; + AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */ + + // Open a Wintab context + + // Get default context information + fpWTInfo( WTI_DEFCONTEXT, 0, &lc ); + + // Open the context + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PACKETMODE; + lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM; + + /* Set the entire tablet as active */ + fpWTInfo(WTI_DEVICES,DVC_X,&TabletX); + fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY); + + /* get the max pressure, to divide into a float */ + BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure); + if (pressureSupport) + m_maxPressure = Pressure.axMax; + else + m_maxPressure = 0; + + /* get the max tilt axes, to divide into floats */ + BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation); + if (tiltSupport) { + /* does the tablet support azimuth ([0]) and altitude ([1]) */ + if (Orientation[0].axResolution && Orientation[1].axResolution) { + /* all this assumes the minimum is 0 */ + m_maxAzimuth = Orientation[0].axMax; + m_maxAltitude = Orientation[1].axMax; + } + else { /* no so dont do tilt stuff */ + m_maxAzimuth = m_maxAltitude = 0; + } + } + + if (fpWTOpen) { + m_tablet = fpWTOpen( m_hWnd, &lc, TRUE ); + if (m_tablet) { + m_tabletData = new GHOST_TabletData(); + m_tabletData->Active = 0; + } + } + } + } +} + + +GHOST_WindowWin32::~GHOST_WindowWin32() +{ + if (m_wintab) { + GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" ); + if (fpWTClose) { + if (m_tablet) + fpWTClose(m_tablet); + if (m_tabletData) + delete m_tabletData; + m_tabletData = NULL; + } + } + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + setDrawingContextType(GHOST_kDrawingContextTypeNone); + if (m_hDC) { + ::ReleaseDC(m_hWnd, m_hDC); + m_hDC = 0; + } + if (m_hWnd) { + ::DestroyWindow(m_hWnd); + m_hWnd = 0; + } +} + +bool GHOST_WindowWin32::getValid() const +{ + return m_hWnd != 0; +} + + +void GHOST_WindowWin32::setTitle(const STR_String& title) +{ + ::SetWindowText(m_hWnd, title); +} + + +void GHOST_WindowWin32::getTitle(STR_String& title) const +{ + char buf[s_maxTitleLength]; + ::GetWindowText(m_hWnd, buf, s_maxTitleLength); + STR_String temp (buf); + title = buf; +} + + +void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const +{ + RECT rect; + ::GetWindowRect(m_hWnd, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const +{ + RECT rect; + ::GetClientRect(m_hWnd, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (cBnds.getWidth() != width) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth() + width - cBnds.getWidth(); + int cy = wBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (cBnds.getHeight() != height) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth(); + int cy = wBnds.getHeight() + height - cBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if ((cBnds.getWidth() != width) || (cBnds.getHeight() != height)) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth() + width - cBnds.getWidth(); + int cy = wBnds.getHeight() + height - cBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TWindowState GHOST_WindowWin32::getState() const +{ + GHOST_TWindowState state; + if (::IsIconic(m_hWnd)) { + state = GHOST_kWindowStateMinimized; + } + else if (::IsZoomed(m_hWnd)) { + state = GHOST_kWindowStateMaximized; + } + else { + state = GHOST_kWindowStateNormal; + } + return state; +} + + +void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + POINT point = { inX, inY }; + ::ScreenToClient(m_hWnd, &point); + outX = point.x; + outY = point.y; +} + + +void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + POINT point = { inX, inY }; + ::ClientToScreen(m_hWnd, &point); + outX = point.x; + outY = point.y; +} + + +GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) +{ + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + ::GetWindowPlacement(m_hWnd, &wp); + switch (state) { + case GHOST_kWindowStateMinimized: + wp.showCmd = SW_SHOWMINIMIZED; + break; + case GHOST_kWindowStateMaximized: + ShowWindow(m_hWnd, SW_HIDE); //fe. HACK! + //Solves redraw problems when switching from fullscreen to normal. + + wp.showCmd = SW_SHOWMAXIMIZED; + SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + break; + case GHOST_kWindowStateFullScreen: + wp.showCmd = SW_SHOWMAXIMIZED; + SetWindowLong(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE); + break; + case GHOST_kWindowStateNormal: + default: + wp.showCmd = SW_SHOWNORMAL; + break; + } + return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order) +{ + HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM; + return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::swapBuffers() +{ + // adding a glFinish() here is to prevent Geforce in 'full scene antialias' mode + // from antialising the Blender window. Officially a swapbuffers does a glFinish + // itself, so this feels really like a hack... but it won't harm. (ton) + glFinish(); + return ::SwapBuffers(m_hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext() +{ + GHOST_TSuccess success; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_hDC && m_hGlRc) { + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::invalidate() +{ + GHOST_TSuccess success; + if (m_hWnd) { + success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + { + if(m_stereoVisual) + sPreferredFormat.dwFlags |= PFD_STEREO; + + // Attempt to match device context pixel format to the preferred format + int iPixelFormat = EnumPixelFormats(m_hDC); + if (iPixelFormat == 0) { + success = GHOST_kFailure; + break; + } + if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) { + success = GHOST_kFailure; + break; + } + // For debugging only: retrieve the pixel format chosen + PIXELFORMATDESCRIPTOR preferredFormat; + ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat); + // Create the context + m_hGlRc = ::wglCreateContext(m_hDC); + if (m_hGlRc) { + if (s_firsthGLRc) { + wglShareLists(s_firsthGLRc, m_hGlRc); + } else { + s_firsthGLRc = m_hGlRc; + } + + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext() +{ + GHOST_TSuccess success; + switch (m_drawingContextType) { + case GHOST_kDrawingContextTypeOpenGL: + if (m_hGlRc) { + success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + if (m_hGlRc == s_firsthGLRc) { + s_firsthGLRc = NULL; + } + m_hGlRc = 0; + } + else { + success = GHOST_kFailure; + } + break; + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + default: + success = GHOST_kFailure; + } + return success; +} + +void GHOST_WindowWin32::lostMouseCapture() +{ + if (m_hasMouseCaptured) { + m_hasMouseCaptured = false; + m_nPressedButtons = 0; + } +} + +void GHOST_WindowWin32::registerMouseClickEvent(bool press) +{ + if (press) { + if (!m_hasMouseCaptured) { + ::SetCapture(m_hWnd); + m_hasMouseCaptured = true; + } + m_nPressedButtons++; + } else { + if (m_nPressedButtons) { + m_nPressedButtons--; + if (!m_nPressedButtons) { + ::ReleaseCapture(); + m_hasMouseCaptured = false; + } + } + } +} + + +void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const +{ + if (!visible) { + while (::ShowCursor(FALSE) >= 0); + } + else { + while (::ShowCursor(TRUE) < 0); + } + + if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { + ::SetCursor( m_customCursor ); + } else { + // Convert GHOST cursor to Windows OEM cursor + bool success = true; + LPCSTR id; + switch (cursor) { + case GHOST_kStandardCursorDefault: id = IDC_ARROW; break; + case GHOST_kStandardCursorRightArrow: id = IDC_ARROW; break; + case GHOST_kStandardCursorLeftArrow: id = IDC_ARROW; break; + case GHOST_kStandardCursorInfo: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west + case GHOST_kStandardCursorDestroy: id = IDC_NO; break; // Slashed circle + case GHOST_kStandardCursorHelp: id = IDC_HELP; break; // Arrow and question mark + case GHOST_kStandardCursorCycle: id = IDC_NO; break; // Slashed circle + case GHOST_kStandardCursorSpray: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west + case GHOST_kStandardCursorWait: id = IDC_WAIT; break; // Hourglass + case GHOST_kStandardCursorText: id = IDC_IBEAM; break; // I-beam + case GHOST_kStandardCursorCrosshair: id = IDC_CROSS; break; // Crosshair + case GHOST_kStandardCursorUpDown: id = IDC_SIZENS; break; // Double-pointed arrow pointing north and south + case GHOST_kStandardCursorLeftRight: id = IDC_SIZEWE; break; // Double-pointed arrow pointing west and east + case GHOST_kStandardCursorTopSide: id = IDC_UPARROW; break; // Vertical arrow + case GHOST_kStandardCursorBottomSide: id = IDC_SIZENS; break; + case GHOST_kStandardCursorLeftSide: id = IDC_SIZEWE; break; + case GHOST_kStandardCursorTopLeftCorner: id = IDC_SIZENWSE; break; + case GHOST_kStandardCursorTopRightCorner: id = IDC_SIZENESW; break; + case GHOST_kStandardCursorBottomRightCorner: id = IDC_SIZENWSE; break; + case GHOST_kStandardCursorBottomLeftCorner: id = IDC_SIZENESW; break; + case GHOST_kStandardCursorPencil: id = IDC_ARROW; break; + default: + success = false; + } + + if (success) { + HCURSOR hCursor = ::SetCursor(::LoadCursor(0, id)); + } + } +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible) +{ + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(visible, getCursorShape()); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape) +{ + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(getCursorVisibility(), cursorShape); + } + + return GHOST_kSuccess; +} +void GHOST_WindowWin32::processWin32TabletInitEvent() +{ + if (m_wintab) { + GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" ); + + // let's see if we can initialize tablet here + /* check if WinTab available. */ + if (fpWTInfo) { + AXIS Pressure, Orientation[3]; /* The maximum tablet size */ + + BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure); + if (pressureSupport) + m_maxPressure = Pressure.axMax; + else + m_maxPressure = 0; + + BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation); + if (tiltSupport) { + /* does the tablet support azimuth ([0]) and altitude ([1]) */ + if (Orientation[0].axResolution && Orientation[1].axResolution) { + m_maxAzimuth = Orientation[0].axMax; + m_maxAltitude = Orientation[1].axMax; + } + else { /* no so dont do tilt stuff */ + m_maxAzimuth = m_maxAltitude = 0; + } + } + + m_tabletData->Active = 0; + } + } +} + +void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) +{ + PACKET pkt; + if (m_wintab) { + GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" ); + if (fpWTPacket) { + if (fpWTPacket((HCTX)lParam, wParam, &pkt)) { + if (m_tabletData) { + switch (pkt.pkCursor) { + case 0: /* first device */ + case 3: /* second device */ + m_tabletData->Active = 0; /* puck - not yet supported */ + break; + case 1: + case 4: + m_tabletData->Active = 1; /* stylus */ + break; + case 2: + case 5: + m_tabletData->Active = 2; /* eraser */ + break; + } + if (m_maxPressure > 0) { + m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure; + } else { + m_tabletData->Pressure = 1.0f; + } + + if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) { + ORIENTATION ort = pkt.pkOrientation; + float vecLen; + float altRad, azmRad; /* in radians */ + + /* + from the wintab spec: + orAzimuth Specifies the clockwise rotation of the + cursor about the z axis through a full circular range. + + orAltitude Specifies the angle with the x-y plane + through a signed, semicircular range. Positive values + specify an angle upward toward the positive z axis; + negative values specify an angle downward toward the negative z axis. + + wintab.h defines .orAltitude as a UINT but documents .orAltitude + as positive for upward angles and negative for downward angles. + WACOM uses negative altitude values to show that the pen is inverted; + therefore we cast .orAltitude as an (int) and then use the absolute value. + */ + + /* convert raw fixed point data to radians */ + altRad = (fabs((float)ort.orAltitude)/(float)m_maxAltitude) * M_PI/2.0; + azmRad = ((float)ort.orAzimuth/(float)m_maxAzimuth) * M_PI*2.0; + + /* find length of the stylus' projected vector on the XY plane */ + vecLen = cos(altRad); + + /* from there calculate X and Y components based on azimuth */ + m_tabletData->Xtilt = sin(azmRad) * vecLen; + m_tabletData->Ytilt = sin(M_PI/2.0 - azmRad) * vecLen; + + } else { + m_tabletData->Xtilt = 0.0f; + m_tabletData->Ytilt = 0.0f; + } + } + } + } + } +} + +/** Reverse the bits in a GHOST_TUns8 */ +static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) +{ + ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA); + ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC); + ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0); + return ch; +} + +/** Reverse the bits in a GHOST_TUns16 */ +static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) +{ + shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); + shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); + shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); + shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); + return shrt; +} +GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], int hotX, int hotY) +{ + return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, + 16, 16, hotX, hotY, 0, 1); +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY, + int fg_color, int bg_color) +{ + GHOST_TUns32 andData[32]; + GHOST_TUns32 xorData[32]; + GHOST_TUns32 fullBitRow, fullMaskRow; + int x, y, cols; + + cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */ + if (sizeX%8) cols++; + + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + memset(&andData, 0xFF, sizeof(andData)); + memset(&xorData, 0, sizeof(xorData)); + + for (y=0; y=0; x--){ + fullBitRow<<=8; + fullMaskRow<<=8; + fullBitRow |= uns8ReverseBits(bitmap[cols*y + x]); + fullMaskRow |= uns8ReverseBits( mask[cols*y + x]); + } + xorData[y]= fullBitRow & fullMaskRow; + andData[y]= ~fullMaskRow; + } + + m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData); + if (!m_customCursor) { + return GHOST_kFailure; + } + + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); + } + + return GHOST_kSuccess; +} + + +/* Ron Fosner's code for weighting pixel formats and forcing software. + See http://www.opengl.org/resources/faq/technical/weight.cpp */ + +static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) { + int weight = 0; + + /* assume desktop color depth is 32 bits per pixel */ + + /* cull unusable pixel formats */ + /* if no formats can be found, can we determine why it was rejected? */ + if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) || + !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || + !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */ + ( pfd.cDepthBits <= 8 ) || + !(pfd.iPixelType == PFD_TYPE_RGBA) ) + return 0; + + weight = 1; /* it's usable */ + + /* the bigger the depth buffer the better */ + /* give no weight to a 16-bit depth buffer, because those are crap */ + weight += pfd.cDepthBits - 16; + + weight += pfd.cColorBits - 8; + + /* want swap copy capability -- it matters a lot */ + if(pfd.dwFlags & PFD_SWAP_COPY) weight += 16; + + /* but if it's a generic (not accelerated) view, it's really bad */ + if(pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10; + + return weight; +} + +/* A modification of Ron Fosner's replacement for ChoosePixelFormat */ +/* returns 0 on error, else returns the pixel format number to be used */ +static int EnumPixelFormats(HDC hdc) { + int iPixelFormat; + int i, n, w, weight = 0; + PIXELFORMATDESCRIPTOR pfd, pfd_fallback; + + /* we need a device context to do anything */ + if(!hdc) return 0; + + iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */ + + /* obtain detailed information about + the device context's first pixel format */ + n = 1+::DescribePixelFormat(hdc, iPixelFormat, + sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + /* choose a pixel format using the useless Windows function in case + we come up empty handed */ + iPixelFormat = ::ChoosePixelFormat( hdc, &sPreferredFormat ); + + if(!iPixelFormat) return 0; /* couldn't find one to use */ + + for(i=1; i<=n; i++) { /* not the idiom, but it's right */ + ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd ); + w = WeightPixelFormat(pfd); + if(w > weight) { + weight = w; + iPixelFormat = i; + } + } + + return iPixelFormat; +} + + diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h new file mode 100644 index 00000000000..08209c0ec29 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -0,0 +1,311 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_WindowWin32.h + * Declaration of GHOST_WindowWin32 class. + */ + +#ifndef _GHOST_WINDOW_WIN32_H_ +#define _GHOST_WINDOW_WIN32_H_ + +#ifndef WIN32 +#error WIN32 only! +#endif // WIN32 + +#include "GHOST_Window.h" + +#include + + +#include +#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR) +#define PACKETMODE PK_BUTTONS +#include + +// typedefs for WinTab functions to allow dynamic loading +typedef UINT (API * GHOST_WIN32_WTInfo) ( UINT, UINT, LPVOID ); +typedef HCTX (API * GHOST_WIN32_WTOpen) (HWND, LPLOGCONTEXTA, BOOL); +typedef BOOL (API * GHOST_WIN32_WTClose) (HCTX); +typedef BOOL (API * GHOST_WIN32_WTPacket) (HCTX, UINT, LPVOID); + +/** + * GHOST window on M$ Windows OSs. + * @author Maarten Gribnau + * @date May 10, 2001 + */ +class GHOST_WindowWin32 : public GHOST_Window { +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_WindowWin32( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + virtual ~GHOST_WindowWin32(); + + /** + * Returns indication as to whether the window is valid. + * @return The validity of the window. + */ + virtual bool getValid() const; + + /** + * Sets the title displayed in the title bar. + * @param title The title to display in the title bar. + */ + virtual void setTitle(const STR_String& title); + + /** + * Returns the title displayed in the title bar. + * @param title The title displayed in the title bar. + */ + virtual void getTitle(STR_String& title) const; + + /** + * Returns the window rectangle dimensions. + * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @param bounds The bounding rectangle of the window. + */ + virtual void getWindowBounds(GHOST_Rect& bounds) const; + + /** + * Returns the client rectangle dimensions. + * The left and top members of the rectangle are always zero. + * @param bounds The bounding rectangle of the cleient area of the window. + */ + virtual void getClientBounds(GHOST_Rect& bounds) const; + + /** + * Resizes client rectangle width. + * @param width The new width of the client area of the window. + */ + virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width); + + /** + * Resizes client rectangle height. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height); + + /** + * Resizes client rectangle. + * @param width The new width of the client area of the window. + * @param height The new height of the client area of the window. + */ + virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height); + + /** + * Returns the state of the window (normal, minimized, maximized). + * @return The state of the window. + */ + virtual GHOST_TWindowState getState() const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate on the screen. + * @param inY The y-coordinate on the screen. + * @param outX The x-coordinate in the client rectangle. + * @param outY The y-coordinate in the client rectangle. + */ + virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Converts a point in screen coordinates to client rectangle coordinates + * @param inX The x-coordinate in the client rectangle. + * @param inY The y-coordinate in the client rectangle. + * @param outX The x-coordinate on the screen. + * @param outY The y-coordinate on the screen. + */ + virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const; + + /** + * Sets the state of the window (normal, minimized, maximized). + * @param state The state of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setState(GHOST_TWindowState state); + + /** + * Sets the order of the window (bottom, top). + * @param order The order of the window. + * @return Indication of success. + */ + virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order); + + /** + * Swaps front and back buffers of a window. + * @return Indication of success. + */ + virtual GHOST_TSuccess swapBuffers(); + + /** + * Activates the drawing context of this window. + * @return Indication of success. + */ + virtual GHOST_TSuccess activateDrawingContext(); + + /** + * Invalidates the contents of this window. + */ + virtual GHOST_TSuccess invalidate(); + + /** + * Returns the name of the window class. + * @return The name of the window class. + */ + static LPCSTR getWindowClassName() { return s_windowClassName; } + + /** + * Register a mouse click event (should be called + * for any real button press, controls mouse + * capturing). + * + * @param press True the event was a button press. + */ + void registerMouseClickEvent(bool press); + + /** + * Inform the window that it has lost mouse capture, + * called in response to native window system messages. + */ + void lostMouseCapture(); + + /** + * Loads the windows equivalent of a standard GHOST cursor. + * @param visible Flag for cursor visibility. + * @param cursorShape The cursor shape. + */ + void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const; + + const GHOST_TabletData* GetTabletData() + { return m_tabletData; } + + void processWin32TabletInitEvent(); + void processWin32TabletEvent(WPARAM wParam, LPARAM lParam); + +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication of success. + */ + virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type); + + /** + * Removes the current drawing context. + * @return Indication of success. + */ + virtual GHOST_TSuccess removeDrawingContext(); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); + + virtual GHOST_TSuccess setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color + ); + + /** Window handle. */ + HWND m_hWnd; + /** Device context handle. */ + HDC m_hDC; + /** OpenGL rendering context. */ + HGLRC m_hGlRc; + /** The first created OpenGL context (for sharing display lists) */ + static HGLRC s_firsthGLRc; + /** Flag for if window has captured the mouse */ + bool m_hasMouseCaptured; + /** Count of number of pressed buttons */ + int m_nPressedButtons; + /** HCURSOR structure of the custom cursor */ + HCURSOR m_customCursor; + + static LPCSTR s_windowClassName; + static const int s_maxTitleLength; + + /** WinTab dll handle */ + HMODULE m_wintab; + + /** Tablet data for GHOST */ + GHOST_TabletData* m_tabletData; + + /** Stores the Tablet context if detected Tablet features using WinTab.dll */ + HCTX m_tablet; + LONG m_maxPressure; + LONG m_maxAzimuth, m_maxAltitude; + +}; + +#endif // _GHOST_WINDOW_WIN32_H_ + diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp new file mode 100644 index 00000000000..30fa30e59e6 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -0,0 +1,1032 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "GHOST_WindowX11.h" +#include "GHOST_SystemX11.h" +#include "STR_String.h" +#include "GHOST_Debug.h" + +// For standard X11 cursors +#include +#include + +#if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__) +#include +#endif + + +// For obscure full screen mode stuuf +// lifted verbatim from blut. + +typedef struct { + long flags; + long functions; + long decorations; + long input_mode; +} MotifWmHints; + +#define MWM_HINTS_DECORATIONS (1L << 1) + +/* +import bpy +I = bpy.data.images['blender.png'] # the 48x48 icon + +# Write to a file that can be +# used within static unsigned char BLENDER_ICON_48x48x24[] = {...} +f = open('/myicon.txt', 'w') +for j in xrange(48): + for k in xrange(48): + v = I.getPixelI(j,47-k) + v.pop() + for p in v: + f.write(str(hex(p))+',') + + f.write('\n') +*/ + +// See the python script above to regenerate the 48x48 icon within blender +#define BLENDER_ICON_WIDTH 48 +#define BLENDER_ICON_HEIGHT 48 +static unsigned char BLENDER_ICON_48x48x24[] = { +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x2a,0xd,0xa7,0x5b,0x1f,0xb8,0x66,0x22,0x6c,0x3b,0x14,0x5,0x3,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x6f,0x3a,0x13,0xea,0x7f,0x2c,0xee,0x7e,0x2b,0xee,0x7e,0x2b,0xef,0x85,0x2e,0x5f,0x35,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x43,0x22,0xb,0xed,0x7f,0x2c,0xed,0x7c,0x2b,0xee,0x7f,0x2c,0xee,0x80,0x2c,0xee,0x80,0x2c,0xa8,0x5f,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x2e,0x16,0x6,0xd0,0x6f,0x26,0xed,0x7b,0x2a,0xed,0x7d,0x2b,0xee,0x7f,0x2c,0xee,0x80,0x2c,0xee,0x82,0x2d,0x9a,0x57,0x1d,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x17,0xb,0x4,0xb9,0x60,0x21,0xed,0x7a,0x2a,0xed,0x7b,0x2a,0xed,0x7e,0x2b,0xee,0x7f,0x2c,0xee,0x7f,0x2c,0xee,0x86,0x2e,0x4e,0x2b,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1,0x0,0x0,0x96,0x4d,0x19,0xee,0x7a,0x2a,0xed,0x79,0x2a,0xed,0x7c,0x2b,0xed,0x7e,0x2b,0xed,0x7e,0x2b,0xef,0x83,0x2d,0x98,0x55,0x1c,0x3,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x20,0xf,0x5,0x4b,0x27,0xe,0x21,0x11,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x67,0x34,0x11,0xed,0x7b,0x2a,0xec,0x79,0x29,0xed,0x7b,0x2a,0xed,0x7c,0x2b,0xed,0x7d,0x2b,0xee,0x7f,0x2c,0xbb,0x69,0x24,0x11,0x9,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x38,0x1c,0x9,0xc9,0x6d,0x2c,0xf1,0x86,0x36,0xd7,0x79,0x2a,0x22,0x12,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x3b,0x1d,0x9,0xe0,0x74,0x27,0xed,0x7a,0x2a,0xed,0x7c,0x2a,0xed,0x7d,0x2b,0xed,0x7d,0x2b,0xed,0x7d,0x2b,0xdc,0x7a,0x2a,0x1e,0xf,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xa6,0x56,0x23,0xee,0x83,0x3b,0xed,0x7d,0x2c,0xf0,0x85,0x2e,0x75,0x43,0x17,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x25,0x12,0x5,0xc9,0x68,0x24,0xed,0x7b,0x2a,0xed,0x7d,0x2b,0xed,0x7e,0x2b,0xee,0x7e,0x2c,0xed,0x7d,0x2b,0xe3,0x7d,0x2b,0x3b,0x1f,0xa,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1c,0xd,0x4,0xd9,0x74,0x35,0xee,0x83,0x3a,0xee,0x7f,0x2b,0xf0,0x86,0x2e,0x83,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xa,0x5,0x1,0xa1,0x54,0x1c,0xee,0x7e,0x2c,0xed,0x7e,0x2c,0xed,0x7f,0x2c,0xed,0x80,0x2c,0xed,0x7f,0x2b,0xec,0x81,0x2d,0x60,0x33,0x11,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7a,0x38,0xee,0x84,0x3a,0xee,0x82,0x2c,0xf0,0x88,0x2f,0x82,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x6f,0x39,0x13,0xef,0x82,0x30,0xed,0x82,0x2f,0xee,0x82,0x2e,0xee,0x82,0x2d,0xee,0x81,0x2c,0xf0,0x83,0x2d,0x88,0x49,0x18,0x3,0x2,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7c,0x3a,0xee,0x86,0x3b,0xee,0x84,0x2d,0xf1,0x8b,0x30,0x82,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0x54,0x2b,0xf,0xe9,0x80,0x30,0xee,0x87,0x33,0xef,0x88,0x32,0xef,0x88,0x30,0xee,0x85,0x2f,0xef,0x83,0x2e,0xae,0x5f,0x20,0x4,0x2,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe0,0x7e,0x3d,0xef,0x8a,0x3d,0xef,0x88,0x2e,0xf1,0x8d,0x31,0x81,0x4d,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0x29,0x15,0x7,0xd2,0x74,0x2d,0xf0,0x8b,0x36,0xf0,0x8d,0x35,0xef,0x8d,0x35,0xef,0x8b,0x33,0xef,0x88,0x30,0xc4,0x6d,0x26,0x18,0xc,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x11,0x5,0xe1,0x80,0x3f,0xf0,0x8d,0x3f,0xef,0x8a,0x2f,0xf1,0x8f,0x32,0x81,0x4e,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x3,0x0,0xb1,0x61,0x26,0xf1,0x8e,0x3a,0xf1,0x90,0x3a,0xf0,0x90,0x38,0xf0,0x90,0x36,0xef,0x8e,0x35,0xd3,0x7a,0x2c,0x22,0x11,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x24,0x12,0x5,0xe1,0x83,0x42,0xf0,0x90,0x42,0xf0,0x8d,0x30,0xf2,0x92,0x33,0x80,0x4e,0x1b,0x0,0x0,0x0,0x3,0x2,0x0,0x81,0x45,0x1b,0xf1,0x90,0x3e,0xf1,0x94,0x3d,0xf1,0x95,0x3c,0xf0,0x94,0x3b,0xf0,0x92,0x39,0xf0,0x90,0x35,0xd0,0x7b,0x2b,0xc2,0x6e,0x26,0xbe,0x6c,0x25,0x94,0x54,0x1c,0x5b,0x33,0x11,0x1a,0xe,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x25,0x14,0x6,0xe2,0x86,0x44,0xf1,0x94,0x45,0xf0,0x90,0x31,0xf2,0x94,0x33,0x80,0x4e,0x1b,0x0,0x0,0x0,0x60,0x34,0x14,0xed,0x8c,0x3e,0xf0,0x96,0x42,0xf1,0x97,0x40,0xf1,0x95,0x3f,0xf0,0x91,0x39,0xef,0x8e,0x33,0xef,0x8d,0x31,0xf0,0x8d,0x31,0xef,0x8c,0x30,0xef,0x8c,0x30,0xf0,0x8d,0x31,0xf1,0x8e,0x31,0xe1,0x85,0x2e,0x92,0x55,0x1d,0x25,0x14,0x7,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe2,0x89,0x46,0xf2,0x97,0x47,0xf1,0x92,0x32,0xf2,0x96,0x34,0x80,0x4e,0x1a,0x32,0x1a,0xa,0xe3,0x87,0x3d,0xf1,0x97,0x45,0xf1,0x98,0x44,0xf1,0x95,0x41,0xf0,0x90,0x39,0xef,0x8d,0x30,0xef,0x8f,0x31,0xf0,0x90,0x32,0xf0,0x92,0x33,0xf1,0x93,0x33,0xf1,0x94,0x34,0xf1,0x94,0x34,0xf0,0x93,0x34,0xf0,0x91,0x32,0xf1,0x91,0x33,0xe2,0x8a,0x30,0x6b,0x3f,0x15,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe3,0x8b,0x49,0xf2,0x9a,0x49,0xf1,0x93,0x32,0xf2,0x98,0x35,0x8f,0x57,0x1d,0xcf,0x7c,0x38,0xf2,0x99,0x48,0xf1,0x98,0x47,0xf1,0x96,0x44,0xf0,0x90,0x39,0xef,0x8d,0x31,0xf0,0x90,0x31,0xf0,0x92,0x33,0xf1,0x94,0x33,0xf1,0x96,0x35,0xf1,0x98,0x35,0xf1,0x9a,0x36,0xf1,0x9c,0x37,0xf2,0x9d,0x37,0xf2,0x9c,0x37,0xf2,0x99,0x36,0xf0,0x94,0x34,0xf3,0x97,0x35,0x9f,0x60,0x21,0x13,0xb,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe3,0x8d,0x4b,0xf2,0x9b,0x4c,0xf1,0x93,0x32,0xf1,0x97,0x35,0xea,0x98,0x43,0xf2,0x9d,0x4d,0xf1,0x9a,0x4b,0xf1,0x99,0x49,0xf0,0x93,0x3d,0xf0,0x8d,0x30,0xf0,0x90,0x32,0xf0,0x92,0x32,0xf0,0x94,0x34,0xf1,0x96,0x34,0xf1,0x98,0x36,0xf1,0x9a,0x36,0xf2,0x9c,0x38,0xf2,0x9f,0x38,0xf2,0xa2,0x39,0xf3,0xa2,0x39,0xf3,0xa2,0x39,0xf2,0x9f,0x38,0xf1,0x99,0x35,0xf2,0x97,0x35,0xba,0x74,0x29,0x13,0xb,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x8e,0x4d,0xf2,0x9d,0x4e,0xf1,0x93,0x32,0xf2,0x9d,0x3f,0xf3,0xa4,0x54,0xf2,0x9d,0x50,0xf1,0x9b,0x4d,0xf2,0x98,0x46,0xef,0x8d,0x31,0xf0,0x8f,0x31,0xf0,0x91,0x32,0xf0,0x93,0x32,0xf1,0x94,0x32,0xf1,0x95,0x32,0xf1,0x98,0x34,0xf1,0x9b,0x36,0xf2,0x9e,0x38,0xf2,0xa1,0x39,0xf2,0xa4,0x3a,0xf3,0xa6,0x3b,0xf4,0xa8,0x3c,0xf3,0xa7,0x3c,0xf3,0xa4,0x3a,0xf2,0x9c,0x37,0xf2,0x99,0x36,0xa9,0x69,0x25,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x90,0x50,0xf2,0x9e,0x51,0xf1,0x95,0x35,0xf4,0xa6,0x54,0xf3,0xa2,0x55,0xf2,0x9e,0x51,0xf2,0x9c,0x4e,0xf0,0x8f,0x35,0xf0,0x8e,0x31,0xf0,0x90,0x32,0xf3,0xa5,0x56,0xf7,0xc4,0x8e,0xfa,0xd8,0xb6,0xfb,0xdf,0xc2,0xfa,0xd8,0xb2,0xf7,0xc4,0x89,0xf4,0xae,0x59,0xf2,0xa1,0x38,0xf3,0xa5,0x3b,0xf4,0xa8,0x3c,0xf4,0xab,0x3d,0xf4,0xac,0x3e,0xf4,0xab,0x3d,0xf3,0xa7,0x3b,0xf2,0x9e,0x38,0xf4,0x9e,0x38,0x6f,0x45,0x17,0x1,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x19,0xc,0x5,0x63,0x36,0x18,0x3f,0x20,0x9,0x2,0x1,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x26,0x14,0x6,0xe4,0x91,0x52,0xf3,0xa2,0x55,0xf2,0x9d,0x43,0xf4,0xa7,0x5b,0xf3,0xa2,0x57,0xf3,0xa0,0x55,0xf1,0x97,0x43,0xf0,0x8d,0x30,0xf2,0x9d,0x4c,0xfa,0xda,0xbc,0xfe,0xfb,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfb,0xf6,0xfa,0xdc,0xb5,0xf4,0xae,0x4e,0xf4,0xa9,0x3c,0xf4,0xac,0x3d,0xf4,0xae,0x3f,0xf4,0xaf,0x3f,0xf4,0xad,0x3f,0xf3,0xa8,0x3d,0xf2,0x9d,0x38,0xe2,0x94,0x34,0x23,0x14,0x6,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x11,0x8,0x3,0x9e,0x62,0x39,0xf2,0x91,0x4e,0xe7,0x79,0x29,0x48,0x25,0xc,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0x27,0x13,0x6,0xe5,0x93,0x54,0xf3,0xa7,0x59,0xf4,0xa6,0x56,0xf4,0xa7,0x5d,0xf3,0xa4,0x59,0xf3,0xa2,0x57,0xf1,0x90,0x36,0xf4,0xa7,0x5d,0xfe,0xf4,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf2,0xe3,0xf6,0xb8,0x5f,0xf4,0xac,0x3e,0xf4,0xaf,0x3f,0xf4,0xb1,0x40,0xf4,0xb2,0x40,0xf5,0xaf,0x3f,0xf3,0xa6,0x3c,0xf3,0x9f,0x38,0x90,0x5d,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x3d,0x1f,0xf,0xed,0x9c,0x6a,0xef,0x8b,0x4a,0xec,0x78,0x29,0xe4,0x79,0x2a,0x29,0x15,0x7,0x0,0x0,0x0,0xff,0x0,0xff,0x28,0x14,0x6,0xe6,0x97,0x57,0xf5,0xad,0x63,0xf5,0xac,0x62,0xf4,0xa8,0x5f,0xf4,0xa6,0x5c,0xf3,0xa0,0x53,0xf4,0xa9,0x64,0xfe,0xf8,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xff,0xf2,0xf7,0xfa,0xed,0xf4,0xf8,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf7,0xed,0xf5,0xb5,0x53,0xf5,0xb0,0x3f,0xf5,0xb3,0x41,0xf5,0xb4,0x42,0xf5,0xb3,0x41,0xf4,0xad,0x3f,0xf3,0xa1,0x39,0xe4,0x98,0x37,0x1d,0x11,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x43,0x23,0x10,0xf2,0xa1,0x70,0xf1,0x99,0x61,0xec,0x78,0x2a,0xed,0x7b,0x2a,0xc4,0x69,0x23,0x15,0xa,0x3,0x0,0x0,0x0,0x1d,0xf,0x5,0xe7,0x9b,0x5b,0xf5,0xb1,0x68,0xf5,0xad,0x65,0xf4,0xaa,0x62,0xf4,0xa8,0x5f,0xf3,0xa4,0x59,0xfd,0xec,0xde,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfd,0xfe,0xc3,0xda,0xe9,0x5c,0x9a,0xc5,0x2a,0x7b,0xb4,0x17,0x6f,0xae,0x36,0x81,0xb8,0x91,0xbb,0xd9,0xf0,0xf6,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe7,0xc7,0xf5,0xb2,0x43,0xf6,0xb3,0x41,0xf5,0xb5,0x43,0xf5,0xb6,0x43,0xf5,0xb3,0x42,0xf4,0xa8,0x3c,0xf4,0xa2,0x3a,0x66,0x41,0x17,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x22,0x10,0x7,0xd6,0x88,0x5b,0xf2,0xa5,0x76,0xee,0x84,0x3f,0xed,0x7a,0x2a,0xee,0x80,0x2c,0xa5,0x59,0x1e,0x7,0x3,0x1,0x19,0xd,0x4,0xe7,0x9e,0x5e,0xf6,0xb2,0x6b,0xf5,0xae,0x67,0xf5,0xac,0x65,0xf4,0xa9,0x61,0xf8,0xcc,0xa1,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xfe,0xfe,0x97,0xbf,0xdb,0x33,0x83,0xbb,0x24,0x7e,0xb9,0x3,0x6a,0xae,0x0,0x66,0xab,0x0,0x64,0xa9,0x1,0x63,0xa9,0x3c,0x87,0xbd,0xee,0xf5,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf8,0xc7,0x76,0xf6,0xb4,0x41,0xf5,0xb7,0x43,0xf6,0xb8,0x44,0xf6,0xb6,0x43,0xf5,0xae,0x3f,0xf3,0xa2,0x3a,0xac,0x71,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x52,0x2c,0x16,0xf0,0xa1,0x71,0xf2,0xa2,0x6f,0xed,0x7e,0x32,0xed,0x7e,0x2b,0xef,0x82,0x2d,0x8a,0x49,0x18,0x1b,0xe,0x4,0xe7,0xa2,0x61,0xf6,0xb3,0x6e,0xf6,0xb0,0x6a,0xf5,0xae,0x67,0xf5,0xab,0x64,0xfe,0xf4,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xb4,0xd1,0xe5,0x3e,0x8d,0xc3,0x37,0x8e,0xc5,0x16,0x7a,0xb9,0x0,0x6b,0xaf,0x0,0x68,0xac,0x0,0x65,0xaa,0x0,0x65,0xab,0x0,0x66,0xac,0x4d,0x93,0xc4,0xf8,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe7,0xc5,0xf6,0xb3,0x40,0xf6,0xb7,0x43,0xf6,0xb9,0x44,0xf6,0xb8,0x45,0xf5,0xb2,0x41,0xf3,0xa5,0x3b,0xe2,0x98,0x37,0x3,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x86,0x4e,0x2e,0xf3,0xa6,0x77,0xf1,0x9e,0x66,0xed,0x7e,0x2d,0xee,0x82,0x2c,0xf0,0x85,0x2d,0x7e,0x47,0x17,0xe8,0xa6,0x64,0xf6,0xb5,0x70,0xf6,0xb2,0x6d,0xf5,0xb0,0x6a,0xf7,0xbb,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xfb,0xfd,0x5b,0x9c,0xca,0x42,0x96,0xcb,0x3c,0x93,0xc9,0x9,0x73,0xb6,0x0,0x6b,0xb0,0x0,0x69,0xad,0x0,0x66,0xab,0x0,0x66,0xab,0x0,0x67,0xad,0x4,0x6a,0xaf,0xbb,0xd7,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf8,0xee,0xf6,0xb9,0x4f,0xf6,0xb7,0x44,0xf6,0xba,0x45,0xf6,0xba,0x45,0xf5,0xb5,0x43,0xf4,0xa8,0x3d,0xf5,0xa7,0x3d,0x1b,0xf,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x11,0x8,0x3,0xb0,0x6d,0x45,0xf4,0xaa,0x7b,0xf1,0x9a,0x5b,0xee,0x82,0x2d,0xef,0x86,0x2e,0xee,0x91,0x36,0xf5,0xb5,0x70,0xf6,0xb7,0x73,0xf6,0xb4,0x70,0xf5,0xb1,0x6c,0xf9,0xcc,0xa1,0xff,0xff,0xff,0xff,0xff,0xff,0xd1,0xe2,0xef,0x4b,0x97,0xca,0x47,0x9a,0xce,0x3f,0x95,0xcb,0x3,0x71,0xb5,0x0,0x6c,0xb0,0x0,0x69,0xae,0x0,0x67,0xac,0x0,0x66,0xac,0x0,0x67,0xad,0x0,0x69,0xaf,0x66,0xa5,0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfa,0xf8,0xc3,0x67,0xf6,0xb8,0x44,0xf6,0xba,0x45,0xf6,0xbb,0x46,0xf6,0xb7,0x44,0xf4,0xab,0x3e,0xf8,0xab,0x3f,0x2a,0x19,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x2b,0x15,0x9,0xd4,0x8a,0x5c,0xf4,0xac,0x7c,0xf1,0x98,0x54,0xee,0x85,0x2e,0xf1,0x93,0x38,0xf6,0xba,0x75,0xf6,0xb9,0x75,0xf6,0xb6,0x72,0xf6,0xb3,0x6f,0xfa,0xd5,0xb1,0xff,0xff,0xff,0xff,0xff,0xff,0xb0,0xcf,0xe5,0x51,0x9e,0xcf,0x4b,0x9d,0xd0,0x43,0x97,0xcc,0x3,0x71,0xb5,0x0,0x6d,0xb1,0x0,0x6a,0xae,0x0,0x67,0xac,0x0,0x67,0xad,0x0,0x68,0xae,0x0,0x6a,0xb0,0x3b,0x8c,0xc2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf9,0xc9,0x77,0xf6,0xb8,0x44,0xf6,0xba,0x45,0xf6,0xbc,0x46,0xf6,0xb8,0x44,0xf4,0xad,0x3f,0xf8,0xac,0x3f,0x2a,0x1a,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x47,0x26,0x12,0xee,0xa3,0x72,0xf4,0xae,0x7b,0xf1,0x97,0x4e,0xf1,0x92,0x38,0xf6,0xbb,0x78,0xf6,0xbb,0x78,0xf6,0xb7,0x75,0xf6,0xb5,0x71,0xfa,0xd6,0xb2,0xff,0xff,0xff,0xff,0xff,0xff,0xad,0xcd,0xe4,0x54,0xa0,0xd1,0x4e,0xa0,0xd1,0x48,0x9b,0xce,0xb,0x76,0xb8,0x0,0x6d,0xb2,0x0,0x6a,0xaf,0x0,0x68,0xad,0x0,0x68,0xad,0x0,0x69,0xae,0x0,0x6b,0xb1,0x36,0x89,0xc1,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xf9,0xc9,0x76,0xf6,0xb9,0x44,0xf6,0xbb,0x46,0xf6,0xbc,0x47,0xf6,0xb9,0x44,0xf4,0xad,0x3f,0xf8,0xad,0x40,0x2a,0x1a,0x8,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x70,0x42,0x26,0xf4,0xad,0x7b,0xf5,0xb1,0x7d,0xf3,0x9f,0x50,0xf7,0xbc,0x7b,0xf7,0xbc,0x7b,0xf6,0xb9,0x78,0xf6,0xb7,0x74,0xf9,0xd0,0xa6,0xff,0xff,0xff,0xff,0xff,0xff,0xc3,0xda,0xeb,0x56,0xa0,0xd0,0x51,0xa1,0xd2,0x4a,0x9c,0xcf,0x20,0x82,0xbf,0x0,0x6e,0xb2,0x0,0x6b,0xb0,0x0,0x68,0xae,0x0,0x68,0xae,0x0,0x69,0xaf,0x0,0x6b,0xb1,0x50,0x98,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf9,0xf8,0xc3,0x66,0xf6,0xb9,0x45,0xf7,0xbb,0x46,0xf6,0xbc,0x47,0xf6,0xb8,0x45,0xf4,0xad,0x3f,0xf8,0xac,0x3f,0x2a,0x19,0x7,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xc,0x5,0x0,0xa5,0x67,0x40,0xf5,0xb1,0x7f,0xf5,0xb7,0x7e,0xf7,0xbf,0x80,0xf7,0xbe,0x7d,0xf7,0xbb,0x7b,0xf6,0xb9,0x78,0xf8,0xc2,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xee,0xf5,0xf9,0x5b,0xa0,0xce,0x53,0xa2,0xd2,0x4c,0x9e,0xd0,0x3c,0x93,0xc8,0x6,0x71,0xb4,0x0,0x6c,0xb0,0x0,0x69,0xae,0x0,0x69,0xae,0x0,0x6a,0xaf,0x0,0x6b,0xb1,0x9b,0xc5,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf7,0xec,0xf6,0xba,0x4e,0xf6,0xb9,0x45,0xf7,0xbb,0x46,0xf6,0xbc,0x47,0xf5,0xb7,0x44,0xf4,0xab,0x3e,0xf5,0xa8,0x3e,0x18,0xd,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1f,0x10,0x7,0xc9,0x84,0x56,0xf5,0xb5,0x81,0xf7,0xbf,0x82,0xf8,0xc0,0x80,0xf7,0xbd,0x7d,0xf7,0xba,0x7a,0xf6,0xb8,0x77,0xfe,0xf5,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0x9a,0xc2,0xdf,0x55,0x9f,0xd0,0x4e,0x9f,0xd0,0x47,0x99,0xcc,0x2a,0x87,0xc1,0x3,0x6d,0xb1,0x0,0x69,0xaf,0x0,0x6a,0xaf,0x0,0x6a,0xb0,0x27,0x80,0xbc,0xec,0xf4,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe5,0xbf,0xf6,0xb6,0x42,0xf6,0xba,0x46,0xf7,0xbb,0x46,0xf7,0xbb,0x47,0xf5,0xb5,0x43,0xf3,0xa8,0x3d,0xdd,0x97,0x37,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x32,0x1a,0xb,0xe4,0x9d,0x6a,0xf7,0xbd,0x84,0xf8,0xc1,0x83,0xf8,0xbe,0x80,0xf7,0xbd,0x7d,0xf7,0xba,0x79,0xfa,0xd9,0xb6,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xf6,0xfa,0x74,0xac,0xd4,0x4f,0x9b,0xcd,0x48,0x99,0xcc,0x41,0x94,0xc8,0x2c,0x85,0xbe,0xb,0x70,0xb3,0x1,0x6a,0xb0,0xb,0x6e,0xb2,0xbf,0xd9,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xf8,0xc8,0x74,0xf6,0xb7,0x44,0xf6,0xba,0x46,0xf7,0xbb,0x46,0xf7,0xb9,0x46,0xf6,0xb2,0x42,0xf4,0xa7,0x3d,0xa6,0x70,0x29,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x2e,0x18,0xef,0xaf,0x78,0xf8,0xc1,0x85,0xf8,0xc0,0x82,0xf7,0xbe,0x7f,0xf7,0xbc,0x7d,0xf7,0xbe,0x81,0xfe,0xf3,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xf2,0xf7,0xfa,0x91,0xbd,0xdb,0x4f,0x97,0xc8,0x40,0x8e,0xc3,0x37,0x8a,0xc0,0x34,0x88,0xbf,0x57,0x9c,0xca,0xcc,0xe1,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xe4,0xbf,0xf5,0xb6,0x45,0xf6,0xb8,0x45,0xf6,0xba,0x46,0xf7,0xba,0x46,0xf6,0xb7,0x45,0xf5,0xad,0x3f,0xf4,0xa9,0x40,0x5c,0x3d,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x85,0x55,0x31,0xf7,0xbd,0x84,0xf8,0xc2,0x85,0xf8,0xc0,0x82,0xf7,0xbe,0x80,0xf7,0xbc,0x7d,0xf9,0xcb,0x99,0xfe,0xf9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xfe,0xfe,0xe5,0xef,0xf6,0xc1,0xda,0xeb,0xba,0xd5,0xe9,0xd8,0xe8,0xf2,0xf9,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xf3,0xe4,0xf6,0xb9,0x51,0xf5,0xb5,0x43,0xf6,0xb8,0x45,0xf6,0xb9,0x46,0xf6,0xb8,0x46,0xf6,0xb3,0x43,0xf4,0xa7,0x3e,0xdf,0x9d,0x43,0x17,0xd,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x14,0xa,0x4,0xb2,0x7b,0x4b,0xf8,0xc2,0x88,0xf8,0xc1,0x85,0xf7,0xbf,0x82,0xf7,0xbe,0x80,0xf7,0xbd,0x7d,0xf9,0xca,0x97,0xfe,0xf9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xf2,0xe1,0xf7,0xbc,0x5d,0xf5,0xb3,0x42,0xf5,0xb6,0x44,0xf5,0xb7,0x45,0xf6,0xb8,0x45,0xf6,0xb5,0x44,0xf5,0xad,0x40,0xf6,0xae,0x4c,0x88,0x5d,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x1d,0x10,0x6,0xdb,0xa0,0x68,0xf8,0xc3,0x88,0xf7,0xc1,0x85,0xf7,0xc0,0x82,0xf7,0xbf,0x80,0xf7,0xbe,0x7e,0xf8,0xc4,0x88,0xfc,0xe6,0xcc,0xfe,0xfb,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfa,0xf3,0xfa,0xda,0xa9,0xf5,0xb3,0x4a,0xf5,0xb2,0x42,0xf5,0xb3,0x43,0xf5,0xb6,0x44,0xf5,0xb7,0x45,0xf5,0xb5,0x44,0xf5,0xb0,0x42,0xf5,0xad,0x4d,0xdd,0x9e,0x4a,0x19,0xf,0x5,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x50,0x33,0x19,0xec,0xb4,0x7a,0xf8,0xc2,0x87,0xf7,0xc1,0x85,0xf7,0xc1,0x83,0xf7,0xc0,0x80,0xf7,0xc0,0x7f,0xf7,0xc0,0x7c,0xf7,0xc2,0x7e,0xf8,0xcc,0x92,0xfa,0xda,0xb0,0xfb,0xdf,0xb9,0xfa,0xd9,0xad,0xf7,0xc8,0x84,0xf5,0xb4,0x54,0xf4,0xad,0x3f,0xf4,0xaf,0x41,0xf5,0xb2,0x42,0xf5,0xb4,0x43,0xf5,0xb5,0x44,0xf5,0xb4,0x44,0xf5,0xb2,0x46,0xf5,0xb2,0x54,0xf5,0xb4,0x5a,0x5e,0x3e,0x1a,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x71,0x4b,0x29,0xf8,0xc0,0x86,0xf7,0xc3,0x87,0xf7,0xc2,0x85,0xf7,0xc1,0x83,0xf7,0xc2,0x82,0xf7,0xc2,0x7f,0xf7,0xc2,0x7e,0xf6,0xc0,0x76,0xf4,0xb4,0x59,0xf3,0xa8,0x3e,0xf3,0xa7,0x39,0xf3,0xa9,0x3d,0xf4,0xab,0x3e,0xf4,0xad,0x40,0xf4,0xb0,0x41,0xf4,0xb2,0x42,0xf5,0xb2,0x42,0xf5,0xb3,0x45,0xf6,0xb7,0x54,0xf6,0xb7,0x60,0xf6,0xb5,0x5f,0x9d,0x6b,0x31,0x2,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x8b,0x5f,0x36,0xf9,0xc1,0x87,0xf7,0xc3,0x88,0xf8,0xc3,0x86,0xf7,0xc3,0x84,0xf8,0xc3,0x81,0xf7,0xc4,0x80,0xf7,0xc4,0x7e,0xf7,0xc4,0x7d,0xf7,0xc3,0x7a,0xf6,0xbd,0x6c,0xf5,0xb7,0x5c,0xf5,0xb5,0x54,0xf5,0xb4,0x50,0xf5,0xb6,0x52,0xf6,0xb9,0x58,0xf6,0xbd,0x62,0xf7,0xbf,0x6a,0xf6,0xba,0x66,0xf6,0xb6,0x63,0xab,0x78,0x39,0xa,0x6,0x2,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x83,0x58,0x32,0xf0,0xb9,0x7f,0xf7,0xc3,0x88,0xf7,0xc3,0x86,0xf8,0xc4,0x84,0xf7,0xc5,0x82,0xf7,0xc5,0x80,0xf7,0xc5,0x7f,0xf8,0xc5,0x7d,0xf7,0xc4,0x7b,0xf7,0xc4,0x79,0xf7,0xc4,0x78,0xf7,0xc3,0x76,0xf7,0xc3,0x74,0xf7,0xc2,0x71,0xf6,0xbe,0x6d,0xf6,0xba,0x6a,0xf4,0xb6,0x65,0x8a,0x5e,0x2c,0xc,0x7,0x3,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x4f,0x33,0x1a,0xd2,0x99,0x60,0xf8,0xc4,0x89,0xf8,0xc3,0x86,0xf8,0xc4,0x84,0xf7,0xc5,0x82,0xf7,0xc5,0x80,0xf7,0xc5,0x7f,0xf7,0xc4,0x7e,0xf7,0xc4,0x7b,0xf7,0xc3,0x79,0xf7,0xc2,0x77,0xf6,0xc0,0x74,0xf6,0xbd,0x71,0xf6,0xbb,0x6e,0xe1,0xa4,0x59,0x5c,0x3d,0x1b,0x1,0x1,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xe,0x6,0x0,0x72,0x4b,0x28,0xd0,0x9a,0x62,0xf7,0xbf,0x80,0xf8,0xc4,0x85,0xf7,0xc3,0x82,0xf7,0xc3,0x80,0xf7,0xc3,0x7e,0xf7,0xc1,0x7c,0xf6,0xc0,0x7a,0xf7,0xbf,0x78,0xf8,0xbc,0x72,0xde,0xa2,0x5d,0x80,0x57,0x2b,0x13,0xb,0x4,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x19,0xe,0x5,0x44,0x2c,0x15,0x81,0x59,0x32,0xb2,0x80,0x4c,0xcb,0x95,0x5b,0xd2,0x9c,0x5f,0xcd,0x97,0x5a,0xb9,0x86,0x4d,0x8b,0x61,0x34,0x4a,0x30,0x17,0x15,0xc,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0x0,0x0,0x0,0x1,0x0,0x0,0x3,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff,0xff,0x0,0xff, +}; + + +GLXContext GHOST_WindowX11::s_firstContext = NULL; + +GHOST_WindowX11:: +GHOST_WindowX11( + GHOST_SystemX11 *system, + Display * display, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual +) : + GHOST_Window(title,left,top,width,height,state,type,stereoVisual), + m_context(NULL), + m_display(display), + m_system (system), + m_valid_setup (false), + m_invalid_window(false), + m_empty_cursor(None), + m_custom_cursor(None) +{ + + // Set up the minimum atrributes that we require and see if + // X can find us a visual matching those requirements. + + int attributes[40], i = 0; + + + if(m_stereoVisual) + attributes[i++] = GLX_STEREO; + + attributes[i++] = GLX_RGBA; + attributes[i++] = GLX_DOUBLEBUFFER; + attributes[i++] = GLX_RED_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_BLUE_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_GREEN_SIZE; attributes[i++] = 1; + attributes[i++] = GLX_DEPTH_SIZE; attributes[i++] = 1; + attributes[i] = None; + + m_visual = glXChooseVisual(m_display, DefaultScreen(m_display), attributes); + + if (m_visual == NULL) { + // barf : no visual meeting these requirements could be found. + printf("%s:%d: X11 glxChooseVisual() failed for OpenGL, verify working openGL system!\n", __FILE__, __LINE__); + return; + } + + // Create a bunch of attributes needed to create an X window. + + + // First create a colormap for the window and visual. + // This seems pretty much a legacy feature as we are in rgba mode anyway. + + XSetWindowAttributes xattributes; + memset(&xattributes, 0, sizeof(xattributes)); + + xattributes.colormap= XCreateColormap( + m_display, + RootWindow(m_display, m_visual->screen), + m_visual->visual, + AllocNone + ); + + xattributes.border_pixel= 0; + + // Specify which events we are interested in hearing. + + xattributes.event_mask= + ExposureMask | StructureNotifyMask | + KeyPressMask | KeyReleaseMask | + EnterWindowMask | LeaveWindowMask | + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | FocusChangeMask; + + // create the window! + + m_window = + XCreateWindow( + m_display, + RootWindow(m_display, m_visual->screen), + left, + top, + width, + height, + 0, // no border. + m_visual->depth, + InputOutput, + m_visual->visual, + CWBorderPixel|CWColormap|CWEventMask, + &xattributes + ); + + + // Are we in fullscreen mode - then include + // some obscure blut code to remove decorations. + + if (state == GHOST_kWindowStateFullScreen) { + + MotifWmHints hints; + Atom atom; + + atom = XInternAtom(m_display, "_MOTIF_WM_HINTS", False); + + if (atom == None) { + GHOST_PRINT("Could not intern X atom for _MOTIF_WM_HINTS.\n"); + } else { + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = 0; /* Absolutely no decorations. */ + // other hints.decorations make no sense + // you can't select individual decorations + + XChangeProperty(m_display, m_window, + atom, atom, 32, + PropModeReplace, (unsigned char *) &hints, 4); + } + } else if (state == GHOST_kWindowStateMaximized) { + // With this, xprop should report the following just after launch + // _NET_WM_STATE(ATOM) = _NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ + // After demaximization the right side is empty, though (maybe not the most correct then?) + Atom state, atomh, atomv; + + state = XInternAtom(m_display, "_NET_WM_STATE", False); + atomh = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + atomv = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + if (state == None ) { + GHOST_PRINT("Atom _NET_WM_STATE requested but not avaliable nor created.\n"); + } else { + XChangeProperty(m_display, m_window, + state, XA_ATOM, 32, + PropModeAppend, (unsigned char *) &atomh, 1); + XChangeProperty(m_display, m_window, + state, XA_ATOM, 32, + PropModeAppend, (unsigned char *) &atomv, 1); + } + } + + // Create some hints for the window manager on how + // we want this window treated. + + XSizeHints * xsizehints = XAllocSizeHints(); + xsizehints->flags = USPosition | USSize; + xsizehints->x = left; + xsizehints->y = top; + xsizehints->width = width; + xsizehints->height = height; + XSetWMNormalHints(m_display, m_window, xsizehints); + XFree(xsizehints); + + XClassHint * xclasshint = XAllocClassHint(); + int len = title.Length() +1 ; + char *wmclass = (char *)malloc(sizeof(char) * len); + strncpy(wmclass, (const char*)title, sizeof(char) * len); + xclasshint->res_name = wmclass; + xclasshint->res_class = wmclass; + XSetClassHint(m_display, m_window, xclasshint); + free(wmclass); + XFree(xclasshint); + + + // Set the window icon + XWMHints *xwmhints = XAllocWMHints(); + XImage *x_image, *mask_image; + Pixmap icon_pixmap, mask_pixmap; + icon_pixmap = XCreatePixmap(display, m_window, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 24); + mask_pixmap = XCreatePixmap(display, m_window, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 1); + GC gc_icon = XCreateGC(display, icon_pixmap, 0, NULL); + GC gc_mask = XCreateGC(display, mask_pixmap, 0, NULL); + + x_image = XCreateImage( display, m_visual->visual, 24, ZPixmap, 0, NULL, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 32, 0 ); + mask_image = XCreateImage( display, m_visual->visual, 1, ZPixmap, 0, NULL, BLENDER_ICON_WIDTH, BLENDER_ICON_HEIGHT, 8, 0); + + x_image->data = (char *)malloc(x_image->bytes_per_line * BLENDER_ICON_HEIGHT); + mask_image->data = (char *)malloc( mask_image->bytes_per_line * BLENDER_ICON_HEIGHT); + + /* copy the BLENDER_ICON_48x48x24 into the XImage */ + unsigned char *col = BLENDER_ICON_48x48x24; + int px, py; + for (px=0; pxicon_pixmap = icon_pixmap; + xwmhints->icon_mask = mask_pixmap; + XFreeGC (display, gc_icon); + XFreeGC (display, gc_mask); + XDestroyImage( x_image ); /* frees x_image->data too */ + XDestroyImage( mask_image ); + + xwmhints->initial_state = NormalState; + xwmhints->flags = IconPixmapHint|IconMaskHint|StateHint; + XSetWMHints(display, m_window, xwmhints ); + XFree(xwmhints); + // done setting the icon + + + setTitle(title); + + initXInputDevices(); + + // now set up the rendering context. + if (installDrawingContext(type) == GHOST_kSuccess) { + m_valid_setup = true; + GHOST_PRINT("Created window\n"); + } + + XMapWindow(m_display, m_window); + GHOST_PRINT("Mapped window\n"); + + XFlush(m_display); +} + +/* + Dummy function to get around IO Handler exiting if device invalid + Basically it will not crash blender now if you have a X device that + is configured but not plugged in. + +*/ +static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent) { + fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", + theEvent->error_code, theEvent->request_code) ; + + /* No exit! - but keep lint happy */ + return 0 ; +} + +void GHOST_WindowX11::initXInputDevices() +{ + static XErrorHandler old_handler = (XErrorHandler) 0 ; + XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + + if(version && (version != (XExtensionVersion*)NoSuchExtension)) { + if(version->present) { + int device_count; + XDeviceInfo* device_info = XListInputDevices(m_display, &device_count); + m_xtablet.StylusDevice = 0; + m_xtablet.EraserDevice = 0; + m_xtablet.CommonData.Active= 0; + + /* Install our error handler to override Xlib's termination behavior */ + old_handler = XSetErrorHandler(ApplicationErrorHandler) ; + + for(int i=0; inum_classes; ++j) { + if(ici->c_class==ValuatorClass) { + XValuatorInfo* xvi = (XValuatorInfo*)ici; + m_xtablet.PressureLevels = xvi->axes[2].max_value; + + /* this is assuming that the tablet has the same tilt resolution in both + * positive and negative directions. It would be rather weird if it didn't.. */ + m_xtablet.XtiltLevels = xvi->axes[3].max_value; + m_xtablet.YtiltLevels = xvi->axes[4].max_value; + break; + } + + ici = (XAnyClassPtr)(((char *)ici) + ici->length); + } + } else { + m_xtablet.StylusID= 0; + } + } + if(!strcasecmp(device_info[i].name, "eraser")) { + m_xtablet.EraserID= device_info[i].id; + m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID); + if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID= 0; + } + } + + /* Restore handler */ + (void) XSetErrorHandler(old_handler) ; + + XFreeDeviceList(device_info); + + + XEventClass xevents[10], ev; + int dcount = 0; + + if(m_xtablet.StylusDevice) { + DeviceMotionNotify(m_xtablet.StylusDevice, m_xtablet.MotionEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityIn(m_xtablet.StylusDevice, m_xtablet.ProxInEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityOut(m_xtablet.StylusDevice, m_xtablet.ProxOutEvent, ev); + if(ev) xevents[dcount++] = ev; + } + if(m_xtablet.EraserDevice) { + DeviceMotionNotify(m_xtablet.EraserDevice, m_xtablet.MotionEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityIn(m_xtablet.EraserDevice, m_xtablet.ProxInEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityOut(m_xtablet.EraserDevice, m_xtablet.ProxOutEvent, ev); + if(ev) xevents[dcount++] = ev; + } + + XSelectExtensionEvent(m_display, m_window, xevents, dcount); + } + XFree(version); + } +} + + + Window +GHOST_WindowX11:: +getXWindow( +){ + return m_window; +} + + bool +GHOST_WindowX11:: +getValid( +) const { + return m_valid_setup; +} + + void +GHOST_WindowX11:: +setTitle( + const STR_String& title +){ + XStoreName(m_display,m_window,title); + XFlush(m_display); +} + + void +GHOST_WindowX11:: +getTitle( + STR_String& title +) const { + char *name = NULL; + + XFetchName(m_display,m_window,&name); + title= name?name:"untitled"; + XFree(name); +} + + void +GHOST_WindowX11:: +getWindowBounds( + GHOST_Rect& bounds +) const { + // Getting the window bounds under X11 is not + // really supported (nor should it be desired). + getClientBounds(bounds); +} + + void +GHOST_WindowX11:: +getClientBounds( + GHOST_Rect& bounds +) const { + Window root_return; + int x_return,y_return; + unsigned int w_return,h_return,border_w_return,depth_return; + GHOST_TInt32 screen_x, screen_y; + + XGetGeometry(m_display,m_window,&root_return,&x_return,&y_return, + &w_return,&h_return,&border_w_return,&depth_return); + + clientToScreen(0, 0, screen_x, screen_y); + + bounds.m_l = screen_x; + bounds.m_r = bounds.m_l + w_return; + bounds.m_t = screen_y; + bounds.m_b = bounds.m_t + h_return; + +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientWidth( + GHOST_TUns32 width +){ + XWindowChanges values; + unsigned int value_mask= CWWidth; + values.width = width; + XConfigureWindow(m_display,m_window,value_mask,&values); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientHeight( + GHOST_TUns32 height +){ + XWindowChanges values; + unsigned int value_mask= CWHeight; + values.height = height; + XConfigureWindow(m_display,m_window,value_mask,&values); + return GHOST_kSuccess; + +} + + GHOST_TSuccess +GHOST_WindowX11:: +setClientSize( + GHOST_TUns32 width, + GHOST_TUns32 height +){ + XWindowChanges values; + unsigned int value_mask= CWWidth | CWHeight; + values.width = width; + values.height = height; + XConfigureWindow(m_display,m_window,value_mask,&values); + return GHOST_kSuccess; + +} + + void +GHOST_WindowX11:: +screenToClient( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY +) const { + // not sure about this one! + + int ax,ay; + Window temp; + + XTranslateCoordinates( + m_display, + RootWindow(m_display, m_visual->screen), + m_window, + inX, + inY, + &ax, + &ay, + &temp + ); + outX = ax; + outY = ay; +} + + void +GHOST_WindowX11:: +clientToScreen( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY +) const { + int ax,ay; + Window temp; + + XTranslateCoordinates( + m_display, + m_window, + RootWindow(m_display, m_visual->screen), + inX, + inY, + &ax, + &ay, + &temp + ); + outX = ax; + outY = ay; +} + + + GHOST_TWindowState +GHOST_WindowX11:: +getState( +) const { + //FIXME + return GHOST_kWindowStateNormal; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setState( + GHOST_TWindowState state +){ + //TODO + + if (state == (int)getState()) { + return GHOST_kSuccess; + } else { + return GHOST_kFailure; + } + +} + +#include +using namespace std; + + GHOST_TSuccess +GHOST_WindowX11:: +setOrder( + GHOST_TWindowOrder order +){ + if (order == GHOST_kWindowOrderTop) { + XWindowAttributes attr; + Atom atom; + + /* We use both XRaiseWindow and _NET_ACTIVE_WINDOW, since some + window managers ignore the former (e.g. kwin from kde) and others + don't implement the latter (e.g. fluxbox pre 0.9.9) */ + + XRaiseWindow(m_display, m_window); + + atom = XInternAtom(m_display, "_NET_ACTIVE_WINDOW", True); + + if (atom != None) { + Window root; + XEvent xev; + long eventmask; + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = m_window; + xev.xclient.message_type = atom; + + xev.xclient.format = 32; + xev.xclient.data.l[0] = 0; + xev.xclient.data.l[1] = 0; + xev.xclient.data.l[2] = 0; + xev.xclient.data.l[3] = 0; + xev.xclient.data.l[4] = 0; + + root = RootWindow(m_display, m_visual->screen), + eventmask = SubstructureRedirectMask | SubstructureNotifyMask; + + XSendEvent(m_display, root, False, eventmask, &xev); + } + + XGetWindowAttributes(m_display, m_window, &attr); + + /* iconized windows give bad match error */ + if (attr.map_state == IsViewable) + XSetInputFocus(m_display, m_window, RevertToPointerRoot, + CurrentTime); + XFlush(m_display); + } else if (order == GHOST_kWindowOrderBottom) { + XLowerWindow(m_display,m_window); + XFlush(m_display); + } else { + return GHOST_kFailure; + } + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +swapBuffers( +){ + if (getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL) { + glXSwapBuffers(m_display,m_window); + return GHOST_kSuccess; + } else { + return GHOST_kFailure; + } +} + + GHOST_TSuccess +GHOST_WindowX11:: +activateDrawingContext( +){ + if (m_context !=NULL) { + glXMakeCurrent(m_display, m_window,m_context); + return GHOST_kSuccess; + } + return GHOST_kFailure; +} + + GHOST_TSuccess +GHOST_WindowX11:: +invalidate( +){ + + // So the idea of this function is to generate an expose event + // for the window. + // Unfortunately X does not handle expose events for you and + // it is the client's job to refresh the dirty part of the window. + // We need to queue up invalidate calls and generate GHOST events + // for them in the system. + + // We implement this by setting a boolean in this class to concatenate + // all such calls into a single event for this window. + + // At the same time we queue the dirty windows in the system class + // and generate events for them at the next processEvents call. + + if (m_invalid_window == false) { + m_system->addDirtyWindow(this); + m_invalid_window = true; + } + + return GHOST_kSuccess; +} + +/** + * called by the X11 system implementation when expose events + * for the window have been pushed onto the GHOST queue + */ + + void +GHOST_WindowX11:: +validate( +){ + m_invalid_window = false; +} + + +/** + * Destructor. + * Closes the window and disposes resources allocated. + */ + +GHOST_WindowX11:: +~GHOST_WindowX11( +){ + std::map::iterator it = m_standard_cursors.begin(); + for (; it != m_standard_cursors.end(); it++) { + XFreeCursor(m_display, it->second); + } + + if (m_empty_cursor) { + XFreeCursor(m_display, m_empty_cursor); + } + if (m_custom_cursor) { + XFreeCursor(m_display, m_custom_cursor); + } + + if (m_context) { + if (m_context == s_firstContext) { + s_firstContext = NULL; + } + glXDestroyContext(m_display, m_context); + } + XDestroyWindow(m_display, m_window); + XFree(m_visual); +} + + + + +/** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + GHOST_TSuccess +GHOST_WindowX11:: +installDrawingContext( + GHOST_TDrawingContextType type +){ + // only support openGL for now. + GHOST_TSuccess success; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + m_context = glXCreateContext(m_display, m_visual, s_firstContext, True); + if (m_context !=NULL) { + if (!s_firstContext) { + s_firstContext = m_context; + } + glXMakeCurrent(m_display, m_window,m_context); + success = GHOST_kSuccess; + } else { + success = GHOST_kFailure; + } + + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + success = GHOST_kFailure; + } + return success; +} + + + +/** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + GHOST_TSuccess +GHOST_WindowX11:: +removeDrawingContext( +){ + GHOST_TSuccess success; + + if (m_context != NULL) { + glXDestroyContext(m_display, m_context); + success = GHOST_kSuccess; + } else { + success = GHOST_kFailure; + } + return success; +} + + + Cursor +GHOST_WindowX11:: +getStandardCursor( + GHOST_TStandardCursor g_cursor +){ + unsigned int xcursor_id; + +#define GtoX(gcurs, xcurs) case gcurs: xcursor_id = xcurs + switch (g_cursor) { + GtoX(GHOST_kStandardCursorRightArrow, XC_arrow); break; + GtoX(GHOST_kStandardCursorLeftArrow, XC_top_left_arrow); break; + GtoX(GHOST_kStandardCursorInfo, XC_hand1); break; + GtoX(GHOST_kStandardCursorDestroy, XC_pirate); break; + GtoX(GHOST_kStandardCursorHelp, XC_question_arrow); break; + GtoX(GHOST_kStandardCursorCycle, XC_exchange); break; + GtoX(GHOST_kStandardCursorSpray, XC_spraycan); break; + GtoX(GHOST_kStandardCursorWait, XC_watch); break; + GtoX(GHOST_kStandardCursorText, XC_xterm); break; + GtoX(GHOST_kStandardCursorCrosshair, XC_crosshair); break; + GtoX(GHOST_kStandardCursorUpDown, XC_sb_v_double_arrow); break; + GtoX(GHOST_kStandardCursorLeftRight, XC_sb_h_double_arrow); break; + GtoX(GHOST_kStandardCursorTopSide, XC_top_side); break; + GtoX(GHOST_kStandardCursorBottomSide, XC_bottom_side); break; + GtoX(GHOST_kStandardCursorLeftSide, XC_left_side); break; + GtoX(GHOST_kStandardCursorRightSide, XC_right_side); break; + GtoX(GHOST_kStandardCursorTopLeftCorner, XC_top_left_corner); break; + GtoX(GHOST_kStandardCursorTopRightCorner, XC_top_right_corner); break; + GtoX(GHOST_kStandardCursorBottomRightCorner, XC_bottom_right_corner); break; + GtoX(GHOST_kStandardCursorBottomLeftCorner, XC_bottom_left_corner); break; + GtoX(GHOST_kStandardCursorPencil, XC_pencil); break; + default: + xcursor_id = 0; + } +#undef GtoX + + if (xcursor_id) { + Cursor xcursor = m_standard_cursors[xcursor_id]; + + if (!xcursor) { + xcursor = XCreateFontCursor(m_display, xcursor_id); + + m_standard_cursors[xcursor_id] = xcursor; + } + + return xcursor; + } else { + return None; + } +} + + Cursor +GHOST_WindowX11:: +getEmptyCursor( +) { + if (!m_empty_cursor) { + Pixmap blank; + XColor dummy; + char data[1] = {0}; + + /* make a blank cursor */ + blank = XCreateBitmapFromData ( + m_display, + RootWindow(m_display,DefaultScreen(m_display)), + data, 1, 1 + ); + + m_empty_cursor = XCreatePixmapCursor(m_display, blank, blank, &dummy, &dummy, 0, 0); + XFreePixmap(m_display, blank); + } + + return m_empty_cursor; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCursorVisibility( + bool visible +){ + Cursor xcursor; + + if (visible) { + xcursor = getStandardCursor( getCursorShape() ); + } else { + xcursor = getEmptyCursor(); + } + + XDefineCursor(m_display, m_window, xcursor); + XFlush(m_display); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCursorShape( + GHOST_TStandardCursor shape +){ + Cursor xcursor = getStandardCursor( shape ); + + XDefineCursor(m_display, m_window, xcursor); + XFlush(m_display); + + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCustomCursorShape( + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY +){ + +setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, + 16, 16, hotX, hotY, 0, 1); + return GHOST_kSuccess; +} + + GHOST_TSuccess +GHOST_WindowX11:: +setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color +){ + Pixmap bitmap_pix, mask_pix; + XColor fg, bg; + + if(XAllocNamedColor(m_display, DefaultColormap(m_display, DefaultScreen(m_display)), + "White", &fg, &fg) == 0) return GHOST_kFailure; + if(XAllocNamedColor(m_display, DefaultColormap(m_display, DefaultScreen(m_display)), + "Black", &bg, &bg) == 0) return GHOST_kFailure; + + if (m_custom_cursor) { + XFreeCursor(m_display, m_custom_cursor); + } + + bitmap_pix = XCreateBitmapFromData(m_display, m_window, (char*) bitmap, sizex, sizey); + mask_pix = XCreateBitmapFromData(m_display, m_window, (char*) mask, sizex, sizey); + + m_custom_cursor = XCreatePixmapCursor(m_display, bitmap_pix, mask_pix, &fg, &bg, hotX, hotY); + XDefineCursor(m_display, m_window, m_custom_cursor); + XFlush(m_display); + + XFreePixmap(m_display, bitmap_pix); + XFreePixmap(m_display, mask_pix); + + return GHOST_kSuccess; +} + +/* + +void glutCustomCursor(char *data1, char *data2, int size) +{ + Pixmap source, mask; + Cursor cursor; + XColor fg, bg; + + if(XAllocNamedColor(__glutDisplay, DefaultColormap(__glutDisplay, __glutScreen), + "White", &fg, &fg) == 0) return; + if(XAllocNamedColor(__glutDisplay, DefaultColormap(__glutDisplay, __glutScreen), + "Red", &bg, &bg) == 0) return; + + + source= XCreateBitmapFromData(__glutDisplay, xdraw, data2, size, size); + mask= XCreateBitmapFromData(__glutDisplay, xdraw, data1, size, size); + + cursor= XCreatePixmapCursor(__glutDisplay, source, mask, &fg, &bg, 7, 7); + + XFreePixmap(__glutDisplay, source); + XFreePixmap(__glutDisplay, mask); + + XDefineCursor(__glutDisplay, xdraw, cursor); +} + +*/ diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h new file mode 100644 index 00000000000..0de4f65acd1 --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -0,0 +1,334 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file GHOST_WindowX11.h + * Declaration of GHOST_WindowX11 class. + */ + +#ifndef _GHOST_WINDOWX11_H_ +#define _GHOST_WINDOWX11_H_ + +#include "GHOST_Window.h" +#include +#include +// For tablets +#include + +#include + +class STR_String; +class GHOST_SystemX11; + +/** + * X11 implementation of GHOST_IWindow. + * Dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + * @author Laurence Bourn + * @date October 26, 2001 + */ + +class GHOST_WindowX11 : public GHOST_Window +{ +public: + /** + * Constructor. + * Creates a new window and opens it. + * To check if the window was created properly, use the getValid() method. + * @param title The text shown in the title bar of the window. + * @param left The coordinate of the left edge of the window. + * @param top The coordinate of the top edge of the window. + * @param width The width the window. + * @param height The height the window. + * @param state The state the window is initially opened with. + * @param type The type of drawing context installed in this window. + * @param stereoVisual Stereo visual for quad buffered stereo. + */ + GHOST_WindowX11( + GHOST_SystemX11 *system, + Display * display, + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone, + const bool stereoVisual = false + ); + + bool + getValid( + ) const; + + void + setTitle(const STR_String& title); + + void + getTitle( + STR_String& title + ) const; + + void + getWindowBounds( + GHOST_Rect& bounds + ) const; + + void + getClientBounds( + GHOST_Rect& bounds + ) const; + + GHOST_TSuccess + setClientWidth( + GHOST_TUns32 width + ); + + GHOST_TSuccess + setClientHeight( + GHOST_TUns32 height + ); + + GHOST_TSuccess + setClientSize( + GHOST_TUns32 width, + GHOST_TUns32 height + ); + + void + screenToClient( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY + ) const; + + void + clientToScreen( + GHOST_TInt32 inX, + GHOST_TInt32 inY, + GHOST_TInt32& outX, + GHOST_TInt32& outY + ) const; + + GHOST_TWindowState + getState( + ) const ; + + GHOST_TSuccess + setState( + GHOST_TWindowState state + ); + + GHOST_TSuccess + setOrder( + GHOST_TWindowOrder order + ); + + GHOST_TSuccess + swapBuffers( + ); + + GHOST_TSuccess + activateDrawingContext( + ); + GHOST_TSuccess + invalidate( + ); + + /** + * Destructor. + * Closes the window and disposes resources allocated. + */ + ~GHOST_WindowX11(); + + /** + * @section + * X11 system specific calls. + */ + + /** + * The reverse of invalidate! Tells this window + * that all events for it have been pushed into + * the GHOST event queue. + */ + + void + validate( + ); + + /** + * Return a handle to the x11 window type. + */ + Window + getXWindow( + ); + + class XTablet + { + public: + GHOST_TabletData CommonData; + + XDevice* StylusDevice; + XDevice* EraserDevice; + + XID StylusID, EraserID; + + int MotionEvent; + int ProxInEvent; + int ProxOutEvent; + + int PressureLevels; + int XtiltLevels, YtiltLevels; + }; + + XTablet& GetXTablet() + { return m_xtablet; } + + const GHOST_TabletData* GetTabletData() + { return &m_xtablet.CommonData; } +protected: + /** + * Tries to install a rendering context in this window. + * @param type The type of rendering context installed. + * @return Indication as to whether installation has succeeded. + */ + GHOST_TSuccess + installDrawingContext( + GHOST_TDrawingContextType type + ); + + /** + * Removes the current drawing context. + * @return Indication as to whether removal has succeeded. + */ + GHOST_TSuccess + removeDrawingContext( + ); + + /** + * Sets the cursor visibility on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCursorVisibility( + bool visible + ); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCursorShape( + GHOST_TStandardCursor shape + ); + + /** + * Sets the cursor shape on the window using + * native window system calls. + */ + GHOST_TSuccess + setWindowCustomCursorShape( + GHOST_TUns8 bitmap[16][2], + GHOST_TUns8 mask[16][2], + int hotX, + int hotY + ); + + /** + * Sets the cursor shape on the window using + * native window system calls (Arbitrary size/color). + */ + GHOST_TSuccess + setWindowCustomCursorShape( + GHOST_TUns8 *bitmap, + GHOST_TUns8 *mask, + int sizex, + int sizey, + int hotX, + int hotY, + int fg_color, + int bg_color + ); + +private : + + /// Force use of public constructor. + + GHOST_WindowX11( + ); + + GHOST_WindowX11( + const GHOST_WindowX11 & + ); + + Cursor + getStandardCursor( + GHOST_TStandardCursor g_cursor + ); + + Cursor + getEmptyCursor( + ); + + void initXInputDevices(); + + GLXContext m_context; + Window m_window; + Display *m_display; + XVisualInfo *m_visual; + + /** The first created OpenGL context (for sharing display lists) */ + static GLXContext s_firstContext; + + /// A pointer to the typed system class. + + GHOST_SystemX11 * m_system; + + bool m_valid_setup; + + /** Used to concatenate calls to invalidate() on this window. */ + bool m_invalid_window; + + /** XCursor structure of an empty (blank) cursor */ + Cursor m_empty_cursor; + + /** XCursor structure of the custom cursor */ + Cursor m_custom_cursor; + + /** Cache of XC_* ID's to XCursor structures */ + std::map m_standard_cursors; + + /* Tablet devices */ + XTablet m_xtablet; +}; + + +#endif // _GHOST_WINDOWX11_H_ diff --git a/intern/ghost/intern/Makefile b/intern/ghost/intern/Makefile new file mode 100644 index 00000000000..32498222ac6 --- /dev/null +++ b/intern/ghost/intern/Makefile @@ -0,0 +1,66 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# ghost intern Makefile +# + +LIBNAME = ghost +DIR = $(OCGDIR)/intern/$(LIBNAME) + +CCSRCS = GHOST_Buttons.cpp GHOST_System.cpp GHOST_Window.cpp +CCSRCS += GHOST_EventManager.cpp GHOST_EventPrinter.cpp GHOST_WindowManager.cpp +CCSRCS += GHOST_ISystem.cpp GHOST_ModifierKeys.cpp GHOST_TimerManager.cpp +CCSRCS += GHOST_Rect.cpp GHOST_DisplayManager.cpp GHOST_C-api.cpp +CCSRCS += GHOST_CallbackEventConsumer.cpp + +include nan_definitions.mk + +ifeq ($(OS),$(findstring $(OS), "darwin")) + CCSRCS += $(wildcard *Carbon.cpp) +endif + +ifeq ($(OS),$(findstring $(OS), "windows")) + CPPFLAGS += -I$(NAN_WINTAB)/include + CCSRCS += $(wildcard *Win32.cpp) +endif + +ifeq ($(OS),$(findstring $(OS), "freebsd irix linux openbsd solaris")) + CCSRCS += $(wildcard *X11.cpp) +endif + +include nan_compile.mk + +#CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I.. +CPPFLAGS += -I$(OPENGL_HEADERS) + diff --git a/intern/ghost/make/msvc/ghost.dsp b/intern/ghost/make/msvc/ghost.dsp new file mode 100644 index 00000000000..fd287488b56 --- /dev/null +++ b/intern/ghost/make/msvc/ghost.dsp @@ -0,0 +1,292 @@ +# Microsoft Developer Studio Project File - Name="ghost" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=ghost - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ghost.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ghost.mak" CFG="ghost - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ghost - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "ghost - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ghost - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\ghost" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\ghost" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../.." /I "../../../../../lib/windows/string/include" /I "..\..\..\..\intern\string" /I "../../../../../lib/windows/wintab/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\ghost\libghost.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copying GHOST files library (release target) to lib tree. +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\ghost\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\ghost\*.lib ..\..\..\..\..\lib\windows\ghost\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "ghost - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\ghost\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\ghost\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../.." /I "../../../../../lib/windows/string/include" /I "..\..\..\..\intern\string" /I "../../../../../lib/windows/wintab/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\ghost\debug\libghost.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copying GHOST files library (debug target) to lib tree. +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\ghost\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\ghost\debug\*.lib ..\..\..\..\..\lib\windows\ghost\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "ghost - Win32 Release" +# Name "ghost - Win32 Debug" +# Begin Group "Header Files" + +# PROP Default_Filter "" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\GHOST_Buttons.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_CallbackEventConsumer.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Debug.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_DisplayManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_DisplayManagerWin32.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Event.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventButton.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventCursor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventKey.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventPrinter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventWheel.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventWindow.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_ModifierKeys.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_System.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_SystemWin32.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_TimerManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_TimerTask.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Window.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_WindowManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_WindowWin32.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE="..\..\GHOST_C-api.h" +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_IEvent.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_IEventConsumer.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_ISystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_ITimerTask.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_IWindow.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_Rect.h +# End Source File +# Begin Source File + +SOURCE=..\..\GHOST_Types.h +# End Source File +# End Group +# End Group +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\GHOST_Buttons.cpp +# End Source File +# Begin Source File + +SOURCE="..\..\intern\GHOST_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_CallbackEventConsumer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_DisplayManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_DisplayManagerWin32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_EventPrinter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_ISystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_ModifierKeys.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Rect.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_SystemWin32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_TimerManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_WindowManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\GHOST_WindowWin32.cpp +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/ghost/make/msvc/ghost.dsw b/intern/ghost/make/msvc/ghost.dsw new file mode 100644 index 00000000000..807a6ec3157 --- /dev/null +++ b/intern/ghost/make/msvc/ghost.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ghost"=".\ghost.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/ghost/make/msvc_7_0/ghost.sln b/intern/ghost/make/msvc_7_0/ghost.sln new file mode 100644 index 00000000000..a2073664ca5 --- /dev/null +++ b/intern/ghost/make/msvc_7_0/ghost.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghost", "ghost.vcproj", "{37364341-0C53-433A-B4CC-CDDD176CABC5}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {37364341-0C53-433A-B4CC-CDDD176CABC5}.Debug.ActiveCfg = Debug|Win32 + {37364341-0C53-433A-B4CC-CDDD176CABC5}.Debug.Build.0 = Debug|Win32 + {37364341-0C53-433A-B4CC-CDDD176CABC5}.Release.ActiveCfg = Release|Win32 + {37364341-0C53-433A-B4CC-CDDD176CABC5}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/ghost/make/msvc_7_0/ghost.vcproj b/intern/ghost/make/msvc_7_0/ghost.vcproj new file mode 100644 index 00000000000..9d0aef451e7 --- /dev/null +++ b/intern/ghost/make/msvc_7_0/ghost.vcproj @@ -0,0 +1,401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/ghost/test/Makefile b/intern/ghost/test/Makefile new file mode 100644 index 00000000000..ded21c32cc6 --- /dev/null +++ b/intern/ghost/test/Makefile @@ -0,0 +1,86 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# GHOST test applications makefile. +# This bounces to test application directories. +# + +LIBNAME = ghost +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = gears multitest + +include nan_subdirs.mk + +include nan_compile.mk +include nan_link.mk + +OCGGHOST = $(OCGDIR)/intern/$(LIBNAME) +GEARDIR = $(OCGGHOST)/test/$(DEBUG_DIR)gears.app + +LIBS = $(OCGGHOST)/$(DEBUG_DIR)libghost.a +SLIBS += $(LCGDIR)/string/lib/libstring.a + +all debug:: $(LIBS) + @echo "****> linking $@ in $(SOURCEDIR)" +ifeq ($(OS),darwin) + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)gears $(DIR)/$(DEBUG_DIR)GHOST_Test.o $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS) + @# set up directory structure for the OSX application bundle + @[ -d $(OCGGHOST)/test/ ] || mkdir $(OCGGHOST)/test/ + @[ -d $(OCGGHOST)/test/debug ] || mkdir $(OCGGHOST)/test/debug + @[ -d $(GEARDIR) ] || mkdir $(GEARDIR) + @[ -d $(GEARDIR)/Contents ] || mkdir $(GEARDIR)/Contents + @[ -d $(GEARDIR)/Contents/MacOS ] || mkdir $(GEARDIR)/Contents/MacOS + @[ -d $(GEARDIR)/Contents/Resources ] || mkdir $(GEARDIR)/Contents/Resources + @[ -d $(GEARDIR)/Contents/Resources/English.lproj ] || mkdir $(GEARDIR)/Contents/Resources/English.lproj + @[ -d $(GEARDIR)/Contents/Resources/English.lproj/MainMenu.nib ] || mkdir $(GEARDIR)/Contents/Resources/English.lproj/MainMenu.nib + @# copy the files into the bundle directory tree + cp -f $(DIR)/$(DEBUG_DIR)gears $(GEARDIR)/Contents/MacOS + cp -f gears/resources/osx/PkgInfo $(GEARDIR)/Contents/ + cp -f gears/resources/osx/Info.plist $(GEARDIR)/Contents/ + cp -f gears/resources/osx/English.lproj/InfoPlist.strings $(GEARDIR)/Contents/Resources/English.lproj + cp -f gears/resources/osx/English.lproj/MainMenu.nib/classes.nib $(GEARDIR)/Contents/Resources/English.lproj + cp -f gears/resources/osx/English.lproj/MainMenu.nib/info.nib $(GEARDIR)/Contents/Resources/English.lproj + cp -f gears/resources/osx/English.lproj/MainMenu.nib/objects.nib $(GEARDIR)/Contents/Resources/English.lproj +else + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)gears_cpp $(DIR)/$(DEBUG_DIR)GHOST_Test.o $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS) + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)gears_c $(DIR)/$(DEBUG_DIR)GHOST_C-Test.o $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS) +endif + +clean:: + @# mac stuff. well ok, only the binary + @rm -f $(DIR)/gears $(DIR)/debug/gears + @# others + @rm -f $(DIR)/gears_c $(DIR)/debug/gears_c + @rm -f $(DIR)/gears_cpp $(DIR)/debug/gears_cpp + +test:: all + $(DIR)/gears_cpp + $(DIR)/gears_c diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c new file mode 100644 index 00000000000..9fd4e155b3b --- /dev/null +++ b/intern/ghost/test/gears/GHOST_C-Test.c @@ -0,0 +1,564 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * Simple test file for the GHOST library. + * The OpenGL gear code is taken from the Qt sample code which, + * in turn, is probably taken from somewhere as well. + * @author Maarten Gribnau + * @date May 31, 2001 + */ + +#include +#include +#include +#include + +#define FALSE 0 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GHOST_C-api.h" + +#if defined(WIN32) || defined(__APPLE__) + #ifdef WIN32 + #include + #include + #else /* WIN32 */ + /* __APPLE__ is defined */ + #include + #endif /* WIN32 */ +#else /* defined(WIN32) || defined(__APPLE__) */ + #include +#endif /* defined(WIN32) || defined(__APPLE__) */ + + +static void gearsTimerProc(GHOST_TimerTaskHandle task, GHOST_TUns64 time); +int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData); + +static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0; +static GLfloat fAngle = 0.0; +static int sExitRequested = 0; +static GHOST_SystemHandle shSystem = NULL; +static GHOST_WindowHandle sMainWindow = NULL; +static GHOST_WindowHandle sSecondaryWindow = NULL; +static GHOST_TStandardCursor sCursor = GHOST_kStandardCursorFirstCursor; +static GHOST_WindowHandle sFullScreenWindow = NULL; +static GHOST_TimerTaskHandle sTestTimer; +static GHOST_TimerTaskHandle sGearsTimer; + +static void testTimerProc(GHOST_TimerTaskHandle task, GHOST_TUns64 time) +{ + printf("timer1, time=%d\n", (int)time); +} + + +static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + const double pi = 3.14159264; + + r0 = inner_radius; + r1 = (float)(outer_radius - tooth_depth/2.0); + r2 = (float)(outer_radius + tooth_depth/2.0); + + da = (float)(2.0*pi / teeth / 4.0); + + glShadeModel(GL_FLAT); + glNormal3f(0.0, 0.0, 1.0); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i=0;i<=teeth;i++) { + angle = (float)(i * 2.0*pi / teeth); + glVertex3f((float)(r0*cos(angle)), (float)(r0*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r1*cos(angle)), (float)(r1*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r0*cos(angle)), (float)(r0*sin(angle)), (float)(width*0.5)); + glVertex3f((float)(r1*cos(angle+3*da)), (float)(r1*sin(angle+3*da)), (float)(width*0.5)); + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = (float)(2.0*pi / teeth / 4.0); + for (i=0;iz > 0) + { + view_rotz += 5.f; + } + else + { + view_rotz -= 5.f; + } + } + break; + + case GHOST_kEventKeyUp: + break; + + case GHOST_kEventKeyDown: + { + keyData = (GHOST_TEventKeyData*)GHOST_GetEventData(hEvent); + switch (keyData->key) + { + case GHOST_kKeyC: + { + cursor = sCursor; + cursor++; + if (cursor >= GHOST_kStandardCursorNumCursors) + { + cursor = GHOST_kStandardCursorFirstCursor; + } + sCursor = (GHOST_TStandardCursor)cursor; + GHOST_SetCursorShape(window, sCursor); + } + break; + case GHOST_kKeyF: + if (!GHOST_GetFullScreen(shSystem)) + { + /* Begin fullscreen mode */ + setting.bpp = 24; + setting.frequency = 85; + setting.xPixels = 640; + setting.yPixels = 480; + + /* + setting.bpp = 16; + setting.frequency = 75; + setting.xPixels = 640; + setting.yPixels = 480; + */ + + sFullScreenWindow = GHOST_BeginFullScreen(shSystem, &setting, + + FALSE /* stereo flag */); + } + else + { + GHOST_EndFullScreen(shSystem); + sFullScreenWindow = 0; + } + break; + case GHOST_kKeyH: + { + visibility = GHOST_GetCursorVisibility(window); + GHOST_SetCursorVisibility(window, !visibility); + } + break; + case GHOST_kKeyQ: + if (GHOST_GetFullScreen(shSystem)) + { + GHOST_EndFullScreen(shSystem); + sFullScreenWindow = 0; + } + sExitRequested = 1; + case GHOST_kKeyT: + if (!sTestTimer) + { + sTestTimer = GHOST_InstallTimer(shSystem, 0, 1000, testTimerProc, NULL); + } + else + { + GHOST_RemoveTimer(shSystem, sTestTimer); + sTestTimer = 0; + } + break; + case GHOST_kKeyW: + { + if (sMainWindow) + { + char *title = GHOST_GetTitle(sMainWindow); + char *ntitle = malloc(strlen(title)+2); + + sprintf(ntitle, "%s-", title); + GHOST_SetTitle(sMainWindow, ntitle); + + free(ntitle); + free(title); + } + } + break; + default: + break; + } + } + break; + + case GHOST_kEventWindowClose: + { + GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent); + if (window2 == sMainWindow) + { + sExitRequested = 1; + } + else + { + if (sGearsTimer) + { + GHOST_RemoveTimer(shSystem, sGearsTimer); + sGearsTimer = 0; + } + GHOST_DisposeWindow(shSystem, window2); + } + } + break; + + case GHOST_kEventWindowActivate: + handled = 0; + break; + case GHOST_kEventWindowDeactivate: + handled = 0; + break; + case GHOST_kEventWindowUpdate: + { + GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent); + if (!GHOST_ValidWindow(shSystem, window2)) + break; + setViewPortGL(window2); + drawGL(); + GHOST_SwapWindowBuffers(window2); + } + break; + + default: + handled = 0; + break; + } + return handled; +} + + +int main(int argc, char** argv) +{ + char* title1 = "gears - main window"; + char* title2 = "gears - secondary window"; + GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(processEvent, NULL); + + /* Create the system */ + shSystem = GHOST_CreateSystem(); + GHOST_AddEventConsumer(shSystem, consumer); + + if (shSystem) + { + /* Create the main window */ + sMainWindow = GHOST_CreateWindow(shSystem, + title1, + 10, + 64, + 320, + 200, + GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, + FALSE); + if (!sMainWindow) + { + printf("could not create main window\n"); + exit(-1); + } + + /* Create a secondary window */ + sSecondaryWindow = GHOST_CreateWindow(shSystem, + title2, + 340, + 64, + 320, + 200, + GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, + FALSE); + if (!sSecondaryWindow) + { + printf("could not create secondary window\n"); + exit(-1); + } + + /* Install a timer to have the gears running */ + sGearsTimer = GHOST_InstallTimer(shSystem, + 0, + 10, + gearsTimerProc, + sMainWindow); + + /* Enter main loop */ + while (!sExitRequested) + { + if (!GHOST_ProcessEvents(shSystem, 0)) + { +#ifdef WIN32 + /* If there were no events, be nice to other applications */ + Sleep(10); +#endif + } + GHOST_DispatchEvents(shSystem); + } + } + + /* Dispose windows */ + if (GHOST_ValidWindow(shSystem, sMainWindow)) + { + GHOST_DisposeWindow(shSystem, sMainWindow); + } + if (GHOST_ValidWindow(shSystem, sSecondaryWindow)) + { + GHOST_DisposeWindow(shSystem, sSecondaryWindow); + } + + /* Dispose the system */ + GHOST_DisposeSystem(shSystem); + GHOST_DisposeEventConsumer(consumer); + + return 0; +} + + +static void gearsTimerProc(GHOST_TimerTaskHandle hTask, GHOST_TUns64 time) +{ + GHOST_WindowHandle hWindow = NULL; + fAngle += 2.0; + view_roty += 1.0; + hWindow = (GHOST_WindowHandle)GHOST_GetTimerTaskUserData(hTask); + if (GHOST_GetFullScreen(shSystem)) + { + /* Running full screen */ + GHOST_InvalidateWindow(sFullScreenWindow); + } + else + { + if (GHOST_ValidWindow(shSystem, hWindow)) + { + GHOST_InvalidateWindow(hWindow); + } + } +} diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp new file mode 100644 index 00000000000..3abdd3977eb --- /dev/null +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -0,0 +1,761 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple test file for the GHOST library. + * The OpenGL gear code is taken from the Qt sample code which, + * in turn, is probably taken from somewhere as well. + * @author Maarten Gribnau + * @date May 31, 2001 + * Stereo code by Raymond de Vries, januari 2002 + */ + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(WIN32) || defined(__APPLE__) + #ifdef WIN32 + #include + #include + + #include + #else // WIN32 + // __APPLE__ is defined + #include + #endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) + #include +#endif // defined(WIN32) || defined(__APPLE__) + +#include "STR_String.h" +#include "GHOST_Rect.h" + +#include "GHOST_ISystem.h" +#include "GHOST_IEvent.h" +#include "GHOST_IEventConsumer.h" + + +#define LEFT_EYE 0 +#define RIGHT_EYE 1 + +static bool nVidiaWindows; // very dirty but hey, it's for testing only + +static void gearsTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time); + +static class Application* fApp; +static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0; +static GLfloat fAngle = 0.0; +static GHOST_ISystem* fSystem = 0; + + +void StereoProjection(float left, float right, float bottom, float top, float nearplane, float farplane, + float zero_plane, float dist, + float eye); + + +static void testTimerProc(GHOST_ITimerTask* /*task*/, GHOST_TUns64 time) +{ + std::cout << "timer1, time=" << (int)time << "\n"; +} + + +static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth/2.0; + r2 = outer_radius + tooth_depth/2.0; + + const double pi = 3.14159264; + da = 2.0*pi / teeth / 4.0; + + glShadeModel(GL_FLAT); + glNormal3f(0.0, 0.0, 1.0); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i=0;i<=teeth;i++) { + angle = i * 2.0*pi / teeth; + glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5); + glVertex3f(r1*cos(angle), r1*sin(angle), width*0.5); + glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5); + glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5); + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.0*pi / teeth / 4.0; + for (i=0;iactivateDrawingContext(); + GHOST_Rect bnds; + int noOfScanlines = 0, lowerScanline = 0; + int verticalBlankingInterval = 32; // hard coded for testing purposes, display device dependant + float left, right, bottom, top; + float nearplane, farplane, zeroPlane, distance; + float eyeSeparation = 0.62f; + window->getClientBounds(bnds); + + // viewport + if(stereo) + { + if(nVidiaWindows) + { + // handled by nVidia driver so act as normal (explicitly put here since + // it -is- stereo) + glViewport(0, 0, bnds.getWidth(), bnds.getHeight()); + } + else + { // generic cross platform above-below stereo + noOfScanlines = (bnds.getHeight() - verticalBlankingInterval) / 2; + switch(eye) + { + case LEFT_EYE: + // upper half of window + lowerScanline = bnds.getHeight() - noOfScanlines; + break; + case RIGHT_EYE: + // lower half of window + lowerScanline = 0; + break; + } + } + } + else + { + noOfScanlines = bnds.getHeight(); + lowerScanline = 0; + } + + glViewport(0, lowerScanline, bnds.getWidth(), noOfScanlines); + + // projection + left = -6.0; + right = 6.0; + bottom = -4.8f; + top = 4.8f; + nearplane = 5.0; + farplane = 60.0; + + if(stereo) + { + zeroPlane = 0.0; + distance = 14.5; + switch(eye) + { + case LEFT_EYE: + StereoProjection(left, right, bottom, top, nearplane, farplane, zeroPlane, distance, -eyeSeparation / 2.0); + break; + case RIGHT_EYE: + StereoProjection(left, right, bottom, top, nearplane, farplane, zeroPlane, distance, eyeSeparation / 2.0); + break; + } + } + else + { +// left = -w; +// right = w; +// bottom = -h; +// top = h; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(left, right, bottom, top, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -40.0); + + } + + glClearColor(.2f,0.0f,0.0f,0.0f); +} + + +void StereoProjection(float left, float right, float bottom, float top, float nearplane, float farplane, + float zero_plane, float dist, + float eye) +/* Perform the perspective projection for one eye's subfield. +The projection is in the direction of the negative z axis. + +-6.0, 6.0, -4.8, 4.8, +left, right, bottom, top = the coordinate range, in the plane of zero +parallax setting, which will be displayed on the screen. The +ratio between (right-left) and (top-bottom) should equal the aspect +ratio of the display. + +6.0, -6.0, +near, far = the z-coordinate values of the clipping planes. + +0.0, +zero_plane = the z-coordinate of the plane of zero parallax setting. + +14.5, +dist = the distance from the center of projection to the plane +of zero parallax. + +-0.31 +eye = half the eye separation; positive for the right eye subfield, +negative for the left eye subfield. +*/ +{ + float xmid, ymid, clip_near, clip_far, topw, bottomw, leftw, rightw, + dx, dy, n_over_d; + + dx = right - left; + dy = top - bottom; + + xmid = (right + left) / 2.0; + ymid = (top + bottom) / 2.0; + + clip_near = dist + zero_plane - nearplane; + clip_far = dist + zero_plane - farplane; + + n_over_d = clip_near / dist; + + topw = n_over_d * dy / 2.0; + bottomw = -topw; + rightw = n_over_d * (dx / 2.0 - eye); + leftw = n_over_d *(-dx / 2.0 - eye); + + /* Need to be in projection mode for this. */ + glLoadIdentity(); + glFrustum(leftw, rightw, bottomw, topw, clip_near, clip_far); + + glTranslatef(-xmid - eye, -ymid, -zero_plane - dist); + return; +} /* stereoproj */ + + +class Application : public GHOST_IEventConsumer { +public: + Application(GHOST_ISystem* system); + ~Application(void); + virtual bool processEvent(GHOST_IEvent* event); + + GHOST_ISystem* m_system; + GHOST_IWindow* m_mainWindow; + GHOST_IWindow* m_secondaryWindow; + GHOST_IWindow* m_fullScreenWindow; + GHOST_ITimerTask* m_gearsTimer, *m_testTimer; + GHOST_TStandardCursor m_cursor; + bool m_exitRequested; + + bool stereo; +}; + + +Application::Application(GHOST_ISystem* system) + : m_system(system), m_mainWindow(0), m_secondaryWindow(0), m_fullScreenWindow(0), + m_gearsTimer(0), m_testTimer(0), m_cursor(GHOST_kStandardCursorFirstCursor), + m_exitRequested(false), stereo(false) +{ + fApp = this; + + // Create the main window + STR_String title1 ("gears - main window"); + m_mainWindow = system->createWindow(title1, 10, 64, 320, 200, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, true /* stereo flag */); + + if (!m_mainWindow) { + std::cout << "could not create main window\n"; + exit(-1); + } + + // Create a secondary window + STR_String title2 ("gears - secondary window"); + m_secondaryWindow = system->createWindow(title2, 340, 64, 320, 200, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, false /* stereo flag */); + if (!m_secondaryWindow) { + cout << "could not create secondary window\n"; + exit(-1); + } + + // Install a timer to have the gears running + m_gearsTimer = system->installTimer(0 /*delay*/, 20/*interval*/, gearsTimerProc, m_mainWindow); +} + + +Application::~Application(void) +{ + // Dispose windows + if (m_system->validWindow(m_mainWindow)) { + m_system->disposeWindow(m_mainWindow); + } + if (m_system->validWindow(m_secondaryWindow)) { + m_system->disposeWindow(m_secondaryWindow); + } +} + + +bool Application::processEvent(GHOST_IEvent* event) +{ + GHOST_IWindow* window = event->getWindow(); + bool handled = true; + + switch (event->getType()) { +/* case GHOST_kEventUnknown: + break; + case GHOST_kEventCursorButton: + std::cout << "GHOST_kEventCursorButton"; break; + case GHOST_kEventCursorMove: + std::cout << "GHOST_kEventCursorMove"; break; +*/ + case GHOST_kEventWheel: + { + GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*) event->getData(); + if (wheelData->z > 0) + { + view_rotz += 5.f; + } + else + { + view_rotz -= 5.f; + } + } + break; + + case GHOST_kEventKeyUp: + break; + + case GHOST_kEventKeyDown: + { + GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*) event->getData(); + switch (keyData->key) { + case GHOST_kKeyC: + { + int cursor = m_cursor; + cursor++; + if (cursor >= GHOST_kStandardCursorNumCursors) { + cursor = GHOST_kStandardCursorFirstCursor; + } + m_cursor = (GHOST_TStandardCursor)cursor; + window->setCursorShape(m_cursor); + } + break; + + case GHOST_kKeyE: + { + int x = 200, y= 200; + m_system->setCursorPosition(x,y); + break; + } + + case GHOST_kKeyF: + if (!m_system->getFullScreen()) { + // Begin fullscreen mode + GHOST_DisplaySetting setting; + + setting.bpp = 16; + setting.frequency = 50; + setting.xPixels = 640; + setting.yPixels = 480; + m_system->beginFullScreen(setting, &m_fullScreenWindow, false /* stereo flag */); + } + else { + m_system->endFullScreen(); + m_fullScreenWindow = 0; + } + break; + + case GHOST_kKeyH: + window->setCursorVisibility(!window->getCursorVisibility()); + break; + + case GHOST_kKeyM: + { + bool down = false; + m_system->getModifierKeyState(GHOST_kModifierKeyLeftShift,down); + if (down) { + std::cout << "left shift down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightShift,down); + if (down) { + std::cout << "right shift down\n"; } + m_system->getModifierKeyState(GHOST_kModifierKeyLeftAlt,down); + if (down) { + std::cout << "left Alt down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightAlt,down); + if (down) { + std::cout << "right Alt down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyLeftControl,down); + if (down) { + std::cout << "left control down\n"; + } + m_system->getModifierKeyState(GHOST_kModifierKeyRightControl,down); + if (down) { + std::cout << "right control down\n"; + } + } + break; + + case GHOST_kKeyQ: + if (m_system->getFullScreen()) + { + m_system->endFullScreen(); + m_fullScreenWindow = 0; + } + m_exitRequested = true; + break; + + case GHOST_kKeyS: // toggle mono and stereo + if(stereo) + stereo = false; + else + stereo = true; + break; + + case GHOST_kKeyT: + if (!m_testTimer) { + m_testTimer = m_system->installTimer(0, 1000, testTimerProc); + } + + else { + m_system->removeTimer(m_testTimer); + m_testTimer = 0; + } + + break; + + case GHOST_kKeyW: + if (m_mainWindow) + { + STR_String title; + m_mainWindow->getTitle(title); + title += "-"; + m_mainWindow->setTitle(title); + + } + break; + + default: + break; + } + } + break; + + case GHOST_kEventWindowClose: + { + GHOST_IWindow* window2 = event->getWindow(); + if (window2 == m_mainWindow) { + m_exitRequested = true; + } + else { + m_system->disposeWindow(window2); + } + } + break; + + case GHOST_kEventWindowActivate: + handled = false; + break; + + case GHOST_kEventWindowDeactivate: + handled = false; + break; + + case GHOST_kEventWindowUpdate: + { + GHOST_IWindow* window2 = event->getWindow(); + if(!m_system->validWindow(window2)) + break; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if(stereo) + { + View(window2, stereo, LEFT_EYE); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + + View(window2, stereo, RIGHT_EYE); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + } + else + { + View(window2, stereo); + glPushMatrix(); + RenderCamera(); + RenderScene(); + glPopMatrix(); + } + window2->swapBuffers(); + } + break; + + default: + handled = false; + break; + } + return handled; +} + + +int main(int /*argc*/, char** /*argv*/) +{ + nVidiaWindows = false; +// nVidiaWindows = true; + +#ifdef WIN32 + /* Set a couple of settings in the registry for the nVidia detonator driver. + * So this is very specific... + */ + if(nVidiaWindows) + { + LONG lresult; + HKEY hkey = 0; + DWORD dwd = 0; + //unsigned char buffer[128]; + + CRegKey regkey; + //DWORD keyValue; +// lresult = regkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable"); + lresult = regkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable", + KEY_ALL_ACCESS ); + + if(lresult == ERROR_SUCCESS) + printf("Succesfully opened key\n"); +#if 0 + lresult = regkey.QueryValue(&keyValue, "StereoEnable"); + if(lresult == ERROR_SUCCESS) + printf("Succesfully queried key\n"); +#endif + lresult = regkey.SetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable", + "1"); + if(lresult == ERROR_SUCCESS) + printf("Succesfully set value for key\n"); + regkey.Close(); + if(lresult == ERROR_SUCCESS) + printf("Succesfully closed key\n"); +// regkey.Write("2"); + } +#endif // WIN32 + + // Create the system + GHOST_ISystem::createSystem(); + fSystem = GHOST_ISystem::getSystem(); + + if (fSystem) { + // Create an application object + Application app (fSystem); + + // Add the application as event consumer + fSystem->addEventConsumer(&app); + + // Enter main loop + while (!app.m_exitRequested) { + //printf("main: loop\n"); + fSystem->processEvents(true); + fSystem->dispatchEvents(); + } + } + + // Dispose the system + GHOST_ISystem::disposeSystem(); + + return 0; +} + + +static void gearsTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 /*time*/) +{ + fAngle += 2.0; + view_roty += 1.0; + GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData(); + if (fApp->m_fullScreenWindow) { + // Running full screen + fApp->m_fullScreenWindow->invalidate(); + } + else { + if (fSystem->validWindow(window)) { + window->invalidate(); + } + } +} diff --git a/intern/ghost/test/gears/Makefile b/intern/ghost/test/gears/Makefile new file mode 100644 index 00000000000..b7966b4d157 --- /dev/null +++ b/intern/ghost/test/gears/Makefile @@ -0,0 +1,48 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# GHOST gears test application Makefile +# + +LIBNAME = gearstest +DIR = $(OCGDIR)/intern/ghost/test + +# we don't want a library here, only object files: +ALLTARGETS = $(OBJS) + +include nan_compile.mk + +CFLAGS += $(LEVEL_2_C_WARNINGS) +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I../.. + diff --git a/intern/ghost/test/make/msvc_6_0/gears.dsp b/intern/ghost/test/make/msvc_6_0/gears.dsp new file mode 100644 index 00000000000..3e809a6b604 --- /dev/null +++ b/intern/ghost/test/make/msvc_6_0/gears.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="gears" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gears - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gears.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gears.mak" CFG="gears - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gears - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gears - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gears - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../../../../../../obj/windows/intern/ghost/test/" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/ghost/test/" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../.." /I "../../../../string" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "gears - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../../../../../../obj/windows/intern/ghost/test/debug" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/ghost/test/debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../.." /I "../../../../string" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gears - Win32 Release" +# Name "gears - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\gears\GHOST_Test.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/intern/ghost/test/make/msvc_6_0/gears_C.dsp b/intern/ghost/test/make/msvc_6_0/gears_C.dsp new file mode 100644 index 00000000000..5972d123268 --- /dev/null +++ b/intern/ghost/test/make/msvc_6_0/gears_C.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="gears_C" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gears_C - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gears_C.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gears_C.mak" CFG="gears_C - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gears_C - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gears_C - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gears_C - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../../../../../../obj/windows/intern/ghost/test/" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/ghost/test/" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../.." /I "../../../../string" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "gears_C - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../../../../../../obj/windows/intern/ghost/test/debug" +# PROP Intermediate_Dir "../../../../../../obj/windows/intern/ghost/test/debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../.." /I "../../../../string" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gears_C - Win32 Release" +# Name "gears_C - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\gears\GHOST_C-Test.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/intern/ghost/test/make/msvc_6_0/ghost_test.dsw b/intern/ghost/test/make/msvc_6_0/ghost_test.dsw new file mode 100644 index 00000000000..03bf5eb5c9a --- /dev/null +++ b/intern/ghost/test/make/msvc_6_0/ghost_test.dsw @@ -0,0 +1,77 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gears"=.\gears.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency +}}} + +############################################################################### + +Project: "gears_C"=.\gears_C.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency +}}} + +############################################################################### + +Project: "ghost"=..\..\..\make\msvc\ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "string"=..\..\..\..\string\make\msvc_6_0\string.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/ghost/test/multitest/Basic.c b/intern/ghost/test/multitest/Basic.c new file mode 100644 index 00000000000..db2ad9428b2 --- /dev/null +++ b/intern/ghost/test/multitest/Basic.c @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "Basic.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +int min_i(int a, int b) { + return (a + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" +#include "EventToBuf.h" + +char *eventtype_to_string(GHOST_TEventType type) { + switch(type) { + case GHOST_kEventCursorMove: return "CursorMove"; + case GHOST_kEventButtonDown: return "ButtonDown"; + case GHOST_kEventButtonUp: return "ButtonUp"; + + case GHOST_kEventKeyDown: return "KeyDown"; + case GHOST_kEventKeyUp: return "KeyUp"; + + case GHOST_kEventQuit: return "Quit"; + + case GHOST_kEventWindowClose: return "WindowClose"; + case GHOST_kEventWindowActivate: return "WindowActivate"; + case GHOST_kEventWindowDeactivate: return "WindowDeactivate"; + case GHOST_kEventWindowUpdate: return "WindowUpdate"; + case GHOST_kEventWindowSize: return "WindowSize"; + default: + return ""; + } +} + +static char *keytype_to_string(GHOST_TKey key) { +#define K(key) case GHOST_k##key: return #key; + switch (key) { + K(KeyBackSpace); + K(KeyTab); + K(KeyLinefeed); + K(KeyClear); + K(KeyEnter); + + K(KeyEsc); + K(KeySpace); + K(KeyQuote); + K(KeyComma); + K(KeyMinus); + K(KeyPeriod); + K(KeySlash); + + K(Key0); + K(Key1); + K(Key2); + K(Key3); + K(Key4); + K(Key5); + K(Key6); + K(Key7); + K(Key8); + K(Key9); + + K(KeySemicolon); + K(KeyEqual); + + K(KeyA); + K(KeyB); + K(KeyC); + K(KeyD); + K(KeyE); + K(KeyF); + K(KeyG); + K(KeyH); + K(KeyI); + K(KeyJ); + K(KeyK); + K(KeyL); + K(KeyM); + K(KeyN); + K(KeyO); + K(KeyP); + K(KeyQ); + K(KeyR); + K(KeyS); + K(KeyT); + K(KeyU); + K(KeyV); + K(KeyW); + K(KeyX); + K(KeyY); + K(KeyZ); + + K(KeyLeftBracket); + K(KeyRightBracket); + K(KeyBackslash); + K(KeyAccentGrave); + + K(KeyLeftShift); + K(KeyRightShift); + K(KeyLeftControl); + K(KeyRightControl); + K(KeyLeftAlt); + K(KeyRightAlt); + K(KeyCommand); + + K(KeyCapsLock); + K(KeyNumLock); + K(KeyScrollLock); + + K(KeyLeftArrow); + K(KeyRightArrow); + K(KeyUpArrow); + K(KeyDownArrow); + + K(KeyPrintScreen); + K(KeyPause); + + K(KeyInsert); + K(KeyDelete); + K(KeyHome); + K(KeyEnd); + K(KeyUpPage); + K(KeyDownPage); + + K(KeyNumpad0); + K(KeyNumpad1); + K(KeyNumpad2); + K(KeyNumpad3); + K(KeyNumpad4); + K(KeyNumpad5); + K(KeyNumpad6); + K(KeyNumpad7); + K(KeyNumpad8); + K(KeyNumpad9); + K(KeyNumpadPeriod); + K(KeyNumpadEnter); + K(KeyNumpadPlus); + K(KeyNumpadMinus); + K(KeyNumpadAsterisk); + K(KeyNumpadSlash); + + K(KeyF1); + K(KeyF2); + K(KeyF3); + K(KeyF4); + K(KeyF5); + K(KeyF6); + K(KeyF7); + K(KeyF8); + K(KeyF9); + K(KeyF10); + K(KeyF11); + K(KeyF12); + K(KeyF13); + K(KeyF14); + K(KeyF15); + K(KeyF16); + K(KeyF17); + K(KeyF18); + K(KeyF19); + K(KeyF20); + K(KeyF21); + K(KeyF22); + K(KeyF23); + K(KeyF24); + + default: + return "KeyUnknown"; + } +#undef K +} + +void event_to_buf(GHOST_EventHandle evt, char buf[128]) { + GHOST_TEventType type= GHOST_GetEventType(evt); + double time= (double) ((GHOST_TInt64) GHOST_GetEventTime(evt))/1000; + GHOST_WindowHandle win= GHOST_GetEventWindow(evt); + void *data= GHOST_GetEventData(evt); + char *pos= buf; + + pos+= sprintf(pos, "event: %6.2f, %16s", time, eventtype_to_string(type)); + if (win) { + char *s= GHOST_GetTitle(win); + pos+= sprintf(pos, " - win: %s", s); + free(s); + } else { + pos+= sprintf(pos, " - sys evt"); + } + switch (type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= data; + pos+= sprintf(pos, " - pos: (%d, %d)", cd->x, cd->y); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= data; + pos+= sprintf(pos, " - but: %d", bd->button); + break; + } + + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= data; + pos+= sprintf(pos, " - key: %s (%d)", keytype_to_string(kd->key), kd->key); + if (kd->ascii) pos+= sprintf(pos, " ascii: '%c' (%d)", kd->ascii, kd->ascii); + break; + } + } +} diff --git a/intern/ghost/test/multitest/EventToBuf.h b/intern/ghost/test/multitest/EventToBuf.h new file mode 100644 index 00000000000..0324af1f73f --- /dev/null +++ b/intern/ghost/test/multitest/EventToBuf.h @@ -0,0 +1,34 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +char *eventtype_to_string(GHOST_TEventType type); +void event_to_buf(GHOST_EventHandle evt, char buf[128]); + diff --git a/intern/ghost/test/multitest/GL.h b/intern/ghost/test/multitest/GL.h new file mode 100644 index 00000000000..7a96ae9e9f8 --- /dev/null +++ b/intern/ghost/test/multitest/GL.h @@ -0,0 +1,44 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#if defined(WIN32) || defined(__APPLE__) + + #ifdef WIN32 + #include + #include + #else // WIN32 + // __APPLE__ is defined + #include + #endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) + #include +#endif // defined(WIN32) || defined(__APPLE__) + diff --git a/intern/ghost/test/multitest/Makefile b/intern/ghost/test/multitest/Makefile new file mode 100644 index 00000000000..a424a397502 --- /dev/null +++ b/intern/ghost/test/multitest/Makefile @@ -0,0 +1,60 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# GHOST gears test application Makefile +# + +DIR = $(OCGDIR)/intern/ghost/test + +# we don't want a library here, only object files: +ALLTARGETS = $(OBJS) + +include nan_compile.mk +include nan_link.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_BMFONT)/include +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../.. + +OCGGHOST = $(OCGDIR)/intern/ghost + +LIBS = $(OCGGHOST)/$(DEBUG_DIR)libghost.a +SLIBS += $(LCGDIR)/string/lib/libstring.a +SLIBS += $(LCGDIR)/bmfont/lib/libbmfont.a +SLIBS += $(LCGDIR)/guardedalloc/lib/libguardedalloc.a + +all:: + @echo "- link $(DIR)/$(DEBUG_DIR)multitest -" + @$(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)multitest $(OBJS) $(LIBS) $(SLIBS) $(LLIBS) $(DADD) $(LOPTS) diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c new file mode 100644 index 00000000000..e81fb3c034e --- /dev/null +++ b/intern/ghost/test/multitest/MultiTest.c @@ -0,0 +1,866 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#define FALSE 0 + +#ifdef WIN32 + +#pragma warning(disable: 4244 4305) +#endif + +#include +#include +#include +#include + +#include "GL.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" +#include "BMF_Api.h" + +#include "Util.h" +#include "Basic.h" +#include "ScrollBar.h" +#include "EventToBuf.h" + +#include "WindowData.h" + +/***/ + +typedef struct _MultiTestApp MultiTestApp; +typedef struct _LoggerWindow LoggerWindow; + +void loggerwindow_log(LoggerWindow *lw, char *line); + +void multitestapp_toggle_extra_window(MultiTestApp *app); +void multitestapp_free_extrawindow(MultiTestApp *app); +LoggerWindow *multitestapp_get_logger(MultiTestApp *app); +GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app); +void multitestapp_exit(MultiTestApp *app); + +/**/ + +void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, float *col, int width) { + int ltidx= (side/2)%4; + int dkidx= (ltidx + 1 + (side&1))%4; + int i, corner; + + glBegin(GL_LINES); + for (i=0; iltidx)?dkf:ltf; + int lx= rect[1][0]-i-1; + int ly= rect[0][1]+i; + + glColor3f(col[0]*stf, col[1]*stf, col[2]*stf); + for (corner=0; corner<4; corner++) { + int x= (corner==0 || corner==1)?(rect[0][0]+i):(rect[1][0]-i-1); + int y= (corner==0 || corner==3)?(rect[0][1]+i):(rect[1][1]-i-1); + + if (ltidx==corner) + glColor3f(col[0]*ltf, col[1]*ltf, col[2]*ltf); + if (dkidx==corner) + glColor3f(col[0]*dkf, col[1]*dkf, col[2]*dkf); + + glVertex2i(lx, ly); + glVertex2i(lx= x, ly= y); + } + } + glEnd(); + + glColor3fv(col); + glRecti(rect[0][0]+width, rect[0][1]+width, rect[1][0]-width, rect[1][1]-width); +} + +void rect_bevel_smooth(int rect[2][2], int width) { + float *lt= malloc(sizeof(*lt)*width); + float *dk= malloc(sizeof(*dk)*width); + float col[4]; + int i; + + for (i=0; iapp), str); +} + +static void mainwindow_do_draw(MainWindow *mw) { + GHOST_ActivateWindowDrawingContext(mw->win); + + if (mw->lmbut[0]) { + glClearColor(0.5, 0.5, 0.5, 1); + } else { + glClearColor(1, 1, 1, 1); + } + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.5, 0.6, 0.8); + glRecti(mw->tmouse[0]-5, mw->tmouse[1]-5, mw->tmouse[0]+5, mw->tmouse[1]+5); + + GHOST_SwapWindowBuffers(mw->win); +} + +static void mainwindow_do_reshape(MainWindow *mw) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(mw->win); + + GHOST_ActivateWindowDrawingContext(mw->win); + + mw->size[0]= GHOST_GetWidthRectangle(bounds); + mw->size[1]= GHOST_GetHeightRectangle(bounds); + + glViewport(0, 0, mw->size[0], mw->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, mw->size[0], 0, mw->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void mainwindow_do_key(MainWindow *mw, GHOST_TKey key, int press) { + switch(key) { + case GHOST_kKeyC: + if (press) + GHOST_SetCursorShape(mw->win, (GHOST_TStandardCursor) (rand()%(GHOST_kStandardCursorNumCursors))); + break; + case GHOST_kKeyLeftBracket: + if (press) + GHOST_SetCursorVisibility(mw->win, 0); + break; + case GHOST_kKeyRightBracket: + if (press) + GHOST_SetCursorVisibility(mw->win, 1); + break; + case GHOST_kKeyE: + if (press) + multitestapp_toggle_extra_window(mw->app); + break; + case GHOST_kKeyQ: + if (press) + multitestapp_exit(mw->app); + break; + case GHOST_kKeyT: + if (press) + mainwindow_log(mw, "TextTest~|`hello`\"world\",<>/"); + break; + case GHOST_kKeyR: + if (press) { + int i; + + mainwindow_log(mw, "Invalidating window 10 times"); + for (i=0; i<10; i++) + GHOST_InvalidateWindow(mw->win); + } + break; + case GHOST_kKeyF11: + if (press) { + GHOST_SetWindowOrder(mw->win, GHOST_kWindowOrderBottom); + } + break; + } +} + +static void mainwindow_do_move(MainWindow *mw, int x, int y) { + mw->lmouse[0]= x, mw->lmouse[1]= y; + + if (mw->lmbut[0]) { + mw->tmouse[0]= x, mw->tmouse[1]= y; + GHOST_InvalidateWindow(mw->win); + } +} + +static void mainwindow_do_button(MainWindow *mw, int which, int press) { + if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[0]= press; + mw->tmouse[0]= mw->lmouse[0], mw->tmouse[1]= mw->lmouse[1]; + GHOST_InvalidateWindow(mw->win); + } else if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[1]= press; + } else if (which==GHOST_kButtonMaskLeft) { + mw->lmbut[2]= press; + } +} + +static void mainwindow_handle(void *priv, GHOST_EventHandle evt) { + MainWindow *mw= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + char buf[256]; + + event_to_buf(evt, buf); + mainwindow_log(mw, buf); + + switch (type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= GHOST_GetEventData(evt); + int x, y; + GHOST_ScreenToClient(mw->win, cd->x, cd->y, &x, &y); + mainwindow_do_move(mw, x, mw->size[1]-y-1); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= GHOST_GetEventData(evt); + mainwindow_do_button(mw, bd->button, (type == GHOST_kEventButtonDown)); + break; + } + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + mainwindow_do_key(mw, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventWindowUpdate: + mainwindow_do_draw(mw); + break; + case GHOST_kEventWindowSize: + mainwindow_do_reshape(mw); + break; + } +} + +/**/ + +static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time) { + MainWindow *mw= GHOST_GetTimerTaskUserData(task); + char buf[64]; + + sprintf(buf, "timer: %6.2f", (double) ((GHOST_TInt64) time)/1000); + mainwindow_log(mw, buf); +} + +MainWindow *mainwindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_WindowHandle win; + + win= GHOST_CreateWindow(sys, "MultiTest:Main", 40, 40, 400, 400, + GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, + FALSE); + + if (win) { + MainWindow *mw= MEM_callocN(sizeof(*mw), "mainwindow_new"); + mw->app= app; + mw->win= win; + + GHOST_SetWindowUserData(mw->win, windowdata_new(mw, mainwindow_handle)); + + GHOST_InstallTimer(sys, 1000, 10000, mainwindow_timer_proc, mw); + + return mw; + } else { + return NULL; + } +} + +void mainwindow_free(MainWindow *mw) { + GHOST_SystemHandle sys= multitestapp_get_system(mw->app); + + windowdata_free(GHOST_GetWindowUserData(mw->win)); + GHOST_DisposeWindow(sys, mw->win); + MEM_freeN(mw); +} + + /* + * LoggerWindow + */ + +struct _LoggerWindow { + MultiTestApp *app; + + GHOST_WindowHandle win; + + BMF_Font *font; + int fonttexid; + int fontheight; + + int size[2]; + + int ndisplines; + int textarea[2][2]; + ScrollBar *scroll; + + char **loglines; + int nloglines, logsize; + + int lmbut[3]; + int lmouse[2]; +}; + +#define SCROLLBAR_PAD 2 +#define SCROLLBAR_WIDTH 14 +#define TEXTAREA_PAD 2 +static void loggerwindow_recalc_regions(LoggerWindow *lw) { + int nscroll[2][2]; + + nscroll[0][0]= SCROLLBAR_PAD; + nscroll[0][1]= SCROLLBAR_PAD; + nscroll[1][0]= nscroll[0][0] + SCROLLBAR_WIDTH; + nscroll[1][1]= lw->size[1] - SCROLLBAR_PAD - 1; + + lw->textarea[0][0]= nscroll[1][0] + TEXTAREA_PAD; + lw->textarea[0][1]= TEXTAREA_PAD; + lw->textarea[1][0]= lw->size[0] - TEXTAREA_PAD - 1; + lw->textarea[1][1]= lw->size[1] - TEXTAREA_PAD - 1; + + lw->ndisplines= (lw->textarea[1][1]-lw->textarea[0][1])/lw->fontheight; + + scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines/lw->nloglines); + scrollbar_set_rect(lw->scroll, nscroll); +} + +static void loggerwindow_setup_window_gl(LoggerWindow *lw) { + glViewport(0, 0, lw->size[0], lw->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, lw->size[0], 0, lw->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void loggerwindow_do_reshape(LoggerWindow *lw) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(lw->win); + + GHOST_ActivateWindowDrawingContext(lw->win); + + lw->size[0]= GHOST_GetWidthRectangle(bounds); + lw->size[1]= GHOST_GetHeightRectangle(bounds); + + loggerwindow_recalc_regions(lw); + loggerwindow_setup_window_gl(lw); +} + +static void loggerwindow_do_draw(LoggerWindow *lw) { + int i, ndisplines, startline; + int sb_rect[2][2], sb_thumb[2][2]; + + GHOST_ActivateWindowDrawingContext(lw->win); + + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8, 0.8, 0.8); + rect_bevel_smooth(lw->textarea, 4); + + scrollbar_get_rect(lw->scroll, sb_rect); + scrollbar_get_thumb(lw->scroll, sb_thumb); + + glColor3f(0.6, 0.6, 0.6); + rect_bevel_smooth(sb_rect, 1); + + if (scrollbar_is_scrolling(lw->scroll)) { + glColor3f(0.6, 0.7, 0.5); + } else { + glColor3f(0.9, 0.9, 0.92); + } + rect_bevel_smooth(sb_thumb, 1); + + startline= scrollbar_get_thumbpos(lw->scroll)*(lw->nloglines-1); + ndisplines= min_i(lw->ndisplines, lw->nloglines-startline); + + if (lw->fonttexid!=-1) { + glBindTexture(GL_TEXTURE_2D, lw->fonttexid); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + } + glColor3f(0, 0, 0); + for (i=0; iloglines[(lw->nloglines-1)-(i+startline)]; + int x_pos= lw->textarea[0][0] + 4; + int y_pos= lw->textarea[0][1] + 4 + i*lw->fontheight; + + if (lw->fonttexid==-1) { + glRasterPos2i(x_pos, y_pos); + BMF_DrawString(lw->font, line); + } else { + BMF_DrawStringTexture(lw->font, line, x_pos, y_pos, 0.0); + } + } + if (lw->fonttexid!=-1) { + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + } + + GHOST_SwapWindowBuffers(lw->win); +} + +static void loggerwindow_do_move(LoggerWindow *lw, int x, int y) { + lw->lmouse[0]= x, lw->lmouse[1]= y; + + if (scrollbar_is_scrolling(lw->scroll)) { + scrollbar_keep_scrolling(lw->scroll, y); + GHOST_InvalidateWindow(lw->win); + } +} + +static void loggerwindow_do_button(LoggerWindow *lw, int which, int press) { + if (which==GHOST_kButtonMaskLeft) { + lw->lmbut[0]= press; + + if (press) { + if (scrollbar_contains_pt(lw->scroll, lw->lmouse)) { + scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]); + GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorUpDown); + GHOST_InvalidateWindow(lw->win); + } + } else { + if (scrollbar_is_scrolling(lw->scroll)) { + scrollbar_stop_scrolling(lw->scroll); + GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorDefault); + GHOST_InvalidateWindow(lw->win); + } + } + } else if (which==GHOST_kButtonMaskMiddle) { + lw->lmbut[1]= press; + } else if (which==GHOST_kButtonMaskRight) { + lw->lmbut[2]= press; + } +} + +static void loggerwindow_do_key(LoggerWindow *lw, GHOST_TKey key, int press) { + switch (key) { + case GHOST_kKeyQ: + if (press) + multitestapp_exit(lw->app); + break; + } +} + +static void loggerwindow_handle(void *priv, GHOST_EventHandle evt) { + LoggerWindow *lw= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + + switch(type) { + case GHOST_kEventCursorMove: { + GHOST_TEventCursorData *cd= GHOST_GetEventData(evt); + int x, y; + GHOST_ScreenToClient(lw->win, cd->x, cd->y, &x, &y); + loggerwindow_do_move(lw, x, lw->size[1]-y-1); + break; + } + case GHOST_kEventButtonDown: + case GHOST_kEventButtonUp: { + GHOST_TEventButtonData *bd= GHOST_GetEventData(evt); + loggerwindow_do_button(lw, bd->button, (type == GHOST_kEventButtonDown)); + break; + } + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + loggerwindow_do_key(lw, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventWindowUpdate: + loggerwindow_do_draw(lw); + break; + case GHOST_kEventWindowSize: + loggerwindow_do_reshape(lw); + break; + } +} + +/**/ + +LoggerWindow *loggerwindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_TUns32 screensize[2]; + GHOST_WindowHandle win; + + GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]); + win= GHOST_CreateWindow(sys, "MultiTest:Logger", 40, screensize[1]-432, + 800, 300, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, FALSE); + + if (win) { + LoggerWindow *lw= MEM_callocN(sizeof(*lw), "loggerwindow_new"); + int bbox[2][2]; + lw->app= app; + lw->win= win; + + lw->font= BMF_GetFont(BMF_kScreen12); + lw->fonttexid= BMF_GetFontTexture(lw->font); + + BMF_GetBoundingBox(lw->font, &bbox[0][0], &bbox[0][1], &bbox[1][0], &bbox[1][1]); + lw->fontheight= rect_height(bbox); + + lw->nloglines= lw->logsize= 0; + lw->loglines= MEM_mallocN(sizeof(*lw->loglines)*lw->nloglines, "loglines"); + + lw->scroll= scrollbar_new(2, 40); + + GHOST_SetWindowUserData(lw->win, windowdata_new(lw, loggerwindow_handle)); + + loggerwindow_do_reshape(lw); + + return lw; + } else { + return NULL; + } +} + +void loggerwindow_log(LoggerWindow *lw, char *line) { + if (lw->nloglines==lw->logsize) { + lw->loglines= memdbl(lw->loglines, &lw->logsize, sizeof(*lw->loglines)); + } + + lw->loglines[lw->nloglines++]= string_dup(line); + scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines/lw->nloglines); + + GHOST_InvalidateWindow(lw->win); +} + +void loggerwindow_free(LoggerWindow *lw) { + GHOST_SystemHandle sys= multitestapp_get_system(lw->app); + int i; + + for (i=0; inloglines; i++) { + MEM_freeN(lw->loglines[i]); + } + MEM_freeN(lw->loglines); + + windowdata_free(GHOST_GetWindowUserData(lw->win)); + GHOST_DisposeWindow(sys, lw->win); + MEM_freeN(lw); +} + + /* + * ExtraWindow + */ + + +typedef struct { + MultiTestApp *app; + + GHOST_WindowHandle win; + + int size[2]; +} ExtraWindow; + +static void extrawindow_do_draw(ExtraWindow *ew) { + GHOST_ActivateWindowDrawingContext(ew->win); + + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8, 0.8, 0.8); + glRecti(10, 10, ew->size[0]-10, ew->size[1]-10); + + GHOST_SwapWindowBuffers(ew->win); +} + +static void extrawindow_do_reshape(ExtraWindow *ew) { + GHOST_RectangleHandle bounds= GHOST_GetClientBounds(ew->win); + + GHOST_ActivateWindowDrawingContext(ew->win); + + ew->size[0]= GHOST_GetWidthRectangle(bounds); + ew->size[1]= GHOST_GetHeightRectangle(bounds); + + glViewport(0, 0, ew->size[0], ew->size[1]); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, ew->size[0], 0, ew->size[1], -1, 1); + glTranslatef(0.375, 0.375, 0.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void extrawindow_do_key(ExtraWindow *ew, GHOST_TKey key, int press) { + switch (key) { + case GHOST_kKeyE: + if (press) + multitestapp_toggle_extra_window(ew->app); + break; + } +} + +static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time) { + GHOST_TUns8 bitmap[16][2]; + GHOST_TUns8 mask[16][2]; + double ftime= (double) ((GHOST_TInt64) time)/1000; + float angle= fmod(ftime, 1.0) * 3.1415*2; + int i; + + memset(&bitmap, 0, sizeof(bitmap)); + memset(&mask, 0, sizeof(mask)); + + bitmap[0][0] |= mask[0][0] |= 0xF; + bitmap[1][0] |= mask[1][0] |= 0xF; + bitmap[2][0] |= mask[2][0] |= 0xF; + bitmap[3][0] |= mask[3][0] |= 0xF; + + for (i=0; i<7; i++) { + int x = 7 + cos(angle)*i; + int y = 7 + sin(angle)*i; + + mask[y][x/8] |= (1 << (x%8)); + } + for (i=0; i<64; i++) { + float v= (i/63.0) * 3.1415*2; + int x = 7 + cos(v)*7; + int y = 7 + sin(v)*7; + + mask[y][x/8] |= (1 << (x%8)); + } + + GHOST_SetCustomCursorShape(ew->win, bitmap, mask, 0, 0); +} + +static void extrawindow_handle(void *priv, GHOST_EventHandle evt) { + ExtraWindow *ew= priv; + GHOST_TEventType type= GHOST_GetEventType(evt); + char buf[256]; + + event_to_buf(evt, buf); + loggerwindow_log(multitestapp_get_logger(ew->app), buf); + + switch (type) { + case GHOST_kEventKeyDown: + case GHOST_kEventKeyUp: { + GHOST_TEventKeyData *kd= GHOST_GetEventData(evt); + extrawindow_do_key(ew, kd->key, (type == GHOST_kEventKeyDown)); + break; + } + + case GHOST_kEventCursorMove: { + extrawindow_spin_cursor(ew, GHOST_GetEventTime(evt)); + break; + } + + case GHOST_kEventWindowClose: + multitestapp_free_extrawindow(ew->app); + break; + case GHOST_kEventWindowUpdate: + extrawindow_do_draw(ew); + break; + case GHOST_kEventWindowSize: + extrawindow_do_reshape(ew); + break; + } +} + +/**/ + +ExtraWindow *extrawindow_new(MultiTestApp *app) { + GHOST_SystemHandle sys= multitestapp_get_system(app); + GHOST_WindowHandle win; + + win= GHOST_CreateWindow(sys, "MultiTest:Extra", 500, 40, 400, 400, + GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, + FALSE); + + if (win) { + ExtraWindow *ew= MEM_callocN(sizeof(*ew), "mainwindow_new"); + ew->app= app; + ew->win= win; + + GHOST_SetWindowUserData(ew->win, windowdata_new(ew, extrawindow_handle)); + + return ew; + } else { + return NULL; + } +} + +void extrawindow_free(ExtraWindow *ew) { + GHOST_SystemHandle sys= multitestapp_get_system(ew->app); + + windowdata_free(GHOST_GetWindowUserData(ew->win)); + GHOST_DisposeWindow(sys, ew->win); + MEM_freeN(ew); +} + + /* + * MultiTestApp + */ + +struct _MultiTestApp { + GHOST_SystemHandle sys; + MainWindow *main; + LoggerWindow *logger; + ExtraWindow *extra; + + int exit; +}; + +static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data) { + MultiTestApp *app= data; + GHOST_WindowHandle win; + + win= GHOST_GetEventWindow(evt); + if (win && !GHOST_ValidWindow(app->sys, win)) { + loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n"); + return 1; + } + + if (win) { + WindowData *wb= GHOST_GetWindowUserData(win); + + windowdata_handle(wb, evt); + } else { + GHOST_TEventType type= GHOST_GetEventType(evt); + + /* GHOST_kEventQuit are the only 'system' events, + * that is, events without a window. + */ + switch(type) { + case GHOST_kEventQuit: + app->exit= 1; + break; + + default: + fatal("Unhandled system event: %d (%s)\n", type, eventtype_to_string(type)); + break; + } + } + + return 1; +} + +/**/ + +MultiTestApp *multitestapp_new(void) { + MultiTestApp *app= MEM_mallocN(sizeof(*app), "multitestapp_new"); + GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(multitest_event_handler, app); + + app->sys= GHOST_CreateSystem(); + if (!app->sys) + fatal("Unable to create ghost system"); + + if (!GHOST_AddEventConsumer(app->sys, consumer)) + fatal("Unable to add multitest event consumer "); + + app->main= mainwindow_new(app); + if (!app->main) + fatal("Unable to create main window"); + + app->logger= loggerwindow_new(app); + if (!app->logger) + fatal("Unable to create logger window"); + + app->extra= NULL; + app->exit= 0; + + return app; +} + +LoggerWindow *multitestapp_get_logger(MultiTestApp *app) { + return app->logger; +} + +GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app) { + return app->sys; +} + +void multitestapp_free_extrawindow(MultiTestApp *app) { + extrawindow_free(app->extra); + app->extra= NULL; +} + +void multitestapp_toggle_extra_window(MultiTestApp *app) { + if (app->extra) { + multitestapp_free_extrawindow(app); + } else { + app->extra= extrawindow_new(app); + } +} + +void multitestapp_exit(MultiTestApp *app) { + app->exit= 1; +} + +void multitestapp_run(MultiTestApp *app) { + while (!app->exit) { + GHOST_ProcessEvents(app->sys, 1); + GHOST_DispatchEvents(app->sys); + } +} + +void multitestapp_free(MultiTestApp *app) { + mainwindow_free(app->main); + loggerwindow_free(app->logger); + GHOST_DisposeSystem(app->sys); + MEM_freeN(app); +} + + /***/ + +int main(int argc, char **argv) { + MultiTestApp *app= multitestapp_new(); + + multitestapp_run(app); + multitestapp_free(app); + + return 0; +} diff --git a/intern/ghost/test/multitest/ScrollBar.c b/intern/ghost/test/multitest/ScrollBar.c new file mode 100644 index 00000000000..6ede0619b5f --- /dev/null +++ b/intern/ghost/test/multitest/ScrollBar.c @@ -0,0 +1,149 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "Basic.h" +#include "ScrollBar.h" + +struct _ScrollBar { + int rect[2][2]; + float thumbpos, thumbpct; + + int inset; + int minthumb; + + int scrolling; + float scrolloffs; +}; + +static int scrollbar_get_thumbH(ScrollBar *sb) { + int scrollable_h= rect_height(sb->rect) - 2*sb->inset; + + return clamp_i(sb->thumbpct*scrollable_h, sb->minthumb, scrollable_h); +} +static int scrollbar_get_thumbableH(ScrollBar *sb) { + int scrollable_h= rect_height(sb->rect) - 2*sb->inset; + int thumb_h= scrollbar_get_thumbH(sb); + + return scrollable_h - thumb_h; +} + +static float scrollbar_co_to_pos(ScrollBar *sb, int yco) { + int thumb_h= scrollbar_get_thumbH(sb); + int thumbable_h= scrollbar_get_thumbableH(sb); + int thumbable_y= (sb->rect[0][1]+sb->inset) + thumb_h/2; + + return (float) (yco-thumbable_y)/thumbable_h; +} + +/**/ + +ScrollBar *scrollbar_new(int inset, int minthumb) { + ScrollBar *sb= MEM_callocN(sizeof(*sb), "scrollbar_new"); + sb->inset= inset; + sb->minthumb= minthumb; + + return sb; +} + +void scrollbar_get_thumb(ScrollBar *sb, int thumb_r[2][2]) { + int thumb_h= scrollbar_get_thumbH(sb); + int thumbable_h= scrollbar_get_thumbableH(sb); + + thumb_r[0][0]= sb->rect[0][0]+sb->inset; + thumb_r[1][0]= sb->rect[1][0]-sb->inset; + + thumb_r[0][1]= sb->rect[0][1]+sb->inset + sb->thumbpos*thumbable_h; + thumb_r[1][1]= thumb_r[0][1] + thumb_h; +} + +int scrollbar_is_scrolling(ScrollBar *sb) { + return sb->scrolling; +} +int scrollbar_contains_pt(ScrollBar *sb, int pt[2]) { + return rect_contains_pt(sb->rect, pt); +} + +void scrollbar_start_scrolling(ScrollBar *sb, int yco) { + int thumb_h_2= scrollbar_get_thumbH(sb)/2; + int thumbable_h= scrollbar_get_thumbableH(sb); + float npos= scrollbar_co_to_pos(sb, yco); + + sb->scrolloffs= sb->thumbpos - npos; + if (fabs(sb->scrolloffs) >= (float) thumb_h_2/thumbable_h) { + sb->scrolloffs= 0.0; + } + + sb->scrolling= 1; + sb->thumbpos= clamp_f(npos + sb->scrolloffs, 0.0, 1.0); +} +void scrollbar_keep_scrolling(ScrollBar *sb, int yco) { + float npos= scrollbar_co_to_pos(sb, yco); + + sb->thumbpos= clamp_f(npos + sb->scrolloffs, 0.0, 1.0); +} +void scrollbar_stop_scrolling(ScrollBar *sb) { + sb->scrolling= 0; + sb->scrolloffs= 0.0; +} + +void scrollbar_set_thumbpct(ScrollBar *sb, float pct) { + sb->thumbpct= pct; +} +void scrollbar_set_thumbpos(ScrollBar *sb, float pos) { + sb->thumbpos= clamp_f(pos, 0.0, 1.0); +} +void scrollbar_set_rect(ScrollBar *sb, int rect[2][2]) { + rect_copy(sb->rect, rect); +} + +float scrollbar_get_thumbpct(ScrollBar *sb) { + return sb->thumbpct; +} +float scrollbar_get_thumbpos(ScrollBar *sb) { + return sb->thumbpos; +} +void scrollbar_get_rect(ScrollBar *sb, int rect_r[2][2]) { + rect_copy(rect_r, sb->rect); +} + +void scrollbar_free(ScrollBar *sb) { + MEM_freeN(sb); +} diff --git a/intern/ghost/test/multitest/ScrollBar.h b/intern/ghost/test/multitest/ScrollBar.h new file mode 100644 index 00000000000..b49ad041415 --- /dev/null +++ b/intern/ghost/test/multitest/ScrollBar.h @@ -0,0 +1,57 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +typedef struct _ScrollBar ScrollBar; + + + /***/ + +ScrollBar* scrollbar_new (int inset, int minthumb); + +int scrollbar_is_scrolling (ScrollBar *sb); +int scrollbar_contains_pt (ScrollBar *sb, int pt[2]); + +void scrollbar_start_scrolling (ScrollBar *sb, int yco); +void scrollbar_keep_scrolling (ScrollBar *sb, int yco); +void scrollbar_stop_scrolling (ScrollBar *sb); + +void scrollbar_set_thumbpct (ScrollBar *sb, float pct); +void scrollbar_set_thumbpos (ScrollBar *sb, float pos); +void scrollbar_set_rect (ScrollBar *sb, int rect[2][2]); + +float scrollbar_get_thumbpct (ScrollBar *sb); +float scrollbar_get_thumbpos (ScrollBar *sb); +void scrollbar_get_rect (ScrollBar *sb, int rect_r[2][2]); + +void scrollbar_get_thumb (ScrollBar *sb, int thumb_r[2][2]); + +void scrollbar_free (ScrollBar *sb); + diff --git a/intern/ghost/test/multitest/Util.c b/intern/ghost/test/multitest/Util.c new file mode 100644 index 00000000000..4cf23ff06a9 --- /dev/null +++ b/intern/ghost/test/multitest/Util.c @@ -0,0 +1,77 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "Util.h" + +void* memdbl(void *mem, int *size_pr, int item_size) { + int cur_size= *size_pr; + int new_size= cur_size?(cur_size*2):1; + void *nmem= MEM_mallocN(new_size*item_size, "memdbl"); + + memcpy(nmem, mem, cur_size*item_size); + MEM_freeN(mem); + + *size_pr= new_size; + return nmem; +} + +char* string_dup(char *str) { + int len= strlen(str); + char *nstr= MEM_mallocN(len + 1, "string_dup"); + + memcpy(nstr, str, len+1); + + return nstr; +} + +void fatal(char *fmt, ...) { + va_list ap; + + fprintf(stderr, "FATAL: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + + exit(1); +} diff --git a/intern/ghost/test/multitest/Util.h b/intern/ghost/test/multitest/Util.h new file mode 100644 index 00000000000..e3e51824515 --- /dev/null +++ b/intern/ghost/test/multitest/Util.h @@ -0,0 +1,36 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +void* memdbl (void *mem, int *size_pr, int item_size); + +char* string_dup (char *str); +void fatal (char *fmt, ...); + diff --git a/intern/ghost/test/multitest/WindowData.c b/intern/ghost/test/multitest/WindowData.c new file mode 100644 index 00000000000..3c5739fd593 --- /dev/null +++ b/intern/ghost/test/multitest/WindowData.c @@ -0,0 +1,63 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" + +#include "WindowData.h" + +struct _WindowData { + void *data; + WindowDataHandler handler; +}; + +WindowData *windowdata_new(void *data, WindowDataHandler handler) { + WindowData *wb= MEM_mallocN(sizeof(*wb), "windowdata_new"); + wb->data= data; + wb->handler= handler; + + return wb; +} + +void windowdata_handle(WindowData *wb, GHOST_EventHandle evt) { + wb->handler(wb->data, evt); +} + +void windowdata_free(WindowData *wb) { + MEM_freeN(wb); +} diff --git a/intern/ghost/test/multitest/WindowData.h b/intern/ghost/test/multitest/WindowData.h new file mode 100644 index 00000000000..10a1ca710f2 --- /dev/null +++ b/intern/ghost/test/multitest/WindowData.h @@ -0,0 +1,40 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +typedef void (*WindowDataHandler)(void *priv, GHOST_EventHandle evt); +typedef struct _WindowData WindowData; + + /***/ + +WindowData* windowdata_new (void *data, WindowDataHandler handler); +void windowdata_handle (WindowData *wb, GHOST_EventHandle evt); +void windowdata_free (WindowData *wb); + diff --git a/intern/guardedalloc/CMakeLists.txt b/intern/guardedalloc/CMakeLists.txt new file mode 100644 index 00000000000..71e3a40fefc --- /dev/null +++ b/intern/guardedalloc/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC .) + +FILE(GLOB SRC intern/*.c) + +BLENDERLIB(bf_guardedalloc "${SRC}" "${INC}") +#, libtype=['intern', 'player'], priority = [10, 175] ) diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h new file mode 100644 index 00000000000..26a9258d03b --- /dev/null +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -0,0 +1,128 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Guarded memory (de)allocation + * + * + * @mainpage MEM - c-style guarded memory allocation + * + * @section about About the MEM module + * + * MEM provides guarded malloc/calloc calls. All memory is enclosed by + * pads, to detect out-of-bound writes. All blocks are placed in a + * linked list, so they remain reachable at all times. There is no + * back-up in case the linked-list related data is lost. + * + * @section issues Known issues with MEM + * + * There are currently no known issues with MEM. Note that there is a + * second intern/ module with MEM_ prefix, for use in c++. + * + * @section dependencies Dependencies + * + * - stdlib + * + * - stdio + * + * */ + +#ifndef MEM_MALLOCN_H +#define MEM_MALLOCN_H + +/* Needed for FILE* */ +#include "stdio.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** Returns the lenght of the allocated memory segment pointed at + * by vmemh. If the pointer was not previously allocated by this + * module, the result is undefined.*/ + int MEM_allocN_len(void *vmemh); + + /** + * Release memory previously allocatred by this module. + */ + short MEM_freeN(void *vmemh); + + /** + * Duplicates a block of memory, and returns a pointer to the + * newly allocated block. */ + void *MEM_dupallocN(void *vmemh); + + /** + * Allocate a block of memory of size len, with tag name str. The + * memory is cleared. The name must be static, because only a + * pointer to it is stored ! */ + void *MEM_callocN(unsigned int len, const char * str); + + /** Allocate a block of memory of size len, with tag name str. The + * name must be a static, because only a pointer to it is stored ! + * */ + void *MEM_mallocN(unsigned int len, const char * str); + + /** Same as callocN, clears memory and uses mmap (disk cached) if supported. + Can be free'd with MEM_freeN as usual. + * */ + void *MEM_mapallocN(unsigned int len, const char * str); + + /** Print a list of the names and sizes of all allocated memory + * blocks. */ + void MEM_printmemlist(void); + + /** Set the callback function for error output. */ + void MEM_set_error_callback(void (*func)(char *)); + + /** + * Are the start/end block markers still correct ? + * + * @retval 0 for correct memory, 1 for corrupted memory. */ + int MEM_check_memory_integrity(void); + + /** Set thread locking functions for safe memory allocation from multiple + threads, pass NULL pointers to disable thread locking again. */ + void MEM_set_lock_callback(void (*lock)(void), void (*unlock)(void)); + + /** Attempt to enforce OSX (or other OS's) to have malloc and stack nonzero */ + void MEM_set_memory_debug(void); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/guardedalloc/Makefile b/intern/guardedalloc/Makefile new file mode 100644 index 00000000000..702e7d5264f --- /dev/null +++ b/intern/guardedalloc/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# decimation main makefile. +# + +include nan_definitions.mk + +LIBNAME = guardedalloc +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_GUARDEDALLOC) ] || mkdir $(NAN_GUARDEDALLOC) + @[ -d $(NAN_GUARDEDALLOC)/include ] || mkdir $(NAN_GUARDEDALLOC)/include + @[ -d $(NAN_GUARDEDALLOC)/lib ] || mkdir $(NAN_GUARDEDALLOC)/lib + @[ -d $(NAN_GUARDEDALLOC)/lib/debug ] || mkdir $(NAN_GUARDEDALLOC)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libguardedalloc.a $(NAN_GUARDEDALLOC)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libguardedalloc.a $(NAN_GUARDEDALLOC)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_GUARDEDALLOC)/lib/libguardedalloc.a + ranlib $(NAN_GUARDEDALLOC)/lib/debug/libguardedalloc.a +endif + @../tools/cpifdiff.sh *.h $(NAN_GUARDEDALLOC)/include/ + diff --git a/intern/guardedalloc/SConscript b/intern/guardedalloc/SConscript new file mode 100644 index 00000000000..ef6c6b49266 --- /dev/null +++ b/intern/guardedalloc/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python + +Import('env') + +sources = env.Glob('intern/*.c') +incs = '.' + +env.BlenderLib ('bf_guardedalloc', sources, Split(incs), defines=[], libtype=['intern', 'player'], priority = [10, 175] ) diff --git a/intern/guardedalloc/intern/Makefile b/intern/guardedalloc/intern/Makefile new file mode 100644 index 00000000000..bc96ba5f27f --- /dev/null +++ b/intern/guardedalloc/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# guardedalloc intern Makefile +# + +LIBNAME = guardedalloc +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(NAN_LEVEL_2_C_WARNINGS) + +CPPFLAGS += -I.. + diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c new file mode 100644 index 00000000000..51c2a2427b5 --- /dev/null +++ b/intern/guardedalloc/intern/mallocn.c @@ -0,0 +1,576 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Guarded memory allocation, and boundary-write detection. + */ + +#include +#include /* memcpy */ +#include + +/* mmap exception */ +#if defined(AMIGA) || defined(__BeOS) || defined(WIN32) +#else +#include +#include +#endif + +#include "MEM_guardedalloc.h" + +/* --------------------------------------------------------------------- */ +/* Data definition */ +/* --------------------------------------------------------------------- */ +/* all memory chunks are put in linked lists */ +typedef struct localLink +{ + struct localLink *next,*prev; +} localLink; + +typedef struct localListBase +{ + void *first, *last; +} localListBase; + + /* note: keep this struct aligned (e.g., irix/gcc) - Hos */ +typedef struct MemHead { + int tag1; + int len; + struct MemHead *next,*prev; + const char * name; + const char * nextname; + int tag2; + int mmap; /* if true, memory was mmapped */ +} MemHead; + +typedef struct MemTail { + int tag3, pad; +} MemTail; + + +/* --------------------------------------------------------------------- */ +/* local functions */ +/* --------------------------------------------------------------------- */ + +static void addtail(volatile localListBase *listbase, void *vlink); +static void remlink(volatile localListBase *listbase, void *vlink); +static void rem_memblock(MemHead *memh); +static void MemorY_ErroR(const char *block, const char *error); +static const char *check_memlist(MemHead *memh); + +/* --------------------------------------------------------------------- */ +/* locally used defines */ +/* --------------------------------------------------------------------- */ + +#if defined( __sgi) || defined (__sun) || defined (__sun__) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || (defined (__APPLE__) && !defined(__LITTLE_ENDIAN__)) +#define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) +#else +#define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) +#endif + +#define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O') +#define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L') +#define MEMTAG3 MAKE_ID('O', 'C', 'K', '!') +#define MEMFREE MAKE_ID('F', 'R', 'E', 'E') + +#define MEMNEXT(x) ((MemHead *)(((char *) x) - ((char *) & (((MemHead *)0)->next)))) + +/* --------------------------------------------------------------------- */ +/* vars */ +/* --------------------------------------------------------------------- */ + + +volatile int totblock= 0; +volatile unsigned long mem_in_use= 0, mmap_in_use= 0; + +volatile static struct localListBase _membase; +volatile static struct localListBase *membase = &_membase; +static void (*error_callback)(char *) = NULL; +static void (*thread_lock_callback)(void) = NULL; +static void (*thread_unlock_callback)(void) = NULL; + +static int malloc_debug_memset= 0; + +#ifdef malloc +#undef malloc +#endif + +#ifdef calloc +#undef calloc +#endif + +#ifdef free +#undef free +#endif + + +/* --------------------------------------------------------------------- */ +/* implementation */ +/* --------------------------------------------------------------------- */ + +static void print_error(const char *str, ...) +{ + char buf[1024]; + va_list ap; + + va_start(ap, str); + vsprintf(buf, str, ap); + va_end(ap); + + if (error_callback) error_callback(buf); +} + +static void mem_lock_thread() +{ + if (thread_lock_callback) + thread_lock_callback(); +} + +static void mem_unlock_thread() +{ + if (thread_unlock_callback) + thread_unlock_callback(); +} + +int MEM_check_memory_integrity() +{ + const char* err_val = NULL; + MemHead* listend; + /* check_memlist starts from the front, and runs until it finds + * the requested chunk. For this test, that's the last one. */ + listend = membase->last; + + err_val = check_memlist(listend); + + if (err_val == 0) return 0; + return 1; +} + + +void MEM_set_error_callback(void (*func)(char *)) +{ + error_callback = func; +} + +void MEM_set_lock_callback(void (*lock)(void), void (*unlock)(void)) +{ + thread_lock_callback = lock; + thread_unlock_callback = unlock; +} + +void MEM_set_memory_debug(void) +{ + malloc_debug_memset= 1; +} + +int MEM_allocN_len(void *vmemh) +{ + if (vmemh) { + MemHead *memh= vmemh; + + memh--; + return memh->len; + } else + return 0; +} + +void *MEM_dupallocN(void *vmemh) +{ + void *newp= NULL; + + if (vmemh) { + MemHead *memh= vmemh; + memh--; + + if(memh->mmap) + newp= MEM_mapallocN(memh->len, "dupli_mapalloc"); + else + newp= MEM_mallocN(memh->len, "dupli_alloc"); + + if (newp == NULL) return NULL; + + memcpy(newp, vmemh, memh->len); + } + + return newp; +} + +static void make_memhead_header(MemHead *memh, unsigned int len, const char *str) +{ + MemTail *memt; + + memh->tag1 = MEMTAG1; + memh->name = str; + memh->nextname = 0; + memh->len = len; + memh->mmap = 0; + memh->tag2 = MEMTAG2; + + memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len); + memt->tag3 = MEMTAG3; + + addtail(membase,&memh->next); + if (memh->next) memh->nextname = MEMNEXT(memh->next)->name; + + totblock++; + mem_in_use += len; +} + +void *MEM_mallocN(unsigned int len, const char *str) +{ + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + + memh= (MemHead *)malloc(len+sizeof(MemHead)+sizeof(MemTail)); + + if(memh) { + make_memhead_header(memh, len, str); + mem_unlock_thread(); + if(malloc_debug_memset && len) + memset(memh+1, 255, len); + return (++memh); + } + mem_unlock_thread(); + print_error("Malloc returns nill: len=%d in %s, total %u\n",len, str, mem_in_use); + return NULL; +} + +void *MEM_callocN(unsigned int len, const char *str) +{ + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + + memh= (MemHead *)calloc(len+sizeof(MemHead)+sizeof(MemTail),1); + + if(memh) { + make_memhead_header(memh, len, str); + mem_unlock_thread(); + return (++memh); + } + mem_unlock_thread(); + print_error("Calloc returns nill: len=%d in %s, total %u\n",len, str, mem_in_use); + return 0; +} + +/* note; mmap returns zero'd memory */ +void *MEM_mapallocN(unsigned int len, const char *str) +{ +#if defined(AMIGA) || defined(__BeOS) || defined(WIN32) + return MEM_callocN(len, str); +#else + MemHead *memh; + + mem_lock_thread(); + + len = (len + 3 ) & ~3; /* allocate in units of 4 */ + +#ifdef __sgi + { +#include + + int fd; + fd = open("/dev/zero", O_RDWR); + + memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail), + PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + } +#else + memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail), + PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0); +#endif + + if(memh!=(MemHead *)-1) { + make_memhead_header(memh, len, str); + memh->mmap= 1; + mmap_in_use += len; + mem_unlock_thread(); + return (++memh); + } + else { + mem_unlock_thread(); + print_error("Mapalloc returns nill, fallback to regular malloc: len=%d in %s, total %u\n",len, str, mmap_in_use); + return MEM_callocN(len, str); + } +#endif +} + + +void MEM_printmemlist() +{ + MemHead *membl; + + mem_lock_thread(); + + membl = membase->first; + if (membl) membl = MEMNEXT(membl); + while(membl) { + print_error("%s len: %d %p\n",membl->name,membl->len, membl+1); + if(membl->next) + membl= MEMNEXT(membl->next); + else break; + } + + mem_unlock_thread(); +} + +short MEM_freeN(void *vmemh) /* anders compileertie niet meer */ +{ + short error = 0; + MemTail *memt; + MemHead *memh= vmemh; + const char *name; + + if (memh == NULL){ + MemorY_ErroR("free","attempt to free NULL pointer"); + /* print_error(err_stream, "%d\n", (memh+4000)->tag1); */ + return(-1); + } + + if(sizeof(long)==8) { + if (((long) memh) & 0x7) { + MemorY_ErroR("free","attempt to free illegal pointer"); + return(-1); + } + } + else { + if (((long) memh) & 0x3) { + MemorY_ErroR("free","attempt to free illegal pointer"); + return(-1); + } + } + + memh--; + if(memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) { + MemorY_ErroR(memh->name,"double free"); + return(-1); + } + + mem_lock_thread(); + + if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) { + memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + memh->len); + if (memt->tag3 == MEMTAG3){ + + memh->tag1 = MEMFREE; + memh->tag2 = MEMFREE; + memt->tag3 = MEMFREE; + /* after tags !!! */ + rem_memblock(memh); + + mem_unlock_thread(); + + return(0); + } + error = 2; + MemorY_ErroR(memh->name,"end corrupt"); + name = check_memlist(memh); + if (name != 0){ + if (name != memh->name) MemorY_ErroR(name,"is also corrupt"); + } + } else{ + error = -1; + name = check_memlist(memh); + if (name == 0) MemorY_ErroR("free","pointer not in memlist"); + else MemorY_ErroR(name,"error in header"); + } + + totblock--; + /* here a DUMP should happen */ + + mem_unlock_thread(); + + return(error); +} + +/* --------------------------------------------------------------------- */ +/* local functions */ +/* --------------------------------------------------------------------- */ + +static void addtail(volatile localListBase *listbase, void *vlink) +{ + struct localLink *link= vlink; + + if (link == 0) return; + if (listbase == 0) return; + + link->next = 0; + link->prev = listbase->last; + + if (listbase->last) ((struct localLink *)listbase->last)->next = link; + if (listbase->first == 0) listbase->first = link; + listbase->last = link; +} + +static void remlink(volatile localListBase *listbase, void *vlink) +{ + struct localLink *link= vlink; + + if (link == 0) return; + if (listbase == 0) return; + + if (link->next) link->next->prev = link->prev; + if (link->prev) link->prev->next = link->next; + + if (listbase->last == link) listbase->last = link->prev; + if (listbase->first == link) listbase->first = link->next; +} + +static void rem_memblock(MemHead *memh) +{ + remlink(membase,&memh->next); + if (memh->prev) { + if (memh->next) + MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name; + else + MEMNEXT(memh->prev)->nextname = NULL; + } + + totblock--; + mem_in_use -= memh->len; + +#if defined(AMIGA) || defined(__BeOS) || defined(WIN32) + free(memh); +#else + + if(memh->mmap) { + mmap_in_use -= memh->len; + if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail))) + printf("Couldn't unmap memory %s\n", memh->name); + } + else { + if(malloc_debug_memset && memh->len) + memset(memh+1, 255, memh->len); + free(memh); + } +#endif +} + +static void MemorY_ErroR(const char *block, const char *error) +{ + print_error("Memoryblock %s: %s\n",block, error); +} + +static const char *check_memlist(MemHead *memh) +{ + MemHead *forw,*back,*forwok,*backok; + const char *name; + + forw = membase->first; + if (forw) forw = MEMNEXT(forw); + forwok = 0; + while(forw){ + if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break; + forwok = forw; + if (forw->next) forw = MEMNEXT(forw->next); + else forw = 0; + } + + back = (MemHead *) membase->last; + if (back) back = MEMNEXT(back); + backok = 0; + while(back){ + if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break; + backok = back; + if (back->prev) back = MEMNEXT(back->prev); + else back = 0; + } + + if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT"); + + if (forw == 0 && back == 0){ + /* geen foute headers gevonden dan maar op zoek naar memblock*/ + + forw = membase->first; + if (forw) forw = MEMNEXT(forw); + forwok = 0; + while(forw){ + if (forw == memh) break; + if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break; + forwok = forw; + if (forw->next) forw = MEMNEXT(forw->next); + else forw = 0; + } + if (forw == 0) return (0); + + back = (MemHead *) membase->last; + if (back) back = MEMNEXT(back); + backok = 0; + while(back){ + if (back == memh) break; + if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break; + backok = back; + if (back->prev) back = MEMNEXT(back->prev); + else back = 0; + } + } + + if (forwok) name = forwok->nextname; + else name = "No name found"; + + if (forw == memh){ + /* voor alle zekerheid wordt dit block maar uit de lijst gehaald */ + if (forwok){ + if (backok){ + forwok->next = (MemHead *)&backok->next; + backok->prev = (MemHead *)&forwok->next; + forwok->nextname = backok->name; + } else{ + forwok->next = 0; + membase->last = (struct localLink *) &forwok->next; +/* membase->last = (struct Link *) &forwok->next; */ + } + } else{ + if (backok){ + backok->prev = 0; + membase->first = &backok->next; + } else{ + membase->first = membase->last = 0; + } + } + } else{ + MemorY_ErroR(name,"Additional error in header"); + return("Additional error in header"); + } + + return(name); +} + +/* eof */ diff --git a/intern/guardedalloc/make/msvc_6_0/guardedalloc.dsp b/intern/guardedalloc/make/msvc_6_0/guardedalloc.dsp new file mode 100644 index 00000000000..21cc20e14f1 --- /dev/null +++ b/intern/guardedalloc/make/msvc_6_0/guardedalloc.dsp @@ -0,0 +1,114 @@ +# Microsoft Developer Studio Project File - Name="guardedalloc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=guardedalloc - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "guardedalloc.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "guardedalloc.mak" CFG="guardedalloc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "guardedalloc - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "guardedalloc - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "guardedalloc - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\guardedalloc\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\guardedalloc\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\.." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\guardedalloc\libguardedalloc.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\guardedalloc\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\guardedalloc\*.lib ..\..\..\..\..\lib\windows\guardedalloc\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "guardedalloc - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\guardedalloc\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\guardedalloc\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\.." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\guardedalloc\debug\libguardedalloc.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\guardedalloc\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\guardedalloc\debug\*.lib ..\..\..\..\..\lib\windows\guardedalloc\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "guardedalloc - Win32 Release" +# Name "guardedalloc - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\mallocn.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\MEM_guardedalloc.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/intern/guardedalloc/make/msvc_7_0/guardedalloc.sln b/intern/guardedalloc/make/msvc_7_0/guardedalloc.sln new file mode 100644 index 00000000000..b2557eee949 --- /dev/null +++ b/intern/guardedalloc/make/msvc_7_0/guardedalloc.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "guardedalloc", "guardedalloc.vcproj", "{1CC733F1-6AB5-4904-8F63-C08C46B79DD9}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {1CC733F1-6AB5-4904-8F63-C08C46B79DD9}.Debug.ActiveCfg = Debug|Win32 + {1CC733F1-6AB5-4904-8F63-C08C46B79DD9}.Debug.Build.0 = Debug|Win32 + {1CC733F1-6AB5-4904-8F63-C08C46B79DD9}.Release.ActiveCfg = Release|Win32 + {1CC733F1-6AB5-4904-8F63-C08C46B79DD9}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/guardedalloc/make/msvc_7_0/guardedalloc.vcproj b/intern/guardedalloc/make/msvc_7_0/guardedalloc.vcproj new file mode 100644 index 00000000000..cb3490716fa --- /dev/null +++ b/intern/guardedalloc/make/msvc_7_0/guardedalloc.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/guardedalloc/test/Makefile b/intern/guardedalloc/test/Makefile new file mode 100644 index 00000000000..760695bd19e --- /dev/null +++ b/intern/guardedalloc/test/Makefile @@ -0,0 +1,55 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Test the guarded memory module +# + +LIBNAME = guardedalloc +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = simpletest + +include nan_subdirs.mk + +include nan_compile.mk +include nan_link.mk + +TESTLIBS = $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)lib$(LIBNAME).a + +all debug:: + @echo "****> linking $@ in $(SOURCEDIR)" + $(CC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)memtest $(DIR)/memtest.o $(TESTLIBS) + +clean:: + $(RM) $(DIR)/memtest $(DIR)/debug/memtest + +test:: $(DIR)/memtest + $(DIR)/memtest $(NAN_TEST_VERBOSITY) + diff --git a/intern/guardedalloc/test/simpletest/Makefile b/intern/guardedalloc/test/simpletest/Makefile new file mode 100644 index 00000000000..8f1db9c4cac --- /dev/null +++ b/intern/guardedalloc/test/simpletest/Makefile @@ -0,0 +1,44 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# Test the guarded memory module +# + +LIBNAME = guardedalloc +DIR = $(OCGDIR)/intern/$(LIBNAME)/test + +# we don't want a library here, only object files: +ALLTARGETS = $(OBJS) + +include nan_compile.mk + +# this module's header +CPPFLAGS = -I../.. + diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c new file mode 100644 index 00000000000..c35af2d9ce2 --- /dev/null +++ b/intern/guardedalloc/test/simpletest/memtest.c @@ -0,0 +1,162 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * Simple test of memory. + */ + + + +/* Number of chunks to test with */ +#define NUM_BLOCKS 10 + +#include +#include +#include +#include "MEM_guardedalloc.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +int main (int argc, char *argv[]) +{ + int verbose = 0; + int error_status = 0; + int retval = 0; + int *ip; + + void *p[NUM_BLOCKS]; + int i = 0; + + /* ----------------------------------------------------------------- */ + switch (argc) { + case 2: + verbose = atoi(argv[1]); + if (verbose < 0) verbose = 0; + break; + case 1: + default: + verbose = 0; + } + if (verbose) { + fprintf(stderr,"\n*** Simple memory test\n|\n"); + } + + /* ----------------------------------------------------------------- */ + /* Round one, do a normal allocation, and free the blocks again. */ + /* ----------------------------------------------------------------- */ + /* flush mem lib output to stderr */ + MEM_set_error_callback(stderr); + + for (i = 0; i < NUM_BLOCKS; i++) { + int blocksize = 10000; + char tagstring[1000]; + if (verbose >1) printf("|--* Allocating block %d\n", i); + sprintf(tagstring,"Memblock no. %d : ", i); + p[i]= MEM_callocN(blocksize, strdup(tagstring)); + } + + /* report on that */ + if (verbose > 1) MEM_printmemlist(); + + /* memory is there: test it */ + error_status = MEM_check_memory_integrity(); + + if (verbose) { + if (error_status) { + fprintf(stderr, "|--* Memory test FAILED\n|\n"); + } else { + fprintf(stderr, "|--* Memory tested as good (as it should be)\n|\n"); + } + } + + for (i = 0; i < NUM_BLOCKS; i++) { + MEM_freeN(p[i]); + } + + /* ----------------------------------------------------------------- */ + /* Round two, do a normal allocation, and corrupt some blocks. */ + /* ----------------------------------------------------------------- */ + /* switch off, because it will complain about some things. */ + MEM_set_error_callback(NULL); + + for (i = 0; i < NUM_BLOCKS; i++) { + int blocksize = 10000; + char tagstring[1000]; + if (verbose >1) printf("|--* Allocating block %d\n", i); + sprintf(tagstring,"Memblock no. %d : ", i); + p[i]= MEM_callocN(blocksize, strdup(tagstring)); + } + + /* now corrupt a few blocks...*/ + ip = (int*) p[5] - 50 ; + for (i = 0; i< 1000; i++,ip++) *ip = i+1; + ip = (int*) p[6]; + *(ip+10005) = 0; + + retval = MEM_check_memory_integrity(); + + /* the test should have failed */ + error_status |= !retval; + if (verbose) { + if (retval) { + fprintf(stderr, "|--* Memory test failed (as it should be)\n"); + } else { + fprintf(stderr, "|--* Memory test FAILED to find corrupted blocks \n"); + } + } + + for (i = 0; i < NUM_BLOCKS; i++) { + MEM_freeN(p[i]); + } + + + if (verbose && error_status) { + fprintf(stderr,"|--* Memory was corrupted\n"); + } + /* ----------------------------------------------------------------- */ + if (verbose) { + if (error_status) { + fprintf(stderr,"|\n|--* Errors were detected\n"); + } else { + fprintf(stderr,"|\n|--* Test exited succesfully\n"); + } + + fprintf(stderr,"|\n*** Finished test\n\n"); + } + return error_status; +} + + diff --git a/intern/iksolver/CMakeLists.txt b/intern/iksolver/CMakeLists.txt new file mode 100644 index 00000000000..c0990c2a405 --- /dev/null +++ b/intern/iksolver/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC intern ../moto/include ../memutil) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB_NOLIST(blender_IK "${SRC}" "${INC}") +#, libtype=['blender'], priority = [10] ) diff --git a/intern/iksolver/Makefile b/intern/iksolver/Makefile new file mode 100644 index 00000000000..b439dcf8fa3 --- /dev/null +++ b/intern/iksolver/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver main makefile. +# + +include nan_definitions.mk + +LIBNAME = iksolver +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_IKSOLVER) ] || mkdir $(NAN_IKSOLVER) + @[ -d $(NAN_IKSOLVER)/include ] || mkdir $(NAN_IKSOLVER)/include + @[ -d $(NAN_IKSOLVER)/lib ] || mkdir $(NAN_IKSOLVER)/lib + @[ -d $(NAN_IKSOLVER)/lib/debug ] || mkdir $(NAN_IKSOLVER)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libiksolver.a $(NAN_IKSOLVER)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libiksolver.a $(NAN_IKSOLVER)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_IKSOLVER)/lib/libiksolver.a + ranlib $(NAN_IKSOLVER)/lib/debug/libiksolver.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_IKSOLVER)/include/ + diff --git a/intern/iksolver/SConscript b/intern/iksolver/SConscript new file mode 100644 index 00000000000..81bf61dfcd8 --- /dev/null +++ b/intern/iksolver/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = 'intern ../moto/include ../memutil' + +env.BlenderLib ('blender_IK', sources, Split(incs), [], libtype='blender', priority=10 ) diff --git a/intern/iksolver/extern/IK_solver.h b/intern/iksolver/extern/IK_solver.h new file mode 100644 index 00000000000..bf53a9e3724 --- /dev/null +++ b/intern/iksolver/extern/IK_solver.h @@ -0,0 +1,172 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * + * @author Laurence, Brecht + * @mainpage IK - Blender inverse kinematics module. + * + * @section about About the IK module + * + * This module allows you to create segments and form them into + * tree. You can then define a goal points that the end of a given + * segment should attempt to reach - an inverse kinematic problem. + * This module will then modify the segments in the tree in order + * to get the as near as possible to the goal. This solver uses an + * inverse jacobian method to find a solution. + * + * @section issues Known issues with this IK solver. + * + * - There is currently no support for joint constraints in the + * solver. This is within the realms of possibility - please ask + * if this functionality is required. + * - The solver is slow, inverse jacobian methods in general give + * 'smooth' solutions and the method is also very flexible, it + * does not rely on specific angle parameterization and can be + * extended to deal with different joint types and joint + * constraints. However it is not suitable for real time use. + * Other algorithms exist which are more suitable for real-time + * applications, please ask if this functionality is required. + * + * @section dependencies Dependencies + * + * This module only depends on Moto. + */ + +#ifndef NAN_INCLUDED_IK_solver_h +#define NAN_INCLUDED_IK_solver_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Typical order of calls for solving an IK problem: + * + * - create number of IK_Segment's and set their parents and transforms + * - create an IK_Solver + * - set a number of goals for the IK_Solver to solve + * - call IK_Solve + * - free the IK_Solver + * - get basis and translation changes from segments + * - free all segments + */ + +/** + * IK_Segment defines a single segment of an IK tree. + * - Individual segments are always defined in local coordinates. + * - The segment is assumed to be oriented in the local + * y-direction. + * - start is the start of the segment relative to the end + * of the parent segment. + * - rest_basis is a column major matrix defineding the rest + * position (w.r.t. which the limits are defined), must + * be a pure rotation + * - basis is a column major matrix defining the current change + * from the rest basis, must be a pure rotation + * - length is the length of the bone. + * + * - basis_change and translation_change respectively define + * the change in rotation or translation. basis_change is a + * column major 3x3 matrix. + * + * The local transformation is then defined as: + * start * rest_basis * basis * basis_change * translation_change * translate(0,length,0) + * + */ + +typedef void IK_Segment; + +enum IK_SegmentFlag { + IK_XDOF = 1, + IK_YDOF = 2, + IK_ZDOF = 4, + IK_TRANS_XDOF = 8, + IK_TRANS_YDOF = 16, + IK_TRANS_ZDOF = 32 +}; + +typedef enum IK_SegmentAxis { + IK_X = 0, + IK_Y = 1, + IK_Z = 2, + IK_TRANS_X = 3, + IK_TRANS_Y = 4, + IK_TRANS_Z = 5 +} IK_SegmentAxis; + +extern IK_Segment *IK_CreateSegment(int flag); +extern void IK_FreeSegment(IK_Segment *seg); + +extern void IK_SetParent(IK_Segment *seg, IK_Segment *parent); +extern void IK_SetTransform(IK_Segment *seg, float start[3], float rest_basis[][3], float basis[][3], float length); +extern void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lmin, float lmax); +extern void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness); + +extern void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3]); +extern void IK_GetTranslationChange(IK_Segment *seg, float *translation_change); + +/** + * An IK_Solver must be created to be able to execute the solver. + * + * An arbitray number of goals can be created, stating that a given + * end effector must have a given position or rotation. If multiple + * goals are specified, they can be weighted (range 0..1) to get + * some control over their importance. + * + * IK_Solve will execute the solver, that will run until either the + * system converges, or a maximum number of iterations is reached. + * It returns 1 if the system converged, 0 otherwise. + */ + +typedef void IK_Solver; + +IK_Solver *IK_CreateSolver(IK_Segment *root); +void IK_FreeSolver(IK_Solver *solver); + +void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight); +void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight); +void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle); +float IK_SolverGetPoleAngle(IK_Solver *solver); + +int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations); + + +#ifdef __cplusplus +} +#endif + +#endif // NAN_INCLUDED_IK_solver_h + diff --git a/intern/iksolver/intern/IK_QJacobian.cpp b/intern/iksolver/intern/IK_QJacobian.cpp new file mode 100644 index 00000000000..1dd4d086aa8 --- /dev/null +++ b/intern/iksolver/intern/IK_QJacobian.cpp @@ -0,0 +1,443 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "IK_QJacobian.h" +#include "TNT/svd.h" + +IK_QJacobian::IK_QJacobian() +: m_sdls(true), m_min_damp(1.0) +{ +} + +IK_QJacobian::~IK_QJacobian() +{ +} + +void IK_QJacobian::ArmMatrices(int dof, int task_size) +{ + m_dof = dof; + m_task_size = task_size; + + m_jacobian.newsize(task_size, dof); + m_jacobian = 0; + + m_alpha.newsize(dof); + m_alpha = 0; + + m_null.newsize(dof, dof); + + m_d_theta.newsize(dof); + m_d_theta_tmp.newsize(dof); + + m_norm.newsize(dof); + m_norm = 0.0; + + m_beta.newsize(task_size); + + m_weight.newsize(dof); + m_weight_sqrt.newsize(dof); + m_weight = 1.0; + m_weight_sqrt = 1.0; + + if (task_size >= dof) { + m_transpose = false; + + m_jacobian_tmp.newsize(task_size, dof); + + m_svd_u.newsize(task_size, dof); + m_svd_v.newsize(dof, dof); + m_svd_w.newsize(dof); + + m_work1.newsize(task_size); + m_work2.newsize(dof); + + m_svd_u_t.newsize(dof, task_size); + m_svd_u_beta.newsize(dof); + } + else { + // use the SVD of the transpose jacobian, it works just as well + // as the original, and often allows using smaller matrices. + m_transpose = true; + + m_jacobian_tmp.newsize(dof, task_size); + + m_svd_u.newsize(task_size, task_size); + m_svd_v.newsize(dof, task_size); + m_svd_w.newsize(task_size); + + m_work1.newsize(dof); + m_work2.newsize(task_size); + + m_svd_u_t.newsize(task_size, task_size); + m_svd_u_beta.newsize(task_size); + } +} + +void IK_QJacobian::SetBetas(int id, int, const MT_Vector3& v) +{ + m_beta[id] = v.x(); + m_beta[id+1] = v.y(); + m_beta[id+2] = v.z(); +} + +void IK_QJacobian::SetDerivatives(int id, int dof_id, const MT_Vector3& v) +{ + m_jacobian[id][dof_id] = v.x()*m_weight_sqrt[dof_id]; + m_jacobian[id+1][dof_id] = v.y()*m_weight_sqrt[dof_id]; + m_jacobian[id+2][dof_id] = v.z()*m_weight_sqrt[dof_id]; +} + +void IK_QJacobian::Invert() +{ + if (m_transpose) { + // SVD will decompose Jt into V*W*Ut with U,V orthogonal and W diagonal, + // so J = U*W*Vt and Jinv = V*Winv*Ut + TNT::transpose(m_jacobian, m_jacobian_tmp); + TNT::SVD(m_jacobian_tmp, m_svd_v, m_svd_w, m_svd_u, m_work1, m_work2); + } + else { + // SVD will decompose J into U*W*Vt with U,V orthogonal and W diagonal, + // so Jinv = V*Winv*Ut + m_jacobian_tmp = m_jacobian; + TNT::SVD(m_jacobian_tmp, m_svd_u, m_svd_w, m_svd_v, m_work1, m_work2); + } + + if (m_sdls) + InvertSDLS(); + else + InvertDLS(); +} + +bool IK_QJacobian::ComputeNullProjection() +{ + MT_Scalar epsilon = 1e-10; + + // compute null space projection based on V + int i, j, rank = 0; + for (i = 0; i < m_svd_w.size(); i++) + if (m_svd_w[i] > epsilon) + rank++; + + if (rank < m_task_size) + return false; + + TMatrix basis(m_svd_v.num_rows(), rank); + TMatrix basis_t(rank, m_svd_v.num_rows()); + int b = 0; + + for (i = 0; i < m_svd_w.size(); i++) + if (m_svd_w[i] > epsilon) { + for (j = 0; j < m_svd_v.num_rows(); j++) + basis[j][b] = m_svd_v[j][i]; + b++; + } + + TNT::transpose(basis, basis_t); + TNT::matmult(m_null, basis, basis_t); + + for (i = 0; i < m_null.num_rows(); i++) + for (j = 0; j < m_null.num_cols(); j++) + if (i == j) + m_null[i][j] = 1.0 - m_null[i][j]; + else + m_null[i][j] = -m_null[i][j]; + + return true; +} + +void IK_QJacobian::SubTask(IK_QJacobian& jacobian) +{ + if (!ComputeNullProjection()) + return; + + // restrict lower priority jacobian + jacobian.Restrict(m_d_theta, m_null); + + // add angle update from lower priority + jacobian.Invert(); + + // note: now damps secondary angles with minimum damping value from + // SDLS, to avoid shaking when the primary task is near singularities, + // doesn't work well at all + int i; + for (i = 0; i < m_d_theta.size(); i++) + m_d_theta[i] = m_d_theta[i] + /*m_min_damp**/jacobian.AngleUpdate(i); +} + +void IK_QJacobian::Restrict(TVector& d_theta, TMatrix& null) +{ + // subtract part already moved by higher task from beta + TVector beta_sub(m_beta.size()); + + TNT::matmult(beta_sub, m_jacobian, d_theta); + m_beta = m_beta - beta_sub; + + // note: should we be using the norm of the unrestricted jacobian for SDLS? + + // project jacobian on to null space of higher priority task + TMatrix jacobian_copy(m_jacobian); + TNT::matmult(m_jacobian, jacobian_copy, null); +} + +void IK_QJacobian::InvertSDLS() +{ + // Compute the dampeds least squeares pseudo inverse of J. + // + // Since J is usually not invertible (most of the times it's not even + // square), the psuedo inverse is used. This gives us a least squares + // solution. + // + // This is fine when the J*Jt is of full rank. When J*Jt is near to + // singular the least squares inverse tries to minimize |J(dtheta) - dX)| + // and doesn't try to minimize dTheta. This results in eratic changes in + // angle. The damped least squares minimizes |dtheta| to try and reduce this + // erratic behaviour. + // + // The selectively damped least squares (SDLS) is used here instead of the + // DLS. The SDLS damps individual singular values, instead of using a single + // damping term. + + MT_Scalar max_angle_change = MT_PI/4.0; + MT_Scalar epsilon = 1e-10; + int i, j; + + m_d_theta = 0; + m_min_damp = 1.0; + + for (i = 0; i < m_dof; i++) { + m_norm[i] = 0.0; + for (j = 0; j < m_task_size; j+=3) { + MT_Scalar n = 0.0; + n += m_jacobian[j][i]*m_jacobian[j][i]; + n += m_jacobian[j+1][i]*m_jacobian[j+1][i]; + n += m_jacobian[j+2][i]*m_jacobian[j+2][i]; + m_norm[i] += sqrt(n); + } + } + + for (i = 0; i max_dtheta) + max_dtheta = abs_dtheta; + } + + M *= wInv; + + // compute damping term and damp the dTheta's + MT_Scalar gamma = max_angle_change; + if (N < M) + gamma *= N/M; + + MT_Scalar damp = (gamma < max_dtheta)? gamma/max_dtheta: 1.0; + + for (j = 0; j < m_d_theta.size(); j++) { + // slight hack: we do 0.80*, so that if there is some oscillation, + // the system can still converge (for joint limits). also, it's + // better to go a little to slow than to far + + MT_Scalar dofdamp = damp/m_weight[j]; + if (dofdamp > 1.0) dofdamp = 1.0; + + m_d_theta[j] += 0.80*dofdamp*m_d_theta_tmp[j]; + } + + if (damp < m_min_damp) + m_min_damp = damp; + } + + // weight + prevent from doing angle updates with angles > max_angle_change + MT_Scalar max_angle = 0.0, abs_angle; + + for (j = 0; j max_angle) + max_angle = abs_angle; + } + + if (max_angle > max_angle_change) { + MT_Scalar damp = (max_angle_change)/(max_angle_change + max_angle); + + for (j = 0; j epsilon && m_svd_w[i] < w_min) + w_min = m_svd_w[i]; + } + + // compute lambda damping term + + MT_Scalar d = x_length/max_angle_change; + MT_Scalar lambda; + + if (w_min <= d/2) + lambda = d/2; + else if (w_min < d) + lambda = sqrt(w_min*(d - w_min)); + else + lambda = 0.0; + + lambda *= lambda; + + if (lambda > 10) + lambda = 10; + + // immediately multiply with Beta, so we can do matrix*vector products + // rather than matrix*matrix products + + // compute Ut*Beta + TNT::transpose(m_svd_u, m_svd_u_t); + TNT::matmult(m_svd_u_beta, m_svd_u_t, m_beta); + + m_d_theta = 0.0; + + for (i = 0; i < m_svd_w.size(); i++) { + if (m_svd_w[i] > epsilon) { + MT_Scalar wInv = m_svd_w[i]/(m_svd_w[i]*m_svd_w[i] + lambda); + + // compute V*Winv*Ut*Beta + m_svd_u_beta[i] *= wInv; + + for (j = 0; j mx) + mx = dtheta_abs; + } + + return mx; +} + +void IK_QJacobian::SetDoFWeight(int dof, MT_Scalar weight) +{ + m_weight[dof] = weight; + m_weight_sqrt[dof] = sqrt(weight); +} + diff --git a/intern/iksolver/intern/IK_QJacobian.h b/intern/iksolver/intern/IK_QJacobian.h new file mode 100644 index 00000000000..3e20e4a9fd0 --- /dev/null +++ b/intern/iksolver/intern/IK_QJacobian.h @@ -0,0 +1,118 @@ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_IK_QJacobian_h + +#define NAN_INCLUDED_IK_QJacobian_h + +#include "TNT/cmat.h" +#include +#include "MT_Vector3.h" + +class IK_QJacobian +{ +public: + typedef TNT::Matrix TMatrix; + typedef TNT::Vector TVector; + + IK_QJacobian(); + ~IK_QJacobian(); + + // Call once to initialize + void ArmMatrices(int dof, int task_size); + void SetDoFWeight(int dof, MT_Scalar weight); + + // Iteratively called + void SetBetas(int id, int size, const MT_Vector3& v); + void SetDerivatives(int id, int dof_id, const MT_Vector3& v); + + void Invert(); + + MT_Scalar AngleUpdate(int dof_id) const; + MT_Scalar AngleUpdateNorm() const; + + // DoF locking for inner clamping loop + void Lock(int dof_id, MT_Scalar delta); + + // Secondary task + bool ComputeNullProjection(); + + void Restrict(TVector& d_theta, TMatrix& null); + void SubTask(IK_QJacobian& jacobian); + +private: + + void InvertSDLS(); + void InvertDLS(); + + int m_dof, m_task_size; + bool m_transpose; + + // the jacobian matrix and it's null space projector + TMatrix m_jacobian, m_jacobian_tmp; + TMatrix m_null; + + /// the vector of intermediate betas + TVector m_beta; + + /// the vector of computed angle changes + TVector m_d_theta; + + /// space required for SVD computation + + TVector m_svd_w; + TMatrix m_svd_v; + TMatrix m_svd_u; + TVector m_work1; + TVector m_work2; + + TMatrix m_svd_u_t; + TVector m_svd_u_beta; + + // space required for SDLS + + bool m_sdls; + TVector m_norm; + TVector m_d_theta_tmp; + MT_Scalar m_min_damp; + + // null space task vector + TVector m_alpha; + + // dof weighting + TVector m_weight; + TVector m_weight_sqrt; +}; + +#endif + diff --git a/intern/iksolver/intern/IK_QJacobianSolver.cpp b/intern/iksolver/intern/IK_QJacobianSolver.cpp new file mode 100644 index 00000000000..17750a7195f --- /dev/null +++ b/intern/iksolver/intern/IK_QJacobianSolver.cpp @@ -0,0 +1,394 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include "IK_QJacobianSolver.h" +#include "MT_Quaternion.h" + +//#include "analyze.h" +IK_QJacobianSolver::IK_QJacobianSolver() +{ + m_poleconstraint = false; + m_getpoleangle = false; + m_rootmatrix.setIdentity(); +} + +MT_Scalar IK_QJacobianSolver::ComputeScale() +{ + std::vector::iterator seg; + float length = 0.0f; + + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) + length += (*seg)->MaxExtension(); + + if(length == 0.0f) + return 1.0f; + else + return 1.0f/length; +} + +void IK_QJacobianSolver::Scale(float scale, std::list& tasks) +{ + std::list::iterator task; + std::vector::iterator seg; + + for (task = tasks.begin(); task != tasks.end(); task++) + (*task)->Scale(scale); + + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) + (*seg)->Scale(scale); + + m_rootmatrix.getOrigin() *= scale; + m_goal *= scale; + m_polegoal *= scale; +} + +void IK_QJacobianSolver::AddSegmentList(IK_QSegment *seg) +{ + m_segments.push_back(seg); + + IK_QSegment *child; + for (child = seg->Child(); child; child = child->Sibling()) + AddSegmentList(child); +} + +bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list& tasks) +{ + m_segments.clear(); + AddSegmentList(root); + + // assign each segment a unique id for the jacobian + std::vector::iterator seg; + int num_dof = 0; + + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) { + (*seg)->SetDoFId(num_dof); + num_dof += (*seg)->NumberOfDoF(); + } + + if (num_dof == 0) + return false; + + // compute task id's and assing weights to task + int primary_size = 0, primary = 0; + int secondary_size = 0, secondary = 0; + MT_Scalar primary_weight = 0.0, secondary_weight = 0.0; + std::list::iterator task; + + for (task = tasks.begin(); task != tasks.end(); task++) { + IK_QTask *qtask = *task; + + if (qtask->Primary()) { + qtask->SetId(primary_size); + primary_size += qtask->Size(); + primary_weight += qtask->Weight(); + primary++; + } + else { + qtask->SetId(secondary_size); + secondary_size += qtask->Size(); + secondary_weight += qtask->Weight(); + secondary++; + } + } + + if (primary_size == 0 || MT_fuzzyZero(primary_weight)) + return false; + + m_secondary_enabled = (secondary > 0); + + // rescale weights of tasks to sum up to 1 + MT_Scalar primary_rescale = 1.0/primary_weight; + MT_Scalar secondary_rescale; + if (MT_fuzzyZero(secondary_weight)) + secondary_rescale = 0.0; + else + secondary_rescale = 1.0/secondary_weight; + + for (task = tasks.begin(); task != tasks.end(); task++) { + IK_QTask *qtask = *task; + + if (qtask->Primary()) + qtask->SetWeight(qtask->Weight()*primary_rescale); + else + qtask->SetWeight(qtask->Weight()*secondary_rescale); + } + + // set matrix sizes + m_jacobian.ArmMatrices(num_dof, primary_size); + if (secondary > 0) + m_jacobian_sub.ArmMatrices(num_dof, secondary_size); + + // set dof weights + int i; + + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) + for (i = 0; i < (*seg)->NumberOfDoF(); i++) + m_jacobian.SetDoFWeight((*seg)->DoFId()+i, (*seg)->Weight(i)); + + return true; +} + +void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal, MT_Vector3& polegoal, float poleangle, bool getangle) +{ + m_poleconstraint = true; + m_poletip = tip; + m_goal = goal; + m_polegoal = polegoal; + m_poleangle = (getangle)? 0.0f: poleangle; + m_getpoleangle = getangle; +} + +static MT_Scalar safe_acos(MT_Scalar f) +{ + // acos that does not return NaN with rounding errors + if (f <= -1.0f) return MT_PI; + else if (f >= 1.0f) return 0.0; + else return acos(f); +} + +static MT_Vector3 normalize(const MT_Vector3& v) +{ + // a sane normalize function that doesn't give (1, 0, 0) in case + // of a zero length vector, like MT_Vector3.normalize + MT_Scalar len = v.length(); + return MT_fuzzyZero(len)? MT_Vector3(0, 0, 0): v/len; +} + +static float angle(const MT_Vector3& v1, const MT_Vector3& v2) +{ + return safe_acos(v1.dot(v2)); +} + +void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list& tasks) +{ + // this function will be called before and after solving. calling it before + // solving gives predictable solutions by rotating towards the solution, + // and calling it afterwards ensures the solution is exact. + + if(!m_poleconstraint) + return; + + // disable pole vector constraint in case of multiple position tasks + std::list::iterator task; + int positiontasks = 0; + + for (task = tasks.begin(); task != tasks.end(); task++) + if((*task)->PositionTask()) + positiontasks++; + + if (positiontasks >= 2) { + m_poleconstraint = false; + return; + } + + // get positions and rotations + root->UpdateTransform(m_rootmatrix); + + const MT_Vector3 rootpos = root->GlobalStart(); + const MT_Vector3 endpos = m_poletip->GlobalEnd(); + const MT_Matrix3x3& rootbasis = root->GlobalTransform().getBasis(); + + // construct "lookat" matrices (like gluLookAt), based on a direction and + // an up vector, with the direction going from the root to the end effector + // and the up vector going from the root to the pole constraint position. + MT_Vector3 dir = normalize(endpos - rootpos); + MT_Vector3 rootx= rootbasis.getColumn(0); + MT_Vector3 rootz= rootbasis.getColumn(2); + MT_Vector3 up = rootx*cos(m_poleangle) + rootz*sin(m_poleangle); + + // in post, don't rotate towards the goal but only correct the pole up + MT_Vector3 poledir = (m_getpoleangle)? dir: normalize(m_goal - rootpos); + MT_Vector3 poleup = normalize(m_polegoal - rootpos); + + MT_Matrix3x3 mat, polemat; + + mat[0] = normalize(MT_cross(dir, up)); + mat[1] = MT_cross(mat[0], dir); + mat[2] = -dir; + + polemat[0] = normalize(MT_cross(poledir, poleup)); + polemat[1] = MT_cross(polemat[0], poledir); + polemat[2] = -poledir; + + if(m_getpoleangle) { + // we compute the pole angle that to rotate towards the target + m_poleangle = angle(mat[1], polemat[1]); + + if(rootz.dot(mat[1]*cos(m_poleangle) + mat[0]*sin(m_poleangle)) > 0.0f) + m_poleangle = -m_poleangle; + + // solve again, with the pole angle we just computed + m_getpoleangle = false; + ConstrainPoleVector(root, tasks); + } + else { + // now we set as root matrix the difference between the current and + // desired rotation based on the pole vector constraint. we use + // transpose instead of inverse because we have orthogonal matrices + // anyway, and in case of a singular matrix we don't get NaN's. + MT_Transform trans(MT_Point3(0, 0, 0), polemat.transposed()*mat); + m_rootmatrix = trans*m_rootmatrix; + } +} + +bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm) +{ + // assing each segment a unique id for the jacobian + std::vector::iterator seg; + IK_QSegment *qseg, *minseg = NULL; + MT_Scalar minabsdelta = 1e10, absdelta; + MT_Vector3 delta, mindelta; + bool locked = false, clamp[3]; + int i, mindof = 0; + + // here we check if any angle limits were violated. angles whose clamped + // position is the same as it was before, are locked immediate. of the + // other violation angles the most violating angle is rememberd + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) { + qseg = *seg; + if (qseg->UpdateAngle(m_jacobian, delta, clamp)) { + for (i = 0; i < qseg->NumberOfDoF(); i++) { + if (clamp[i] && !qseg->Locked(i)) { + absdelta = MT_abs(delta[i]); + + if (absdelta < MT_EPSILON) { + qseg->Lock(i, m_jacobian, delta); + locked = true; + } + else if (absdelta < minabsdelta) { + minabsdelta = absdelta; + mindelta = delta; + minseg = qseg; + mindof = i; + } + } + } + } + } + + // lock most violating angle + if (minseg) { + minseg->Lock(mindof, m_jacobian, mindelta); + locked = true; + + if (minabsdelta > norm) + norm = minabsdelta; + } + + if (locked == false) + // no locking done, last inner iteration, apply the angles + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) { + (*seg)->UnLock(); + (*seg)->UpdateAngleApply(); + } + + // signal if another inner iteration is needed + return locked; +} + +bool IK_QJacobianSolver::Solve( + IK_QSegment *root, + std::list tasks, + const MT_Scalar, + const int max_iterations +) +{ + float scale = ComputeScale(); + bool solved = false; + //double dt = analyze_time(); + + Scale(scale, tasks); + + ConstrainPoleVector(root, tasks); + + root->UpdateTransform(m_rootmatrix); + + // iterate + for (int iterations = 0; iterations < max_iterations; iterations++) { + // update transform + root->UpdateTransform(m_rootmatrix); + + std::list::iterator task; + + // compute jacobian + for (task = tasks.begin(); task != tasks.end(); task++) { + if ((*task)->Primary()) + (*task)->ComputeJacobian(m_jacobian); + else + (*task)->ComputeJacobian(m_jacobian_sub); + } + + MT_Scalar norm = 0.0; + + do { + // invert jacobian + try { + m_jacobian.Invert(); + if (m_secondary_enabled) + m_jacobian.SubTask(m_jacobian_sub); + } + catch (...) { + fprintf(stderr, "IK Exception\n"); + return false; + } + + // update angles and check limits + } while (UpdateAngles(norm)); + + // unlock segments again after locking in clamping loop + std::vector::iterator seg; + for (seg = m_segments.begin(); seg != m_segments.end(); seg++) + (*seg)->UnLock(); + + // compute angle update norm + MT_Scalar maxnorm = m_jacobian.AngleUpdateNorm(); + if (maxnorm > norm) + norm = maxnorm; + + // check for convergence + if (norm < 1e-3) { + solved = true; + break; + } + } + + if(m_poleconstraint) + root->PrependBasis(m_rootmatrix.getBasis()); + + Scale(1.0f/scale, tasks); + + //analyze_add_run(max_iterations, analyze_time()-dt); + + return solved; +} + diff --git a/intern/iksolver/intern/IK_QJacobianSolver.h b/intern/iksolver/intern/IK_QJacobianSolver.h new file mode 100644 index 00000000000..9ad46cd0aa6 --- /dev/null +++ b/intern/iksolver/intern/IK_QJacobianSolver.h @@ -0,0 +1,101 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_IK_QJacobianSolver_h + +#define NAN_INCLUDED_IK_QJacobianSolver_h + +/** + * @author Laurence Bourn + * @date 28/6/2001 + */ + +#include +#include + +#include "MT_Vector3.h" +#include "MT_Transform.h" +#include "IK_QJacobian.h" +#include "IK_QSegment.h" +#include "IK_QTask.h" + +class IK_QJacobianSolver +{ +public: + IK_QJacobianSolver(); + ~IK_QJacobianSolver() {}; + + // setup pole vector constraint + void SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal, + MT_Vector3& polegoal, float poleangle, bool getangle); + float GetPoleAngle() { return m_poleangle; }; + + // call setup once before solving, if it fails don't solve + bool Setup(IK_QSegment *root, std::list& tasks); + + // returns true if converged, false if max number of iterations was used + bool Solve( + IK_QSegment *root, + std::list tasks, + const MT_Scalar tolerance, + const int max_iterations + ); + +private: + void AddSegmentList(IK_QSegment *seg); + bool UpdateAngles(MT_Scalar& norm); + void ConstrainPoleVector(IK_QSegment *root, std::list& tasks); + + MT_Scalar ComputeScale(); + void Scale(float scale, std::list& tasks); + +private: + + IK_QJacobian m_jacobian; + IK_QJacobian m_jacobian_sub; + + bool m_secondary_enabled; + + std::vector m_segments; + + MT_Transform m_rootmatrix; + + bool m_poleconstraint; + bool m_getpoleangle; + MT_Vector3 m_goal; + MT_Vector3 m_polegoal; + float m_poleangle; + IK_QSegment *m_poletip; +}; + +#endif + diff --git a/intern/iksolver/intern/IK_QSegment.cpp b/intern/iksolver/intern/IK_QSegment.cpp new file mode 100644 index 00000000000..a5217ed91d6 --- /dev/null +++ b/intern/iksolver/intern/IK_QSegment.cpp @@ -0,0 +1,1052 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "IK_QSegment.h" + +// Utility functions + +static MT_Matrix3x3 RotationMatrix(MT_Scalar sine, MT_Scalar cosine, int axis) +{ + if (axis == 0) + return MT_Matrix3x3(1.0, 0.0, 0.0, + 0.0, cosine, -sine, + 0.0, sine, cosine); + else if (axis == 1) + return MT_Matrix3x3(cosine, 0.0, sine, + 0.0, 1.0, 0.0, + -sine, 0.0, cosine); + else + return MT_Matrix3x3(cosine, -sine, 0.0, + sine, cosine, 0.0, + 0.0, 0.0, 1.0); +} + +static MT_Matrix3x3 RotationMatrix(MT_Scalar angle, int axis) +{ + return RotationMatrix(sin(angle), cos(angle), axis); +} + + +static MT_Scalar EulerAngleFromMatrix(const MT_Matrix3x3& R, int axis) +{ + MT_Scalar t = sqrt(R[0][0]*R[0][0] + R[0][1]*R[0][1]); + + if (t > 16.0*MT_EPSILON) { + if (axis == 0) return atan2(R[1][2], R[2][2]); + else if(axis == 1) return atan2(-R[0][2], t); + else return atan2(R[0][1], R[0][0]); + } else { + if (axis == 0) return atan2(-R[2][1], R[1][1]); + else if(axis == 1) return atan2(-R[0][2], t); + else return 0.0f; + } +} + +static MT_Scalar safe_acos(MT_Scalar f) +{ + if (f <= -1.0f) + return MT_PI; + else if (f >= 1.0f) + return 0.0; + else + return acos(f); +} + +static MT_Scalar ComputeTwist(const MT_Matrix3x3& R) +{ + // qy and qw are the y and w components of the quaternion from R + MT_Scalar qy = R[0][2] - R[2][0]; + MT_Scalar qw = R[0][0] + R[1][1] + R[2][2] + 1; + + MT_Scalar tau = 2*atan2(qy, qw); + + return tau; +} + +static MT_Matrix3x3 ComputeTwistMatrix(MT_Scalar tau) +{ + return RotationMatrix(tau, 1); +} + +static void RemoveTwist(MT_Matrix3x3& R) +{ + // compute twist parameter + MT_Scalar tau = ComputeTwist(R); + + // compute twist matrix + MT_Matrix3x3 T = ComputeTwistMatrix(tau); + + // remove twist + R = R*T.transposed(); +} + +static MT_Vector3 SphericalRangeParameters(const MT_Matrix3x3& R) +{ + // compute twist parameter + MT_Scalar tau = ComputeTwist(R); + + // compute swing parameters + MT_Scalar num = 2.0*(1.0 + R[1][1]); + + // singularity at pi + if (MT_abs(num) < MT_EPSILON) + // TODO: this does now rotation of size pi over z axis, but could + // be any axis, how to deal with this i'm not sure, maybe don't + // enforce limits at all then + return MT_Vector3(0.0, tau, 1.0); + + num = 1.0/sqrt(num); + MT_Scalar ax = -R[2][1]*num; + MT_Scalar az = R[0][1]*num; + + return MT_Vector3(ax, tau, az); +} + +static MT_Matrix3x3 ComputeSwingMatrix(MT_Scalar ax, MT_Scalar az) +{ + // length of (ax, 0, az) = sin(theta/2) + MT_Scalar sine2 = ax*ax + az*az; + MT_Scalar cosine2 = sqrt((sine2 >= 1.0)? 0.0: 1.0-sine2); + + // compute swing matrix + MT_Matrix3x3 S(MT_Quaternion(ax, 0.0, az, -cosine2)); + + return S; +} + +static MT_Vector3 MatrixToAxisAngle(const MT_Matrix3x3& R) +{ + MT_Vector3 delta = MT_Vector3(R[2][1] - R[1][2], + R[0][2] - R[2][0], + R[1][0] - R[0][1]); + + MT_Scalar c = safe_acos((R[0][0] + R[1][1] + R[2][2] - 1)/2); + MT_Scalar l = delta.length(); + + if (!MT_fuzzyZero(l)) + delta *= c/l; + + return delta; +} + +static bool EllipseClamp(MT_Scalar& ax, MT_Scalar& az, MT_Scalar *amin, MT_Scalar *amax) +{ + MT_Scalar xlim, zlim, x, z; + + if (ax < 0.0) { + x = -ax; + xlim = -amin[0]; + } + else { + x = ax; + xlim = amax[0]; + } + + if (az < 0.0) { + z = -az; + zlim = -amin[1]; + } + else { + z = az; + zlim = amax[1]; + } + + if (MT_fuzzyZero(xlim) || MT_fuzzyZero(zlim)) { + if (x <= xlim && z <= zlim) + return false; + + if (x > xlim) + x = xlim; + if (z > zlim) + z = zlim; + } + else { + MT_Scalar invx = 1.0/(xlim*xlim); + MT_Scalar invz = 1.0/(zlim*zlim); + + if ((x*x*invx + z*z*invz) <= 1.0) + return false; + + if (MT_fuzzyZero(x)) { + x = 0.0; + z = zlim; + } + else { + MT_Scalar rico = z/x; + MT_Scalar old_x = x; + x = sqrt(1.0/(invx + invz*rico*rico)); + if (old_x < 0.0) + x = -x; + z = rico*x; + } + } + + ax = (ax < 0.0)? -x: x; + az = (az < 0.0)? -z: z; + + return true; +} + +// IK_QSegment + +IK_QSegment::IK_QSegment(int num_DoF, bool translational) +: m_parent(NULL), m_child(NULL), m_sibling(NULL), m_composite(NULL), + m_num_DoF(num_DoF), m_translational(translational) +{ + m_locked[0] = m_locked[1] = m_locked[2] = false; + m_weight[0] = m_weight[1] = m_weight[2] = 1.0; + + m_max_extension = 0.0; + + m_start = MT_Vector3(0, 0, 0); + m_rest_basis.setIdentity(); + m_basis.setIdentity(); + m_translation = MT_Vector3(0, 0, 0); + + m_orig_basis = m_basis; + m_orig_translation = m_translation; +} + +void IK_QSegment::Reset() +{ + m_locked[0] = m_locked[1] = m_locked[2] = false; + + m_basis = m_orig_basis; + m_translation = m_orig_translation; + SetBasis(m_basis); + + for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling) + seg->Reset(); +} + +void IK_QSegment::SetTransform( + const MT_Vector3& start, + const MT_Matrix3x3& rest_basis, + const MT_Matrix3x3& basis, + const MT_Scalar length +) +{ + m_max_extension = start.length() + length; + + m_start = start; + m_rest_basis = rest_basis; + + m_orig_basis = basis; + SetBasis(basis); + + m_translation = MT_Vector3(0, length, 0); + m_orig_translation = m_translation; +} + +MT_Matrix3x3 IK_QSegment::BasisChange() const +{ + return m_orig_basis.transposed()*m_basis; +} + +MT_Vector3 IK_QSegment::TranslationChange() const +{ + return m_translation - m_orig_translation; +} + +IK_QSegment::~IK_QSegment() +{ + if (m_parent) + m_parent->RemoveChild(this); + + for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling) + seg->m_parent = NULL; +} + +void IK_QSegment::SetParent(IK_QSegment *parent) +{ + if (m_parent == parent) + return; + + if (m_parent) + m_parent->RemoveChild(this); + + if (parent) { + m_sibling = parent->m_child; + parent->m_child = this; + } + + m_parent = parent; +} + +void IK_QSegment::SetComposite(IK_QSegment *seg) +{ + m_composite = seg; +} + +void IK_QSegment::RemoveChild(IK_QSegment *child) +{ + if (m_child == NULL) + return; + else if (m_child == child) + m_child = m_child->m_sibling; + else { + IK_QSegment *seg = m_child; + + while (seg->m_sibling != child); + seg = seg->m_sibling; + + if (child == seg->m_sibling) + seg->m_sibling = child->m_sibling; + } +} + +void IK_QSegment::UpdateTransform(const MT_Transform& global) +{ + // compute the global transform at the end of the segment + m_global_start = global.getOrigin() + global.getBasis()*m_start; + + m_global_transform.setOrigin(m_global_start); + m_global_transform.setBasis(global.getBasis() * m_rest_basis * m_basis); + m_global_transform.translate(m_translation); + + // update child transforms + for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling) + seg->UpdateTransform(m_global_transform); +} + +void IK_QSegment::PrependBasis(const MT_Matrix3x3& mat) +{ + m_basis = m_rest_basis.inverse() * mat * m_rest_basis * m_basis; +} + +void IK_QSegment::Scale(float scale) +{ + m_start *= scale; + m_translation *= scale; + m_orig_translation *= scale; + m_global_start *= scale; + m_global_transform.getOrigin() *= scale; + m_max_extension *= scale; +} + +// IK_QSphericalSegment + +IK_QSphericalSegment::IK_QSphericalSegment() +: IK_QSegment(3, false), m_limit_x(false), m_limit_y(false), m_limit_z(false) +{ +} + +MT_Vector3 IK_QSphericalSegment::Axis(int dof) const +{ + return m_global_transform.getBasis().getColumn(dof); +} + +void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmin >= lmax) + return; + + if (axis == 1) { + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + m_min_y = MT_radians(lmin); + m_max_y = MT_radians(lmax); + + m_limit_y = true; + } + else { + // clamp and convert to axis angle parameters + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + lmin = sin(MT_radians(lmin)*0.5); + lmax = sin(MT_radians(lmax)*0.5); + + if (axis == 0) { + m_min[0] = -lmax; + m_max[0] = -lmin; + m_limit_x = true; + } + else if (axis == 2) { + m_min[1] = -lmax; + m_max[1] = -lmin; + m_limit_z = true; + } + } +} + +void IK_QSphericalSegment::SetWeight(int axis, MT_Scalar weight) +{ + m_weight[axis] = weight; +} + +bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + if (m_locked[0] && m_locked[1] && m_locked[2]) + return false; + + MT_Vector3 dq; + dq.x() = jacobian.AngleUpdate(m_DoF_id); + dq.y() = jacobian.AngleUpdate(m_DoF_id+1); + dq.z() = jacobian.AngleUpdate(m_DoF_id+2); + + // Directly update the rotation matrix, with Rodrigues' rotation formula, + // to avoid singularities and allow smooth integration. + + MT_Scalar theta = dq.length(); + + if (!MT_fuzzyZero(theta)) { + MT_Vector3 w = dq*(1.0/theta); + + MT_Scalar sine = sin(theta); + MT_Scalar cosine = cos(theta); + MT_Scalar cosineInv = 1-cosine; + + MT_Scalar xsine = w.x()*sine; + MT_Scalar ysine = w.y()*sine; + MT_Scalar zsine = w.z()*sine; + + MT_Scalar xxcosine = w.x()*w.x()*cosineInv; + MT_Scalar xycosine = w.x()*w.y()*cosineInv; + MT_Scalar xzcosine = w.x()*w.z()*cosineInv; + MT_Scalar yycosine = w.y()*w.y()*cosineInv; + MT_Scalar yzcosine = w.y()*w.z()*cosineInv; + MT_Scalar zzcosine = w.z()*w.z()*cosineInv; + + MT_Matrix3x3 M( + cosine + xxcosine, -zsine + xycosine, ysine + xzcosine, + zsine + xycosine, cosine + yycosine, -xsine + yzcosine, + -ysine + xzcosine, xsine + yzcosine, cosine + zzcosine); + + m_new_basis = m_basis*M; + } + else + m_new_basis = m_basis; + + + if (m_limit_y == false && m_limit_x == false && m_limit_z == false) + return false; + + MT_Vector3 a = SphericalRangeParameters(m_new_basis); + + if (m_locked[0]) + a.x() = m_locked_ax; + if (m_locked[1]) + a.y() = m_locked_ay; + if (m_locked[2]) + a.z() = m_locked_az; + + MT_Scalar ax = a.x(), ay = a.y(), az = a.z(); + + clamp[0] = clamp[1] = clamp[2] = false; + + if (m_limit_y) { + if (a.y() > m_max_y) { + ay = m_max_y; + clamp[1] = true; + } + else if (a.y() < m_min_y) { + ay = m_min_y; + clamp[1] = true; + } + } + + if (m_limit_x && m_limit_z) { + if (EllipseClamp(ax, az, m_min, m_max)) + clamp[0] = clamp[2] = true; + } + else if (m_limit_x) { + if (ax < m_min[0]) { + ax = m_min[0]; + clamp[0] = true; + } + else if (ax > m_max[0]) { + ax = m_max[0]; + clamp[0] = true; + } + } + else if (m_limit_z) { + if (az < m_min[1]) { + az = m_min[1]; + clamp[2] = true; + } + else if (az > m_max[1]) { + az = m_max[1]; + clamp[2] = true; + } + } + + if (clamp[0] == false && clamp[1] == false && clamp[2] == false) { + if (m_locked[0] || m_locked[1] || m_locked[2]) + m_new_basis = ComputeSwingMatrix(ax, az)*ComputeTwistMatrix(ay); + return false; + } + + m_new_basis = ComputeSwingMatrix(ax, az)*ComputeTwistMatrix(ay); + + delta = MatrixToAxisAngle(m_basis.transposed()*m_new_basis); + + if (!(m_locked[0] || m_locked[2]) && (clamp[0] || clamp[2])) { + m_locked_ax = ax; + m_locked_az = az; + } + + if (!m_locked[1] && clamp[1]) + m_locked_ay = ay; + + return true; +} + +void IK_QSphericalSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + if (dof == 1) { + m_locked[1] = true; + jacobian.Lock(m_DoF_id+1, delta[1]); + } + else { + m_locked[0] = m_locked[2] = true; + jacobian.Lock(m_DoF_id, delta[0]); + jacobian.Lock(m_DoF_id+2, delta[2]); + } +} + +void IK_QSphericalSegment::UpdateAngleApply() +{ + m_basis = m_new_basis; +} + +// IK_QNullSegment + +IK_QNullSegment::IK_QNullSegment() +: IK_QSegment(0, false) +{ +} + +// IK_QRevoluteSegment + +IK_QRevoluteSegment::IK_QRevoluteSegment(int axis) +: IK_QSegment(1, false), m_axis(axis), m_angle(0.0), m_limit(false) +{ +} + +void IK_QRevoluteSegment::SetBasis(const MT_Matrix3x3& basis) +{ + if (m_axis == 1) { + m_angle = ComputeTwist(basis); + m_basis = ComputeTwistMatrix(m_angle); + } + else { + m_angle = EulerAngleFromMatrix(basis, m_axis); + m_basis = RotationMatrix(m_angle, m_axis); + } +} + +MT_Vector3 IK_QRevoluteSegment::Axis(int) const +{ + return m_global_transform.getBasis().getColumn(m_axis); +} + +bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + if (m_locked[0]) + return false; + + m_new_angle = m_angle + jacobian.AngleUpdate(m_DoF_id); + + clamp[0] = false; + + if (m_limit == false) + return false; + + if (m_new_angle > m_max) + delta[0] = m_max - m_angle; + else if (m_new_angle < m_min) + delta[0] = m_min - m_angle; + else + return false; + + clamp[0] = true; + m_new_angle = m_angle + delta[0]; + + return true; +} + +void IK_QRevoluteSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + m_locked[0] = true; + jacobian.Lock(m_DoF_id, delta[0]); +} + +void IK_QRevoluteSegment::UpdateAngleApply() +{ + m_angle = m_new_angle; + m_basis = RotationMatrix(m_angle, m_axis); +} + +void IK_QRevoluteSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmin >= lmax || m_axis != axis) + return; + + // clamp and convert to axis angle parameters + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + m_min = MT_radians(lmin); + m_max = MT_radians(lmax); + + m_limit = true; +} + +void IK_QRevoluteSegment::SetWeight(int axis, MT_Scalar weight) +{ + if (axis == m_axis) + m_weight[0] = weight; +} + +// IK_QSwingSegment + +IK_QSwingSegment::IK_QSwingSegment() +: IK_QSegment(2, false), m_limit_x(false), m_limit_z(false) +{ +} + +void IK_QSwingSegment::SetBasis(const MT_Matrix3x3& basis) +{ + m_basis = basis; + RemoveTwist(m_basis); +} + +MT_Vector3 IK_QSwingSegment::Axis(int dof) const +{ + return m_global_transform.getBasis().getColumn((dof==0)? 0: 2); +} + +bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + if (m_locked[0] && m_locked[1]) + return false; + + MT_Vector3 dq; + dq.x() = jacobian.AngleUpdate(m_DoF_id); + dq.y() = 0.0; + dq.z() = jacobian.AngleUpdate(m_DoF_id+1); + + // Directly update the rotation matrix, with Rodrigues' rotation formula, + // to avoid singularities and allow smooth integration. + + MT_Scalar theta = dq.length(); + + if (!MT_fuzzyZero(theta)) { + MT_Vector3 w = dq*(1.0/theta); + + MT_Scalar sine = sin(theta); + MT_Scalar cosine = cos(theta); + MT_Scalar cosineInv = 1-cosine; + + MT_Scalar xsine = w.x()*sine; + MT_Scalar zsine = w.z()*sine; + + MT_Scalar xxcosine = w.x()*w.x()*cosineInv; + MT_Scalar xzcosine = w.x()*w.z()*cosineInv; + MT_Scalar zzcosine = w.z()*w.z()*cosineInv; + + MT_Matrix3x3 M( + cosine + xxcosine, -zsine, xzcosine, + zsine, cosine, -xsine, + xzcosine, xsine, cosine + zzcosine); + + m_new_basis = m_basis*M; + + RemoveTwist(m_new_basis); + } + else + m_new_basis = m_basis; + + if (m_limit_x == false && m_limit_z == false) + return false; + + MT_Vector3 a = SphericalRangeParameters(m_new_basis); + MT_Scalar ax = 0, az = 0; + + clamp[0] = clamp[1] = false; + + if (m_limit_x && m_limit_z) { + ax = a.x(); + az = a.z(); + + if (EllipseClamp(ax, az, m_min, m_max)) + clamp[0] = clamp[1] = true; + } + else if (m_limit_x) { + if (ax < m_min[0]) { + ax = m_min[0]; + clamp[0] = true; + } + else if (ax > m_max[0]) { + ax = m_max[0]; + clamp[0] = true; + } + } + else if (m_limit_z) { + if (az < m_min[1]) { + az = m_min[1]; + clamp[1] = true; + } + else if (az > m_max[1]) { + az = m_max[1]; + clamp[1] = true; + } + } + + if (clamp[0] == false && clamp[1] == false) + return false; + + m_new_basis = ComputeSwingMatrix(ax, az); + + delta = MatrixToAxisAngle(m_basis.transposed()*m_new_basis); + delta[1] = delta[2]; delta[2] = 0.0; + + return true; +} + +void IK_QSwingSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + m_locked[0] = m_locked[1] = true; + jacobian.Lock(m_DoF_id, delta[0]); + jacobian.Lock(m_DoF_id+1, delta[1]); +} + +void IK_QSwingSegment::UpdateAngleApply() +{ + m_basis = m_new_basis; +} + +void IK_QSwingSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmin >= lmax) + return; + + // clamp and convert to axis angle parameters + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + lmin = sin(MT_radians(lmin)*0.5); + lmax = sin(MT_radians(lmax)*0.5); + + // put center of ellispe in the middle between min and max + MT_Scalar offset = 0.5*(lmin + lmax); + //lmax = lmax - offset; + + if (axis == 0) { + m_min[0] = -lmax; + m_max[0] = -lmin; + + m_limit_x = true; + m_offset_x = offset; + m_max_x = lmax; + } + else if (axis == 2) { + m_min[1] = -lmax; + m_max[1] = -lmin; + + m_limit_z = true; + m_offset_z = offset; + m_max_z = lmax; + } +} + +void IK_QSwingSegment::SetWeight(int axis, MT_Scalar weight) +{ + if (axis == 0) + m_weight[0] = weight; + else if (axis == 2) + m_weight[1] = weight; +} + +// IK_QElbowSegment + +IK_QElbowSegment::IK_QElbowSegment(int axis) +: IK_QSegment(2, false), m_axis(axis), m_twist(0.0), m_angle(0.0), + m_cos_twist(1.0), m_sin_twist(0.0), m_limit(false), m_limit_twist(false) +{ +} + +void IK_QElbowSegment::SetBasis(const MT_Matrix3x3& basis) +{ + m_basis = basis; + + m_twist = ComputeTwist(m_basis); + RemoveTwist(m_basis); + m_angle = EulerAngleFromMatrix(basis, m_axis); + + m_basis = RotationMatrix(m_angle, m_axis)*ComputeTwistMatrix(m_twist); +} + +MT_Vector3 IK_QElbowSegment::Axis(int dof) const +{ + if (dof == 0) { + MT_Vector3 v; + if (m_axis == 0) + v = MT_Vector3(m_cos_twist, 0, m_sin_twist); + else + v = MT_Vector3(-m_sin_twist, 0, m_cos_twist); + + return m_global_transform.getBasis() * v; + } + else + return m_global_transform.getBasis().getColumn(1); +} + +bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + if (m_locked[0] && m_locked[1]) + return false; + + clamp[0] = clamp[1] = false; + + if (!m_locked[0]) { + m_new_angle = m_angle + jacobian.AngleUpdate(m_DoF_id); + + if (m_limit) { + if (m_new_angle > m_max) { + delta[0] = m_max - m_angle; + m_new_angle = m_max; + clamp[0] = true; + } + else if (m_new_angle < m_min) { + delta[0] = m_min - m_angle; + m_new_angle = m_min; + clamp[0] = true; + } + } + } + + if (!m_locked[1]) { + m_new_twist = m_twist + jacobian.AngleUpdate(m_DoF_id+1); + + if (m_limit_twist) { + if (m_new_twist > m_max_twist) { + delta[1] = m_max_twist - m_twist; + m_new_twist = m_max_twist; + clamp[1] = true; + } + else if (m_new_twist < m_min_twist) { + delta[1] = m_min_twist - m_twist; + m_new_twist = m_min_twist; + clamp[1] = true; + } + } + } + + return (clamp[0] || clamp[1]); +} + +void IK_QElbowSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + if (dof == 0) { + m_locked[0] = true; + jacobian.Lock(m_DoF_id, delta[0]); + } + else { + m_locked[1] = true; + jacobian.Lock(m_DoF_id+1, delta[1]); + } +} + +void IK_QElbowSegment::UpdateAngleApply() +{ + m_angle = m_new_angle; + m_twist = m_new_twist; + + m_sin_twist = sin(m_twist); + m_cos_twist = cos(m_twist); + + MT_Matrix3x3 A = RotationMatrix(m_angle, m_axis); + MT_Matrix3x3 T = RotationMatrix(m_sin_twist, m_cos_twist, 1); + + m_basis = A*T; +} + +void IK_QElbowSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmin >= lmax) + return; + + // clamp and convert to axis angle parameters + lmin = MT_clamp(lmin, -180, 180); + lmax = MT_clamp(lmax, -180, 180); + + lmin = MT_radians(lmin); + lmax = MT_radians(lmax); + + if (axis == 1) { + m_min_twist = lmin; + m_max_twist = lmax; + m_limit_twist = true; + } + else if (axis == m_axis) { + m_min = lmin; + m_max = lmax; + m_limit = true; + } +} + +void IK_QElbowSegment::SetWeight(int axis, MT_Scalar weight) +{ + if (axis == m_axis) + m_weight[0] = weight; + else if (axis == 1) + m_weight[1] = weight; +} + +// IK_QTranslateSegment + +IK_QTranslateSegment::IK_QTranslateSegment(int axis1) +: IK_QSegment(1, true) +{ + m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = false; + m_axis_enabled[axis1] = true; + + m_axis[0] = axis1; + + m_limit[0] = m_limit[1] = m_limit[2] = false; +} + +IK_QTranslateSegment::IK_QTranslateSegment(int axis1, int axis2) +: IK_QSegment(2, true) +{ + m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = false; + m_axis_enabled[axis1] = true; + m_axis_enabled[axis2] = true; + + m_axis[0] = axis1; + m_axis[1] = axis2; + + m_limit[0] = m_limit[1] = m_limit[2] = false; +} + +IK_QTranslateSegment::IK_QTranslateSegment() +: IK_QSegment(3, true) +{ + m_axis_enabled[0] = m_axis_enabled[1] = m_axis_enabled[2] = true; + + m_axis[0] = 0; + m_axis[1] = 1; + m_axis[2] = 2; + + m_limit[0] = m_limit[1] = m_limit[2] = false; +} + +MT_Vector3 IK_QTranslateSegment::Axis(int dof) const +{ + return m_global_transform.getBasis().getColumn(m_axis[dof]); +} + +bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +{ + int dof_id = m_DoF_id, dof = 0, i, clamped = false; + + MT_Vector3 dx(0.0, 0.0, 0.0); + + for (i = 0; i < 3; i++) { + if (!m_axis_enabled[i]) { + m_new_translation[i] = m_translation[i]; + continue; + } + + clamp[dof] = false; + + if (!m_locked[dof]) { + m_new_translation[i] = m_translation[i] + jacobian.AngleUpdate(dof_id); + + if (m_limit[i]) { + if (m_new_translation[i] > m_max[i]) { + delta[dof] = m_max[i] - m_translation[i]; + m_new_translation[i] = m_max[i]; + clamped = clamp[dof] = true; + } + else if (m_new_translation[i] < m_min[i]) { + delta[dof] = m_min[i] - m_translation[i]; + m_new_translation[i] = m_min[i]; + clamped = clamp[dof] = true; + } + } + } + + dof_id++; + dof++; + } + + return clamped; +} + +void IK_QTranslateSegment::UpdateAngleApply() +{ + m_translation = m_new_translation; +} + +void IK_QTranslateSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +{ + m_locked[dof] = true; + jacobian.Lock(m_DoF_id+dof, delta[dof]); +} + +void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight) +{ + int i; + + for (i = 0; i < m_num_DoF; i++) + if (m_axis[i] == axis) + m_weight[i] = weight; +} + +void IK_QTranslateSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +{ + if (lmax < lmin) + return; + + m_min[axis]= lmin; + m_max[axis]= lmax; + m_limit[axis]= true; +} + +void IK_QTranslateSegment::Scale(float scale) +{ + int i; + + IK_QSegment::Scale(scale); + + for (i = 0; i < 3; i++) { + m_min[0] *= scale; + m_max[1] *= scale; + } + + m_new_translation *= scale; +} + diff --git a/intern/iksolver/intern/IK_QSegment.h b/intern/iksolver/intern/IK_QSegment.h new file mode 100644 index 00000000000..3c5df463468 --- /dev/null +++ b/intern/iksolver/intern/IK_QSegment.h @@ -0,0 +1,351 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_IK_QSegment_h +#define NAN_INCLUDED_IK_QSegment_h + +#include "MT_Vector3.h" +#include "MT_Transform.h" +#include "MT_Matrix4x4.h" +#include "IK_QJacobian.h" +#include "MEM_SmartPtr.h" + +#include + +/** + * An IK_Qsegment encodes information about a segments + * local coordinate system. + * + * These segments always point along the y-axis. + * + * Here we define the local coordinates of a joint as + * local_transform = + * translate(tr1) * rotation(A) * rotation(q) * translate(0,length,0) + * We use the standard moto column ordered matrices. You can read + * this as: + * - first translate by (0,length,0) + * - multiply by the rotation matrix derived from the current + * angle parameterization q. + * - multiply by the user defined matrix representing the rest + * position of the bone. + * - translate by the used defined translation (tr1) + * The ordering of these transformations is vital, you must + * use exactly the same transformations when displaying the segments + */ + +class IK_QSegment +{ +public: + virtual ~IK_QSegment(); + + // start: a user defined translation + // rest_basis: a user defined rotation + // basis: a user defined rotation + // length: length of this segment + + void SetTransform( + const MT_Vector3& start, + const MT_Matrix3x3& rest_basis, + const MT_Matrix3x3& basis, + const MT_Scalar length + ); + + // tree structure access + void SetParent(IK_QSegment *parent); + + IK_QSegment *Child() const + { return m_child; } + + IK_QSegment *Sibling() const + { return m_sibling; } + + IK_QSegment *Parent() const + { return m_parent; } + + // for combining two joints into one from the interface + void SetComposite(IK_QSegment *seg); + + IK_QSegment *Composite() const + { return m_composite; } + + // number of degrees of freedom + int NumberOfDoF() const + { return m_num_DoF; } + + // unique id for this segment, for identification in the jacobian + int DoFId() const + { return m_DoF_id; } + + void SetDoFId(int dof_id) + { m_DoF_id = dof_id; } + + // the max distance of the end of this bone from the local origin. + const MT_Scalar MaxExtension() const + { return m_max_extension; } + + // the change in rotation and translation w.r.t. the rest pose + MT_Matrix3x3 BasisChange() const; + MT_Vector3 TranslationChange() const; + + // the start and end of the segment + const MT_Point3 &GlobalStart() const + { return m_global_start; } + + const MT_Point3 &GlobalEnd() const + { return m_global_transform.getOrigin(); } + + // the global transformation at the end of the segment + const MT_Transform &GlobalTransform() const + { return m_global_transform; } + + // is a translational segment? + bool Translational() const + { return m_translational; } + + // locking (during inner clamping loop) + bool Locked(int dof) const + { return m_locked[dof]; } + + void UnLock() + { m_locked[0] = m_locked[1] = m_locked[2] = false; } + + // per dof joint weighting + MT_Scalar Weight(int dof) const + { return m_weight[dof]; } + + void ScaleWeight(int dof, MT_Scalar scale) + { m_weight[dof] *= scale; } + + // recursively update the global coordinates of this segment, 'global' + // is the global transformation from the parent segment + void UpdateTransform(const MT_Transform &global); + + // get axis from rotation matrix for derivative computation + virtual MT_Vector3 Axis(int dof) const=0; + + // update the angles using the dTheta's computed using the jacobian matrix + virtual bool UpdateAngle(const IK_QJacobian&, MT_Vector3&, bool*)=0; + virtual void Lock(int, IK_QJacobian&, MT_Vector3&) {} + virtual void UpdateAngleApply()=0; + + // set joint limits + virtual void SetLimit(int, MT_Scalar, MT_Scalar) {}; + + // set joint weights (per axis) + virtual void SetWeight(int, MT_Scalar) {}; + + virtual void SetBasis(const MT_Matrix3x3& basis) { m_basis = basis; } + + // functions needed for pole vector constraint + void PrependBasis(const MT_Matrix3x3& mat); + void Reset(); + + // scale + virtual void Scale(float scale); + +protected: + + // num_DoF: number of degrees of freedom + IK_QSegment(int num_DoF, bool translational); + + // remove child as a child of this segment + void RemoveChild(IK_QSegment *child); + + // tree structure variables + IK_QSegment *m_parent; + IK_QSegment *m_child; + IK_QSegment *m_sibling; + IK_QSegment *m_composite; + + // full transform = + // start * rest_basis * basis * translation + MT_Vector3 m_start; + MT_Matrix3x3 m_rest_basis; + MT_Matrix3x3 m_basis; + MT_Vector3 m_translation; + + // original basis + MT_Matrix3x3 m_orig_basis; + MT_Vector3 m_orig_translation; + + // maximum extension of this segment + MT_Scalar m_max_extension; + + // accumulated transformations starting from root + MT_Point3 m_global_start; + MT_Transform m_global_transform; + + // number degrees of freedom, (first) id of this segments DOF's + int m_num_DoF, m_DoF_id; + + bool m_locked[3]; + bool m_translational; + MT_Scalar m_weight[3]; +}; + +class IK_QSphericalSegment : public IK_QSegment +{ +public: + IK_QSphericalSegment(); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + void UpdateAngleApply(); + + bool ComputeClampRotation(MT_Vector3& clamp); + + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, MT_Scalar weight); + +private: + MT_Matrix3x3 m_new_basis; + bool m_limit_x, m_limit_y, m_limit_z; + MT_Scalar m_min[2], m_max[2]; + MT_Scalar m_min_y, m_max_y, m_max_x, m_max_z, m_offset_x, m_offset_z; + MT_Scalar m_locked_ax, m_locked_ay, m_locked_az; +}; + +class IK_QNullSegment : public IK_QSegment +{ +public: + IK_QNullSegment(); + + bool UpdateAngle(const IK_QJacobian&, MT_Vector3&, bool*) { return false; } + void UpdateAngleApply() {} + + MT_Vector3 Axis(int) const { return MT_Vector3(0, 0, 0); } + void SetBasis(const MT_Matrix3x3&) { m_basis.setIdentity(); } +}; + +class IK_QRevoluteSegment : public IK_QSegment +{ +public: + // axis: the axis of the DoF, in range 0..2 + IK_QRevoluteSegment(int axis); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + void UpdateAngleApply(); + + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, MT_Scalar weight); + void SetBasis(const MT_Matrix3x3& basis); + +private: + int m_axis; + MT_Scalar m_angle, m_new_angle; + bool m_limit; + MT_Scalar m_min, m_max; +}; + +class IK_QSwingSegment : public IK_QSegment +{ +public: + // XZ DOF, uses one direct rotation + IK_QSwingSegment(); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + void UpdateAngleApply(); + + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, MT_Scalar weight); + void SetBasis(const MT_Matrix3x3& basis); + +private: + MT_Matrix3x3 m_new_basis; + bool m_limit_x, m_limit_z; + MT_Scalar m_min[2], m_max[2]; + MT_Scalar m_max_x, m_max_z, m_offset_x, m_offset_z; +}; + +class IK_QElbowSegment : public IK_QSegment +{ +public: + // XY or ZY DOF, uses two sequential rotations: first rotate around + // X or Z, then rotate around Y (twist) + IK_QElbowSegment(int axis); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + void UpdateAngleApply(); + + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, MT_Scalar weight); + void SetBasis(const MT_Matrix3x3& basis); + +private: + int m_axis; + + MT_Scalar m_twist, m_angle, m_new_twist, m_new_angle; + MT_Scalar m_cos_twist, m_sin_twist; + + bool m_limit, m_limit_twist; + MT_Scalar m_min, m_max, m_min_twist, m_max_twist; +}; + +class IK_QTranslateSegment : public IK_QSegment +{ +public: + // 1DOF, 2DOF or 3DOF translational segments + IK_QTranslateSegment(int axis1); + IK_QTranslateSegment(int axis1, int axis2); + IK_QTranslateSegment(); + + MT_Vector3 Axis(int dof) const; + + bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); + void Lock(int, IK_QJacobian&, MT_Vector3&); + void UpdateAngleApply(); + + void SetWeight(int axis, MT_Scalar weight); + void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + + void Scale(float scale); + +private: + int m_axis[3]; + bool m_axis_enabled[3], m_limit[3]; + MT_Vector3 m_new_translation; + MT_Scalar m_min[3], m_max[3]; +}; + +#endif + diff --git a/intern/iksolver/intern/IK_QTask.cpp b/intern/iksolver/intern/IK_QTask.cpp new file mode 100644 index 00000000000..c72f146b36e --- /dev/null +++ b/intern/iksolver/intern/IK_QTask.cpp @@ -0,0 +1,239 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "IK_QTask.h" + +// IK_QTask + +IK_QTask::IK_QTask( + int size, + bool primary, + bool active, + const IK_QSegment *segment +) : + m_size(size), m_primary(primary), m_active(active), m_segment(segment), + m_weight(1.0) +{ +} + +// IK_QPositionTask + +IK_QPositionTask::IK_QPositionTask( + bool primary, + const IK_QSegment *segment, + const MT_Vector3& goal +) : + IK_QTask(3, primary, true, segment), m_goal(goal) +{ + // computing clamping length + int num; + const IK_QSegment *seg; + + m_clamp_length = 0.0; + num = 0; + + for (seg = m_segment; seg; seg = seg->Parent()) { + m_clamp_length += seg->MaxExtension(); + num++; + } + + m_clamp_length /= 2*num; +} + +void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian) +{ + // compute beta + const MT_Vector3& pos = m_segment->GlobalEnd(); + + MT_Vector3 d_pos = m_goal - pos; + MT_Scalar length = d_pos.length(); + + if (length > m_clamp_length) + d_pos = (m_clamp_length/length)*d_pos; + + jacobian.SetBetas(m_id, m_size, m_weight*d_pos); + + // compute derivatives + int i; + const IK_QSegment *seg; + + for (seg = m_segment; seg; seg = seg->Parent()) { + MT_Vector3 p = seg->GlobalStart() - pos; + + for (i = 0; i < seg->NumberOfDoF(); i++) { + MT_Vector3 axis = seg->Axis(i)*m_weight; + + if (seg->Translational()) + jacobian.SetDerivatives(m_id, seg->DoFId()+i, axis); + else { + MT_Vector3 pa = p.cross(axis); + jacobian.SetDerivatives(m_id, seg->DoFId()+i, pa); + } + } + } +} + +MT_Scalar IK_QPositionTask::Distance() const +{ + const MT_Vector3& pos = m_segment->GlobalEnd(); + MT_Vector3 d_pos = m_goal - pos; + return d_pos.length(); +} + +// IK_QOrientationTask + +IK_QOrientationTask::IK_QOrientationTask( + bool primary, + const IK_QSegment *segment, + const MT_Matrix3x3& goal +) : + IK_QTask(3, primary, true, segment), m_goal(goal), m_distance(0.0) +{ +} + +void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian) +{ + // compute betas + const MT_Matrix3x3& rot = m_segment->GlobalTransform().getBasis(); + + MT_Matrix3x3 d_rotm = m_goal*rot.transposed(); + d_rotm.transpose(); + + MT_Vector3 d_rot; + d_rot = -0.5*MT_Vector3(d_rotm[2][1] - d_rotm[1][2], + d_rotm[0][2] - d_rotm[2][0], + d_rotm[1][0] - d_rotm[0][1]); + + m_distance = d_rot.length(); + + jacobian.SetBetas(m_id, m_size, m_weight*d_rot); + + // compute derivatives + int i; + const IK_QSegment *seg; + + for (seg = m_segment; seg; seg = seg->Parent()) + for (i = 0; i < seg->NumberOfDoF(); i++) { + + if (seg->Translational()) + jacobian.SetDerivatives(m_id, seg->DoFId()+i, MT_Vector3(0, 0, 0)); + else { + MT_Vector3 axis = seg->Axis(i)*m_weight; + jacobian.SetDerivatives(m_id, seg->DoFId()+i, axis); + } + } +} + +// IK_QCenterOfMassTask +// Note: implementation not finished! + +IK_QCenterOfMassTask::IK_QCenterOfMassTask( + bool primary, + const IK_QSegment *segment, + const MT_Vector3& goal_center +) : + IK_QTask(3, primary, true, segment), m_goal_center(goal_center) +{ + m_total_mass_inv = ComputeTotalMass(m_segment); + if (!MT_fuzzyZero(m_total_mass_inv)) + m_total_mass_inv = 1.0/m_total_mass_inv; +} + +MT_Scalar IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment) +{ + MT_Scalar mass = /*seg->Mass()*/ 1.0; + + const IK_QSegment *seg; + for (seg = segment->Child(); seg; seg = seg->Sibling()) + mass += ComputeTotalMass(seg); + + return mass; +} + +MT_Vector3 IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment) +{ + MT_Vector3 center = /*seg->Mass()**/segment->GlobalStart(); + + const IK_QSegment *seg; + for (seg = segment->Child(); seg; seg = seg->Sibling()) + center += ComputeCenter(seg); + + return center; +} + +void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment) +{ + int i; + MT_Vector3 p = center - segment->GlobalStart(); + + for (i = 0; i < segment->NumberOfDoF(); i++) { + MT_Vector3 axis = segment->Axis(i)*m_weight; + axis *= /*segment->Mass()**/m_total_mass_inv; + + if (segment->Translational()) + jacobian.SetDerivatives(m_id, segment->DoFId()+i, axis); + else { + MT_Vector3 pa = axis.cross(p); + jacobian.SetDerivatives(m_id, segment->DoFId()+i, pa); + } + } + + const IK_QSegment *seg; + for (seg = segment->Child(); seg; seg = seg->Sibling()) + JacobianSegment(jacobian, center, seg); +} + +void IK_QCenterOfMassTask::ComputeJacobian(IK_QJacobian& jacobian) +{ + MT_Vector3 center = ComputeCenter(m_segment)*m_total_mass_inv; + + // compute beta + MT_Vector3 d_pos = m_goal_center - center; + + m_distance = d_pos.length(); + +#if 0 + if (m_distance > m_clamp_length) + d_pos = (m_clamp_length/m_distance)*d_pos; +#endif + + jacobian.SetBetas(m_id, m_size, m_weight*d_pos); + + // compute derivatives + JacobianSegment(jacobian, center, m_segment); +} + +MT_Scalar IK_QCenterOfMassTask::Distance() const +{ + return m_distance; +} + diff --git a/intern/iksolver/intern/IK_QTask.h b/intern/iksolver/intern/IK_QTask.h new file mode 100644 index 00000000000..f2fd34119a1 --- /dev/null +++ b/intern/iksolver/intern/IK_QTask.h @@ -0,0 +1,156 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_IK_QTask_h +#define NAN_INCLUDED_IK_QTask_h + +#include "MT_Vector3.h" +#include "MT_Transform.h" +#include "MT_Matrix4x4.h" +#include "IK_QJacobian.h" +#include "IK_QSegment.h" + +class IK_QTask +{ +public: + IK_QTask( + int size, + bool primary, + bool active, + const IK_QSegment *segment + ); + virtual ~IK_QTask() {}; + + int Id() const + { return m_size; } + + void SetId(int id) + { m_id = id; } + + int Size() const + { return m_size; } + + bool Primary() const + { return m_primary; } + + bool Active() const + { return m_active; } + + MT_Scalar Weight() const + { return m_weight*m_weight; } + + void SetWeight(MT_Scalar weight) + { m_weight = sqrt(weight); } + + virtual void ComputeJacobian(IK_QJacobian& jacobian)=0; + + virtual MT_Scalar Distance() const=0; + + virtual bool PositionTask() const { return false; } + + virtual void Scale(float scale) {} + +protected: + int m_id; + int m_size; + bool m_primary; + bool m_active; + const IK_QSegment *m_segment; + MT_Scalar m_weight; +}; + +class IK_QPositionTask : public IK_QTask +{ +public: + IK_QPositionTask( + bool primary, + const IK_QSegment *segment, + const MT_Vector3& goal + ); + + void ComputeJacobian(IK_QJacobian& jacobian); + + MT_Scalar Distance() const; + + bool PositionTask() const { return true; } + void Scale(float scale) { m_goal *= scale; m_clamp_length *= scale; } + +private: + MT_Vector3 m_goal; + MT_Scalar m_clamp_length; +}; + +class IK_QOrientationTask : public IK_QTask +{ +public: + IK_QOrientationTask( + bool primary, + const IK_QSegment *segment, + const MT_Matrix3x3& goal + ); + + MT_Scalar Distance() const { return m_distance; }; + void ComputeJacobian(IK_QJacobian& jacobian); + +private: + MT_Matrix3x3 m_goal; + MT_Scalar m_distance; +}; + + +class IK_QCenterOfMassTask : public IK_QTask +{ +public: + IK_QCenterOfMassTask( + bool primary, + const IK_QSegment *segment, + const MT_Vector3& center + ); + + void ComputeJacobian(IK_QJacobian& jacobian); + + MT_Scalar Distance() const; + + void Scale(float scale) { m_goal_center *= scale; m_distance *= scale; } + +private: + MT_Scalar ComputeTotalMass(const IK_QSegment *segment); + MT_Vector3 ComputeCenter(const IK_QSegment *segment); + void JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment); + + MT_Vector3 m_goal_center; + MT_Scalar m_total_mass_inv; + MT_Scalar m_distance; +}; + +#endif + diff --git a/intern/iksolver/intern/IK_Solver.cpp b/intern/iksolver/intern/IK_Solver.cpp new file mode 100644 index 00000000000..140c35c8c46 --- /dev/null +++ b/intern/iksolver/intern/IK_Solver.cpp @@ -0,0 +1,380 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "../extern/IK_solver.h" + +#include "IK_QJacobianSolver.h" +#include "IK_QSegment.h" +#include "IK_QTask.h" + +#include +using namespace std; + +class IK_QSolver { +public: + IK_QSolver() : root(NULL) {}; + + IK_QJacobianSolver solver; + IK_QSegment *root; + std::list tasks; +}; + +IK_QSegment *CreateSegment(int flag, bool translate) +{ + int ndof = 0; + ndof += (flag & IK_XDOF)? 1: 0; + ndof += (flag & IK_YDOF)? 1: 0; + ndof += (flag & IK_ZDOF)? 1: 0; + + IK_QSegment *seg; + + if (ndof == 0) + return NULL; + else if (ndof == 1) { + int axis; + + if (flag & IK_XDOF) axis = 0; + else if (flag & IK_YDOF) axis = 1; + else axis = 2; + + if (translate) + seg = new IK_QTranslateSegment(axis); + else + seg = new IK_QRevoluteSegment(axis); + } + else if (ndof == 2) { + int axis1, axis2; + + if (flag & IK_XDOF) { + axis1 = 0; + axis2 = (flag & IK_YDOF)? 1: 2; + } + else { + axis1 = 1; + axis2 = 2; + } + + if (translate) + seg = new IK_QTranslateSegment(axis1, axis2); + else { + if (axis1 + axis2 == 2) + seg = new IK_QSwingSegment(); + else + seg = new IK_QElbowSegment((axis1 == 0)? 0: 2); + } + } + else { + if (translate) + seg = new IK_QTranslateSegment(); + else + seg = new IK_QSphericalSegment(); + } + + return seg; +} + +IK_Segment *IK_CreateSegment(int flag) +{ + IK_QSegment *rot = CreateSegment(flag, false); + IK_QSegment *trans = CreateSegment(flag >> 3, true); + + IK_QSegment *seg; + + if (rot == NULL && trans == NULL) + seg = new IK_QNullSegment(); + else if (rot == NULL) + seg = trans; + else { + seg = rot; + + // make it seem from the interface as if the rotation and translation + // segment are one + if (trans) { + seg->SetComposite(trans); + trans->SetParent(seg); + } + } + + return seg; +} + +void IK_FreeSegment(IK_Segment *seg) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + + if (qseg->Composite()) + delete qseg->Composite(); + delete qseg; +} + +void IK_SetParent(IK_Segment *seg, IK_Segment *parent) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + IK_QSegment *qparent = (IK_QSegment*)parent; + + if (qparent && qparent->Composite()) + qseg->SetParent(qparent->Composite()); + else + qseg->SetParent(qparent); +} + +void IK_SetTransform(IK_Segment *seg, float start[3], float rest[][3], float basis[][3], float length) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + + MT_Vector3 mstart(start); + // convert from blender column major to moto row major + MT_Matrix3x3 mbasis(basis[0][0], basis[1][0], basis[2][0], + basis[0][1], basis[1][1], basis[2][1], + basis[0][2], basis[1][2], basis[2][2]); + MT_Matrix3x3 mrest(rest[0][0], rest[1][0], rest[2][0], + rest[0][1], rest[1][1], rest[2][1], + rest[0][2], rest[1][2], rest[2][2]); + MT_Scalar mlength(length); + + if (qseg->Composite()) { + MT_Vector3 cstart(0, 0, 0); + MT_Matrix3x3 cbasis; + cbasis.setIdentity(); + + qseg->SetTransform(mstart, mrest, mbasis, 0.0); + qseg->Composite()->SetTransform(cstart, cbasis, cbasis, mlength); + } + else + qseg->SetTransform(mstart, mrest, mbasis, mlength); +} + +void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lmin, float lmax) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + + if (axis >= IK_TRANS_X) { + if(!qseg->Translational()) + if(qseg->Composite() && qseg->Composite()->Translational()) + qseg = qseg->Composite(); + else + return; + + if(axis == IK_TRANS_X) axis = IK_X; + else if(axis == IK_TRANS_Y) axis = IK_Y; + else axis = IK_Z; + } + + qseg->SetLimit(axis, lmin, lmax); +} + +void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness) +{ + if (stiffness < 0.0) + return; + + if (stiffness > 0.999) + stiffness = 0.999; + + IK_QSegment *qseg = (IK_QSegment*)seg; + MT_Scalar weight = 1.0-stiffness; + + if (axis >= IK_TRANS_X) { + if(!qseg->Translational()) + if(qseg->Composite() && qseg->Composite()->Translational()) + qseg = qseg->Composite(); + else + return; + + if(axis == IK_TRANS_X) axis = IK_X; + else if(axis == IK_TRANS_Y) axis = IK_Y; + else axis = IK_Z; + } + + qseg->SetWeight(axis, weight); +} + +void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3]) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + const MT_Matrix3x3& change = qseg->BasisChange(); + + if (qseg->Translational() && qseg->Composite()) + qseg = qseg->Composite(); + + // convert from moto row major to blender column major + basis_change[0][0] = (float)change[0][0]; + basis_change[1][0] = (float)change[0][1]; + basis_change[2][0] = (float)change[0][2]; + basis_change[0][1] = (float)change[1][0]; + basis_change[1][1] = (float)change[1][1]; + basis_change[2][1] = (float)change[1][2]; + basis_change[0][2] = (float)change[2][0]; + basis_change[1][2] = (float)change[2][1]; + basis_change[2][2] = (float)change[2][2]; +} + +void IK_GetTranslationChange(IK_Segment *seg, float *translation_change) +{ + IK_QSegment *qseg = (IK_QSegment*)seg; + + if (!qseg->Translational() && qseg->Composite()) + qseg = qseg->Composite(); + + const MT_Vector3& change = qseg->TranslationChange(); + + translation_change[0] = (float)change[0]; + translation_change[1] = (float)change[1]; + translation_change[2] = (float)change[2]; +} + +IK_Solver *IK_CreateSolver(IK_Segment *root) +{ + if (root == NULL) + return NULL; + + IK_QSolver *solver = new IK_QSolver(); + solver->root = (IK_QSegment*)root; + + return (IK_Solver*)solver; +} + +void IK_FreeSolver(IK_Solver *solver) +{ + if (solver == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + std::list& tasks = qsolver->tasks; + std::list::iterator task; + + for (task = tasks.begin(); task != tasks.end(); task++) + delete (*task); + + delete qsolver; +} + +void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight) +{ + if (solver == NULL || tip == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + IK_QSegment *qtip = (IK_QSegment*)tip; + + if (qtip->Composite()) + qtip = qtip->Composite(); + + MT_Vector3 pos(goal); + + IK_QTask *ee = new IK_QPositionTask(true, qtip, pos); + ee->SetWeight(weight); + qsolver->tasks.push_back(ee); +} + +void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight) +{ + if (solver == NULL || tip == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + IK_QSegment *qtip = (IK_QSegment*)tip; + + if (qtip->Composite()) + qtip = qtip->Composite(); + + // convert from blender column major to moto row major + MT_Matrix3x3 rot(goal[0][0], goal[1][0], goal[2][0], + goal[0][1], goal[1][1], goal[2][1], + goal[0][2], goal[1][2], goal[2][2]); + + IK_QTask *orient = new IK_QOrientationTask(true, qtip, rot); + orient->SetWeight(weight); + qsolver->tasks.push_back(orient); +} + +void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle) +{ + if (solver == NULL || tip == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + IK_QSegment *qtip = (IK_QSegment*)tip; + + MT_Vector3 qgoal(goal); + MT_Vector3 qpolegoal(polegoal); + + qsolver->solver.SetPoleVectorConstraint( + qtip, qgoal, qpolegoal, poleangle, getangle); +} + +float IK_SolverGetPoleAngle(IK_Solver *solver) +{ + if (solver == NULL) + return 0.0f; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + + return qsolver->solver.GetPoleAngle(); +} + +void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float goal[3], float weight) +{ + if (solver == NULL || root == NULL) + return; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + IK_QSegment *qroot = (IK_QSegment*)root; + + // convert from blender column major to moto row major + MT_Vector3 center(goal); + + IK_QTask *com = new IK_QCenterOfMassTask(true, qroot, center); + com->SetWeight(weight); + qsolver->tasks.push_back(com); +} + +int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations) +{ + if (solver == NULL) + return 0; + + IK_QSolver *qsolver = (IK_QSolver*)solver; + + IK_QSegment *root = qsolver->root; + IK_QJacobianSolver& jacobian = qsolver->solver; + std::list& tasks = qsolver->tasks; + MT_Scalar tol = tolerance; + + if(!jacobian.Setup(root, tasks)) + return 0; + + bool result = jacobian.Solve(root, tasks, tol, max_iterations); + + return ((result)? 1: 0); +} + diff --git a/intern/iksolver/intern/MT_ExpMap.cpp b/intern/iksolver/intern/MT_ExpMap.cpp new file mode 100644 index 00000000000..9b758103de8 --- /dev/null +++ b/intern/iksolver/intern/MT_ExpMap.cpp @@ -0,0 +1,251 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original Author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "MT_ExpMap.h" + +/** + * Set the exponential map from a quaternion. The quaternion must be non-zero. + */ + + void +MT_ExpMap:: +setRotation( + const MT_Quaternion &q +) { + // ok first normalize the quaternion + // then compute theta the axis-angle and the normalized axis v + // scale v by theta and that's it hopefully! + + m_q = q.normalized(); + m_v = MT_Vector3(m_q.x(), m_q.y(), m_q.z()); + + MT_Scalar cosp = m_q.w(); + m_sinp = m_v.length(); + m_v /= m_sinp; + + m_theta = atan2(double(m_sinp),double(cosp)); + m_v *= m_theta; +} + +/** + * Convert from an exponential map to a quaternion + * representation + */ + + const MT_Quaternion& +MT_ExpMap:: +getRotation( +) const { + return m_q; +} + +/** + * Convert the exponential map to a 3x3 matrix + */ + + MT_Matrix3x3 +MT_ExpMap:: +getMatrix( +) const { + return MT_Matrix3x3(m_q); +} + +/** + * Update & reparameterizate the exponential map + */ + + void +MT_ExpMap:: +update( + const MT_Vector3& dv +){ + m_v += dv; + + angleUpdated(); +} + +/** + * Compute the partial derivatives of the exponential + * map (dR/de - where R is a 3x3 rotation matrix formed + * from the map) and return them as a 3x3 matrix + */ + + void +MT_ExpMap:: +partialDerivatives( + MT_Matrix3x3& dRdx, + MT_Matrix3x3& dRdy, + MT_Matrix3x3& dRdz +) const { + + MT_Quaternion dQdx[3]; + + compute_dQdVi(dQdx); + + compute_dRdVi(dQdx[0], dRdx); + compute_dRdVi(dQdx[1], dRdy); + compute_dRdVi(dQdx[2], dRdz); +} + + void +MT_ExpMap:: +compute_dRdVi( + const MT_Quaternion &dQdvi, + MT_Matrix3x3 & dRdvi +) const { + + MT_Scalar prod[9]; + + /* This efficient formulation is arrived at by writing out the + * entire chain rule product dRdq * dqdv in terms of 'q' and + * noticing that all the entries are formed from sums of just + * nine products of 'q' and 'dqdv' */ + + prod[0] = -MT_Scalar(4)*m_q.x()*dQdvi.x(); + prod[1] = -MT_Scalar(4)*m_q.y()*dQdvi.y(); + prod[2] = -MT_Scalar(4)*m_q.z()*dQdvi.z(); + prod[3] = MT_Scalar(2)*(m_q.y()*dQdvi.x() + m_q.x()*dQdvi.y()); + prod[4] = MT_Scalar(2)*(m_q.w()*dQdvi.z() + m_q.z()*dQdvi.w()); + prod[5] = MT_Scalar(2)*(m_q.z()*dQdvi.x() + m_q.x()*dQdvi.z()); + prod[6] = MT_Scalar(2)*(m_q.w()*dQdvi.y() + m_q.y()*dQdvi.w()); + prod[7] = MT_Scalar(2)*(m_q.z()*dQdvi.y() + m_q.y()*dQdvi.z()); + prod[8] = MT_Scalar(2)*(m_q.w()*dQdvi.x() + m_q.x()*dQdvi.w()); + + /* first row, followed by second and third */ + dRdvi[0][0] = prod[1] + prod[2]; + dRdvi[0][1] = prod[3] - prod[4]; + dRdvi[0][2] = prod[5] + prod[6]; + + dRdvi[1][0] = prod[3] + prod[4]; + dRdvi[1][1] = prod[0] + prod[2]; + dRdvi[1][2] = prod[7] - prod[8]; + + dRdvi[2][0] = prod[5] - prod[6]; + dRdvi[2][1] = prod[7] + prod[8]; + dRdvi[2][2] = prod[0] + prod[1]; +} + +// compute partial derivatives dQ/dVi + + void +MT_ExpMap:: +compute_dQdVi( + MT_Quaternion *dQdX +) const { + + /* This is an efficient implementation of the derivatives given + * in Appendix A of the paper with common subexpressions factored out */ + + MT_Scalar sinc, termCoeff; + + if (m_theta < MT_EXPMAP_MINANGLE) { + sinc = 0.5 - m_theta*m_theta/48.0; + termCoeff = (m_theta*m_theta/40.0 - 1.0)/24.0; + } + else { + MT_Scalar cosp = m_q.w(); + MT_Scalar ang = 1.0/m_theta; + + sinc = m_sinp*ang; + termCoeff = ang*ang*(0.5*cosp - sinc); + } + + for (int i = 0; i < 3; i++) { + MT_Quaternion& dQdx = dQdX[i]; + int i2 = (i+1)%3; + int i3 = (i+2)%3; + + MT_Scalar term = m_v[i]*termCoeff; + + dQdx[i] = term*m_v[i] + sinc; + dQdx[i2] = term*m_v[i2]; + dQdx[i3] = term*m_v[i3]; + dQdx.w() = -0.5*m_v[i]*sinc; + } +} + +// reParametize away from singularity, updating +// m_v and m_theta + + void +MT_ExpMap:: +reParametrize( +){ + if (m_theta > MT_PI) { + MT_Scalar scl = m_theta; + if (m_theta > MT_2_PI){ /* first get theta into range 0..2PI */ + m_theta = MT_Scalar(fmod(m_theta, MT_2_PI)); + scl = m_theta/scl; + m_v *= scl; + } + if (m_theta > MT_PI){ + scl = m_theta; + m_theta = MT_2_PI - m_theta; + scl = MT_Scalar(1.0) - MT_2_PI/scl; + m_v *= scl; + } + } +} + +// compute cached variables + + void +MT_ExpMap:: +angleUpdated( +){ + m_theta = m_v.length(); + + reParametrize(); + + // compute quaternion, sinp and cosp + + if (m_theta < MT_EXPMAP_MINANGLE) { + m_sinp = MT_Scalar(0.0); + + /* Taylor Series for sinc */ + MT_Vector3 temp = m_v * MT_Scalar(MT_Scalar(.5) - m_theta*m_theta/MT_Scalar(48.0)); + m_q.x() = temp.x(); + m_q.y() = temp.y(); + m_q.z() = temp.z(); + m_q.w() = MT_Scalar(1.0); + } else { + m_sinp = MT_Scalar(sin(.5*m_theta)); + + /* Taylor Series for sinc */ + MT_Vector3 temp = m_v * (m_sinp/m_theta); + m_q.x() = temp.x(); + m_q.y() = temp.y(); + m_q.z() = temp.z(); + m_q.w() = MT_Scalar(cos(.5*m_theta)); + } +} + diff --git a/intern/iksolver/intern/MT_ExpMap.h b/intern/iksolver/intern/MT_ExpMap.h new file mode 100644 index 00000000000..401993764aa --- /dev/null +++ b/intern/iksolver/intern/MT_ExpMap.h @@ -0,0 +1,212 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef MT_ExpMap_H +#define MT_ExpMap_H + +#include + +#include "MT_Vector3.h" +#include "MT_Quaternion.h" +#include "MT_Matrix4x4.h" + +const MT_Scalar MT_EXPMAP_MINANGLE (1e-7); + +/** + * MT_ExpMap an exponential map parameterization of rotations + * in 3D. This implementation is derived from the paper + * "F. Sebastian Grassia. Practical parameterization of + * rotations using the exponential map. Journal of Graphics Tools, + * 3(3):29-48, 1998" Please go to http://www.acm.org/jgt/papers/Grassia98/ + * for a thorough description of the theory and sample code used + * to derive this class. + * + * Basic overview of why this class is used. + * In an IK system we need to paramterize the joint angles in some + * way. Typically 2 parameterizations are used. + * - Euler Angles + * These suffer from singularities in the parameterization known + * as gimbal lock. They also do not interpolate well. For every + * set of euler angles there is exactly 1 corresponding 3d rotation. + * - Quaternions. + * Great for interpolating. Only unit quaternions are valid rotations + * means that in a differential ik solver we often stray outside of + * this manifold into invalid rotations. Means we have to do a lot + * of nasty normalizations all the time. Does not suffer from + * gimbal lock problems. More expensive to compute partial derivatives + * as there are 4 of them. + * + * So exponential map is similar to a quaternion axis/angle + * representation but we store the angle as the length of the + * axis. So require only 3 parameters. Means that all exponential + * maps are valid rotations. Suffers from gimbal lock. But it's + * possible to detect when gimbal lock is near and reparameterize + * away from it. Also nice for interpolating. + * Exponential maps are share some of the useful properties of + * euler and quaternion parameterizations. And are very useful + * for differential IK solvers. + */ + +class MT_ExpMap { +public: + + /** + * Default constructor + * @warning there is no initialization in the + * default constructor + */ + + MT_ExpMap() {} + MT_ExpMap(const MT_Vector3& v) : m_v(v) { angleUpdated(); } + + MT_ExpMap(const float v[3]) : m_v(v) { angleUpdated(); } + MT_ExpMap(const double v[3]) : m_v(v) { angleUpdated(); } + + MT_ExpMap(MT_Scalar x, MT_Scalar y, MT_Scalar z) : + m_v(x, y, z) { angleUpdated(); } + + /** + * Construct an exponential map from a quaternion + */ + + MT_ExpMap( + const MT_Quaternion &q + ) { + setRotation(q); + }; + + /** + * Accessors + * Decided not to inherit from MT_Vector3 but rather + * this class contains an MT_Vector3. This is because + * it is very dangerous to use MT_Vector3 functions + * on this class and some of them have no direct meaning. + */ + + const + MT_Vector3 & + vector( + ) const { + return m_v; + }; + + /** + * Set the exponential map from a quaternion + */ + + void + setRotation( + const MT_Quaternion &q + ); + + /** + * Convert from an exponential map to a quaternion + * representation + */ + + const MT_Quaternion& + getRotation( + ) const; + + /** + * Convert the exponential map to a 3x3 matrix + */ + + MT_Matrix3x3 + getMatrix( + ) const; + + /** + * Update (and reparameterize) the expontial map + * @param dv delta update values. + */ + + void + update( + const MT_Vector3& dv + ); + + /** + * Compute the partial derivatives of the exponential + * map (dR/de - where R is a 4x4 matrix formed + * from the map) and return them as a 4x4 matrix + */ + + void + partialDerivatives( + MT_Matrix3x3& dRdx, + MT_Matrix3x3& dRdy, + MT_Matrix3x3& dRdz + ) const ; + +private : + + // m_v contains the exponential map, the other variables are + // cached for efficiency + + MT_Vector3 m_v; + MT_Scalar m_theta, m_sinp; + MT_Quaternion m_q; + + // private methods + + // Compute partial derivatives dR (3x3 rotation matrix) / dVi (EM vector) + // given the partial derivative dQ (Quaternion) / dVi (ith element of EM vector) + + void + compute_dRdVi( + const MT_Quaternion &dQdV, + MT_Matrix3x3 & dRdVi + ) const; + + // compute partial derivatives dQ/dVi + + void + compute_dQdVi( + MT_Quaternion *dQdX + ) const ; + + // reparametrize away from singularity + + void + reParametrize( + ); + + // (re-)compute cached variables + + void + angleUpdated( + ); +}; + +#endif + diff --git a/intern/iksolver/intern/Makefile b/intern/iksolver/intern/Makefile new file mode 100644 index 00000000000..fff4aec252d --- /dev/null +++ b/intern/iksolver/intern/Makefile @@ -0,0 +1,45 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver intern Makefile +# + +LIBNAME = iksolver +DIR = $(OCGDIR)/intern/$(LIBNAME) +CCSRCS = IK_QJacobianSolver.cpp IK_QSegment.cpp IK_Solver.cpp IK_QJacobian.cpp +CCSRCS += IK_QTask.cpp + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include + diff --git a/intern/iksolver/intern/TNT/cholesky.h b/intern/iksolver/intern/TNT/cholesky.h new file mode 100644 index 00000000000..3a8011c374c --- /dev/null +++ b/intern/iksolver/intern/TNT/cholesky.h @@ -0,0 +1,99 @@ +/* + * $Id$ + */ + +/* +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + +#ifndef CHOLESKY_H +#define CHOLESKY_H + +#include + +// index method + +namespace TNT +{ + + +// +// Only upper part of A is used. Cholesky factor is returned in +// lower part of L. Returns 0 if successful, 1 otherwise. +// +template +int Cholesky_upper_factorization(SPDMatrix &A, SymmMatrix &L) +{ + Subscript M = A.dim(1); + Subscript N = A.dim(2); + + assert(M == N); // make sure A is square + + // readjust size of L, if necessary + + if (M != L.dim(1) || N != L.dim(2)) + L = SymmMatrix(N,N); + + Subscript i,j,k; + + + typename SPDMatrix::element_type dot=0; + + + for (j=1; j<=N; j++) // form column j of L + { + dot= 0; + + for (i=1; i +#include +#include +#ifdef TNT_USE_REGIONS +#include "region2d.h" +#endif + +namespace TNT +{ + +template +class Matrix +{ + + + public: + + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + Subscript m_; + Subscript n_; + Subscript mn_; // total size + T* v_; + T** row_; + T* vm1_ ; // these point to the same data, but are 1-based + T** rowm1_; + + // internal helper function to create the array + // of row pointers + + void initialize(Subscript M, Subscript N) + { + mn_ = M*N; + m_ = M; + n_ = N; + + v_ = new T[mn_]; + row_ = new T*[M]; + rowm1_ = new T*[M]; + + assert(v_ != NULL); + assert(row_ != NULL); + assert(rowm1_ != NULL); + + T* p = v_; + vm1_ = v_ - 1; + for (Subscript i=0; i &A) + { + initialize(A.m_, A.n_); + copy(A.v_); + } + + Matrix(Subscript M, Subscript N, const T& value = T()) + { + initialize(M,N); + set(value); + } + + Matrix(Subscript M, Subscript N, const T* v) + { + initialize(M,N); + copy(v); + } + + + // destructor + // + ~Matrix() + { + destroy(); + } + + + // reallocating + // + Matrix& newsize(Subscript M, Subscript N) + { + if (num_rows() == M && num_cols() == N) + return *this; + + destroy(); + initialize(M,N); + + return *this; + } + + void + diagonal(Vector &diag) + { + int sz = diag.dim(); + newsize(sz,sz); + set(0); + + Subscript i; + for (i = 0; i < sz; i++) { + row_[i][i] = diag[i]; + } + } + + + + // assignments + // + Matrix& operator=(const Matrix &A) + { + if (v_ == A.v_) + return *this; + + if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc + copy(A.v_); + + else + { + destroy(); + initialize(A.m_, A.n_); + copy(A.v_); + } + + return *this; + } + + Matrix& operator=(const T& scalar) + { + set(scalar); + return *this; + } + + + Subscript dim(Subscript d) const + { +#ifdef TNT_BOUNDS_CHECK + assert( d >= 1); + assert( d <= 2); +#endif + return (d==1) ? m_ : ((d==2) ? n_ : 0); + } + + Subscript num_rows() const { return m_; } + Subscript num_cols() const { return n_; } + + + + + inline T* operator[](Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < m_) ; +#endif + return row_[i]; + } + + inline const T* operator[](Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < m_) ; +#endif + return row_[i]; + } + + inline reference operator()(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= mn_) ; +#endif + return vm1_[i]; + } + + inline const_reference operator()(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= mn_) ; +#endif + return vm1_[i]; + } + + + + inline reference operator()(Subscript i, Subscript j) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return rowm1_[i][j]; + } + + + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return rowm1_[i][j]; + } + + + +#ifdef TNT_USE_REGIONS + + typedef Region2D > Region; + + + Region operator()(const Index1D &I, const Index1D &J) + { + return Region(*this, I,J); + } + + + typedef const_Region2D< Matrix > const_Region; + const_Region operator()(const Index1D &I, const Index1D &J) const + { + return const_Region(*this, I,J); + } + +#endif + + +}; + + +/* *************************** I/O ********************************/ + +template +std::ostream& operator<<(std::ostream &s, const Matrix &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << "\n"; + + for (Subscript i=0; i +std::istream& operator>>(std::istream &s, Matrix &A) +{ + + Subscript M, N; + + s >> M >> N; + + if ( !(M == A.num_rows() && N == A.num_cols() )) + { + A.newsize(M,N); + } + + + for (Subscript i=0; i> A[i][j]; + } + + + return s; +} + +// *******************[ basic matrix algorithms ]*************************** + +template +Matrix operator+(const Matrix &A, + const Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix tmp(M,N); + Subscript i,j; + + for (i=0; i +Matrix operator-(const Matrix &A, + const Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix tmp(M,N); + Subscript i,j; + + for (i=0; i +Matrix mult_element(const Matrix &A, + const Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix tmp(M,N); + Subscript i,j; + + for (i=0; i +void transpose(const Matrix &A, Matrix &S) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==S.num_cols()); + assert(N==S.num_rows()); + + Subscript i, j; + + for (i=0; i +inline void matmult(Matrix& C, const Matrix &A, + const Matrix &B) +{ + + assert(A.num_cols() == B.num_rows()); + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + Subscript K = B.num_cols(); + + C.newsize(M,K); + + T sum; + + const T* row_i; + const T* col_k; + + for (Subscript i=0; i +void matmult(Vector &y, const Matrix &A, const Vector &x) +{ + +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() == x.dim()); + assert(A.num_rows() == y.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + T sum; + + for (Subscript i=0; i +inline void matmultdiag( + Matrix& C, + const Matrix &A, + const Vector &diag +){ +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() ==A.num_rows()== diag.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript K = diag.dim(); + + C.newsize(M,K); + + const T* row_i; + const T* col_k; + + for (Subscript i=0; i +inline void matmultdiag( + Matrix& C, + const Vector &diag, + const Matrix &A +){ +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() ==A.num_rows()== diag.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript K = diag.dim(); + + C.newsize(M,K); + + for (Subscript i=0; i +#include +#include "tnt.h" +#include "vec.h" + +using namespace std; + +namespace TNT +{ + +template +class Fortran_Sparse_Col_Matrix +{ + + protected: + + Vector val_; // data values (nz_ elements) + Vector rowind_; // row_ind (nz_ elements) + Vector colptr_; // col_ptr (n_+1 elements) + + int nz_; // number of nonzeros + Subscript m_; // global dimensions + Subscript n_; + + public: + + + Fortran_Sparse_Col_Matrix(void); + Fortran_Sparse_Col_Matrix(const Fortran_Sparse_Col_Matrix &S) + : val_(S.val_), rowind_(S.rowind_), colptr_(S.colptr_), nz_(S.nz_), + m_(S.m_), n_(S.n_) {}; + Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, + Subscript nz, const T *val, const Subscript *r, + const Subscript *c) : val_(nz, val), rowind_(nz, r), + colptr_(N+1, c), nz_(nz), m_(M), n_(N) {}; + + Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, + Subscript nz, char *val, char *r, + char *c) : val_(nz, val), rowind_(nz, r), + colptr_(N+1, c), nz_(nz), m_(M), n_(N) {}; + + Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, + Subscript nz, const T *val, Subscript *r, Subscript *c) + : val_(nz, val), rowind_(nz, r), colptr_(N+1, c), nz_(nz), + m_(M), n_(N) {}; + + ~Fortran_Sparse_Col_Matrix() {}; + + + T & val(Subscript i) { return val_(i); } + const T & val(Subscript i) const { return val_(i); } + + Subscript & row_ind(Subscript i) { return rowind_(i); } + const Subscript & row_ind(Subscript i) const { return rowind_(i); } + + Subscript col_ptr(Subscript i) { return colptr_(i);} + const Subscript col_ptr(Subscript i) const { return colptr_(i);} + + + Subscript num_cols() const { return m_;} + Subscript num_rows() const { return n_; } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert( 1 <= i ); + assert( i <= 2 ); +#endif + if (i==1) return m_; + else if (i==2) return m_; + else return 0; + } + + Subscript num_nonzeros() const {return nz_;}; + Subscript lbound() const {return 1;} + + + + Fortran_Sparse_Col_Matrix& operator=(const + Fortran_Sparse_Col_Matrix &C) + { + val_ = C.val_; + rowind_ = C.rowind_; + colptr_ = C.colptr_; + nz_ = C.nz_; + m_ = C.m_; + n_ = C.n_; + + return *this; + } + + Fortran_Sparse_Col_Matrix& newsize(Subscript M, Subscript N, + Subscript nz) + { + val_.newsize(nz); + rowind_.newsize(nz); + colptr_.newsize(N+1); + return *this; + } +}; + +template +ostream& operator<<(ostream &s, const Fortran_Sparse_Col_Matrix &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << " " << A.num_nonzeros() << endl; + + + for (Subscript k=1; k<=N; k++) + { + Subscript start = A.col_ptr(k); + Subscript end = A.col_ptr(k+1); + + for (Subscript i= start; i +#include +#include +#ifdef TNT_USE_REGIONS +#include "region2d.h" +#endif + +// simple 1-based, column oriented Matrix class + +namespace TNT +{ + +template +class Fortran_Matrix +{ + + + public: + + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + T* v_; // these are adjusted to simulate 1-offset + Subscript m_; + Subscript n_; + T** col_; // these are adjusted to simulate 1-offset + + // internal helper function to create the array + // of row pointers + + void initialize(Subscript M, Subscript N) + { + // adjust col_[] pointers so that they are 1-offset: + // col_[j][i] is really col_[j-1][i-1]; + // + // v_[] is the internal contiguous array, it is still 0-offset + // + v_ = new T[M*N]; + col_ = new T*[N]; + + assert(v_ != NULL); + assert(col_ != NULL); + + + m_ = M; + n_ = N; + T* p = v_ - 1; + for (Subscript i=0; i &A) + { + initialize(A.m_, A.n_); + copy(A.v_); + } + + Fortran_Matrix(Subscript M, Subscript N, const T& value = T()) + { + initialize(M,N); + set(value); + } + + Fortran_Matrix(Subscript M, Subscript N, const T* v) + { + initialize(M,N); + copy(v); + } + + + // destructor + ~Fortran_Matrix() + { + destroy(); + } + + + // assignments + // + Fortran_Matrix& operator=(const Fortran_Matrix &A) + { + if (v_ == A.v_) + return *this; + + if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc + copy(A.v_); + + else + { + destroy(); + initialize(A.m_, A.n_); + copy(A.v_); + } + + return *this; + } + + Fortran_Matrix& operator=(const T& scalar) + { + set(scalar); + return *this; + } + + + Subscript dim(Subscript d) const + { +#ifdef TNT_BOUNDS_CHECK + assert( d >= 1); + assert( d <= 2); +#endif + return (d==1) ? m_ : ((d==2) ? n_ : 0); + } + + Subscript num_rows() const { return m_; } + Subscript num_cols() const { return n_; } + + Fortran_Matrix& newsize(Subscript M, Subscript N) + { + if (num_rows() == M && num_cols() == N) + return *this; + + destroy(); + initialize(M,N); + + return *this; + } + + + + // 1-based element access + // + inline reference operator()(Subscript i, Subscript j) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return col_[j][i]; + } + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return col_[j][i]; + } + + +#ifdef TNT_USE_REGIONS + + typedef Region2D > Region; + typedef const_Region2D< Fortran_Matrix > const_Region; + + Region operator()(const Index1D &I, const Index1D &J) + { + return Region(*this, I,J); + } + + const_Region operator()(const Index1D &I, const Index1D &J) const + { + return const_Region(*this, I,J); + } + +#endif + + +}; + + +/* *************************** I/O ********************************/ + +template +std::ostream& operator<<(std::ostream &s, const Fortran_Matrix &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << "\n"; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << "\n"; + } + + + return s; +} + +template +std::istream& operator>>(std::istream &s, Fortran_Matrix &A) +{ + + Subscript M, N; + + s >> M >> N; + + if ( !(M == A.num_rows() && N == A.num_cols())) + { + A.newsize(M,N); + } + + + for (Subscript i=1; i<=M; i++) + for (Subscript j=1; j<=N; j++) + { + s >> A(i,j); + } + + + return s; +} + +// *******************[ basic matrix algorithms ]*************************** + + +template +Fortran_Matrix operator+(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Fortran_Matrix tmp(M,N); + Subscript i,j; + + for (i=1; i<=M; i++) + for (j=1; j<=N; j++) + tmp(i,j) = A(i,j) + B(i,j); + + return tmp; +} + +template +Fortran_Matrix operator-(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Fortran_Matrix tmp(M,N); + Subscript i,j; + + for (i=1; i<=M; i++) + for (j=1; j<=N; j++) + tmp(i,j) = A(i,j) - B(i,j); + + return tmp; +} + +// element-wise multiplication (use matmult() below for matrix +// multiplication in the linear algebra sense.) +// +// +template +Fortran_Matrix mult_element(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Fortran_Matrix tmp(M,N); + Subscript i,j; + + for (i=1; i<=M; i++) + for (j=1; j<=N; j++) + tmp(i,j) = A(i,j) * B(i,j); + + return tmp; +} + + +template +Fortran_Matrix transpose(const Fortran_Matrix &A) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + Fortran_Matrix S(N,M); + Subscript i, j; + + for (i=1; i<=M; i++) + for (j=1; j<=N; j++) + S(j,i) = A(i,j); + + return S; +} + + + +template +inline Fortran_Matrix matmult(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() == B.num_rows()); +#endif + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + Subscript K = B.num_cols(); + + Fortran_Matrix tmp(M,K); + T sum; + + for (Subscript i=1; i<=M; i++) + for (Subscript k=1; k<=K; k++) + { + sum = 0; + for (Subscript j=1; j<=N; j++) + sum = sum + A(i,j) * B(j,k); + + tmp(i,k) = sum; + } + + return tmp; +} + +template +inline Fortran_Matrix operator*(const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + return matmult(A,B); +} + +template +inline int matmult(Fortran_Matrix& C, const Fortran_Matrix &A, + const Fortran_Matrix &B) +{ + + assert(A.num_cols() == B.num_rows()); + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + Subscript K = B.num_cols(); + + C.newsize(M,K); // adjust shape of C, if necessary + + + T sum; + + const T* row_i; + const T* col_k; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript k=1; k<=K; k++) + { + row_i = &A(i,1); + col_k = &B(1,k); + sum = 0; + for (Subscript j=1; j<=N; j++) + { + sum += *row_i * *col_k; + row_i += M; + col_k ++; + } + + C(i,k) = sum; + } + + } + + return 0; +} + + +template +Vector matmult(const Fortran_Matrix &A, const Vector &x) +{ + +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() == x.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + Vector tmp(M); + T sum; + + for (Subscript i=1; i<=M; i++) + { + sum = 0; + for (Subscript j=1; j<=N; j++) + sum = sum + A(i,j) * x(j); + + tmp(i) = sum; + } + + return tmp; +} + +template +inline Vector operator*(const Fortran_Matrix &A, const Vector &x) +{ + return matmult(A,x); +} + +template +inline Fortran_Matrix operator*(const Fortran_Matrix &A, const T &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + Subscript MN = M*N; + + Fortran_Matrix res(M,N); + const T* a = A.begin(); + T* t = res.begin(); + T* tend = res.end(); + + for (t=res.begin(); t < tend; t++, a++) + *t = *a * x; + + return res; +} + +} // namespace TNT + +#endif // FMAT_H + diff --git a/intern/iksolver/intern/TNT/fortran.h b/intern/iksolver/intern/TNT/fortran.h new file mode 100644 index 00000000000..0837a918a0a --- /dev/null +++ b/intern/iksolver/intern/TNT/fortran.h @@ -0,0 +1,70 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Header file to define C/Fortran conventions (Platform specific) + +#ifndef FORTRAN_H +#define FORTRAN_H + +// help map between C/C++ data types and Fortran types + +typedef int Fortran_integer; +typedef float Fortran_float; +typedef double Fortran_double; + + +typedef Fortran_double *fda_; // (in/out) double precision array +typedef const Fortran_double *cfda_; // (in) double precsion array + +typedef Fortran_double *fd_; // (in/out) single double precision +typedef const Fortran_double *cfd_; // (in) single double precision + +typedef Fortran_float *ffa_; // (in/out) float precision array +typedef const Fortran_float *cffa_; // (in) float precsion array + +typedef Fortran_float *ff_; // (in/out) single float precision +typedef const Fortran_float *cff_; // (in) single float precision + +typedef Fortran_integer *fia_; // (in/out) single integer array +typedef const Fortran_integer *cfia_; // (in) single integer array + +typedef Fortran_integer *fi_; // (in/out) single integer +typedef const Fortran_integer *cfi_; // (in) single integer + +typedef char *fch_; // (in/out) single character +typedef char *cfch_; // (in) single character + + +#ifndef TNT_SUBSCRIPT_TYPE +#define TNT_SUBSCRIPT_TYPE TNT::Fortran_integer +#endif + +#endif // FORTRAN_H + diff --git a/intern/iksolver/intern/TNT/fspvec.h b/intern/iksolver/intern/TNT/fspvec.h new file mode 100644 index 00000000000..1fafccdfe93 --- /dev/null +++ b/intern/iksolver/intern/TNT/fspvec.h @@ -0,0 +1,172 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +// Templated sparse vector (Fortran conventions). +// Used primarily to interface with Fortran sparse matrix libaries. +// (CANNOT BE USED AS AN STL CONTAINER.) + +#ifndef FSPVEC_H +#define FSPVEC_H + +#include "tnt.h" +#include "vec.h" +#include +#include +#include + +using namespace std; + +namespace TNT +{ + +template +class Fortran_Sparse_Vector +{ + + + public: + + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + Vector val_; + Vector index_; + Subscript dim_; // prescribed dimension + + + public: + + // size and shape information + + Subscript dim() const { return dim_; } + Subscript num_nonzeros() const { return val_.dim(); } + + // access + + T& val(Subscript i) { return val_(i); } + const T& val(Subscript i) const { return val_(i); } + + Subscript &index(Subscript i) { return index_(i); } + const Subscript &index(Subscript i) const { return index_(i); } + + // constructors + + Fortran_Sparse_Vector() : val_(), index_(), dim_(0) {}; + Fortran_Sparse_Vector(Subscript N, Subscript nz) : val_(nz), + index_(nz), dim_(N) {}; + Fortran_Sparse_Vector(Subscript N, Subscript nz, const T *values, + const Subscript *indices): val_(nz, values), index_(nz, indices), + dim_(N) {} + + Fortran_Sparse_Vector(const Fortran_Sparse_Vector &S): + val_(S.val_), index_(S.index_), dim_(S.dim_) {} + + // initialize from string, e.g. + // + // Fortran_Sparse_Vector A(N, 2, "1.0 2.1", "1 3"); + // + Fortran_Sparse_Vector(Subscript N, Subscript nz, char *v, + char *ind) : val_(nz, v), index_(nz, ind), dim_(N) {} + + // assignments + + Fortran_Sparse_Vector & newsize(Subscript N, Subscript nz) + { + val_.newsize(nz); + index_.newsize(nz); + dim_ = N; + return *this; + } + + Fortran_Sparse_Vector & operator=( const Fortran_Sparse_Vector &A) + { + val_ = A.val_; + index_ = A.index_; + dim_ = A.dim_; + + return *this; + } + + // methods + + + +}; + + +/* *************************** I/O ********************************/ + +template +ostream& operator<<(ostream &s, const Fortran_Sparse_Vector &A) +{ + // output format is : N nz val1 ind1 val2 ind2 ... + Subscript nz=A.num_nonzeros(); + + s << A.dim() << " " << nz << endl; + + for (Subscript i=1; i<=nz; i++) + s << A.val(i) << " " << A.index(i) << endl; + s << endl; + + return s; +} + + +template +istream& operator>>(istream &s, Fortran_Sparse_Vector &A) +{ + // output format is : N nz val1 ind1 val2 ind2 ... + + Subscript N; + Subscript nz; + + s >> N >> nz; + + A.newsize(N, nz); + + for (Subscript i=1; i<=nz; i++) + s >> A.val(i) >> A.index(i); + + + return s; +} + +} // namespace TNT + +#endif // FSPVEC_H + diff --git a/intern/iksolver/intern/TNT/index.h b/intern/iksolver/intern/TNT/index.h new file mode 100644 index 00000000000..71f254e47b9 --- /dev/null +++ b/intern/iksolver/intern/TNT/index.h @@ -0,0 +1,88 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Vector/Matrix/Array Index Module + +#ifndef INDEX_H +#define INDEX_H + +#include "subscript.h" + +namespace TNT +{ + +class Index1D +{ + Subscript lbound_; + Subscript ubound_; + + public: + + Subscript lbound() const { return lbound_; } + Subscript ubound() const { return ubound_; } + + Index1D(const Index1D &D) : lbound_(D.lbound_), ubound_(D.ubound_) {} + Index1D(Subscript i1, Subscript i2) : lbound_(i1), ubound_(i2) {} + + Index1D & operator=(const Index1D &D) + { + lbound_ = D.lbound_; + ubound_ = D.ubound_; + return *this; + } + +}; + +inline Index1D operator+(const Index1D &D, Subscript i) +{ + return Index1D(i+D.lbound(), i+D.ubound()); +} + +inline Index1D operator+(Subscript i, const Index1D &D) +{ + return Index1D(i+D.lbound(), i+D.ubound()); +} + + + +inline Index1D operator-(Index1D &D, Subscript i) +{ + return Index1D(D.lbound()-i, D.ubound()-i); +} + +inline Index1D operator-(Subscript i, Index1D &D) +{ + return Index1D(i-D.lbound(), i-D.ubound()); +} + +} // namespace TNT + +#endif + diff --git a/intern/iksolver/intern/TNT/lapack.h b/intern/iksolver/intern/TNT/lapack.h new file mode 100644 index 00000000000..043400cd211 --- /dev/null +++ b/intern/iksolver/intern/TNT/lapack.h @@ -0,0 +1,190 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Header file for Fortran Lapack + +#ifndef LAPACK_H +#define LAPACK_H + +// This file incomplete and included here to only demonstrate the +// basic framework for linking with the Fortran Lapack routines. + +#include "fortran.h" +#include "vec.h" +#include "fmat.h" + + +#define F77_DGESV dgesv_ +#define F77_DGELS dgels_ +#define F77_DSYEV dsyev_ +#define F77_DGEEV dgeev_ + +extern "C" +{ + + // linear equations (general) using LU factorizaiton + // + void F77_DGESV(cfi_ N, cfi_ nrhs, fda_ A, cfi_ lda, + fia_ ipiv, fda_ b, cfi_ ldb, fi_ info); + + // solve linear least squares using QR or LU factorization + // + void F77_DGELS(cfch_ trans, cfi_ M, + cfi_ N, cfi_ nrhs, fda_ A, cfi_ lda, fda_ B, cfi_ ldb, fda_ work, + cfi_ lwork, fi_ info); + + // solve symmetric eigenvalues + // + void F77_DSYEV( cfch_ jobz, cfch_ uplo, cfi_ N, fda_ A, cfi_ lda, + fda_ W, fda_ work, cfi_ lwork, fi_ info); + + // solve unsymmetric eigenvalues + // + void F77_DGEEV(cfch_ jobvl, cfch_ jobvr, cfi_ N, fda_ A, cfi_ lda, + fda_ wr, fda_ wi, fda_ vl, cfi_ ldvl, fda_ vr, + cfi_ ldvr, fda_ work, cfi_ lwork, fi_ info); + +} + +// solve linear equations using LU factorization + +using namespace TNT; + +Vector Lapack_LU_linear_solve(const Fortran_Matrix &A, + const Vector &b) +{ + const Fortran_integer one=1; + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + Fortran_Matrix Tmp(A); + Vector x(b); + Vector index(M); + Fortran_integer info = 0; + + F77_DGESV(&N, &one, &Tmp(1,1), &M, &index(1), &x(1), &M, &info); + + if (info != 0) return Vector(0); + else + return x; +} + +// solve linear least squares problem using QR factorization +// +Vector Lapack_LLS_QR_linear_solve(const Fortran_Matrix &A, + const Vector &b) +{ + const Fortran_integer one=1; + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + Fortran_Matrix Tmp(A); + Vector x(b); + Fortran_integer info = 0; + + char transp = 'N'; + Fortran_integer lwork = 5 * (M+N); // temporary work space + Vector work(lwork); + + F77_DGELS(&transp, &M, &N, &one, &Tmp(1,1), &M, &x(1), &M, &work(1), + &lwork, &info); + + if (info != 0) return Vector(0); + else + return x; +} + +// *********************** Eigenvalue problems ******************* + +// solve symmetric eigenvalue problem (eigenvalues only) +// +Vector Upper_symmetric_eigenvalue_solve(const Fortran_Matrix &A) +{ + char jobz = 'N'; + char uplo = 'U'; + Subscript N = A.num_rows(); + + assert(N == A.num_cols()); + + Vector eigvals(N); + Fortran_integer worksize = 3*N; + Fortran_integer info = 0; + Vector work(worksize); + Fortran_Matrix Tmp = A; + + F77_DSYEV(&jobz, &uplo, &N, &Tmp(1,1), &N, eigvals.begin(), work.begin(), + &worksize, &info); + + if (info != 0) return Vector(); + else + return eigvals; +} + + +// solve unsymmetric eigenvalue problems +// +int eigenvalue_solve(const Fortran_Matrix &A, + Vector &wr, Vector &wi) +{ + char jobvl = 'N'; + char jobvr = 'N'; + + Fortran_integer N = A.num_rows(); + + + assert(N == A.num_cols()); + + if (N<1) return 1; + + Fortran_Matrix vl(1,N); /* should be NxN ? **** */ + Fortran_Matrix vr(1,N); + Fortran_integer one = 1; + + Fortran_integer worksize = 5*N; + Fortran_integer info = 0; + Vector work(worksize, 0.0); + Fortran_Matrix Tmp = A; + + wr.newsize(N); + wi.newsize(N); + +// void F77_DGEEV(cfch_ jobvl, cfch_ jobvr, cfi_ N, fda_ A, cfi_ lda, +// fda_ wr, fda_ wi, fda_ vl, cfi_ ldvl, fda_ vr, +// cfi_ ldvr, fda_ work, cfi_ lwork, fi_ info); + + F77_DGEEV(&jobvl, &jobvr, &N, &Tmp(1,1), &N, &(wr(1)), + &(wi(1)), &(vl(1,1)), &one, &(vr(1,1)), &one, + &(work(1)), &worksize, &info); + + return (info==0 ? 0: 1); +} + +#endif // LAPACK_H + diff --git a/intern/iksolver/intern/TNT/lu.h b/intern/iksolver/intern/TNT/lu.h new file mode 100644 index 00000000000..40b474bb532 --- /dev/null +++ b/intern/iksolver/intern/TNT/lu.h @@ -0,0 +1,209 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +#ifndef LU_H +#define LU_H + +// Solve system of linear equations Ax = b. +// +// Typical usage: +// +// Matrix(double) A; +// Vector(Subscript) ipiv; +// Vector(double) b; +// +// 1) LU_Factor(A,ipiv); +// 2) LU_Solve(A,ipiv,b); +// +// Now b has the solution x. Note that both A and b +// are overwritten. If these values need to be preserved, +// one can make temporary copies, as in +// +// O) Matrix(double) T = A; +// 1) LU_Factor(T,ipiv); +// 1a) Vector(double) x=b; +// 2) LU_Solve(T,ipiv,x); +// +// See details below. +// + + +// for fabs() +// +#include + +// right-looking LU factorization algorithm (unblocked) +// +// Factors matrix A into lower and upper triangular matrices +// (L and U respectively) in solving the linear equation Ax=b. +// +// +// Args: +// +// A (input/output) Matrix(1:n, 1:n) In input, matrix to be +// factored. On output, overwritten with lower and +// upper triangular factors. +// +// indx (output) Vector(1:n) Pivot vector. Describes how +// the rows of A were reordered to increase +// numerical stability. +// +// Return value: +// +// int (0 if successful, 1 otherwise) +// +// + + +namespace TNT +{ + +template +int LU_factor( MaTRiX &A, VecToRSubscript &indx) +{ + assert(A.lbound() == 1); // currently for 1-offset + assert(indx.lbound() == 1); // vectors and matrices + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + if (M == 0 || N==0) return 0; + if (indx.dim() != M) + indx.newsize(M); + + Subscript i=0,j=0,k=0; + Subscript jp=0; + + typename MaTRiX::element_type t; + + Subscript minMN = (M < N ? M : N) ; // min(M,N); + + for (j=1; j<= minMN; j++) + { + + // find pivot in column j and test for singularity. + + jp = j; + t = fabs(A(j,j)); + for (i=j+1; i<=M; i++) + if ( fabs(A(i,j)) > t) + { + jp = i; + t = fabs(A(i,j)); + } + + indx(j) = jp; + + // jp now has the index of maximum element + // of column j, below the diagonal + + if ( A(jp,j) == 0 ) + return 1; // factorization failed because of zero pivot + + + if (jp != j) // swap rows j and jp + for (k=1; k<=N; k++) + { + t = A(j,k); + A(j,k) = A(jp,k); + A(jp,k) =t; + } + + if (j +int LU_solve(const MaTRiX &A, const VecToRSubscripts &indx, VecToR &b) +{ + assert(A.lbound() == 1); // currently for 1-offset + assert(indx.lbound() == 1); // vectors and matrices + assert(b.lbound() == 1); + + Subscript i,ii=0,ip,j; + Subscript n = b.dim(); + typename MaTRiX::element_type sum = 0.0; + + for (i=1;i<=n;i++) + { + ip=indx(i); + sum=b(ip); + b(ip)=b(i); + if (ii) + for (j=ii;j<=i-1;j++) + sum -= A(i,j)*b(j); + else if (sum) ii=i; + b(i)=sum; + } + for (i=n;i>=1;i--) + { + sum=b(i); + for (j=i+1;j<=n;j++) + sum -= A(i,j)*b(j); + b(i)=sum/A(i,i); + } + + return 0; +} + +} // namespace TNT + +#endif // LU_H + diff --git a/intern/iksolver/intern/TNT/qr.h b/intern/iksolver/intern/TNT/qr.h new file mode 100644 index 00000000000..954dad468af --- /dev/null +++ b/intern/iksolver/intern/TNT/qr.h @@ -0,0 +1,234 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +#ifndef QR_H +#define QR_H + +// Classical QR factorization example, based on Stewart[1973]. +// +// +// This algorithm computes the factorization of a matrix A +// into a product of an orthognal matrix (Q) and an upper triangular +// matrix (R), such that QR = A. +// +// Parameters: +// +// A (in): Matrix(1:N, 1:N) +// +// Q (output): Matrix(1:N, 1:N), collection of Householder +// column vectors Q1, Q2, ... QN +// +// R (output): upper triangular Matrix(1:N, 1:N) +// +// Returns: +// +// 0 if successful, 1 if A is detected to be singular +// + + +#include //for sqrt() & fabs() +#include "tntmath.h" // for sign() + +// Classical QR factorization, based on Stewart[1973]. +// +// +// This algorithm computes the factorization of a matrix A +// into a product of an orthognal matrix (Q) and an upper triangular +// matrix (R), such that QR = A. +// +// Parameters: +// +// A (in/out): On input, A is square, Matrix(1:N, 1:N), that represents +// the matrix to be factored. +// +// On output, Q and R is encoded in the same Matrix(1:N,1:N) +// in the following manner: +// +// R is contained in the upper triangular section of A, +// except that R's main diagonal is in D. The lower +// triangular section of A represents Q, where each +// column j is the vector Qj = I - uj*uj'/pi_j. +// +// C (output): vector of Pi[j] +// D (output): main diagonal of R, i.e. D(i) is R(i,i) +// +// Returns: +// +// 0 if successful, 1 if A is detected to be singular +// + +namespace TNT +{ + +template +int QR_factor(MaTRiX &A, Vector& C, Vector &D) +{ + assert(A.lbound() == 1); // ensure these are all + assert(C.lbound() == 1); // 1-based arrays and vectors + assert(D.lbound() == 1); + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M == N); // make sure A is square + + Subscript i,j,k; + typename MaTRiX::element_type eta, sigma, sum; + + // adjust the shape of C and D, if needed... + + if (N != C.size()) C.newsize(N); + if (N != D.size()) D.newsize(N); + + for (k=1; k eta ? absA : eta ); + } + + if (eta == 0) // matrix is singular + { + cerr << "QR: k=" << k << "\n"; + return 1; + } + + // form Qk and premiltiply M by it + // + for(i=k; i<=N; i++) + A(i,k) = A(i,k) / eta; + + sum = 0; + for (i=k; i<=N; i++) + sum = sum + A(i,k)*A(i,k); + sigma = sign(A(k,k)) * sqrt(sum); + + + A(k,k) = A(k,k) + sigma; + C(k) = sigma * A(k,k); + D(k) = -eta * sigma; + + for (j=k+1; j<=N; j++) + { + sum = 0; + for (i=k; i<=N; i++) + sum = sum + A(i,k)*A(i,j); + sum = sum / C(k); + + for (i=k; i<=N; i++) + A(i,j) = A(i,j) - sum * A(i,k); + } + + D(N) = A(N,N); + } + + return 0; +} + +// modified form of upper triangular solve, except that the main diagonal +// of R (upper portion of A) is in D. +// +template +int R_solve(const MaTRiX &A, /*const*/ Vector &D, Vector &b) +{ + assert(A.lbound() == 1); // ensure these are all + assert(D.lbound() == 1); // 1-based arrays and vectors + assert(b.lbound() == 1); + + Subscript i,j; + Subscript N = A.num_rows(); + + assert(N == A.num_cols()); + assert(N == D.dim()); + assert(N == b.dim()); + + typename MaTRiX::element_type sum; + + if (D(N) == 0) + return 1; + + b(N) = b(N) / + D(N); + + for (i=N-1; i>=1; i--) + { + if (D(i) == 0) + return 1; + sum = 0; + for (j=i+1; j<=N; j++) + sum = sum + A(i,j)*b(j); + b(i) = ( b(i) - sum ) / + D(i); + } + + return 0; +} + + +template +int QR_solve(const MaTRiX &A, const Vector &c, /*const*/ Vector &d, + Vector &b) +{ + assert(A.lbound() == 1); // ensure these are all + assert(c.lbound() == 1); // 1-based arrays and vectors + assert(d.lbound() == 1); + + Subscript N=A.num_rows(); + + assert(N == A.num_cols()); + assert(N == c.dim()); + assert(N == d.dim()); + assert(N == b.dim()); + + Subscript i,j; + typename MaTRiX::element_type sum, tau; + + for (j=1; j +#include + +namespace TNT +{ + +template +class const_Region1D; + +template +class Region1D +{ + protected: + + Array1D & A_; + Subscript offset_; // 0-based + Subscript dim_; + + typedef typename Array1D::element_type T; + + public: + const Array1D & array() const { return A_; } + + Subscript offset() const { return offset_;} + Subscript dim() const { return dim_; } + + Subscript offset(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(i==TNT_BASE_OFFSET); +#endif + return offset_; + } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(i== TNT_BASE_OFFSET); +#endif + return offset_; + } + + + Region1D(Array1D &A, Subscript i1, Subscript i2) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1 ); + assert(i2 <= A.dim() + (TNT_BASE_OFFSET-1)); + assert(i1 <= i2); +#endif + offset_ = i1 - TNT_BASE_OFFSET; + dim_ = i2-i1 + 1; + } + + Region1D(Array1D &A, const Index1D &I) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <=I.lbound()); + assert(I.ubound() <= A.dim() + (TNT_BASE_OFFSET-1)); + assert(I.lbound() <= I.ubound()); +#endif + offset_ = I.lbound() - TNT_BASE_OFFSET; + dim_ = I.ubound() - I.lbound() + 1; + } + + Region1D(Region1D &A, Subscript i1, Subscript i2) : + A_(A.A_) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1 ); + assert(i2 <= A.dim() + (TNT_BASE_OFFSET - 1)); + assert(i1 <= i2); +#endif + // (old-offset) (new-offset) + // + offset_ = (i1 - TNT_BASE_OFFSET) + A.offset_; + dim_ = i2-i1 + 1; + } + + Region1D operator()(Subscript i1, Subscript i2) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1); + assert(i2 <= dim() + (TNT_BASE_OFFSET -1)); + assert(i1 <= i2); +#endif + // offset_ is 0-based, so no need for + // ( - TNT_BASE_OFFSET) + // + return Region1D(A_, i1+offset_, + offset_ + i2); + } + + + Region1D operator()(const Index1D &I) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET<=I.lbound()); + assert(I.ubound() <= dim() + (TNT_BASE_OFFSET-1)); + assert(I.lbound() <= I.ubound()); +#endif + return Region1D(A_, I.lbound()+offset_, + offset_ + I.ubound()); + } + + + + + T & operator()(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i); + assert(i <= dim() + (TNT_BASE_OFFSET-1)); +#endif + return A_(i+offset_); + } + + const T & operator() (Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i); + assert(i <= dim() + (TNT_BASE_OFFSET-1)); +#endif + return A_(i+offset_); + } + + + Region1D & operator=(const Region1D &R) + { + // make sure both sides conform + assert(dim() == R.dim()); + + Subscript N = dim(); + Subscript i; + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = istart + N-1; + + for (i=istart; i<=iend; i++) + (*this)(i) = R(i); + + return *this; + } + + + + Region1D & operator=(const const_Region1D &R) + { + // make sure both sides conform + assert(dim() == R.dim()); + + Subscript N = dim(); + Subscript i; + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = istart + N-1; + + for (i=istart; i<=iend; i++) + (*this)(i) = R(i); + + return *this; + + } + + + Region1D & operator=(const T& t) + { + Subscript N=dim(); + Subscript i; + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = istart + N-1; + + for (i=istart; i<= iend; i++) + (*this)(i) = t; + + return *this; + + } + + + Region1D & operator=(const Array1D &R) + { + // make sure both sides conform + Subscript N = dim(); + assert(dim() == R.dim()); + + Subscript i; + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = istart + N-1; + + for (i=istart; i<=iend; i++) + (*this)(i) = R(i); + + return *this; + + } + +}; + +template +std::ostream& operator<<(std::ostream &s, Region1D &A) +{ + Subscript N=A.dim(); + Subscript istart = TNT_BASE_OFFSET; + Subscript iend = N - 1 + TNT_BASE_OFFSET; + + for (Subscript i=istart; i<=iend; i++) + s << A(i) << endl; + + return s; +} + + +/* --------- class const_Region1D ------------ */ + +template +class const_Region1D +{ + protected: + + const Array1D & A_; + Subscript offset_; // 0-based + Subscript dim_; + typedef typename Array1D::element_type T; + + public: + const Array1D & array() const { return A_; } + + Subscript offset() const { return offset_;} + Subscript dim() const { return dim_; } + + Subscript offset(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(i==TNT_BASE_OFFSET); +#endif + return offset_; + } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(i== TNT_BASE_OFFSET); +#endif + return offset_; + } + + + const_Region1D(const Array1D &A, Subscript i1, Subscript i2) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1 ); + assert(i2 <= A.dim() + (TNT_BASE_OFFSET-1)); + assert(i1 <= i2); +#endif + offset_ = i1 - TNT_BASE_OFFSET; + dim_ = i2-i1 + 1; + } + + const_Region1D(const Array1D &A, const Index1D &I) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <=I.lbound()); + assert(I.ubound() <= A.dim() + (TNT_BASE_OFFSET-1)); + assert(I.lbound() <= I.ubound()); +#endif + offset_ = I.lbound() - TNT_BASE_OFFSET; + dim_ = I.ubound() - I.lbound() + 1; + } + + const_Region1D(const_Region1D &A, Subscript i1, Subscript i2) : + A_(A.A_) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1 ); + assert(i2 <= A.dim() + (TNT_BASE_OFFSET - 1)); + assert(i1 <= i2); +#endif + // (old-offset) (new-offset) + // + offset_ = (i1 - TNT_BASE_OFFSET) + A.offset_; + dim_ = i2-i1 + 1; + } + + const_Region1D operator()(Subscript i1, Subscript i2) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i1); + assert(i2 <= dim() + (TNT_BASE_OFFSET -1)); + assert(i1 <= i2); +#endif + // offset_ is 0-based, so no need for + // ( - TNT_BASE_OFFSET) + // + return const_Region1D(A_, i1+offset_, + offset_ + i2); + } + + + const_Region1D operator()(const Index1D &I) + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET<=I.lbound()); + assert(I.ubound() <= dim() + (TNT_BASE_OFFSET-1)); + assert(I.lbound() <= I.ubound()); +#endif + return const_Region1D(A_, I.lbound()+offset_, + offset_ + I.ubound()); + } + + + const T & operator() (Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(TNT_BASE_OFFSET <= i); + assert(i <= dim() + (TNT_BASE_OFFSET-1)); +#endif + return A_(i+offset_); + } + + + + +}; + +template +std::ostream& operator<<(std::ostream &s, const_Region1D &A) +{ + Subscript N=A.dim(); + + for (Subscript i=1; i<=N; i++) + s << A(i) << endl; + + return s; +} + + +} // namespace TNT + +#endif // const_Region1D_H + diff --git a/intern/iksolver/intern/TNT/region2d.h b/intern/iksolver/intern/TNT/region2d.h new file mode 100644 index 00000000000..364edd76689 --- /dev/null +++ b/intern/iksolver/intern/TNT/region2d.h @@ -0,0 +1,472 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +// 2D Regions for arrays and matrices + +#ifndef REGION2D_H +#define REGION2D_H + +#include "index.h" +#include +#include + +namespace TNT +{ + +template +class const_Region2D; + + +template +class Region2D +{ + protected: + + Array2D & A_; + Subscript offset_[2]; // 0-offset internally + Subscript dim_[2]; + + public: + typedef typename Array2D::value_type T; + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Array2D & array() { return A_; } + const Array2D & array() const { return A_; } + Subscript lbound() const { return A_.lbound(); } + Subscript num_rows() const { return dim_[0]; } + Subscript num_cols() const { return dim_[1]; } + Subscript offset(Subscript i) const // 1-offset + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= dim_[0] + A_.lbound()-1); +#endif + return offset_[i-A_.lbound()]; + } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= dim_[0] + A_.lbound()-1); +#endif + return dim_[i-A_.lbound()]; + } + + + + Region2D(Array2D &A, Subscript i1, Subscript i2, Subscript j1, + Subscript j2) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( A.lbound() <= i1); + assert( i2<= A.dim(A.lbound()) + A.lbound()-1); + assert( A.lbound() <= j1); + assert( j2<= A.dim(A.lbound()+1) + A.lbound()-1 ); +#endif + + + offset_[0] = i1-A.lbound(); + offset_[1] = j1-A.lbound(); + dim_[0] = i2-i1+1; + dim_[1] = j2-j1+1; + } + + Region2D(Array2D &A, const Index1D &I, const Index1D &J) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert( I.lbound() <= I.ubound() ); + assert( J.lbound() <= J.ubound() ); + assert( A.lbound() <= I.lbound()); + assert( I.ubound()<= A.dim(A.lbound()) + A.lbound()-1); + assert( A.lbound() <= J.lbound()); + assert( J.ubound() <= A.dim(A.lbound()+1) + A.lbound()-1 ); +#endif + + offset_[0] = I.lbound()-A.lbound(); + offset_[1] = J.lbound()-A.lbound(); + dim_[0] = I.ubound() - I.lbound() + 1; + dim_[1] = J.ubound() - J.lbound() + 1; + } + + Region2D(Region2D &A, Subscript i1, Subscript i2, + Subscript j1, Subscript j2) : A_(A.A_) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( A.lbound() <= i1); + assert( i2<= A.dim(A.lbound()) + A.lbound()-1); + assert( A.lbound() <= j1); + assert( j2<= A.dim(A.lbound()+1) + A.lbound()-1 ); +#endif + offset_[0] = (i1 - A.lbound()) + A.offset_[0]; + offset_[1] = (j1 - A.lbound()) + A.offset_[1]; + dim_[0] = i2-i1 + 1; + dim_[1] = j2-j1+1; + } + + Region2D operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( A_.lbound() <= i1); + assert( i2<= dim_[0] + A_.lbound()-1); + assert( A_.lbound() <= j1); + assert( j2<= dim_[1] + A_.lbound()-1 ); +#endif + return Region2D(A_, + i1+offset_[0], offset_[0] + i2, + j1+offset_[1], offset_[1] + j2); + } + + + Region2D operator()(const Index1D &I, + const Index1D &J) + { +#ifdef TNT_BOUNDS_CHECK + assert( I.lbound() <= I.ubound() ); + assert( J.lbound() <= J.ubound() ); + assert( A_.lbound() <= I.lbound()); + assert( I.ubound()<= dim_[0] + A_.lbound()-1); + assert( A_.lbound() <= J.lbound()); + assert( J.ubound() <= dim_[1] + A_.lbound()-1 ); +#endif + + return Region2D(A_, I.lbound()+offset_[0], + offset_[0] + I.ubound(), offset_[1]+J.lbound(), + offset_[1] + J.ubound()); + } + + inline T & operator()(Subscript i, Subscript j) + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= dim_[0] + A_.lbound()-1); + assert( A_.lbound() <= j); + assert( j<= dim_[1] + A_.lbound()-1 ); +#endif + return A_(i+offset_[0], j+offset_[1]); + } + + inline const T & operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= dim_[0] + A_.lbound()-1); + assert( A_.lbound() <= j); + assert( j<= dim_[1] + A_.lbound()-1 ); +#endif + return A_(i+offset_[0], j+offset_[1]); + } + + + Region2D & operator=(const Region2D &R) + { + Subscript M = num_rows(); + Subscript N = num_cols(); + + // make sure both sides conform + assert(M == R.num_rows()); + assert(N == R.num_cols()); + + + Subscript start = R.lbound(); + Subscript Mend = start + M - 1; + Subscript Nend = start + N - 1; + for (Subscript i=start; i<=Mend; i++) + for (Subscript j=start; j<=Nend; j++) + (*this)(i,j) = R(i,j); + + return *this; + } + + Region2D & operator=(const const_Region2D &R) + { + Subscript M = num_rows(); + Subscript N = num_cols(); + + // make sure both sides conform + assert(M == R.num_rows()); + assert(N == R.num_cols()); + + + Subscript start = R.lbound(); + Subscript Mend = start + M - 1; + Subscript Nend = start + N - 1; + for (Subscript i=start; i<=Mend; i++) + for (Subscript j=start; j<=Nend; j++) + (*this)(i,j) = R(i,j); + + return *this; + } + + Region2D & operator=(const Array2D &R) + { + Subscript M = num_rows(); + Subscript N = num_cols(); + + // make sure both sides conform + assert(M == R.num_rows()); + assert(N == R.num_cols()); + + + Subscript start = R.lbound(); + Subscript Mend = start + M - 1; + Subscript Nend = start + N - 1; + for (Subscript i=start; i<=Mend; i++) + for (Subscript j=start; j<=Nend; j++) + (*this)(i,j) = R(i,j); + + return *this; + } + + Region2D & operator=(const T &scalar) + { + Subscript start = lbound(); + Subscript Mend = lbound() + num_rows() - 1; + Subscript Nend = lbound() + num_cols() - 1; + + + for (Subscript i=start; i<=Mend; i++) + for (Subscript j=start; j<=Nend; j++) + (*this)(i,j) = scalar; + + return *this; + } + +}; + +//************************ + +template +class const_Region2D +{ + protected: + + const Array2D & A_; + Subscript offset_[2]; // 0-offset internally + Subscript dim_[2]; + + public: + typedef typename Array2D::value_type T; + typedef T value_type; + typedef T element_type; + typedef const T* const_iterator; + typedef const T& const_reference; + + const Array2D & array() const { return A_; } + Subscript lbound() const { return A_.lbound(); } + Subscript num_rows() const { return dim_[0]; } + Subscript num_cols() const { return dim_[1]; } + Subscript offset(Subscript i) const // 1-offset + { +#ifdef TNT_BOUNDS_CHECK + assert( TNT_BASE_OFFSET <= i); + assert( i<= dim_[0] + TNT_BASE_OFFSET-1); +#endif + return offset_[i-TNT_BASE_OFFSET]; + } + + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert( TNT_BASE_OFFSET <= i); + assert( i<= dim_[0] + TNT_BASE_OFFSET-1); +#endif + return dim_[i-TNT_BASE_OFFSET]; + } + + + const_Region2D(const Array2D &A, Subscript i1, Subscript i2, + Subscript j1, Subscript j2) : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( TNT_BASE_OFFSET <= i1); + assert( i2<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= j1); + assert( j2<= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); +#endif + + offset_[0] = i1-TNT_BASE_OFFSET; + offset_[1] = j1-TNT_BASE_OFFSET; + dim_[0] = i2-i1+1; + dim_[1] = j2-j1+1; + } + + const_Region2D(const Array2D &A, const Index1D &I, const Index1D &J) + : A_(A) + { +#ifdef TNT_BOUNDS_CHECK + assert( I.lbound() <= I.ubound() ); + assert( J.lbound() <= J.ubound() ); + assert( TNT_BASE_OFFSET <= I.lbound()); + assert( I.ubound()<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= J.lbound()); + assert( J.ubound() <= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); +#endif + + offset_[0] = I.lbound()-TNT_BASE_OFFSET; + offset_[1] = J.lbound()-TNT_BASE_OFFSET; + dim_[0] = I.ubound() - I.lbound() + 1; + dim_[1] = J.ubound() - J.lbound() + 1; + } + + + const_Region2D(const_Region2D &A, Subscript i1, + Subscript i2, + Subscript j1, Subscript j2) : A_(A.A_) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( TNT_BASE_OFFSET <= i1); + assert( i2<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= j1); + assert( j2<= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); +#endif + offset_[0] = (i1 - TNT_BASE_OFFSET) + A.offset_[0]; + offset_[1] = (j1 - TNT_BASE_OFFSET) + A.offset_[1]; + dim_[0] = i2-i1 + 1; + dim_[1] = j2-j1+1; + } + + const_Region2D operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) + { +#ifdef TNT_BOUNDS_CHECK + assert( i1 <= i2 ); + assert( j1 <= j2); + assert( TNT_BASE_OFFSET <= i1); + assert( i2<= dim_[0] + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= j1); + assert( j2<= dim_[0] + TNT_BASE_OFFSET-1 ); +#endif + return const_Region2D(A_, + i1+offset_[0], offset_[0] + i2, + j1+offset_[1], offset_[1] + j2); + } + + + const_Region2D operator()(const Index1D &I, + const Index1D &J) + { +#ifdef TNT_BOUNDS_CHECK + assert( I.lbound() <= I.ubound() ); + assert( J.lbound() <= J.ubound() ); + assert( TNT_BASE_OFFSET <= I.lbound()); + assert( I.ubound()<= dim_[0] + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= J.lbound()); + assert( J.ubound() <= dim_[1] + TNT_BASE_OFFSET-1 ); +#endif + + return const_Region2D(A_, I.lbound()+offset_[0], + offset_[0] + I.ubound(), offset_[1]+J.lbound(), + offset_[1] + J.ubound()); + } + + + inline const T & operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert( TNT_BASE_OFFSET <= i); + assert( i<= dim_[0] + TNT_BASE_OFFSET-1); + assert( TNT_BASE_OFFSET <= j); + assert( j<= dim_[1] + TNT_BASE_OFFSET-1 ); +#endif + return A_(i+offset_[0], j+offset_[1]); + } + +}; + + +// ************** std::ostream algorithms ******************************* + +template +std::ostream& operator<<(std::ostream &s, const const_Region2D &A) +{ + Subscript start = A.lbound(); + Subscript Mend=A.lbound()+ A.num_rows() - 1; + Subscript Nend=A.lbound() + A.num_cols() - 1; + + + s << A.num_rows() << " " << A.num_cols() << "\n"; + for (Subscript i=start; i<=Mend; i++) + { + for (Subscript j=start; j<=Nend; j++) + { + s << A(i,j) << " "; + } + s << "\n"; + } + + + return s; +} + +template +std::ostream& operator<<(std::ostream &s, const Region2D &A) +{ + Subscript start = A.lbound(); + Subscript Mend=A.lbound()+ A.num_rows() - 1; + Subscript Nend=A.lbound() + A.num_cols() - 1; + + + s << A.num_rows() << " " << A.num_cols() << "\n"; + for (Subscript i=start; i<=Mend; i++) + { + for (Subscript j=start; j<=Nend; j++) + { + s << A(i,j) << " "; + } + s << "\n"; + } + + + return s; + +} + +} // namespace TNT + +#endif // REGION2D_H + diff --git a/intern/iksolver/intern/TNT/stopwatch.h b/intern/iksolver/intern/TNT/stopwatch.h new file mode 100644 index 00000000000..30cc0fd1641 --- /dev/null +++ b/intern/iksolver/intern/TNT/stopwatch.h @@ -0,0 +1,84 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + +#ifndef STPWATCH_H +#define STPWATCH_H + +// for clock() and CLOCKS_PER_SEC +#include + +namespace TNT +{ + +/* Simple stopwatch object: + + void start() : start timing + double stop() : stop timing + void reset() : set elapsed time to 0.0 + double read() : read elapsed time (in seconds) + +*/ + +inline double seconds(void) +{ + static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC; + return ( (double) clock() ) * secs_per_tick; +} + + +class stopwatch { + private: + int running; + double last_time; + double total; + + public: + stopwatch() : running(0), last_time(0.0), total(0.0) {} + void reset() { running = 0; last_time = 0.0; total=0.0; } + void start() { if (!running) { last_time = seconds(); running = 1;}} + double stop() { if (running) + { + total += seconds() - last_time; + running = 0; + } + return total; + } + double read() { if (running) + { + total+= seconds() - last_time; + last_time = seconds(); + } + return total; + } + +}; + +} // namespace TNT + +#endif + diff --git a/intern/iksolver/intern/TNT/subscript.h b/intern/iksolver/intern/TNT/subscript.h new file mode 100644 index 00000000000..d9e037c43fd --- /dev/null +++ b/intern/iksolver/intern/TNT/subscript.h @@ -0,0 +1,64 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +#ifndef SUBSCRPT_H +#define SUBSCRPT_H + + +//--------------------------------------------------------------------- +// This definition describes the default TNT data type used for +// indexing into TNT matrices and vectors. The data type should +// be wide enough to index into large arrays. It defaults to an +// "int", but can be overriden at compile time redefining TNT_SUBSCRIPT_TYPE, +// e.g. +// +// g++ -DTNT_SUBSCRIPT_TYPE='unsigned int' ... +// +//--------------------------------------------------------------------- +// + +#ifndef TNT_SUBSCRIPT_TYPE +#define TNT_SUBSCRIPT_TYPE int +#endif + +namespace TNT +{ + typedef TNT_SUBSCRIPT_TYPE Subscript; +} + + +// () indexing in TNT means 1-offset, i.e. x(1) and A(1,1) are the +// first elements. This offset is left as a macro for future +// purposes, but should not be changed in the current release. +// +// +#define TNT_BASE_OFFSET (1) + +#endif + diff --git a/intern/iksolver/intern/TNT/svd.h b/intern/iksolver/intern/TNT/svd.h new file mode 100644 index 00000000000..af281d0fce0 --- /dev/null +++ b/intern/iksolver/intern/TNT/svd.h @@ -0,0 +1,429 @@ +/** + * $Id$ + */ + +#ifndef SVD_H + +#define SVD_H + +// Compute the Single Value Decomposition of an arbitrary matrix A +// That is compute the 3 matrices U,W,V with U column orthogonal (m,n) +// ,W a diagonal matrix and V an orthogonal square matrix s.t. +// A = U.W.Vt. From this decomposition it is trivial to compute the +// inverse of A as Ainv = V.Winv.tranpose(U). +// +// s = diagonal elements of W +// work1 = workspace, length must be A.num_rows +// work2 = workspace, length must be A.num_cols + +#include "tntmath.h" + +namespace TNT +{ + +template +void SVD(MaTRiX &A, MaTRiX &U, VecToR &s, MaTRiX &V, VecToR &work1, VecToR &work2) { + + int m = A.num_rows(); + int n = A.num_cols(); + int nu = min(m,n); + + VecToR& work = work1; + VecToR& e = work2; + + U = 0; + s = 0; + + int i=0, j=0, k=0; + + // Reduce A to bidiagonal form, storing the diagonal elements + // in s and the super-diagonal elements in e. + + int nct = min(m-1,n); + int nrt = max(0,min(n-2,m)); + for (k = 0; k < max(nct,nrt); k++) { + if (k < nct) { + + // Compute the transformation for the k-th column and + // place the k-th diagonal in s[k]. + // Compute 2-norm of k-th column without under/overflow. + s[k] = 0; + for (i = k; i < m; i++) { + s[k] = hypot(s[k],A[i][k]); + } + if (s[k] != 0.0) { + if (A[k][k] < 0.0) { + s[k] = -s[k]; + } + for (i = k; i < m; i++) { + A[i][k] /= s[k]; + } + A[k][k] += 1.0; + } + s[k] = -s[k]; + } + for (j = k+1; j < n; j++) { + if ((k < nct) && (s[k] != 0.0)) { + + // Apply the transformation. + + typename MaTRiX::value_type t = 0; + for (i = k; i < m; i++) { + t += A[i][k]*A[i][j]; + } + t = -t/A[k][k]; + for (i = k; i < m; i++) { + A[i][j] += t*A[i][k]; + } + } + + // Place the k-th row of A into e for the + // subsequent calculation of the row transformation. + + e[j] = A[k][j]; + } + if (k < nct) { + + // Place the transformation in U for subsequent back + // multiplication. + + for (i = k; i < m; i++) + U[i][k] = A[i][k]; + } + if (k < nrt) { + + // Compute the k-th row transformation and place the + // k-th super-diagonal in e[k]. + // Compute 2-norm without under/overflow. + e[k] = 0; + for (i = k+1; i < n; i++) { + e[k] = hypot(e[k],e[i]); + } + if (e[k] != 0.0) { + if (e[k+1] < 0.0) { + e[k] = -e[k]; + } + for (i = k+1; i < n; i++) { + e[i] /= e[k]; + } + e[k+1] += 1.0; + } + e[k] = -e[k]; + if ((k+1 < m) & (e[k] != 0.0)) { + + // Apply the transformation. + + for (i = k+1; i < m; i++) { + work[i] = 0.0; + } + for (j = k+1; j < n; j++) { + for (i = k+1; i < m; i++) { + work[i] += e[j]*A[i][j]; + } + } + for (j = k+1; j < n; j++) { + typename MaTRiX::value_type t = -e[j]/e[k+1]; + for (i = k+1; i < m; i++) { + A[i][j] += t*work[i]; + } + } + } + + // Place the transformation in V for subsequent + // back multiplication. + + for (i = k+1; i < n; i++) + V[i][k] = e[i]; + } + } + + // Set up the final bidiagonal matrix or order p. + + int p = min(n,m+1); + if (nct < n) { + s[nct] = A[nct][nct]; + } + if (m < p) { + s[p-1] = 0.0; + } + if (nrt+1 < p) { + e[nrt] = A[nrt][p-1]; + } + e[p-1] = 0.0; + + // If required, generate U. + + for (j = nct; j < nu; j++) { + for (i = 0; i < m; i++) { + U[i][j] = 0.0; + } + U[j][j] = 1.0; + } + for (k = nct-1; k >= 0; k--) { + if (s[k] != 0.0) { + for (j = k+1; j < nu; j++) { + typename MaTRiX::value_type t = 0; + for (i = k; i < m; i++) { + t += U[i][k]*U[i][j]; + } + t = -t/U[k][k]; + for (i = k; i < m; i++) { + U[i][j] += t*U[i][k]; + } + } + for (i = k; i < m; i++ ) { + U[i][k] = -U[i][k]; + } + U[k][k] = 1.0 + U[k][k]; + for (i = 0; i < k-1; i++) { + U[i][k] = 0.0; + } + } else { + for (i = 0; i < m; i++) { + U[i][k] = 0.0; + } + U[k][k] = 1.0; + } + } + + // If required, generate V. + + for (k = n-1; k >= 0; k--) { + if ((k < nrt) & (e[k] != 0.0)) { + for (j = k+1; j < nu; j++) { + typename MaTRiX::value_type t = 0; + for (i = k+1; i < n; i++) { + t += V[i][k]*V[i][j]; + } + t = -t/V[k+1][k]; + for (i = k+1; i < n; i++) { + V[i][j] += t*V[i][k]; + } + } + } + for (i = 0; i < n; i++) { + V[i][k] = 0.0; + } + V[k][k] = 1.0; + } + + // Main iteration loop for the singular values. + + int pp = p-1; + int iter = 0; + typename MaTRiX::value_type eps = pow(2.0,-52.0); + while (p > 0) { + int kase=0; + k=0; + + // Here is where a test for too many iterations would go. + + // This section of the program inspects for + // negligible elements in the s and e arrays. On + // completion the variables kase and k are set as follows. + + // kase = 1 if s(p) and e[k-1] are negligible and k

= -1; k--) { + if (k == -1) { + break; + } + if (TNT::abs(e[k]) <= eps*(TNT::abs(s[k]) + TNT::abs(s[k+1]))) { + e[k] = 0.0; + break; + } + } + if (k == p-2) { + kase = 4; + } else { + int ks; + for (ks = p-1; ks >= k; ks--) { + if (ks == k) { + break; + } + typename MaTRiX::value_type t = (ks != p ? TNT::abs(e[ks]) : 0.) + + (ks != k+1 ? TNT::abs(e[ks-1]) : 0.); + if (TNT::abs(s[ks]) <= eps*t) { + s[ks] = 0.0; + break; + } + } + if (ks == k) { + kase = 3; + } else if (ks == p-1) { + kase = 1; + } else { + kase = 2; + k = ks; + } + } + k++; + + // Perform the task indicated by kase. + + switch (kase) { + + // Deflate negligible s(p). + + case 1: { + typename MaTRiX::value_type f = e[p-2]; + e[p-2] = 0.0; + for (j = p-2; j >= k; j--) { + typename MaTRiX::value_type t = hypot(s[j],f); + typename MaTRiX::value_type cs = s[j]/t; + typename MaTRiX::value_type sn = f/t; + s[j] = t; + if (j != k) { + f = -sn*e[j-1]; + e[j-1] = cs*e[j-1]; + } + + for (i = 0; i < n; i++) { + t = cs*V[i][j] + sn*V[i][p-1]; + V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1]; + V[i][j] = t; + } + } + } + break; + + // Split at negligible s(k). + + case 2: { + typename MaTRiX::value_type f = e[k-1]; + e[k-1] = 0.0; + for (j = k; j < p; j++) { + typename MaTRiX::value_type t = hypot(s[j],f); + typename MaTRiX::value_type cs = s[j]/t; + typename MaTRiX::value_type sn = f/t; + s[j] = t; + f = -sn*e[j]; + e[j] = cs*e[j]; + + for (i = 0; i < m; i++) { + t = cs*U[i][j] + sn*U[i][k-1]; + U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1]; + U[i][j] = t; + } + } + } + break; + + // Perform one qr step. + + case 3: { + + // Calculate the shift. + + typename MaTRiX::value_type scale = max(max(max(max( + TNT::abs(s[p-1]),TNT::abs(s[p-2])),TNT::abs(e[p-2])), + TNT::abs(s[k])),TNT::abs(e[k])); + typename MaTRiX::value_type sp = s[p-1]/scale; + typename MaTRiX::value_type spm1 = s[p-2]/scale; + typename MaTRiX::value_type epm1 = e[p-2]/scale; + typename MaTRiX::value_type sk = s[k]/scale; + typename MaTRiX::value_type ek = e[k]/scale; + typename MaTRiX::value_type b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; + typename MaTRiX::value_type c = (sp*epm1)*(sp*epm1); + typename MaTRiX::value_type shift = 0.0; + if ((b != 0.0) || (c != 0.0)) { + shift = sqrt(b*b + c); + if (b < 0.0) { + shift = -shift; + } + shift = c/(b + shift); + } + typename MaTRiX::value_type f = (sk + sp)*(sk - sp) + shift; + typename MaTRiX::value_type g = sk*ek; + + // Chase zeros. + + for (j = k; j < p-1; j++) { + typename MaTRiX::value_type t = hypot(f,g); + typename MaTRiX::value_type cs = f/t; + typename MaTRiX::value_type sn = g/t; + if (j != k) { + e[j-1] = t; + } + f = cs*s[j] + sn*e[j]; + e[j] = cs*e[j] - sn*s[j]; + g = sn*s[j+1]; + s[j+1] = cs*s[j+1]; + + for (i = 0; i < n; i++) { + t = cs*V[i][j] + sn*V[i][j+1]; + V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1]; + V[i][j] = t; + } + + t = hypot(f,g); + cs = f/t; + sn = g/t; + s[j] = t; + f = cs*e[j] + sn*s[j+1]; + s[j+1] = -sn*e[j] + cs*s[j+1]; + g = sn*e[j+1]; + e[j+1] = cs*e[j+1]; + if (j < m-1) { + for (i = 0; i < m; i++) { + t = cs*U[i][j] + sn*U[i][j+1]; + U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1]; + U[i][j] = t; + } + } + } + e[p-2] = f; + iter = iter + 1; + } + break; + + // Convergence. + + case 4: { + + // Make the singular values positive. + + if (s[k] <= 0.0) { + s[k] = (s[k] < 0.0 ? -s[k] : 0.0); + + for (i = 0; i <= pp; i++) + V[i][k] = -V[i][k]; + } + + // Order the singular values. + + while (k < pp) { + if (s[k] >= s[k+1]) { + break; + } + typename MaTRiX::value_type t = s[k]; + s[k] = s[k+1]; + s[k+1] = t; + if (k < n-1) { + for (i = 0; i < n; i++) { + t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t; + } + } + if (k < m-1) { + for (i = 0; i < m; i++) { + t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t; + } + } + k++; + } + iter = 0; + p--; + } + break; + } + } +} + +} + +#endif + diff --git a/intern/iksolver/intern/TNT/tnt.h b/intern/iksolver/intern/TNT/tnt.h new file mode 100644 index 00000000000..6c65a0bedcd --- /dev/null +++ b/intern/iksolver/intern/TNT/tnt.h @@ -0,0 +1,94 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +#ifndef TNT_H +#define TNT_H + +//--------------------------------------------------------------------- +// tnt.h TNT general header file. Defines default types +// and conventions. +//--------------------------------------------------------------------- + +//--------------------------------------------------------------------- +// Include current version +//--------------------------------------------------------------------- +#include "version.h" + +//--------------------------------------------------------------------- +// Define the data type used for matrix and vector Subscripts. +// This will default to "int", but it can be overriden at compile time, +// e.g. +// +// g++ -DTNT_SUBSCRIPT_TYPE='unsinged long' ... +// +// See subscript.h for details. +//--------------------------------------------------------------------- + +#include "subscript.h" + + + +//--------------------------------------------------------------------- +// Define this macro if you want TNT to ensure all refernces +// are within the bounds of the array. This encurs a run-time +// overhead, of course, but is recommended while developing +// code. It can be turned off for production runs. +// +// #define TNT_BOUNDS_CHECK +//--------------------------------------------------------------------- +// +#define TNT_BOUNDS_CHECK +#ifdef TNT_NO_BOUNDS_CHECK +#undef TNT_BOUNDS_CHECK +#endif + +//--------------------------------------------------------------------- +// Define this macro if you want to utilize matrix and vector +// regions. This is typically on, but you can save some +// compilation time by turning it off. If you do this and +// attempt to use regions you will get an error message. +// +// #define TNT_USE_REGIONS +//--------------------------------------------------------------------- +// +#define TNT_USE_REGIONS + +//--------------------------------------------------------------------- +// +//--------------------------------------------------------------------- +// if your system doesn't have abs() min(), and max() uncoment the following +//--------------------------------------------------------------------- +// +// +//#define __NEED_ABS_MIN_MAX_ + +#include "tntmath.h" + +#endif // TNT_H + diff --git a/intern/iksolver/intern/TNT/tntmath.h b/intern/iksolver/intern/TNT/tntmath.h new file mode 100644 index 00000000000..5773900caf9 --- /dev/null +++ b/intern/iksolver/intern/TNT/tntmath.h @@ -0,0 +1,153 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Header file for scalar math functions + +#ifndef TNTMATH_H +#define TNTMATH_H + +// conventional functions required by several matrix algorithms + + + +namespace TNT +{ + +struct TNTException { + int i; +}; + + +inline double abs(double t) +{ + return ( t > 0 ? t : -t); +} + +inline double min(double a, double b) +{ + return (a < b ? a : b); +} + +inline double max(double a, double b) +{ + return (a > b ? a : b); +} + +inline float abs(float t) +{ + return ( t > 0 ? t : -t); +} + +inline float min(float a, float b) +{ + return (a < b ? a : b); +} + +inline int min(int a, int b) +{ + return (a < b ? a : b); +} + +inline int max(int a, int b) +{ + return (a > b ? a : b); +} + +inline float max(float a, float b) +{ + return (a > b ? a : b); +} + +inline double sign(double a) +{ + return (a > 0 ? 1.0 : -1.0); +} + +inline double sign(double a,double b) { + return (b >= 0.0 ? TNT::abs(a) : -TNT::abs(a)); +} + +inline float sign(float a,float b) { + return (b >= 0.0f ? TNT::abs(a) : -TNT::abs(a)); +} + +inline float sign(float a) +{ + return (a > 0.0 ? 1.0f : -1.0f); +} + +inline float pythag(float a, float b) +{ + float absa,absb; + absa = abs(a); + absb = abs(b); + + if (absa > absb) { + float sqr = absb/absa; + sqr *= sqr; + return absa * float(sqrt(1 + sqr)); + } else { + if (absb > float(0)) { + float sqr = absa/absb; + sqr *= sqr; + return absb * float(sqrt(1 + sqr)); + } else { + return float(0); + } + } +} + +inline double pythag(double a, double b) +{ + double absa,absb; + absa = abs(a); + absb = abs(b); + + if (absa > absb) { + double sqr = absb/absa; + sqr *= sqr; + return absa * double(sqrt(1 + sqr)); + } else { + + if (absb > double(0)) { + double sqr = absa/absb; + sqr *= sqr; + return absb * double(sqrt(1 + sqr)); + } else { + return double(0); + } + } +} + + +} /* namespace TNT */ + +#endif /* TNTMATH_H */ + diff --git a/intern/iksolver/intern/TNT/tntreqs.h b/intern/iksolver/intern/TNT/tntreqs.h new file mode 100644 index 00000000000..75b79fd86a9 --- /dev/null +++ b/intern/iksolver/intern/TNT/tntreqs.h @@ -0,0 +1,74 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + +// The requirements for a bare-bones vector class: +// +// +// o) must have 0-based [] indexing for const and +// non-const objects (i.e. operator[] defined) +// +// o) must have size() method to denote the number of +// elements +// o) must clean up after itself when destructed +// (i.e. no memory leaks) +// +// -) must have begin() and end() methods (The begin() +// method is necessary, because relying on +// &v_[0] may not work on a empty vector (i.e. v_ is NULL.) +// +// o) must be templated +// o) must have X::value_type defined to be the types of elements +// o) must have X::X(const &x) copy constructor (by *value*) +// o) must have X::X(int N) constructor to N-length vector +// (NOTE: this constructor need *NOT* initalize elements) +// +// -) must have X::X(int N, T scalar) constructor to initalize +// elements to value of "scalar". +// +// ( removed, because valarray<> class uses (scalar, N) rather +// than (N, scalar) ) +// -) must have X::X(int N, const T* scalars) constructor to copy from +// any C linear array +// +// ( removed, because of same reverse order of valarray<> ) +// +// o) must have assignment A=B, by value +// +// NOTE: this class is *NOT* meant to be derived from, +// so its methods (particularly indexing) need not be +// declared virtual. +// +// +// Some things it *DOES NOT* need to do are +// +// o) bounds checking +// o) array referencing (e.g. reference counting) +// o) support () indexing +// o) I/O +// + diff --git a/intern/iksolver/intern/TNT/transv.h b/intern/iksolver/intern/TNT/transv.h new file mode 100644 index 00000000000..dca3d09b4ac --- /dev/null +++ b/intern/iksolver/intern/TNT/transv.h @@ -0,0 +1,165 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Matrix Transpose Views + +#ifndef TRANSV_H +#define TRANSV_H + +#include +#include +#include "vec.h" + +namespace TNT +{ + +template +class Transpose_View +{ + protected: + + const Array2D & A_; + + public: + + typedef typename Array2D::element_type T; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + + const Array2D & array() const { return A_; } + Subscript num_rows() const { return A_.num_cols();} + Subscript num_cols() const { return A_.num_rows();} + Subscript lbound() const { return A_.lbound(); } + Subscript dim(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert( A_.lbound() <= i); + assert( i<= A_.lbound()+1); +#endif + if (i== A_.lbound()) + return num_rows(); + else + return num_cols(); + } + + + Transpose_View(const Transpose_View &A) : A_(A.A_) {}; + Transpose_View(const Array2D &A) : A_(A) {}; + + + inline const typename Array2D::element_type & operator()( + Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(lbound()<=i); + assert(i<=A_.num_cols() + lbound() - 1); + assert(lbound()<=j); + assert(j<=A_.num_rows() + lbound() - 1); +#endif + + return A_(j,i); + } + + +}; + +template +Transpose_View Transpose_view(const Matrix &A) +{ + return Transpose_View(A); +} + +template +Vector matmult( + const Transpose_View & A, + const Vector &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(B.dim() == N); + + Vector x(N); + + Subscript i, j; + T tmp = 0; + + for (i=1; i<=M; i++) + { + tmp = 0; + for (j=1; j<=N; j++) + tmp += A(i,j) * B(j); + x(i) = tmp; + } + + return x; +} + +template +inline Vector operator*(const Transpose_View & A, const Vector &B) +{ + return matmult(A,B); +} + + +template +std::ostream& operator<<(std::ostream &s, const Transpose_View &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() - 1; + Subscript Nend = N + A.lbound() - 1; + + s << M << " " << N << endl; + for (Subscript i=start; i<=Mend; i++) + { + for (Subscript j=start; j<=Nend; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + +} // namespace TNT + +#endif // TRANSV_H + diff --git a/intern/iksolver/intern/TNT/triang.h b/intern/iksolver/intern/TNT/triang.h new file mode 100644 index 00000000000..73b98afbb40 --- /dev/null +++ b/intern/iksolver/intern/TNT/triang.h @@ -0,0 +1,638 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Triangular Matrices (Views and Adpators) + +#ifndef TRIANG_H +#define TRIANG_H + +// default to use lower-triangular portions of arrays +// for symmetric matrices. + +namespace TNT +{ + +template +class LowerTriangularView +{ + protected: + + + const MaTRiX &A_; + const typename MaTRiX::element_type zero_; + + public: + + + typedef typename MaTRiX::const_reference const_reference; + typedef const typename MaTRiX::element_type element_type; + typedef const typename MaTRiX::element_type value_type; + typedef element_type T; + + Subscript dim(Subscript d) const { return A_.dim(d); } + Subscript lbound() const { return A_.lbound(); } + Subscript num_rows() const { return A_.num_rows(); } + Subscript num_cols() const { return A_.num_cols(); } + + + // constructors + + LowerTriangularView(/*const*/ MaTRiX &A) : A_(A), zero_(0) {} + + + inline const_reference get(Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(lbound()<=i); + assert(i<=A_.num_rows() + lbound() - 1); + assert(lbound()<=j); + assert(j<=A_.num_cols() + lbound() - 1); +#endif + if (i > + const_Region; + + const_Region operator()(/*const*/ Index1D &I, + /*const*/ Index1D &J) const + { + return const_Region(*this, I, J); + } + + const_Region operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) const + { + return const_Region(*this, i1, i2, j1, j2); + } + + + +#endif +// TNT_USE_REGIONS + +}; + + +/* *********** Lower_triangular_view() algorithms ****************** */ + +template +VecToR matmult(/*const*/ LowerTriangularView &A, VecToR &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(N == x.dim()); + + Subscript i, j; + typename MaTRiX::element_type sum=0.0; + VecToR result(M); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() -1 ; + + for (i=start; i<=Mend; i++) + { + sum = 0.0; + for (j=start; j<=i; j++) + sum = sum + A(i,j)*x(j); + result(i) = sum; + } + + return result; +} + +template +inline VecToR operator*(/*const*/ LowerTriangularView &A, VecToR &x) +{ + return matmult(A,x); +} + +template +class UnitLowerTriangularView +{ + protected: + + const MaTRiX &A_; + const typename MaTRiX::element_type zero; + const typename MaTRiX::element_type one; + + public: + + typedef typename MaTRiX::const_reference const_reference; + typedef typename MaTRiX::element_type element_type; + typedef typename MaTRiX::element_type value_type; + typedef element_type T; + + Subscript lbound() const { return 1; } + Subscript dim(Subscript d) const { return A_.dim(d); } + Subscript num_rows() const { return A_.num_rows(); } + Subscript num_cols() const { return A_.num_cols(); } + + + // constructors + + UnitLowerTriangularView(/*const*/ MaTRiX &A) : A_(A), zero(0), one(1) {} + + + inline const_reference get(Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i<=A_.dim(1)); + assert(1<=j); + assert(j<=A_.dim(2)); + assert(0<=i && ij) + return A_(i,j); + else if (i==j) + return one; + else + return zero; + } + + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i<=A_.dim(1)); + assert(1<=j); + assert(j<=A_.dim(2)); +#endif + if (i>j) + return A_(i,j); + else if (i==j) + return one; + else + return zero; + } + + +#ifdef TNT_USE_REGIONS + // These are the "index-aware" features + + typedef const_Region2D< UnitLowerTriangularView > + const_Region; + + const_Region operator()(/*const*/ Index1D &I, + /*const*/ Index1D &J) const + { + return const_Region(*this, I, J); + } + + const_Region operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) const + { + return const_Region(*this, i1, i2, j1, j2); + } +#endif +// TNT_USE_REGIONS +}; + +template +LowerTriangularView Lower_triangular_view( + /*const*/ MaTRiX &A) +{ + return LowerTriangularView(A); +} + + +template +UnitLowerTriangularView Unit_lower_triangular_view( + /*const*/ MaTRiX &A) +{ + return UnitLowerTriangularView(A); +} + +template +VecToR matmult(/*const*/ UnitLowerTriangularView &A, VecToR &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(N == x.dim()); + + Subscript i, j; + typename MaTRiX::element_type sum=0.0; + VecToR result(M); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() -1 ; + + for (i=start; i<=Mend; i++) + { + sum = 0.0; + for (j=start; j +inline VecToR operator*(/*const*/ UnitLowerTriangularView &A, VecToR &x) +{ + return matmult(A,x); +} + + +//********************** Algorithms ************************************* + + + +template +std::ostream& operator<<(std::ostream &s, const LowerTriangularView&A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << endl; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + +template +std::ostream& operator<<(std::ostream &s, + const UnitLowerTriangularView&A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << endl; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + + + +// ******************* Upper Triangular Section ************************** + +template +class UpperTriangularView +{ + protected: + + + /*const*/ MaTRiX &A_; + /*const*/ typename MaTRiX::element_type zero_; + + public: + + + typedef typename MaTRiX::const_reference const_reference; + typedef /*const*/ typename MaTRiX::element_type element_type; + typedef /*const*/ typename MaTRiX::element_type value_type; + typedef element_type T; + + Subscript dim(Subscript d) const { return A_.dim(d); } + Subscript lbound() const { return A_.lbound(); } + Subscript num_rows() const { return A_.num_rows(); } + Subscript num_cols() const { return A_.num_cols(); } + + + // constructors + + UpperTriangularView(/*const*/ MaTRiX &A) : A_(A), zero_(0) {} + + + inline const_reference get(Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(lbound()<=i); + assert(i<=A_.num_rows() + lbound() - 1); + assert(lbound()<=j); + assert(j<=A_.num_cols() + lbound() - 1); +#endif + if (i>j) + return zero_; + else + return A_(i,j); + } + + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(lbound()<=i); + assert(i<=A_.num_rows() + lbound() - 1); + assert(lbound()<=j); + assert(j<=A_.num_cols() + lbound() - 1); +#endif + if (i>j) + return zero_; + else + return A_(i,j); + } + +#ifdef TNT_USE_REGIONS + + typedef const_Region2D< UpperTriangularView > + const_Region; + + const_Region operator()(const Index1D &I, + const Index1D &J) const + { + return const_Region(*this, I, J); + } + + const_Region operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) const + { + return const_Region(*this, i1, i2, j1, j2); + } + + + +#endif +// TNT_USE_REGIONS + +}; + + +/* *********** Upper_triangular_view() algorithms ****************** */ + +template +VecToR matmult(/*const*/ UpperTriangularView &A, VecToR &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(N == x.dim()); + + Subscript i, j; + typename VecToR::element_type sum=0.0; + VecToR result(M); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() -1 ; + + for (i=start; i<=Mend; i++) + { + sum = 0.0; + for (j=i; j<=N; j++) + sum = sum + A(i,j)*x(j); + result(i) = sum; + } + + return result; +} + +template +inline VecToR operator*(/*const*/ UpperTriangularView &A, VecToR &x) +{ + return matmult(A,x); +} + +template +class UnitUpperTriangularView +{ + protected: + + const MaTRiX &A_; + const typename MaTRiX::element_type zero; + const typename MaTRiX::element_type one; + + public: + + typedef typename MaTRiX::const_reference const_reference; + typedef typename MaTRiX::element_type element_type; + typedef typename MaTRiX::element_type value_type; + typedef element_type T; + + Subscript lbound() const { return 1; } + Subscript dim(Subscript d) const { return A_.dim(d); } + Subscript num_rows() const { return A_.num_rows(); } + Subscript num_cols() const { return A_.num_cols(); } + + + // constructors + + UnitUpperTriangularView(/*const*/ MaTRiX &A) : A_(A), zero(0), one(1) {} + + + inline const_reference get(Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i<=A_.dim(1)); + assert(1<=j); + assert(j<=A_.dim(2)); + assert(0<=i && i > + const_Region; + + const_Region operator()(const Index1D &I, + const Index1D &J) const + { + return const_Region(*this, I, J); + } + + const_Region operator()(Subscript i1, Subscript i2, + Subscript j1, Subscript j2) const + { + return const_Region(*this, i1, i2, j1, j2); + } +#endif +// TNT_USE_REGIONS +}; + +template +UpperTriangularView Upper_triangular_view( + /*const*/ MaTRiX &A) +{ + return UpperTriangularView(A); +} + + +template +UnitUpperTriangularView Unit_upper_triangular_view( + /*const*/ MaTRiX &A) +{ + return UnitUpperTriangularView(A); +} + +template +VecToR matmult(/*const*/ UnitUpperTriangularView &A, VecToR &x) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(N == x.dim()); + + Subscript i, j; + typename VecToR::element_type sum=0.0; + VecToR result(M); + + Subscript start = A.lbound(); + Subscript Mend = M + A.lbound() -1 ; + + for (i=start; i<=Mend; i++) + { + sum = x(i); + for (j=i+1; j<=N; j++) + sum = sum + A(i,j)*x(j); + result(i) = sum + x(i); + } + + return result; +} + +template +inline VecToR operator*(/*const*/ UnitUpperTriangularView &A, VecToR &x) +{ + return matmult(A,x); +} + + +//********************** Algorithms ************************************* + + + +template +std::ostream& operator<<(std::ostream &s, + /*const*/ UpperTriangularView&A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << endl; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + +template +std::ostream& operator<<(std::ostream &s, + /*const*/ UnitUpperTriangularView&A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << endl; + + for (Subscript i=1; i<=M; i++) + { + for (Subscript j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << endl; + } + + + return s; +} + +} // namespace TNT + +#endif //TRIANG_H + diff --git a/intern/iksolver/intern/TNT/trisolve.h b/intern/iksolver/intern/TNT/trisolve.h new file mode 100644 index 00000000000..255eb0ca0c6 --- /dev/null +++ b/intern/iksolver/intern/TNT/trisolve.h @@ -0,0 +1,189 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + + +// Triangular Solves + +#ifndef TRISLV_H +#define TRISLV_H + + +#include "triang.h" + +namespace TNT +{ + +template +VecToR Lower_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) +{ + Subscript N = A.num_rows(); + + // make sure matrix sizes agree; A must be square + + assert(A.num_cols() == N); + assert(b.dim() == N); + + VecToR x(N); + + Subscript i; + for (i=1; i<=N; i++) + { + typename MaTriX::element_type tmp=0; + + for (Subscript j=1; j +VecToR Unit_lower_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) +{ + Subscript N = A.num_rows(); + + // make sure matrix sizes agree; A must be square + + assert(A.num_cols() == N); + assert(b.dim() == N); + + VecToR x(N); + + Subscript i; + for (i=1; i<=N; i++) + { + + typename MaTriX::element_type tmp=0; + + for (Subscript j=1; j +VecToR linear_solve(/*const*/ LowerTriangularView &A, + /*const*/ VecToR &b) +{ + return Lower_triangular_solve(A, b); +} + +template +VecToR linear_solve(/*const*/ UnitLowerTriangularView &A, + /*const*/ VecToR &b) +{ + return Unit_lower_triangular_solve(A, b); +} + + + +//********************** Upper triangular section **************** + +template +VecToR Upper_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) +{ + Subscript N = A.num_rows(); + + // make sure matrix sizes agree; A must be square + + assert(A.num_cols() == N); + assert(b.dim() == N); + + VecToR x(N); + + Subscript i; + for (i=N; i>=1; i--) + { + + typename MaTriX::element_type tmp=0; + + for (Subscript j=i+1; j<=N; j++) + tmp = tmp + A(i,j)*x(j); + + x(i) = (b(i) - tmp)/ A(i,i); + } + + return x; +} + + +template +VecToR Unit_upper_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) +{ + Subscript N = A.num_rows(); + + // make sure matrix sizes agree; A must be square + + assert(A.num_cols() == N); + assert(b.dim() == N); + + VecToR x(N); + + Subscript i; + for (i=N; i>=1; i--) + { + + typename MaTriX::element_type tmp=0; + + for (Subscript j=i+1; j +VecToR linear_solve(/*const*/ UpperTriangularView &A, + /*const*/ VecToR &b) +{ + return Upper_triangular_solve(A, b); +} + +template +VecToR linear_solve(/*const*/ UnitUpperTriangularView &A, + /*const*/ VecToR &b) +{ + return Unit_upper_triangular_solve(A, b); +} + + +} // namespace TNT + +#endif // TRISLV_H + diff --git a/intern/iksolver/intern/TNT/vec.h b/intern/iksolver/intern/TNT/vec.h new file mode 100644 index 00000000000..1729d83ca10 --- /dev/null +++ b/intern/iksolver/intern/TNT/vec.h @@ -0,0 +1,492 @@ +/** + * $Id$ + */ + +/* + +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. The Template Numerical Toolkit (TNT) is +* an experimental system. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +* see http://math.nist.gov/tnt for latest updates. +* +*/ + + +// Basic TNT numerical vector (0-based [i] AND 1-based (i) indexing ) +// + +#ifndef VEC_H +#define VEC_H + +#include "subscript.h" +#include +#include +#include + +namespace TNT +{ + +template +class Vector +{ + + + public: + + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + T* v_; + T* vm1_; // pointer adjustment for optimzied 1-offset indexing + Subscript n_; + + // internal helper function to create the array + // of row pointers + + void initialize(Subscript N) + { + // adjust pointers so that they are 1-offset: + // v_[] is the internal contiguous array, it is still 0-offset + // + assert(v_ == NULL); + v_ = new T[N]; + assert(v_ != NULL); + vm1_ = v_-1; + n_ = N; + } + + void copy(const T* v) + { + Subscript N = n_; + Subscript i; + +#ifdef TNT_UNROLL_LOOPS + Subscript Nmod4 = N & 3; + Subscript N4 = N - Nmod4; + + for (i=0; i &A) : v_(0), vm1_(0), n_(0) + { + initialize(A.n_); + copy(A.v_); + } + + Vector(Subscript N, const T& value = T()) : v_(0), vm1_(0), n_(0) + { + initialize(N); + set(value); + } + + Vector(Subscript N, const T* v) : v_(0), vm1_(0), n_(0) + { + initialize(N); + copy(v); + } + + + // methods + // + Vector& newsize(Subscript N) + { + if (n_ == N) return *this; + + destroy(); + initialize(N); + + return *this; + } + + + // assignments + // + Vector& operator=(const Vector &A) + { + if (v_ == A.v_) + return *this; + + if (n_ == A.n_) // no need to re-alloc + copy(A.v_); + + else + { + destroy(); + initialize(A.n_); + copy(A.v_); + } + + return *this; + } + + Vector& operator=(const T& scalar) + { + set(scalar); + return *this; + } + + inline Subscript dim() const + { + return n_; + } + + inline Subscript size() const + { + return n_; + } + + + inline reference operator()(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= n_) ; +#endif + return vm1_[i]; + } + + inline const_reference operator() (Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= n_) ; +#endif + return vm1_[i]; + } + + inline reference operator[](Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < n_) ; +#endif + return v_[i]; + } + + inline const_reference operator[](Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i) ; + assert(i < n_) ; +#endif + return v_[i]; + } + + + +}; + + +/* *************************** I/O ********************************/ + +template +std::ostream& operator<<(std::ostream &s, const Vector &A) +{ + Subscript N=A.dim(); + + s << N << std::endl; + + for (Subscript i=0; i +std::istream & operator>>(std::istream &s, Vector &A) +{ + + Subscript N; + + s >> N; + + if ( !(N == A.size() )) + { + A.newsize(N); + } + + + for (Subscript i=0; i> A[i]; + + + return s; +} + +// *******************[ basic matrix algorithms ]*************************** + + +template +Vector operator+(const Vector &A, + const Vector &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector tmp(N); + Subscript i; + + for (i=0; i +Vector operator-(const Vector &A, + const Vector &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector tmp(N); + Subscript i; + + for (i=0; i +Vector operator*(const Vector &A, + const Vector &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector tmp(N); + Subscript i; + + for (i=0; i +Vector operator*(const Vector &A, + const T &B) +{ + Subscript N = A.dim(); + + Vector tmp(N); + Subscript i; + + for (i=0; i +T dot_prod(const Vector &A, const Vector &B) +{ + Subscript N = A.dim(); + assert(N == B.dim()); + + Subscript i; + T sum = 0; + + for (i=0; i +void vectoradd( + Vector &A, + const Vector &B) +{ + const Subscript N = A.dim(); + assert(N==B.dim()); + Subscript i; + + for (i=0; i +void vectoradd( + Vector &C, + const Vector &A, + const Vector &B) +{ + const Subscript N = A.dim(); + assert(N==B.dim()); + Subscript i; + + for (i=0; i +void vectorsub( + Vector &A, + const Vector &B) +{ + const Subscript N = A.dim(); + assert(N==B.dim()); + Subscript i; + + for (i=0; i +void vectorsub( + Vector &C, + const Vector &A, + const Vector &B) +{ + const Subscript N = A.dim(); + assert(N==B.dim()); + Subscript i; + + for (i=0; i +void vectorscale( + Vector &C, + const Vector &A, + const T &B) +{ + const Subscript N = A.dim(); + Subscript i; + + for (i=0; i +void vectorscale( + Vector &A, + const T &B) +{ + const Subscript N = A.dim(); + Subscript i; + + for (i=0; i +#include +#include + +#include "subscript.h" + +#ifdef TNT_USE_REGIONS +#include "region1d.h" +#endif + +namespace TNT +{ + +// see "tntreq.h" for TNT requirements for underlying vector +// class. This need NOT be the STL vector<> class, but a subset +// that provides minimal services. +// +// This is a container adaptor that provides the following services. +// +// o) adds 1-offset operator() access ([] is always 0 offset) +// o) adds TNT_BOUNDS_CHECK to () and [] +// o) adds initialization from strings, e.g. "1.0 2.0 3.0"; +// o) adds newsize(N) function (does not preserve previous values) +// o) adds dim() and dim(1) +// o) adds free() function to release memory used by vector +// o) adds regions, e.g. A(Index(1,10)) = ... +// o) add getVector() method to return adapted container +// o) adds simple I/O for ostreams + +template +class Vector_Adaptor +{ + + public: + typedef typename BBVec::value_type T; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1; } + + protected: + BBVec v_; + T* vm1_; + + public: + + Subscript size() const { return v_.size(); } + + // These were removed so that the ANSI C++ valarray class + // would work as a possible storage container. + // + // + //iterator begin() { return v_.begin();} + //iterator begin() { return &v_[0];} + // + //iterator end() { return v_.end(); } + //iterator end() { return &v_[0] + v_.size(); } + // + //const_iterator begin() const { return v_.begin();} + //const_iterator begin() const { return &v_[0];} + // + //const_iterator end() const { return v_.end(); } + //const_iterator end() const { return &v_[0] + v_.size(); } + + BBVec& getVector() { return v_; } + Subscript dim() const { return v_.size(); } + Subscript dim(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(i==TNT_BASE_OFFSET); +#endif + return (i==TNT_BASE_OFFSET ? v_.size() : 0 ); + } + Vector_Adaptor() : v_() {}; + Vector_Adaptor(const Vector_Adaptor &A) : v_(A.v_) + { + vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); + + } + + Vector_Adaptor(Subscript N, const T& value = T()) : v_(N) + { + for (Subscript i=0; i 0 ? &(v_[0]) -1 : NULL); + } + + Vector_Adaptor(Subscript N, const T* values) : v_(N) + { + for (Subscript i=0; i 0 ? &(v_[0]) -1 : NULL); + } + Vector_Adaptor(const BBVec & A) : v_(A) + { + vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); + } + + // NOTE: this assumes that BBVec(0) constructor creates an + // null vector that does not take up space... It would be + // great to require that BBVec have a corresponding free() + // function, but in particular STL vectors do not. + // + Vector_Adaptor& free() + { + return *this = Vector_Adaptor(0); + } + + Vector_Adaptor& operator=(const Vector_Adaptor &A) + { + v_ = A.v_ ; + vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); + return *this; + } + + Vector_Adaptor& newsize(Subscript N) + { + // NOTE: this is not as efficient as it could be + // but to retain compatiblity with STL interface + // we cannot assume underlying implementation + // has a newsize() function. + + return *this = Vector_Adaptor(N); + + } + + Vector_Adaptor& operator=(const T &a) + { + Subscript i; + Subscript N = v_.size(); + for (i=0; i& resize(Subscript N) + { + if (N == size()) return *this; + + Vector_Adaptor tmp(N); + Subscript n = (N < size() ? N : size()); // min(N, size()); + Subscript i; + + for (i=0; i > Region; + + typedef const_Region1D< Vector_Adaptor > const_Region; + + Region operator()(const Index1D &I) + { return Region(*this, I); } + + Region operator()(const Subscript i1, Subscript i2) + { return Region(*this, i1, i2); } + + const_Region operator()(const Index1D &I) const + { return const_Region(*this, I); } + + const_Region operator()(const Subscript i1, Subscript i2) const + { return const_Region(*this, i1, i2); } +#endif +// TNT_USE_REGIONS + + +}; + +#include + +template +std::ostream& operator<<(std::ostream &s, const Vector_Adaptor &A) +{ + Subscript M=A.size(); + + s << M << endl; + for (Subscript i=1; i<=M; i++) + s << A(i) << endl; + return s; +} + +template +std::istream& operator>>(std::istream &s, Vector_Adaptor &A) +{ + Subscript N; + + s >> N; + + A.resize(N); + + for (Subscript i=1; i<=N; i++) + s >> A(i); + + return s; +} + +} // namespace TNT + +#endif + diff --git a/intern/iksolver/intern/TNT/version.h b/intern/iksolver/intern/TNT/version.h new file mode 100644 index 00000000000..55aefbdf31d --- /dev/null +++ b/intern/iksolver/intern/TNT/version.h @@ -0,0 +1,26 @@ +/** + * $Id$ + */ + +// Template Numerical Toolkit (TNT) for Linear Algebra + +// +// BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE +// Please see http://math.nist.gov/tnt for updates +// +// R. Pozo +// Mathematical and Computational Sciences Division +// National Institute of Standards and Technology + + +#ifndef TNT_VERSION_H +#define TNT_VERSION_H + + +#define TNT_MAJOR_VERSION '0' +#define TNT_MINOR_VERSION '9' +#define TNT_SUBMINOR_VERSION '4' +#define TNT_VERSION_STRING "0.9.4" + +#endif + diff --git a/intern/iksolver/make/msvc_6_0/iksolver.dsp b/intern/iksolver/make/msvc_6_0/iksolver.dsp new file mode 100644 index 00000000000..c5e842bdd04 --- /dev/null +++ b/intern/iksolver/make/msvc_6_0/iksolver.dsp @@ -0,0 +1,260 @@ +# Microsoft Developer Studio Project File - Name="iksolver" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=iksolver - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "iksolver.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "iksolver.mak" CFG="iksolver - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "iksolver - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "iksolver - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "iksolver - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\iksolver" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\iksolver" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /Ob2 /I "..\..\..\..\intern\moto\include" /I "..\..\..\..\intern\memutil" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\iksolver\libiksolver.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\iksolver\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\iksolver\*.lib ..\..\..\..\..\lib\windows\iksolver\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "iksolver - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\iksolver\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\iksolver\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\intern\moto\include" /I "..\..\..\..\intern\memutil" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\iksolver\debug\libiksolver.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\iksolver\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\iksolver\debug\*.lib ..\..\..\..\..\lib\windows\iksolver\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "iksolver - Win32 Release" +# Name "iksolver - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Group "common" + +# PROP Default_Filter "" +# End Group +# Begin Group "TNT" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\TNT\cholesky.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\cmat.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\fcscmat.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\fmat.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\fortran.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\fspvec.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\index.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\lapack.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\lu.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\qr.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\region1d.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\region2d.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\stopwatch.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\subscript.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\svd.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\tnt.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\tntmath.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\tntreqs.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\transv.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\triang.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\trisolve.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\vec.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\vecadaptor.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\TNT\version.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\intern\IK_QJacobian.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QJacobian.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QJacobianSolver.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QJacobianSolver.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QSegment.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QSegment.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QSolver_Class.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QTask.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_QTask.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\IK_Solver.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_ExpMap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_ExpMap.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\extern\IK_solver.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/iksolver/make/msvc_6_0/iksolver.dsw b/intern/iksolver/make/msvc_6_0/iksolver.dsw new file mode 100644 index 00000000000..90a123d9ce8 --- /dev/null +++ b/intern/iksolver/make/msvc_6_0/iksolver.dsw @@ -0,0 +1,35 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "iksolver"=.\iksolver.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + + + + + + + diff --git a/intern/iksolver/make/msvc_7_0/iksolver.sln b/intern/iksolver/make/msvc_7_0/iksolver.sln new file mode 100644 index 00000000000..e06e5163993 --- /dev/null +++ b/intern/iksolver/make/msvc_7_0/iksolver.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iksolver", "iksolver.vcproj", "{EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}.Debug.ActiveCfg = Debug|Win32 + {EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}.Debug.Build.0 = Debug|Win32 + {EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}.Release.ActiveCfg = Release|Win32 + {EB6E6428-C3FA-4A95-91AE-F060EFD1D57C}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/iksolver/make/msvc_7_0/iksolver.vcproj b/intern/iksolver/make/msvc_7_0/iksolver.vcproj new file mode 100644 index 00000000000..008a29774dc --- /dev/null +++ b/intern/iksolver/make/msvc_7_0/iksolver.vcproj @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/iksolver/test/Makefile b/intern/iksolver/test/Makefile new file mode 100644 index 00000000000..c472c514bad --- /dev/null +++ b/intern/iksolver/test/Makefile @@ -0,0 +1,71 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver test makefile. +# + +LIBNAME = iksolver +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +DIRS = ik_glut_test + +include nan_subdirs.mk + +include nan_link.mk + +LIBS = $(OCGDIR)/intern/$(LIBNAME)/test/ik_glut_test/intern/$(DEBUG_DIR)libintern.a +LIBS += $(OCGDIR)/intern/$(LIBNAME)/test/ik_glut_test/common/$(DEBUG_DIR)libcommon.a +LIBS += $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)libiksolver.a + +SLIBS += $(NAN_MOTO)/lib/$(DEBUG_DIR)libmoto.a + +ifeq ($(OS),$(findstring $(OS), "beos darwin linux freebsd openbsd")) + LLIBS = -L/usr/X11R6/lib -lglut -pthread +endif + +ifeq ($(OS),$(findstring $(OS), "solaris")) + LLIBS = -L/usr/openwin/lib -lglut -lX11 -lGL -lGLU -lXmu +endif + +all debug:: $(LIBS) $(DIR)/$(DEBUG_DIR)iksolvertest + +$(DIR)/$(DEBUG_DIR)iksolvertest: + @echo "****> linking $@ in $(DIR)" + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)iksolvertest $(LIBS) $(SLIBS) $(LLIBS) $(DADD) + +clean:: + $(RM) $(DIR)/iksolvertest $(DIR)/debug/iksolvertest + +test:: all + $(DIR)/iksolvertest + diff --git a/intern/iksolver/test/ik_glut_test/Makefile b/intern/iksolver/test/ik_glut_test/Makefile new file mode 100644 index 00000000000..4b47af16599 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver subdir bouncer. Pure waste. +# + +include nan_definitions.mk + +LIBNAME = ik_glut_test +SOURCEDIR = intern/iksolver/test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = common intern + +include nan_subdirs.mk + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp new file mode 100644 index 00000000000..6161addc170 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp @@ -0,0 +1,99 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GlutDrawer.h" + +#include "MT_assert.h" + +MEM_SmartPtr GlutDrawManager::m_s_instance = MEM_SmartPtr(); + + GlutDrawManager * +GlutDrawManager:: +Instance( +){ + if (m_s_instance == NULL) { + m_s_instance = new GlutDrawManager(); + } + + return m_s_instance; +} + + +// this is the function you should pass to glut + + void +GlutDrawManager:: +Draw( +){ + GlutDrawManager *manager = GlutDrawManager::Instance(); + + if (manager->m_drawer != NULL) { + manager->m_drawer->Draw(); + } +} + + void +GlutDrawManager:: +InstallDrawer( + GlutDrawer * drawer +){ + + MT_assert(m_drawer == NULL); + m_drawer = drawer; +} + + void +GlutDrawManager:: +ReleaseDrawer( +){ + m_drawer = NULL; +} + + +GlutDrawManager:: +~GlutDrawManager( +){ + + delete(m_drawer); +} + + + + + + + + + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h new file mode 100644 index 00000000000..706ccb92dec --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h @@ -0,0 +1,99 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_GlutDrawer +#define NAN_INCLUDED_GlutDrawer + +#include "MEM_NonCopyable.h" +#include "MEM_SmartPtr.h" + +// So pissed off with Glut callback stuff +// that is impossible to call objects unless they are global + +// inherit from GlutDrawer and installl the drawer in the singleton +// class GlutDrawManager. + +class GlutDrawer { +public : + + virtual + void + Draw( + )= 0; + + virtual + ~GlutDrawer( + ){}; +}; + +class GlutDrawManager : public MEM_NonCopyable{ + +public : + + static + GlutDrawManager * + Instance( + ); + + // this is the function you should pass to glut + + static + void + Draw( + ); + + void + InstallDrawer( + GlutDrawer * + ); + + void + ReleaseDrawer( + ); + + ~GlutDrawManager( + ); + +private : + + GlutDrawManager ( + ) : + m_drawer (0) + { + }; + + GlutDrawer * m_drawer; + + static MEM_SmartPtr m_s_instance; +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp new file mode 100644 index 00000000000..454e76f11bb --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp @@ -0,0 +1,92 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GlutKeyboardManager.h" +#include "MT_assert.h" + +MEM_SmartPtr GlutKeyboardManager::m_s_instance = MEM_SmartPtr(); + + GlutKeyboardManager * +GlutKeyboardManager:: +Instance( +){ + if (m_s_instance == NULL) { + m_s_instance = new GlutKeyboardManager(); + } + + return m_s_instance; +} + + +// this is the function you should pass to glut + + void +GlutKeyboardManager:: +HandleKeyboard( + unsigned char key, + int x, + int y +){ + GlutKeyboardManager *manager = GlutKeyboardManager::Instance(); + + if (manager->m_handler != NULL) { + manager->m_handler->HandleKeyboard(key,x,y); + } +} + + void +GlutKeyboardManager:: +InstallHandler( + GlutKeyboardHandler * handler +){ + + MT_assert(m_handler == NULL); + m_handler = handler; +} + + void +GlutKeyboardManager:: +ReleaseHandler( +){ + m_handler = NULL; +} + + +GlutKeyboardManager:: +~GlutKeyboardManager( +){ + + delete(m_handler); +} diff --git a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h new file mode 100644 index 00000000000..595e5e19d0e --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h @@ -0,0 +1,105 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_GlutKeyboardManager +#define NAN_INCLUDED_GlutKeyboardManager + +#include "MEM_NonCopyable.h" +#include "MEM_SmartPtr.h" + +// So pissed off with Glut callback stuff +// that is impossible to call objects unless they are global + +// inherit from GlutKeyboardHandler and installl the drawer in the singleton +// class GlutKeyboardManager. + +class GlutKeyboardHandler : public MEM_NonCopyable { +public : + + virtual + void + HandleKeyboard( + unsigned char key, + int x, + int y + )= 0; + + virtual + ~GlutKeyboardHandler( + ){}; +}; + +class GlutKeyboardManager : public MEM_NonCopyable{ + +public : + + static + GlutKeyboardManager * + Instance( + ); + + // this is the function you should pass to glut + + static + void + HandleKeyboard( + unsigned char key, + int x, + int y + ); + + void + InstallHandler( + GlutKeyboardHandler * + ); + + void + ReleaseHandler( + ); + + ~GlutKeyboardManager( + ); + +private : + + GlutKeyboardManager ( + ) : + m_handler (0) + { + }; + + GlutKeyboardHandler * m_handler; + + static MEM_SmartPtr m_s_instance; +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp new file mode 100644 index 00000000000..8221cb55a00 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp @@ -0,0 +1,107 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "GlutMouseManager.h" +#include "MT_assert.h" + +MEM_SmartPtr GlutMouseManager::m_s_instance = MEM_SmartPtr(); + + + GlutMouseManager * +GlutMouseManager:: +Instance( +){ + if (m_s_instance == NULL) { + m_s_instance = new GlutMouseManager(); + } + + return m_s_instance; +} + +// these are the functions you should pass to GLUT + + void +GlutMouseManager:: +Mouse( + int button, + int state, + int x, + int y +){ + GlutMouseManager *manager = GlutMouseManager::Instance(); + + if (manager->m_handler != NULL) { + manager->m_handler->Mouse(button,state,x,y); + } +} + + void +GlutMouseManager:: +Motion( + int x, + int y +){ + GlutMouseManager *manager = GlutMouseManager::Instance(); + + if (manager->m_handler != NULL) { + manager->m_handler->Motion(x,y); + } +} + + void +GlutMouseManager:: +InstallHandler( + GlutMouseHandler *handler +){ + + MT_assert(m_handler == NULL); + m_handler = handler; +} + + void +GlutMouseManager:: +ReleaseHandler( +){ + m_handler = NULL; +} + +GlutMouseManager:: +~GlutMouseManager( +){ + + delete(m_handler); +} + + diff --git a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h new file mode 100644 index 00000000000..9675bd3ca1c --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h @@ -0,0 +1,115 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_GlutMouseManager_h +#define NAN_INCLUDED_GlutMouseManager_h + +#include "MEM_NonCopyable.h" +#include "MEM_SmartPtr.h" + +class GlutMouseHandler { +public : + + virtual + void + Mouse( + int button, + int state, + int x, + int y + ) = 0; + + virtual + void + Motion( + int x, + int y + ) = 0; + + virtual + ~GlutMouseHandler( + ){}; +}; + +class GlutMouseManager : public MEM_NonCopyable{ + +public : + + static + GlutMouseManager * + Instance( + ); + + // these are the functions you should pass to GLUT + + static + void + Mouse( + int button, + int state, + int x, + int y + ); + + static + void + Motion( + int x, + int y + ); + + void + InstallHandler( + GlutMouseHandler * + ); + + void + ReleaseHandler( + ); + + ~GlutMouseManager( + ); + +private : + + GlutMouseManager ( + ) : + m_handler (0) + { + }; + + GlutMouseHandler * m_handler; + + static MEM_SmartPtr m_s_instance; +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/common/Makefile b/intern/iksolver/test/ik_glut_test/common/Makefile new file mode 100644 index 00000000000..07ad1837a7d --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/common/Makefile @@ -0,0 +1,44 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver test intern Makefile +# + +LIBNAME = common +SOURCEDIR = intern/iksolver/test/ik_glut_test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include + diff --git a/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h b/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h new file mode 100644 index 00000000000..6312d9c23f9 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h @@ -0,0 +1,379 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_ChainDrawer_h +#define NAN_INCLUDED_ChainDrawer_h + +#include "../common/GlutDrawer.h" +#include "MyGlutMouseHandler.h" +#include "MyGlutKeyHandler.h" +#include "MT_Transform.h" +# include "IK_Qsolver.h" +# include "../intern/IK_QChain.h" +# include "../intern/IK_QSolver_Class.h" +#include + +class ChainDrawer : public GlutDrawer +{ +public : + static + ChainDrawer * + New( + ) { + return new ChainDrawer(); + } + + void + SetMouseHandler( + MyGlutMouseHandler *mouse_handler + ) { + m_mouse_handler = mouse_handler; + } + + void + SetKeyHandler ( + MyGlutKeyHandler *key_handler + ) { + m_key_handler = key_handler; + } + + void + SetChain( + IK_Chain_ExternPtr *chains,int chain_num + ) { + m_chain_num = chain_num; + m_chains = chains; + } + + + // inherited from GlutDrawer + void + Draw( + ) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glPopMatrix(); + glPushMatrix(); + glRotatef(m_mouse_handler->AngleX(), 0.0, 1.0, 0.0); + glRotatef(m_mouse_handler->AngleY(), 1.0, 0.0, 0.0); + + DrawScene(); + glutSwapBuffers(); + + } + + ~ChainDrawer( + ){ + // nothing to do + }; + +private : + + void + DrawScene( + ){ + + // draw a little cross at the position of the key handler + // coordinates + + MT_Vector3 line_x(4,0,0); + MT_Vector3 line_y(0.0,4,0); + MT_Vector3 line_z(0.0,0.0,4); + + MT_Vector3 cross_origin = m_mouse_handler->Position(); + MT_Vector3 temp; + + glDisable(GL_LIGHTING); + + + glBegin(GL_LINES); + + glColor3f (1.0f,1.0f,1.0f); + + temp = cross_origin - line_x; + glVertex3f(temp[0],temp[1],temp[2]); + temp = cross_origin + line_x; + glVertex3f(temp[0],temp[1],temp[2]); + + temp = cross_origin - line_y; + glVertex3f(temp[0],temp[1],temp[2]); + temp = cross_origin + line_y; + glVertex3f(temp[0],temp[1],temp[2]); + + temp = cross_origin - line_z; + glVertex3f(temp[0],temp[1],temp[2]); + temp = cross_origin + line_z; + glVertex3f(temp[0],temp[1],temp[2]); + + glEnd(); + glEnable(GL_LIGHTING); + + + IK_Chain_ExternPtr chain; + + int chain_num; + for (chain_num = 0; chain_num < m_chain_num; chain_num++) { + chain = m_chains[chain_num]; + + + IK_Segment_ExternPtr segs = chain->segments; + IK_Segment_ExternPtr seg_start = segs; + const IK_Segment_ExternPtr seg_end = segs + chain->num_segments; + float ogl_matrix[16]; + + glColor3f (0.0f,1.0f,0.0f); + + MT_Vector3 previous_origin(0,0,0); + + MT_Transform global_transform; + global_transform.setIdentity(); + + for (; seg_start != seg_end; ++seg_start) { + + glPushMatrix(); + + // fill ogl_matrix with zeros + + std::fill(ogl_matrix,ogl_matrix + 16,float(0)); + + // we have to do a bit of work here to compute the chain's + // bone values + + // first compute all the matrices we need + + MT_Transform translation; + translation.setIdentity(); + translation.translate(MT_Vector3(0,seg_start->length,0)); + + MT_Matrix3x3 seg_rot( + seg_start->basis_change[0],seg_start->basis_change[1],seg_start->basis_change[2], + seg_start->basis_change[3],seg_start->basis_change[4],seg_start->basis_change[5], + seg_start->basis_change[6],seg_start->basis_change[7],seg_start->basis_change[8] + ); + + seg_rot.transpose(); + + MT_Matrix3x3 seg_pre_rot( + seg_start->basis[0],seg_start->basis[1],seg_start->basis[2], + seg_start->basis[3],seg_start->basis[4],seg_start->basis[5], + seg_start->basis[6],seg_start->basis[7],seg_start->basis[8] + ); + + + MT_Transform seg_t_pre_rot( + MT_Point3( + seg_start->seg_start[0], + seg_start->seg_start[1], + seg_start->seg_start[2] + ), + seg_pre_rot + ); + // start of the bone is just the current global transform + // multiplied by the seg_start vector + + + + MT_Transform seg_t_rot(MT_Point3(0,0,0),seg_rot); + MT_Transform seg_local = seg_t_pre_rot * seg_t_rot * translation; + + MT_Vector3 bone_start = global_transform * + MT_Point3( + seg_start->seg_start[0], + seg_start->seg_start[1], + seg_start->seg_start[2] + ); + + + global_transform = global_transform * seg_local; + + global_transform.getValue(ogl_matrix); + MT_Vector3 bone_end = global_transform.getOrigin(); + + glMultMatrixf(ogl_matrix); +// glutSolidSphere(0.5,5,5); + + glPopMatrix(); + + glDisable(GL_LIGHTING); + + glBegin(GL_LINES); + + // draw lines of the principle axis of the local transform + + MT_Vector3 x_axis(1,0,0); + MT_Vector3 y_axis(0,1,0); + MT_Vector3 z_axis(0,0,1); + + x_axis = global_transform.getBasis() * x_axis * 5; + y_axis = global_transform.getBasis() * y_axis * 5; + z_axis = global_transform.getBasis() * z_axis * 5; + + + x_axis = x_axis + bone_start; + y_axis = y_axis + bone_start; + z_axis = z_axis + bone_start; + + glColor3f(1,0,0); + + glVertex3f(x_axis.x(),x_axis.y(),x_axis.z()); + glVertex3f( + bone_start.x(), + bone_start.y(), + bone_start.z() + ); + + glColor3f(0,1,0); + + glVertex3f(y_axis.x(),y_axis.y(),y_axis.z()); + glVertex3f( + bone_start.x(), + bone_start.y(), + bone_start.z() + ); + + glColor3f(0,1,1); + + glVertex3f(z_axis.x(),z_axis.y(),z_axis.z()); + glVertex3f( + bone_start.x(), + bone_start.y(), + bone_start.z() + ); + + glColor3f(0,0,1); + + glVertex3f( + bone_start.x(), + bone_start.y(), + bone_start.z() + ); + glVertex3f(bone_end[0],bone_end[1],bone_end[2]); + + glEnd(); + glEnable(GL_LIGHTING); + } +#if 0 + // draw jacobian column vectors + + // hack access to internals + + IK_Solver_Class * internals = static_cast(chain->intern); + + glDisable(GL_LIGHTING); + + glBegin(GL_LINES); + + const TNT::Matrix & jac = internals->Chain().TransposedJacobian(); + + int i = 0; + for (i=0; i < jac.num_rows(); i++) { + glColor3f(1,1,1); + + previous_origin = internals->Chain().Segments()[i/3].GlobalSegmentStart(); + + glVertex3f(previous_origin[0],previous_origin[1],previous_origin[2]); + glVertex3f(jac[i][0] + previous_origin[0],jac[i][1] + previous_origin[1],jac[i][2] + previous_origin[2]); + + + } + glEnd(); + glEnable(GL_LIGHTING); +#endif + + } + + glColor3f(1.0,1.0,1.0); + + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + + MT_Scalar cube_size = 50; + glVertex3f(cube_size,cube_size,cube_size); + glVertex3f(-cube_size,cube_size,cube_size); + + glVertex3f(cube_size,-cube_size,cube_size); + glVertex3f(-cube_size,-cube_size,cube_size); + + glVertex3f(cube_size,cube_size,-cube_size); + glVertex3f(-cube_size,cube_size,-cube_size); + + glVertex3f(cube_size,-cube_size,-cube_size); + glVertex3f(-cube_size,-cube_size,-cube_size); + + + glVertex3f(-cube_size,cube_size,cube_size); + glVertex3f(-cube_size,-cube_size,cube_size); + + glVertex3f(cube_size,cube_size,-cube_size); + glVertex3f(cube_size,-cube_size,-cube_size); + + glVertex3f(cube_size,cube_size,cube_size); + glVertex3f(cube_size,-cube_size,cube_size); + + glVertex3f(-cube_size,cube_size,-cube_size); + glVertex3f(-cube_size,-cube_size,-cube_size); + + + glVertex3f(cube_size,cube_size,cube_size); + glVertex3f(cube_size,cube_size,-cube_size); + + glVertex3f(cube_size,-cube_size,cube_size); + glVertex3f(cube_size,-cube_size,-cube_size); + + glVertex3f(-cube_size,cube_size,cube_size); + glVertex3f(-cube_size,cube_size,-cube_size); + + glVertex3f(-cube_size,-cube_size,cube_size); + glVertex3f(-cube_size,-cube_size,-cube_size); + glEnd(); + glEnable(GL_LIGHTING); + + }; + + + +private : + + MyGlutMouseHandler * m_mouse_handler; + MyGlutKeyHandler *m_key_handler; + IK_Chain_ExternPtr *m_chains; + + int m_chain_num; + ChainDrawer ( + ) : m_chains (NULL), + m_mouse_handler (NULL), + m_chain_num (0) + { + }; + +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/intern/Makefile b/intern/iksolver/test/ik_glut_test/intern/Makefile new file mode 100644 index 00000000000..fe1f4b54182 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/Makefile @@ -0,0 +1,51 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# iksolver test intern Makefile +# + +LIBNAME = intern +SOURCEDIR = intern/iksolver/test/ik_glut_test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I../../../extern +CPPFLAGS += -I../common +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include + +ifeq ($(OS),windows) + CPPFLAGS += -I$(NAN_LIBDIR)/windows/glut-3.7/include +endif + diff --git a/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h b/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h new file mode 100644 index 00000000000..e9a85fad320 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h @@ -0,0 +1,84 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MyGlutKeyHandler_h +#define NAN_INCLUDED_MyGlutKeyHandler_h + +#include "../common/GlutKeyboardManager.h" + +class MyGlutKeyHandler : public GlutKeyboardHandler +{ +public : + static + MyGlutKeyHandler * + New( + ) { + MEM_SmartPtr output = new MyGlutKeyHandler(); + + if (output == NULL + ) { + return NULL; + } + return output.Release(); + + } + + void + HandleKeyboard( + unsigned char key, + int x, + int y + ){ + + switch (key) { + + case 27 : + + exit(0); + } + } + + ~MyGlutKeyHandler( + ) + { + }; + +private : + + MyGlutKeyHandler( + ) + { + } + +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h b/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h new file mode 100644 index 00000000000..978d9693692 --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h @@ -0,0 +1,210 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef NAN_INCLUDED_MyGlutMouseHandler_h +#define NAN_INCLUDED_MyGlutMouseHandler_h + +#include "../common/GlutMouseManager.h" +#include +#include "IK_solver.h" + +class MyGlutMouseHandler : public GlutMouseHandler +{ + +public : + + static + MyGlutMouseHandler * + New( + ) { + MEM_SmartPtr output = new MyGlutMouseHandler(); + if (output == NULL + ) { + return NULL; + } + return output.Release(); + + } + + void + SetChain( + IK_Chain_ExternPtr *chains, int num_chains + ){ + m_chains = chains; + m_num_chains = num_chains; + } + + void + Mouse( + int button, + int state, + int x, + int y + ){ + if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { + m_moving = true; + m_begin_x = x; + m_begin_y = y; + } + if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { + m_moving = false; + } + + if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { + m_tracking = true; + } + if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP) { + m_tracking = false; + } + + if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) { + m_cg_on = true; + } + if (button == GLUT_MIDDLE_BUTTON && state == GLUT_UP) { + m_cg_on = false; + } + + } + + + void + Motion( + int x, + int y + ){ + if (m_moving) { + m_angle_x = m_angle_x + (x - m_begin_x); + m_begin_x = x; + + m_angle_y = m_angle_y + (y - m_begin_y); + m_begin_y = y; + + glutPostRedisplay(); + } + if (m_tracking) { + + int w_h = glutGet((GLenum)GLUT_WINDOW_HEIGHT); + + y = w_h - y; + + double mvmatrix[16]; + double projmatrix[16]; + GLint viewport[4]; + + double px, py, pz,sz; + + /* Get the matrices needed for gluUnProject */ + glGetIntegerv(GL_VIEWPORT, viewport); + glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); + + // work out the position of the end effector in screen space + + GLdouble ex,ey,ez; + ex = m_pos.x(); + ey = m_pos.y(); + ez = m_pos.z(); + + gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz); + gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz); + + m_pos = MT_Vector3(px,py,pz); + + } + if (m_tracking || m_cg_on) { + float temp[3]; + m_pos.getValue(temp); + + IK_SolveChain(m_chains[0],temp,0.01,200,0.1,m_chains[1]->segments); + IK_LoadChain(m_chains[0],m_chains[0]->segments,m_chains[0]->num_segments); + + glutPostRedisplay(); + } + + + } + + const + float + AngleX( + ) const { + return m_angle_x; + } + + const + float + AngleY( + ) const { + return m_angle_y; + } + + const + MT_Vector3 + Position( + ) const { + return m_pos; + } + + +private : + + MyGlutMouseHandler ( + ) : + m_angle_x(0), + m_angle_y(0), + m_begin_x(0), + m_begin_y(0), + m_moving (false), + m_tracking (false), + m_pos(0,0,0), + m_cg_on (false), + m_chains(NULL), + m_num_chains(0) + { + }; + + float m_angle_x; + float m_angle_y; + float m_begin_x; + float m_begin_y; + + bool m_moving; + bool m_tracking; + bool m_cg_on; + MT_Vector3 m_pos; + + IK_Chain_ExternPtr *m_chains; + int m_num_chains; + +}; + +#endif + diff --git a/intern/iksolver/test/ik_glut_test/intern/main.cpp b/intern/iksolver/test/ik_glut_test/intern/main.cpp new file mode 100644 index 00000000000..7f1cce80a7e --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/intern/main.cpp @@ -0,0 +1,364 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_SmartPtr.h" + +#ifdef USE_QUATERNIONS +#include "IK_Qsolver.h" +#else +#include "IK_solver.h" +#endif + +#include +#include "MT_Vector3.h" +#include "MT_Quaternion.h" +#include "MT_Matrix3x3.h" +#include "MyGlutMouseHandler.h" +#include "MyGlutKeyHandler.h" +#include "ChainDrawer.h" + +void +init(MT_Vector3 min,MT_Vector3 max) +{ + + GLfloat light_diffuse0[] = {1.0, 0.0, 0.0, 1.0}; /* Red diffuse light. */ + GLfloat light_position0[] = {1.0, 1.0, 1.0, 0.0}; /* Infinite light location. */ + + GLfloat light_diffuse1[] = {1.0, 1.0, 1.0, 1.0}; /* Red diffuse light. */ + GLfloat light_position1[] = {1.0, 0, 0, 0.0}; /* Infinite light location. */ + + /* Enable a single OpenGL light. */ + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0); + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + + /* Use depth buffering for hidden surface elimination. */ + glEnable(GL_DEPTH_TEST); + + /* Setup the view of the cube. */ + glMatrixMode(GL_PROJECTION); + + // center of the box + 3* depth of box + + MT_Vector3 center = (min + max) * 0.5; + MT_Vector3 diag = max - min; + + float depth = diag.length(); + float distance = 2; + + gluPerspective( + /* field of view in degree */ 40.0, + /* aspect ratio */ 1.0, + /* Z near */ 1.0, + /* Z far */ distance * depth * 2 + ); + glMatrixMode(GL_MODELVIEW); + + + gluLookAt( + center.x(), center.y(), center.z() + distance*depth, /* eye is at (0,0,5) */ + center.x(), center.y(), center.z(), /* center is at (0,0,0) */ + 0.0, 1.0, 0.); /* up is in positive Y direction */ + + glPushMatrix(); + + +} +int +main(int argc, char **argv) +{ + + + const int seg_num = 5; + const MT_Scalar seg_length = 15; + + const float seg_startA[3] = {0,0,0}; + const float seg_startB[3] = {0,-20,0}; + + // create some segments to solve with + + // First chain + ////////////// + + + IK_Segment_ExternPtr const segmentsA = new IK_Segment_Extern[seg_num]; + IK_Segment_ExternPtr const segmentsB = new IK_Segment_Extern[seg_num]; + + IK_Segment_ExternPtr seg_it = segmentsA; + IK_Segment_ExternPtr seg_itB = segmentsB; + + + { + +// MT_Quaternion qmat(MT_Vector3(0,0,1),-3.141/2); + MT_Quaternion qmat(MT_Vector3(0,0,1),0); + MT_Matrix3x3 mat(qmat); + + seg_it->seg_start[0] = seg_startA[0]; + seg_it->seg_start[1] = seg_startA[1]; + seg_it->seg_start[2] = seg_startA[2]; + + float temp[12]; + mat.getValue(temp); + + seg_it->basis[0] = temp[0]; + seg_it->basis[1] = temp[1]; + seg_it->basis[2] = temp[2]; + + seg_it->basis[3] = temp[4]; + seg_it->basis[4] = temp[5]; + seg_it->basis[5] = temp[6]; + + seg_it->basis[6] = temp[8]; + seg_it->basis[7] = temp[9]; + seg_it->basis[8] = temp[10]; + + seg_it->length = seg_length; + + MT_Quaternion q; + q.setEuler(0,0,0); + + + MT_Matrix3x3 qrot(q); + + seg_it->basis_change[0] = 1; + seg_it->basis_change[1] = 0; + seg_it->basis_change[2] = 0; + seg_it->basis_change[3] = 0; + seg_it->basis_change[4] = 1; + seg_it->basis_change[5] = 0; + seg_it->basis_change[6] = 0; + seg_it->basis_change[7] = 0; + seg_it->basis_change[8] = 1; + + + seg_it ++; + + seg_itB->seg_start[0] = seg_startA[0]; + seg_itB->seg_start[1] = seg_startA[1]; + seg_itB->seg_start[2] = seg_startA[2]; + + seg_itB->basis[0] = temp[0]; + seg_itB->basis[1] = temp[1]; + seg_itB->basis[2] = temp[2]; + + seg_itB->basis[3] = temp[4]; + seg_itB->basis[4] = temp[5]; + seg_itB->basis[5] = temp[6]; + + seg_itB->basis[6] = temp[8]; + seg_itB->basis[7] = temp[9]; + seg_itB->basis[8] = temp[10]; + + seg_itB->length = seg_length; + + seg_itB->basis_change[0] = 1; + seg_itB->basis_change[1] = 0; + seg_itB->basis_change[2] = 0; + seg_itB->basis_change[3] = 0; + seg_itB->basis_change[4] = 1; + seg_itB->basis_change[5] = 0; + seg_itB->basis_change[6] = 0; + seg_itB->basis_change[7] = 0; + seg_itB->basis_change[8] = 1; + + + seg_itB ++; + + + } + + + int i; + for (i=1; i < seg_num; ++i, ++seg_it,++seg_itB) { + + MT_Quaternion qmat(MT_Vector3(0,0,1),0.3); + MT_Matrix3x3 mat(qmat); + + seg_it->seg_start[0] = 0; + seg_it->seg_start[1] = 0; + seg_it->seg_start[2] = 0; + + float temp[12]; + mat.getValue(temp); + + seg_it->basis[0] = temp[0]; + seg_it->basis[1] = temp[1]; + seg_it->basis[2] = temp[2]; + + seg_it->basis[3] = temp[4]; + seg_it->basis[4] = temp[5]; + seg_it->basis[5] = temp[6]; + + seg_it->basis[6] = temp[8]; + seg_it->basis[7] = temp[9]; + seg_it->basis[8] = temp[10]; + + seg_it->length = seg_length; + + MT_Quaternion q; + q.setEuler(0,0,0); + + + MT_Matrix3x3 qrot(q); + + seg_it->basis_change[0] = 1; + seg_it->basis_change[1] = 0; + seg_it->basis_change[2] = 0; + seg_it->basis_change[3] = 0; + seg_it->basis_change[4] = 1; + seg_it->basis_change[5] = 0; + seg_it->basis_change[6] = 0; + seg_it->basis_change[7] = 0; + seg_it->basis_change[8] = 1; + + + /////////////////////////////// + + seg_itB->seg_start[0] = 0; + seg_itB->seg_start[1] = 0; + seg_itB->seg_start[2] = 0; + + seg_itB->basis[0] = temp[0]; + seg_itB->basis[1] = temp[1]; + seg_itB->basis[2] = temp[2]; + + seg_itB->basis[3] = temp[4]; + seg_itB->basis[4] = temp[5]; + seg_itB->basis[5] = temp[6]; + + seg_itB->basis[6] = temp[8]; + seg_itB->basis[7] = temp[9]; + seg_itB->basis[8] = temp[10]; + + seg_itB->length = seg_length; + + seg_itB->basis_change[0] = 1; + seg_itB->basis_change[1] = 0; + seg_itB->basis_change[2] = 0; + seg_itB->basis_change[3] = 0; + seg_itB->basis_change[4] = 1; + seg_itB->basis_change[5] = 0; + seg_itB->basis_change[6] = 0; + seg_itB->basis_change[7] = 0; + seg_itB->basis_change[8] = 1; + + + + } + + // create the chains + + const int num_chains = 2; + + IK_Chain_ExternPtr chains[num_chains]; + + chains[0] = IK_CreateChain(); + chains[1] = IK_CreateChain(); + + // load segments into chain + + IK_LoadChain(chains[0],segmentsA,seg_num); + IK_LoadChain(chains[1],segmentsB,seg_num); + + // make and install a mouse handler + + MEM_SmartPtr mouse_handler (MyGlutMouseHandler::New()); + GlutMouseManager::Instance()->InstallHandler(mouse_handler); + + mouse_handler->SetChain(chains,num_chains); + + // make and install a keyhandler + MEM_SmartPtr key_handler (MyGlutKeyHandler::New()); + GlutKeyboardManager::Instance()->InstallHandler(key_handler); + + // instantiate the drawing class + + MEM_SmartPtr drawer (ChainDrawer::New()); + GlutDrawManager::Instance()->InstallDrawer(drawer); + + drawer->SetMouseHandler(mouse_handler); + drawer->SetChain(chains,num_chains); + drawer->SetKeyHandler(key_handler); + + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutCreateWindow("ik"); + glutDisplayFunc(GlutDrawManager::Draw); + glutMouseFunc(GlutMouseManager::Mouse); + glutMotionFunc(GlutMouseManager::Motion); + glutKeyboardFunc(GlutKeyboardManager::HandleKeyboard); + + init(MT_Vector3(-50,-50,-50),MT_Vector3(50,50,50)); + glutMainLoop(); + return 0; /* ANSI C requires main to return int. */ +} diff --git a/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsp b/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsp new file mode 100644 index 00000000000..8688b2fcc2c --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsp @@ -0,0 +1,130 @@ +# Microsoft Developer Studio Project File - Name="ik_glut_test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ik_glut_test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ik_glut_test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ik_glut_test.mak" CFG="ik_glut_test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ik_glut_test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ik_glut_test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ik_glut_test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\extern" /I "..\..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\..\lib\windows\memutil\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 iksolver_rmtd.lib libmoto.a /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\lib\windows\release" /libpath:"..\..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\..\lib\windows\moto\lib" + +!ELSEIF "$(CFG)" == "ik_glut_test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\extern" /I "..\..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\..\lib\windows\memutil\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 iksolver_dmtd.lib libmoto.a /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBCMTD.lib" /pdbtype:sept /libpath:"..\..\..\..\lib\windows\debug" /libpath:"..\..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\..\lib\windows\moto\lib\debug" + +!ENDIF + +# Begin Target + +# Name "ik_glut_test - Win32 Release" +# Name "ik_glut_test - Win32 Debug" +# Begin Group "common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\common\GlutDrawer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutDrawer.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutKeyboardManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutKeyboardManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutMouseManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\common\GlutMouseManager.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\intern\ChainDrawer.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\main.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MyGlutKeyHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MyGlutMouseHandler.h +# End Source File +# End Target +# End Project diff --git a/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsw b/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsw new file mode 100644 index 00000000000..09b7094137b --- /dev/null +++ b/intern/iksolver/test/ik_glut_test/make/msvc_6_0/ik_glut_test.dsw @@ -0,0 +1,49 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ik_glut_test"=.\ik_glut_test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name iksolver + End Project Dependency +}}} + +############################################################################### + +Project: "iksolver"=..\..\..\..\make\msvc_6_0\iksolver.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + + + + + + diff --git a/intern/make/msvc_6_0/build_install_all.dsp b/intern/make/msvc_6_0/build_install_all.dsp new file mode 100644 index 00000000000..110c28ddeac --- /dev/null +++ b/intern/make/msvc_6_0/build_install_all.dsp @@ -0,0 +1,68 @@ +# Microsoft Developer Studio Project File - Name="Build_install_all" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Generic Project" 0x010a + +CFG=Build_install_all - Win32 Debug +!MESSAGE This is not a valid makefile. To Build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Build_install_all.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Build_install_all.mak" CFG="Build_install_all - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Build_install_all - Win32 Release" (based on "Win32 (x86) Generic Project") +!MESSAGE "Build_install_all - Win32 Debug" (based on "Win32 (x86) Generic Project") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +MTL=midl.exe + +!IF "$(CFG)" == "Build_install_all - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "Build_install_all - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Python freeze +PostBuild_Cmds=ECHO Freezing Blender Python code ..\..\python\freeze\freeze.bat +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "Build_install_all - Win32 Release" +# Name "Build_install_all - Win32 Debug" +# End Target +# End Project diff --git a/intern/make/msvc_6_0/intern.dsw b/intern/make/msvc_6_0/intern.dsw new file mode 100644 index 00000000000..2818636c1c6 --- /dev/null +++ b/intern/make/msvc_6_0/intern.dsw @@ -0,0 +1,302 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Build_install_all"=.\build_install_all.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name OpenNL + End Project Dependency + Begin Project Dependency + Project_Dep_Name bmfont + End Project Dependency + Begin Project Dependency + Project_Dep_Name bsplib + End Project Dependency + Begin Project Dependency + Project_Dep_Name container + End Project Dependency + Begin Project Dependency + Project_Dep_Name decimation + End Project Dependency + Begin Project Dependency + Project_Dep_Name DummySoundSystem + End Project Dependency + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name guardedalloc + End Project Dependency + Begin Project Dependency + Project_Dep_Name iksolver + End Project Dependency + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency + Begin Project Dependency + Project_Dep_Name SoundSystem + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency + Begin Project Dependency + Project_Dep_Name elbeem + End Project Dependency + Begin Project Dependency + Project_Dep_Name boolop + End Project Dependency + Begin Project Dependency + Project_Dep_Name OpenALSoundSystem + End Project Dependency +}}} + +############################################################################### + +Project: "DummySoundSystem"=..\..\SoundSystem\make\msvc_6_0\dummy\DummySoundSystem.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "MoTo"=..\..\moto\make\msvc_6_0\MoTo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "OpenALSoundSystem"=..\..\SoundSystem\make\msvc_6_0\openal\OpenALSoundSystem.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "OpenNL"=..\..\opennl\make\msvc_6_0\OpenNL.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SoundSystem"=..\..\SoundSystem\make\msvc_6_0\SoundSystem.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bmfont"=..\..\bmfont\make\msvc_6_0\bmfont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "boolop"=..\..\boolop\make\msvc_6_0\boolop.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bsplib"=..\..\bsp\make\msvc6_0\bsplib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name container + End Project Dependency + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency +}}} + +############################################################################### + +Project: "container"=..\..\container\make\msvc_6_0\container.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "csg"=..\..\csg\make\msvc60\csg.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "decimation"=..\..\decimation\make\msvc_6_0\decimation.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency + Begin Project Dependency + Project_Dep_Name container + End Project Dependency +}}} + +############################################################################### + +Project: "elbeem"=..\..\elbeem\make\msvc_6_0\elbeem.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "ghost"=..\..\ghost\make\msvc\ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name string + End Project Dependency +}}} + +############################################################################### + +Project: "guardedalloc"=..\..\guardedalloc\make\msvc_6_0\guardedalloc.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "iksolver"=..\..\iksolver\make\msvc_6_0\iksolver.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "memutil"=..\..\memutil\make\msvc_60\memutil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "string"=..\..\string\make\msvc_6_0\string.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/make/msvc_7_0/build_install_all.vcproj b/intern/make/msvc_7_0/build_install_all.vcproj new file mode 100644 index 00000000000..3d80bd48b8b --- /dev/null +++ b/intern/make/msvc_7_0/build_install_all.vcproj @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/make/msvc_7_0/intern.sln b/intern/make/msvc_7_0/intern.sln new file mode 100644 index 00000000000..5fdb4ca95d0 --- /dev/null +++ b/intern/make/msvc_7_0/intern.sln @@ -0,0 +1,252 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "build_install_all", "build_install_all.vcproj", "{02110D03-59DB-4571-8787-72B3C03B2F2D}" + ProjectSection(ProjectDependencies) = postProject + {A90C4918-4B21-4277-93BD-AF65F30951D9} = {A90C4918-4B21-4277-93BD-AF65F30951D9} + {98330220-47A6-42E0-9DE4-AD0FF5D204D6} = {98330220-47A6-42E0-9DE4-AD0FF5D204D6} + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8} = {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8} + {FAF46346-65CC-4DB2-85C4-B99826F79D0C} = {FAF46346-65CC-4DB2-85C4-B99826F79D0C} + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E} = {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E} + {E784098D-3ED8-433A-9353-9679415DDDC5} = {E784098D-3ED8-433A-9353-9679415DDDC5} + {76D90B92-ECC7-409C-9F98-A8814B90F3C0} = {76D90B92-ECC7-409C-9F98-A8814B90F3C0} + {542A9FA1-B7FF-441C-AE15-054DB31D3488} = {542A9FA1-B7FF-441C-AE15-054DB31D3488} + {213356A9-3A1F-41DA-9819-1297BCD17DEE} = {213356A9-3A1F-41DA-9819-1297BCD17DEE} + {51A348C1-8684-4D67-B980-97B1FC74159B} = {51A348C1-8684-4D67-B980-97B1FC74159B} + {8B8D4FC3-3234-4E54-8376-5AB83D00D164} = {8B8D4FC3-3234-4E54-8376-5AB83D00D164} + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9} = {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9} + {E86B7BDE-C33C-4E55-9433-E74C141D7538} = {E86B7BDE-C33C-4E55-9433-E74C141D7538} + {B789C2F3-279E-4A85-8F0A-7F7AC068E598} = {B789C2F3-279E-4A85-8F0A-7F7AC068E598} + {6B3229F4-2A37-47EE-8B89-9AA046B35193} = {6B3229F4-2A37-47EE-8B89-9AA046B35193} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MoTo", "..\..\moto\make\msvc_7_0\MoTo.vcproj", "{4B6AFCC5-968C-424A-8F20-76E41B3BEF74}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bmfont", "..\..\bmfont\make\msvc_7_0\bmfont.vcproj", "{E784098D-3ED8-433A-9353-9679415DDDC5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bsplib", "..\..\bsp\make\msvc_7_0\bsplib.vcproj", "{B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}" + ProjectSection(ProjectDependencies) = postProject + {51A348C1-8684-4D67-B980-97B1FC74159B} = {51A348C1-8684-4D67-B980-97B1FC74159B} + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {E86B7BDE-C33C-4E55-9433-E74C141D7538} = {E86B7BDE-C33C-4E55-9433-E74C141D7538} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "container", "..\..\container\make\msvc_7_0\container.vcproj", "{51A348C1-8684-4D67-B980-97B1FC74159B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "decimation", "..\..\decimation\make\msvc_7_0\decimation.vcproj", "{C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}" + ProjectSection(ProjectDependencies) = postProject + {51A348C1-8684-4D67-B980-97B1FC74159B} = {51A348C1-8684-4D67-B980-97B1FC74159B} + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {E86B7BDE-C33C-4E55-9433-E74C141D7538} = {E86B7BDE-C33C-4E55-9433-E74C141D7538} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghost", "..\..\ghost\make\msvc_7_0\ghost.vcproj", "{76D90B92-ECC7-409C-9F98-A8814B90F3C0}" + ProjectSection(ProjectDependencies) = postProject + {B789C2F3-279E-4A85-8F0A-7F7AC068E598} = {B789C2F3-279E-4A85-8F0A-7F7AC068E598} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "guardedalloc", "..\..\guardedalloc\make\msvc_7_0\guardedalloc.vcproj", "{6B3229F4-2A37-47EE-8B89-9AA046B35193}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iksolver", "..\..\iksolver\make\msvc_7_0\iksolver.vcproj", "{542A9FA1-B7FF-441C-AE15-054DB31D3488}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memutil", "..\..\memutil\make\msvc_7_0\memutil.vcproj", "{E86B7BDE-C33C-4E55-9433-E74C141D7538}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string", "..\..\string\make\msvc_7_0\string.vcproj", "{B789C2F3-279E-4A85-8F0A-7F7AC068E598}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundSystem", "..\..\SoundSystem\make\msvc_7_0\SoundSystem.vcproj", "{98330220-47A6-42E0-9DE4-AD0FF5D204D6}" + ProjectSection(ProjectDependencies) = postProject + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {B789C2F3-279E-4A85-8F0A-7F7AC068E598} = {B789C2F3-279E-4A85-8F0A-7F7AC068E598} + {6B3229F4-2A37-47EE-8B89-9AA046B35193} = {6B3229F4-2A37-47EE-8B89-9AA046B35193} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenALSoundSystem", "..\..\SoundSystem\make\msvc_7_0\openal\OpenALSoundSystem.vcproj", "{213356A9-3A1F-41DA-9819-1297BCD17DEE}" + ProjectSection(ProjectDependencies) = postProject + {98330220-47A6-42E0-9DE4-AD0FF5D204D6} = {98330220-47A6-42E0-9DE4-AD0FF5D204D6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DummySoundSystem", "..\..\SoundSystem\make\msvc_7_0\dummy\DummySoundSystem.vcproj", "{FAF46346-65CC-4DB2-85C4-B99826F79D0C}" + ProjectSection(ProjectDependencies) = postProject + {98330220-47A6-42E0-9DE4-AD0FF5D204D6} = {98330220-47A6-42E0-9DE4-AD0FF5D204D6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opennl", "..\..\opennl\make\msvc_7_0\opennl.vcproj", "{8B8D4FC3-3234-4E54-8376-5AB83D00D164}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elbeem", "..\..\elbeem\make\msvc_7_0\elbeem.vcproj", "{A90C4918-4B21-4277-93BD-AF65F30951D9}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boolop", "..\..\boolop\make\msvc_7_0\boolop.vcproj", "{EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}" + ProjectSection(ProjectDependencies) = postProject + {51A348C1-8684-4D67-B980-97B1FC74159B} = {51A348C1-8684-4D67-B980-97B1FC74159B} + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} = {4B6AFCC5-968C-424A-8F20-76E41B3BEF74} + {E86B7BDE-C33C-4E55-9433-E74C141D7538} = {E86B7BDE-C33C-4E55-9433-E74C141D7538} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + 3DPlugin Debug = 3DPlugin Debug + 3DPlugin Release = 3DPlugin Release + Blender Debug = Blender Debug + Blender Release = Blender Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {02110D03-59DB-4571-8787-72B3C03B2F2D}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.Blender Debug.Build.0 = Blender Debug|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.Blender Release.ActiveCfg = Blender Release|Win32 + {02110D03-59DB-4571-8787-72B3C03B2F2D}.Blender Release.Build.0 = Blender Release|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.Blender Debug.Build.0 = Blender Debug|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.Blender Release.ActiveCfg = Blender Release|Win32 + {4B6AFCC5-968C-424A-8F20-76E41B3BEF74}.Blender Release.Build.0 = Blender Release|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.Blender Debug.Build.0 = Blender Debug|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.Blender Release.ActiveCfg = Blender Release|Win32 + {E784098D-3ED8-433A-9353-9679415DDDC5}.Blender Release.Build.0 = Blender Release|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.Blender Debug.Build.0 = Blender Debug|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.Blender Release.ActiveCfg = Blender Release|Win32 + {B093415D-C0F6-4E76-8F5A-6BC1917BCE9E}.Blender Release.Build.0 = Blender Release|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.Blender Debug.Build.0 = Blender Debug|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.Blender Release.ActiveCfg = Blender Release|Win32 + {51A348C1-8684-4D67-B980-97B1FC74159B}.Blender Release.Build.0 = Blender Release|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.Blender Debug.Build.0 = Blender Debug|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.Blender Release.ActiveCfg = Blender Release|Win32 + {C66F722C-46BE-40C9-ABAE-2EAC7A697EB8}.Blender Release.Build.0 = Blender Release|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.Blender Debug.Build.0 = Blender Debug|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.Blender Release.ActiveCfg = Blender Release|Win32 + {76D90B92-ECC7-409C-9F98-A8814B90F3C0}.Blender Release.Build.0 = Blender Release|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.Blender Debug.Build.0 = Blender Debug|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.Blender Release.ActiveCfg = Blender Release|Win32 + {6B3229F4-2A37-47EE-8B89-9AA046B35193}.Blender Release.Build.0 = Blender Release|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.Blender Debug.Build.0 = Blender Debug|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.Blender Release.ActiveCfg = Blender Release|Win32 + {542A9FA1-B7FF-441C-AE15-054DB31D3488}.Blender Release.Build.0 = Blender Release|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.Blender Debug.Build.0 = Blender Debug|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.Blender Release.ActiveCfg = Blender Release|Win32 + {E86B7BDE-C33C-4E55-9433-E74C141D7538}.Blender Release.Build.0 = Blender Release|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.Blender Debug.Build.0 = Blender Debug|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.Blender Release.ActiveCfg = Blender Release|Win32 + {B789C2F3-279E-4A85-8F0A-7F7AC068E598}.Blender Release.Build.0 = Blender Release|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.Blender Debug.Build.0 = Blender Debug|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.Blender Release.ActiveCfg = Blender Release|Win32 + {98330220-47A6-42E0-9DE4-AD0FF5D204D6}.Blender Release.Build.0 = Blender Release|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.Blender Debug.Build.0 = Blender Debug|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.Blender Release.ActiveCfg = Blender Release|Win32 + {213356A9-3A1F-41DA-9819-1297BCD17DEE}.Blender Release.Build.0 = Blender Release|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.Blender Debug.Build.0 = Blender Debug|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.Blender Release.ActiveCfg = Blender Release|Win32 + {FAF46346-65CC-4DB2-85C4-B99826F79D0C}.Blender Release.Build.0 = Blender Release|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.Blender Debug.Build.0 = Blender Debug|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.Blender Release.ActiveCfg = Blender Release|Win32 + {8B8D4FC3-3234-4E54-8376-5AB83D00D164}.Blender Release.Build.0 = Blender Release|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.Blender Debug.Build.0 = Blender Debug|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.Blender Release.ActiveCfg = Blender Release|Win32 + {A90C4918-4B21-4277-93BD-AF65F30951D9}.Blender Release.Build.0 = Blender Release|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.3DPlugin Debug.ActiveCfg = 3DPlugin Debug|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.3DPlugin Debug.Build.0 = 3DPlugin Debug|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.3DPlugin Release.ActiveCfg = 3DPlugin Release|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.3DPlugin Release.Build.0 = 3DPlugin Release|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.Blender Debug.Build.0 = Blender Debug|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.Blender Release.ActiveCfg = Blender Release|Win32 + {EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}.Blender Release.Build.0 = Blender Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/memutil/CMakeLists.txt b/intern/memutil/CMakeLists.txt new file mode 100644 index 00000000000..a116ca8b721 --- /dev/null +++ b/intern/memutil/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC . ..) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_memutil "${SRC}" "${INC}") +#, libtype=['intern', 'player'], priority = [0, 180] ) diff --git a/intern/memutil/MEM_Allocator.h b/intern/memutil/MEM_Allocator.h new file mode 100644 index 00000000000..68712e45558 --- /dev/null +++ b/intern/memutil/MEM_Allocator.h @@ -0,0 +1,111 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Peter Schlaile 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_Allocator_h_included__ +#define __MEM_Allocator_h_included__ 1 + +#include "guardedalloc/MEM_guardedalloc.h" + +#ifdef _MSC_VER +#if _MSC_VER < 1300 // 1200 == VC++ 6.0 according to boost +#define MS_VISUALC_6_0_WORKAROUND 1 +#endif +#endif + +template +struct MEM_Allocator +{ + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + typedef _Tp value_type; + +#ifndef MS_VISUALC_6_0_WORKAROUND + template + struct rebind { + typedef MEM_Allocator<_Tp1> other; + }; +#endif + + MEM_Allocator() throw() {} + MEM_Allocator(const MEM_Allocator&) throw() {} + +#ifndef MS_VISUALC_6_0_WORKAROUND + template + MEM_Allocator(const MEM_Allocator<_Tp1>) throw() { } +#endif + + ~MEM_Allocator() throw() {} + + pointer address(reference __x) const { return &__x; } + + const_pointer address(const_reference __x) const { return &__x; } + +#ifdef MS_VISUALC_6_0_WORKAROUND + char *_Charalloc(size_type n) { + return (char *) MEM_mallocN(n, "STL MEM_Allocator VC6.0"); + } +#endif + // NB: __n is permitted to be 0. The C++ standard says nothing + // about what the return value is when __n == 0. + _Tp* allocate(size_type __n, const void* = 0) { + _Tp* __ret = 0; + if (__n) + __ret = static_cast<_Tp*>( + MEM_mallocN(__n * sizeof(_Tp), + "STL MEM_Allocator")); + return __ret; + } + +#ifndef MS_VISUALC_6_0_WORKAROUND + // __p is not permitted to be a null pointer. + void deallocate(pointer __p, size_type){ + MEM_freeN(__p); + } +#else + // __p is not permitted to be a null pointer. + void deallocate(void* __p, size_type){ + MEM_freeN(__p); + } +#endif + + size_type max_size() const throw() { + return size_t(-1) / sizeof(_Tp); + } + + void construct(pointer __p, const _Tp& __val) { + new(__p) _Tp(__val); + } + + void destroy(pointer __p) { + __p->~_Tp(); + } +}; + +#endif diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h new file mode 100644 index 00000000000..13fb6b23446 --- /dev/null +++ b/intern/memutil/MEM_CacheLimiter.h @@ -0,0 +1,170 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Peter Schlaile 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_cache_limiter_h_included__ +#define __MEM_cache_limiter_h_included__ 1 + +/** + * @section MEM_CacheLimiter + * This class defines a generic memory cache management system + * to limit memory usage to a fixed global maximum. + * + * Please use the C-API in MEM_CacheLimiterC-Api.h for code written in C. + * + * Usage example: + * + * class BigFatImage { + * public: + * ~BigFatImage() { tell_everyone_we_are_gone(this); } + * }; + * + * void doit() { + * MEM_Cache BigFatImages; + * + * MEM_Cache_Handle* h = BigFatImages.insert(new BigFatImage); + * + * BigFatImages.enforce_limits(); + * h->ref(); + * + * work with image... + * + * h->unref(); + * + * leave image in cache. + */ + +#include +#include "MEM_Allocator.h" + +template +class MEM_CacheLimiter; + +#ifndef __MEM_cache_limiter_c_api_h_included__ +extern "C" { + extern void MEM_CacheLimiter_set_maximum(int m); + extern int MEM_CacheLimiter_get_maximum(); + // this is rather _ugly_! + extern int mem_in_use; + extern int mmap_in_use; +}; +#endif + +template +class MEM_CacheLimiterHandle { +public: + explicit MEM_CacheLimiterHandle(T * data_, + MEM_CacheLimiter * parent_) + : data(data_), refcount(0), parent(parent_) { } + + void ref() { + refcount++; + } + void unref() { + refcount--; + } + T * get() { + return data; + } + const T * get() const { + return data; + } + int get_refcount() const { + return refcount; + } + bool can_destroy() const { + return !data || !refcount; + } + bool destroy_if_possible() { + if (can_destroy()) { + delete data; + data = 0; + unmanage(); + return true; + } + return false; + } + void unmanage() { + parent->unmanage(this); + } + void touch() { + parent->touch(this); + } +private: + friend class MEM_CacheLimiter; + + T * data; + int refcount; + typename std::list *, + MEM_Allocator *> >::iterator me; + MEM_CacheLimiter * parent; +}; + +template +class MEM_CacheLimiter { +public: + typedef typename std::list *, + MEM_Allocator *> >::iterator iterator; + ~MEM_CacheLimiter() { + for (iterator it = queue.begin(); it != queue.end(); it++) { + delete *it; + } + } + MEM_CacheLimiterHandle * insert(T * elem) { + queue.push_back(new MEM_CacheLimiterHandle(elem, this)); + iterator it = queue.end(); + --it; + queue.back()->me = it; + return queue.back(); + } + void unmanage(MEM_CacheLimiterHandle * handle) { + queue.erase(handle->me); + delete handle; + } + void enforce_limits() { + int max = MEM_CacheLimiter_get_maximum(); + if (max == 0) { + return; + } + for (iterator it = queue.begin(); + it != queue.end() && mem_in_use + mmap_in_use > max;) { + iterator jt = it; + ++it; + (*jt)->destroy_if_possible(); + } + } + void touch(MEM_CacheLimiterHandle * handle) { + queue.push_back(handle); + queue.erase(handle->me); + iterator it = queue.end(); + --it; + handle->me = it; + } +private: + std::list*, + MEM_Allocator *> > queue; +}; + +#endif diff --git a/intern/memutil/MEM_CacheLimiterC-Api.h b/intern/memutil/MEM_CacheLimiterC-Api.h new file mode 100644 index 00000000000..f06acb5adea --- /dev/null +++ b/intern/memutil/MEM_CacheLimiterC-Api.h @@ -0,0 +1,144 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Peter Schlaile 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_cache_limiter_c_api_h_included__ +#define __MEM_cache_limiter_c_api_h_included__ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +struct MEM_CacheLimiter_s; +struct MEM_CacheLimiterHandle_s; + +typedef struct MEM_CacheLimiter_s MEM_CacheLimiterC; +typedef struct MEM_CacheLimiterHandle_s MEM_CacheLimiterHandleC; + +/* function used to remove data from memory */ +typedef void(*MEM_CacheLimiter_Destruct_Func)(void*); + +#ifndef __MEM_cache_limiter_h_included__ +extern void MEM_CacheLimiter_set_maximum(int m); +extern int MEM_CacheLimiter_get_maximum(); +#endif +/** + * Create new MEM_CacheLimiter object + * managed objects are destructed with the data_destructor + * + * @param data_destructor + * @return A new MEM_CacheLimter object + */ + +extern MEM_CacheLimiterC * new_MEM_CacheLimiter( + MEM_CacheLimiter_Destruct_Func data_destructor); + +/** + * Delete MEM_CacheLimiter + * + * Frees the memory of the CacheLimiter but does not touch managed objects! + * + * @param This "This" pointer + */ + +extern void delete_MEM_CacheLimiter(MEM_CacheLimiterC * This); + +/** + * Manage object + * + * @param This "This" pointer, data data object to manage + * @return CacheLimiterHandle to ref, unref, touch the managed object + */ + +extern MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert( + MEM_CacheLimiterC * This, void * data); + +/** + * Free objects until memory constraints are satisfied + * + * @param This "This" pointer + */ + +extern void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC * This); + +/** + * Unmanage object previously inserted object. + * Does _not_ delete managed object! + * + * @param This "This" pointer, handle of object + */ + +extern void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC * handle); + + +/** + * Raise priority of object (put it at the tail of the deletion chain) + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC * handle); + +/** + * Increment reference counter. Objects with reference counter != 0 are _not_ + * deleted. + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC * handle); + +/** + * Decrement reference counter. Objects with reference counter != 0 are _not_ + * deleted. + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC * handle); + +/** + * Get reference counter. + * + * @param This "This" pointer, handle of object + */ + +extern int MEM_CacheLimiter_get_refcount(MEM_CacheLimiterHandleC * handle); + +/** + * Get pointer to managed object + * + * @param handle of object + */ + +extern void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/intern/memutil/MEM_NonCopyable.h b/intern/memutil/MEM_NonCopyable.h new file mode 100644 index 00000000000..e413c2ce28c --- /dev/null +++ b/intern/memutil/MEM_NonCopyable.h @@ -0,0 +1,61 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_NonCopyable.h + * Declaration of MEM_NonCopyable class. + */ + +#ifndef NAN_INCLUDED_NonCopyable_h +#define NAN_INCLUDED_NonCopyable_h + +/** + * Simple class that makes sure sub classes cannot + * generate standard copy constructors. + * If you want to make sure that your class does + * not have any of these cheesy hidden constructors + * inherit from this class. + */ + +class MEM_NonCopyable { +protected : + + MEM_NonCopyable( + ) { + }; + +private : + + MEM_NonCopyable (const MEM_NonCopyable *); + MEM_NonCopyable (const MEM_NonCopyable &); +}; + +#endif + diff --git a/intern/memutil/MEM_RefCountPtr.h b/intern/memutil/MEM_RefCountPtr.h new file mode 100644 index 00000000000..042c90fa0cb --- /dev/null +++ b/intern/memutil/MEM_RefCountPtr.h @@ -0,0 +1,293 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_RefCountPtr.h + * Declaration of MEM_RefCounted and MEM_RefCountable classes. + * @author Laurence + */ + +#ifndef NAN_INCLUDED_MEM_RefCountPtr_h +#define NAN_INCLUDED_MEM_RefCountPtr_h + +#include // for NULL ! + +/** + * @section MEM_RefCountable + * This is a base class for reference countable objects. + * If you want an object to be shared using a reference + * counted system derrivce from this class. All subclasses + * should insist that they are created on the heap, this + * can be done by makeing all constructors private and + * defining a static New() method that returns a ref counted + * ptr to a new()ly allocated instance. + * + * @section Example subclass + * + * + * class MySharedObject : public MEM_RefCountable { + * + * private : + * MySharedObject() : MEM_RefCountable() { //class specific initialization}; + * MySharedObject(const MySharedObject &other) // not implemented + * public : + * static + * MEM_RefCountPtr + * New( + * ) { + * return MEM_RefCountPtr( new MySharedObject()); + * } + * + * // other member functions + * }; + * + * Alternitively you may first wish to define a fully functional + * class and then define a reference counting wrapper for this class. + * This is useful when the base type can be used without reference + * counting. + * + * E.g. + * class UsefullClass { + * private : + * ... + * public : + * + * UsefullClass() + * UsefullMethod(...) + * AnotherUsefullMethod(...) + * }; + * + * class RcUsefullClass : public UsefullClass, public MEM_RefCountable + * { + * private : + * // Override base class public constructor --- forces + * // use of New(...) + * RcUsefullClass(...) + * public : + * + * // Override each public constructor of UsefullClass with + * // an equivalent static New method returning a MEM_RefCountPtr + * + * static + * MEM_RefCountPtr + * New(...){ + * return MEM_RefCountPtr output( + * new UsefullClass(...) + * ); + * } + * + * // warning never call destructor directly allow ref counting + * // mechanism to handle object lifetime. + * ~RcUsefullClass(); + * }; + * + * + */ + +class MEM_RefCountable { +private : + + /** + * The reference count! + * We use mutable here because we would like to + * share references of const objects! + * Maybe should think about having decRef() + * another value because we should not be deleting + * non-const objects + */ + + mutable int m_count; + +protected : + + /** + * Protected constructors + * This class is not for direct instanciation. Sub classes + * should only be allocated on the heap. + */ + + MEM_RefCountable ( + ) : + m_count (0) + { + }; + + MEM_RefCountable ( + const MEM_RefCountable & + ) : + m_count (0) + { + } + +public : + + void + IncRef( + ) const { + m_count++; + } + + int + DecRef( + ) { + return (--m_count); + } + + ~MEM_RefCountable( + ) { + //nothing to do + } +}; + +/** + * @section MEM_RefCountPtr + */ + +template + < class T > +class MEM_RefCountPtr { + +public : + + /** + * Construction from reference - share ownership with + * the right hand side. + */ + + MEM_RefCountPtr( + const MEM_RefCountPtr &rhs + ) : m_val (NULL) { + ShareOwnership(rhs.m_val); + } + + /** + * Construction from ptr - this class shares + * ownership of object val. + */ + + MEM_RefCountPtr( + const T* val + ) : + m_val (NULL) + { + ShareOwnership(val); + } + + /** + * Default constructor + */ + + MEM_RefCountPtr( + ) : + m_val (NULL) + { + } + + /** + * Type conversion from this class to the type + * of a pointer to the template parameter. + * This means you can pass an instance of this class + * to a function expecting a ptr of type T. + */ + + operator T * () const { + return m_val; + } + + + MEM_RefCountPtr & operator=( + const MEM_RefCountPtr &rhs + ) { + if (this->m_val != rhs.m_val) { + ReleaseOwnership(); + ShareOwnership(rhs.m_val); + } + return *this; + } + + /** + * Overload the operator -> so that it's possible to access + * all the normal methods of the internal ptr. + */ + + T * operator->() const { + return m_val; + } + + /** + * Returrn a reference to the shared object. + */ + + T& + Ref( + ) { + return *m_val; + } + + + /** + * Destructor - deletes object if it's ref count is zero. + */ + + ~MEM_RefCountPtr( + ) { + ReleaseOwnership(); + } + +private : + + /// The ptr owned by this class. + T * m_val; + + void + ShareOwnership( + const T * val + ) { + if (val != NULL) { + val->IncRef(); + } + m_val = const_cast(val); + } + + void + ReleaseOwnership( + ) { + if (m_val) { + if (m_val->DecRef() == 0) { + delete(m_val); + m_val = NULL; + } + } + } + +}; + +#endif + diff --git a/intern/memutil/MEM_RefCounted.h b/intern/memutil/MEM_RefCounted.h new file mode 100644 index 00000000000..239465cdf34 --- /dev/null +++ b/intern/memutil/MEM_RefCounted.h @@ -0,0 +1,115 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_RefCounted.h + * Declaration of MEM_RefCounted class. + */ + +#ifndef _H_MEM_REF_COUNTED +#define _H_MEM_REF_COUNTED + +/** + * An object with reference counting. + * Base class for objects with reference counting. + * When a shared object is ceated, it has reference count == 1. + * If the the reference count of a shared object reaches zero, the object self-destructs. + * The default destructor of this object has been made protected on purpose. + * This disables the creation of shared objects on the stack. + * + * @author Maarten Gribnau + * @date March 31, 2001 + */ + +class MEM_RefCounted { +public: + /** + * Constructs a a shared object. + */ + MEM_RefCounted() : m_refCount(1) + { + } + + /** + * Returns the reference count of this object. + * @return the reference count. + */ + inline virtual int getRef() const; + + /** + * Increases the reference count of this object. + * @return the new reference count. + */ + inline virtual int incRef(); + + /** + * Decreases the reference count of this object. + * If the the reference count reaches zero, the object self-destructs. + * @return the new reference count. + */ + inline virtual int decRef(); + +protected: + /** + * Destructs a shared object. + * The destructor is protected to force the use of incRef and decRef. + */ + virtual ~MEM_RefCounted() + { + } + +protected: + /// The reference count. + int m_refCount; +}; + + +inline int MEM_RefCounted::getRef() const +{ + return m_refCount; +} + +inline int MEM_RefCounted::incRef() +{ + return ++m_refCount; +} + +inline int MEM_RefCounted::decRef() +{ + m_refCount--; + if (m_refCount == 0) { + delete this; + return 0; + } + return m_refCount; +} + +#endif // _H_MEM_REF_COUNTED + diff --git a/intern/memutil/MEM_RefCountedC-Api.h b/intern/memutil/MEM_RefCountedC-Api.h new file mode 100644 index 00000000000..f78194fe2f6 --- /dev/null +++ b/intern/memutil/MEM_RefCountedC-Api.h @@ -0,0 +1,78 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_RefCountedC-Api.h + * Interface for C access to functionality relating to shared objects in the foundation library. + */ + +#ifndef _H_MEM_REF_COUNTED_C_API +#define _H_MEM_REF_COUNTED_C_API + +/** A pointer to a private object. */ +typedef struct MEM_TOpaqueObject* MEM_TObjectPtr; +/** A pointer to a shared object. */ +typedef MEM_TObjectPtr MEM_TRefCountedObjectPtr; + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Returns the reference count of this object. + * @param shared The object to query. + * @return The current reference count. + */ +extern int MEM_RefCountedGetRef(MEM_TRefCountedObjectPtr shared); + +/** + * Increases the reference count of this object. + * @param shared The object to query. + * @return The new reference count. + */ +extern int MEM_RefCountedIncRef(MEM_TRefCountedObjectPtr shared); + +/** + * Decreases the reference count of this object. + * If the the reference count reaches zero, the object self-destructs. + * @param shared The object to query. + * @return The new reference count. + */ +extern int MEM_RefCountedDecRef(MEM_TRefCountedObjectPtr shared); + + +#ifdef __cplusplus +} +#endif + +#endif // _H_MEM_REF_COUNTED_C_API + diff --git a/intern/memutil/MEM_SmartPtr.h b/intern/memutil/MEM_SmartPtr.h new file mode 100644 index 00000000000..55bae151027 --- /dev/null +++ b/intern/memutil/MEM_SmartPtr.h @@ -0,0 +1,240 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +/** + * @file MEM_SmartPtr.h + * Declaration of MEM_RefCounted and MEM_RefCountable classes. + * @author Laurence + */ + +#ifndef NAN_INCLUDED_MEM_SmartPtr_h +#define NAN_INCLUDED_MEM_SmartPtr_h + + +#include // for NULL ! + + +/** + * @section MEM_SmartPtr + * This class defines a smart pointer similar to that defined in + * the Standard Template Library but without the painful get() + * semantics to access the internal c style pointer. + * + * It is often useful to explicitely decalre ownership of memory + * allocated on the heap within class or function scope. This + * class helps you to encapsulate this ownership within a value + * type. When an instance of this class goes out of scope it + * makes sure that any memory associated with it's internal pointer + * is deleted. It can help to inform users of an aggregate class + * that it owns instances of it's members and these instances + * should not be shared. This is not reliably enforcable in C++ + * but this class attempts to make the 1-1 relationship clear. + * + * @section Example usage + * + * class foo { + * ...constructors accessors etc. + * int x[1000]; + * } + * + * class bar { + * public : + * static + * bar * + * New( + * ) { + * MEM_SmartPtr afoo = new foo(); + * MEM_SmartPtr that = new bar(); + * + * if (foo == NULL || that == NULL) return NULL; + * + * that->m_foo = afoo.Release(); + * return that.Release(); + * } + * + * ~bar() { + * // smart ptr takes care of deletion + * } + * private : + * MEM_SmartPtr m_foo; + * } + * + * You may also safely construct vectors of MEM_SmartPtrs and + * have the vector own stuff you put into it. + * + * e.g. + * { + * std::vector > foo_vector; + * foo_vector.push_back( new foo()); + * foo_vector.push_back( new foo()); + * + * foo_vector[0]->bla(); + * } // foo_vector out of scope => heap memory freed for both foos + * + * @warning this class should only be used for objects created + * on the heap via the new function. It will not behave correctly + * if you pass ptrs to objects created with new[] nor with + * objects declared on the stack. Doing this is likely to crash + * the program or lead to memory leaks. + */ + +template + < class T > +class MEM_SmartPtr { + +public : + + /** + * Construction from reference - this class + * always assumes ownership from the rhs. + */ + + MEM_SmartPtr( + const MEM_SmartPtr &rhs + ){ + m_val = rhs.Release(); + } + + /** + * Construction from ptr - this class always + * assumes that it now owns the memory associated with the + * ptr. + */ + + MEM_SmartPtr( + T* val + ) : + m_val (val) + { + } + + /** + * Defalut constructor + */ + + MEM_SmartPtr( + ) : + m_val (NULL) + { + } + + /** + * Type conversion from this class to the type + * of a pointer to the template parameter. + * This means you can pass an instance of this class + * to a function expecting a ptr of type T. + */ + + operator T * () const { + return m_val; + } + + /** + * Return a reference to the internal ptr class. + * Use with care when you now that the internal ptr + * is not NULL! + */ + + T & + Ref( + ) const { + return *m_val; + } + + /** + * Assignment operator - ownership is transfered from rhs to lhs. + * There is an intenional side-effect of function of transferring + * ownership from the const parameter rhs. This is to insure + * the 1-1 relationship. + * The object associated with this instance is deleted if it + * is not the same as that contained in the rhs. + */ + + MEM_SmartPtr & operator=( + const MEM_SmartPtr &rhs + ) { + if (this->m_val != rhs.m_val) { + delete this->m_val; + } + + this->m_val = rhs.Release(); + return *this; + } + + /** + * Overload the operator -> so that it's possible to access + * all the normal methods of the internal ptr. + */ + + T * operator->() const { + return m_val; + } + + /** + * Caller takes ownership of the object - the object will not + * be deleted when the ptr goes out of scope. + */ + + T * + Release( + ) const { + T* temp = m_val; + (const_cast(this))->m_val = NULL; + return temp; + } + + /** + * Force destruction of the internal object. + */ + + void + Delete( + ) { + delete (m_val); + m_val = NULL; + } + + /** + * Destructor - deletes object if it exists + */ + + ~MEM_SmartPtr( + ) { + delete (m_val); + } + +private : + + /// The ptr owned by this class. + T * m_val; +}; + +#endif + diff --git a/intern/memutil/Makefile b/intern/memutil/Makefile new file mode 100644 index 00000000000..57a8adc8e10 --- /dev/null +++ b/intern/memutil/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# memutil main makefile. +# + +include nan_definitions.mk + +LIBNAME = memutil +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_MEMUTIL) ] || mkdir $(NAN_MEMUTIL) + @[ -d $(NAN_MEMUTIL)/include ] || mkdir $(NAN_MEMUTIL)/include + @[ -d $(NAN_MEMUTIL)/lib ] || mkdir $(NAN_MEMUTIL)/lib + @[ -d $(NAN_MEMUTIL)/lib/debug ] || mkdir $(NAN_MEMUTIL)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libmemutil.a $(NAN_MEMUTIL)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libmemutil.a $(NAN_MEMUTIL)/lib/debug +ifeq ($(OS),darwin) + ranlib $(NAN_MEMUTIL)/lib/libmemutil.a + ranlib $(NAN_MEMUTIL)/lib/debug/libmemutil.a +endif + @../tools/cpifdiff.sh *.h $(NAN_MEMUTIL)/include/ + diff --git a/intern/memutil/SConscript b/intern/memutil/SConscript new file mode 100644 index 00000000000..4528de814f3 --- /dev/null +++ b/intern/memutil/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = '. ..' + +env.BlenderLib ('bf_memutil', sources, Split(incs), [], libtype=['intern', 'player'], priority = [0, 180] ) diff --git a/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp new file mode 100644 index 00000000000..4cf0ef305d4 --- /dev/null +++ b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp @@ -0,0 +1,195 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Peter Schlaile 2005 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_CacheLimiter.h" +#include "MEM_CacheLimiterC-Api.h" + +static int & get_max() +{ + static int m = 32*1024*1024; + return m; +} + +void MEM_CacheLimiter_set_maximum(int m) +{ + get_max() = m; +} + +int MEM_CacheLimiter_get_maximum() +{ + return get_max(); +} + +class MEM_CacheLimiterHandleCClass; +class MEM_CacheLimiterCClass; + +typedef MEM_CacheLimiterHandle handle_t; +typedef MEM_CacheLimiter cache_t; +typedef std::list > list_t; + +class MEM_CacheLimiterCClass { +public: + MEM_CacheLimiterCClass(MEM_CacheLimiter_Destruct_Func data_destructor_) + : data_destructor(data_destructor_) { + } + ~MEM_CacheLimiterCClass(); + + handle_t * insert(void * data); + + void destruct(void * data, + list_t::iterator it); + + cache_t * get_cache() { + return &cache; + } +private: + MEM_CacheLimiter_Destruct_Func data_destructor; + + MEM_CacheLimiter cache; + + list_t cclass_list; +}; + +class MEM_CacheLimiterHandleCClass { +public: + MEM_CacheLimiterHandleCClass(void * data_, + MEM_CacheLimiterCClass * parent_) + : data(data_), parent(parent_) { } + ~MEM_CacheLimiterHandleCClass(); + void set_iter(list_t::iterator it_) { + it = it_; + } + void set_data(void * data_) { + data = data_; + } + void * get_data() const { + return data; + } +private: + void * data; + MEM_CacheLimiterCClass * parent; + list_t::iterator it; +}; + +handle_t * MEM_CacheLimiterCClass::insert(void * data) +{ + cclass_list.push_back(new MEM_CacheLimiterHandleCClass(data, this)); + list_t::iterator it = cclass_list.end(); + --it; + cclass_list.back()->set_iter(it); + + return cache.insert(cclass_list.back()); +} + +void MEM_CacheLimiterCClass::destruct(void * data, list_t::iterator it) +{ + data_destructor(data); + cclass_list.erase(it); +} + +MEM_CacheLimiterHandleCClass::~MEM_CacheLimiterHandleCClass() +{ + if (data) { + parent->destruct(data, it); + } +} + +MEM_CacheLimiterCClass::~MEM_CacheLimiterCClass() +{ + // should not happen, but don't leak memory in this case... + for (list_t::iterator it = cclass_list.begin(); + it != cclass_list.end(); it++) { + (*it)->set_data(0); + delete *it; + } +} + +// ---------------------------------------------------------------------- + +static inline MEM_CacheLimiterCClass* cast(MEM_CacheLimiterC * l) +{ + return (MEM_CacheLimiterCClass*) l; +} + +static inline handle_t* cast(MEM_CacheLimiterHandleC * l) +{ + return (handle_t*) l; +} + +MEM_CacheLimiterC * new_MEM_CacheLimiter( + MEM_CacheLimiter_Destruct_Func data_destructor) +{ + return (MEM_CacheLimiterC*) new MEM_CacheLimiterCClass( + data_destructor); +} + +void delete_MEM_CacheLimiter(MEM_CacheLimiterC * This) +{ + delete cast(This); +} + +MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert( + MEM_CacheLimiterC * This, void * data) +{ + return (MEM_CacheLimiterHandleC *) cast(This)->insert(data); +} + +void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC * This) +{ + cast(This)->get_cache()->enforce_limits(); +} + +void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->unmanage(); +} + +void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->touch(); +} + +void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->ref(); +} + +void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->unref(); +} + +int MEM_CacheLimiter_get_refcount(MEM_CacheLimiterHandleC * handle) +{ + return cast(handle)->get_refcount(); +} + + +void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle) +{ + return cast(handle)->get()->get_data(); +} diff --git a/intern/memutil/intern/MEM_RefCountedC-Api.cpp b/intern/memutil/intern/MEM_RefCountedC-Api.cpp new file mode 100644 index 00000000000..873b2c99a59 --- /dev/null +++ b/intern/memutil/intern/MEM_RefCountedC-Api.cpp @@ -0,0 +1,56 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MEM_RefCountedC-Api.h" +#include "MEM_RefCounted.h" + + + +int MEM_RefCountedGetRef(MEM_TRefCountedObjectPtr shared) +{ + return shared ? ((MEM_RefCounted*)shared)->getRef() : 0; +} + + +int MEM_RefCountedIncRef(MEM_TRefCountedObjectPtr shared) +{ + return shared ? ((MEM_RefCounted*)shared)->incRef() : 0; +} + + +int MEM_RefCountedDecRef(MEM_TRefCountedObjectPtr shared) +{ + return shared ? ((MEM_RefCounted*)shared)->decRef() : 0; +} diff --git a/intern/memutil/intern/Makefile b/intern/memutil/intern/Makefile new file mode 100644 index 00000000000..71ffa6fa7e4 --- /dev/null +++ b/intern/memutil/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# memutil intern Makefile +# + +LIBNAME = memutil +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I.. -I../.. + diff --git a/intern/memutil/make/msvc_60/memutil.dsp b/intern/memutil/make/msvc_60/memutil.dsp new file mode 100644 index 00000000000..62b7efba9d8 --- /dev/null +++ b/intern/memutil/make/msvc_60/memutil.dsp @@ -0,0 +1,150 @@ +# Microsoft Developer Studio Project File - Name="memutil" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=memutil - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "memutil.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "memutil.mak" CFG="memutil - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "memutil - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "memutil - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "memutil - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\memutil\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\memutil\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /I "../../" /I "../../../" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\memutil\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\memutil\*.lib ..\..\..\..\..\lib\windows\memutil\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "memutil - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\memutil\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\memutil\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /I "../../../" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\memutil\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\memutil\debug\*.lib ..\..\..\..\..\lib\windows\memutil\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\memutil\debug\vc60.* ..\..\..\..\..\lib\windows\memutil\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "memutil - Win32 Release" +# Name "memutil - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\MEM_Allocator.h +# End Source File +# Begin Source File + +SOURCE=..\..\MEM_CacheLimiter.h +# End Source File +# Begin Source File + +SOURCE="..\..\intern\MEM_CacheLimiterC-Api.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\..\guardedalloc\MEM_guardedalloc.h +# End Source File +# Begin Source File + +SOURCE="..\..\intern\MEM_RefCountedC-Api.cpp" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "intern" + +# PROP Default_Filter "" +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\MEM_NonCopyable.h +# End Source File +# Begin Source File + +SOURCE=..\..\MEM_RefCounted.h +# End Source File +# Begin Source File + +SOURCE="..\..\MEM_RefCountedC-Api.h" +# End Source File +# Begin Source File + +SOURCE=..\..\MEM_RefCountPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\MEM_SmartPtr.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/intern/memutil/make/msvc_60/memutil.dsw b/intern/memutil/make/msvc_60/memutil.dsw new file mode 100644 index 00000000000..bba4cbcdafd --- /dev/null +++ b/intern/memutil/make/msvc_60/memutil.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "memutil"=".\memutil.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/memutil/make/msvc_7_0/memutil.sln b/intern/memutil/make/msvc_7_0/memutil.sln new file mode 100644 index 00000000000..462cd1a3871 --- /dev/null +++ b/intern/memutil/make/msvc_7_0/memutil.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memutil", "memutil.vcproj", "{8B8B95BA-3084-408F-8EE6-3FE6EF52E112}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {8B8B95BA-3084-408F-8EE6-3FE6EF52E112}.Debug.ActiveCfg = Debug|Win32 + {8B8B95BA-3084-408F-8EE6-3FE6EF52E112}.Debug.Build.0 = Debug|Win32 + {8B8B95BA-3084-408F-8EE6-3FE6EF52E112}.Release.ActiveCfg = Release|Win32 + {8B8B95BA-3084-408F-8EE6-3FE6EF52E112}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/memutil/make/msvc_7_0/memutil.vcproj b/intern/memutil/make/msvc_7_0/memutil.vcproj new file mode 100644 index 00000000000..2d570ea3d49 --- /dev/null +++ b/intern/memutil/make/msvc_7_0/memutil.vcproj @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/moto/CMakeLists.txt b/intern/moto/CMakeLists.txt new file mode 100644 index 00000000000..9004e4c435d --- /dev/null +++ b/intern/moto/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC include) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_moto "${SRC}" "${INC}") +#, libtype=['intern','game','game2','player'], priority = [15, 55, 100, 135] ) diff --git a/intern/moto/Makefile b/intern/moto/Makefile new file mode 100644 index 00000000000..0649719e92e --- /dev/null +++ b/intern/moto/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# moto main makefile. +# + +include nan_definitions.mk + +LIBNAME = moto +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +#not ready yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_MOTO) ] || mkdir $(NAN_MOTO) + @[ -d $(NAN_MOTO)/include ] || mkdir $(NAN_MOTO)/include + @[ -d $(NAN_MOTO)/lib ] || mkdir $(NAN_MOTO)/lib + @[ -d $(NAN_MOTO)/lib/debug ] || mkdir $(NAN_MOTO)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libmoto.a $(NAN_MOTO)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libmoto.a $(NAN_MOTO)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_MOTO)/lib/libmoto.a + ranlib $(NAN_MOTO)/lib/debug/libmoto.a +endif + @../tools/cpifdiff.sh include/*.h $(NAN_MOTO)/include/ + diff --git a/intern/moto/SConscript b/intern/moto/SConscript new file mode 100644 index 00000000000..636515aa5c5 --- /dev/null +++ b/intern/moto/SConscript @@ -0,0 +1,8 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') + +incs = 'include' + +env.BlenderLib ('bf_moto', sources, Split(incs), [], libtype=['intern','game','game2','player'], priority = [15, 55, 100, 135] ) diff --git a/intern/moto/include/GEN_List.h b/intern/moto/include/GEN_List.h new file mode 100644 index 00000000000..00fdbb85ad1 --- /dev/null +++ b/intern/moto/include/GEN_List.h @@ -0,0 +1,117 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef GEN_LIST_H +#define GEN_LIST_H + +class GEN_Link { +public: + GEN_Link() : m_next(0), m_prev(0) {} + GEN_Link(GEN_Link *next, GEN_Link *prev) : m_next(next), m_prev(prev) {} + + GEN_Link *getNext() const { return m_next; } + GEN_Link *getPrev() const { return m_prev; } + + bool isHead() const { return m_prev == 0; } + bool isTail() const { return m_next == 0; } + + void insertBefore(GEN_Link *link) { + m_next = link; + m_prev = link->m_prev; + m_next->m_prev = this; + m_prev->m_next = this; + } + + void insertAfter(GEN_Link *link) { + m_next = link->m_next; + m_prev = link; + m_next->m_prev = this; + m_prev->m_next = this; + } + + void remove() { + m_next->m_prev = m_prev; + m_prev->m_next = m_next; + } + +private: + GEN_Link *m_next; + GEN_Link *m_prev; +}; + +class GEN_List { +public: + GEN_List() : m_head(&m_tail, 0), m_tail(0, &m_head) {} + + GEN_Link *getHead() const { return m_head.getNext(); } + GEN_Link *getTail() const { return m_tail.getPrev(); } + + void addHead(GEN_Link *link) { link->insertAfter(&m_head); } + void addTail(GEN_Link *link) { link->insertBefore(&m_tail); } + +private: + GEN_Link m_head; + GEN_Link m_tail; +}; + +#endif + diff --git a/intern/moto/include/GEN_Map.h b/intern/moto/include/GEN_Map.h new file mode 100644 index 00000000000..64a2c3cfc6e --- /dev/null +++ b/intern/moto/include/GEN_Map.h @@ -0,0 +1,149 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef GEN_MAP_H +#define GEN_MAP_H + +template +class GEN_Map { +private: + struct Entry { + Entry (Entry *next, Key key, Value value) : + m_next(next), + m_key(key), + m_value(value) {} + + Entry *m_next; + Key m_key; + Value m_value; + }; + +public: + GEN_Map(int num_buckets = 100) : m_num_buckets(num_buckets) { + m_buckets = new Entry *[num_buckets]; + for (int i = 0; i < num_buckets; ++i) { + m_buckets[i] = 0; + } + } + + int size() { + int count=0; + for (int i=0;im_next; + count++; + } + } + return count; + } + + Value* at(int index) { + int count=0; + for (int i=0;im_value; + } + bucket = bucket->m_next; + count++; + } + } + return 0; + } + + void clear() { + for (int i = 0; i < m_num_buckets; ++i) { + Entry *entry_ptr = m_buckets[i]; + + while (entry_ptr != 0) { + Entry *tmp_ptr = entry_ptr->m_next; + delete entry_ptr; + entry_ptr = tmp_ptr; + } + m_buckets[i] = 0; + } + } + + ~GEN_Map() { + clear(); + delete [] m_buckets; + } + + void insert(const Key& key, const Value& value) { + Entry *entry_ptr = m_buckets[key.hash() % m_num_buckets]; + while ((entry_ptr != 0) && !(key == entry_ptr->m_key)) { + entry_ptr = entry_ptr->m_next; + } + + if (entry_ptr != 0) { + entry_ptr->m_value = value; + } + else { + Entry **bucket = &m_buckets[key.hash() % m_num_buckets]; + *bucket = new Entry(*bucket, key, value); + } + } + + void remove(const Key& key) { + Entry **entry_ptr = &m_buckets[key.hash() % m_num_buckets]; + while ((*entry_ptr != 0) && !(key == (*entry_ptr)->m_key)) { + entry_ptr = &(*entry_ptr)->m_next; + } + + if (*entry_ptr != 0) { + Entry *tmp_ptr = (*entry_ptr)->m_next; + delete *entry_ptr; + *entry_ptr = tmp_ptr; + } + } + + Value *operator[](Key key) { + Entry *bucket = m_buckets[key.hash() % m_num_buckets]; + while ((bucket != 0) && !(key == bucket->m_key)) { + bucket = bucket->m_next; + } + return bucket != 0 ? &bucket->m_value : 0; + } + +private: + int m_num_buckets; + Entry **m_buckets; +}; + +#endif + diff --git a/intern/moto/include/MT_CmMatrix4x4.h b/intern/moto/include/MT_CmMatrix4x4.h new file mode 100644 index 00000000000..86858576abf --- /dev/null +++ b/intern/moto/include/MT_CmMatrix4x4.h @@ -0,0 +1,147 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef INCLUDED_MT_CmMatrix4x4 +#define INCLUDED_MT_CmMatrix4x4 + +/** + * A 4x4 matrix. This is an OpenGl style matrix (column major) meaning + * that the vector {m[0][0],m[0][1],m[0][2],m[0][3]} is the first column of + * the matrix , the same as what you get if you transform {1,0,0,0}. + * This makes it easy to transform stuff to OpenGl. Please note that the + * the other MoTo matrices are row major. + * + * This class should be deprecated in favour of the more consistent + * MT_Matrix4x4. Please do not start using this class. + */ + +#include "MT_Scalar.h" + +class MT_Point3; +class MT_Vector3; + +class MT_CmMatrix4x4 +{ + +public : + + MT_CmMatrix4x4( + const float value[4][4] + ); + + MT_CmMatrix4x4( + ); + + + MT_CmMatrix4x4( + const double value[16] + ); + + MT_CmMatrix4x4( + const MT_CmMatrix4x4 & other + ); + + MT_CmMatrix4x4( + const MT_Point3& orig, + const MT_Vector3& dir, + const MT_Vector3 up + ); + + void + Identity( + ); + + void + SetMatrix( + const MT_CmMatrix4x4 & other + ); + + double* + getPointer( + ); + + const + double* + getPointer( + ) const; + + void + setElem( + int pos, + double newvalue + ); + + MT_Vector3 + GetRight( + ) const; + + MT_Vector3 + GetUp( + ) const; + + MT_Vector3 + GetDir( + ) const; + + MT_Point3 + GetPos( + ) const; + + void + SetPos( + const MT_Vector3 & v + ); + + double& + operator ( + ) (int row,int col) { return m_V[col][row]; } + + static + MT_CmMatrix4x4 + Perspective( + MT_Scalar inLeft, + MT_Scalar inRight, + MT_Scalar inBottom, + MT_Scalar inTop, + MT_Scalar inNear, + MT_Scalar inFar + ); + +protected: + union + { + double m_V[4][4]; + double m_Vflat[16]; + }; +}; + +#endif //MT_CmMatrix4x4 + diff --git a/intern/moto/include/MT_Matrix3x3.h b/intern/moto/include/MT_Matrix3x3.h new file mode 100644 index 00000000000..fb899a7da96 --- /dev/null +++ b/intern/moto/include/MT_Matrix3x3.h @@ -0,0 +1,224 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_MATRIX3X3_H +#define MT_MATRIX3X3_H + +#include + +#include "MT_Vector3.h" +#include "MT_Quaternion.h" + +class MT_Matrix3x3 { +public: + MT_Matrix3x3() {} + MT_Matrix3x3(const float *m) { setValue(m); } + MT_Matrix3x3(const double *m) { setValue(m); } + MT_Matrix3x3(const MT_Quaternion& q) { setRotation(q); } + + MT_Matrix3x3(const MT_Quaternion& q, const MT_Vector3& s) { + setRotation(q); + scale(s[0], s[1], s[2]); + } + + MT_Matrix3x3(const MT_Vector3& euler) { setEuler(euler); } + MT_Matrix3x3(const MT_Vector3& euler, const MT_Vector3& s) { + setEuler(euler); + scale(s[0], s[1], s[2]); + } + + MT_Matrix3x3(MT_Scalar xx, MT_Scalar xy, MT_Scalar xz, + MT_Scalar yx, MT_Scalar yy, MT_Scalar yz, + MT_Scalar zx, MT_Scalar zy, MT_Scalar zz) { + setValue(xx, xy, xz, + yx, yy, yz, + zx, zy, zz); + } + + MT_Vector3& operator[](int i) { return m_el[i]; } + const MT_Vector3& operator[](int i) const { return m_el[i]; } + + MT_Vector3 getColumn(int i) const { + return MT_Vector3(m_el[0][i], m_el[1][i], m_el[2][i]); + } + void setColumn(int i, const MT_Vector3& v) { + m_el[0][i] = v[0]; + m_el[1][i] = v[1]; + m_el[2][i] = v[2]; + } + + void setValue(const float *m) { + m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; m++; + m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; m++; + m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m; + } + + void setValue(const double *m) { + m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; m++; + m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; m++; + m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m; + } + + void setValue(MT_Scalar xx, MT_Scalar xy, MT_Scalar xz, + MT_Scalar yx, MT_Scalar yy, MT_Scalar yz, + MT_Scalar zx, MT_Scalar zy, MT_Scalar zz) { + m_el[0][0] = xx; m_el[0][1] = xy; m_el[0][2] = xz; + m_el[1][0] = yx; m_el[1][1] = yy; m_el[1][2] = yz; + m_el[2][0] = zx; m_el[2][1] = zy; m_el[2][2] = zz; + } + + void setRotation(const MT_Quaternion& q) { + MT_Scalar d = q.length2(); + MT_assert(!MT_fuzzyZero2(d)); + MT_Scalar s = MT_Scalar(2.0) / d; + MT_Scalar xs = q[0] * s, ys = q[1] * s, zs = q[2] * s; + MT_Scalar wx = q[3] * xs, wy = q[3] * ys, wz = q[3] * zs; + MT_Scalar xx = q[0] * xs, xy = q[0] * ys, xz = q[0] * zs; + MT_Scalar yy = q[1] * ys, yz = q[1] * zs, zz = q[2] * zs; + setValue(MT_Scalar(1.0) - (yy + zz), xy - wz , xz + wy, + xy + wz , MT_Scalar(1.0) - (xx + zz), yz - wx, + xz - wy , yz + wx, MT_Scalar(1.0) - (xx + yy)); + } + + /** + * setEuler + * @param euler a const reference to a MT_Vector3 of euler angles + * These angles are used to produce a rotation matrix. The euler + * angles are applied in ZYX order. I.e a vector is first rotated + * about X then Y and then Z + **/ + + void setEuler(const MT_Vector3& euler) { + MT_Scalar ci = cos(euler[0]); + MT_Scalar cj = cos(euler[1]); + MT_Scalar ch = cos(euler[2]); + MT_Scalar si = sin(euler[0]); + MT_Scalar sj = sin(euler[1]); + MT_Scalar sh = sin(euler[2]); + MT_Scalar cc = ci * ch; + MT_Scalar cs = ci * sh; + MT_Scalar sc = si * ch; + MT_Scalar ss = si * sh; + + setValue(cj * ch, sj * sc - cs, sj * cc + ss, + cj * sh, sj * ss + cc, sj * cs - sc, + -sj, cj * si, cj * ci); + } + + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z) { + m_el[0][0] *= x; m_el[0][1] *= y; m_el[0][2] *= z; + m_el[1][0] *= x; m_el[1][1] *= y; m_el[1][2] *= z; + m_el[2][0] *= x; m_el[2][1] *= y; m_el[2][2] *= z; + } + + MT_Matrix3x3 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z) const { + return MT_Matrix3x3(m_el[0][0] * x, m_el[0][1] * y, m_el[0][2] * z, + m_el[1][0] * x, m_el[1][1] * y, m_el[1][2] * z, + m_el[2][0] * x, m_el[2][1] * y, m_el[2][2] * z); + } + + void setIdentity() { + setValue(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0)); + } + + void getValue(float *m) const { + *m++ = (float) m_el[0][0]; *m++ = (float) m_el[1][0]; *m++ = (float) m_el[2][0]; *m++ = (float) 0.0; + *m++ = (float) m_el[0][1]; *m++ = (float) m_el[1][1]; *m++ = (float) m_el[2][1]; *m++ = (float) 0.0; + *m++ = (float) m_el[0][2]; *m++ = (float) m_el[1][2]; *m++ = (float) m_el[2][2]; *m = (float) 0.0; + } + + void getValue(double *m) const { + *m++ = m_el[0][0]; *m++ = m_el[1][0]; *m++ = m_el[2][0]; *m++ = 0.0; + *m++ = m_el[0][1]; *m++ = m_el[1][1]; *m++ = m_el[2][1]; *m++ = 0.0; + *m++ = m_el[0][2]; *m++ = m_el[1][2]; *m++ = m_el[2][2]; *m = 0.0; + } + + MT_Quaternion getRotation() const; + + MT_Matrix3x3& operator*=(const MT_Matrix3x3& m); + + MT_Scalar tdot(int c, const MT_Vector3& v) const { + return m_el[0][c] * v[0] + m_el[1][c] * v[1] + m_el[2][c] * v[2]; + } + + MT_Scalar cofac(int r1, int c1, int r2, int c2) const { + return m_el[r1][c1] * m_el[r2][c2] - m_el[r1][c2] * m_el[r2][c1]; + } + + MT_Scalar determinant() const; + MT_Matrix3x3 adjoint() const; + + MT_Matrix3x3 absolute() const; + + MT_Matrix3x3 transposed() const; + void transpose(); + + MT_Matrix3x3 inverse() const; + void invert(); + +protected: + + MT_Vector3 m_el[3]; +}; + +MT_Vector3 operator*(const MT_Matrix3x3& m, const MT_Vector3& v); +MT_Vector3 operator*(const MT_Vector3& v, const MT_Matrix3x3& m); +MT_Matrix3x3 operator*(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2); + +MT_Matrix3x3 MT_multTransposeLeft(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2); +MT_Matrix3x3 MT_multTransposeRight(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2); + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Matrix3x3& m) { + return os << m[0] << GEN_endl << m[1] << GEN_endl << m[2] << GEN_endl; +} + +#ifdef GEN_INLINED +#include "MT_Matrix3x3.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Matrix3x3.inl b/intern/moto/include/MT_Matrix3x3.inl new file mode 100644 index 00000000000..c581640ebfe --- /dev/null +++ b/intern/moto/include/MT_Matrix3x3.inl @@ -0,0 +1,128 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Quaternion MT_Matrix3x3::getRotation() const { + static int next[3] = { 1, 2, 0 }; + + MT_Quaternion result; + + MT_Scalar trace = m_el[0][0] + m_el[1][1] + m_el[2][2]; + + if (trace > 0.0) + { + MT_Scalar s = sqrt(trace + MT_Scalar(1.0)); + result[3] = s * MT_Scalar(0.5); + s = MT_Scalar(0.5) / s; + + result[0] = (m_el[2][1] - m_el[1][2]) * s; + result[1] = (m_el[0][2] - m_el[2][0]) * s; + result[2] = (m_el[1][0] - m_el[0][1]) * s; + } + else + { + int i = 0; + if (m_el[1][1] > m_el[0][0]) + i = 1; + if (m_el[2][2] > m_el[i][i]) + i = 2; + + int j = next[i]; + int k = next[j]; + + MT_Scalar s = sqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + MT_Scalar(1.0)); + + result[i] = s * MT_Scalar(0.5); + + s = MT_Scalar(0.5) / s; + + result[3] = (m_el[k][j] - m_el[j][k]) * s; + result[j] = (m_el[j][i] + m_el[i][j]) * s; + result[k] = (m_el[k][i] + m_el[i][k]) * s; + } + return result; +} + +GEN_INLINE MT_Matrix3x3& MT_Matrix3x3::operator*=(const MT_Matrix3x3& m) { + setValue(m.tdot(0, m_el[0]), m.tdot(1, m_el[0]), m.tdot(2, m_el[0]), + m.tdot(0, m_el[1]), m.tdot(1, m_el[1]), m.tdot(2, m_el[1]), + m.tdot(0, m_el[2]), m.tdot(1, m_el[2]), m.tdot(2, m_el[2])); + return *this; +} + +GEN_INLINE MT_Scalar MT_Matrix3x3::determinant() const { + return MT_triple((*this)[0], (*this)[1], (*this)[2]); +} + +GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::absolute() const { + return + MT_Matrix3x3(MT_abs(m_el[0][0]), MT_abs(m_el[0][1]), MT_abs(m_el[0][2]), + MT_abs(m_el[1][0]), MT_abs(m_el[1][1]), MT_abs(m_el[1][2]), + MT_abs(m_el[2][0]), MT_abs(m_el[2][1]), MT_abs(m_el[2][2])); +} + +GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::transposed() const { + return MT_Matrix3x3(m_el[0][0], m_el[1][0], m_el[2][0], + m_el[0][1], m_el[1][1], m_el[2][1], + m_el[0][2], m_el[1][2], m_el[2][2]); +} + +GEN_INLINE void MT_Matrix3x3::transpose() { + *this = transposed(); +} + +GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::adjoint() const { + return + MT_Matrix3x3(cofac(1, 1, 2, 2), cofac(0, 2, 2, 1), cofac(0, 1, 1, 2), + cofac(1, 2, 2, 0), cofac(0, 0, 2, 2), cofac(0, 2, 1, 0), + cofac(1, 0, 2, 1), cofac(0, 1, 2, 0), cofac(0, 0, 1, 1)); +} + +GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::inverse() const { + MT_Vector3 co(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)); + MT_Scalar det = MT_dot((*this)[0], co); + MT_assert(!MT_fuzzyZero2(det)); + MT_Scalar s = MT_Scalar(1.0) / det; + return + MT_Matrix3x3(co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, + co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s, + co[2] * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s); +} + +GEN_INLINE void MT_Matrix3x3::invert() { + *this = inverse(); +} + +GEN_INLINE MT_Vector3 operator*(const MT_Matrix3x3& m, const MT_Vector3& v) { + return MT_Vector3(MT_dot(m[0], v), MT_dot(m[1], v), MT_dot(m[2], v)); +} + +GEN_INLINE MT_Vector3 operator*(const MT_Vector3& v, const MT_Matrix3x3& m) { + return MT_Vector3(m.tdot(0, v), m.tdot(1, v), m.tdot(2, v)); +} + +GEN_INLINE MT_Matrix3x3 operator*(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2) { + return + MT_Matrix3x3(m2.tdot(0, m1[0]), m2.tdot(1, m1[0]), m2.tdot(2, m1[0]), + m2.tdot(0, m1[1]), m2.tdot(1, m1[1]), m2.tdot(2, m1[1]), + m2.tdot(0, m1[2]), m2.tdot(1, m1[2]), m2.tdot(2, m1[2])); +} + +GEN_INLINE MT_Matrix3x3 MT_multTransposeLeft(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2) { + return MT_Matrix3x3( + m1[0][0] * m2[0][0] + m1[1][0] * m2[1][0] + m1[2][0] * m2[2][0], + m1[0][0] * m2[0][1] + m1[1][0] * m2[1][1] + m1[2][0] * m2[2][1], + m1[0][0] * m2[0][2] + m1[1][0] * m2[1][2] + m1[2][0] * m2[2][2], + m1[0][1] * m2[0][0] + m1[1][1] * m2[1][0] + m1[2][1] * m2[2][0], + m1[0][1] * m2[0][1] + m1[1][1] * m2[1][1] + m1[2][1] * m2[2][1], + m1[0][1] * m2[0][2] + m1[1][1] * m2[1][2] + m1[2][1] * m2[2][2], + m1[0][2] * m2[0][0] + m1[1][2] * m2[1][0] + m1[2][2] * m2[2][0], + m1[0][2] * m2[0][1] + m1[1][2] * m2[1][1] + m1[2][2] * m2[2][1], + m1[0][2] * m2[0][2] + m1[1][2] * m2[1][2] + m1[2][2] * m2[2][2]); +} + +GEN_INLINE MT_Matrix3x3 MT_multTransposeRight(const MT_Matrix3x3& m1, const MT_Matrix3x3& m2) { + return + MT_Matrix3x3(m1[0].dot(m2[0]), m1[0].dot(m2[1]), m1[0].dot(m2[2]), + m1[1].dot(m2[0]), m1[1].dot(m2[1]), m1[1].dot(m2[2]), + m1[2].dot(m2[0]), m1[2].dot(m2[1]), m1[2].dot(m2[2])); + +} diff --git a/intern/moto/include/MT_Matrix4x4.h b/intern/moto/include/MT_Matrix4x4.h new file mode 100644 index 00000000000..fc930055524 --- /dev/null +++ b/intern/moto/include/MT_Matrix4x4.h @@ -0,0 +1,251 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * A 4x4 matrix compatible with other stuff. + */ + +#ifndef MT_MATRIX4X4_H +#define MT_MATRIX4X4_H + +#include + +#include "MT_Vector4.h" +#include "MT_Transform.h" + +// Row-major 4x4 matrix + +class MT_Matrix4x4 { +public: + /** + * Empty contructor. + */ + MT_Matrix4x4() {} + /** + * Initialize all fields with the values pointed at by m. A + * contigous block of 16 values is read. */ + MT_Matrix4x4(const float *m) { setValue(m); } + /** + * Initialize all fields with the values pointed at by m. A + * contigous block of 16 values is read. */ + MT_Matrix4x4(const double *m) { setValue(m); } + + /** + * Initialise with these 16 explicit values. + */ + MT_Matrix4x4(MT_Scalar xx, MT_Scalar xy, MT_Scalar xz, MT_Scalar xw, + MT_Scalar yx, MT_Scalar yy, MT_Scalar yz, MT_Scalar yw, + MT_Scalar zx, MT_Scalar zy, MT_Scalar zz, MT_Scalar zw, + MT_Scalar wx, MT_Scalar wy, MT_Scalar wz, MT_Scalar ww) { + setValue(xx, xy, xz, xw, + yx, yy, yz, yw, + zx, zy, zz, zw, + wx, wy, wz, ww); + } + + /** + * Initialize from an MT_Transform. + */ + MT_Matrix4x4(const MT_Transform &t) { + + const MT_Matrix3x3 &basis = t.getBasis(); + const MT_Vector3 &origin = t.getOrigin(); + + setValue( + basis[0][0],basis[0][1],basis[0][2],origin[0], + basis[1][0],basis[1][1],basis[1][2],origin[1], + basis[2][0],basis[2][1],basis[2][2],origin[2], + MT_Scalar(0),MT_Scalar(0),MT_Scalar(0),MT_Scalar(1) + ); + } + + /** + * Get the i-th row. + */ + MT_Vector4& operator[](int i) { return m_el[i]; } + /** + * Get the i-th row. + */ + const MT_Vector4& operator[](int i) const { return m_el[i]; } + + /** + * Set the matrix to the values pointer at by m. A contiguous + * block of 16 values is copied. */ + void setValue(const float *m) { + m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; m_el[3][0] = *m++; + m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; m_el[3][1] = *m++; + m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m++; m_el[3][2] = *m++; + m_el[0][3] = *m++; m_el[1][3] = *m++; m_el[2][3] = *m++; m_el[3][3] = *m; + } + + /** + * Set the matrix to the values pointer at by m. A contiguous + * block of 16 values is copied. + */ + void setValue(const double *m) { + m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; m_el[3][0] = *m++; + m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; m_el[3][1] = *m++; + m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m++; m_el[3][2] = *m++; + m_el[0][3] = *m++; m_el[1][3] = *m++; m_el[2][3] = *m++; m_el[3][3] = *m; + } + + /** + * Set the matrix to these 16 explicit values. + */ + void setValue(MT_Scalar xx, MT_Scalar xy, MT_Scalar xz, MT_Scalar xw, + MT_Scalar yx, MT_Scalar yy, MT_Scalar yz, MT_Scalar yw, + MT_Scalar zx, MT_Scalar zy, MT_Scalar zz, MT_Scalar zw, + MT_Scalar wx, MT_Scalar wy, MT_Scalar wz, MT_Scalar ww) { + m_el[0][0] = xx; m_el[0][1] = xy; m_el[0][2] = xz; m_el[0][3] = xw; + m_el[1][0] = yx; m_el[1][1] = yy; m_el[1][2] = yz; m_el[1][3] = yw; + m_el[2][0] = zx; m_el[2][1] = zy; m_el[2][2] = zz; m_el[2][3] = zw; + m_el[3][0] = wx; m_el[3][1] = wy; m_el[3][2] = wz; m_el[3][3] = ww; + } + + /** + * Scale the columns of this matrix with x, y, z, w respectively. + */ + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) { + m_el[0][0] *= x; m_el[0][1] *= y; m_el[0][2] *= z; m_el[0][3] *= w; + m_el[1][0] *= x; m_el[1][1] *= y; m_el[1][2] *= z; m_el[1][3] *= w; + m_el[2][0] *= x; m_el[2][1] *= y; m_el[2][2] *= z; m_el[2][3] *= w; + m_el[3][0] *= x; m_el[3][1] *= y; m_el[3][2] *= z; m_el[3][3] *= w; + } + + /** + * Return a column-scaled version of this matrix. + */ + MT_Matrix4x4 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) const { + return MT_Matrix4x4(m_el[0][0] * x, m_el[0][1] * y, m_el[0][2] * z, m_el[0][3] * w, + m_el[1][0] * x, m_el[1][1] * y, m_el[1][2] * z, m_el[1][3] * w, + m_el[2][0] * x, m_el[2][1] * y, m_el[2][2] * z, m_el[2][3] * w, + m_el[3][0] * x, m_el[3][1] * y, m_el[3][2] * z, m_el[3][3] * w); + } + + /** + * Set this matrix to I. + */ + void setIdentity() { + setValue(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0), + MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0)); + } + + /** + * Read the element from row i, column j. + */ + float getElement(int i, int j) { + return (float) m_el[i][j]; + } + + /** + * Copy the contents to a contiguous block of 16 floats. + */ + void getValue(float *m) const { + *m++ = (float) m_el[0][0]; *m++ = (float) m_el[1][0]; *m++ = (float) m_el[2][0]; *m++ = (float) m_el[3][0]; + *m++ = (float) m_el[0][1]; *m++ = (float) m_el[1][1]; *m++ = (float) m_el[2][1]; *m++ = (float) m_el[3][1]; + *m++ = (float) m_el[0][2]; *m++ = (float) m_el[1][2]; *m++ = (float) m_el[2][2]; *m++ = (float) m_el[3][2]; + *m++ = (float) m_el[0][3]; *m++ = (float) m_el[1][3]; *m++ = (float) m_el[2][3]; *m = (float) m_el[3][3]; + } + + /** + * Copy the contents to a contiguous block of 16 doubles. + */ + void getValue(double *m) const { + *m++ = m_el[0][0]; *m++ = m_el[1][0]; *m++ = m_el[2][0]; *m++ = m_el[3][0]; + *m++ = m_el[0][1]; *m++ = m_el[1][1]; *m++ = m_el[2][1]; *m++ = m_el[3][1]; + *m++ = m_el[0][2]; *m++ = m_el[1][2]; *m++ = m_el[2][2]; *m++ = m_el[3][2]; + *m++ = m_el[0][3]; *m++ = m_el[1][3]; *m++ = m_el[2][3]; *m = m_el[3][3]; + } + + /** + * Left-multiply this matrix with the argument. + */ + MT_Matrix4x4& operator*=(const MT_Matrix4x4& m); + + /** + * Left-multiply column c with row vector c. + */ + MT_Scalar tdot(int c, const MT_Vector4& v) const { + return m_el[0][c] * v[0] + + m_el[1][c] * v[1] + + m_el[2][c] * v[2] + + m_el[3][c] * v[3]; + } + + /* I'll postpone this for now... - nzc*/ +/* MT_Scalar determinant() const; */ +/* MT_Matrix4x4 adjoint() const; */ +/* MT_Matrix4x4 inverse() const; */ + + MT_Matrix4x4 absolute() const; + + MT_Matrix4x4 transposed() const; + void transpose(); + + void invert(); + +protected: + /** + * Access with [row index][column index] + */ + MT_Vector4 m_el[4]; +}; + +/* These multiplicators do exactly what you ask from them: they + * multiply in the indicated order. */ +MT_Vector4 operator*(const MT_Matrix4x4& m, const MT_Vector4& v); +MT_Vector4 operator*(const MT_Vector4& v, const MT_Matrix4x4& m); +MT_Matrix4x4 operator*(const MT_Matrix4x4& m1, const MT_Matrix4x4& m2); + +/* MT_Matrix4x4 MT_multTransposeLeft(const MT_Matrix4x4& m1, const MT_Matrix4x4& m2); */ +/* MT_Matrix4x4 MT_multTransposeRight(const MT_Matrix4x4& m1, const MT_Matrix4x4& m2); */ + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Matrix4x4& m) { + return os << m[0] << GEN_endl + << m[1] << GEN_endl + << m[2] << GEN_endl + << m[3] << GEN_endl; + + + +} + +#ifdef GEN_INLINED +#include "MT_Matrix4x4.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Matrix4x4.inl b/intern/moto/include/MT_Matrix4x4.inl new file mode 100644 index 00000000000..a2aa893a6b3 --- /dev/null +++ b/intern/moto/include/MT_Matrix4x4.inl @@ -0,0 +1,108 @@ +#include "MT_Optimize.h" + +/* + * This is a supposedly faster inverter than the cofactor + * computation. It uses an LU decomposition sort of thing. */ +GEN_INLINE void MT_Matrix4x4::invert() { + /* normalize row 0 */ + + int i,j,k; + + for (i=1; i < 4; i++) m_el[0][i] /= m_el[0][0]; + for (i=1; i < 4; i++) { + for (j=i; j < 4; j++) { // do a column of L + MT_Scalar sum = 0.0; + for (k = 0; k < i; k++) + sum += m_el[j][k] * m_el[k][i]; + m_el[j][i] -= sum; + } + if (i == 3) continue; + for (j=i+1; j < 4; j++) { // do a row of U + MT_Scalar sum = 0.0; + for (k = 0; k < i; k++) + sum += m_el[i][k]*m_el[k][j]; + m_el[i][j] = + (m_el[i][j]-sum) / m_el[i][i]; + } + } + for (i = 0; i < 4; i++ ) // invert L + for (j = i; j < 4; j++ ) { + MT_Scalar x = 1.0; + if ( i != j ) { + x = 0.0; + for (k = i; k < j; k++ ) + x -= m_el[j][k]*m_el[k][i]; + } + m_el[j][i] = x / m_el[j][j]; + } + for (i = 0; i < 4; i++ ) // invert U + for (j = i; j < 4; j++ ) { + if ( i == j ) continue; + MT_Scalar sum = 0.0; + for (k = i; k < j; k++ ) + sum += m_el[k][j]*( (i==k) ? 1.0 : m_el[i][k] ); + m_el[i][j] = -sum; + } + for (i = 0; i < 4; i++ ) // final inversion + for (j = 0; j < 4; j++ ) { + MT_Scalar sum = 0.0; + for (k = ((i>j)?i:j); k < 4; k++ ) + sum += ((j==k)?1.0:m_el[j][k])*m_el[k][i]; + m_el[j][i] = sum; + } +} + +/* We do things slightly different here, because the invert() modifies + * the buffer itself. This makes it impossible to make this op right + * away. Like other, still missing facilities, I will repair this + * later. */ +/* GEN_INLINE T_Matrix4x4 MT_Matrix4x4::inverse() const */ +/* { */ +/* } */ + + +GEN_INLINE MT_Matrix4x4& MT_Matrix4x4::operator*=(const MT_Matrix4x4& m) +{ + setValue(m.tdot(0, m_el[0]), m.tdot(1, m_el[0]), m.tdot(2, m_el[0]), m.tdot(3, m_el[0]), + m.tdot(0, m_el[1]), m.tdot(1, m_el[1]), m.tdot(2, m_el[1]), m.tdot(3, m_el[1]), + m.tdot(0, m_el[2]), m.tdot(1, m_el[2]), m.tdot(2, m_el[2]), m.tdot(3, m_el[2]), + m.tdot(0, m_el[3]), m.tdot(1, m_el[3]), m.tdot(2, m_el[3]), m.tdot(3, m_el[3])); + return *this; + +} + +GEN_INLINE MT_Vector4 operator*(const MT_Matrix4x4& m, const MT_Vector4& v) { + return MT_Vector4(MT_dot(m[0], v), MT_dot(m[1], v), MT_dot(m[2], v), MT_dot(m[3], v)); +} + +GEN_INLINE MT_Vector4 operator*(const MT_Vector4& v, const MT_Matrix4x4& m) { + return MT_Vector4(m.tdot(0, v), m.tdot(1, v), m.tdot(2, v), m.tdot(3, v)); +} + +GEN_INLINE MT_Matrix4x4 operator*(const MT_Matrix4x4& m1, const MT_Matrix4x4& m2) { + return + MT_Matrix4x4(m2.tdot(0, m1[0]), m2.tdot(1, m1[0]), m2.tdot(2, m1[0]), m2.tdot(3, m1[0]), + m2.tdot(0, m1[1]), m2.tdot(1, m1[1]), m2.tdot(2, m1[1]), m2.tdot(3, m1[1]), + m2.tdot(0, m1[2]), m2.tdot(1, m1[2]), m2.tdot(2, m1[2]), m2.tdot(3, m1[2]), + m2.tdot(0, m1[3]), m2.tdot(1, m1[3]), m2.tdot(2, m1[3]), m2.tdot(3, m1[3])); +} + + +GEN_INLINE MT_Matrix4x4 MT_Matrix4x4::transposed() const { + return MT_Matrix4x4(m_el[0][0], m_el[1][0], m_el[2][0], m_el[3][0], + m_el[0][1], m_el[1][1], m_el[2][1], m_el[3][1], + m_el[0][2], m_el[1][2], m_el[2][2], m_el[3][2], + m_el[0][3], m_el[1][3], m_el[2][3], m_el[3][3]); +} + +GEN_INLINE void MT_Matrix4x4::transpose() { + *this = transposed(); +} + +GEN_INLINE MT_Matrix4x4 MT_Matrix4x4::absolute() const { + return + MT_Matrix4x4(MT_abs(m_el[0][0]), MT_abs(m_el[0][1]), MT_abs(m_el[0][2]), MT_abs(m_el[0][3]), + MT_abs(m_el[1][0]), MT_abs(m_el[1][1]), MT_abs(m_el[1][2]), MT_abs(m_el[1][3]), + MT_abs(m_el[2][0]), MT_abs(m_el[2][1]), MT_abs(m_el[2][2]), MT_abs(m_el[2][3]), + MT_abs(m_el[3][0]), MT_abs(m_el[3][1]), MT_abs(m_el[3][2]), MT_abs(m_el[3][3])); +} diff --git a/intern/moto/include/MT_MinMax.h b/intern/moto/include/MT_MinMax.h new file mode 100644 index 00000000000..06f8a8d18c8 --- /dev/null +++ b/intern/moto/include/MT_MinMax.h @@ -0,0 +1,70 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_MINMAX_H +#define MT_MINMAX_H + +template +inline const T& MT_min(const T& a, const T& b) { + return b < a ? b : a; +} + +template +inline const T& MT_max(const T& a, const T& b) { + return a < b ? b : a; +} + +template +inline void MT_set_min(T& a, const T& b) { + if (a > b) a = b; +} + +template +inline void MT_set_max(T& a, const T& b) { + if (a < b) a = b; +} + +#endif + diff --git a/intern/moto/include/MT_Optimize.h b/intern/moto/include/MT_Optimize.h new file mode 100644 index 00000000000..c09a9431a34 --- /dev/null +++ b/intern/moto/include/MT_Optimize.h @@ -0,0 +1,42 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef GEN_OPTIMIZE_H +#define GEN_OPTIMIZE_H + +#ifdef GEN_INLINED +#define GEN_INLINE inline +#else +#define GEN_INLINE +#endif + +#endif + diff --git a/intern/moto/include/MT_Plane3.h b/intern/moto/include/MT_Plane3.h new file mode 100644 index 00000000000..5caf1c4c36e --- /dev/null +++ b/intern/moto/include/MT_Plane3.h @@ -0,0 +1,136 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef MT_PLANE3 +#define MT_PLANE3 + +#include "MT_Tuple4.h" +#include "MT_Point3.h" + +/** + * A simple 3d plane class. + * + * This class represents a plane in 3d. The internal parameterization used + * is n.x + d =0 where n is a unit vector and d is a scalar. + * + * It inherits data from MT_Tuple4 please see this class for low level + * access to the internal representation. + * + */ + +class MT_Plane3 : public MT_Tuple4 +{ +public : + /** + * Constructor from 3 points + */ + + MT_Plane3( + const MT_Vector3 &a, + const MT_Vector3 &b, + const MT_Vector3 &c + ); + /** + * Construction from vector and a point. + */ + + MT_Plane3( + const MT_Vector3 &n, + const MT_Vector3 &p + ); + + /** + * Default constructor + */ + MT_Plane3( + ); + + /** + * Default constructor + */ + + MT_Plane3( + const MT_Plane3 & p + ): + MT_Tuple4(p) + { + } + + /** + * Return plane normal + */ + + MT_Vector3 + Normal( + ) const; + + /** + * Return plane scalar i.e the d from n.x + d = 0 + */ + + MT_Scalar + Scalar( + ) const ; + + /** + * Invert the plane - just swaps direction of normal. + */ + void + Invert( + ); + + /** + * Assignment operator + */ + + MT_Plane3 & + operator = ( + const MT_Plane3 & rhs + ); + + /** + * Return the signed perpendicular distance from a point to the plane + */ + + MT_Scalar + signedDistance( + const MT_Vector3 & + ) const; + + +}; + +#ifdef GEN_INLINED +#include "MT_Plane3.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Plane3.inl b/intern/moto/include/MT_Plane3.inl new file mode 100644 index 00000000000..77db9b35e1d --- /dev/null +++ b/intern/moto/include/MT_Plane3.inl @@ -0,0 +1,128 @@ +#include "MT_Optimize.h" + + +GEN_INLINE +MT_Plane3:: +MT_Plane3( + const MT_Vector3 &a, + const MT_Vector3 &b, + const MT_Vector3 &c +){ + MT_Vector3 l1 = b-a; + MT_Vector3 l2 = c-b; + + MT_Vector3 n = l1.cross(l2); + n = n.safe_normalized(); + MT_Scalar d = n.dot(a); + + m_co[0] = n.x(); + m_co[1] = n.y(); + m_co[2] = n.z(); + m_co[3] = -d; +} + +/** + * Construction from vector and a point. + */ +GEN_INLINE +MT_Plane3:: +MT_Plane3( + const MT_Vector3 &n, + const MT_Vector3 &p +){ + + MT_Vector3 mn = n.safe_normalized(); + MT_Scalar md = mn.dot(p); + + m_co[0] = mn.x(); + m_co[1] = mn.y(); + m_co[2] = mn.z(); + m_co[3] = -md; +} + + +/** + * Default constructor + */ +GEN_INLINE +MT_Plane3:: +MT_Plane3( +): + MT_Tuple4() +{ + m_co[0] = MT_Scalar(1); + m_co[1] = MT_Scalar(0); + m_co[2] = MT_Scalar(0); + m_co[3] = MT_Scalar(0); +} + +/** + * Return plane normal + */ + +GEN_INLINE + MT_Vector3 +MT_Plane3:: +Normal( +) const { + return MT_Vector3(m_co[0],m_co[1],m_co[2]); +} + +/** + * Return plane scalar i.e the d from n.x + d = 0 + */ + +GEN_INLINE + MT_Scalar +MT_Plane3:: +Scalar( +) const { + return m_co[3]; +} + +GEN_INLINE + void +MT_Plane3:: +Invert( +) { + m_co[0] = -m_co[0]; + m_co[1] = -m_co[1]; + m_co[2] = -m_co[2]; + m_co[3] = -m_co[3]; +} + + +/** + * Assignment operator + */ + +GEN_INLINE + MT_Plane3 & +MT_Plane3:: +operator = ( + const MT_Plane3 & rhs +) { + m_co[0] = rhs.m_co[0]; + m_co[1] = rhs.m_co[1]; + m_co[2] = rhs.m_co[2]; + m_co[3] = rhs.m_co[3]; + return *this; +} + +/** + * Return the distance from a point to the plane + */ + +GEN_INLINE + MT_Scalar +MT_Plane3:: +signedDistance( + const MT_Vector3 &v +) const { + return Normal().dot(v) + m_co[3]; +} + + + + + diff --git a/intern/moto/include/MT_Point2.h b/intern/moto/include/MT_Point2.h new file mode 100644 index 00000000000..cc6819039fc --- /dev/null +++ b/intern/moto/include/MT_Point2.h @@ -0,0 +1,82 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_POINT2_H +#define MT_POINT2_H + +#include "MT_Vector2.h" + +class MT_Point2 : public MT_Vector2 { +public: + MT_Point2() {} + MT_Point2(const float *v2) : MT_Vector2(v2) {} + MT_Point2(const double *v2) : MT_Vector2(v2) {} + MT_Point2(MT_Scalar x2, MT_Scalar y2) : MT_Vector2(x2, y2) {} + + MT_Point2& operator+=(const MT_Vector2& v); + MT_Point2& operator-=(const MT_Vector2& v); + MT_Point2& operator=(const MT_Vector2& v); + + MT_Scalar distance(const MT_Point2& p) const; + MT_Scalar distance2(const MT_Point2& p) const; + + MT_Point2 lerp(const MT_Point2& p, MT_Scalar t) const; +}; + +MT_Point2 operator+(const MT_Point2& p, const MT_Vector2& v); +MT_Point2 operator-(const MT_Point2& p, const MT_Vector2& v); +MT_Vector2 operator-(const MT_Point2& p1, const MT_Point2& p2); + +MT_Scalar MT_distance(const MT_Point2& p1, const MT_Point2& p2); +MT_Scalar MT_distance2(const MT_Point2& p1, const MT_Point2& p2); + +MT_Point2 MT_lerp(const MT_Point2& p1, const MT_Point2& p2, MT_Scalar t); + +#ifdef GEN_INLINED +#include "MT_Point2.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Point2.inl b/intern/moto/include/MT_Point2.inl new file mode 100644 index 00000000000..ec09a3260e2 --- /dev/null +++ b/intern/moto/include/MT_Point2.inl @@ -0,0 +1,54 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Point2& MT_Point2::operator+=(const MT_Vector2& v) { + m_co[0] += v[0]; m_co[1] += v[1]; + return *this; +} + +GEN_INLINE MT_Point2& MT_Point2::operator-=(const MT_Vector2& v) { + m_co[0] -= v[0]; m_co[1] -= v[1]; + return *this; +} + +GEN_INLINE MT_Point2& MT_Point2::operator=(const MT_Vector2& v) { + m_co[0] = v[0]; m_co[1] = v[1]; + return *this; +} + +GEN_INLINE MT_Scalar MT_Point2::distance(const MT_Point2& p) const { + return (p - *this).length(); +} + +GEN_INLINE MT_Scalar MT_Point2::distance2(const MT_Point2& p) const { + return (p - *this).length2(); +} + +GEN_INLINE MT_Point2 MT_Point2::lerp(const MT_Point2& p, MT_Scalar t) const { + return MT_Point2(m_co[0] + (p[0] - m_co[0]) * t, + m_co[1] + (p[1] - m_co[1]) * t); +} + +GEN_INLINE MT_Point2 operator+(const MT_Point2& p, const MT_Vector2& v) { + return MT_Point2(p[0] + v[0], p[1] + v[1]); +} + +GEN_INLINE MT_Point2 operator-(const MT_Point2& p, const MT_Vector2& v) { + return MT_Point2(p[0] - v[0], p[1] - v[1]); +} + +GEN_INLINE MT_Vector2 operator-(const MT_Point2& p1, const MT_Point2& p2) { + return MT_Vector2(p1[0] - p2[0], p1[1] - p2[1]); +} + +GEN_INLINE MT_Scalar MT_distance(const MT_Point2& p1, const MT_Point2& p2) { + return p1.distance(p2); +} + +GEN_INLINE MT_Scalar MT_distance2(const MT_Point2& p1, const MT_Point2& p2) { + return p1.distance2(p2); +} + +GEN_INLINE MT_Point2 MT_lerp(const MT_Point2& p1, const MT_Point2& p2, MT_Scalar t) { + return p1.lerp(p2, t); +} + diff --git a/intern/moto/include/MT_Point3.h b/intern/moto/include/MT_Point3.h new file mode 100644 index 00000000000..372718af312 --- /dev/null +++ b/intern/moto/include/MT_Point3.h @@ -0,0 +1,83 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_POINT_H +#define MT_POINT_H + +#include "MT_Vector3.h" + +class MT_Point3 : public MT_Vector3 { +public: + MT_Point3() {} + MT_Point3(const float *v) : MT_Vector3(v) {} + MT_Point3(const double *v) : MT_Vector3(v) {} + MT_Point3(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) : MT_Vector3(xx, yy, zz) {} + + MT_Point3& operator+=(const MT_Vector3& v); + MT_Point3& operator-=(const MT_Vector3& v); + MT_Point3& operator=(const MT_Vector3& v); + MT_Point3& operator=(const MT_Point3& v); + + MT_Scalar distance(const MT_Point3& p) const; + MT_Scalar distance2(const MT_Point3& p) const; + + MT_Point3 lerp(const MT_Point3& p, MT_Scalar t) const; +}; + +MT_Point3 operator+(const MT_Point3& p, const MT_Vector3& v); +MT_Point3 operator-(const MT_Point3& p, const MT_Vector3& v); +MT_Vector3 operator-(const MT_Point3& p1, const MT_Point3& p2); + +MT_Scalar MT_distance(const MT_Point3& p1, const MT_Point3& p2); +MT_Scalar MT_distance2(const MT_Point3& p1, const MT_Point3& p2); + +MT_Point3 MT_lerp(const MT_Point3& p1, const MT_Point3& p2, MT_Scalar t); + +#ifdef GEN_INLINED +#include "MT_Point3.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Point3.inl b/intern/moto/include/MT_Point3.inl new file mode 100644 index 00000000000..081a8195694 --- /dev/null +++ b/intern/moto/include/MT_Point3.inl @@ -0,0 +1,59 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Point3& MT_Point3::operator+=(const MT_Vector3& v) { + m_co[0] += v[0]; m_co[1] += v[1]; m_co[2] += v[2]; + return *this; +} + +GEN_INLINE MT_Point3& MT_Point3::operator-=(const MT_Vector3& v) { + m_co[0] -= v[0]; m_co[1] -= v[1]; m_co[2] -= v[2]; + return *this; +} + +GEN_INLINE MT_Point3& MT_Point3::operator=(const MT_Vector3& v) { + m_co[0] = v[0]; m_co[1] = v[1]; m_co[2] = v[2]; + return *this; +} + +GEN_INLINE MT_Point3& MT_Point3::operator=(const MT_Point3& v) { + m_co[0] = v[0]; m_co[1] = v[1]; m_co[2] = v[2]; + return *this; +} + +GEN_INLINE MT_Scalar MT_Point3::distance(const MT_Point3& p) const { + return (p - *this).length(); +} + +GEN_INLINE MT_Scalar MT_Point3::distance2(const MT_Point3& p) const { + return (p - *this).length2(); +} + +GEN_INLINE MT_Point3 MT_Point3::lerp(const MT_Point3& p, MT_Scalar t) const { + return MT_Point3(m_co[0] + (p[0] - m_co[0]) * t, + m_co[1] + (p[1] - m_co[1]) * t, + m_co[2] + (p[2] - m_co[2]) * t); +} + +GEN_INLINE MT_Point3 operator+(const MT_Point3& p, const MT_Vector3& v) { + return MT_Point3(p[0] + v[0], p[1] + v[1], p[2] + v[2]); +} + +GEN_INLINE MT_Point3 operator-(const MT_Point3& p, const MT_Vector3& v) { + return MT_Point3(p[0] - v[0], p[1] - v[1], p[2] - v[2]); +} + +GEN_INLINE MT_Vector3 operator-(const MT_Point3& p1, const MT_Point3& p2) { + return MT_Vector3(p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2]); +} + +GEN_INLINE MT_Scalar MT_distance(const MT_Point3& p1, const MT_Point3& p2) { + return p1.distance(p2); +} + +GEN_INLINE MT_Scalar MT_distance2(const MT_Point3& p1, const MT_Point3& p2) { + return p1.distance2(p2); +} + +GEN_INLINE MT_Point3 MT_lerp(const MT_Point3& p1, const MT_Point3& p2, MT_Scalar t) { + return p1.lerp(p2, t); +} diff --git a/intern/moto/include/MT_Quaternion.h b/intern/moto/include/MT_Quaternion.h new file mode 100644 index 00000000000..98046292982 --- /dev/null +++ b/intern/moto/include/MT_Quaternion.h @@ -0,0 +1,113 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_QUATERNION_H +#define MT_QUATERNION_H + +#include + +#include "MT_Vector3.h" +#include "MT_Vector4.h" + +class MT_Quaternion : public MT_Vector4 { +public: + MT_Quaternion() {} + MT_Quaternion(const MT_Vector4& v) : MT_Vector4(v) {} + MT_Quaternion(const float v[4]) : MT_Vector4(v) {} + MT_Quaternion(const double v[4]) : MT_Vector4(v) {} + MT_Quaternion(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) : + MT_Vector4(xx, yy, zz, ww) {} + MT_Quaternion(const MT_Vector3& axis, MT_Scalar mt_angle) { + setRotation(axis, mt_angle); + } + MT_Quaternion(MT_Scalar yaw, MT_Scalar pitch, MT_Scalar roll) { + setEuler(yaw, pitch, roll); + } + + void setRotation(const MT_Vector3& axis, MT_Scalar mt_angle) { + MT_Scalar d = axis.length(); + MT_assert(!MT_fuzzyZero(d)); + MT_Scalar s = sin(mt_angle * MT_Scalar(0.5)) / d; + setValue(axis[0] * s, axis[1] * s, axis[2] * s, + cos(mt_angle * MT_Scalar(0.5))); + } + + void setEuler(MT_Scalar yaw, MT_Scalar pitch, MT_Scalar roll) { + MT_Scalar cosYaw = cos(yaw * MT_Scalar(0.5)); + MT_Scalar sinYaw = sin(yaw * MT_Scalar(0.5)); + MT_Scalar cosPitch = cos(pitch * MT_Scalar(0.5)); + MT_Scalar sinPitch = sin(pitch * MT_Scalar(0.5)); + MT_Scalar cosRoll = cos(roll * MT_Scalar(0.5)); + MT_Scalar sinRoll = sin(roll * MT_Scalar(0.5)); + setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, + cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, + sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, + cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); + } + + MT_Quaternion& operator*=(const MT_Quaternion& q); + + void conjugate(); + MT_Quaternion conjugate() const; + + void invert(); + MT_Quaternion inverse() const; + + MT_Scalar angle(const MT_Quaternion& q) const; + MT_Quaternion slerp(const MT_Quaternion& q, const MT_Scalar& t) const; + + static MT_Quaternion random(); +}; + +MT_Quaternion operator*(const MT_Quaternion& q1, const MT_Quaternion& q2); +MT_Quaternion operator*(const MT_Quaternion& q, const MT_Vector3& w); +MT_Quaternion operator*(const MT_Vector3& w, const MT_Quaternion& q); + +#ifdef GEN_INLINED +#include "MT_Quaternion.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Quaternion.inl b/intern/moto/include/MT_Quaternion.inl new file mode 100644 index 00000000000..ecfd6699f67 --- /dev/null +++ b/intern/moto/include/MT_Quaternion.inl @@ -0,0 +1,92 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Quaternion& MT_Quaternion::operator*=(const MT_Quaternion& q) { + setValue(m_co[3] * q[0] + m_co[0] * q[3] + m_co[1] * q[2] - m_co[2] * q[1], + m_co[3] * q[1] + m_co[1] * q[3] + m_co[2] * q[0] - m_co[0] * q[2], + m_co[3] * q[2] + m_co[2] * q[3] + m_co[0] * q[1] - m_co[1] * q[0], + m_co[3] * q[3] - m_co[0] * q[0] - m_co[1] * q[1] - m_co[2] * q[2]); + return *this; +} + +GEN_INLINE void MT_Quaternion::conjugate() { + m_co[0] = -m_co[0]; m_co[1] = -m_co[1]; m_co[2] = -m_co[2]; +} + +GEN_INLINE MT_Quaternion MT_Quaternion::conjugate() const { + return MT_Quaternion(-m_co[0], -m_co[1], -m_co[2], m_co[3]); +} + +GEN_INLINE void MT_Quaternion::invert() { + conjugate(); + *this /= length2(); +} + +GEN_INLINE MT_Quaternion MT_Quaternion::inverse() const { + return conjugate() / length2(); +} + +// From: "Uniform Random Rotations", Ken Shoemake, Graphics Gems III, +// pg. 124-132 +GEN_INLINE MT_Quaternion MT_Quaternion::random() { + MT_Scalar x0 = MT_random(); + MT_Scalar r1 = sqrt(MT_Scalar(1.0) - x0), r2 = sqrt(x0); + MT_Scalar t1 = MT_2_PI * MT_random(), t2 = MT_2_PI * MT_random(); + MT_Scalar c1 = cos(t1), s1 = sin(t1); + MT_Scalar c2 = cos(t2), s2 = sin(t2); + return MT_Quaternion(s1 * r1, c1 * r1, s2 * r2, c2 * r2); +} + +GEN_INLINE MT_Quaternion operator*(const MT_Quaternion& q1, + const MT_Quaternion& q2) { + return MT_Quaternion(q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1], + q1[3] * q2[1] + q1[1] * q2[3] + q1[2] * q2[0] - q1[0] * q2[2], + q1[3] * q2[2] + q1[2] * q2[3] + q1[0] * q2[1] - q1[1] * q2[0], + q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2]); +} + +GEN_INLINE MT_Quaternion operator*(const MT_Quaternion& q, const MT_Vector3& w) +{ + return MT_Quaternion( q[3] * w[0] + q[1] * w[2] - q[2] * w[1], + q[3] * w[1] + q[2] * w[0] - q[0] * w[2], + q[3] * w[2] + q[0] * w[1] - q[1] * w[0], + -q[0] * w[0] - q[1] * w[1] - q[2] * w[2]); +} + +GEN_INLINE MT_Quaternion operator*(const MT_Vector3& w, const MT_Quaternion& q) +{ + return MT_Quaternion( w[0] * q[3] + w[1] * q[2] - w[2] * q[1], + w[1] * q[3] + w[2] * q[0] - w[0] * q[2], + w[2] * q[3] + w[0] * q[1] - w[1] * q[0], + -w[0] * q[0] - w[1] * q[1] - w[2] * q[2]); +} + +GEN_INLINE MT_Scalar MT_Quaternion::angle(const MT_Quaternion& q) const +{ + MT_Scalar s = sqrt(length2() * q.length2()); + assert(s != MT_Scalar(0.0)); + + s = dot(q) / s; + + s = MT_clamp(s, -1.0, 1.0); + + return acos(s); +} + +GEN_INLINE MT_Quaternion MT_Quaternion::slerp(const MT_Quaternion& q, const MT_Scalar& t) const +{ + MT_Scalar theta = angle(q); + + if (!MT_fuzzyZero(theta)) + { + MT_Scalar d = MT_Scalar(1.0) / sin(theta); + MT_Scalar s0 = sin((MT_Scalar(1.0) - t) * theta); + MT_Scalar s1 = sin(t * theta); + + return d*(*this * s0 + q * s1); + } + else + { + return *this; + } +} + diff --git a/intern/moto/include/MT_Scalar.h b/intern/moto/include/MT_Scalar.h new file mode 100644 index 00000000000..5cf9f76e592 --- /dev/null +++ b/intern/moto/include/MT_Scalar.h @@ -0,0 +1,96 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_SCALAR_H +#define MT_SCALAR_H + +#include +#include + +#include "MT_random.h" +#include "NM_Scalar.h" + +typedef double MT_Scalar; //this should be float ! + + +const MT_Scalar MT_DEGS_PER_RAD(57.29577951308232286465); +const MT_Scalar MT_RADS_PER_DEG(0.01745329251994329547); +const MT_Scalar MT_PI(3.14159265358979323846); +const MT_Scalar MT_2_PI(6.28318530717958623200); +const MT_Scalar MT_EPSILON(1.0e-10); +const MT_Scalar MT_EPSILON2(1.0e-20); +const MT_Scalar MT_INFINITY(1.0e50); + +inline int MT_sign(MT_Scalar x) { + return x < 0.0 ? -1 : x > 0.0 ? 1 : 0; +} + +inline MT_Scalar MT_abs(MT_Scalar x) { return fabs(x); } + +inline bool MT_fuzzyZero(MT_Scalar x) { return MT_abs(x) < MT_EPSILON; } +inline bool MT_fuzzyZero2(MT_Scalar x) { return MT_abs(x) < MT_EPSILON2; } + +inline MT_Scalar MT_radians(MT_Scalar x) { + return x * MT_RADS_PER_DEG; +} + +inline MT_Scalar MT_degrees(MT_Scalar x) { + return x * MT_DEGS_PER_RAD; +} + +inline MT_Scalar MT_random() { + return MT_Scalar(MT_rand()) / MT_Scalar(MT_RAND_MAX); +} + +inline MT_Scalar MT_clamp(const MT_Scalar x, const MT_Scalar min, const MT_Scalar max) +{ + if (x < min) + return min; + else if (x > max) + return max; + return x; +} +#endif + diff --git a/intern/moto/include/MT_Stream.h b/intern/moto/include/MT_Stream.h new file mode 100644 index 00000000000..49378eceb18 --- /dev/null +++ b/intern/moto/include/MT_Stream.h @@ -0,0 +1,58 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef GEN_STREAM_H +#define GEN_STREAM_H + +#ifdef __CUSTOM_STREAM + +class MT_OStream +{ +public: + inline MT_OStream& operator<<(double); + inline MT_OStream& operator<<(int); + inline MT_OStream& operator<<(char*); +}; + +const char GEN_endl = '\n'; + +#else + +#include + +typedef std::ostream MT_OStream; + +inline MT_OStream& GEN_endl(MT_OStream& os) { return std::endl(os); } + +#endif + +#endif + diff --git a/intern/moto/include/MT_Transform.h b/intern/moto/include/MT_Transform.h new file mode 100644 index 00000000000..ee5ae29dc41 --- /dev/null +++ b/intern/moto/include/MT_Transform.h @@ -0,0 +1,189 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + MoTo - 3D Motion Toolkit + Copyright (C) 2000 Gino van den Bergen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef MT_TRANSFORM_H +#define MT_TRANSFORM_H + +#include "MT_Point3.h" +#include "MT_Matrix3x3.h" + +class MT_Transform { +public: + MT_Transform() {} + MT_Transform(const float *m) { setValue(m); } + MT_Transform(const double *m) { setValue(m); } + MT_Transform(const MT_Point3& p, const MT_Quaternion& q) + : m_type(IDENTITY) + { + setOrigin(p); + setRotation(q); + } + + MT_Transform(const MT_Point3& p, const MT_Matrix3x3& m) + : m_type(IDENTITY) + { + setOrigin(p); + setBasis(m); + } + + static MT_Transform Identity() + { + MT_Transform t; + t.setIdentity(); + return t; + } + + + MT_Point3 operator()(const MT_Point3& p) const { + return MT_Point3(MT_dot(m_basis[0], p) + m_origin[0], + MT_dot(m_basis[1], p) + m_origin[1], + MT_dot(m_basis[2], p) + m_origin[2]); + } + + MT_Vector3 operator()(const MT_Vector3& p) const { + return MT_Vector3(MT_dot(m_basis[0], p) + m_origin[0], + MT_dot(m_basis[1], p) + m_origin[1], + MT_dot(m_basis[2], p) + m_origin[2]); + } + + MT_Point3 operator*(const MT_Point3& p) const { + return (*this)(p); + } + + MT_Vector3 operator*(const MT_Vector3& p) const { + return (*this)(p); + } + + + MT_Matrix3x3& getBasis() { return m_basis; } + const MT_Matrix3x3& getBasis() const { return m_basis; } + MT_Point3& getOrigin() { return m_origin; } + const MT_Point3& getOrigin() const { return m_origin; } + MT_Quaternion getRotation() const { return m_basis.getRotation(); } + + void setValue(const float *m); + void setValue(const double *m); + + void setOrigin(const MT_Point3& origin) { + m_origin = origin; + m_type |= TRANSLATION; + } + + void setBasis(const MT_Matrix3x3& basis) { + m_basis = basis; + m_type |= LINEAR; + } + + void setRotation(const MT_Quaternion& q) { + m_basis.setRotation(q); + m_type &= ~SCALING; + m_type |= ROTATION; + } + + void getValue(float *m) const; + void getValue(double *m) const; + + void setIdentity(); + + MT_Transform& operator*=(const MT_Transform& t); + + /** + * Translate the origin of the transform according to the vector. + * @param v The vector to translate over. The vector is specified + * in the coordinate system of the transform itself. + */ + void translate(const MT_Vector3& v); + void rotate(const MT_Quaternion& q); + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z); + + void invert(const MT_Transform& t); + void mult(const MT_Transform& t1, const MT_Transform& t2); + void multInverseLeft(const MT_Transform& t1, const MT_Transform& t2); + +private: + enum { + IDENTITY = 0x00, + TRANSLATION = 0x01, + ROTATION = 0x02, + RIGID = TRANSLATION | ROTATION, + SCALING = 0x04, + LINEAR = ROTATION | SCALING, + AFFINE = TRANSLATION | LINEAR + }; + + MT_Transform(const MT_Matrix3x3& basis, const MT_Point3& origin, + unsigned int type) { + setValue(basis, origin, type); + } + + void setValue(const MT_Matrix3x3& basis, const MT_Point3& origin, + unsigned int type) { + m_basis = basis; + m_origin = origin; + m_type = type; + } + + friend MT_Transform operator*(const MT_Transform& t1, const MT_Transform& t2); + + MT_Matrix3x3 m_basis; + MT_Point3 m_origin; + unsigned int m_type; +}; + +inline MT_Transform operator*(const MT_Transform& t1, const MT_Transform& t2) { + return MT_Transform(t1.m_basis * t2.m_basis, + t1(t2.m_origin), + t1.m_type | t2.m_type); +} + +#endif + diff --git a/intern/moto/include/MT_Tuple2.h b/intern/moto/include/MT_Tuple2.h new file mode 100644 index 00000000000..84280bec50a --- /dev/null +++ b/intern/moto/include/MT_Tuple2.h @@ -0,0 +1,110 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_Tuple2_H +#define MT_Tuple2_H + +#include "MT_Stream.h" +#include "MT_Scalar.h" + +class MT_Tuple2 { +public: + MT_Tuple2() {} + MT_Tuple2(const float *vv) { setValue(vv); } + MT_Tuple2(const double *vv) { setValue(vv); } + MT_Tuple2(MT_Scalar xx, MT_Scalar yy) { setValue(xx, yy); } + + MT_Scalar& operator[](int i) { return m_co[i]; } + const MT_Scalar& operator[](int i) const { return m_co[i]; } + + MT_Scalar& x() { return m_co[0]; } + const MT_Scalar& x() const { return m_co[0]; } + + MT_Scalar& y() { return m_co[1]; } + const MT_Scalar& y() const { return m_co[1]; } + + MT_Scalar& u() { return m_co[0]; } + const MT_Scalar& u() const { return m_co[0]; } + + MT_Scalar& v() { return m_co[1]; } + const MT_Scalar& v() const { return m_co[1]; } + + MT_Scalar *getValue() { return m_co; } + const MT_Scalar *getValue() const { return m_co; } + + void getValue(float *vv) const { + vv[0] = (float) m_co[0]; vv[1] = (float) m_co[1]; + } + + void getValue(double *vv) const { + vv[0] = m_co[0]; vv[1] = m_co[1]; + } + + void setValue(const float *vv) { + m_co[0] = vv[0]; m_co[1] = vv[1]; + } + + void setValue(const double *vv) { + m_co[0] = vv[0]; m_co[1] = vv[1]; + } + + void setValue(MT_Scalar xx, MT_Scalar yy) { + m_co[0] = xx; m_co[1] = yy; + } + +protected: + MT_Scalar m_co[2]; +}; + +inline bool operator==(const MT_Tuple2& t1, const MT_Tuple2& t2) { + return t1[0] == t2[0] && t1[1] == t2[1]; +} + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Tuple2& t) { + return os << t[0] << ' ' << t[1]; +} + +#endif + diff --git a/intern/moto/include/MT_Tuple3.h b/intern/moto/include/MT_Tuple3.h new file mode 100644 index 00000000000..271e323aab5 --- /dev/null +++ b/intern/moto/include/MT_Tuple3.h @@ -0,0 +1,115 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_TUPLE3_H +#define MT_TUPLE3_H + +#include "MT_Stream.h" +#include "MT_Scalar.h" + +class MT_Tuple3 { +public: + MT_Tuple3() {} + MT_Tuple3(const float *v) { setValue(v); } + MT_Tuple3(const double *v) { setValue(v); } + MT_Tuple3(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) { setValue(xx, yy, zz); } + + MT_Scalar& operator[](int i) { return m_co[i]; } + const MT_Scalar& operator[](int i) const { return m_co[i]; } + + MT_Scalar& x() { return m_co[0]; } + const MT_Scalar& x() const { return m_co[0]; } + + MT_Scalar& y() { return m_co[1]; } + const MT_Scalar& y() const { return m_co[1]; } + + MT_Scalar& z() { return m_co[2]; } + const MT_Scalar& z() const { return m_co[2]; } + + MT_Scalar *getValue() { return m_co; } + const MT_Scalar *getValue() const { return m_co; } + + void getValue(float *v) const { + v[0] = float(m_co[0]); + v[1] = float(m_co[1]); + v[2] = float(m_co[2]); + } + + void getValue(double *v) const { + v[0] = double(m_co[0]); + v[1] = double(m_co[1]); + v[2] = double(m_co[2]); + } + + void setValue(const float *v) { + m_co[0] = MT_Scalar(v[0]); + m_co[1] = MT_Scalar(v[1]); + m_co[2] = MT_Scalar(v[2]); + } + + void setValue(const double *v) { + m_co[0] = MT_Scalar(v[0]); + m_co[1] = MT_Scalar(v[1]); + m_co[2] = MT_Scalar(v[2]); + } + + void setValue(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) { + m_co[0] = xx; m_co[1] = yy; m_co[2] = zz; + } + +protected: + MT_Scalar m_co[3]; +}; + +inline bool operator==(const MT_Tuple3& t1, const MT_Tuple3& t2) { + return t1[0] == t2[0] && t1[1] == t2[1] && t1[2] == t2[2]; +} + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Tuple3& t) { + return os << t[0] << ' ' << t[1] << ' ' << t[2]; +} + +#endif + diff --git a/intern/moto/include/MT_Tuple4.h b/intern/moto/include/MT_Tuple4.h new file mode 100644 index 00000000000..9a484dbedde --- /dev/null +++ b/intern/moto/include/MT_Tuple4.h @@ -0,0 +1,125 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_TUPLE4_H +#define MT_TUPLE4_H + +#include "MT_Stream.h" +#include "MT_Scalar.h" + +class MT_Tuple4 { +public: + MT_Tuple4() {} + MT_Tuple4(const float *v) { setValue(v); } + MT_Tuple4(const double *v) { setValue(v); } + MT_Tuple4(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) { + setValue(xx, yy, zz, ww); + } + + MT_Scalar& operator[](int i) { return m_co[i]; } + const MT_Scalar& operator[](int i) const { return m_co[i]; } + + MT_Scalar& x() { return m_co[0]; } + const MT_Scalar& x() const { return m_co[0]; } + + MT_Scalar& y() { return m_co[1]; } + const MT_Scalar& y() const { return m_co[1]; } + + MT_Scalar& z() { return m_co[2]; } + const MT_Scalar& z() const { return m_co[2]; } + + MT_Scalar& w() { return m_co[3]; } + const MT_Scalar& w() const { return m_co[3]; } + + MT_Scalar *getValue() { return m_co; } + const MT_Scalar *getValue() const { return m_co; } + + + void getValue(float *v) const { + v[0] = float(m_co[0]); + v[1] = float(m_co[1]); + v[2] = float(m_co[2]); + v[3] = float(m_co[3]); + } + + void getValue(double *v) const { + v[0] = double(m_co[0]); + v[1] = double(m_co[1]); + v[2] = double(m_co[2]); + v[3] = double(m_co[3]); + } + + void setValue(const float *v) { + m_co[0] = MT_Scalar(v[0]); + m_co[1] = MT_Scalar(v[1]); + m_co[2] = MT_Scalar(v[2]); + m_co[3] = MT_Scalar(v[3]); + } + + void setValue(const double *v) { + m_co[0] = MT_Scalar(v[0]); + m_co[1] = MT_Scalar(v[1]); + m_co[2] = MT_Scalar(v[2]); + m_co[3] = MT_Scalar(v[3]); + } + + void setValue(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) { + m_co[0] = xx; m_co[1] = yy; m_co[2] = zz; m_co[3] = ww; + } + +protected: + MT_Scalar m_co[4]; +}; + +inline bool operator==(const MT_Tuple4& t1, const MT_Tuple4& t2) { + return t1[0] == t2[0] && t1[1] == t2[1] && t1[2] == t2[2] && t1[3] == t2[3]; +} + +inline MT_OStream& operator<<(MT_OStream& os, const MT_Tuple4& t) { + return os << t[0] << ' ' << t[1] << ' ' << t[2] << ' ' << t[3]; +} + +#endif + diff --git a/intern/moto/include/MT_Vector2.h b/intern/moto/include/MT_Vector2.h new file mode 100644 index 00000000000..629d962a781 --- /dev/null +++ b/intern/moto/include/MT_Vector2.h @@ -0,0 +1,113 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_VECTOR2_H +#define MT_VECTOR2_H + +#include +#include "MT_Tuple2.h" + +class MT_Vector2 : public MT_Tuple2 { +public: + MT_Vector2() {} + MT_Vector2(const float *v2) : MT_Tuple2(v2) {} + MT_Vector2(const double *v2) : MT_Tuple2(v2) {} + MT_Vector2(MT_Scalar xx, MT_Scalar yy) : MT_Tuple2(xx, yy) {} + + MT_Vector2& operator+=(const MT_Vector2& v); + MT_Vector2& operator-=(const MT_Vector2& v); + MT_Vector2& operator*=(MT_Scalar s); + MT_Vector2& operator/=(MT_Scalar s); + + MT_Scalar dot(const MT_Vector2& v) const; + + MT_Scalar length2() const; + MT_Scalar length() const; + + MT_Vector2 absolute() const; + + void normalize(); + MT_Vector2 normalized() const; + + void scale(MT_Scalar x, MT_Scalar y); + MT_Vector2 scaled(MT_Scalar x, MT_Scalar y) const; + + bool fuzzyZero() const; + + MT_Scalar angle(const MT_Vector2& v) const; + MT_Vector2 cross(const MT_Vector2& v) const; + MT_Scalar triple(const MT_Vector2& v1, const MT_Vector2& v2) const; + + int closestAxis() const; + + static MT_Vector2 random(); +}; + +MT_Vector2 operator+(const MT_Vector2& v1, const MT_Vector2& v2); +MT_Vector2 operator-(const MT_Vector2& v1, const MT_Vector2& v2); +MT_Vector2 operator-(const MT_Vector2& v); +MT_Vector2 operator*(const MT_Vector2& v, MT_Scalar s); +MT_Vector2 operator*(MT_Scalar s, const MT_Vector2& v); +MT_Vector2 operator/(const MT_Vector2& v, MT_Scalar s); + +MT_Scalar MT_dot(const MT_Vector2& v1, const MT_Vector2& v2); + +MT_Scalar MT_length2(const MT_Vector2& v); +MT_Scalar MT_length(const MT_Vector2& v); + +bool MT_fuzzyZero(const MT_Vector2& v); +bool MT_fuzzyEqual(const MT_Vector2& v1, const MT_Vector2& v2); + +MT_Scalar MT_angle(const MT_Vector2& v1, const MT_Vector2& v2); +MT_Vector2 MT_cross(const MT_Vector2& v1, const MT_Vector2& v2); +MT_Scalar MT_triple(const MT_Vector2& v1, const MT_Vector2& v2, + const MT_Vector2& v3); + +#ifdef GEN_INLINED +#include "MT_Vector2.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Vector2.inl b/intern/moto/include/MT_Vector2.inl new file mode 100644 index 00000000000..860f9bad830 --- /dev/null +++ b/intern/moto/include/MT_Vector2.inl @@ -0,0 +1,89 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Vector2& MT_Vector2::operator+=(const MT_Vector2& vv) { + m_co[0] += vv[0]; m_co[1] += vv[1]; + return *this; +} + +GEN_INLINE MT_Vector2& MT_Vector2::operator-=(const MT_Vector2& vv) { + m_co[0] -= vv[0]; m_co[1] -= vv[1]; + return *this; +} + +GEN_INLINE MT_Vector2& MT_Vector2::operator*=(MT_Scalar s) { + m_co[0] *= s; m_co[1] *= s; + return *this; +} + +GEN_INLINE MT_Vector2& MT_Vector2::operator/=(MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return *this *= 1.0 / s; +} + +GEN_INLINE MT_Vector2 operator+(const MT_Vector2& v1, const MT_Vector2& v2) { + return MT_Vector2(v1[0] + v2[0], v1[1] + v2[1]); +} + +GEN_INLINE MT_Vector2 operator-(const MT_Vector2& v1, const MT_Vector2& v2) { + return MT_Vector2(v1[0] - v2[0], v1[1] - v2[1]); +} + +GEN_INLINE MT_Vector2 operator-(const MT_Vector2& v) { + return MT_Vector2(-v[0], -v[1]); +} + +GEN_INLINE MT_Vector2 operator*(const MT_Vector2& v, MT_Scalar s) { + return MT_Vector2(v[0] * s, v[1] * s); +} + +GEN_INLINE MT_Vector2 operator*(MT_Scalar s, const MT_Vector2& v) { return v * s; } + +GEN_INLINE MT_Vector2 operator/(const MT_Vector2& v, MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return v * (1.0 / s); +} + +GEN_INLINE MT_Scalar MT_Vector2::dot(const MT_Vector2& vv) const { + return m_co[0] * vv[0] + m_co[1] * vv[1]; +} + +GEN_INLINE MT_Scalar MT_Vector2::length2() const { return dot(*this); } +GEN_INLINE MT_Scalar MT_Vector2::length() const { return sqrt(length2()); } + +GEN_INLINE MT_Vector2 MT_Vector2::absolute() const { + return MT_Vector2(MT_abs(m_co[0]), MT_abs(m_co[1])); +} + +GEN_INLINE bool MT_Vector2::fuzzyZero() const { return MT_fuzzyZero2(length2()); } + +GEN_INLINE void MT_Vector2::normalize() { *this /= length(); } +GEN_INLINE MT_Vector2 MT_Vector2::normalized() const { return *this / length(); } + +GEN_INLINE void MT_Vector2::scale(MT_Scalar xx, MT_Scalar yy) { + m_co[0] *= xx; m_co[1] *= yy; +} + +GEN_INLINE MT_Vector2 MT_Vector2::scaled(MT_Scalar xx, MT_Scalar yy) const { + return MT_Vector2(m_co[0] * xx, m_co[1] * yy); +} + +GEN_INLINE MT_Scalar MT_Vector2::angle(const MT_Vector2& vv) const { + MT_Scalar s = sqrt(length2() * vv.length2()); + MT_assert(!MT_fuzzyZero(s)); + return acos(dot(vv) / s); +} + + +GEN_INLINE MT_Scalar MT_dot(const MT_Vector2& v1, const MT_Vector2& v2) { + return v1.dot(v2); +} + +GEN_INLINE MT_Scalar MT_length2(const MT_Vector2& v) { return v.length2(); } +GEN_INLINE MT_Scalar MT_length(const MT_Vector2& v) { return v.length(); } + +GEN_INLINE bool MT_fuzzyZero(const MT_Vector2& v) { return v.fuzzyZero(); } +GEN_INLINE bool MT_fuzzyEqual(const MT_Vector2& v1, const MT_Vector2& v2) { + return MT_fuzzyZero(v1 - v2); +} + +GEN_INLINE MT_Scalar MT_angle(const MT_Vector2& v1, const MT_Vector2& v2) { return v1.angle(v2); } diff --git a/intern/moto/include/MT_Vector3.h b/intern/moto/include/MT_Vector3.h new file mode 100644 index 00000000000..c35a9d47234 --- /dev/null +++ b/intern/moto/include/MT_Vector3.h @@ -0,0 +1,120 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_VECTOR3_H +#define MT_VECTOR3_H + +#include +#include "MT_Tuple3.h" + +class MT_Vector3 : public MT_Tuple3 { +public: + virtual ~MT_Vector3() {} + MT_Vector3() {} + MT_Vector3(const float *v) : MT_Tuple3(v) {} + MT_Vector3(const double *v) : MT_Tuple3(v) {} + MT_Vector3(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) : MT_Tuple3(xx, yy, zz) {} + + MT_Vector3& operator+=(const MT_Vector3& v); + MT_Vector3& operator-=(const MT_Vector3& v); + MT_Vector3& operator*=(MT_Scalar s); + MT_Vector3& operator/=(MT_Scalar s); + + MT_Scalar dot(const MT_Vector3& v) const; + + MT_Scalar length2() const; + MT_Scalar length() const; + + MT_Vector3 absolute() const; + + void noiseGate(MT_Scalar threshold); + + void normalize(); + MT_Vector3 normalized() const; + MT_Vector3 safe_normalized() const; + + + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z); + MT_Vector3 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z) const; + + bool fuzzyZero() const; + + MT_Scalar angle(const MT_Vector3& v) const; + MT_Vector3 cross(const MT_Vector3& v) const; + MT_Scalar triple(const MT_Vector3& v1, const MT_Vector3& v2) const; + + int closestAxis() const; + + static MT_Vector3 random(); +}; + +MT_Vector3 operator+(const MT_Vector3& v1, const MT_Vector3& v2); +MT_Vector3 operator-(const MT_Vector3& v1, const MT_Vector3& v2); +MT_Vector3 operator-(const MT_Vector3& v); +MT_Vector3 operator*(const MT_Vector3& v, MT_Scalar s); +MT_Vector3 operator*(MT_Scalar s, const MT_Vector3& v); +MT_Vector3 operator/(const MT_Vector3& v, MT_Scalar s); + +MT_Vector3 operator*(const MT_Vector3& v1, const MT_Vector3& v2); + +MT_Scalar MT_dot(const MT_Vector3& v1, const MT_Vector3& v2); + +MT_Scalar MT_length2(const MT_Vector3& v); +MT_Scalar MT_length(const MT_Vector3& v); + +bool MT_fuzzyZero(const MT_Vector3& v); +bool MT_fuzzyEqual(const MT_Vector3& v1, const MT_Vector3& v2); + +MT_Scalar MT_angle(const MT_Vector3& v1, const MT_Vector3& v2); +MT_Vector3 MT_cross(const MT_Vector3& v1, const MT_Vector3& v2); +MT_Scalar MT_triple(const MT_Vector3& v1, const MT_Vector3& v2, + const MT_Vector3& v3); + +#ifdef GEN_INLINED +#include "MT_Vector3.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Vector3.inl b/intern/moto/include/MT_Vector3.inl new file mode 100644 index 00000000000..b17ef47c709 --- /dev/null +++ b/intern/moto/include/MT_Vector3.inl @@ -0,0 +1,134 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Vector3& MT_Vector3::operator+=(const MT_Vector3& v) { + m_co[0] += v[0]; m_co[1] += v[1]; m_co[2] += v[2]; + return *this; +} + +GEN_INLINE MT_Vector3& MT_Vector3::operator-=(const MT_Vector3& v) { + m_co[0] -= v[0]; m_co[1] -= v[1]; m_co[2] -= v[2]; + return *this; +} + +GEN_INLINE MT_Vector3& MT_Vector3::operator*=(MT_Scalar s) { + m_co[0] *= s; m_co[1] *= s; m_co[2] *= s; + return *this; +} + +GEN_INLINE MT_Vector3& MT_Vector3::operator/=(MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return *this *= MT_Scalar(1.0) / s; +} + +GEN_INLINE MT_Vector3 operator+(const MT_Vector3& v1, const MT_Vector3& v2) { + return MT_Vector3(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]); +} + +GEN_INLINE MT_Vector3 operator-(const MT_Vector3& v1, const MT_Vector3& v2) { + return MT_Vector3(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]); +} + +GEN_INLINE MT_Vector3 operator-(const MT_Vector3& v) { + return MT_Vector3(-v[0], -v[1], -v[2]); +} + +GEN_INLINE MT_Vector3 operator*(const MT_Vector3& v, MT_Scalar s) { + return MT_Vector3(v[0] * s, v[1] * s, v[2] * s); +} + +GEN_INLINE MT_Vector3 operator*(MT_Scalar s, const MT_Vector3& v) { return v * s; } + +GEN_INLINE MT_Vector3 operator/(const MT_Vector3& v, MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return v * (MT_Scalar(1.0) / s); +} + +GEN_INLINE MT_Vector3 operator*(const MT_Vector3& v1, const MT_Vector3& v2) { + return MT_Vector3(v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]); +} + +GEN_INLINE MT_Scalar MT_Vector3::dot(const MT_Vector3& v) const { + return m_co[0] * v[0] + m_co[1] * v[1] + m_co[2] * v[2]; +} + +GEN_INLINE MT_Scalar MT_Vector3::length2() const { return dot(*this); } +GEN_INLINE MT_Scalar MT_Vector3::length() const { return sqrt(length2()); } + +GEN_INLINE MT_Vector3 MT_Vector3::absolute() const { + return MT_Vector3(MT_abs(m_co[0]), MT_abs(m_co[1]), MT_abs(m_co[2])); +} + +GEN_INLINE bool MT_Vector3::fuzzyZero() const { + return MT_fuzzyZero(length2()); +} + +GEN_INLINE void MT_Vector3::noiseGate(MT_Scalar threshold) { + if (length2() < threshold) { + setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)); + } +} + +GEN_INLINE void MT_Vector3::normalize() { *this /= length(); } +GEN_INLINE MT_Vector3 MT_Vector3::normalized() const { return *this / length(); } +GEN_INLINE MT_Vector3 MT_Vector3::safe_normalized() const { + MT_Scalar len = length(); + return MT_fuzzyZero(len) ? + MT_Vector3(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0)) : + *this / len; +} + +GEN_INLINE void MT_Vector3::scale(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) { + m_co[0] *= xx; m_co[1] *= yy; m_co[2] *= zz; +} + +GEN_INLINE MT_Vector3 MT_Vector3::scaled(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz) const { + return MT_Vector3(m_co[0] * xx, m_co[1] * yy, m_co[2] * zz); +} + +GEN_INLINE MT_Scalar MT_Vector3::angle(const MT_Vector3& v) const { + MT_Scalar s = sqrt(length2() * v.length2()); + MT_assert(!MT_fuzzyZero(s)); + return acos(dot(v) / s); +} + +GEN_INLINE MT_Vector3 MT_Vector3::cross(const MT_Vector3& v) const { + return MT_Vector3(m_co[1] * v[2] - m_co[2] * v[1], + m_co[2] * v[0] - m_co[0] * v[2], + m_co[0] * v[1] - m_co[1] * v[0]); +} + +GEN_INLINE MT_Scalar MT_Vector3::triple(const MT_Vector3& v1, const MT_Vector3& v2) const { + return m_co[0] * (v1[1] * v2[2] - v1[2] * v2[1]) + + m_co[1] * (v1[2] * v2[0] - v1[0] * v2[2]) + + m_co[2] * (v1[0] * v2[1] - v1[1] * v2[0]); +} + +GEN_INLINE int MT_Vector3::closestAxis() const { + MT_Vector3 a = absolute(); + return a[0] < a[1] ? (a[1] < a[2] ? 2 : 1) : (a[0] < a[2] ? 2 : 0); +} + +GEN_INLINE MT_Vector3 MT_Vector3::random() { + MT_Scalar z = MT_Scalar(2.0) * MT_random() - MT_Scalar(1.0); + MT_Scalar r = sqrt(MT_Scalar(1.0) - z * z); + MT_Scalar t = MT_2_PI * MT_random(); + return MT_Vector3(r * cos(t), r * sin(t), z); +} + +GEN_INLINE MT_Scalar MT_dot(const MT_Vector3& v1, const MT_Vector3& v2) { + return v1.dot(v2); +} + +GEN_INLINE MT_Scalar MT_length2(const MT_Vector3& v) { return v.length2(); } +GEN_INLINE MT_Scalar MT_length(const MT_Vector3& v) { return v.length(); } + +GEN_INLINE bool MT_fuzzyZero(const MT_Vector3& v) { return v.fuzzyZero(); } +GEN_INLINE bool MT_fuzzyEqual(const MT_Vector3& v1, const MT_Vector3& v2) { + return MT_fuzzyZero(v1 - v2); +} + +GEN_INLINE MT_Scalar MT_angle(const MT_Vector3& v1, const MT_Vector3& v2) { return v1.angle(v2); } +GEN_INLINE MT_Vector3 MT_cross(const MT_Vector3& v1, const MT_Vector3& v2) { return v1.cross(v2); } +GEN_INLINE MT_Scalar MT_triple(const MT_Vector3& v1, const MT_Vector3& v2, const MT_Vector3& v3) { + return v1.triple(v2, v3); +} diff --git a/intern/moto/include/MT_Vector4.h b/intern/moto/include/MT_Vector4.h new file mode 100644 index 00000000000..5f1ee99d584 --- /dev/null +++ b/intern/moto/include/MT_Vector4.h @@ -0,0 +1,103 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + * Copyright (c) 2000 Gino van den Bergen + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Gino van den Bergen makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef MT_VECTOR4_H +#define MT_VECTOR4_H + +#include + +#include "MT_Tuple4.h" + +class MT_Vector4 : public MT_Tuple4 { +public: + virtual ~MT_Vector4() {} + MT_Vector4() {} + MT_Vector4(const float *v) : MT_Tuple4(v) {} + MT_Vector4(const double *v) : MT_Tuple4(v) {} + MT_Vector4(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) : + MT_Tuple4(xx, yy, zz, ww) {} + + MT_Vector4& operator+=(const MT_Vector4& v); + MT_Vector4& operator-=(const MT_Vector4& v); + MT_Vector4& operator*=(MT_Scalar s); + MT_Vector4& operator/=(MT_Scalar s); + + MT_Scalar dot(const MT_Vector4& v) const; + + MT_Scalar length2() const; + MT_Scalar length() const; + + MT_Vector4 absolute() const; + + void normalize(); + MT_Vector4 normalized() const; + + void scale(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w); + MT_Vector4 scaled(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) const; + + bool fuzzyZero() const; +}; + +MT_Vector4 operator+(const MT_Vector4& v1, const MT_Vector4& v2); +MT_Vector4 operator-(const MT_Vector4& v1, const MT_Vector4& v2); +MT_Vector4 operator-(const MT_Vector4& v); +MT_Vector4 operator*(const MT_Vector4& v, MT_Scalar s); +MT_Vector4 operator*(MT_Scalar s, const MT_Vector4& v); +MT_Vector4 operator/(const MT_Vector4& v, MT_Scalar s); + +MT_Scalar MT_dot(const MT_Vector4& v1, const MT_Vector4& v2); + +MT_Scalar MT_length2(const MT_Vector4& v); +MT_Scalar MT_length(const MT_Vector4& v); + +bool MT_fuzzyZero(const MT_Vector4& v); +bool MT_fuzzyEqual(const MT_Vector4& v1, const MT_Vector4& v2); + +#ifdef GEN_INLINED +#include "MT_Vector4.inl" +#endif + +#endif + diff --git a/intern/moto/include/MT_Vector4.inl b/intern/moto/include/MT_Vector4.inl new file mode 100644 index 00000000000..9b4126093c1 --- /dev/null +++ b/intern/moto/include/MT_Vector4.inl @@ -0,0 +1,80 @@ +#include "MT_Optimize.h" + +GEN_INLINE MT_Vector4& MT_Vector4::operator+=(const MT_Vector4& v) { + m_co[0] += v[0]; m_co[1] += v[1]; m_co[2] += v[2]; m_co[3] += v[3]; + return *this; +} + +GEN_INLINE MT_Vector4& MT_Vector4::operator-=(const MT_Vector4& v) { + m_co[0] -= v[0]; m_co[1] -= v[1]; m_co[2] -= v[2]; m_co[3] -= v[3]; + return *this; +} + +GEN_INLINE MT_Vector4& MT_Vector4::operator*=(MT_Scalar s) { + m_co[0] *= s; m_co[1] *= s; m_co[2] *= s; m_co[3] *= s; + return *this; +} + +GEN_INLINE MT_Vector4& MT_Vector4::operator/=(MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return *this *= MT_Scalar(1.0) / s; +} + +GEN_INLINE MT_Vector4 operator+(const MT_Vector4& v1, const MT_Vector4& v2) { + return MT_Vector4(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2], v1[3] + v2[3]); +} + +GEN_INLINE MT_Vector4 operator-(const MT_Vector4& v1, const MT_Vector4& v2) { + return MT_Vector4(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2], v1[3] - v2[3]); +} + +GEN_INLINE MT_Vector4 operator-(const MT_Vector4& v) { + return MT_Vector4(-v[0], -v[1], -v[2], -v[3]); +} + +GEN_INLINE MT_Vector4 operator*(const MT_Vector4& v, MT_Scalar s) { + return MT_Vector4(v[0] * s, v[1] * s, v[2] * s, v[3] * s); +} + +GEN_INLINE MT_Vector4 operator*(MT_Scalar s, const MT_Vector4& v) { return v * s; } + +GEN_INLINE MT_Vector4 operator/(const MT_Vector4& v, MT_Scalar s) { + MT_assert(!MT_fuzzyZero(s)); + return v * (MT_Scalar(1.0) / s); +} + +GEN_INLINE MT_Scalar MT_Vector4::dot(const MT_Vector4& v) const { + return m_co[0] * v[0] + m_co[1] * v[1] + m_co[2] * v[2] + m_co[3] * v[3]; +} + +GEN_INLINE MT_Scalar MT_Vector4::length2() const { return MT_dot(*this, *this); } +GEN_INLINE MT_Scalar MT_Vector4::length() const { return sqrt(length2()); } + +GEN_INLINE MT_Vector4 MT_Vector4::absolute() const { + return MT_Vector4(MT_abs(m_co[0]), MT_abs(m_co[1]), MT_abs(m_co[2]), MT_abs(m_co[3])); +} + +GEN_INLINE void MT_Vector4::scale(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) { + m_co[0] *= xx; m_co[1] *= yy; m_co[2] *= zz; m_co[3] *= ww; +} + +GEN_INLINE MT_Vector4 MT_Vector4::scaled(MT_Scalar xx, MT_Scalar yy, MT_Scalar zz, MT_Scalar ww) const { + return MT_Vector4(m_co[0] * xx, m_co[1] * yy, m_co[2] * zz, m_co[3] * ww); +} + +GEN_INLINE bool MT_Vector4::fuzzyZero() const { return MT_fuzzyZero2(length2()); } + +GEN_INLINE void MT_Vector4::normalize() { *this /= length(); } +GEN_INLINE MT_Vector4 MT_Vector4::normalized() const { return *this / length(); } + +GEN_INLINE MT_Scalar MT_dot(const MT_Vector4& v1, const MT_Vector4& v2) { + return v1.dot(v2); +} + +GEN_INLINE MT_Scalar MT_length2(const MT_Vector4& v) { return v.length2(); } +GEN_INLINE MT_Scalar MT_length(const MT_Vector4& v) { return v.length(); } + +GEN_INLINE bool MT_fuzzyZero(const MT_Vector4& v) { return v.fuzzyZero(); } +GEN_INLINE bool MT_fuzzyEqual(const MT_Vector4& v1, const MT_Vector4& v2) { + return MT_fuzzyZero(v1 - v2); +} diff --git a/intern/moto/include/MT_assert.h b/intern/moto/include/MT_assert.h new file mode 100644 index 00000000000..54aea403cda --- /dev/null +++ b/intern/moto/include/MT_assert.h @@ -0,0 +1,102 @@ +/** +* $Id$ +* ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. The Blender +* Foundation also sells licenses for use in proprietary software under +* the Blender License. See http://www.blender.org/BL/ for information +* about this. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef MT_ASSERT_H +#define MT_ASSERT_H + +#include +#include +#include + + +// So it can be used from C +#ifdef __cplusplus +#define MT_CDECL extern "C" +#else +#define MT_CDECL +#endif + +// Ask the user if they wish to abort/break, ignore, or ignore for good. +// file, line, predicate form the message to ask, *do_assert should be set +// to 0 to ignore. +// returns 1 to break, false to ignore +MT_CDECL int MT_QueryAssert(const char *file, int line, const char *predicate, int *do_assert); + + +#ifdef NDEBUG +#define MT_assert(predicate) ((void)0) +#define BREAKPOINT() ((void)0) +#else + +// BREAKPOINT() will cause a break into the debugger +#if defined(__i386) && defined(__GNUC__) +// gcc on intel... +#define BREAKPOINT() \ +asm("int $3") +#elif defined(_MSC_VER) +// Visual C++ (on Intel) +#define BREAKPOINT() \ +{ _asm int 3 } +#elif defined(SIGTRAP) +// POSIX compatible... +#define BREAKPOINT() \ +raise(SIGTRAP); +#else +// FIXME: Don't know how to do a decent break! +// Add some code for your cpu type, or get a posix +// system. +// abort instead +#define BREAKPOINT() \ +abort(); +#endif /* breakpoint */ + + +#if defined(WIN32) && !defined(__GNUC__) +#define MT_assert(predicate) assert(predicate) +#else + + + +// Abort the program if predicate is not true +#define MT_assert(predicate) \ +{ \ + static int do_assert = 1; \ + if (!(predicate) && MT_QueryAssert(__FILE__, __LINE__, #predicate, &do_assert)) \ + { \ + BREAKPOINT(); \ + } \ +} +#endif /* windows */ + +#endif /* NDEBUG */ + +#endif + diff --git a/intern/moto/include/MT_random.h b/intern/moto/include/MT_random.h new file mode 100644 index 00000000000..8a578fa7d09 --- /dev/null +++ b/intern/moto/include/MT_random.h @@ -0,0 +1,43 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef MT_RANDOM_H +#define MT_RANDOM_H + +#include + +#define MT_RAND_MAX ULONG_MAX + +extern void MT_srand(unsigned long); +extern unsigned long MT_rand(); + +#endif + diff --git a/intern/moto/include/NM_Scalar.h b/intern/moto/include/NM_Scalar.h new file mode 100644 index 00000000000..a15b187cab9 --- /dev/null +++ b/intern/moto/include/NM_Scalar.h @@ -0,0 +1,158 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include + +template +class NM_Scalar { +public: + NM_Scalar() {} + explicit NM_Scalar(T value, T error = 0.0) : + m_value(value), m_error(error) {} + + T getValue() const { return m_value; } + T getError() const { return m_error; } + + operator T() const { return m_value; } + + NM_Scalar operator-() const { + return NM_Scalar(-m_value, m_error); + } + + NM_Scalar& operator=(T value) { + m_value = value; + m_error = 0.0; + return *this; + } + + NM_Scalar& operator+=(const NM_Scalar& x) { + m_value += x.m_value; + m_error = (fabs(m_value) * (m_error + 1.0) + + fabs(x.m_value) * (x.m_error + 1.0)) / + fabs(m_value + x.m_value); + return *this; + } + + NM_Scalar& operator-=(const NM_Scalar& x) { + m_value -= x.m_value; + m_error = (fabs(m_value) * (m_error + 1.0) + + fabs(x.m_value) * (x.m_error + 1.0)) / + fabs(m_value - x.m_value); + return *this; + } + + NM_Scalar& operator*=(const NM_Scalar& x) { + m_value *= x.m_value; + m_error += x.m_error + 1.0; + return *this; + } + + NM_Scalar& operator/=(const NM_Scalar& x) { + m_value /= x.m_value; + m_error += x.m_error + 1.0; + return *this; + } + +private: + T m_value; + T m_error; +}; + +template +inline NM_Scalar operator+(const NM_Scalar& x, const NM_Scalar& y) { + return x.getValue() == 0.0 && y.getValue() == 0.0 ? + NM_Scalar(0.0, 0.0) : + NM_Scalar(x.getValue() + y.getValue(), + (fabs(x.getValue()) * (x.getError() + 1.0) + + fabs(y.getValue()) * (y.getError() + 1.0)) / + fabs(x.getValue() + y.getValue())); +} + +template +inline NM_Scalar operator-(const NM_Scalar& x, const NM_Scalar& y) { + return x.getValue() == 0.0 && y.getValue() == 0.0 ? + NM_Scalar(0.0, 0.0) : + NM_Scalar(x.getValue() - y.getValue(), + (fabs(x.getValue()) * (x.getError() + 1.0) + + fabs(y.getValue()) * (y.getError() + 1.0)) / + fabs(x.getValue() - y.getValue())); +} + +template +inline NM_Scalar operator*(const NM_Scalar& x, const NM_Scalar& y) { + return NM_Scalar(x.getValue() * y.getValue(), + x.getError() + y.getError() + 1.0); +} + +template +inline NM_Scalar operator/(const NM_Scalar& x, const NM_Scalar& y) { + return NM_Scalar(x.getValue() / y.getValue(), + x.getError() + y.getError() + 1.0); +} + +template +inline std::ostream& operator<<(std::ostream& os, const NM_Scalar& x) { + return os << x.getValue() << '[' << x.getError() << ']'; +} + +template +inline NM_Scalar sqrt(const NM_Scalar& x) { + return NM_Scalar(sqrt(x.getValue()), + 0.5 * x.getError() + 1.0); +} + +template +inline NM_Scalar acos(const NM_Scalar& x) { + return NM_Scalar(acos(x.getValue()), x.getError() + 1.0); +} + +template +inline NM_Scalar cos(const NM_Scalar& x) { + return NM_Scalar(cos(x.getValue()), x.getError() + 1.0); +} + +template +inline NM_Scalar sin(const NM_Scalar& x) { + return NM_Scalar(sin(x.getValue()), x.getError() + 1.0); +} + +template +inline NM_Scalar fabs(const NM_Scalar& x) { + return NM_Scalar(fabs(x.getValue()), x.getError()); +} + +template +inline NM_Scalar pow(const NM_Scalar& x, const NM_Scalar& y) { + return NM_Scalar(pow(x.getValue(), y.getValue()), + fabs(y.getValue()) * x.getError() + 1.0); +} + diff --git a/intern/moto/intern/MT_Assert.cpp b/intern/moto/intern/MT_Assert.cpp new file mode 100644 index 00000000000..c16c43f2045 --- /dev/null +++ b/intern/moto/intern/MT_Assert.cpp @@ -0,0 +1,67 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include + +#ifdef _WIN32 +#include +#endif + +#include "MT_assert.h" + +#ifdef _MSC_VER +#ifndef snprintf + #define snprintf _snprintf +#endif +#endif + +// Query the user if they want to break/abort the program, ignore the assert, or ignore all future +// occurance of the assert. +int MT_QueryAssert(const char *file, int line, const char *predicate, int *do_assert) +{ +#ifdef _WIN32 + if (*do_assert) + { + char buffer[1024]; + snprintf(buffer, 1024, "ASSERT %s:%d: %s failed.\nWould you like to debug? (Cancel = ignore)", file, line, predicate); + int result = MessageBox(NULL, buffer, "ASSERT failed.", MB_YESNOCANCEL|MB_ICONERROR); + if (result == IDCANCEL) + { + *do_assert = 0; + return 0; + } + + return result == IDYES; + } +#endif + printf("ASSERT %s:%d: %s failed.\n", file, line, predicate); + return *do_assert; +} diff --git a/intern/moto/intern/MT_CmMatrix4x4.cpp b/intern/moto/intern/MT_CmMatrix4x4.cpp new file mode 100644 index 00000000000..64ff3512c7a --- /dev/null +++ b/intern/moto/intern/MT_CmMatrix4x4.cpp @@ -0,0 +1,240 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_CmMatrix4x4.h" +#include "MT_Vector3.h" +#include "MT_Point3.h" + + +MT_CmMatrix4x4::MT_CmMatrix4x4() +{ + Identity(); +} + + + +MT_CmMatrix4x4::MT_CmMatrix4x4(const float value[4][4]) +{ + for (int i=0;i<4;i++) + { + for (int j=0;j<4;j++) + m_V[i][j] = value[i][j]; + } +} + + + +MT_CmMatrix4x4::MT_CmMatrix4x4(const double value[16]) +{ + for (int i=0;i<16;i++) + m_Vflat[i] = value[i]; +} + + + +MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_CmMatrix4x4& other) +{ + SetMatrix(other); +} + + + +MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_Point3& orig, + const MT_Vector3& dir, + const MT_Vector3 up) +{ + MT_Vector3 z = -(dir.normalized()); + MT_Vector3 x = (up.cross(z)).normalized(); + MT_Vector3 y = (z.cross(x)); + + m_V[0][0] = x.x(); + m_V[0][1] = y.x(); + m_V[0][2] = z.x(); + m_V[0][3] = 0.0f; + + m_V[1][0] = x.y(); + m_V[1][1] = y.y(); + m_V[1][2] = z.y(); + m_V[1][3] = 0.0f; + + m_V[2][0] = x.z(); + m_V[2][1] = y.z(); + m_V[2][2] = z.z(); + m_V[2][3] = 0.0f; + + m_V[3][0] = orig.x();//0.0f; + m_V[3][1] = orig.y();//0.0f; + m_V[3][2] = orig.z();//0.0f; + m_V[3][3] = 1.0f; + + //Translate(-orig); +} + + + +MT_Vector3 MT_CmMatrix4x4::GetRight() const +{ + return MT_Vector3(m_V[0][0], m_V[0][1], m_V[0][2]); +} + + + +MT_Vector3 MT_CmMatrix4x4::GetUp() const +{ + return MT_Vector3(m_V[1][0], m_V[1][1], m_V[1][2]); +} + + + +MT_Vector3 MT_CmMatrix4x4::GetDir() const +{ + return MT_Vector3(m_V[2][0], m_V[2][1], m_V[2][2]); +} + + + +MT_Point3 MT_CmMatrix4x4::GetPos() const +{ + return MT_Point3(m_V[3][0], m_V[3][1], m_V[3][2]); +} + + + +void MT_CmMatrix4x4::Identity() +{ + for (int i=0; i<4; i++) + { + for (int j=0; j<4; j++) + m_V[i][j] = (i==j?1.0f:0.0f); + } +} + + + +void MT_CmMatrix4x4::SetMatrix(const MT_CmMatrix4x4& other) +{ + for (int i=0; i<16; i++) + m_Vflat[i] = other.m_Vflat[i]; +} + + + +double* MT_CmMatrix4x4::getPointer() +{ + return &m_V[0][0]; +} + + + +const double* MT_CmMatrix4x4::getPointer() const +{ + return &m_V[0][0]; +} + + + +void MT_CmMatrix4x4::setElem(int pos,double newvalue) +{ + m_Vflat[pos] = newvalue; +} + +MT_CmMatrix4x4 MT_CmMatrix4x4::Perspective( + MT_Scalar inLeft, + MT_Scalar inRight, + MT_Scalar inBottom, + MT_Scalar inTop, + MT_Scalar inNear, + MT_Scalar inFar +){ + + MT_CmMatrix4x4 mat; + + // Column 0 + mat(0, 0) = -(2.0*inNear) / (inRight-inLeft); + mat(1, 0) = 0; + mat(2, 0) = 0; + mat(3, 0) = 0; + + // Column 1 + mat(0, 1) = 0; + mat(1, 1) = (2.0*inNear) / (inTop-inBottom); + mat(2, 1) = 0; + mat(3, 1) = 0; + + // Column 2 + mat(0, 2) = (inRight+inLeft) / (inRight-inLeft); + mat(1, 2) = (inTop+inBottom) / (inTop-inBottom); + mat(2, 2) = -(inFar+inNear) / (inFar-inNear); + mat(3, 2) = -1; + + // Column 3 + mat(0, 3) = 0; + mat(1, 3) = 0; + mat(2, 3) = -(2.0*inFar*inNear) / (inFar-inNear); + mat(3, 3) = 0; + + return mat; +} diff --git a/intern/moto/intern/MT_Matrix3x3.cpp b/intern/moto/intern/MT_Matrix3x3.cpp new file mode 100644 index 00000000000..61dcc3b2d02 --- /dev/null +++ b/intern/moto/intern/MT_Matrix3x3.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Matrix3x3.h" + + +#ifndef GEN_INLINED +#include "MT_Matrix3x3.inl" +#endif diff --git a/intern/moto/intern/MT_Matrix4x4.cpp b/intern/moto/intern/MT_Matrix4x4.cpp new file mode 100644 index 00000000000..ff0ad3caba7 --- /dev/null +++ b/intern/moto/intern/MT_Matrix4x4.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Matrix4x4.h" + + +#ifndef GEN_INLINED +#include "MT_Matrix4x4.inl" +#endif diff --git a/intern/moto/intern/MT_Plane3.cpp b/intern/moto/intern/MT_Plane3.cpp new file mode 100644 index 00000000000..054b09a48cc --- /dev/null +++ b/intern/moto/intern/MT_Plane3.cpp @@ -0,0 +1,71 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef GEN_INLINED +#include "MT_Plane3.h" +#include "MT_Plane3.inl" +#endif + diff --git a/intern/moto/intern/MT_Point3.cpp b/intern/moto/intern/MT_Point3.cpp new file mode 100644 index 00000000000..1c585ad5eb4 --- /dev/null +++ b/intern/moto/intern/MT_Point3.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Point3.h" + + +#ifndef GEN_INLINED +#include "MT_Point3.inl" +#endif diff --git a/intern/moto/intern/MT_Quaternion.cpp b/intern/moto/intern/MT_Quaternion.cpp new file mode 100644 index 00000000000..6dd08ad484f --- /dev/null +++ b/intern/moto/intern/MT_Quaternion.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Quaternion.h" + + +#ifndef GEN_INLINED +#include "MT_Quaternion.inl" +#endif diff --git a/intern/moto/intern/MT_Transform.cpp b/intern/moto/intern/MT_Transform.cpp new file mode 100644 index 00000000000..1af52abca3b --- /dev/null +++ b/intern/moto/intern/MT_Transform.cpp @@ -0,0 +1,142 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + + MOTTO - 3D Motion Toolkit + Copyright (C) 2000 Gino van den Bergen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Transform.h" + +void MT_Transform::setValue(const float *m) { + m_basis.setValue(m); + m_origin.setValue(&m[12]); + m_type = AFFINE; +} + +void MT_Transform::setValue(const double *m) { + m_basis.setValue(m); + m_origin.setValue(&m[12]); + m_type = AFFINE; +} + +void MT_Transform::getValue(float *m) const { + m_basis.getValue(m); + m_origin.getValue(&m[12]); + m[15] = 1.0; +} + +void MT_Transform::getValue(double *m) const { + m_basis.getValue(m); + m_origin.getValue(&m[12]); + m[15] = 1.0; +} + +MT_Transform& MT_Transform::operator*=(const MT_Transform& t) { + m_origin += m_basis * t.m_origin; + m_basis *= t.m_basis; + m_type |= t.m_type; + return *this; +} + +void MT_Transform::translate(const MT_Vector3& v) { + m_origin += m_basis * v; + m_type |= TRANSLATION; +} + +void MT_Transform::rotate(const MT_Quaternion& q) { + m_basis *= MT_Matrix3x3(q); + m_type |= ROTATION; +} + +void MT_Transform::scale(MT_Scalar x, MT_Scalar y, MT_Scalar z) { + m_basis.scale(x, y, z); + m_type |= SCALING; +} + +void MT_Transform::setIdentity() { + m_basis.setIdentity(); + m_origin.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0)); + m_type = IDENTITY; +} + +void MT_Transform::invert(const MT_Transform& t) { + m_basis = t.m_type & SCALING ? + t.m_basis.inverse() : + t.m_basis.transposed(); + m_origin.setValue(-MT_dot(m_basis[0], t.m_origin), + -MT_dot(m_basis[1], t.m_origin), + -MT_dot(m_basis[2], t.m_origin)); + m_type = t.m_type; +} + +void MT_Transform::mult(const MT_Transform& t1, const MT_Transform& t2) { + m_basis = t1.m_basis * t2.m_basis; + m_origin = t1(t2.m_origin); + m_type = t1.m_type | t2.m_type; +} + +void MT_Transform::multInverseLeft(const MT_Transform& t1, const MT_Transform& t2) { + MT_Vector3 v = t2.m_origin - t1.m_origin; + if (t1.m_type & SCALING) { + MT_Matrix3x3 inv = t1.m_basis.inverse(); + m_basis = inv * t2.m_basis; + m_origin = inv * v; + } + else { + m_basis = MT_multTransposeLeft(t1.m_basis, t2.m_basis); + m_origin = v * t1.m_basis; + } + m_type = t1.m_type | t2.m_type; +} + + + diff --git a/intern/moto/intern/MT_Vector2.cpp b/intern/moto/intern/MT_Vector2.cpp new file mode 100644 index 00000000000..c8ac08210e5 --- /dev/null +++ b/intern/moto/intern/MT_Vector2.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Vector2.h" + + +#ifndef GEN_INLINED +#include "MT_Vector2.inl" +#endif diff --git a/intern/moto/intern/MT_Vector3.cpp b/intern/moto/intern/MT_Vector3.cpp new file mode 100644 index 00000000000..9285f2fcb19 --- /dev/null +++ b/intern/moto/intern/MT_Vector3.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Vector3.h" + + +#ifndef GEN_INLINED +#include "MT_Vector3.inl" +#endif diff --git a/intern/moto/intern/MT_Vector4.cpp b/intern/moto/intern/MT_Vector4.cpp new file mode 100644 index 00000000000..efe7d3e7b04 --- /dev/null +++ b/intern/moto/intern/MT_Vector4.cpp @@ -0,0 +1,41 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_Vector4.h" + + +#ifndef GEN_INLINED +#include "MT_Vector4.inl" +#endif diff --git a/intern/moto/intern/MT_random.cpp b/intern/moto/intern/MT_random.cpp new file mode 100644 index 00000000000..0c46211c3e8 --- /dev/null +++ b/intern/moto/intern/MT_random.cpp @@ -0,0 +1,146 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* A C-program for MT19937: Real number version */ + +/* genrand() generates one pseudorandom real number (double) */ +/* which is uniformly distributed on [0,1]-interval, for each */ +/* call. sgenrand(seed) set initial values to the working area */ +/* of 624 words. Before genrand(), sgenrand(seed) must be */ +/* called once. (seed is any 32-bit integer except for 0). */ +/* Integer generator is obtained by modifying two lines. */ +/* Coded by Takuji Nishimura, considering the suggestions by */ +/* Topher Cooper and Marc Rieffel in July-Aug. 1997. */ + +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, or (at your option) any later */ +/* version. */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ +/* See the GNU Library General Public License for more details. */ +/* You should have received a copy of the GNU Library General */ +/* Public License along with this library; if not, write to the */ +/* Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ + +/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ +/* When you use this, send an email to: matumoto@math.keio.ac.jp */ +/* with an appropriate reference to your work. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "MT_random.h" + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0df /* constant vector a */ +#define UPPER_MASK 0x80000000 /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffff /* least significant r bits */ + +/* Tempering parameters */ +#define TEMPERING_MASK_B 0x9d2c5680 +#define TEMPERING_MASK_C 0xefc60000 +#define TEMPERING_SHIFT_U(y) (y >> 11) +#define TEMPERING_SHIFT_S(y) (y << 7) +#define TEMPERING_SHIFT_T(y) (y << 15) +#define TEMPERING_SHIFT_L(y) (y >> 18) + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti = N+1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializing the array with a NONZERO seed */ +void MT_srand(unsigned long seed) +{ + /* setting initial seeds to mt[N] using */ + /* the generator Line 25 of Table 1 in */ + /* [KNUTH 1981, The Art of Computer Programming */ + /* Vol. 2 (2nd Ed.), pp102] */ + mt[0] = seed & 0xffffffff; + for (mti = 1; mti < N; mti++) + mt[mti] = (69069 * mt[mti-1]) & 0xffffffff; +} + +unsigned long MT_rand() +{ + static unsigned long mag01[2] = { 0x0, MATRIX_A }; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + unsigned long y; + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if sgenrand() has not been called, */ + MT_srand(4357); /* a default initial seed is used */ + + for (kk = 0; kk < N - M; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1]; + } + for (; kk < N-1; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); + mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1]; + } + y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1]; + + mti = 0; + } + + y = mt[mti++]; + y ^= TEMPERING_SHIFT_U(y); + y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; + y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; + y ^= TEMPERING_SHIFT_L(y); + + return y; +} + +#undef N +#undef M +#undef MATRIX_A +#undef UPPER_MASK +#undef LOWER_MASK + +/* Tempering parameters */ +#undef TEMPERING_MASK_B +#undef TEMPERING_MASK_C +#undef TEMPERING_SHIFT_U +#undef TEMPERING_SHIFT_S +#undef TEMPERING_SHIFT_T +#undef TEMPERING_SHIFT_L + diff --git a/intern/moto/intern/Makefile b/intern/moto/intern/Makefile new file mode 100644 index 00000000000..eeba381ab2a --- /dev/null +++ b/intern/moto/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# moto intern Makefile +# + +LIBNAME = moto +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../include + diff --git a/intern/moto/make/msvc_6_0/MoTo.dsp b/intern/moto/make/msvc_6_0/MoTo.dsp new file mode 100644 index 00000000000..23224fc7fa8 --- /dev/null +++ b/intern/moto/make/msvc_6_0/MoTo.dsp @@ -0,0 +1,379 @@ +# Microsoft Developer Studio Project File - Name="MoTo" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=MoTo - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "MoTo.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "MoTo.mak" CFG="MoTo - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MoTo - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "MoTo - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\moto\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\moto\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W4 /GX /O2 /Ob2 /I "..\..\include\\" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\moto\libmoto.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\include\*.h ..\..\..\..\..\lib\windows\moto\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\moto\*.lib ..\..\..\..\..\lib\windows\moto\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\moto\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\moto\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\include\\" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\moto\debug\libmoto.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\include\*.h ..\..\..\..\..\lib\windows\moto\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\moto\debug\*.lib ..\..\..\..\..\lib\windows\moto\lib\debug\*.a ECHO Copying Debug info. XCOPY /Y ..\..\..\..\obj\windows\intern\moto\debug\vc60.* ..\..\..\..\..\lib\windows\moto\lib\debug\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "MoTo - Win32 Release" +# Name "MoTo - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\MT_CmMatrix4x4.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Matrix3x3.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Matrix4x4.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Plane3.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Point3.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Quaternion.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_random.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Transform.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Vector2.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Vector3.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\intern\MT_Vector4.cpp + +!IF "$(CFG)" == "MoTo - Win32 Release" + +# ADD CPP /W3 /I "../../include" + +!ELSEIF "$(CFG)" == "MoTo - Win32 Debug" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "inlines" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\include\MT_Matrix3x3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Matrix4x4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Plane3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Point2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Point3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Quaternion.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector4.inl +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\include\GEN_List.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\GEN_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_assert.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_CmMatrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Matrix3x3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Matrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_MinMax.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Optimize.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Plane3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Point2.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Point3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Quaternion.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_random.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Scalar.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Stream.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Tuple2.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Tuple3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Tuple4.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector2.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector3.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\MT_Vector4.h +# End Source File +# Begin Source File + +SOURCE=..\..\include\NM_Scalar.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/moto/make/msvc_6_0/MoTo.dsw b/intern/moto/make/msvc_6_0/MoTo.dsw new file mode 100644 index 00000000000..bc76539dd6c --- /dev/null +++ b/intern/moto/make/msvc_6_0/MoTo.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "MoTo"=.\MoTo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/moto/make/msvc_7_0/moto.sln b/intern/moto/make/msvc_7_0/moto.sln new file mode 100644 index 00000000000..c1c34ff4af1 --- /dev/null +++ b/intern/moto/make/msvc_7_0/moto.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MoTo", "MoTo.vcproj", "{11ABF09B-4414-4188-8071-27CE3FE49256}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {11ABF09B-4414-4188-8071-27CE3FE49256}.Debug.ActiveCfg = Debug|Win32 + {11ABF09B-4414-4188-8071-27CE3FE49256}.Debug.Build.0 = Debug|Win32 + {11ABF09B-4414-4188-8071-27CE3FE49256}.Release.ActiveCfg = Release|Win32 + {11ABF09B-4414-4188-8071-27CE3FE49256}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/moto/make/msvc_7_0/moto.vcproj b/intern/moto/make/msvc_7_0/moto.vcproj new file mode 100644 index 00000000000..6ecff4b78d0 --- /dev/null +++ b/intern/moto/make/msvc_7_0/moto.vcproj @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/opennl/CMakeLists.txt b/intern/opennl/CMakeLists.txt new file mode 100644 index 00000000000..78e2359eec5 --- /dev/null +++ b/intern/opennl/CMakeLists.txt @@ -0,0 +1,36 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC extern superlu) + +FILE(GLOB SRC intern/*.c superlu/*.c) + +BLENDERLIB(blender_ONL "${SRC}" "${INC}") +#, libtype='core', priority=55 ) + diff --git a/intern/opennl/Makefile b/intern/opennl/Makefile new file mode 100644 index 00000000000..8aa0d4f590b --- /dev/null +++ b/intern/opennl/Makefile @@ -0,0 +1,67 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# opennl main makefile. +# + +include nan_definitions.mk + +LIBNAME = opennl +LIBNAME_SLU = superlu +SOURCEDIR = intern/$(LIBNAME) +SOURCEDIR_SLU = intern/$(LIBNAME_SLU) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIR_SLU = $(OCGDIR)/$(SOURCEDIR_SLU) +DIRS = intern superlu + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_OPENNL) ] || mkdir $(NAN_OPENNL) + @[ -d $(NAN_OPENNL)/include ] || mkdir $(NAN_OPENNL)/include + @[ -d $(NAN_OPENNL)/lib ] || mkdir $(NAN_OPENNL)/lib + @[ -d $(NAN_OPENNL)/lib/debug ] || mkdir $(NAN_OPENNL)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libopennl.a $(NAN_OPENNL)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libopennl.a $(NAN_OPENNL)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_OPENNL)/lib/libopennl.a + ranlib $(NAN_OPENNL)/lib/debug/libopennl.a +endif + @../tools/cpifdiff.sh extern/*.h $(NAN_OPENNL)/include/ + @[ -d $(NAN_SUPERLU) ] || mkdir $(NAN_SUPERLU) + @[ -d $(NAN_SUPERLU)/lib ] || mkdir $(NAN_SUPERLU)/lib + @[ -d $(NAN_SUPERLU)/lib/debug ] || mkdir $(NAN_SUPERLU)/lib/debug + @../tools/cpifdiff.sh $(DIR_SLU)/libsuperlu.a $(NAN_SUPERLU)/lib/ + @../tools/cpifdiff.sh $(DIR_SLU)/debug/libsuperlu.a $(NAN_SUPERLU)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_SUPERLU)/lib/libsuperlu.a + ranlib $(NAN_SUPERLU)/lib/debug/libsuperlu.a +endif + diff --git a/intern/opennl/SConscript b/intern/opennl/SConscript new file mode 100644 index 00000000000..bcfb030f7e6 --- /dev/null +++ b/intern/opennl/SConscript @@ -0,0 +1,12 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.c') + env.Glob('superlu/*.c') + +incs = 'extern superlu' + +if (env['OURPLATFORM'] == 'win32-mingw'): + env.BlenderLib ('blender_ONL', sources, Split(incs), [], libtype=['core','intern'], priority=[1,80] ) +else: + env.BlenderLib ('blender_ONL', sources, Split(incs), [], libtype='core', priority=55 ) + diff --git a/intern/opennl/doc/OpenNL_License.txt b/intern/opennl/doc/OpenNL_License.txt new file mode 100644 index 00000000000..4e8d97fd526 --- /dev/null +++ b/intern/opennl/doc/OpenNL_License.txt @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/intern/opennl/doc/OpenNL_Readme.txt b/intern/opennl/doc/OpenNL_Readme.txt new file mode 100644 index 00000000000..e6aea3c0286 --- /dev/null +++ b/intern/opennl/doc/OpenNL_Readme.txt @@ -0,0 +1,13 @@ + +This is OpenNL, a library to easily construct and solve sparse linear systems. +* OpenNL is supplied with a set of iterative solvers (Conjugate gradient, + BICGSTAB, GMRes) and preconditioners (Jacobi, SSOR). +* OpenNL can also use other solvers (SuperLU 3.0 supported as an OpenNL + extension) + +Note that to be compatible with OpenNL, SuperLU 3.0 needs to be compiled with +the following flag (see make.inc in SuperLU3.0): +CDEFS = -DAdd_ (the default is -DAdd__, just remove the second underscore) + +OpenNL was modified for Blender to be used only as a wrapper for SuperLU. + diff --git a/intern/opennl/doc/SuperLU_License.txt b/intern/opennl/doc/SuperLU_License.txt new file mode 100644 index 00000000000..f31a01782e2 --- /dev/null +++ b/intern/opennl/doc/SuperLU_License.txt @@ -0,0 +1,31 @@ +Copyright (c) 2003, The Regents of the University of California, through +Lawrence Berkeley National Laboratory (subject to receipt of any required +approvals from U.S. Dept. of Energy) + +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. +(3) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of +Energy nor the names of its contributors may be used to endorse or promote +products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/intern/opennl/doc/SuperLU_Readme.txt b/intern/opennl/doc/SuperLU_Readme.txt new file mode 100644 index 00000000000..c1cedd09893 --- /dev/null +++ b/intern/opennl/doc/SuperLU_Readme.txt @@ -0,0 +1,52 @@ + SuperLU (Version 3.0) + ===================== + +Copyright (c) 2003, The Regents of the University of California, through +Lawrence Berkeley National Laboratory (subject to receipt of any required +approvals from U.S. Dept. of Energy) + +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. +(3) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of +Energy nor the names of its contributors may be used to endorse or promote +products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +SuperLU contains a set of subroutines to solve a sparse linear system +A*X=B. It uses Gaussian elimination with partial pivoting (GEPP). +The columns of A may be preordered before factorization; the +preordering for sparsity is completely separate from the factorization. + +SuperLU is implemented in ANSI C, and must be compiled with standard +ANSI C compilers. It provides functionality for both real and complex +matrices, in both single and double precision. The file names for the +single-precision real version start with letter "s" (such as sgstrf.c); +the file names for the double-precision real version start with letter "d" +(such as dgstrf.c); the file names for the single-precision complex +version start with letter "c" (such as cgstrf.c); the file names +for the double-precision complex version start with letter "z" +(such as zgstrf.c). + +SuperLU was modified for Blender to only include single-precision +functionality. + diff --git a/intern/opennl/extern/ONL_opennl.h b/intern/opennl/extern/ONL_opennl.h new file mode 100644 index 00000000000..be76aa95eac --- /dev/null +++ b/intern/opennl/extern/ONL_opennl.h @@ -0,0 +1,147 @@ +/* + * $Id$ + * + * OpenNL: Numerical Library + * Copyright (C) 2004 Bruno Levy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + * + * Contact: Bruno Levy + * + * levy@loria.fr + * + * ISA Project + * LORIA, INRIA Lorraine, + * Campus Scientifique, BP 239 + * 54506 VANDOEUVRE LES NANCY CEDEX + * FRANCE + * + * Note that the GNU General Public License does not permit incorporating + * the Software into proprietary programs. + */ + +/* +#define NL_DEBUG +#define NL_PARANOID +*/ + +#define NL_USE_SUPERLU + +#ifndef nlOPENNL_H +#define nlOPENNL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define NL_VERSION_0_0 1 + +/* Datatypes */ + +typedef unsigned int NLenum; +typedef unsigned char NLboolean; +typedef unsigned int NLbitfield; +typedef void NLvoid; +typedef signed char NLbyte; /* 1-byte signed */ +typedef short NLshort; /* 2-byte signed */ +typedef int NLint; /* 4-byte signed */ +typedef unsigned char NLubyte; /* 1-byte unsigned */ +typedef unsigned short NLushort; /* 2-byte unsigned */ +typedef unsigned int NLuint; /* 4-byte unsigned */ +typedef int NLsizei; /* 4-byte signed */ +typedef float NLfloat; /* single precision float */ +typedef double NLdouble; /* double precision float */ + +typedef void* NLContext; + +/* Constants */ + +#define NL_FALSE 0x0 +#define NL_TRUE 0x1 + +/* Primitives */ + +#define NL_SYSTEM 0x0 +#define NL_MATRIX 0x1 + +/* Solver Parameters */ + +#define NL_SOLVER 0x100 +#define NL_NB_VARIABLES 0x101 +#define NL_LEAST_SQUARES 0x102 +#define NL_SYMMETRIC 0x106 +#define NL_ERROR 0x108 +#define NL_NB_ROWS 0x110 +#define NL_NB_RIGHT_HAND_SIDES 0x112 /* 4 max */ + +/* Contexts */ + +NLContext nlNewContext(void); +void nlDeleteContext(NLContext context); +void nlMakeCurrent(NLContext context); +NLContext nlGetCurrent(void); + +/* State get/set */ + +void nlSolverParameterf(NLenum pname, NLfloat param); +void nlSolverParameteri(NLenum pname, NLint param); + +void nlGetBooleanv(NLenum pname, NLboolean* params); +void nlGetFloatv(NLenum pname, NLfloat* params); +void nlGetIntergerv(NLenum pname, NLint* params); + +void nlEnable(NLenum pname); +void nlDisable(NLenum pname); +NLboolean nlIsEnabled(NLenum pname); + +/* Variables */ + +void nlSetVariable(NLuint rhsindex, NLuint index, NLfloat value); +NLfloat nlGetVariable(NLuint rhsindex, NLuint index); +void nlLockVariable(NLuint index); +void nlUnlockVariable(NLuint index); +NLboolean nlVariableIsLocked(NLuint index); + +/* Begin/End */ + +void nlBegin(NLenum primitive); +void nlEnd(NLenum primitive); + +/* Setting elements in matrix/vector */ + +void nlMatrixAdd(NLuint row, NLuint col, NLfloat value); +void nlRightHandSideAdd(NLuint rhsindex, NLuint index, NLfloat value); +void nlRightHandSideSet(NLuint rhsindex, NLuint index, NLfloat value); + +/* Multiply */ + +void nlMatrixMultiply(NLfloat *x, NLfloat *y); + +/* Solve */ + +void nlPrintMatrix(void); +NLboolean nlSolve(); +NLboolean nlSolveAdvanced(NLint *permutation, NLboolean solveAgain); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/intern/opennl/intern/Makefile b/intern/opennl/intern/Makefile new file mode 100644 index 00000000000..2e57905d931 --- /dev/null +++ b/intern/opennl/intern/Makefile @@ -0,0 +1,43 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# opennl intern Makefile +# + +LIBNAME = opennl +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(NAN_LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../superlu -I../extern + + diff --git a/intern/opennl/intern/opennl.c b/intern/opennl/intern/opennl.c new file mode 100644 index 00000000000..2d30da075d3 --- /dev/null +++ b/intern/opennl/intern/opennl.c @@ -0,0 +1,1263 @@ +/* + * $Id$ + * + * OpenNL: Numerical Library + * Copyright (C) 2004 Bruno Levy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + * + * Contact: Bruno Levy + * + * levy@loria.fr + * + * ISA Project + * LORIA, INRIA Lorraine, + * Campus Scientifique, BP 239 + * 54506 VANDOEUVRE LES NANCY CEDEX + * FRANCE + * + * Note that the GNU General Public License does not permit incorporating + * the Software into proprietary programs. + */ + +#include "ONL_opennl.h" + +#include +#include +#include +#include + +#ifdef NL_PARANOID +#ifndef NL_DEBUG +#define NL_DEBUG +#endif +#endif + +/* SuperLU includes */ +#include +#include + +/************************************************************************************/ +/* Assertions */ + + +static void __nl_assertion_failed(char* cond, char* file, int line) { + fprintf( + stderr, + "OpenNL assertion failed: %s, file:%s, line:%d\n", + cond,file,line + ); + abort(); +} + +static void __nl_range_assertion_failed( + float x, float min_val, float max_val, char* file, int line +) { + fprintf( + stderr, + "OpenNL range assertion failed: %f in [ %f ... %f ], file:%s, line:%d\n", + x, min_val, max_val, file,line + ); + abort(); +} + +static void __nl_should_not_have_reached(char* file, int line) { + fprintf( + stderr, + "OpenNL should not have reached this point: file:%s, line:%d\n", + file,line + ); + abort(); +} + + +#define __nl_assert(x) { \ + if(!(x)) { \ + __nl_assertion_failed(#x,__FILE__, __LINE__); \ + } \ +} + +#define __nl_range_assert(x,min_val,max_val) { \ + if(((x) < (min_val)) || ((x) > (max_val))) { \ + __nl_range_assertion_failed(x, min_val, max_val, \ + __FILE__, __LINE__ \ + ); \ + } \ +} + +#define __nl_assert_not_reached { \ + __nl_should_not_have_reached(__FILE__, __LINE__); \ +} + +#ifdef NL_DEBUG +#define __nl_debug_assert(x) __nl_assert(x) +#define __nl_debug_range_assert(x,min_val,max_val) __nl_range_assert(x,min_val,max_val) +#else +#define __nl_debug_assert(x) +#define __nl_debug_range_assert(x,min_val,max_val) +#endif + +#ifdef NL_PARANOID +#define __nl_parano_assert(x) __nl_assert(x) +#define __nl_parano_range_assert(x,min_val,max_val) __nl_range_assert(x,min_val,max_val) +#else +#define __nl_parano_assert(x) +#define __nl_parano_range_assert(x,min_val,max_val) +#endif + +/************************************************************************************/ +/* classic macros */ + +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + +#ifndef MAX +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#endif + +/************************************************************************************/ +/* memory management */ + +#define __NL_NEW(T) (T*)(calloc(1, sizeof(T))) +#define __NL_NEW_ARRAY(T,NB) (T*)(calloc((NB),sizeof(T))) +#define __NL_RENEW_ARRAY(T,x,NB) (T*)(realloc(x,(NB)*sizeof(T))) +#define __NL_DELETE(x) free(x); x = NULL +#define __NL_DELETE_ARRAY(x) free(x); x = NULL + +#define __NL_CLEAR(T, x) memset(x, 0, sizeof(T)) +#define __NL_CLEAR_ARRAY(T,x,NB) memset(x, 0, (NB)*sizeof(T)) + +/************************************************************************************/ +/* Dynamic arrays for sparse row/columns */ + +typedef struct { + NLuint index; + NLfloat value; +} __NLCoeff; + +typedef struct { + NLuint size; + NLuint capacity; + __NLCoeff* coeff; +} __NLRowColumn; + +static void __nlRowColumnConstruct(__NLRowColumn* c) { + c->size = 0; + c->capacity = 0; + c->coeff = NULL; +} + +static void __nlRowColumnDestroy(__NLRowColumn* c) { + __NL_DELETE_ARRAY(c->coeff); +#ifdef NL_PARANOID + __NL_CLEAR(__NLRowColumn, c); +#endif +} + +static void __nlRowColumnGrow(__NLRowColumn* c) { + if(c->capacity != 0) { + c->capacity = 2 * c->capacity; + c->coeff = __NL_RENEW_ARRAY(__NLCoeff, c->coeff, c->capacity); + } else { + c->capacity = 4; + c->coeff = __NL_NEW_ARRAY(__NLCoeff, c->capacity); + } +} + +static void __nlRowColumnAdd(__NLRowColumn* c, NLint index, NLfloat value) { + NLuint i; + for(i=0; isize; i++) { + if(c->coeff[i].index == (NLuint)index) { + c->coeff[i].value += value; + return; + } + } + if(c->size == c->capacity) { + __nlRowColumnGrow(c); + } + c->coeff[c->size].index = index; + c->coeff[c->size].value = value; + c->size++; +} + +/* Does not check whether the index already exists */ +static void __nlRowColumnAppend(__NLRowColumn* c, NLint index, NLfloat value) { + if(c->size == c->capacity) { + __nlRowColumnGrow(c); + } + c->coeff[c->size].index = index; + c->coeff[c->size].value = value; + c->size++; +} + +static void __nlRowColumnClear(__NLRowColumn* c) { + c->size = 0; + c->capacity = 0; + __NL_DELETE_ARRAY(c->coeff); +} + +/************************************************************************************/ +/* SparseMatrix data structure */ + +#define __NL_ROWS 1 +#define __NL_COLUMNS 2 +#define __NL_SYMMETRIC 4 + +typedef struct { + NLuint m; + NLuint n; + NLuint diag_size; + NLenum storage; + __NLRowColumn* row; + __NLRowColumn* column; + NLfloat* diag; +} __NLSparseMatrix; + + +static void __nlSparseMatrixConstruct( + __NLSparseMatrix* M, NLuint m, NLuint n, NLenum storage +) { + NLuint i; + M->m = m; + M->n = n; + M->storage = storage; + if(storage & __NL_ROWS) { + M->row = __NL_NEW_ARRAY(__NLRowColumn, m); + for(i=0; irow[i])); + } + } else { + M->row = NULL; + } + + if(storage & __NL_COLUMNS) { + M->column = __NL_NEW_ARRAY(__NLRowColumn, n); + for(i=0; icolumn[i])); + } + } else { + M->column = NULL; + } + + M->diag_size = MIN(m,n); + M->diag = __NL_NEW_ARRAY(NLfloat, M->diag_size); +} + +static void __nlSparseMatrixDestroy(__NLSparseMatrix* M) { + NLuint i; + __NL_DELETE_ARRAY(M->diag); + if(M->storage & __NL_ROWS) { + for(i=0; im; i++) { + __nlRowColumnDestroy(&(M->row[i])); + } + __NL_DELETE_ARRAY(M->row); + } + if(M->storage & __NL_COLUMNS) { + for(i=0; in; i++) { + __nlRowColumnDestroy(&(M->column[i])); + } + __NL_DELETE_ARRAY(M->column); + } +#ifdef NL_PARANOID + __NL_CLEAR(__NLSparseMatrix,M); +#endif +} + +static void __nlSparseMatrixAdd( + __NLSparseMatrix* M, NLuint i, NLuint j, NLfloat value +) { + __nl_parano_range_assert(i, 0, M->m - 1); + __nl_parano_range_assert(j, 0, M->n - 1); + if((M->storage & __NL_SYMMETRIC) && (j > i)) { + return; + } + if(i == j) { + M->diag[i] += value; + } + if(M->storage & __NL_ROWS) { + __nlRowColumnAdd(&(M->row[i]), j, value); + } + if(M->storage & __NL_COLUMNS) { + __nlRowColumnAdd(&(M->column[j]), i, value); + } +} + +static void __nlSparseMatrixClear( __NLSparseMatrix* M) { + NLuint i; + if(M->storage & __NL_ROWS) { + for(i=0; im; i++) { + __nlRowColumnClear(&(M->row[i])); + } + } + if(M->storage & __NL_COLUMNS) { + for(i=0; in; i++) { + __nlRowColumnClear(&(M->column[i])); + } + } + __NL_CLEAR_ARRAY(NLfloat, M->diag, M->diag_size); +} + +/* Returns the number of non-zero coefficients */ +static NLuint __nlSparseMatrixNNZ( __NLSparseMatrix* M) { + NLuint nnz = 0; + NLuint i; + if(M->storage & __NL_ROWS) { + for(i = 0; im; i++) { + nnz += M->row[i].size; + } + } else if (M->storage & __NL_COLUMNS) { + for(i = 0; in; i++) { + nnz += M->column[i].size; + } + } else { + __nl_assert_not_reached; + } + return nnz; +} + +/************************************************************************************/ +/* SparseMatrix x Vector routines, internal helper routines */ + +static void __nlSparseMatrix_mult_rows_symmetric( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint m = A->m; + NLuint i,ij; + __NLRowColumn* Ri = NULL; + __NLCoeff* c = NULL; + for(i=0; irow[i]); + for(ij=0; ijsize; ij++) { + c = &(Ri->coeff[ij]); + y[i] += c->value * x[c->index]; + if(i != c->index) { + y[c->index] += c->value * x[i]; + } + } + } +} + +static void __nlSparseMatrix_mult_rows( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint m = A->m; + NLuint i,ij; + __NLRowColumn* Ri = NULL; + __NLCoeff* c = NULL; + for(i=0; irow[i]); + for(ij=0; ijsize; ij++) { + c = &(Ri->coeff[ij]); + y[i] += c->value * x[c->index]; + } + } +} + +static void __nlSparseMatrix_mult_cols_symmetric( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint n = A->n; + NLuint j,ii; + __NLRowColumn* Cj = NULL; + __NLCoeff* c = NULL; + for(j=0; jcolumn[j]); + for(ii=0; iisize; ii++) { + c = &(Cj->coeff[ii]); + y[c->index] += c->value * x[j]; + if(j != c->index) { + y[j] += c->value * x[c->index]; + } + } + } +} + +static void __nlSparseMatrix_mult_cols( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint n = A->n; + NLuint j,ii; + __NLRowColumn* Cj = NULL; + __NLCoeff* c = NULL; + __NL_CLEAR_ARRAY(NLfloat, y, A->m); + for(j=0; jcolumn[j]); + for(ii=0; iisize; ii++) { + c = &(Cj->coeff[ii]); + y[c->index] += c->value * x[j]; + } + } +} + +/************************************************************************************/ +/* SparseMatrix x Vector routines, main driver routine */ + +static void __nlSparseMatrixMult(__NLSparseMatrix* A, NLfloat* x, NLfloat* y) { + if(A->storage & __NL_ROWS) { + if(A->storage & __NL_SYMMETRIC) { + __nlSparseMatrix_mult_rows_symmetric(A, x, y); + } else { + __nlSparseMatrix_mult_rows(A, x, y); + } + } else { + if(A->storage & __NL_SYMMETRIC) { + __nlSparseMatrix_mult_cols_symmetric(A, x, y); + } else { + __nlSparseMatrix_mult_cols(A, x, y); + } + } +} + +/* ****************** Routines for least squares ******************* */ + +static void __nlSparseMatrix_square( + __NLSparseMatrix* AtA, __NLSparseMatrix *A +) { + NLuint m = A->m; + NLuint n = A->n; + NLuint i, j0, j1; + __NLRowColumn *Ri = NULL; + __NLCoeff *c0 = NULL, *c1 = NULL; + float value; + + __nlSparseMatrixConstruct(AtA, n, n, A->storage); + + for(i=0; irow[i]); + + for(j0=0; j0size; j0++) { + c0 = &(Ri->coeff[j0]); + for(j1=0; j1size; j1++) { + c1 = &(Ri->coeff[j1]); + + value = c0->value*c1->value; + __nlSparseMatrixAdd(AtA, c0->index, c1->index, value); + } + } + } +} + +static void __nlSparseMatrix_transpose_mult_rows( + __NLSparseMatrix* A, NLfloat* x, NLfloat* y +) { + NLuint m = A->m; + NLuint n = A->n; + NLuint i,ij; + __NLRowColumn* Ri = NULL; + __NLCoeff* c = NULL; + + __NL_CLEAR_ARRAY(NLfloat, y, n); + + for(i=0; irow[i]); + for(ij=0; ijsize; ij++) { + c = &(Ri->coeff[ij]); + y[c->index] += c->value * x[i]; + } + } +} + +/************************************************************************************/ +/* NLContext data structure */ + +typedef void(*__NLMatrixFunc)(float* x, float* y); + +typedef struct { + NLfloat value[4]; + NLboolean locked; + NLuint index; + __NLRowColumn *a; +} __NLVariable; + +#define __NL_STATE_INITIAL 0 +#define __NL_STATE_SYSTEM 1 +#define __NL_STATE_MATRIX 2 +#define __NL_STATE_MATRIX_CONSTRUCTED 3 +#define __NL_STATE_SYSTEM_CONSTRUCTED 4 +#define __NL_STATE_SYSTEM_SOLVED 5 + +typedef struct { + NLenum state; + NLuint n; + NLuint m; + __NLVariable* variable; + NLfloat* b; + NLfloat* Mtb; + __NLSparseMatrix M; + __NLSparseMatrix MtM; + NLfloat* x; + NLuint nb_variables; + NLuint nb_rows; + NLboolean least_squares; + NLboolean symmetric; + NLuint nb_rhs; + NLboolean solve_again; + NLboolean alloc_M; + NLboolean alloc_MtM; + NLboolean alloc_variable; + NLboolean alloc_x; + NLboolean alloc_b; + NLboolean alloc_Mtb; + NLfloat error; + __NLMatrixFunc matrix_vector_prod; + + struct __NLSuperLUContext { + NLboolean alloc_slu; + SuperMatrix L, U; + NLint *perm_c, *perm_r; + SuperLUStat_t stat; + } slu; +} __NLContext; + +static __NLContext* __nlCurrentContext = NULL; + +static void __nlMatrixVectorProd_default(NLfloat* x, NLfloat* y) { + __nlSparseMatrixMult(&(__nlCurrentContext->M), x, y); +} + + +NLContext nlNewContext(void) { + __NLContext* result = __NL_NEW(__NLContext); + result->state = __NL_STATE_INITIAL; + result->matrix_vector_prod = __nlMatrixVectorProd_default; + result->nb_rhs = 1; + nlMakeCurrent(result); + return result; +} + +static void __nlFree_SUPERLU(__NLContext *context); + +void nlDeleteContext(NLContext context_in) { + __NLContext* context = (__NLContext*)(context_in); + int i; + + if(__nlCurrentContext == context) { + __nlCurrentContext = NULL; + } + if(context->alloc_M) { + __nlSparseMatrixDestroy(&context->M); + } + if(context->alloc_MtM) { + __nlSparseMatrixDestroy(&context->MtM); + } + if(context->alloc_variable) { + for(i=0; inb_variables; i++) { + if(context->variable[i].a) { + __nlRowColumnDestroy(context->variable[i].a); + __NL_DELETE(context->variable[i].a); + } + } + } + if(context->alloc_b) { + __NL_DELETE_ARRAY(context->b); + } + if(context->alloc_Mtb) { + __NL_DELETE_ARRAY(context->Mtb); + } + if(context->alloc_x) { + __NL_DELETE_ARRAY(context->x); + } + if (context->slu.alloc_slu) { + __nlFree_SUPERLU(context); + } + +#ifdef NL_PARANOID + __NL_CLEAR(__NLContext, context); +#endif + __NL_DELETE(context); +} + +void nlMakeCurrent(NLContext context) { + __nlCurrentContext = (__NLContext*)(context); +} + +NLContext nlGetCurrent(void) { + return __nlCurrentContext; +} + +static void __nlCheckState(NLenum state) { + __nl_assert(__nlCurrentContext->state == state); +} + +static void __nlTransition(NLenum from_state, NLenum to_state) { + __nlCheckState(from_state); + __nlCurrentContext->state = to_state; +} + +/************************************************************************************/ +/* Get/Set parameters */ + +void nlSolverParameterf(NLenum pname, NLfloat param) { + __nlCheckState(__NL_STATE_INITIAL); + switch(pname) { + case NL_NB_VARIABLES: { + __nl_assert(param > 0); + __nlCurrentContext->nb_variables = (NLuint)param; + } break; + case NL_NB_ROWS: { + __nl_assert(param > 0); + __nlCurrentContext->nb_rows = (NLuint)param; + } break; + case NL_LEAST_SQUARES: { + __nlCurrentContext->least_squares = (NLboolean)param; + } break; + case NL_SYMMETRIC: { + __nlCurrentContext->symmetric = (NLboolean)param; + } break; + case NL_NB_RIGHT_HAND_SIDES: { + __nlCurrentContext->nb_rhs = (NLuint)param; + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +void nlSolverParameteri(NLenum pname, NLint param) { + __nlCheckState(__NL_STATE_INITIAL); + switch(pname) { + case NL_NB_VARIABLES: { + __nl_assert(param > 0); + __nlCurrentContext->nb_variables = (NLuint)param; + } break; + case NL_NB_ROWS: { + __nl_assert(param > 0); + __nlCurrentContext->nb_rows = (NLuint)param; + } break; + case NL_LEAST_SQUARES: { + __nlCurrentContext->least_squares = (NLboolean)param; + } break; + case NL_SYMMETRIC: { + __nlCurrentContext->symmetric = (NLboolean)param; + } break; + case NL_NB_RIGHT_HAND_SIDES: { + __nlCurrentContext->nb_rhs = (NLuint)param; + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +void nlGetBooleanv(NLenum pname, NLboolean* params) { + switch(pname) { + case NL_LEAST_SQUARES: { + *params = __nlCurrentContext->least_squares; + } break; + case NL_SYMMETRIC: { + *params = __nlCurrentContext->symmetric; + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +void nlGetFloatv(NLenum pname, NLfloat* params) { + switch(pname) { + case NL_NB_VARIABLES: { + *params = (NLfloat)(__nlCurrentContext->nb_variables); + } break; + case NL_NB_ROWS: { + *params = (NLfloat)(__nlCurrentContext->nb_rows); + } break; + case NL_LEAST_SQUARES: { + *params = (NLfloat)(__nlCurrentContext->least_squares); + } break; + case NL_SYMMETRIC: { + *params = (NLfloat)(__nlCurrentContext->symmetric); + } break; + case NL_ERROR: { + *params = (NLfloat)(__nlCurrentContext->error); + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +void nlGetIntergerv(NLenum pname, NLint* params) { + switch(pname) { + case NL_NB_VARIABLES: { + *params = (NLint)(__nlCurrentContext->nb_variables); + } break; + case NL_NB_ROWS: { + *params = (NLint)(__nlCurrentContext->nb_rows); + } break; + case NL_LEAST_SQUARES: { + *params = (NLint)(__nlCurrentContext->least_squares); + } break; + case NL_SYMMETRIC: { + *params = (NLint)(__nlCurrentContext->symmetric); + } break; + default: { + __nl_assert_not_reached; + } break; + } +} + +/************************************************************************************/ +/* Enable / Disable */ + +void nlEnable(NLenum pname) { + switch(pname) { + default: { + __nl_assert_not_reached; + } + } +} + +void nlDisable(NLenum pname) { + switch(pname) { + default: { + __nl_assert_not_reached; + } + } +} + +NLboolean nlIsEnabled(NLenum pname) { + switch(pname) { + default: { + __nl_assert_not_reached; + } + } + return NL_FALSE; +} + +/************************************************************************************/ +/* Get/Set Lock/Unlock variables */ + +void nlSetVariable(NLuint rhsindex, NLuint index, NLfloat value) { + __nlCheckState(__NL_STATE_SYSTEM); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + __nlCurrentContext->variable[index].value[rhsindex] = value; +} + +NLfloat nlGetVariable(NLuint rhsindex, NLuint index) { + __nl_assert(__nlCurrentContext->state != __NL_STATE_INITIAL); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + return __nlCurrentContext->variable[index].value[rhsindex]; +} + +void nlLockVariable(NLuint index) { + __nlCheckState(__NL_STATE_SYSTEM); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + __nlCurrentContext->variable[index].locked = NL_TRUE; +} + +void nlUnlockVariable(NLuint index) { + __nlCheckState(__NL_STATE_SYSTEM); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + __nlCurrentContext->variable[index].locked = NL_FALSE; +} + +NLboolean nlVariableIsLocked(NLuint index) { + __nl_assert(__nlCurrentContext->state != __NL_STATE_INITIAL); + __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1); + return __nlCurrentContext->variable[index].locked; +} + +/************************************************************************************/ +/* System construction */ + +static void __nlVariablesToVector() { + __NLContext *context = __nlCurrentContext; + NLuint i, j, nb_rhs; + + __nl_assert(context->alloc_x); + __nl_assert(context->alloc_variable); + + nb_rhs= context->nb_rhs; + + for(i=0; inb_variables; i++) { + __NLVariable* v = &(context->variable[i]); + if(!v->locked) { + __nl_assert(v->index < context->n); + + for(j=0; jx[context->n*j + v->index] = v->value[j]; + } + } +} + +static void __nlVectorToVariables() { + __NLContext *context = __nlCurrentContext; + NLuint i, j, nb_rhs; + + __nl_assert(context->alloc_x); + __nl_assert(context->alloc_variable); + + nb_rhs= context->nb_rhs; + + for(i=0; inb_variables; i++) { + __NLVariable* v = &(context->variable[i]); + if(!v->locked) { + __nl_assert(v->index < context->n); + + for(j=0; jvalue[j] = context->x[context->n*j + v->index]; + } + } +} + +static void __nlBeginSystem() { + __nl_assert(__nlCurrentContext->nb_variables > 0); + + if (__nlCurrentContext->solve_again) + __nlTransition(__NL_STATE_SYSTEM_SOLVED, __NL_STATE_SYSTEM); + else { + __nlTransition(__NL_STATE_INITIAL, __NL_STATE_SYSTEM); + + __nlCurrentContext->variable = __NL_NEW_ARRAY( + __NLVariable, __nlCurrentContext->nb_variables); + + __nlCurrentContext->alloc_variable = NL_TRUE; + } +} + +static void __nlEndSystem() { + __nlTransition(__NL_STATE_MATRIX_CONSTRUCTED, __NL_STATE_SYSTEM_CONSTRUCTED); +} + +static void __nlBeginMatrix() { + NLuint i; + NLuint m = 0, n = 0; + NLenum storage = __NL_ROWS; + __NLContext *context = __nlCurrentContext; + + __nlTransition(__NL_STATE_SYSTEM, __NL_STATE_MATRIX); + + if (!context->solve_again) { + for(i=0; inb_variables; i++) { + if(context->variable[i].locked) { + context->variable[i].index = ~0; + context->variable[i].a = __NL_NEW(__NLRowColumn); + __nlRowColumnConstruct(context->variable[i].a); + } + else + context->variable[i].index = n++; + } + + m = (context->nb_rows == 0)? n: context->nb_rows; + + context->m = m; + context->n = n; + + __nlSparseMatrixConstruct(&context->M, m, n, storage); + context->alloc_M = NL_TRUE; + + context->b = __NL_NEW_ARRAY(NLfloat, m*context->nb_rhs); + context->alloc_b = NL_TRUE; + + context->x = __NL_NEW_ARRAY(NLfloat, n*context->nb_rhs); + context->alloc_x = NL_TRUE; + } + else { + /* need to recompute b only, A is not constructed anymore */ + __NL_CLEAR_ARRAY(NLfloat, context->b, context->m*context->nb_rhs); + } + + __nlVariablesToVector(); +} + +static void __nlEndMatrixRHS(NLuint rhs) { + __NLContext *context = __nlCurrentContext; + __NLVariable *variable; + __NLRowColumn *a; + NLfloat *b, *Mtb; + NLuint i, j; + + b = context->b + context->m*rhs; + Mtb = context->Mtb + context->n*rhs; + + for(i=0; i<__nlCurrentContext->nb_variables; i++) { + variable = &(context->variable[i]); + + if(variable->locked) { + a = variable->a; + + for(j=0; jsize; j++) { + b[a->coeff[j].index] -= a->coeff[j].value*variable->value[rhs]; + } + } + } + + if(context->least_squares) + __nlSparseMatrix_transpose_mult_rows(&context->M, b, Mtb); +} + +static void __nlEndMatrix() { + __NLContext *context = __nlCurrentContext; + NLuint i; + + __nlTransition(__NL_STATE_MATRIX, __NL_STATE_MATRIX_CONSTRUCTED); + + if(context->least_squares) { + if(!__nlCurrentContext->solve_again) { + __nlSparseMatrix_square(&context->MtM, &context->M); + context->alloc_MtM = NL_TRUE; + + context->Mtb = + __NL_NEW_ARRAY(NLfloat, context->n*context->nb_rhs); + context->alloc_Mtb = NL_TRUE; + } + } + + for(i=0; inb_rhs; i++) + __nlEndMatrixRHS(i); +} + +void nlMatrixAdd(NLuint row, NLuint col, NLfloat value) +{ + __NLContext *context = __nlCurrentContext; + + __nlCheckState(__NL_STATE_MATRIX); + + if(context->solve_again) + return; + + if (!context->least_squares && context->variable[row].locked); + else if (context->variable[col].locked) { + if(!context->least_squares) + row = context->variable[row].index; + __nlRowColumnAppend(context->variable[col].a, row, value); + } + else { + __NLSparseMatrix* M = &context->M; + + if(!context->least_squares) + row = context->variable[row].index; + col = context->variable[col].index; + + __nl_range_assert(row, 0, context->m - 1); + __nl_range_assert(col, 0, context->n - 1); + + __nlSparseMatrixAdd(M, row, col, value); + } +} + +void nlRightHandSideAdd(NLuint rhsindex, NLuint index, NLfloat value) +{ + __NLContext *context = __nlCurrentContext; + NLfloat* b = context->b; + + __nlCheckState(__NL_STATE_MATRIX); + + if(context->least_squares) { + __nl_range_assert(index, 0, context->m - 1); + b[rhsindex*context->m + index] += value; + } + else { + if(!context->variable[index].locked) { + index = context->variable[index].index; + __nl_range_assert(index, 0, context->m - 1); + + b[rhsindex*context->m + index] += value; + } + } +} + +void nlRightHandSideSet(NLuint rhsindex, NLuint index, NLfloat value) +{ + __NLContext *context = __nlCurrentContext; + NLfloat* b = context->b; + + __nlCheckState(__NL_STATE_MATRIX); + + if(context->least_squares) { + __nl_range_assert(index, 0, context->m - 1); + b[rhsindex*context->m + index] = value; + } + else { + if(!context->variable[index].locked) { + index = context->variable[index].index; + __nl_range_assert(index, 0, context->m - 1); + + b[rhsindex*context->m + index] = value; + } + } +} + +void nlBegin(NLenum prim) { + switch(prim) { + case NL_SYSTEM: { + __nlBeginSystem(); + } break; + case NL_MATRIX: { + __nlBeginMatrix(); + } break; + default: { + __nl_assert_not_reached; + } + } +} + +void nlEnd(NLenum prim) { + switch(prim) { + case NL_SYSTEM: { + __nlEndSystem(); + } break; + case NL_MATRIX: { + __nlEndMatrix(); + } break; + default: { + __nl_assert_not_reached; + } + } +} + +/************************************************************************/ +/* SuperLU wrapper */ + +/* Note: SuperLU is difficult to call, but it is worth it. */ +/* Here is a driver inspired by A. Sheffer's "cow flattener". */ +static NLboolean __nlFactorize_SUPERLU(__NLContext *context, NLint *permutation) { + + /* OpenNL Context */ + __NLSparseMatrix* M = (context->least_squares)? &context->MtM: &context->M; + NLuint n = context->n; + NLuint nnz = __nlSparseMatrixNNZ(M); /* number of non-zero coeffs */ + + /* Compressed Row Storage matrix representation */ + NLint *xa = __NL_NEW_ARRAY(NLint, n+1); + NLfloat *rhs = __NL_NEW_ARRAY(NLfloat, n); + NLfloat *a = __NL_NEW_ARRAY(NLfloat, nnz); + NLint *asub = __NL_NEW_ARRAY(NLint, nnz); + NLint *etree = __NL_NEW_ARRAY(NLint, n); + + /* SuperLU variables */ + SuperMatrix At, AtP; + NLint info, panel_size, relax; + superlu_options_t options; + + /* Temporary variables */ + NLuint i, jj, count; + + __nl_assert(!(M->storage & __NL_SYMMETRIC)); + __nl_assert(M->storage & __NL_ROWS); + __nl_assert(M->m == M->n); + + /* Convert M to compressed column format */ + for(i=0, count=0; irow + i; + xa[i] = count; + + for(jj=0; jjsize; jj++, count++) { + a[count] = Ri->coeff[jj].value; + asub[count] = Ri->coeff[jj].index; + } + } + xa[n] = nnz; + + /* Free M, don't need it anymore at this point */ + __nlSparseMatrixClear(M); + + /* Create superlu A matrix transposed */ + sCreate_CompCol_Matrix( + &At, n, n, nnz, a, asub, xa, + SLU_NC, /* Colum wise, no supernode */ + SLU_S, /* floats */ + SLU_GE /* general storage */ + ); + + /* Set superlu options */ + set_default_options(&options); + options.ColPerm = MY_PERMC; + options.Fact = DOFACT; + + StatInit(&(context->slu.stat)); + + panel_size = sp_ienv(1); /* sp_ienv give us the defaults */ + relax = sp_ienv(2); + + /* Compute permutation and permuted matrix */ + context->slu.perm_r = __NL_NEW_ARRAY(NLint, n); + context->slu.perm_c = __NL_NEW_ARRAY(NLint, n); + + if ((permutation == NULL) || (*permutation == -1)) { + get_perm_c(3, &At, context->slu.perm_c); + + if (permutation) + memcpy(permutation, context->slu.perm_c, sizeof(NLint)*n); + } + else + memcpy(context->slu.perm_c, permutation, sizeof(NLint)*n); + + sp_preorder(&options, &At, context->slu.perm_c, etree, &AtP); + + /* Decompose into L and U */ + sgstrf(&options, &AtP, relax, panel_size, + etree, NULL, 0, context->slu.perm_c, context->slu.perm_r, + &(context->slu.L), &(context->slu.U), &(context->slu.stat), &info); + + /* Cleanup */ + + Destroy_SuperMatrix_Store(&At); + Destroy_CompCol_Permuted(&AtP); + + __NL_DELETE_ARRAY(etree); + __NL_DELETE_ARRAY(xa); + __NL_DELETE_ARRAY(rhs); + __NL_DELETE_ARRAY(a); + __NL_DELETE_ARRAY(asub); + + context->slu.alloc_slu = NL_TRUE; + + return (info == 0); +} + +static NLboolean __nlInvert_SUPERLU(__NLContext *context) { + + /* OpenNL Context */ + NLfloat* b = (context->least_squares)? context->Mtb: context->b; + NLfloat* x = context->x; + NLuint n = context->n, j; + + /* SuperLU variables */ + SuperMatrix B; + NLint info; + + for(j=0; jnb_rhs; j++, b+=n, x+=n) { + /* Create superlu array for B */ + sCreate_Dense_Matrix( + &B, n, 1, b, n, + SLU_DN, /* Fortran-type column-wise storage */ + SLU_S, /* floats */ + SLU_GE /* general */ + ); + + /* Forward/Back substitution to compute x */ + sgstrs(TRANS, &(context->slu.L), &(context->slu.U), + context->slu.perm_c, context->slu.perm_r, &B, + &(context->slu.stat), &info); + + if(info == 0) + memcpy(x, ((DNformat*)B.Store)->nzval, sizeof(*x)*n); + + Destroy_SuperMatrix_Store(&B); + } + + return (info == 0); +} + +static void __nlFree_SUPERLU(__NLContext *context) { + + Destroy_SuperNode_Matrix(&(context->slu.L)); + Destroy_CompCol_Matrix(&(context->slu.U)); + + StatFree(&(context->slu.stat)); + + __NL_DELETE_ARRAY(context->slu.perm_r); + __NL_DELETE_ARRAY(context->slu.perm_c); + + context->slu.alloc_slu = NL_FALSE; +} + +void nlPrintMatrix(void) { + __NLContext *context = __nlCurrentContext; + __NLSparseMatrix* M = &(context->M); + __NLSparseMatrix* MtM = &(context->MtM); + float *b = context->b; + NLuint i, jj, k; + NLuint m = context->m; + NLuint n = context->n; + __NLRowColumn* Ri = NULL; + float *value = malloc(sizeof(*value)*(n+m)); + + printf("A:\n"); + for(i=0; irow[i]); + + memset(value, 0.0, sizeof(*value)*n); + for(jj=0; jjsize; jj++) + value[Ri->coeff[jj].index] = Ri->coeff[jj].value; + + for (k = 0; knb_rhs; k++) { + printf("b (%d):\n", k); + for(i=0; in*k + i]); + printf("\n"); + } + + if(context->alloc_MtM) { + printf("AtA:\n"); + for(i=0; irow[i]); + + memset(value, 0.0, sizeof(*value)*m); + for(jj=0; jjsize; jj++) + value[Ri->coeff[jj].index] = Ri->coeff[jj].value; + + for (k = 0; knb_rhs; k++) { + printf("Mtb (%d):\n", k); + for(i=0; iMtb[context->n*k + i]); + printf("\n"); + } + printf("\n"); + } + + free(value); +} + +/************************************************************************/ +/* nlSolve() driver routine */ + +NLboolean nlSolveAdvanced(NLint *permutation, NLboolean solveAgain) { + NLboolean result = NL_TRUE; + + __nlCheckState(__NL_STATE_SYSTEM_CONSTRUCTED); + + if (!__nlCurrentContext->solve_again) + result = __nlFactorize_SUPERLU(__nlCurrentContext, permutation); + + if (result) { + result = __nlInvert_SUPERLU(__nlCurrentContext); + + if (result) { + __nlVectorToVariables(); + + if (solveAgain) + __nlCurrentContext->solve_again = NL_TRUE; + + __nlTransition(__NL_STATE_SYSTEM_CONSTRUCTED, __NL_STATE_SYSTEM_SOLVED); + } + } + + return result; +} + +NLboolean nlSolve() { + return nlSolveAdvanced(NULL, NL_FALSE); +} + diff --git a/intern/opennl/make/msvc_6_0/OpenNL.dsp b/intern/opennl/make/msvc_6_0/OpenNL.dsp new file mode 100644 index 00000000000..bce93059e50 --- /dev/null +++ b/intern/opennl/make/msvc_6_0/OpenNL.dsp @@ -0,0 +1,252 @@ +# Microsoft Developer Studio Project File - Name="OpenNL" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=OpenNL - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "OpenNL.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "OpenNL.mak" CFG="OpenNL - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OpenNL - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "OpenNL - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "OpenNL - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../../../../obj/windows/intern/opennl" +# PROP Intermediate_Dir "../../../../obj/windows/intern/opennl/imf" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../extern" /I "../../superlu" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../../../obj/windows/intern/opennl\blender_ONL.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\opennl\include\*.h ECHO copy library XCOPY /Y ..\..\..\..\obj\windows\intern\openNL\*.lib ..\..\..\..\..\lib\windows\openNL\*.lib +# End Special Build Tool + +!ELSEIF "$(CFG)" == "OpenNL - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../../../../obj/windows/intern/opennl/Debug/" +# PROP Intermediate_Dir "../../../../obj/windows/intern/opennl/imf/Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../extern" /I "../../superlu" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../../../obj/windows/intern/opennl/Debug/blender_ONL.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO copy header files XCOPY /Y ..\..\extern\*.h ..\..\..\..\..\lib\windows\opennl\include\*.h ECHO copy library XCOPY /Y ..\..\..\..\obj\windows\intern\openNL\debug\*.lib ..\..\..\..\..\lib\windows\openNL\debug\*.lib +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "OpenNL - Win32 Release" +# Name "OpenNL - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\superlu\colamd.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\get_perm_c.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\heap_relax_snode.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\lsame.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\memory.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\mmd.c +# End Source File +# Begin Source File + +SOURCE=..\..\intern\opennl.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\relax_snode.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\scolumn_bmod.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\scolumn_dfs.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\scopy_to_ucol.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sgssv.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sgstrf.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sgstrs.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\smemory.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\smyblas2.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sp_coletree.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sp_ienv.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sp_preorder.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\spanel_bmod.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\spanel_dfs.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\spivotL.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\spruneL.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssnode_bmod.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssnode_dfs.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssp_blas2.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssp_blas3.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\strsv.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\superlu_timer.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\sutil.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\util.c +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\xerbla.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\superlu\Cnames.h +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\colamd.h +# End Source File +# Begin Source File + +SOURCE=..\..\extern\ONL_opennl.h +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\ssp_defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\supermatrix.h +# End Source File +# Begin Source File + +SOURCE=..\..\superlu\util.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/opennl/make/msvc_6_0/OpenNL.dsw b/intern/opennl/make/msvc_6_0/OpenNL.dsw new file mode 100644 index 00000000000..407aeb006fd --- /dev/null +++ b/intern/opennl/make/msvc_6_0/OpenNL.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "OpenNL"=.\OpenNL.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/opennl/make/msvc_7_0/opennl.vcproj b/intern/opennl/make/msvc_7_0/opennl.vcproj new file mode 100644 index 00000000000..ec999b0c252 --- /dev/null +++ b/intern/opennl/make/msvc_7_0/opennl.vcproj @@ -0,0 +1,742 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/opennl/superlu/Cnames.h b/intern/opennl/superlu/Cnames.h new file mode 100644 index 00000000000..35ff7b0b665 --- /dev/null +++ b/intern/opennl/superlu/Cnames.h @@ -0,0 +1,281 @@ +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 1, 1997 + * + */ +#ifndef __SUPERLU_CNAMES /* allow multiple inclusions */ +#define __SUPERLU_CNAMES + +/* We want this flag, safer than putting in build system */ +#define Add_ + +/* + * These macros define how C routines will be called. ADD_ assumes that + * they will be called by fortran, which expects C routines to have an + * underscore postfixed to the name (Suns, and the Intel expect this). + * NOCHANGE indicates that fortran will be calling, and that it expects + * the name called by fortran to be identical to that compiled by the C + * (RS6K's do this). UPCASE says it expects C routines called by fortran + * to be in all upcase (CRAY wants this). + */ + +#define ADD_ 0 +#define ADD__ 1 +#define NOCHANGE 2 +#define UPCASE 3 +#define C_CALL 4 + +#ifdef UpCase +#define F77_CALL_C UPCASE +#endif + +#ifdef NoChange +#define F77_CALL_C NOCHANGE +#endif + +#ifdef Add_ +#define F77_CALL_C ADD_ +#endif + +#ifdef Add__ +#define F77_CALL_C ADD__ +#endif + +/* Default */ +#ifndef F77_CALL_C +#define F77_CALL_C ADD_ +#endif + + +#if (F77_CALL_C == ADD_) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * No redefinition necessary to have following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm_(...) + * + * This is the default. + */ + +#endif + +#if (F77_CALL_C == ADD__) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * for following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm__(...) + */ +#define sasum_ sasum__ +#define isamax_ isamax__ +#define scopy_ scopy__ +#define sscal_ sscal__ +#define sger_ sger__ +#define snrm2_ snrm2__ +#define ssymv_ ssymv__ +#define sdot_ sdot__ +#define saxpy_ saxpy__ +#define ssyr2_ ssyr2__ +#define srot_ srot__ +#define sgemv_ sgemv__ +#define strsv_ strsv__ +#define sgemm_ sgemm__ +#define strsm_ strsm__ + +#define dasum_ dasum__ +#define idamax_ idamax__ +#define dcopy_ dcopy__ +#define dscal_ dscal__ +#define dger_ dger__ +#define dnrm2_ dnrm2__ +#define dsymv_ dsymv__ +#define ddot_ ddot__ +#define daxpy_ daxpy__ +#define dsyr2_ dsyr2__ +#define drot_ drot__ +#define dgemv_ dgemv__ +#define dtrsv_ dtrsv__ +#define dgemm_ dgemm__ +#define dtrsm_ dtrsm__ + +#define scasum_ scasum__ +#define icamax_ icamax__ +#define ccopy_ ccopy__ +#define cscal_ cscal__ +#define scnrm2_ scnrm2__ +#define caxpy_ caxpy__ +#define cgemv_ cgemv__ +#define ctrsv_ ctrsv__ +#define cgemm_ cgemm__ +#define ctrsm_ ctrsm__ +#define cgerc_ cgerc__ +#define chemv_ chemv__ +#define cher2_ cher2__ + +#define dzasum_ dzasum__ +#define izamax_ izamax__ +#define zcopy_ zcopy__ +#define zscal_ zscal__ +#define dznrm2_ dznrm2__ +#define zaxpy_ zaxpy__ +#define zgemv_ zgemv__ +#define ztrsv_ ztrsv__ +#define zgemm_ zgemm__ +#define ztrsm_ ztrsm__ +#define zgerc_ zgerc__ +#define zhemv_ zhemv__ +#define zher2_ zher2__ + +#define c_bridge_dgssv_ c_bridge_dgssv__ +#define c_fortran_dgssv_ c_fortran_dgssv__ +#endif + +#if (F77_CALL_C == UPCASE) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void DGEMM(...) + */ +#define sasum_ SASUM +#define isamax_ ISAMAX +#define scopy_ SCOPY +#define sscal_ SSCAL +#define sger_ SGER +#define snrm2_ SNRM2 +#define ssymv_ SSYMV +#define sdot_ SDOT +#define saxpy_ SAXPY +#define ssyr2_ SSYR2 +#define srot_ SROT +#define sgemv_ SGEMV +#define strsv_ STRSV +#define sgemm_ SGEMM +#define strsm_ STRSM + +#define dasum_ SASUM +#define idamax_ ISAMAX +#define dcopy_ SCOPY +#define dscal_ SSCAL +#define dger_ SGER +#define dnrm2_ SNRM2 +#define dsymv_ SSYMV +#define ddot_ SDOT +#define daxpy_ SAXPY +#define dsyr2_ SSYR2 +#define drot_ SROT +#define dgemv_ SGEMV +#define dtrsv_ STRSV +#define dgemm_ SGEMM +#define dtrsm_ STRSM + +#define scasum_ SCASUM +#define icamax_ ICAMAX +#define ccopy_ CCOPY +#define cscal_ CSCAL +#define scnrm2_ SCNRM2 +#define caxpy_ CAXPY +#define cgemv_ CGEMV +#define ctrsv_ CTRSV +#define cgemm_ CGEMM +#define ctrsm_ CTRSM +#define cgerc_ CGERC +#define chemv_ CHEMV +#define cher2_ CHER2 + +#define dzasum_ SCASUM +#define izamax_ ICAMAX +#define zcopy_ CCOPY +#define zscal_ CSCAL +#define dznrm2_ SCNRM2 +#define zaxpy_ CAXPY +#define zgemv_ CGEMV +#define ztrsv_ CTRSV +#define zgemm_ CGEMM +#define ztrsm_ CTRSM +#define zgerc_ CGERC +#define zhemv_ CHEMV +#define zher2_ CHER2 + +#define c_bridge_dgssv_ C_BRIDGE_DGSSV +#define c_fortran_dgssv_ C_FORTRAN_DGSSV +#endif + +#if (F77_CALL_C == NOCHANGE) +/* + * These defines set up the naming scheme required to have a fortran 77 + * routine call a C routine + * for following Fortran to C interface: + * FORTRAN CALL C DECLARATION + * call dgemm(...) void dgemm(...) + */ +#define sasum_ sasum +#define isamax_ isamax +#define scopy_ scopy +#define sscal_ sscal +#define sger_ sger +#define snrm2_ snrm2 +#define ssymv_ ssymv +#define sdot_ sdot +#define saxpy_ saxpy +#define ssyr2_ ssyr2 +#define srot_ srot +#define sgemv_ sgemv +#define strsv_ strsv +#define sgemm_ sgemm +#define strsm_ strsm + +#define dasum_ dasum +#define idamax_ idamax +#define dcopy_ dcopy +#define dscal_ dscal +#define dger_ dger +#define dnrm2_ dnrm2 +#define dsymv_ dsymv +#define ddot_ ddot +#define daxpy_ daxpy +#define dsyr2_ dsyr2 +#define drot_ drot +#define dgemv_ dgemv +#define dtrsv_ dtrsv +#define dgemm_ dgemm +#define dtrsm_ dtrsm + +#define scasum_ scasum +#define icamax_ icamax +#define ccopy_ ccopy +#define cscal_ cscal +#define scnrm2_ scnrm2 +#define caxpy_ caxpy +#define cgemv_ cgemv +#define ctrsv_ ctrsv +#define cgemm_ cgemm +#define ctrsm_ ctrsm +#define cgerc_ cgerc +#define chemv_ chemv +#define cher2_ cher2 + +#define dzasum_ dzasum +#define izamax_ izamax +#define zcopy_ zcopy +#define zscal_ zscal +#define dznrm2_ dznrm2 +#define zaxpy_ zaxpy +#define zgemv_ zgemv +#define ztrsv_ ztrsv +#define zgemm_ zgemm +#define ztrsm_ ztrsm +#define zgerc_ zgerc +#define zhemv_ zhemv +#define zher2_ zher2 + +#define c_bridge_dgssv_ c_bridge_dgssv +#define c_fortran_dgssv_ c_fortran_dgssv +#endif + +#endif /* __SUPERLU_CNAMES */ diff --git a/intern/opennl/superlu/Makefile b/intern/opennl/superlu/Makefile new file mode 100644 index 00000000000..942ceebc79c --- /dev/null +++ b/intern/opennl/superlu/Makefile @@ -0,0 +1,40 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# opennl intern Makefile +# + +LIBNAME = superlu +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(NAN_LEVEL_2_CPP_WARNINGS) + diff --git a/intern/opennl/superlu/colamd.c b/intern/opennl/superlu/colamd.c new file mode 100644 index 00000000000..b60718f9938 --- /dev/null +++ b/intern/opennl/superlu/colamd.c @@ -0,0 +1,2583 @@ +/* ========================================================================== */ +/* === colamd - a sparse matrix column ordering algorithm =================== */ +/* ========================================================================== */ + +/* + colamd: An approximate minimum degree column ordering algorithm. + + Purpose: + + Colamd computes a permutation Q such that the Cholesky factorization of + (AQ)'(AQ) has less fill-in and requires fewer floating point operations + than A'A. This also provides a good ordering for sparse partial + pivoting methods, P(AQ) = LU, where Q is computed prior to numerical + factorization, and P is computed during numerical factorization via + conventional partial pivoting with row interchanges. Colamd is the + column ordering method used in SuperLU, part of the ScaLAPACK library. + It is also available as user-contributed software for Matlab 5.2, + available from MathWorks, Inc. (http://www.mathworks.com). This + routine can be used in place of COLMMD in Matlab. By default, the \ + and / operators in Matlab perform a column ordering (using COLMMD) + prior to LU factorization using sparse partial pivoting, in the + built-in Matlab LU(A) routine. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (davis@cise.ufl.edu), University of Florida. The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Date: + + August 3, 1998. Version 1.0. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998 by the University of Florida. All Rights Reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + User documentation of any code that uses this code must cite the + Authors, the Copyright, and "Used by permission." If this code is + accessible from within Matlab, then typing "help colamd" or "colamd" + (with no arguments) must cite the Authors. Permission to modify the + code and to distribute modified code is granted, provided the above + notices are retained, and a notice that the code was modified is + included with the above copyright notice. You must also retain the + Availability information below, of the original version. + + This software is provided free of charge. + + Availability: + + This file is located at + + http://www.cise.ufl.edu/~davis/colamd/colamd.c + + The colamd.h file is required, located in the same directory. + The colamdmex.c file provides a Matlab interface for colamd. + The symamdmex.c file provides a Matlab interface for symamd, which is + a symmetric ordering based on this code, colamd.c. All codes are + purely ANSI C compliant (they use no Unix-specific routines, include + files, etc.). +*/ + +/* ========================================================================== */ +/* === Description of user-callable routines ================================ */ +/* ========================================================================== */ + +/* + Each user-callable routine (declared as PUBLIC) is briefly described below. + Refer to the comments preceding each routine for more details. + + ---------------------------------------------------------------------------- + colamd_recommended: + ---------------------------------------------------------------------------- + + Usage: + + Alen = colamd_recommended (nnz, n_row, n_col) ; + + Purpose: + + Returns recommended value of Alen for use by colamd. Returns -1 + if any input argument is negative. + + Arguments: + + int nnz ; Number of nonzeros in the matrix A. This must + be the same value as p [n_col] in the call to + colamd - otherwise you will get a wrong value + of the recommended memory to use. + int n_row ; Number of rows in the matrix A. + int n_col ; Number of columns in the matrix A. + + ---------------------------------------------------------------------------- + colamd_set_defaults: + ---------------------------------------------------------------------------- + + Usage: + + colamd_set_defaults (knobs) ; + + Purpose: + + Sets the default parameters. + + Arguments: + + double knobs [COLAMD_KNOBS] ; Output only. + + Rows with more than (knobs [COLAMD_DENSE_ROW] * n_col) entries + are removed prior to ordering. Columns with more than + (knobs [COLAMD_DENSE_COL] * n_row) entries are removed + prior to ordering, and placed last in the output column + ordering. Default values of these two knobs are both 0.5. + Currently, only knobs [0] and knobs [1] are used, but future + versions may use more knobs. If so, they will be properly set + to their defaults by the future version of colamd_set_defaults, + so that the code that calls colamd will not need to change, + assuming that you either use colamd_set_defaults, or pass a + (double *) NULL pointer as the knobs array to colamd. + + ---------------------------------------------------------------------------- + colamd: + ---------------------------------------------------------------------------- + + Usage: + + colamd (n_row, n_col, Alen, A, p, knobs) ; + + Purpose: + + Computes a column ordering (Q) of A such that P(AQ)=LU or + (AQ)'AQ=LL' have less fill-in and require fewer floating point + operations than factorizing the unpermuted matrix A or A'A, + respectively. + + Arguments: + + int n_row ; + + Number of rows in the matrix A. + Restriction: n_row >= 0. + Colamd returns FALSE if n_row is negative. + + int n_col ; + + Number of columns in the matrix A. + Restriction: n_col >= 0. + Colamd returns FALSE if n_col is negative. + + int Alen ; + + Restriction (see note): + Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col + COLAMD_STATS + Colamd returns FALSE if these conditions are not met. + + Note: this restriction makes an modest assumption regarding + the size of the two typedef'd structures, below. We do, + however, guarantee that + Alen >= colamd_recommended (nnz, n_row, n_col) + will be sufficient. + + int A [Alen] ; Input argument, stats on output. + + A is an integer array of size Alen. Alen must be at least as + large as the bare minimum value given above, but this is very + low, and can result in excessive run time. For best + performance, we recommend that Alen be greater than or equal to + colamd_recommended (nnz, n_row, n_col), which adds + nnz/5 to the bare minimum value given above. + + On input, the row indices of the entries in column c of the + matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices + in a given column c need not be in ascending order, and + duplicate row indices may be be present. However, colamd will + work a little faster if both of these conditions are met + (Colamd puts the matrix into this format, if it finds that the + the conditions are not met). + + The matrix is 0-based. That is, rows are in the range 0 to + n_row-1, and columns are in the range 0 to n_col-1. Colamd + returns FALSE if any row index is out of range. + + The contents of A are modified during ordering, and are thus + undefined on output with the exception of a few statistics + about the ordering (A [0..COLAMD_STATS-1]): + A [0]: number of dense or empty rows ignored. + A [1]: number of dense or empty columns ignored (and ordered + last in the output permutation p) + A [2]: number of garbage collections performed. + A [3]: 0, if all row indices in each column were in sorted + order, and no duplicates were present. + 1, otherwise (in which case colamd had to do more work) + Note that a row can become "empty" if it contains only + "dense" and/or "empty" columns, and similarly a column can + become "empty" if it only contains "dense" and/or "empty" rows. + Future versions may return more statistics in A, but the usage + of these 4 entries in A will remain unchanged. + + int p [n_col+1] ; Both input and output argument. + + p is an integer array of size n_col+1. On input, it holds the + "pointers" for the column form of the matrix A. Column c of + the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first + entry, p [0], must be zero, and p [c] <= p [c+1] must hold + for all c in the range 0 to n_col-1. The value p [n_col] is + thus the total number of entries in the pattern of the matrix A. + Colamd returns FALSE if these conditions are not met. + + On output, if colamd returns TRUE, the array p holds the column + permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is + the first column index in the new ordering, and p [n_col-1] is + the last. That is, p [k] = j means that column j of A is the + kth pivot column, in AQ, where k is in the range 0 to n_col-1 + (p [0] = j means that column j of A is the first column in AQ). + + If colamd returns FALSE, then no permutation is returned, and + p is undefined on output. + + double knobs [COLAMD_KNOBS] ; Input only. + + See colamd_set_defaults for a description. If the knobs array + is not present (that is, if a (double *) NULL pointer is passed + in its place), then the default values of the parameters are + used instead. + +*/ + + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +/* limits.h: the largest positive integer (INT_MAX) */ +#include + +/* colamd.h: knob array size, stats output size, and global prototypes */ +#include "colamd.h" + +/* ========================================================================== */ +/* === Scaffolding code definitions ======================================== */ +/* ========================================================================== */ + +/* Ensure that debugging is turned off: */ +#ifndef NDEBUG +#define NDEBUG +#endif + +/* assert.h: the assert macro (no debugging if NDEBUG is defined) */ +#include + +/* + Our "scaffolding code" philosophy: In our opinion, well-written library + code should keep its "debugging" code, and just normally have it turned off + by the compiler so as not to interfere with performance. This serves + several purposes: + + (1) assertions act as comments to the reader, telling you what the code + expects at that point. All assertions will always be true (unless + there really is a bug, of course). + + (2) leaving in the scaffolding code assists anyone who would like to modify + the code, or understand the algorithm (by reading the debugging output, + one can get a glimpse into what the code is doing). + + (3) (gasp!) for actually finding bugs. This code has been heavily tested + and "should" be fully functional and bug-free ... but you never know... + + To enable debugging, comment out the "#define NDEBUG" above. The code will + become outrageously slow when debugging is enabled. To control the level of + debugging output, set an environment variable D to 0 (little), 1 (some), + 2, 3, or 4 (lots). +*/ + +/* ========================================================================== */ +/* === Row and Column structures ============================================ */ +/* ========================================================================== */ + +typedef struct ColInfo_struct +{ + int start ; /* index for A of first row in this column, or DEAD */ + /* if column is dead */ + int length ; /* number of rows in this column */ + union + { + int thickness ; /* number of original columns represented by this */ + /* col, if the column is alive */ + int parent ; /* parent in parent tree super-column structure, if */ + /* the column is dead */ + } shared1 ; + union + { + int score ; /* the score used to maintain heap, if col is alive */ + int order ; /* pivot ordering of this column, if col is dead */ + } shared2 ; + union + { + int headhash ; /* head of a hash bucket, if col is at the head of */ + /* a degree list */ + int hash ; /* hash value, if col is not in a degree list */ + int prev ; /* previous column in degree list, if col is in a */ + /* degree list (but not at the head of a degree list) */ + } shared3 ; + union + { + int degree_next ; /* next column, if col is in a degree list */ + int hash_next ; /* next column, if col is in a hash list */ + } shared4 ; + +} ColInfo ; + +typedef struct RowInfo_struct +{ + int start ; /* index for A of first col in this row */ + int length ; /* number of principal columns in this row */ + union + { + int degree ; /* number of principal & non-principal columns in row */ + int p ; /* used as a row pointer in init_rows_cols () */ + } shared1 ; + union + { + int mark ; /* for computing set differences and marking dead rows*/ + int first_column ;/* first column in row (used in garbage collection) */ + } shared2 ; + +} RowInfo ; + +/* ========================================================================== */ +/* === Definitions ========================================================== */ +/* ========================================================================== */ + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#define ONES_COMPLEMENT(r) (-(r)-1) + +#define TRUE (1) +#define FALSE (0) +#define EMPTY (-1) + +/* Row and column status */ +#define ALIVE (0) +#define DEAD (-1) + +/* Column status */ +#define DEAD_PRINCIPAL (-1) +#define DEAD_NON_PRINCIPAL (-2) + +/* Macros for row and column status update and checking. */ +#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) +#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) +#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) +#define COL_IS_DEAD(c) (Col [c].start < ALIVE) +#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) +#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) +#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } +#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } +#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } + +/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ +#define PUBLIC +#define PRIVATE static + +/* ========================================================================== */ +/* === Prototypes of PRIVATE routines ======================================= */ +/* ========================================================================== */ + +PRIVATE int init_rows_cols +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int p [] +) ; + +PRIVATE void init_scoring +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int head [], + double knobs [COLAMD_KNOBS], + int *p_n_row2, + int *p_n_col2, + int *p_max_deg +) ; + +PRIVATE int find_ordering +( + int n_row, + int n_col, + int Alen, + RowInfo Row [], + ColInfo Col [], + int A [], + int head [], + int n_col2, + int max_deg, + int pfree +) ; + +PRIVATE void order_children +( + int n_col, + ColInfo Col [], + int p [] +) ; + +PRIVATE void detect_super_cols +( +#ifndef NDEBUG + int n_col, + RowInfo Row [], +#endif + ColInfo Col [], + int A [], + int head [], + int row_start, + int row_length +) ; + +PRIVATE int garbage_collection +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int *pfree +) ; + +PRIVATE int clear_mark +( + int n_row, + RowInfo Row [] +) ; + +/* ========================================================================== */ +/* === Debugging definitions ================================================ */ +/* ========================================================================== */ + +#ifndef NDEBUG + +/* === With debugging ======================================================= */ + +/* stdlib.h: for getenv and atoi, to get debugging level from environment */ +#include + +/* stdio.h: for printf (no printing if debugging is turned off) */ +#include + +PRIVATE void debug_deg_lists +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int head [], + int min_score, + int should, + int max_deg +) ; + +PRIVATE void debug_mark +( + int n_row, + RowInfo Row [], + int tag_mark, + int max_mark +) ; + +PRIVATE void debug_matrix +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [] +) ; + +PRIVATE void debug_structures +( + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int n_col2 +) ; + +/* the following is the *ONLY* global variable in this file, and is only */ +/* present when debugging */ + +PRIVATE int debug_colamd ; /* debug print level */ + +#define DEBUG0(params) { (void) printf params ; } +#define DEBUG1(params) { if (debug_colamd >= 1) (void) printf params ; } +#define DEBUG2(params) { if (debug_colamd >= 2) (void) printf params ; } +#define DEBUG3(params) { if (debug_colamd >= 3) (void) printf params ; } +#define DEBUG4(params) { if (debug_colamd >= 4) (void) printf params ; } + +#else + +/* === No debugging ========================================================= */ + +#define DEBUG0(params) ; +#define DEBUG1(params) ; +#define DEBUG2(params) ; +#define DEBUG3(params) ; +#define DEBUG4(params) ; + +#endif + +/* ========================================================================== */ + + +/* ========================================================================== */ +/* === USER-CALLABLE ROUTINES: ============================================== */ +/* ========================================================================== */ + + +/* ========================================================================== */ +/* === colamd_recommended =================================================== */ +/* ========================================================================== */ + +/* + The colamd_recommended routine returns the suggested size for Alen. This + value has been determined to provide good balance between the number of + garbage collections and the memory requirements for colamd. +*/ + +PUBLIC int colamd_recommended /* returns recommended value of Alen. */ +( + /* === Parameters ======================================================= */ + + int nnz, /* number of nonzeros in A */ + int n_row, /* number of rows in A */ + int n_col /* number of columns in A */ +) +{ + /* === Local variables ================================================== */ + + int minimum ; /* bare minimum requirements */ + int recommended ; /* recommended value of Alen */ + + if (nnz < 0 || n_row < 0 || n_col < 0) + { + /* return -1 if any input argument is corrupted */ + DEBUG0 (("colamd_recommended error!")) ; + DEBUG0 ((" nnz: %d, n_row: %d, n_col: %d\n", nnz, n_row, n_col)) ; + return (-1) ; + } + + minimum = + 2 * (nnz) /* for A */ + + (((n_col) + 1) * sizeof (ColInfo) / sizeof (int)) /* for Col */ + + (((n_row) + 1) * sizeof (RowInfo) / sizeof (int)) /* for Row */ + + n_col /* minimum elbow room to guarrantee success */ + + COLAMD_STATS ; /* for output statistics */ + + /* recommended is equal to the minumum plus enough memory to keep the */ + /* number garbage collections low */ + recommended = minimum + nnz/5 ; + + return (recommended) ; +} + + +/* ========================================================================== */ +/* === colamd_set_defaults ================================================== */ +/* ========================================================================== */ + +/* + The colamd_set_defaults routine sets the default values of the user- + controllable parameters for colamd: + + knobs [0] rows with knobs[0]*n_col entries or more are removed + prior to ordering. + + knobs [1] columns with knobs[1]*n_row entries or more are removed + prior to ordering, and placed last in the column + permutation. + + knobs [2..19] unused, but future versions might use this +*/ + +PUBLIC void colamd_set_defaults +( + /* === Parameters ======================================================= */ + + double knobs [COLAMD_KNOBS] /* knob array */ +) +{ + /* === Local variables ================================================== */ + + int i ; + + if (!knobs) + { + return ; /* no knobs to initialize */ + } + for (i = 0 ; i < COLAMD_KNOBS ; i++) + { + knobs [i] = 0 ; + } + knobs [COLAMD_DENSE_ROW] = 0.5 ; /* ignore rows over 50% dense */ + knobs [COLAMD_DENSE_COL] = 0.5 ; /* ignore columns over 50% dense */ +} + + +/* ========================================================================== */ +/* === colamd =============================================================== */ +/* ========================================================================== */ + +/* + The colamd routine computes a column ordering Q of a sparse matrix + A such that the LU factorization P(AQ) = LU remains sparse, where P is + selected via partial pivoting. The routine can also be viewed as + providing a permutation Q such that the Cholesky factorization + (AQ)'(AQ) = LL' remains sparse. + + On input, the nonzero patterns of the columns of A are stored in the + array A, in order 0 to n_col-1. A is held in 0-based form (rows in the + range 0 to n_row-1 and columns in the range 0 to n_col-1). Row indices + for column c are located in A [(p [c]) ... (p [c+1]-1)], where p [0] = 0, + and thus p [n_col] is the number of entries in A. The matrix is + destroyed on output. The row indices within each column do not have to + be sorted (from small to large row indices), and duplicate row indices + may be present. However, colamd will work a little faster if columns are + sorted and no duplicates are present. Matlab 5.2 always passes the matrix + with sorted columns, and no duplicates. + + The integer array A is of size Alen. Alen must be at least of size + (where nnz is the number of entries in A): + + nnz for the input column form of A + + nnz for a row form of A that colamd generates + + 6*(n_col+1) for a ColInfo Col [0..n_col] array + (this assumes sizeof (ColInfo) is 6 int's). + + 4*(n_row+1) for a RowInfo Row [0..n_row] array + (this assumes sizeof (RowInfo) is 4 int's). + + elbow_room must be at least n_col. We recommend at least + nnz/5 in addition to that. If sufficient, + changes in the elbow room affect the ordering + time only, not the ordering itself. + + COLAMD_STATS for the output statistics + + Colamd returns FALSE is memory is insufficient, or TRUE otherwise. + + On input, the caller must specify: + + n_row the number of rows of A + n_col the number of columns of A + Alen the size of the array A + A [0 ... nnz-1] the row indices, where nnz = p [n_col] + A [nnz ... Alen-1] (need not be initialized by the user) + p [0 ... n_col] the column pointers, p [0] = 0, and p [n_col] + is the number of entries in A. Column c of A + is stored in A [p [c] ... p [c+1]-1]. + knobs [0 ... 19] a set of parameters that control the behavior + of colamd. If knobs is a NULL pointer the + defaults are used. The user-callable + colamd_set_defaults routine sets the default + parameters. See that routine for a description + of the user-controllable parameters. + + If the return value of Colamd is TRUE, then on output: + + p [0 ... n_col-1] the column permutation. p [0] is the first + column index, and p [n_col-1] is the last. + That is, p [k] = j means that column j of A + is the kth column of AQ. + + A is undefined on output (the matrix pattern is + destroyed), except for the following statistics: + + A [0] the number of dense (or empty) rows ignored + A [1] the number of dense (or empty) columms. These + are ordered last, in their natural order. + A [2] the number of garbage collections performed. + If this is excessive, then you would have + gotten your results faster if Alen was larger. + A [3] 0, if all row indices in each column were in + sorted order and no duplicates were present. + 1, if there were unsorted or duplicate row + indices in the input. You would have gotten + your results faster if A [3] was returned as 0. + + If the return value of Colamd is FALSE, then A and p are undefined on + output. +*/ + +PUBLIC int colamd /* returns TRUE if successful */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows in A */ + int n_col, /* number of columns in A */ + int Alen, /* length of A */ + int A [], /* row indices of A */ + int p [], /* pointers to columns in A */ + double knobs [COLAMD_KNOBS] /* parameters (uses defaults if NULL) */ +) +{ + /* === Local variables ================================================== */ + + int i ; /* loop index */ + int nnz ; /* nonzeros in A */ + int Row_size ; /* size of Row [], in integers */ + int Col_size ; /* size of Col [], in integers */ + int elbow_room ; /* remaining free space */ + RowInfo *Row ; /* pointer into A of Row [0..n_row] array */ + ColInfo *Col ; /* pointer into A of Col [0..n_col] array */ + int n_col2 ; /* number of non-dense, non-empty columns */ + int n_row2 ; /* number of non-dense, non-empty rows */ + int ngarbage ; /* number of garbage collections performed */ + int max_deg ; /* maximum row degree */ + double default_knobs [COLAMD_KNOBS] ; /* default knobs knobs array */ + int init_result ; /* return code from initialization */ + +#ifndef NDEBUG + debug_colamd = 0 ; /* no debug printing */ + /* get "D" environment variable, which gives the debug printing level */ + if (getenv ("D")) debug_colamd = atoi (getenv ("D")) ; + DEBUG0 (("debug version, D = %d (THIS WILL BE SLOOOOW!)\n", debug_colamd)) ; +#endif + + /* === Check the input arguments ======================================== */ + + if (n_row < 0 || n_col < 0 || !A || !p) + { + /* n_row and n_col must be non-negative, A and p must be present */ + DEBUG0 (("colamd error! %d %d %d\n", n_row, n_col, Alen)) ; + return (FALSE) ; + } + nnz = p [n_col] ; + if (nnz < 0 || p [0] != 0) + { + /* nnz must be non-negative, and p [0] must be zero */ + DEBUG0 (("colamd error! %d %d\n", nnz, p [0])) ; + return (FALSE) ; + } + + /* === If no knobs, set default parameters ============================== */ + + if (!knobs) + { + knobs = default_knobs ; + colamd_set_defaults (knobs) ; + } + + /* === Allocate the Row and Col arrays from array A ===================== */ + + Col_size = (n_col + 1) * sizeof (ColInfo) / sizeof (int) ; + Row_size = (n_row + 1) * sizeof (RowInfo) / sizeof (int) ; + elbow_room = Alen - (2*nnz + Col_size + Row_size) ; + if (elbow_room < n_col + COLAMD_STATS) + { + /* not enough space in array A to perform the ordering */ + DEBUG0 (("colamd error! elbow_room %d, %d\n", elbow_room,n_col)) ; + return (FALSE) ; + } + Alen = 2*nnz + elbow_room ; + Col = (ColInfo *) &A [Alen] ; + Row = (RowInfo *) &A [Alen + Col_size] ; + + /* === Construct the row and column data structures ===================== */ + + init_result = init_rows_cols (n_row, n_col, Row, Col, A, p) ; + if (init_result == -1) + { + /* input matrix is invalid */ + DEBUG0 (("colamd error! matrix invalid\n")) ; + return (FALSE) ; + } + + /* === Initialize scores, kill dense rows/columns ======================= */ + + init_scoring (n_row, n_col, Row, Col, A, p, knobs, + &n_row2, &n_col2, &max_deg) ; + + /* === Order the supercolumns =========================================== */ + + ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, + n_col2, max_deg, 2*nnz) ; + + /* === Order the non-principal columns ================================== */ + + order_children (n_col, Col, p) ; + + /* === Return statistics in A =========================================== */ + + for (i = 0 ; i < COLAMD_STATS ; i++) + { + A [i] = 0 ; + } + A [COLAMD_DENSE_ROW] = n_row - n_row2 ; + A [COLAMD_DENSE_COL] = n_col - n_col2 ; + A [COLAMD_DEFRAG_COUNT] = ngarbage ; + A [COLAMD_JUMBLED_COLS] = init_result ; + + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === NON-USER-CALLABLE ROUTINES: ========================================== */ +/* ========================================================================== */ + +/* There are no user-callable routines beyond this point in the file */ + + +/* ========================================================================== */ +/* === init_rows_cols ======================================================= */ +/* ========================================================================== */ + +/* + Takes the column form of the matrix in A and creates the row form of the + matrix. Also, row and column attributes are stored in the Col and Row + structs. If the columns are un-sorted or contain duplicate row indices, + this routine will also sort and remove duplicate row indices from the + column form of the matrix. Returns -1 on error, 1 if columns jumbled, + or 0 if columns not jumbled. Not user-callable. +*/ + +PRIVATE int init_rows_cols /* returns status code */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows of A */ + int n_col, /* number of columns of A */ + RowInfo Row [], /* of size n_row+1 */ + ColInfo Col [], /* of size n_col+1 */ + int A [], /* row indices of A, of size Alen */ + int p [] /* pointers to columns in A, of size n_col+1 */ +) +{ + /* === Local variables ================================================== */ + + int col ; /* a column index */ + int row ; /* a row index */ + int *cp ; /* a column pointer */ + int *cp_end ; /* a pointer to the end of a column */ + int *rp ; /* a row pointer */ + int *rp_end ; /* a pointer to the end of a row */ + int last_start ; /* start index of previous column in A */ + int start ; /* start index of column in A */ + int last_row ; /* previous row */ + int jumbled_columns ; /* indicates if columns are jumbled */ + + /* === Initialize columns, and check column pointers ==================== */ + + last_start = 0 ; + for (col = 0 ; col < n_col ; col++) + { + start = p [col] ; + if (start < last_start) + { + /* column pointers must be non-decreasing */ + DEBUG0 (("colamd error! last p %d p [col] %d\n",last_start,start)); + return (-1) ; + } + Col [col].start = start ; + Col [col].length = p [col+1] - start ; + Col [col].shared1.thickness = 1 ; + Col [col].shared2.score = 0 ; + Col [col].shared3.prev = EMPTY ; + Col [col].shared4.degree_next = EMPTY ; + last_start = start ; + } + /* must check the end pointer for last column */ + if (p [n_col] < last_start) + { + /* column pointers must be non-decreasing */ + DEBUG0 (("colamd error! last p %d p [n_col] %d\n",p[col],last_start)) ; + return (-1) ; + } + + /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ + + /* === Scan columns, compute row degrees, and check row indices ========= */ + + jumbled_columns = FALSE ; + + for (row = 0 ; row < n_row ; row++) + { + Row [row].length = 0 ; + Row [row].shared2.mark = -1 ; + } + + for (col = 0 ; col < n_col ; col++) + { + last_row = -1 ; + + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + + while (cp < cp_end) + { + row = *cp++ ; + + /* make sure row indices within range */ + if (row < 0 || row >= n_row) + { + DEBUG0 (("colamd error! col %d row %d last_row %d\n", + col, row, last_row)) ; + return (-1) ; + } + else if (row <= last_row) + { + /* row indices are not sorted or repeated, thus cols */ + /* are jumbled */ + jumbled_columns = TRUE ; + } + /* prevent repeated row from being counted */ + if (Row [row].shared2.mark != col) + { + Row [row].length++ ; + Row [row].shared2.mark = col ; + last_row = row ; + } + else + { + /* this is a repeated entry in the column, */ + /* it will be removed */ + Col [col].length-- ; + } + } + } + + /* === Compute row pointers ============================================= */ + + /* row form of the matrix starts directly after the column */ + /* form of matrix in A */ + Row [0].start = p [n_col] ; + Row [0].shared1.p = Row [0].start ; + Row [0].shared2.mark = -1 ; + for (row = 1 ; row < n_row ; row++) + { + Row [row].start = Row [row-1].start + Row [row-1].length ; + Row [row].shared1.p = Row [row].start ; + Row [row].shared2.mark = -1 ; + } + + /* === Create row form ================================================== */ + + if (jumbled_columns) + { + /* if cols jumbled, watch for repeated row indices */ + for (col = 0 ; col < n_col ; col++) + { + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + while (cp < cp_end) + { + row = *cp++ ; + if (Row [row].shared2.mark != col) + { + A [(Row [row].shared1.p)++] = col ; + Row [row].shared2.mark = col ; + } + } + } + } + else + { + /* if cols not jumbled, we don't need the mark (this is faster) */ + for (col = 0 ; col < n_col ; col++) + { + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + while (cp < cp_end) + { + A [(Row [*cp++].shared1.p)++] = col ; + } + } + } + + /* === Clear the row marks and set row degrees ========================== */ + + for (row = 0 ; row < n_row ; row++) + { + Row [row].shared2.mark = 0 ; + Row [row].shared1.degree = Row [row].length ; + } + + /* === See if we need to re-create columns ============================== */ + + if (jumbled_columns) + { + +#ifndef NDEBUG + /* make sure column lengths are correct */ + for (col = 0 ; col < n_col ; col++) + { + p [col] = Col [col].length ; + } + for (row = 0 ; row < n_row ; row++) + { + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + p [*rp++]-- ; + } + } + for (col = 0 ; col < n_col ; col++) + { + assert (p [col] == 0) ; + } + /* now p is all zero (different than when debugging is turned off) */ +#endif + + /* === Compute col pointers ========================================= */ + + /* col form of the matrix starts at A [0]. */ + /* Note, we may have a gap between the col form and the row */ + /* form if there were duplicate entries, if so, it will be */ + /* removed upon the first garbage collection */ + Col [0].start = 0 ; + p [0] = Col [0].start ; + for (col = 1 ; col < n_col ; col++) + { + /* note that the lengths here are for pruned columns, i.e. */ + /* no duplicate row indices will exist for these columns */ + Col [col].start = Col [col-1].start + Col [col-1].length ; + p [col] = Col [col].start ; + } + + /* === Re-create col form =========================================== */ + + for (row = 0 ; row < n_row ; row++) + { + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + A [(p [*rp++])++] = row ; + } + } + return (1) ; + } + else + { + /* no columns jumbled (this is faster) */ + return (0) ; + } +} + + +/* ========================================================================== */ +/* === init_scoring ========================================================= */ +/* ========================================================================== */ + +/* + Kills dense or empty columns and rows, calculates an initial score for + each column, and places all columns in the degree lists. Not user-callable. +*/ + +PRIVATE void init_scoring +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows of A */ + int n_col, /* number of columns of A */ + RowInfo Row [], /* of size n_row+1 */ + ColInfo Col [], /* of size n_col+1 */ + int A [], /* column form and row form of A */ + int head [], /* of size n_col+1 */ + double knobs [COLAMD_KNOBS],/* parameters */ + int *p_n_row2, /* number of non-dense, non-empty rows */ + int *p_n_col2, /* number of non-dense, non-empty columns */ + int *p_max_deg /* maximum row degree */ +) +{ + /* === Local variables ================================================== */ + + int c ; /* a column index */ + int r, row ; /* a row index */ + int *cp ; /* a column pointer */ + int deg ; /* degree (# entries) of a row or column */ + int *cp_end ; /* a pointer to the end of a column */ + int *new_cp ; /* new column pointer */ + int col_length ; /* length of pruned column */ + int score ; /* current column score */ + int n_col2 ; /* number of non-dense, non-empty columns */ + int n_row2 ; /* number of non-dense, non-empty rows */ + int dense_row_count ; /* remove rows with more entries than this */ + int dense_col_count ; /* remove cols with more entries than this */ + int min_score ; /* smallest column score */ + int max_deg ; /* maximum row degree */ + int next_col ; /* Used to add to degree list.*/ +#ifndef NDEBUG + int debug_count ; /* debug only. */ +#endif + + /* === Extract knobs ==================================================== */ + + dense_row_count = MAX (0, MIN (knobs [COLAMD_DENSE_ROW] * n_col, n_col)) ; + dense_col_count = MAX (0, MIN (knobs [COLAMD_DENSE_COL] * n_row, n_row)) ; + DEBUG0 (("densecount: %d %d\n", dense_row_count, dense_col_count)) ; + max_deg = 0 ; + n_col2 = n_col ; + n_row2 = n_row ; + + /* === Kill empty columns =============================================== */ + + /* Put the empty columns at the end in their natural, so that LU */ + /* factorization can proceed as far as possible. */ + for (c = n_col-1 ; c >= 0 ; c--) + { + deg = Col [c].length ; + if (deg == 0) + { + /* this is a empty column, kill and order it last */ + Col [c].shared2.order = --n_col2 ; + KILL_PRINCIPAL_COL (c) ; + } + } + DEBUG0 (("null columns killed: %d\n", n_col - n_col2)) ; + + /* === Kill dense columns =============================================== */ + + /* Put the dense columns at the end, in their natural order */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* skip any dead columns */ + if (COL_IS_DEAD (c)) + { + continue ; + } + deg = Col [c].length ; + if (deg > dense_col_count) + { + /* this is a dense column, kill and order it last */ + Col [c].shared2.order = --n_col2 ; + /* decrement the row degrees */ + cp = &A [Col [c].start] ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + Row [*cp++].shared1.degree-- ; + } + KILL_PRINCIPAL_COL (c) ; + } + } + DEBUG0 (("Dense and null columns killed: %d\n", n_col - n_col2)) ; + + /* === Kill dense and empty rows ======================================== */ + + for (r = 0 ; r < n_row ; r++) + { + deg = Row [r].shared1.degree ; + assert (deg >= 0 && deg <= n_col) ; + if (deg > dense_row_count || deg == 0) + { + /* kill a dense or empty row */ + KILL_ROW (r) ; + --n_row2 ; + } + else + { + /* keep track of max degree of remaining rows */ + max_deg = MAX (max_deg, deg) ; + } + } + DEBUG0 (("Dense and null rows killed: %d\n", n_row - n_row2)) ; + + /* === Compute initial column scores ==================================== */ + + /* At this point the row degrees are accurate. They reflect the number */ + /* of "live" (non-dense) columns in each row. No empty rows exist. */ + /* Some "live" columns may contain only dead rows, however. These are */ + /* pruned in the code below. */ + + /* now find the initial matlab score for each column */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* skip dead column */ + if (COL_IS_DEAD (c)) + { + continue ; + } + score = 0 ; + cp = &A [Col [c].start] ; + new_cp = cp ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + /* skip if dead */ + if (ROW_IS_DEAD (row)) + { + continue ; + } + /* compact the column */ + *new_cp++ = row ; + /* add row's external degree */ + score += Row [row].shared1.degree - 1 ; + /* guard against integer overflow */ + score = MIN (score, n_col) ; + } + /* determine pruned column length */ + col_length = (int) (new_cp - &A [Col [c].start]) ; + if (col_length == 0) + { + /* a newly-made null column (all rows in this col are "dense" */ + /* and have already been killed) */ + DEBUG0 (("Newly null killed: %d\n", c)) ; + Col [c].shared2.order = --n_col2 ; + KILL_PRINCIPAL_COL (c) ; + } + else + { + /* set column length and set score */ + assert (score >= 0) ; + assert (score <= n_col) ; + Col [c].length = col_length ; + Col [c].shared2.score = score ; + } + } + DEBUG0 (("Dense, null, and newly-null columns killed: %d\n",n_col-n_col2)) ; + + /* At this point, all empty rows and columns are dead. All live columns */ + /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ + /* yet). Rows may contain dead columns, but all live rows contain at */ + /* least one live column. */ + +#ifndef NDEBUG + debug_structures (n_row, n_col, Row, Col, A, n_col2) ; +#endif + + /* === Initialize degree lists ========================================== */ + +#ifndef NDEBUG + debug_count = 0 ; +#endif + + /* clear the hash buckets */ + for (c = 0 ; c <= n_col ; c++) + { + head [c] = EMPTY ; + } + min_score = n_col ; + /* place in reverse order, so low column indices are at the front */ + /* of the lists. This is to encourage natural tie-breaking */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* only add principal columns to degree lists */ + if (COL_IS_ALIVE (c)) + { + DEBUG4 (("place %d score %d minscore %d ncol %d\n", + c, Col [c].shared2.score, min_score, n_col)) ; + + /* === Add columns score to DList =============================== */ + + score = Col [c].shared2.score ; + + assert (min_score >= 0) ; + assert (min_score <= n_col) ; + assert (score >= 0) ; + assert (score <= n_col) ; + assert (head [score] >= EMPTY) ; + + /* now add this column to dList at proper score location */ + next_col = head [score] ; + Col [c].shared3.prev = EMPTY ; + Col [c].shared4.degree_next = next_col ; + + /* if there already was a column with the same score, set its */ + /* previous pointer to this new column */ + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = c ; + } + head [score] = c ; + + /* see if this score is less than current min */ + min_score = MIN (min_score, score) ; + +#ifndef NDEBUG + debug_count++ ; +#endif + } + } + +#ifndef NDEBUG + DEBUG0 (("Live cols %d out of %d, non-princ: %d\n", + debug_count, n_col, n_col-debug_count)) ; + assert (debug_count == n_col2) ; + debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ; +#endif + + /* === Return number of remaining columns, and max row degree =========== */ + + *p_n_col2 = n_col2 ; + *p_n_row2 = n_row2 ; + *p_max_deg = max_deg ; +} + + +/* ========================================================================== */ +/* === find_ordering ======================================================== */ +/* ========================================================================== */ + +/* + Order the principal columns of the supercolumn form of the matrix + (no supercolumns on input). Uses a minimum approximate column minimum + degree ordering method. Not user-callable. +*/ + +PRIVATE int find_ordering /* return the number of garbage collections */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows of A */ + int n_col, /* number of columns of A */ + int Alen, /* size of A, 2*nnz + elbow_room or larger */ + RowInfo Row [], /* of size n_row+1 */ + ColInfo Col [], /* of size n_col+1 */ + int A [], /* column form and row form of A */ + int head [], /* of size n_col+1 */ + int n_col2, /* Remaining columns to order */ + int max_deg, /* Maximum row degree */ + int pfree /* index of first free slot (2*nnz on entry) */ +) +{ + /* === Local variables ================================================== */ + + int k ; /* current pivot ordering step */ + int pivot_col ; /* current pivot column */ + int *cp ; /* a column pointer */ + int *rp ; /* a row pointer */ + int pivot_row ; /* current pivot row */ + int *new_cp ; /* modified column pointer */ + int *new_rp ; /* modified row pointer */ + int pivot_row_start ; /* pointer to start of pivot row */ + int pivot_row_degree ; /* # of columns in pivot row */ + int pivot_row_length ; /* # of supercolumns in pivot row */ + int pivot_col_score ; /* score of pivot column */ + int needed_memory ; /* free space needed for pivot row */ + int *cp_end ; /* pointer to the end of a column */ + int *rp_end ; /* pointer to the end of a row */ + int row ; /* a row index */ + int col ; /* a column index */ + int max_score ; /* maximum possible score */ + int cur_score ; /* score of current column */ + unsigned int hash ; /* hash value for supernode detection */ + int head_column ; /* head of hash bucket */ + int first_col ; /* first column in hash bucket */ + int tag_mark ; /* marker value for mark array */ + int row_mark ; /* Row [row].shared2.mark */ + int set_difference ; /* set difference size of row with pivot row */ + int min_score ; /* smallest column score */ + int col_thickness ; /* "thickness" (# of columns in a supercol) */ + int max_mark ; /* maximum value of tag_mark */ + int pivot_col_thickness ; /* number of columns represented by pivot col */ + int prev_col ; /* Used by Dlist operations. */ + int next_col ; /* Used by Dlist operations. */ + int ngarbage ; /* number of garbage collections performed */ +#ifndef NDEBUG + int debug_d ; /* debug loop counter */ + int debug_step = 0 ; /* debug loop counter */ +#endif + + /* === Initialization and clear mark ==================================== */ + + max_mark = INT_MAX - n_col ; /* INT_MAX defined in */ + tag_mark = clear_mark (n_row, Row) ; + min_score = 0 ; + ngarbage = 0 ; + DEBUG0 (("Ordering.. n_col2=%d\n", n_col2)) ; + + /* === Order the columns ================================================ */ + + for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */) + { + +#ifndef NDEBUG + if (debug_step % 100 == 0) + { + DEBUG0 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ; + } + else + { + DEBUG1 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ; + } + debug_step++ ; + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k, max_deg) ; + debug_matrix (n_row, n_col, Row, Col, A) ; +#endif + + /* === Select pivot column, and order it ============================ */ + + /* make sure degree list isn't empty */ + assert (min_score >= 0) ; + assert (min_score <= n_col) ; + assert (head [min_score] >= EMPTY) ; + +#ifndef NDEBUG + for (debug_d = 0 ; debug_d < min_score ; debug_d++) + { + assert (head [debug_d] == EMPTY) ; + } +#endif + + /* get pivot column from head of minimum degree list */ + while (head [min_score] == EMPTY && min_score < n_col) + { + min_score++ ; + } + pivot_col = head [min_score] ; + assert (pivot_col >= 0 && pivot_col <= n_col) ; + next_col = Col [pivot_col].shared4.degree_next ; + head [min_score] = next_col ; + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = EMPTY ; + } + + assert (COL_IS_ALIVE (pivot_col)) ; + DEBUG3 (("Pivot col: %d\n", pivot_col)) ; + + /* remember score for defrag check */ + pivot_col_score = Col [pivot_col].shared2.score ; + + /* the pivot column is the kth column in the pivot order */ + Col [pivot_col].shared2.order = k ; + + /* increment order count by column thickness */ + pivot_col_thickness = Col [pivot_col].shared1.thickness ; + k += pivot_col_thickness ; + assert (pivot_col_thickness > 0) ; + + /* === Garbage_collection, if necessary ============================= */ + + needed_memory = MIN (pivot_col_score, n_col - k) ; + if (pfree + needed_memory >= Alen) + { + pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; + ngarbage++ ; + /* after garbage collection we will have enough */ + assert (pfree + needed_memory < Alen) ; + /* garbage collection has wiped out the Row[].shared2.mark array */ + tag_mark = clear_mark (n_row, Row) ; +#ifndef NDEBUG + debug_matrix (n_row, n_col, Row, Col, A) ; +#endif + } + + /* === Compute pivot row pattern ==================================== */ + + /* get starting location for this new merged row */ + pivot_row_start = pfree ; + + /* initialize new row counts to zero */ + pivot_row_degree = 0 ; + + /* tag pivot column as having been visited so it isn't included */ + /* in merged pivot row */ + Col [pivot_col].shared1.thickness = -pivot_col_thickness ; + + /* pivot row is the union of all rows in the pivot column pattern */ + cp = &A [Col [pivot_col].start] ; + cp_end = cp + Col [pivot_col].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ; + /* skip if row is dead */ + if (ROW_IS_DEAD (row)) + { + continue ; + } + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + /* get a column */ + col = *rp++ ; + /* add the column, if alive and untagged */ + col_thickness = Col [col].shared1.thickness ; + if (col_thickness > 0 && COL_IS_ALIVE (col)) + { + /* tag column in pivot row */ + Col [col].shared1.thickness = -col_thickness ; + assert (pfree < Alen) ; + /* place column in pivot row */ + A [pfree++] = col ; + pivot_row_degree += col_thickness ; + } + } + } + + /* clear tag on pivot column */ + Col [pivot_col].shared1.thickness = pivot_col_thickness ; + max_deg = MAX (max_deg, pivot_row_degree) ; + +#ifndef NDEBUG + DEBUG3 (("check2\n")) ; + debug_mark (n_row, Row, tag_mark, max_mark) ; +#endif + + /* === Kill all rows used to construct pivot row ==================== */ + + /* also kill pivot row, temporarily */ + cp = &A [Col [pivot_col].start] ; + cp_end = cp + Col [pivot_col].length ; + while (cp < cp_end) + { + /* may be killing an already dead row */ + row = *cp++ ; + DEBUG2 (("Kill row in pivot col: %d\n", row)) ; + KILL_ROW (row) ; + } + + /* === Select a row index to use as the new pivot row =============== */ + + pivot_row_length = pfree - pivot_row_start ; + if (pivot_row_length > 0) + { + /* pick the "pivot" row arbitrarily (first row in col) */ + pivot_row = A [Col [pivot_col].start] ; + DEBUG2 (("Pivotal row is %d\n", pivot_row)) ; + } + else + { + /* there is no pivot row, since it is of zero length */ + pivot_row = EMPTY ; + assert (pivot_row_length == 0) ; + } + assert (Col [pivot_col].length > 0 || pivot_row_length == 0) ; + + /* === Approximate degree computation =============================== */ + + /* Here begins the computation of the approximate degree. The column */ + /* score is the sum of the pivot row "length", plus the size of the */ + /* set differences of each row in the column minus the pattern of the */ + /* pivot row itself. The column ("thickness") itself is also */ + /* excluded from the column score (we thus use an approximate */ + /* external degree). */ + + /* The time taken by the following code (compute set differences, and */ + /* add them up) is proportional to the size of the data structure */ + /* being scanned - that is, the sum of the sizes of each column in */ + /* the pivot row. Thus, the amortized time to compute a column score */ + /* is proportional to the size of that column (where size, in this */ + /* context, is the column "length", or the number of row indices */ + /* in that column). The number of row indices in a column is */ + /* monotonically non-decreasing, from the length of the original */ + /* column on input to colamd. */ + + /* === Compute set differences ====================================== */ + + DEBUG1 (("** Computing set differences phase. **\n")) ; + + /* pivot row is currently dead - it will be revived later. */ + + DEBUG2 (("Pivot row: ")) ; + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + col = *rp++ ; + assert (COL_IS_ALIVE (col) && col != pivot_col) ; + DEBUG2 (("Col: %d\n", col)) ; + + /* clear tags used to construct pivot row pattern */ + col_thickness = -Col [col].shared1.thickness ; + assert (col_thickness > 0) ; + Col [col].shared1.thickness = col_thickness ; + + /* === Remove column from degree list =========================== */ + + cur_score = Col [col].shared2.score ; + prev_col = Col [col].shared3.prev ; + next_col = Col [col].shared4.degree_next ; + assert (cur_score >= 0) ; + assert (cur_score <= n_col) ; + assert (cur_score >= EMPTY) ; + if (prev_col == EMPTY) + { + head [cur_score] = next_col ; + } + else + { + Col [prev_col].shared4.degree_next = next_col ; + } + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = prev_col ; + } + + /* === Scan the column ========================================== */ + + cp = &A [Col [col].start] ; + cp_end = cp + Col [col].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + row_mark = Row [row].shared2.mark ; + /* skip if dead */ + if (ROW_IS_MARKED_DEAD (row_mark)) + { + continue ; + } + assert (row != pivot_row) ; + set_difference = row_mark - tag_mark ; + /* check if the row has been seen yet */ + if (set_difference < 0) + { + assert (Row [row].shared1.degree <= max_deg) ; + set_difference = Row [row].shared1.degree ; + } + /* subtract column thickness from this row's set difference */ + set_difference -= col_thickness ; + assert (set_difference >= 0) ; + /* absorb this row if the set difference becomes zero */ + if (set_difference == 0) + { + DEBUG1 (("aggressive absorption. Row: %d\n", row)) ; + KILL_ROW (row) ; + } + else + { + /* save the new mark */ + Row [row].shared2.mark = set_difference + tag_mark ; + } + } + } + +#ifndef NDEBUG + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k-pivot_row_degree, max_deg) ; +#endif + + /* === Add up set differences for each column ======================= */ + + DEBUG1 (("** Adding set differences phase. **\n")) ; + + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + /* get a column */ + col = *rp++ ; + assert (COL_IS_ALIVE (col) && col != pivot_col) ; + hash = 0 ; + cur_score = 0 ; + cp = &A [Col [col].start] ; + /* compact the column */ + new_cp = cp ; + cp_end = cp + Col [col].length ; + + DEBUG2 (("Adding set diffs for Col: %d.\n", col)) ; + + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + assert(row >= 0 && row < n_row) ; + row_mark = Row [row].shared2.mark ; + /* skip if dead */ + if (ROW_IS_MARKED_DEAD (row_mark)) + { + continue ; + } + assert (row_mark > tag_mark) ; + /* compact the column */ + *new_cp++ = row ; + /* compute hash function */ + hash += row ; + /* add set difference */ + cur_score += row_mark - tag_mark ; + /* integer overflow... */ + cur_score = MIN (cur_score, n_col) ; + } + + /* recompute the column's length */ + Col [col].length = (int) (new_cp - &A [Col [col].start]) ; + + /* === Further mass elimination ================================= */ + + if (Col [col].length == 0) + { + DEBUG1 (("further mass elimination. Col: %d\n", col)) ; + /* nothing left but the pivot row in this column */ + KILL_PRINCIPAL_COL (col) ; + pivot_row_degree -= Col [col].shared1.thickness ; + assert (pivot_row_degree >= 0) ; + /* order it */ + Col [col].shared2.order = k ; + /* increment order count by column thickness */ + k += Col [col].shared1.thickness ; + } + else + { + /* === Prepare for supercolumn detection ==================== */ + + DEBUG2 (("Preparing supercol detection for Col: %d.\n", col)) ; + + /* save score so far */ + Col [col].shared2.score = cur_score ; + + /* add column to hash table, for supercolumn detection */ + hash %= n_col + 1 ; + + DEBUG2 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ; + assert (hash <= n_col) ; + + head_column = head [hash] ; + if (head_column > EMPTY) + { + /* degree list "hash" is non-empty, use prev (shared3) of */ + /* first column in degree list as head of hash bucket */ + first_col = Col [head_column].shared3.headhash ; + Col [head_column].shared3.headhash = col ; + } + else + { + /* degree list "hash" is empty, use head as hash bucket */ + first_col = - (head_column + 2) ; + head [hash] = - (col + 2) ; + } + Col [col].shared4.hash_next = first_col ; + + /* save hash function in Col [col].shared3.hash */ + Col [col].shared3.hash = (int) hash ; + assert (COL_IS_ALIVE (col)) ; + } + } + + /* The approximate external column degree is now computed. */ + + /* === Supercolumn detection ======================================== */ + + DEBUG1 (("** Supercolumn detection phase. **\n")) ; + + detect_super_cols ( +#ifndef NDEBUG + n_col, Row, +#endif + Col, A, head, pivot_row_start, pivot_row_length) ; + + /* === Kill the pivotal column ====================================== */ + + KILL_PRINCIPAL_COL (pivot_col) ; + + /* === Clear mark =================================================== */ + + tag_mark += (max_deg + 1) ; + if (tag_mark >= max_mark) + { + DEBUG1 (("clearing tag_mark\n")) ; + tag_mark = clear_mark (n_row, Row) ; + } +#ifndef NDEBUG + DEBUG3 (("check3\n")) ; + debug_mark (n_row, Row, tag_mark, max_mark) ; +#endif + + /* === Finalize the new pivot row, and column scores ================ */ + + DEBUG1 (("** Finalize scores phase. **\n")) ; + + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + /* compact the pivot row */ + new_rp = rp ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + col = *rp++ ; + /* skip dead columns */ + if (COL_IS_DEAD (col)) + { + continue ; + } + *new_rp++ = col ; + /* add new pivot row to column */ + A [Col [col].start + (Col [col].length++)] = pivot_row ; + + /* retrieve score so far and add on pivot row's degree. */ + /* (we wait until here for this in case the pivot */ + /* row's degree was reduced due to mass elimination). */ + cur_score = Col [col].shared2.score + pivot_row_degree ; + + /* calculate the max possible score as the number of */ + /* external columns minus the 'k' value minus the */ + /* columns thickness */ + max_score = n_col - k - Col [col].shared1.thickness ; + + /* make the score the external degree of the union-of-rows */ + cur_score -= Col [col].shared1.thickness ; + + /* make sure score is less or equal than the max score */ + cur_score = MIN (cur_score, max_score) ; + assert (cur_score >= 0) ; + + /* store updated score */ + Col [col].shared2.score = cur_score ; + + /* === Place column back in degree list ========================= */ + + assert (min_score >= 0) ; + assert (min_score <= n_col) ; + assert (cur_score >= 0) ; + assert (cur_score <= n_col) ; + assert (head [cur_score] >= EMPTY) ; + next_col = head [cur_score] ; + Col [col].shared4.degree_next = next_col ; + Col [col].shared3.prev = EMPTY ; + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = col ; + } + head [cur_score] = col ; + + /* see if this score is less than current min */ + min_score = MIN (min_score, cur_score) ; + + } + +#ifndef NDEBUG + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k, max_deg) ; +#endif + + /* === Resurrect the new pivot row ================================== */ + + if (pivot_row_degree > 0) + { + /* update pivot row length to reflect any cols that were killed */ + /* during super-col detection and mass elimination */ + Row [pivot_row].start = pivot_row_start ; + Row [pivot_row].length = (int) (new_rp - &A[pivot_row_start]) ; + Row [pivot_row].shared1.degree = pivot_row_degree ; + Row [pivot_row].shared2.mark = 0 ; + /* pivot row is no longer dead */ + } + } + + /* === All principal columns have now been ordered ====================== */ + + return (ngarbage) ; +} + + +/* ========================================================================== */ +/* === order_children ======================================================= */ +/* ========================================================================== */ + +/* + The find_ordering routine has ordered all of the principal columns (the + representatives of the supercolumns). The non-principal columns have not + yet been ordered. This routine orders those columns by walking up the + parent tree (a column is a child of the column which absorbed it). The + final permutation vector is then placed in p [0 ... n_col-1], with p [0] + being the first column, and p [n_col-1] being the last. It doesn't look + like it at first glance, but be assured that this routine takes time linear + in the number of columns. Although not immediately obvious, the time + taken by this routine is O (n_col), that is, linear in the number of + columns. Not user-callable. +*/ + +PRIVATE void order_children +( + /* === Parameters ======================================================= */ + + int n_col, /* number of columns of A */ + ColInfo Col [], /* of size n_col+1 */ + int p [] /* p [0 ... n_col-1] is the column permutation*/ +) +{ + /* === Local variables ================================================== */ + + int i ; /* loop counter for all columns */ + int c ; /* column index */ + int parent ; /* index of column's parent */ + int order ; /* column's order */ + + /* === Order each non-principal column ================================== */ + + for (i = 0 ; i < n_col ; i++) + { + /* find an un-ordered non-principal column */ + assert (COL_IS_DEAD (i)) ; + if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY) + { + parent = i ; + /* once found, find its principal parent */ + do + { + parent = Col [parent].shared1.parent ; + } while (!COL_IS_DEAD_PRINCIPAL (parent)) ; + + /* now, order all un-ordered non-principal columns along path */ + /* to this parent. collapse tree at the same time */ + c = i ; + /* get order of parent */ + order = Col [parent].shared2.order ; + + do + { + assert (Col [c].shared2.order == EMPTY) ; + + /* order this column */ + Col [c].shared2.order = order++ ; + /* collaps tree */ + Col [c].shared1.parent = parent ; + + /* get immediate parent of this column */ + c = Col [c].shared1.parent ; + + /* continue until we hit an ordered column. There are */ + /* guarranteed not to be anymore unordered columns */ + /* above an ordered column */ + } while (Col [c].shared2.order == EMPTY) ; + + /* re-order the super_col parent to largest order for this group */ + Col [parent].shared2.order = order ; + } + } + + /* === Generate the permutation ========================================= */ + + for (c = 0 ; c < n_col ; c++) + { + p [Col [c].shared2.order] = c ; + } +} + + +/* ========================================================================== */ +/* === detect_super_cols ==================================================== */ +/* ========================================================================== */ + +/* + Detects supercolumns by finding matches between columns in the hash buckets. + Check amongst columns in the set A [row_start ... row_start + row_length-1]. + The columns under consideration are currently *not* in the degree lists, + and have already been placed in the hash buckets. + + The hash bucket for columns whose hash function is equal to h is stored + as follows: + + if head [h] is >= 0, then head [h] contains a degree list, so: + + head [h] is the first column in degree bucket h. + Col [head [h]].headhash gives the first column in hash bucket h. + + otherwise, the degree list is empty, and: + + -(head [h] + 2) is the first column in hash bucket h. + + For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous + column" pointer. Col [c].shared3.hash is used instead as the hash number + for that column. The value of Col [c].shared4.hash_next is the next column + in the same hash bucket. + + Assuming no, or "few" hash collisions, the time taken by this routine is + linear in the sum of the sizes (lengths) of each column whose score has + just been computed in the approximate degree computation. + Not user-callable. +*/ + +PRIVATE void detect_super_cols +( + /* === Parameters ======================================================= */ + +#ifndef NDEBUG + /* these two parameters are only needed when debugging is enabled: */ + int n_col, /* number of columns of A */ + RowInfo Row [], /* of size n_row+1 */ +#endif + ColInfo Col [], /* of size n_col+1 */ + int A [], /* row indices of A */ + int head [], /* head of degree lists and hash buckets */ + int row_start, /* pointer to set of columns to check */ + int row_length /* number of columns to check */ +) +{ + /* === Local variables ================================================== */ + + int hash ; /* hash # for a column */ + int *rp ; /* pointer to a row */ + int c ; /* a column index */ + int super_c ; /* column index of the column to absorb into */ + int *cp1 ; /* column pointer for column super_c */ + int *cp2 ; /* column pointer for column c */ + int length ; /* length of column super_c */ + int prev_c ; /* column preceding c in hash bucket */ + int i ; /* loop counter */ + int *rp_end ; /* pointer to the end of the row */ + int col ; /* a column index in the row to check */ + int head_column ; /* first column in hash bucket or degree list */ + int first_col ; /* first column in hash bucket */ + + /* === Consider each column in the row ================================== */ + + rp = &A [row_start] ; + rp_end = rp + row_length ; + while (rp < rp_end) + { + col = *rp++ ; + if (COL_IS_DEAD (col)) + { + continue ; + } + + /* get hash number for this column */ + hash = Col [col].shared3.hash ; + assert (hash <= n_col) ; + + /* === Get the first column in this hash bucket ===================== */ + + head_column = head [hash] ; + if (head_column > EMPTY) + { + first_col = Col [head_column].shared3.headhash ; + } + else + { + first_col = - (head_column + 2) ; + } + + /* === Consider each column in the hash bucket ====================== */ + + for (super_c = first_col ; super_c != EMPTY ; + super_c = Col [super_c].shared4.hash_next) + { + assert (COL_IS_ALIVE (super_c)) ; + assert (Col [super_c].shared3.hash == hash) ; + length = Col [super_c].length ; + + /* prev_c is the column preceding column c in the hash bucket */ + prev_c = super_c ; + + /* === Compare super_c with all columns after it ================ */ + + for (c = Col [super_c].shared4.hash_next ; + c != EMPTY ; c = Col [c].shared4.hash_next) + { + assert (c != super_c) ; + assert (COL_IS_ALIVE (c)) ; + assert (Col [c].shared3.hash == hash) ; + + /* not identical if lengths or scores are different */ + if (Col [c].length != length || + Col [c].shared2.score != Col [super_c].shared2.score) + { + prev_c = c ; + continue ; + } + + /* compare the two columns */ + cp1 = &A [Col [super_c].start] ; + cp2 = &A [Col [c].start] ; + + for (i = 0 ; i < length ; i++) + { + /* the columns are "clean" (no dead rows) */ + assert (ROW_IS_ALIVE (*cp1)) ; + assert (ROW_IS_ALIVE (*cp2)) ; + /* row indices will same order for both supercols, */ + /* no gather scatter nessasary */ + if (*cp1++ != *cp2++) + { + break ; + } + } + + /* the two columns are different if the for-loop "broke" */ + if (i != length) + { + prev_c = c ; + continue ; + } + + /* === Got it! two columns are identical =================== */ + + assert (Col [c].shared2.score == Col [super_c].shared2.score) ; + + Col [super_c].shared1.thickness += Col [c].shared1.thickness ; + Col [c].shared1.parent = super_c ; + KILL_NON_PRINCIPAL_COL (c) ; + /* order c later, in order_children() */ + Col [c].shared2.order = EMPTY ; + /* remove c from hash bucket */ + Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; + } + } + + /* === Empty this hash bucket ======================================= */ + + if (head_column > EMPTY) + { + /* corresponding degree list "hash" is not empty */ + Col [head_column].shared3.headhash = EMPTY ; + } + else + { + /* corresponding degree list "hash" is empty */ + head [hash] = EMPTY ; + } + } +} + + +/* ========================================================================== */ +/* === garbage_collection =================================================== */ +/* ========================================================================== */ + +/* + Defragments and compacts columns and rows in the workspace A. Used when + all avaliable memory has been used while performing row merging. Returns + the index of the first free position in A, after garbage collection. The + time taken by this routine is linear is the size of the array A, which is + itself linear in the number of nonzeros in the input matrix. + Not user-callable. +*/ + +PRIVATE int garbage_collection /* returns the new value of pfree */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows */ + int n_col, /* number of columns */ + RowInfo Row [], /* row info */ + ColInfo Col [], /* column info */ + int A [], /* A [0 ... Alen-1] holds the matrix */ + int *pfree /* &A [0] ... pfree is in use */ +) +{ + /* === Local variables ================================================== */ + + int *psrc ; /* source pointer */ + int *pdest ; /* destination pointer */ + int j ; /* counter */ + int r ; /* a row index */ + int c ; /* a column index */ + int length ; /* length of a row or column */ + +#ifndef NDEBUG + int debug_rows ; + DEBUG0 (("Defrag..\n")) ; + for (psrc = &A[0] ; psrc < pfree ; psrc++) assert (*psrc >= 0) ; + debug_rows = 0 ; +#endif + + /* === Defragment the columns =========================================== */ + + pdest = &A[0] ; + for (c = 0 ; c < n_col ; c++) + { + if (COL_IS_ALIVE (c)) + { + psrc = &A [Col [c].start] ; + + /* move and compact the column */ + assert (pdest <= psrc) ; + Col [c].start = (int) (pdest - &A [0]) ; + length = Col [c].length ; + for (j = 0 ; j < length ; j++) + { + r = *psrc++ ; + if (ROW_IS_ALIVE (r)) + { + *pdest++ = r ; + } + } + Col [c].length = (int) (pdest - &A [Col [c].start]) ; + } + } + + /* === Prepare to defragment the rows =================================== */ + + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_ALIVE (r)) + { + if (Row [r].length == 0) + { + /* this row is of zero length. cannot compact it, so kill it */ + DEBUG0 (("Defrag row kill\n")) ; + KILL_ROW (r) ; + } + else + { + /* save first column index in Row [r].shared2.first_column */ + psrc = &A [Row [r].start] ; + Row [r].shared2.first_column = *psrc ; + assert (ROW_IS_ALIVE (r)) ; + /* flag the start of the row with the one's complement of row */ + *psrc = ONES_COMPLEMENT (r) ; +#ifndef NDEBUG + debug_rows++ ; +#endif + } + } + } + + /* === Defragment the rows ============================================== */ + + psrc = pdest ; + while (psrc < pfree) + { + /* find a negative number ... the start of a row */ + if (*psrc++ < 0) + { + psrc-- ; + /* get the row index */ + r = ONES_COMPLEMENT (*psrc) ; + assert (r >= 0 && r < n_row) ; + /* restore first column index */ + *psrc = Row [r].shared2.first_column ; + assert (ROW_IS_ALIVE (r)) ; + + /* move and compact the row */ + assert (pdest <= psrc) ; + Row [r].start = (int) (pdest - &A [0]) ; + length = Row [r].length ; + for (j = 0 ; j < length ; j++) + { + c = *psrc++ ; + if (COL_IS_ALIVE (c)) + { + *pdest++ = c ; + } + } + Row [r].length = (int) (pdest - &A [Row [r].start]) ; +#ifndef NDEBUG + debug_rows-- ; +#endif + } + } + /* ensure we found all the rows */ + assert (debug_rows == 0) ; + + /* === Return the new value of pfree ==================================== */ + + return ((int) (pdest - &A [0])) ; +} + + +/* ========================================================================== */ +/* === clear_mark =========================================================== */ +/* ========================================================================== */ + +/* + Clears the Row [].shared2.mark array, and returns the new tag_mark. + Return value is the new tag_mark. Not user-callable. +*/ + +PRIVATE int clear_mark /* return the new value for tag_mark */ +( + /* === Parameters ======================================================= */ + + int n_row, /* number of rows in A */ + RowInfo Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */ +) +{ + /* === Local variables ================================================== */ + + int r ; + + DEBUG0 (("Clear mark\n")) ; + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_ALIVE (r)) + { + Row [r].shared2.mark = 0 ; + } + } + return (1) ; +} + + +/* ========================================================================== */ +/* === debugging routines =================================================== */ +/* ========================================================================== */ + +/* When debugging is disabled, the remainder of this file is ignored. */ + +#ifndef NDEBUG + + +/* ========================================================================== */ +/* === debug_structures ===================================================== */ +/* ========================================================================== */ + +/* + At this point, all empty rows and columns are dead. All live columns + are "clean" (containing no dead rows) and simplicial (no supercolumns + yet). Rows may contain dead columns, but all live rows contain at + least one live column. +*/ + +PRIVATE void debug_structures +( + /* === Parameters ======================================================= */ + + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [], + int n_col2 +) +{ + /* === Local variables ================================================== */ + + int i ; + int c ; + int *cp ; + int *cp_end ; + int len ; + int score ; + int r ; + int *rp ; + int *rp_end ; + int deg ; + + /* === Check A, Row, and Col ============================================ */ + + for (c = 0 ; c < n_col ; c++) + { + if (COL_IS_ALIVE (c)) + { + len = Col [c].length ; + score = Col [c].shared2.score ; + DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ; + assert (len > 0) ; + assert (score >= 0) ; + assert (Col [c].shared1.thickness == 1) ; + cp = &A [Col [c].start] ; + cp_end = cp + len ; + while (cp < cp_end) + { + r = *cp++ ; + assert (ROW_IS_ALIVE (r)) ; + } + } + else + { + i = Col [c].shared2.order ; + assert (i >= n_col2 && i < n_col) ; + } + } + + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_ALIVE (r)) + { + i = 0 ; + len = Row [r].length ; + deg = Row [r].shared1.degree ; + assert (len > 0) ; + assert (deg > 0) ; + rp = &A [Row [r].start] ; + rp_end = rp + len ; + while (rp < rp_end) + { + c = *rp++ ; + if (COL_IS_ALIVE (c)) + { + i++ ; + } + } + assert (i > 0) ; + } + } +} + + +/* ========================================================================== */ +/* === debug_deg_lists ====================================================== */ +/* ========================================================================== */ + +/* + Prints the contents of the degree lists. Counts the number of columns + in the degree list and compares it to the total it should have. Also + checks the row degrees. +*/ + +PRIVATE void debug_deg_lists +( + /* === Parameters ======================================================= */ + + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int head [], + int min_score, + int should, + int max_deg +) +{ + /* === Local variables ================================================== */ + + int deg ; + int col ; + int have ; + int row ; + + /* === Check the degree lists =========================================== */ + + if (n_col > 10000 && debug_colamd <= 0) + { + return ; + } + have = 0 ; + DEBUG4 (("Degree lists: %d\n", min_score)) ; + for (deg = 0 ; deg <= n_col ; deg++) + { + col = head [deg] ; + if (col == EMPTY) + { + continue ; + } + DEBUG4 (("%d:", deg)) ; + while (col != EMPTY) + { + DEBUG4 ((" %d", col)) ; + have += Col [col].shared1.thickness ; + assert (COL_IS_ALIVE (col)) ; + col = Col [col].shared4.degree_next ; + } + DEBUG4 (("\n")) ; + } + DEBUG4 (("should %d have %d\n", should, have)) ; + assert (should == have) ; + + /* === Check the row degrees ============================================ */ + + if (n_row > 10000 && debug_colamd <= 0) + { + return ; + } + for (row = 0 ; row < n_row ; row++) + { + if (ROW_IS_ALIVE (row)) + { + assert (Row [row].shared1.degree <= max_deg) ; + } + } +} + + +/* ========================================================================== */ +/* === debug_mark =========================================================== */ +/* ========================================================================== */ + +/* + Ensures that the tag_mark is less that the maximum and also ensures that + each entry in the mark array is less than the tag mark. +*/ + +PRIVATE void debug_mark +( + /* === Parameters ======================================================= */ + + int n_row, + RowInfo Row [], + int tag_mark, + int max_mark +) +{ + /* === Local variables ================================================== */ + + int r ; + + /* === Check the Row marks ============================================== */ + + assert (tag_mark > 0 && tag_mark <= max_mark) ; + if (n_row > 10000 && debug_colamd <= 0) + { + return ; + } + for (r = 0 ; r < n_row ; r++) + { + assert (Row [r].shared2.mark < tag_mark) ; + } +} + + +/* ========================================================================== */ +/* === debug_matrix ========================================================= */ +/* ========================================================================== */ + +/* + Prints out the contents of the columns and the rows. +*/ + +PRIVATE void debug_matrix +( + /* === Parameters ======================================================= */ + + int n_row, + int n_col, + RowInfo Row [], + ColInfo Col [], + int A [] +) +{ + /* === Local variables ================================================== */ + + int r ; + int c ; + int *rp ; + int *rp_end ; + int *cp ; + int *cp_end ; + + /* === Dump the rows and columns of the matrix ========================== */ + + if (debug_colamd < 3) + { + return ; + } + DEBUG3 (("DUMP MATRIX:\n")) ; + for (r = 0 ; r < n_row ; r++) + { + DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ; + if (ROW_IS_DEAD (r)) + { + continue ; + } + DEBUG3 (("start %d length %d degree %d\n", + Row [r].start, Row [r].length, Row [r].shared1.degree)) ; + rp = &A [Row [r].start] ; + rp_end = rp + Row [r].length ; + while (rp < rp_end) + { + c = *rp++ ; + DEBUG3 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ; + } + } + + for (c = 0 ; c < n_col ; c++) + { + DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ; + if (COL_IS_DEAD (c)) + { + continue ; + } + DEBUG3 (("start %d length %d shared1 %d shared2 %d\n", + Col [c].start, Col [c].length, + Col [c].shared1.thickness, Col [c].shared2.score)) ; + cp = &A [Col [c].start] ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + r = *cp++ ; + DEBUG3 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ; + } + } +} + +#endif + diff --git a/intern/opennl/superlu/colamd.h b/intern/opennl/superlu/colamd.h new file mode 100644 index 00000000000..00783983b27 --- /dev/null +++ b/intern/opennl/superlu/colamd.h @@ -0,0 +1,67 @@ +/* ========================================================================== */ +/* === colamd prototypes and definitions ==================================== */ +/* ========================================================================== */ + +/* + This is the colamd include file, + + http://www.cise.ufl.edu/~davis/colamd/colamd.h + + for use in the colamd.c, colamdmex.c, and symamdmex.c files located at + + http://www.cise.ufl.edu/~davis/colamd/ + + See those files for a description of colamd and symamd, and for the + copyright notice, which also applies to this file. + + August 3, 1998. Version 1.0. +*/ + +/* ========================================================================== */ +/* === Definitions ========================================================== */ +/* ========================================================================== */ + +/* size of the knobs [ ] array. Only knobs [0..1] are currently used. */ +#define COLAMD_KNOBS 20 + +/* number of output statistics. Only A [0..2] are currently used. */ +#define COLAMD_STATS 20 + +/* knobs [0] and A [0]: dense row knob and output statistic. */ +#define COLAMD_DENSE_ROW 0 + +/* knobs [1] and A [1]: dense column knob and output statistic. */ +#define COLAMD_DENSE_COL 1 + +/* A [2]: memory defragmentation count output statistic */ +#define COLAMD_DEFRAG_COUNT 2 + +/* A [3]: whether or not the input columns were jumbled or had duplicates */ +#define COLAMD_JUMBLED_COLS 3 + +/* ========================================================================== */ +/* === Prototypes of user-callable routines ================================= */ +/* ========================================================================== */ + +int colamd_recommended /* returns recommended value of Alen */ +( + int nnz, /* nonzeros in A */ + int n_row, /* number of rows in A */ + int n_col /* number of columns in A */ +) ; + +void colamd_set_defaults /* sets default parameters */ +( /* knobs argument is modified on output */ + double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ +) ; + +int colamd /* returns TRUE if successful, FALSE otherwise*/ +( /* A and p arguments are modified on output */ + int n_row, /* number of rows in A */ + int n_col, /* number of columns in A */ + int Alen, /* size of the array A */ + int A [], /* row indices of A, of size Alen */ + int p [], /* column pointers of A, of size n_col+1 */ + double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ +) ; + diff --git a/intern/opennl/superlu/get_perm_c.c b/intern/opennl/superlu/get_perm_c.c new file mode 100644 index 00000000000..e255b4a76bd --- /dev/null +++ b/intern/opennl/superlu/get_perm_c.c @@ -0,0 +1,453 @@ +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ + +#include "ssp_defs.h" +#include "colamd.h" + +extern int genmmd_(int *, int *, int *, int *, int *, int *, int *, + int *, int *, int *, int *, int *); + +static void +get_colamd( + const int m, /* number of rows in matrix A. */ + const int n, /* number of columns in matrix A. */ + const int nnz,/* number of nonzeros in matrix A. */ + int *colptr, /* column pointer of size n+1 for matrix A. */ + int *rowind, /* row indices of size nz for matrix A. */ + int *perm_c /* out - the column permutation vector. */ + ) +{ + int Alen, *A, i, info, *p; + double *knobs; + + Alen = colamd_recommended(nnz, m, n); + + if ( !(knobs = (double *) SUPERLU_MALLOC(COLAMD_KNOBS * sizeof(double))) ) + ABORT("Malloc fails for knobs"); + colamd_set_defaults(knobs); + + if (!(A = (int *) SUPERLU_MALLOC(Alen * sizeof(int))) ) + ABORT("Malloc fails for A[]"); + if (!(p = (int *) SUPERLU_MALLOC((n+1) * sizeof(int))) ) + ABORT("Malloc fails for p[]"); + for (i = 0; i <= n; ++i) p[i] = colptr[i]; + for (i = 0; i < nnz; ++i) A[i] = rowind[i]; + info = colamd(m, n, Alen, A, p, knobs); + if ( info == FALSE ) ABORT("COLAMD failed"); + + for (i = 0; i < n; ++i) perm_c[p[i]] = i; + + SUPERLU_FREE(knobs); + SUPERLU_FREE(A); + SUPERLU_FREE(p); +} + +static void +getata( + const int m, /* number of rows in matrix A. */ + const int n, /* number of columns in matrix A. */ + const int nz, /* number of nonzeros in matrix A */ + int *colptr, /* column pointer of size n+1 for matrix A. */ + int *rowind, /* row indices of size nz for matrix A. */ + int *atanz, /* out - on exit, returns the actual number of + nonzeros in matrix A'*A. */ + int **ata_colptr, /* out - size n+1 */ + int **ata_rowind /* out - size *atanz */ + ) +/* + * Purpose + * ======= + * + * Form the structure of A'*A. A is an m-by-n matrix in column oriented + * format represented by (colptr, rowind). The output A'*A is in column + * oriented format (symmetrically, also row oriented), represented by + * (ata_colptr, ata_rowind). + * + * This routine is modified from GETATA routine by Tim Davis. + * The complexity of this algorithm is: SUM_{i=1,m} r(i)^2, + * i.e., the sum of the square of the row counts. + * + * Questions + * ========= + * o Do I need to withhold the *dense* rows? + * o How do I know the number of nonzeros in A'*A? + * + */ +{ + register int i, j, k, col, num_nz, ti, trow; + int *marker, *b_colptr, *b_rowind; + int *t_colptr, *t_rowind; /* a column oriented form of T = A' */ + + if ( !(marker = (int*) SUPERLU_MALLOC((SUPERLU_MAX(m,n)+1)*sizeof(int))) ) + ABORT("SUPERLU_MALLOC fails for marker[]"); + if ( !(t_colptr = (int*) SUPERLU_MALLOC((m+1) * sizeof(int))) ) + ABORT("SUPERLU_MALLOC t_colptr[]"); + if ( !(t_rowind = (int*) SUPERLU_MALLOC(nz * sizeof(int))) ) + ABORT("SUPERLU_MALLOC fails for t_rowind[]"); + + + /* Get counts of each column of T, and set up column pointers */ + for (i = 0; i < m; ++i) marker[i] = 0; + for (j = 0; j < n; ++j) { + for (i = colptr[j]; i < colptr[j+1]; ++i) + ++marker[rowind[i]]; + } + t_colptr[0] = 0; + for (i = 0; i < m; ++i) { + t_colptr[i+1] = t_colptr[i] + marker[i]; + marker[i] = t_colptr[i]; + } + + /* Transpose the matrix from A to T */ + for (j = 0; j < n; ++j) + for (i = colptr[j]; i < colptr[j+1]; ++i) { + col = rowind[i]; + t_rowind[marker[col]] = j; + ++marker[col]; + } + + + /* ---------------------------------------------------------------- + compute B = T * A, where column j of B is: + + Struct (B_*j) = UNION ( Struct (T_*k) ) + A_kj != 0 + + do not include the diagonal entry + + ( Partition A as: A = (A_*1, ..., A_*n) + Then B = T * A = (T * A_*1, ..., T * A_*n), where + T * A_*j = (T_*1, ..., T_*m) * A_*j. ) + ---------------------------------------------------------------- */ + + /* Zero the diagonal flag */ + for (i = 0; i < n; ++i) marker[i] = -1; + + /* First pass determines number of nonzeros in B */ + num_nz = 0; + for (j = 0; j < n; ++j) { + /* Flag the diagonal so it's not included in the B matrix */ + marker[j] = j; + + for (i = colptr[j]; i < colptr[j+1]; ++i) { + /* A_kj is nonzero, add pattern of column T_*k to B_*j */ + k = rowind[i]; + for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { + trow = t_rowind[ti]; + if ( marker[trow] != j ) { + marker[trow] = j; + num_nz++; + } + } + } + } + *atanz = num_nz; + + /* Allocate storage for A'*A */ + if ( !(*ata_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for ata_colptr[]"); + if ( *atanz ) { + if ( !(*ata_rowind = (int*) SUPERLU_MALLOC( *atanz * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for ata_rowind[]"); + } + b_colptr = *ata_colptr; /* aliasing */ + b_rowind = *ata_rowind; + + /* Zero the diagonal flag */ + for (i = 0; i < n; ++i) marker[i] = -1; + + /* Compute each column of B, one at a time */ + num_nz = 0; + for (j = 0; j < n; ++j) { + b_colptr[j] = num_nz; + + /* Flag the diagonal so it's not included in the B matrix */ + marker[j] = j; + + for (i = colptr[j]; i < colptr[j+1]; ++i) { + /* A_kj is nonzero, add pattern of column T_*k to B_*j */ + k = rowind[i]; + for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { + trow = t_rowind[ti]; + if ( marker[trow] != j ) { + marker[trow] = j; + b_rowind[num_nz++] = trow; + } + } + } + } + b_colptr[n] = num_nz; + + SUPERLU_FREE(marker); + SUPERLU_FREE(t_colptr); + SUPERLU_FREE(t_rowind); +} + + +static void +at_plus_a( + const int n, /* number of columns in matrix A. */ + const int nz, /* number of nonzeros in matrix A */ + int *colptr, /* column pointer of size n+1 for matrix A. */ + int *rowind, /* row indices of size nz for matrix A. */ + int *bnz, /* out - on exit, returns the actual number of + nonzeros in matrix A'*A. */ + int **b_colptr, /* out - size n+1 */ + int **b_rowind /* out - size *bnz */ + ) +{ +/* + * Purpose + * ======= + * + * Form the structure of A'+A. A is an n-by-n matrix in column oriented + * format represented by (colptr, rowind). The output A'+A is in column + * oriented format (symmetrically, also row oriented), represented by + * (b_colptr, b_rowind). + * + */ + register int i, j, k, col, num_nz; + int *t_colptr, *t_rowind; /* a column oriented form of T = A' */ + int *marker; + + if ( !(marker = (int*) SUPERLU_MALLOC( n * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for marker[]"); + if ( !(t_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for t_colptr[]"); + if ( !(t_rowind = (int*) SUPERLU_MALLOC( nz * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails t_rowind[]"); + + + /* Get counts of each column of T, and set up column pointers */ + for (i = 0; i < n; ++i) marker[i] = 0; + for (j = 0; j < n; ++j) { + for (i = colptr[j]; i < colptr[j+1]; ++i) + ++marker[rowind[i]]; + } + t_colptr[0] = 0; + for (i = 0; i < n; ++i) { + t_colptr[i+1] = t_colptr[i] + marker[i]; + marker[i] = t_colptr[i]; + } + + /* Transpose the matrix from A to T */ + for (j = 0; j < n; ++j) + for (i = colptr[j]; i < colptr[j+1]; ++i) { + col = rowind[i]; + t_rowind[marker[col]] = j; + ++marker[col]; + } + + + /* ---------------------------------------------------------------- + compute B = A + T, where column j of B is: + + Struct (B_*j) = Struct (A_*k) UNION Struct (T_*k) + + do not include the diagonal entry + ---------------------------------------------------------------- */ + + /* Zero the diagonal flag */ + for (i = 0; i < n; ++i) marker[i] = -1; + + /* First pass determines number of nonzeros in B */ + num_nz = 0; + for (j = 0; j < n; ++j) { + /* Flag the diagonal so it's not included in the B matrix */ + marker[j] = j; + + /* Add pattern of column A_*k to B_*j */ + for (i = colptr[j]; i < colptr[j+1]; ++i) { + k = rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + ++num_nz; + } + } + + /* Add pattern of column T_*k to B_*j */ + for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { + k = t_rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + ++num_nz; + } + } + } + *bnz = num_nz; + + /* Allocate storage for A+A' */ + if ( !(*b_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for b_colptr[]"); + if ( *bnz) { + if ( !(*b_rowind = (int*) SUPERLU_MALLOC( *bnz * sizeof(int)) ) ) + ABORT("SUPERLU_MALLOC fails for b_rowind[]"); + } + + /* Zero the diagonal flag */ + for (i = 0; i < n; ++i) marker[i] = -1; + + /* Compute each column of B, one at a time */ + num_nz = 0; + for (j = 0; j < n; ++j) { + (*b_colptr)[j] = num_nz; + + /* Flag the diagonal so it's not included in the B matrix */ + marker[j] = j; + + /* Add pattern of column A_*k to B_*j */ + for (i = colptr[j]; i < colptr[j+1]; ++i) { + k = rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + (*b_rowind)[num_nz++] = k; + } + } + + /* Add pattern of column T_*k to B_*j */ + for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { + k = t_rowind[i]; + if ( marker[k] != j ) { + marker[k] = j; + (*b_rowind)[num_nz++] = k; + } + } + } + (*b_colptr)[n] = num_nz; + + SUPERLU_FREE(marker); + SUPERLU_FREE(t_colptr); + SUPERLU_FREE(t_rowind); +} + +void +get_perm_c(int ispec, SuperMatrix *A, int *perm_c) +/* + * Purpose + * ======= + * + * GET_PERM_C obtains a permutation matrix Pc, by applying the multiple + * minimum degree ordering code by Joseph Liu to matrix A'*A or A+A'. + * or using approximate minimum degree column ordering by Davis et. al. + * The LU factorization of A*Pc tends to have less fill than the LU + * factorization of A. + * + * Arguments + * ========= + * + * ispec (input) int + * Specifies the type of column ordering to reduce fill: + * = 1: minimum degree on the structure of A^T * A + * = 2: minimum degree on the structure of A^T + A + * = 3: approximate minimum degree for unsymmetric matrices + * If ispec == 0, the natural ordering (i.e., Pc = I) is returned. + * + * A (input) SuperMatrix* + * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number + * of the linear equations is A->nrow. Currently, the type of A + * can be: Stype = NC; Dtype = _D; Mtype = GE. In the future, + * more general A can be handled. + * + * perm_c (output) int* + * Column permutation vector of size A->ncol, which defines the + * permutation matrix Pc; perm_c[i] = j means column i of A is + * in position j in A*Pc. + * + */ +{ + NCformat *Astore = A->Store; + int m, n, bnz, *b_colptr, i; + int delta, maxint, nofsub, *invp; + int *b_rowind, *dhead, *qsize, *llist, *marker; + double t, SuperLU_timer_(); + + m = A->nrow; + n = A->ncol; + + t = SuperLU_timer_(); + switch ( ispec ) { + case 0: /* Natural ordering */ + for (i = 0; i < n; ++i) perm_c[i] = i; +#if ( PRNTlevel>=1 ) + printf("Use natural column ordering.\n"); +#endif + return; + case 1: /* Minimum degree ordering on A'*A */ + getata(m, n, Astore->nnz, Astore->colptr, Astore->rowind, + &bnz, &b_colptr, &b_rowind); +#if ( PRNTlevel>=1 ) + printf("Use minimum degree ordering on A'*A.\n"); +#endif + t = SuperLU_timer_() - t; + /*printf("Form A'*A time = %8.3f\n", t);*/ + break; + case 2: /* Minimum degree ordering on A'+A */ + if ( m != n ) ABORT("Matrix is not square"); + at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind, + &bnz, &b_colptr, &b_rowind); +#if ( PRNTlevel>=1 ) + printf("Use minimum degree ordering on A'+A.\n"); +#endif + t = SuperLU_timer_() - t; + /*printf("Form A'+A time = %8.3f\n", t);*/ + break; + case 3: /* Approximate minimum degree column ordering. */ + get_colamd(m, n, Astore->nnz, Astore->colptr, Astore->rowind, + perm_c); +#if ( PRNTlevel>=1 ) + printf(".. Use approximate minimum degree column ordering.\n"); +#endif + return; + default: + ABORT("Invalid ISPEC"); + } + + if ( bnz != 0 ) { + t = SuperLU_timer_(); + + /* Initialize and allocate storage for GENMMD. */ + delta = 1; /* DELTA is a parameter to allow the choice of nodes + whose degree <= min-degree + DELTA. */ + maxint = 2147483647; /* 2**31 - 1 */ + invp = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); + if ( !invp ) ABORT("SUPERLU_MALLOC fails for invp."); + dhead = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); + if ( !dhead ) ABORT("SUPERLU_MALLOC fails for dhead."); + qsize = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); + if ( !qsize ) ABORT("SUPERLU_MALLOC fails for qsize."); + llist = (int *) SUPERLU_MALLOC(n*sizeof(int)); + if ( !llist ) ABORT("SUPERLU_MALLOC fails for llist."); + marker = (int *) SUPERLU_MALLOC(n*sizeof(int)); + if ( !marker ) ABORT("SUPERLU_MALLOC fails for marker."); + + /* Transform adjacency list into 1-based indexing required by GENMMD.*/ + for (i = 0; i <= n; ++i) ++b_colptr[i]; + for (i = 0; i < bnz; ++i) ++b_rowind[i]; + + genmmd_(&n, b_colptr, b_rowind, perm_c, invp, &delta, dhead, + qsize, llist, marker, &maxint, &nofsub); + + /* Transform perm_c into 0-based indexing. */ + for (i = 0; i < n; ++i) --perm_c[i]; + + SUPERLU_FREE(b_colptr); + SUPERLU_FREE(b_rowind); + SUPERLU_FREE(invp); + SUPERLU_FREE(dhead); + SUPERLU_FREE(qsize); + SUPERLU_FREE(llist); + SUPERLU_FREE(marker); + + t = SuperLU_timer_() - t; + /* printf("call GENMMD time = %8.3f\n", t);*/ + + } else { /* Empty adjacency structure */ + for (i = 0; i < n; ++i) perm_c[i] = i; + } + +} diff --git a/intern/opennl/superlu/heap_relax_snode.c b/intern/opennl/superlu/heap_relax_snode.c new file mode 100644 index 00000000000..86971f59571 --- /dev/null +++ b/intern/opennl/superlu/heap_relax_snode.c @@ -0,0 +1,116 @@ +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +void +heap_relax_snode ( + const int n, + int *et, /* column elimination tree */ + const int relax_columns, /* max no of columns allowed in a + relaxed snode */ + int *descendants, /* no of descendants of each node + in the etree */ + int *relax_end /* last column in a supernode */ + ) +{ +/* + * Purpose + * ======= + * relax_snode() - Identify the initial relaxed supernodes, assuming that + * the matrix has been reordered according to the postorder of the etree. + * + */ + register int i, j, k, l, parent; + register int snode_start; /* beginning of a snode */ + int *et_save, *post, *inv_post, *iwork; + int nsuper_et = 0, nsuper_et_post = 0; + + /* The etree may not be postordered, but is heap ordered. */ + + iwork = (int*) intMalloc(3*n+2); + if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]"); + inv_post = iwork + n+1; + et_save = inv_post + n+1; + + /* Post order etree */ + post = (int *) TreePostorder(n, et); + for (i = 0; i < n+1; ++i) inv_post[post[i]] = i; + + /* Renumber etree in postorder */ + for (i = 0; i < n; ++i) { + iwork[post[i]] = post[et[i]]; + et_save[i] = et[i]; /* Save the original etree */ + } + for (i = 0; i < n; ++i) et[i] = iwork[i]; + + /* Compute the number of descendants of each node in the etree */ + ifill (relax_end, n, EMPTY); + for (j = 0; j < n; j++) descendants[j] = 0; + for (j = 0; j < n; j++) { + parent = et[j]; + if ( parent != n ) /* not the dummy root */ + descendants[parent] += descendants[j] + 1; + } + + /* Identify the relaxed supernodes by postorder traversal of the etree. */ + for (j = 0; j < n; ) { + parent = et[j]; + snode_start = j; + while ( parent != n && descendants[parent] < relax_columns ) { + j = parent; + parent = et[j]; + } + /* Found a supernode in postordered etree; j is the last column. */ + ++nsuper_et_post; + k = n; + for (i = snode_start; i <= j; ++i) + k = SUPERLU_MIN(k, inv_post[i]); + l = inv_post[j]; + if ( (l - k) == (j - snode_start) ) { + /* It's also a supernode in the original etree */ + relax_end[k] = l; /* Last column is recorded */ + ++nsuper_et; + } else { + for (i = snode_start; i <= j; ++i) { + l = inv_post[i]; + if ( descendants[i] == 0 ) relax_end[l] = l; + } + } + j++; + /* Search for a new leaf */ + while ( descendants[j] != 0 && j < n ) j++; + } + +#if ( PRNTlevel>=1 ) + printf(".. heap_snode_relax:\n" + "\tNo of relaxed snodes in postordered etree:\t%d\n" + "\tNo of relaxed snodes in original etree:\t%d\n", + nsuper_et_post, nsuper_et); +#endif + + /* Recover the original etree */ + for (i = 0; i < n; ++i) et[i] = et_save[i]; + + SUPERLU_FREE(post); + SUPERLU_FREE(iwork); +} + + diff --git a/intern/opennl/superlu/lsame.c b/intern/opennl/superlu/lsame.c new file mode 100644 index 00000000000..79fb4d428a5 --- /dev/null +++ b/intern/opennl/superlu/lsame.c @@ -0,0 +1,73 @@ +int lsame_(char *, char *); + + +int lsame_(char *ca, char *cb) +{ +/* -- LAPACK auxiliary routine (version 2.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 + + Purpose + ======= + + LSAME returns .TRUE. if CA is the same letter as CB regardless of case. + + Arguments + ========= + + CA (input) CHARACTER*1 + CB (input) CHARACTER*1 + CA and CB specify the single characters to be compared. + + ===================================================================== +*/ + + /* System generated locals */ + int ret_val; + + /* Local variables */ + int inta, intb, zcode; + + ret_val = *(unsigned char *)ca == *(unsigned char *)cb; + if (ret_val) { + return ret_val; + } + + /* Now test for equivalence if both characters are alphabetic. */ + + zcode = 'Z'; + + /* Use 'Z' rather than 'A' so that ASCII can be detected on Prime + machines, on which ICHAR returns a value with bit 8 set. + ICHAR('A') on Prime machines returns 193 which is the same as + ICHAR('A') on an EBCDIC machine. */ + + inta = *(unsigned char *)ca; + intb = *(unsigned char *)cb; + + if (zcode == 90 || zcode == 122) { + /* ASCII is assumed - ZCODE is the ASCII code of either lower or + upper case 'Z'. */ + if (inta >= 97 && inta <= 122) inta += -32; + if (intb >= 97 && intb <= 122) intb += -32; + + } else if (zcode == 233 || zcode == 169) { + /* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or + upper case 'Z'. */ + if ((inta >= 129 && inta <= 137) || (inta >= 145 && inta <= 153) || (inta + >= 162 && inta <= 169)) + inta += 64; + if ((intb >= 129 && intb <= 137) || (intb >= 145 && intb <= 153) || (intb + >= 162 && intb <= 169)) + intb += 64; + } else if (zcode == 218 || zcode == 250) { + /* ASCII is assumed, on Prime machines - ZCODE is the ASCII code + plus 128 of either lower or upper case 'Z'. */ + if (inta >= 225 && inta <= 250) inta += -32; + if (intb >= 225 && intb <= 250) intb += -32; + } + ret_val = inta == intb; + return ret_val; + +} /* lsame_ */ diff --git a/intern/opennl/superlu/memory.c b/intern/opennl/superlu/memory.c new file mode 100644 index 00000000000..279b60b5239 --- /dev/null +++ b/intern/opennl/superlu/memory.c @@ -0,0 +1,211 @@ +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/** Precision-independent memory-related routines. + (Shared by [sdcz]memory.c) **/ + +#include "ssp_defs.h" + +/* prototypes --------------------------------- */ +void copy_mem_int(int, void *, void *); +void user_bcopy(char *, char *, int); + + +#if ( DEBUGlevel>=1 ) /* Debug malloc/free. */ +int superlu_malloc_total = 0; + +#define PAD_FACTOR 2 +#define DWORD (sizeof(double)) /* Be sure it's no smaller than double. */ + +void *superlu_malloc(size_t size) +{ + char *buf; + + buf = (char *) malloc(size + DWORD); + if ( !buf ) { + printf("superlu_malloc fails: malloc_total %.0f MB, size %d\n", + superlu_malloc_total*1e-6, size); + ABORT("superlu_malloc: out of memory"); + } + + ((int_t *) buf)[0] = size; +#if 0 + superlu_malloc_total += size + DWORD; +#else + superlu_malloc_total += size; +#endif + return (void *) (buf + DWORD); +} + +void superlu_free(void *addr) +{ + char *p = ((char *) addr) - DWORD; + + if ( !addr ) + ABORT("superlu_free: tried to free NULL pointer"); + + if ( !p ) + ABORT("superlu_free: tried to free NULL+DWORD pointer"); + + { + int_t n = ((int_t *) p)[0]; + + if ( !n ) + ABORT("superlu_free: tried to free a freed pointer"); + *((int_t *) p) = 0; /* Set to zero to detect duplicate free's. */ +#if 0 + superlu_malloc_total -= (n + DWORD); +#else + superlu_malloc_total -= n; +#endif + + if ( superlu_malloc_total < 0 ) + ABORT("superlu_malloc_total went negative!"); + + /*free (addr);*/ + free (p); + } + +} + +#else /* production mode */ + +void *superlu_malloc(size_t size) +{ + void *buf; + buf = (void *) malloc(size); + return (buf); +} + +void superlu_free(void *addr) +{ + free (addr); +} + +#endif + + +/* + * Set up pointers for integer working arrays. + */ +void +SetIWork(int m, int n, int panel_size, int *iworkptr, int **segrep, + int **parent, int **xplore, int **repfnz, int **panel_lsub, + int **xprune, int **marker) +{ + *segrep = iworkptr; + *parent = iworkptr + m; + *xplore = *parent + m; + *repfnz = *xplore + m; + *panel_lsub = *repfnz + panel_size * m; + *xprune = *panel_lsub + panel_size * m; + *marker = *xprune + n; + ifill (*repfnz, m * panel_size, EMPTY); + ifill (*panel_lsub, m * panel_size, EMPTY); +} + + +void +copy_mem_int(int howmany, void *old, void *new) +{ + register int i; + int *iold = old; + int *inew = new; + for (i = 0; i < howmany; i++) inew[i] = iold[i]; +} + + +void +user_bcopy(char *src, char *dest, int bytes) +{ + char *s_ptr, *d_ptr; + + s_ptr = src + bytes - 1; + d_ptr = dest + bytes - 1; + for (; d_ptr >= dest; --s_ptr, --d_ptr ) *d_ptr = *s_ptr; +} + + + +int *intMalloc(int n) +{ + int *buf; + buf = (int *) SUPERLU_MALLOC(n * sizeof(int)); + if ( !buf ) { + ABORT("SUPERLU_MALLOC fails for buf in intMalloc()"); + } + return (buf); +} + +int *intCalloc(int n) +{ + int *buf; + register int i; + buf = (int *) SUPERLU_MALLOC(n * sizeof(int)); + if ( !buf ) { + ABORT("SUPERLU_MALLOC fails for buf in intCalloc()"); + } + for (i = 0; i < n; ++i) buf[i] = 0; + return (buf); +} + + + +#if 0 +check_expanders() +{ + int p; + printf("Check expanders:\n"); + for (p = 0; p < NO_MEMTYPE; p++) { + printf("type %d, size %d, mem %d\n", + p, expanders[p].size, (int)expanders[p].mem); + } + + return 0; +} + + +StackInfo() +{ + printf("Stack: size %d, used %d, top1 %d, top2 %d\n", + stack.size, stack.used, stack.top1, stack.top2); + return 0; +} + + + +PrintStack(char *msg, GlobalLU_t *Glu) +{ + int i; + int *xlsub, *lsub, *xusub, *usub; + + xlsub = Glu->xlsub; + lsub = Glu->lsub; + xusub = Glu->xusub; + usub = Glu->usub; + + printf("%s\n", msg); + +/* printf("\nUCOL: "); + for (i = 0; i < xusub[ndim]; ++i) + printf("%f ", ucol[i]); + + printf("\nLSUB: "); + for (i = 0; i < xlsub[ndim]; ++i) + printf("%d ", lsub[i]); + + printf("\nUSUB: "); + for (i = 0; i < xusub[ndim]; ++i) + printf("%d ", usub[i]); + + printf("\n");*/ + return 0; +} +#endif + + + diff --git a/intern/opennl/superlu/mmd.c b/intern/opennl/superlu/mmd.c new file mode 100644 index 00000000000..e103c7de175 --- /dev/null +++ b/intern/opennl/superlu/mmd.c @@ -0,0 +1,1025 @@ + +typedef int shortint; + + +/* prototypes -------------------- */ +int genmmd_(int *, int *, int *, int *, int *, int *, int *, + int *, int *, int *, int *, int *); +int mmdint_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, + shortint *, shortint *); +int mmdelm_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, + shortint *, shortint *, int *, int *); +int mmdupd_(int *, int *, int *, shortint *, int *, int *, shortint *, + shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *); +int mmdnum_(int *, shortint *, shortint *, shortint *); + + +/* *************************************************************** */ +/* *************************************************************** */ +/* **** GENMMD ..... MULTIPLE MINIMUM EXTERNAL DEGREE **** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE IMPLEMENTS THE MINIMUM DEGREE */ +/* ALGORITHM. IT MAKES USE OF THE IMPLICIT REPRESENTATION */ +/* OF ELIMINATION GRAPHS BY QUOTIENT GRAPHS, AND THE */ +/* NOTION OF INDISTINGUISHABLE NODES. IT ALSO IMPLEMENTS */ +/* THE MODIFICATIONS BY MULTIPLE ELIMINATION AND MINIMUM */ +/* EXTERNAL DEGREE. */ +/* --------------------------------------------- */ +/* CAUTION - THE ADJACENCY VECTOR ADJNCY WILL BE */ +/* DESTROYED. */ +/* --------------------------------------------- */ + +/* INPUT PARAMETERS - */ +/* NEQNS - NUMBER OF EQUATIONS. */ +/* (XADJ,ADJNCY) - THE ADJACENCY STRUCTURE. */ +/* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */ +/* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) INTEGER */ +/* (ANY SMALLER ESTIMATE WILL DO) FOR MARKING */ +/* NODES. */ + +/* OUTPUT PARAMETERS - */ +/* PERM - THE MINIMUM DEGREE ORDERING. */ +/* INVP - THE INVERSE OF PERM. */ +/* NOFSUB - AN UPPER BOUND ON THE NUMBER OF NONZERO */ +/* SUBSCRIPTS FOR THE COMPRESSED STORAGE SCHEME. */ + +/* WORKING PARAMETERS - */ +/* DHEAD - VECTOR FOR HEAD OF DEGREE LISTS. */ +/* INVP - USED TEMPORARILY FOR DEGREE FORWARD LINK. */ +/* PERM - USED TEMPORARILY FOR DEGREE BACKWARD LINK. */ +/* QSIZE - VECTOR FOR SIZE OF SUPERNODES. */ +/* LLIST - VECTOR FOR TEMPORARY LINKED LISTS. */ +/* MARKER - A TEMPORARY MARKER VECTOR. */ + +/* PROGRAM SUBROUTINES - */ +/* MMDELM, MMDINT, MMDNUM, MMDUPD. */ + +/* *************************************************************** */ + +/* Subroutine */ int genmmd_(int *neqns, int *xadj, shortint *adjncy, + shortint *invp, shortint *perm, int *delta, shortint *dhead, + shortint *qsize, shortint *llist, shortint *marker, int *maxint, + int *nofsub) +{ + /* System generated locals */ + int i__1; + + /* Local variables */ + static int mdeg, ehead, i, mdlmt, mdnode; + extern /* Subroutine */ int mmdelm_(int *, int *, shortint *, + shortint *, shortint *, shortint *, shortint *, shortint *, + shortint *, int *, int *), mmdupd_(int *, int *, + int *, shortint *, int *, int *, shortint *, shortint + *, shortint *, shortint *, shortint *, shortint *, int *, + int *), mmdint_(int *, int *, shortint *, shortint *, + shortint *, shortint *, shortint *, shortint *, shortint *), + mmdnum_(int *, shortint *, shortint *, shortint *); + static int nextmd, tag, num; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + + /* Parameter adjustments */ + --marker; + --llist; + --qsize; + --dhead; + --perm; + --invp; + --adjncy; + --xadj; + + /* Function Body */ + if (*neqns <= 0) { + return 0; + } + +/* ------------------------------------------------ */ +/* INITIALIZATION FOR THE MINIMUM DEGREE ALGORITHM. */ +/* ------------------------------------------------ */ + *nofsub = 0; + mmdint_(neqns, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], & + qsize[1], &llist[1], &marker[1]); + +/* ---------------------------------------------- */ +/* NUM COUNTS THE NUMBER OF ORDERED NODES PLUS 1. */ +/* ---------------------------------------------- */ + num = 1; + +/* ----------------------------- */ +/* ELIMINATE ALL ISOLATED NODES. */ +/* ----------------------------- */ + nextmd = dhead[1]; +L100: + if (nextmd <= 0) { + goto L200; + } + mdnode = nextmd; + nextmd = invp[mdnode]; + marker[mdnode] = *maxint; + invp[mdnode] = -num; + ++num; + goto L100; + +L200: +/* ---------------------------------------- */ +/* SEARCH FOR NODE OF THE MINIMUM DEGREE. */ +/* MDEG IS THE CURRENT MINIMUM DEGREE; */ +/* TAG IS USED TO FACILITATE MARKING NODES. */ +/* ---------------------------------------- */ + if (num > *neqns) { + goto L1000; + } + tag = 1; + dhead[1] = 0; + mdeg = 2; +L300: + if (dhead[mdeg] > 0) { + goto L400; + } + ++mdeg; + goto L300; +L400: +/* ------------------------------------------------- */ +/* USE VALUE OF DELTA TO SET UP MDLMT, WHICH GOVERNS */ +/* WHEN A DEGREE UPDATE IS TO BE PERFORMED. */ +/* ------------------------------------------------- */ + mdlmt = mdeg + *delta; + ehead = 0; + +L500: + mdnode = dhead[mdeg]; + if (mdnode > 0) { + goto L600; + } + ++mdeg; + if (mdeg > mdlmt) { + goto L900; + } + goto L500; +L600: +/* ---------------------------------------- */ +/* REMOVE MDNODE FROM THE DEGREE STRUCTURE. */ +/* ---------------------------------------- */ + nextmd = invp[mdnode]; + dhead[mdeg] = nextmd; + if (nextmd > 0) { + perm[nextmd] = -mdeg; + } + invp[mdnode] = -num; + *nofsub = *nofsub + mdeg + qsize[mdnode] - 2; + if (num + qsize[mdnode] > *neqns) { + goto L1000; + } +/* ---------------------------------------------- */ +/* ELIMINATE MDNODE AND PERFORM QUOTIENT GRAPH */ +/* TRANSFORMATION. RESET TAG VALUE IF NECESSARY. */ +/* ---------------------------------------------- */ + ++tag; + if (tag < *maxint) { + goto L800; + } + tag = 1; + i__1 = *neqns; + for (i = 1; i <= i__1; ++i) { + if (marker[i] < *maxint) { + marker[i] = 0; + } +/* L700: */ + } +L800: + mmdelm_(&mdnode, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], & + qsize[1], &llist[1], &marker[1], maxint, &tag); + num += qsize[mdnode]; + llist[mdnode] = ehead; + ehead = mdnode; + if (*delta >= 0) { + goto L500; + } +L900: +/* ------------------------------------------- */ +/* UPDATE DEGREES OF THE NODES INVOLVED IN THE */ +/* MINIMUM DEGREE NODES ELIMINATION. */ +/* ------------------------------------------- */ + if (num > *neqns) { + goto L1000; + } + mmdupd_(&ehead, neqns, &xadj[1], &adjncy[1], delta, &mdeg, &dhead[1], & + invp[1], &perm[1], &qsize[1], &llist[1], &marker[1], maxint, &tag) + ; + goto L300; + +L1000: + mmdnum_(neqns, &perm[1], &invp[1], &qsize[1]); + return 0; + +} /* genmmd_ */ + +/* *************************************************************** */ +/* *************************************************************** */ +/* *** MMDINT ..... MULT MINIMUM DEGREE INITIALIZATION *** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE PERFORMS INITIALIZATION FOR THE */ +/* MULTIPLE ELIMINATION VERSION OF THE MINIMUM DEGREE */ +/* ALGORITHM. */ + +/* INPUT PARAMETERS - */ +/* NEQNS - NUMBER OF EQUATIONS. */ +/* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */ + +/* OUTPUT PARAMETERS - */ +/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ +/* QSIZE - SIZE OF SUPERNODE (INITIALIZED TO ONE). */ +/* LLIST - LINKED LIST. */ +/* MARKER - MARKER VECTOR. */ + +/* *************************************************************** */ + +/* Subroutine */ int mmdint_(int *neqns, int *xadj, shortint *adjncy, + shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, + shortint *llist, shortint *marker) +{ + /* System generated locals */ + int i__1; + + /* Local variables */ + static int ndeg, node, fnode; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + + /* Parameter adjustments */ + --marker; + --llist; + --qsize; + --dbakw; + --dforw; + --dhead; + --adjncy; + --xadj; + + /* Function Body */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + dhead[node] = 0; + qsize[node] = 1; + marker[node] = 0; + llist[node] = 0; +/* L100: */ + } +/* ------------------------------------------ */ +/* INITIALIZE THE DEGREE DOUBLY LINKED LISTS. */ +/* ------------------------------------------ */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + ndeg = xadj[node + 1] - xadj[node] + 1; + fnode = dhead[ndeg]; + dforw[node] = fnode; + dhead[ndeg] = node; + if (fnode > 0) { + dbakw[fnode] = node; + } + dbakw[node] = -ndeg; +/* L200: */ + } + return 0; + +} /* mmdint_ */ + +/* *************************************************************** */ +/* *************************************************************** */ +/* ** MMDELM ..... MULTIPLE MINIMUM DEGREE ELIMINATION *** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE ELIMINATES THE NODE MDNODE OF */ +/* MINIMUM DEGREE FROM THE ADJACENCY STRUCTURE, WHICH */ +/* IS STORED IN THE QUOTIENT GRAPH FORMAT. IT ALSO */ +/* TRANSFORMS THE QUOTIENT GRAPH REPRESENTATION OF THE */ +/* ELIMINATION GRAPH. */ + +/* INPUT PARAMETERS - */ +/* MDNODE - NODE OF MINIMUM DEGREE. */ +/* MAXINT - ESTIMATE OF MAXIMUM REPRESENTABLE (SHORT) */ +/* INT. */ +/* TAG - TAG VALUE. */ + +/* UPDATED PARAMETERS - */ +/* (XADJ,ADJNCY) - UPDATED ADJACENCY STRUCTURE. */ +/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ +/* QSIZE - SIZE OF SUPERNODE. */ +/* MARKER - MARKER VECTOR. */ +/* LLIST - TEMPORARY LINKED LIST OF ELIMINATED NABORS. */ + +/* *************************************************************** */ + +/* Subroutine */ int mmdelm_(int *mdnode, int *xadj, shortint *adjncy, + shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, + shortint *llist, shortint *marker, int *maxint, int *tag) +{ + /* System generated locals */ + int i__1, i__2; + + /* Local variables */ + static int node, link, rloc, rlmt, i, j, nabor, rnode, elmnt, xqnbr, + istop, jstop, istrt, jstrt, nxnode, pvnode, nqnbrs, npv; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + +/* ----------------------------------------------- */ +/* FIND REACHABLE SET AND PLACE IN DATA STRUCTURE. */ +/* ----------------------------------------------- */ + /* Parameter adjustments */ + --marker; + --llist; + --qsize; + --dbakw; + --dforw; + --dhead; + --adjncy; + --xadj; + + /* Function Body */ + marker[*mdnode] = *tag; + istrt = xadj[*mdnode]; + istop = xadj[*mdnode + 1] - 1; +/* ------------------------------------------------------- */ +/* ELMNT POINTS TO THE BEGINNING OF THE LIST OF ELIMINATED */ +/* NABORS OF MDNODE, AND RLOC GIVES THE STORAGE LOCATION */ +/* FOR THE NEXT REACHABLE NODE. */ +/* ------------------------------------------------------- */ + elmnt = 0; + rloc = istrt; + rlmt = istop; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + nabor = adjncy[i]; + if (nabor == 0) { + goto L300; + } + if (marker[nabor] >= *tag) { + goto L200; + } + marker[nabor] = *tag; + if (dforw[nabor] < 0) { + goto L100; + } + adjncy[rloc] = nabor; + ++rloc; + goto L200; +L100: + llist[nabor] = elmnt; + elmnt = nabor; +L200: + ; + } +L300: +/* ----------------------------------------------------- */ +/* MERGE WITH REACHABLE NODES FROM GENERALIZED ELEMENTS. */ +/* ----------------------------------------------------- */ + if (elmnt <= 0) { + goto L1000; + } + adjncy[rlmt] = -elmnt; + link = elmnt; +L400: + jstrt = xadj[link]; + jstop = xadj[link + 1] - 1; + i__1 = jstop; + for (j = jstrt; j <= i__1; ++j) { + node = adjncy[j]; + link = -node; + if (node < 0) { + goto L400; + } else if (node == 0) { + goto L900; + } else { + goto L500; + } +L500: + if (marker[node] >= *tag || dforw[node] < 0) { + goto L800; + } + marker[node] = *tag; +/* --------------------------------- */ +/* USE STORAGE FROM ELIMINATED NODES */ +/* IF NECESSARY. */ +/* --------------------------------- */ +L600: + if (rloc < rlmt) { + goto L700; + } + link = -adjncy[rlmt]; + rloc = xadj[link]; + rlmt = xadj[link + 1] - 1; + goto L600; +L700: + adjncy[rloc] = node; + ++rloc; +L800: + ; + } +L900: + elmnt = llist[elmnt]; + goto L300; +L1000: + if (rloc <= rlmt) { + adjncy[rloc] = 0; + } +/* -------------------------------------------------------- */ +/* FOR EACH NODE IN THE REACHABLE SET, DO THE FOLLOWING ... */ +/* -------------------------------------------------------- */ + link = *mdnode; +L1100: + istrt = xadj[link]; + istop = xadj[link + 1] - 1; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + rnode = adjncy[i]; + link = -rnode; + if (rnode < 0) { + goto L1100; + } else if (rnode == 0) { + goto L1800; + } else { + goto L1200; + } +L1200: +/* -------------------------------------------- */ +/* IF RNODE IS IN THE DEGREE LIST STRUCTURE ... */ +/* -------------------------------------------- */ + pvnode = dbakw[rnode]; + if (pvnode == 0 || pvnode == -(*maxint)) { + goto L1300; + } +/* ------------------------------------- */ +/* THEN REMOVE RNODE FROM THE STRUCTURE. */ +/* ------------------------------------- */ + nxnode = dforw[rnode]; + if (nxnode > 0) { + dbakw[nxnode] = pvnode; + } + if (pvnode > 0) { + dforw[pvnode] = nxnode; + } + npv = -pvnode; + if (pvnode < 0) { + dhead[npv] = nxnode; + } +L1300: +/* ---------------------------------------- */ +/* PURGE INACTIVE QUOTIENT NABORS OF RNODE. */ +/* ---------------------------------------- */ + jstrt = xadj[rnode]; + jstop = xadj[rnode + 1] - 1; + xqnbr = jstrt; + i__2 = jstop; + for (j = jstrt; j <= i__2; ++j) { + nabor = adjncy[j]; + if (nabor == 0) { + goto L1500; + } + if (marker[nabor] >= *tag) { + goto L1400; + } + adjncy[xqnbr] = nabor; + ++xqnbr; +L1400: + ; + } +L1500: +/* ---------------------------------------- */ +/* IF NO ACTIVE NABOR AFTER THE PURGING ... */ +/* ---------------------------------------- */ + nqnbrs = xqnbr - jstrt; + if (nqnbrs > 0) { + goto L1600; + } +/* ----------------------------- */ +/* THEN MERGE RNODE WITH MDNODE. */ +/* ----------------------------- */ + qsize[*mdnode] += qsize[rnode]; + qsize[rnode] = 0; + marker[rnode] = *maxint; + dforw[rnode] = -(*mdnode); + dbakw[rnode] = -(*maxint); + goto L1700; +L1600: +/* -------------------------------------- */ +/* ELSE FLAG RNODE FOR DEGREE UPDATE, AND */ +/* ADD MDNODE AS A NABOR OF RNODE. */ +/* -------------------------------------- */ + dforw[rnode] = nqnbrs + 1; + dbakw[rnode] = 0; + adjncy[xqnbr] = *mdnode; + ++xqnbr; + if (xqnbr <= jstop) { + adjncy[xqnbr] = 0; + } + +L1700: + ; + } +L1800: + return 0; + +} /* mmdelm_ */ + +/* *************************************************************** */ +/* *************************************************************** */ +/* ***** MMDUPD ..... MULTIPLE MINIMUM DEGREE UPDATE ***** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE UPDATES THE DEGREES OF NODES */ +/* AFTER A MULTIPLE ELIMINATION STEP. */ + +/* INPUT PARAMETERS - */ +/* EHEAD - THE BEGINNING OF THE LIST OF ELIMINATED */ +/* NODES (I.E., NEWLY FORMED ELEMENTS). */ +/* NEQNS - NUMBER OF EQUATIONS. */ +/* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */ +/* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */ +/* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) */ +/* INTEGER. */ + +/* UPDATED PARAMETERS - */ +/* MDEG - NEW MINIMUM DEGREE AFTER DEGREE UPDATE. */ +/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ +/* QSIZE - SIZE OF SUPERNODE. */ +/* LLIST - WORKING LINKED LIST. */ +/* MARKER - MARKER VECTOR FOR DEGREE UPDATE. */ +/* TAG - TAG VALUE. */ + +/* *************************************************************** */ + +/* Subroutine */ int mmdupd_(int *ehead, int *neqns, int *xadj, + shortint *adjncy, int *delta, int *mdeg, shortint *dhead, + shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist, + shortint *marker, int *maxint, int *tag) +{ + /* System generated locals */ + int i__1, i__2; + + /* Local variables */ + static int node, mtag, link, mdeg0, i, j, enode, fnode, nabor, elmnt, + istop, jstop, q2head, istrt, jstrt, qxhead, iq2, deg, deg0; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + + /* Parameter adjustments */ + --marker; + --llist; + --qsize; + --dbakw; + --dforw; + --dhead; + --adjncy; + --xadj; + + /* Function Body */ + mdeg0 = *mdeg + *delta; + elmnt = *ehead; +L100: +/* ------------------------------------------------------- */ +/* FOR EACH OF THE NEWLY FORMED ELEMENT, DO THE FOLLOWING. */ +/* (RESET TAG VALUE IF NECESSARY.) */ +/* ------------------------------------------------------- */ + if (elmnt <= 0) { + return 0; + } + mtag = *tag + mdeg0; + if (mtag < *maxint) { + goto L300; + } + *tag = 1; + i__1 = *neqns; + for (i = 1; i <= i__1; ++i) { + if (marker[i] < *maxint) { + marker[i] = 0; + } +/* L200: */ + } + mtag = *tag + mdeg0; +L300: +/* --------------------------------------------- */ +/* CREATE TWO LINKED LISTS FROM NODES ASSOCIATED */ +/* WITH ELMNT: ONE WITH TWO NABORS (Q2HEAD) IN */ +/* ADJACENCY STRUCTURE, AND THE OTHER WITH MORE */ +/* THAN TWO NABORS (QXHEAD). ALSO COMPUTE DEG0, */ +/* NUMBER OF NODES IN THIS ELEMENT. */ +/* --------------------------------------------- */ + q2head = 0; + qxhead = 0; + deg0 = 0; + link = elmnt; +L400: + istrt = xadj[link]; + istop = xadj[link + 1] - 1; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + enode = adjncy[i]; + link = -enode; + if (enode < 0) { + goto L400; + } else if (enode == 0) { + goto L800; + } else { + goto L500; + } + +L500: + if (qsize[enode] == 0) { + goto L700; + } + deg0 += qsize[enode]; + marker[enode] = mtag; +/* ---------------------------------- */ +/* IF ENODE REQUIRES A DEGREE UPDATE, */ +/* THEN DO THE FOLLOWING. */ +/* ---------------------------------- */ + if (dbakw[enode] != 0) { + goto L700; + } +/* --------------------------------------- +*/ +/* PLACE EITHER IN QXHEAD OR Q2HEAD LISTS. +*/ +/* --------------------------------------- +*/ + if (dforw[enode] == 2) { + goto L600; + } + llist[enode] = qxhead; + qxhead = enode; + goto L700; +L600: + llist[enode] = q2head; + q2head = enode; +L700: + ; + } +L800: +/* -------------------------------------------- */ +/* FOR EACH ENODE IN Q2 LIST, DO THE FOLLOWING. */ +/* -------------------------------------------- */ + enode = q2head; + iq2 = 1; +L900: + if (enode <= 0) { + goto L1500; + } + if (dbakw[enode] != 0) { + goto L2200; + } + ++(*tag); + deg = deg0; +/* ------------------------------------------ */ +/* IDENTIFY THE OTHER ADJACENT ELEMENT NABOR. */ +/* ------------------------------------------ */ + istrt = xadj[enode]; + nabor = adjncy[istrt]; + if (nabor == elmnt) { + nabor = adjncy[istrt + 1]; + } +/* ------------------------------------------------ */ +/* IF NABOR IS UNELIMINATED, INCREASE DEGREE COUNT. */ +/* ------------------------------------------------ */ + link = nabor; + if (dforw[nabor] < 0) { + goto L1000; + } + deg += qsize[nabor]; + goto L2100; +L1000: +/* -------------------------------------------- */ +/* OTHERWISE, FOR EACH NODE IN THE 2ND ELEMENT, */ +/* DO THE FOLLOWING. */ +/* -------------------------------------------- */ + istrt = xadj[link]; + istop = xadj[link + 1] - 1; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + node = adjncy[i]; + link = -node; + if (node == enode) { + goto L1400; + } + if (node < 0) { + goto L1000; + } else if (node == 0) { + goto L2100; + } else { + goto L1100; + } + +L1100: + if (qsize[node] == 0) { + goto L1400; + } + if (marker[node] >= *tag) { + goto L1200; + } +/* ----------------------------------- +-- */ +/* CASE WHEN NODE IS NOT YET CONSIDERED +. */ +/* ----------------------------------- +-- */ + marker[node] = *tag; + deg += qsize[node]; + goto L1400; +L1200: +/* ---------------------------------------- + */ +/* CASE WHEN NODE IS INDISTINGUISHABLE FROM + */ +/* ENODE. MERGE THEM INTO A NEW SUPERNODE. + */ +/* ---------------------------------------- + */ + if (dbakw[node] != 0) { + goto L1400; + } + if (dforw[node] != 2) { + goto L1300; + } + qsize[enode] += qsize[node]; + qsize[node] = 0; + marker[node] = *maxint; + dforw[node] = -enode; + dbakw[node] = -(*maxint); + goto L1400; +L1300: +/* -------------------------------------- +*/ +/* CASE WHEN NODE IS OUTMATCHED BY ENODE. +*/ +/* -------------------------------------- +*/ + if (dbakw[node] == 0) { + dbakw[node] = -(*maxint); + } +L1400: + ; + } + goto L2100; +L1500: +/* ------------------------------------------------ */ +/* FOR EACH ENODE IN THE QX LIST, DO THE FOLLOWING. */ +/* ------------------------------------------------ */ + enode = qxhead; + iq2 = 0; +L1600: + if (enode <= 0) { + goto L2300; + } + if (dbakw[enode] != 0) { + goto L2200; + } + ++(*tag); + deg = deg0; +/* --------------------------------- */ +/* FOR EACH UNMARKED NABOR OF ENODE, */ +/* DO THE FOLLOWING. */ +/* --------------------------------- */ + istrt = xadj[enode]; + istop = xadj[enode + 1] - 1; + i__1 = istop; + for (i = istrt; i <= i__1; ++i) { + nabor = adjncy[i]; + if (nabor == 0) { + goto L2100; + } + if (marker[nabor] >= *tag) { + goto L2000; + } + marker[nabor] = *tag; + link = nabor; +/* ------------------------------ */ +/* IF UNELIMINATED, INCLUDE IT IN */ +/* DEG COUNT. */ +/* ------------------------------ */ + if (dforw[nabor] < 0) { + goto L1700; + } + deg += qsize[nabor]; + goto L2000; +L1700: +/* ------------------------------- +*/ +/* IF ELIMINATED, INCLUDE UNMARKED +*/ +/* NODES IN THIS ELEMENT INTO THE +*/ +/* DEGREE COUNT. */ +/* ------------------------------- +*/ + jstrt = xadj[link]; + jstop = xadj[link + 1] - 1; + i__2 = jstop; + for (j = jstrt; j <= i__2; ++j) { + node = adjncy[j]; + link = -node; + if (node < 0) { + goto L1700; + } else if (node == 0) { + goto L2000; + } else { + goto L1800; + } + +L1800: + if (marker[node] >= *tag) { + goto L1900; + } + marker[node] = *tag; + deg += qsize[node]; +L1900: + ; + } +L2000: + ; + } +L2100: +/* ------------------------------------------- */ +/* UPDATE EXTERNAL DEGREE OF ENODE IN DEGREE */ +/* STRUCTURE, AND MDEG (MIN DEG) IF NECESSARY. */ +/* ------------------------------------------- */ + deg = deg - qsize[enode] + 1; + fnode = dhead[deg]; + dforw[enode] = fnode; + dbakw[enode] = -deg; + if (fnode > 0) { + dbakw[fnode] = enode; + } + dhead[deg] = enode; + if (deg < *mdeg) { + *mdeg = deg; + } +L2200: +/* ---------------------------------- */ +/* GET NEXT ENODE IN CURRENT ELEMENT. */ +/* ---------------------------------- */ + enode = llist[enode]; + if (iq2 == 1) { + goto L900; + } + goto L1600; +L2300: +/* ----------------------------- */ +/* GET NEXT ELEMENT IN THE LIST. */ +/* ----------------------------- */ + *tag = mtag; + elmnt = llist[elmnt]; + goto L100; + +} /* mmdupd_ */ + +/* *************************************************************** */ +/* *************************************************************** */ +/* ***** MMDNUM ..... MULTI MINIMUM DEGREE NUMBERING ***** */ +/* *************************************************************** */ +/* *************************************************************** */ + +/* AUTHOR - JOSEPH W.H. LIU */ +/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ + +/* PURPOSE - THIS ROUTINE PERFORMS THE FINAL STEP IN */ +/* PRODUCING THE PERMUTATION AND INVERSE PERMUTATION */ +/* VECTORS IN THE MULTIPLE ELIMINATION VERSION OF THE */ +/* MINIMUM DEGREE ORDERING ALGORITHM. */ + +/* INPUT PARAMETERS - */ +/* NEQNS - NUMBER OF EQUATIONS. */ +/* QSIZE - SIZE OF SUPERNODES AT ELIMINATION. */ + +/* UPDATED PARAMETERS - */ +/* INVP - INVERSE PERMUTATION VECTOR. ON INPUT, */ +/* IF QSIZE(NODE)=0, THEN NODE HAS BEEN MERGED */ +/* INTO THE NODE -INVP(NODE); OTHERWISE, */ +/* -INVP(NODE) IS ITS INVERSE LABELLING. */ + +/* OUTPUT PARAMETERS - */ +/* PERM - THE PERMUTATION VECTOR. */ + +/* *************************************************************** */ + +/* Subroutine */ int mmdnum_(int *neqns, shortint *perm, shortint *invp, + shortint *qsize) +{ + /* System generated locals */ + int i__1; + + /* Local variables */ + static int node, root, nextf, father, nqsize, num; + + +/* *************************************************************** */ + + +/* *************************************************************** */ + + /* Parameter adjustments */ + --qsize; + --invp; + --perm; + + /* Function Body */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + nqsize = qsize[node]; + if (nqsize <= 0) { + perm[node] = invp[node]; + } + if (nqsize > 0) { + perm[node] = -invp[node]; + } +/* L100: */ + } +/* ------------------------------------------------------ */ +/* FOR EACH NODE WHICH HAS BEEN MERGED, DO THE FOLLOWING. */ +/* ------------------------------------------------------ */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + if (perm[node] > 0) { + goto L500; + } +/* ----------------------------------------- */ +/* TRACE THE MERGED TREE UNTIL ONE WHICH HAS */ +/* NOT BEEN MERGED, CALL IT ROOT. */ +/* ----------------------------------------- */ + father = node; +L200: + if (perm[father] > 0) { + goto L300; + } + father = -perm[father]; + goto L200; +L300: +/* ----------------------- */ +/* NUMBER NODE AFTER ROOT. */ +/* ----------------------- */ + root = father; + num = perm[root] + 1; + invp[node] = -num; + perm[root] = num; +/* ------------------------ */ +/* SHORTEN THE MERGED TREE. */ +/* ------------------------ */ + father = node; +L400: + nextf = -perm[father]; + if (nextf <= 0) { + goto L500; + } + perm[father] = -root; + father = nextf; + goto L400; +L500: + ; + } +/* ---------------------- */ +/* READY TO COMPUTE PERM. */ +/* ---------------------- */ + i__1 = *neqns; + for (node = 1; node <= i__1; ++node) { + num = -invp[node]; + invp[node] = num; + perm[num] = node; +/* L600: */ + } + return 0; + +} /* mmdnum_ */ + diff --git a/intern/opennl/superlu/relax_snode.c b/intern/opennl/superlu/relax_snode.c new file mode 100644 index 00000000000..549f3fcf873 --- /dev/null +++ b/intern/opennl/superlu/relax_snode.c @@ -0,0 +1,71 @@ +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +void +relax_snode ( + const int n, + int *et, /* column elimination tree */ + const int relax_columns, /* max no of columns allowed in a + relaxed snode */ + int *descendants, /* no of descendants of each node + in the etree */ + int *relax_end /* last column in a supernode */ + ) +{ +/* + * Purpose + * ======= + * relax_snode() - Identify the initial relaxed supernodes, assuming that + * the matrix has been reordered according to the postorder of the etree. + * + */ + register int j, parent; + register int snode_start; /* beginning of a snode */ + + ifill (relax_end, n, EMPTY); + for (j = 0; j < n; j++) descendants[j] = 0; + + /* Compute the number of descendants of each node in the etree */ + for (j = 0; j < n; j++) { + parent = et[j]; + if ( parent != n ) /* not the dummy root */ + descendants[parent] += descendants[j] + 1; + } + + /* Identify the relaxed supernodes by postorder traversal of the etree. */ + for (j = 0; j < n; ) { + parent = et[j]; + snode_start = j; + while ( parent != n && descendants[parent] < relax_columns ) { + j = parent; + parent = et[j]; + } + /* Found a supernode with j being the last column. */ + relax_end[snode_start] = j; /* Last column is recorded */ + j++; + /* Search for a new leaf */ + while ( descendants[j] != 0 && j < n ) j++; + } + + /*printf("No of relaxed snodes: %d; relaxed columns: %d\n", + nsuper, no_relaxed_col); */ +} diff --git a/intern/opennl/superlu/scolumn_bmod.c b/intern/opennl/superlu/scolumn_bmod.c new file mode 100644 index 00000000000..c877a27dd53 --- /dev/null +++ b/intern/opennl/superlu/scolumn_bmod.c @@ -0,0 +1,353 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include +#include "ssp_defs.h" + +/* + * Function prototypes + */ +void susolve(int, int, float*, float*); +void slsolve(int, int, float*, float*); +void smatvec(int, int, int, float*, float*, float*); + + + +/* Return value: 0 - successful return + * > 0 - number of bytes allocated when run out of space + */ +int +scolumn_bmod ( + const int jcol, /* in */ + const int nseg, /* in */ + float *dense, /* in */ + float *tempv, /* working array */ + int *segrep, /* in */ + int *repfnz, /* in */ + int fpanelc, /* in -- first column in the current panel */ + GlobalLU_t *Glu, /* modified */ + SuperLUStat_t *stat /* output */ + ) +{ +/* + * Purpose: + * ======== + * Performs numeric block updates (sup-col) in topological order. + * It features: col-col, 2cols-col, 3cols-col, and sup-col updates. + * Special processing on the supernodal portion of L\U[*,j] + * + */ +#ifdef _CRAY + _fcd ftcs1 = _cptofcd("L", strlen("L")), + ftcs2 = _cptofcd("N", strlen("N")), + ftcs3 = _cptofcd("U", strlen("U")); +#endif + +#ifdef USE_VENDOR_BLAS + int incx = 1, incy = 1; + float alpha, beta; +#endif + + /* krep = representative of current k-th supernode + * fsupc = first supernodal column + * nsupc = no of columns in supernode + * nsupr = no of rows in supernode (used as leading dimension) + * luptr = location of supernodal LU-block in storage + * kfnz = first nonz in the k-th supernodal segment + * no_zeros = no of leading zeros in a supernodal U-segment + */ + float ukj, ukj1, ukj2; + int luptr, luptr1, luptr2; + int fsupc, nsupc, nsupr, segsze; + int nrow; /* No of rows in the matrix of matrix-vector */ + int jcolp1, jsupno, k, ksub, krep, krep_ind, ksupno; + register int lptr, kfnz, isub, irow, i; + register int no_zeros, new_next; + int ufirst, nextlu; + int fst_col; /* First column within small LU update */ + int d_fsupc; /* Distance between the first column of the current + panel and the first column of the current snode. */ + int *xsup, *supno; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + int nzlumax; + float *tempv1; + float zero = 0.0; +#ifdef USE_VENDOR_BLAS + float one = 1.0; + float none = -1.0; +#endif + int mem_error; + flops_t *ops = stat->ops; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + nzlumax = Glu->nzlumax; + jcolp1 = jcol + 1; + jsupno = supno[jcol]; + + /* + * For each nonz supernode segment of U[*,j] in topological order + */ + k = nseg - 1; + for (ksub = 0; ksub < nseg; ksub++) { + + krep = segrep[k]; + k--; + ksupno = supno[krep]; + if ( jsupno != ksupno ) { /* Outside the rectangular supernode */ + + fsupc = xsup[ksupno]; + fst_col = SUPERLU_MAX ( fsupc, fpanelc ); + + /* Distance from the current supernode to the current panel; + d_fsupc=0 if fsupc > fpanelc. */ + d_fsupc = fst_col - fsupc; + + luptr = xlusup[fst_col] + d_fsupc; + lptr = xlsub[fsupc] + d_fsupc; + + kfnz = repfnz[krep]; + kfnz = SUPERLU_MAX ( kfnz, fpanelc ); + + segsze = krep - kfnz + 1; + nsupc = krep - fst_col + 1; + nsupr = xlsub[fsupc+1] - xlsub[fsupc]; /* Leading dimension */ + nrow = nsupr - d_fsupc - nsupc; + krep_ind = lptr + nsupc - 1; + + ops[TRSV] += segsze * (segsze - 1); + ops[GEMV] += 2 * nrow * segsze; + + + /* + * Case 1: Update U-segment of size 1 -- col-col update + */ + if ( segsze == 1 ) { + ukj = dense[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc; + + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + dense[irow] -= ukj*lusup[luptr]; + luptr++; + } + + } else if ( segsze <= 3 ) { + ukj = dense[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc-1; + ukj1 = dense[lsub[krep_ind - 1]]; + luptr1 = luptr - nsupr; + + if ( segsze == 2 ) { /* Case 2: 2cols-col update */ + ukj -= ukj1 * lusup[luptr1]; + dense[lsub[krep_ind]] = ukj; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + luptr++; + luptr1++; + dense[irow] -= ( ukj*lusup[luptr] + + ukj1*lusup[luptr1] ); + } + } else { /* Case 3: 3cols-col update */ + ukj2 = dense[lsub[krep_ind - 2]]; + luptr2 = luptr1 - nsupr; + ukj1 -= ukj2 * lusup[luptr2-1]; + ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; + dense[lsub[krep_ind]] = ukj; + dense[lsub[krep_ind-1]] = ukj1; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + luptr++; + luptr1++; + luptr2++; + dense[irow] -= ( ukj*lusup[luptr] + + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); + } + } + + + + } else { + /* + * Case: sup-col update + * Perform a triangular solve and block update, + * then scatter the result of sup-col update to dense + */ + + no_zeros = kfnz - fst_col; + + /* Copy U[*,j] segment from dense[*] to tempv[*] */ + isub = lptr + no_zeros; + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + tempv[i] = dense[irow]; + ++isub; + } + + /* Dense triangular solve -- start effective triangle */ + luptr += nsupr * no_zeros + no_zeros; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], + &nsupr, tempv, &incx ); +#else + strsv_( "L", "N", "U", &segsze, &lusup[luptr], + &nsupr, tempv, &incx ); +#endif + luptr += segsze; /* Dense matrix-vector */ + tempv1 = &tempv[segsze]; + alpha = one; + beta = zero; +#ifdef _CRAY + SGEMV( ftcs2, &nrow, &segsze, &alpha, &lusup[luptr], + &nsupr, tempv, &incx, &beta, tempv1, &incy ); +#else + sgemv_( "N", &nrow, &segsze, &alpha, &lusup[luptr], + &nsupr, tempv, &incx, &beta, tempv1, &incy ); +#endif +#else + slsolve ( nsupr, segsze, &lusup[luptr], tempv ); + + luptr += segsze; /* Dense matrix-vector */ + tempv1 = &tempv[segsze]; + smatvec (nsupr, nrow , segsze, &lusup[luptr], tempv, tempv1); +#endif + + + /* Scatter tempv[] into SPA dense[] as a temporary storage */ + isub = lptr + no_zeros; + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + dense[irow] = tempv[i]; + tempv[i] = zero; + ++isub; + } + + /* Scatter tempv1[] into SPA dense[] */ + for (i = 0; i < nrow; i++) { + irow = lsub[isub]; + dense[irow] -= tempv1[i]; + tempv1[i] = zero; + ++isub; + } + } + + } /* if jsupno ... */ + + } /* for each segment... */ + + /* + * Process the supernodal portion of L\U[*,j] + */ + nextlu = xlusup[jcol]; + fsupc = xsup[jsupno]; + + /* Copy the SPA dense into L\U[*,j] */ + new_next = nextlu + xlsub[fsupc+1] - xlsub[fsupc]; + while ( new_next > nzlumax ) { + if ((mem_error = sLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, Glu))) + return (mem_error); + lusup = Glu->lusup; + lsub = Glu->lsub; + } + + for (isub = xlsub[fsupc]; isub < xlsub[fsupc+1]; isub++) { + irow = lsub[isub]; + lusup[nextlu] = dense[irow]; + dense[irow] = zero; + ++nextlu; + } + + xlusup[jcolp1] = nextlu; /* Close L\U[*,jcol] */ + + /* For more updates within the panel (also within the current supernode), + * should start from the first column of the panel, or the first column + * of the supernode, whichever is bigger. There are 2 cases: + * 1) fsupc < fpanelc, then fst_col := fpanelc + * 2) fsupc >= fpanelc, then fst_col := fsupc + */ + fst_col = SUPERLU_MAX ( fsupc, fpanelc ); + + if ( fst_col < jcol ) { + + /* Distance between the current supernode and the current panel. + d_fsupc=0 if fsupc >= fpanelc. */ + d_fsupc = fst_col - fsupc; + + lptr = xlsub[fsupc] + d_fsupc; + luptr = xlusup[fst_col] + d_fsupc; + nsupr = xlsub[fsupc+1] - xlsub[fsupc]; /* Leading dimension */ + nsupc = jcol - fst_col; /* Excluding jcol */ + nrow = nsupr - d_fsupc - nsupc; + + /* Points to the beginning of jcol in snode L\U(jsupno) */ + ufirst = xlusup[jcol] + d_fsupc; + + ops[TRSV] += nsupc * (nsupc - 1); + ops[GEMV] += 2 * nrow * nsupc; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &lusup[luptr], + &nsupr, &lusup[ufirst], &incx ); +#else + strsv_( "L", "N", "U", &nsupc, &lusup[luptr], + &nsupr, &lusup[ufirst], &incx ); +#endif + + alpha = none; beta = one; /* y := beta*y + alpha*A*x */ + +#ifdef _CRAY + SGEMV( ftcs2, &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, + &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); +#else + sgemv_( "N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, + &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); +#endif +#else + slsolve ( nsupr, nsupc, &lusup[luptr], &lusup[ufirst] ); + + smatvec ( nsupr, nrow, nsupc, &lusup[luptr+nsupc], + &lusup[ufirst], tempv ); + + /* Copy updates from tempv[*] into lusup[*] */ + isub = ufirst + nsupc; + for (i = 0; i < nrow; i++) { + lusup[isub] -= tempv[i]; + tempv[i] = 0.0; + ++isub; + } + +#endif + + + } /* if fst_col < jcol ... */ + + return 0; +} diff --git a/intern/opennl/superlu/scolumn_dfs.c b/intern/opennl/superlu/scolumn_dfs.c new file mode 100644 index 00000000000..ecfb5c3b839 --- /dev/null +++ b/intern/opennl/superlu/scolumn_dfs.c @@ -0,0 +1,270 @@ + + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +/* What type of supernodes we want */ +#define T2_SUPER + +int +scolumn_dfs( + const int m, /* in - number of rows in the matrix */ + const int jcol, /* in */ + int *perm_r, /* in */ + int *nseg, /* modified - with new segments appended */ + int *lsub_col, /* in - defines the RHS vector to start the dfs */ + int *segrep, /* modified - with new segments appended */ + int *repfnz, /* modified */ + int *xprune, /* modified */ + int *marker, /* modified */ + int *parent, /* working array */ + int *xplore, /* working array */ + GlobalLU_t *Glu /* modified */ + ) +{ +/* + * Purpose + * ======= + * "column_dfs" performs a symbolic factorization on column jcol, and + * decide the supernode boundary. + * + * This routine does not use numeric values, but only use the RHS + * row indices to start the dfs. + * + * A supernode representative is the last column of a supernode. + * The nonzeros in U[*,j] are segments that end at supernodal + * representatives. The routine returns a list of such supernodal + * representatives in topological order of the dfs that generates them. + * The location of the first nonzero in each such supernodal segment + * (supernodal entry location) is also returned. + * + * Local parameters + * ================ + * nseg: no of segments in current U[*,j] + * jsuper: jsuper=EMPTY if column j does not belong to the same + * supernode as j-1. Otherwise, jsuper=nsuper. + * + * marker2: A-row --> A-row/col (0/1) + * repfnz: SuperA-col --> PA-row + * parent: SuperA-col --> SuperA-col + * xplore: SuperA-col --> index to L-structure + * + * Return value + * ============ + * 0 success; + * > 0 number of bytes allocated when run out of space. + * + */ + int jcolp1, jcolm1, jsuper, nsuper, nextl; + int k, krep, krow, kmark, kperm; + int *marker2; /* Used for small panel LU */ + int fsupc; /* First column of a snode */ + int myfnz; /* First nonz column of a U-segment */ + int chperm, chmark, chrep, kchild; + int xdfs, maxdfs, kpar, oldrep; + int jptr, jm1ptr; + int ito, ifrom, istop; /* Used to compress row subscripts */ + int mem_error; + int *xsup, *supno, *lsub, *xlsub; + int nzlmax; + static int first = 1, maxsuper; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + nzlmax = Glu->nzlmax; + + if ( first ) { + maxsuper = sp_ienv(3); + first = 0; + } + jcolp1 = jcol + 1; + jcolm1 = jcol - 1; + nsuper = supno[jcol]; + jsuper = nsuper; + nextl = xlsub[jcol]; + marker2 = &marker[2*m]; + + + /* For each nonzero in A[*,jcol] do dfs */ + for (k = 0; lsub_col[k] != EMPTY; k++) { + + krow = lsub_col[k]; + lsub_col[k] = EMPTY; + kmark = marker2[krow]; + + /* krow was visited before, go to the next nonz */ + if ( kmark == jcol ) continue; + + /* For each unmarked nbr krow of jcol + * krow is in L: place it in structure of L[*,jcol] + */ + marker2[krow] = jcol; + kperm = perm_r[krow]; + + if ( kperm == EMPTY ) { + lsub[nextl++] = krow; /* krow is indexed into A */ + if ( nextl >= nzlmax ) { + if ((mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu))) + return (mem_error); + lsub = Glu->lsub; + } + if ( kmark != jcolm1 ) jsuper = EMPTY;/* Row index subset testing */ + } else { + /* krow is in U: if its supernode-rep krep + * has been explored, update repfnz[*] + */ + krep = xsup[supno[kperm]+1] - 1; + myfnz = repfnz[krep]; + + if ( myfnz != EMPTY ) { /* Visited before */ + if ( myfnz > kperm ) repfnz[krep] = kperm; + /* continue; */ + } + else { + /* Otherwise, perform dfs starting at krep */ + oldrep = EMPTY; + parent[krep] = oldrep; + repfnz[krep] = kperm; + xdfs = xlsub[krep]; + maxdfs = xprune[krep]; + + do { + /* + * For each unmarked kchild of krep + */ + while ( xdfs < maxdfs ) { + + kchild = lsub[xdfs]; + xdfs++; + chmark = marker2[kchild]; + + if ( chmark != jcol ) { /* Not reached yet */ + marker2[kchild] = jcol; + chperm = perm_r[kchild]; + + /* Case kchild is in L: place it in L[*,k] */ + if ( chperm == EMPTY ) { + lsub[nextl++] = kchild; + if ( nextl >= nzlmax ) { + if ((mem_error = + sLUMemXpand(jcol,nextl,LSUB,&nzlmax,Glu))) + return (mem_error); + lsub = Glu->lsub; + } + if ( chmark != jcolm1 ) jsuper = EMPTY; + } else { + /* Case kchild is in U: + * chrep = its supernode-rep. If its rep has + * been explored, update its repfnz[*] + */ + chrep = xsup[supno[chperm]+1] - 1; + myfnz = repfnz[chrep]; + if ( myfnz != EMPTY ) { /* Visited before */ + if ( myfnz > chperm ) + repfnz[chrep] = chperm; + } else { + /* Continue dfs at super-rep of kchild */ + xplore[krep] = xdfs; + oldrep = krep; + krep = chrep; /* Go deeper down G(L^t) */ + parent[krep] = oldrep; + repfnz[krep] = chperm; + xdfs = xlsub[krep]; + maxdfs = xprune[krep]; + } /* else */ + + } /* else */ + + } /* if */ + + } /* while */ + + /* krow has no more unexplored nbrs; + * place supernode-rep krep in postorder DFS. + * backtrack dfs to its parent + */ + segrep[*nseg] = krep; + ++(*nseg); + kpar = parent[krep]; /* Pop from stack, mimic recursion */ + if ( kpar == EMPTY ) break; /* dfs done */ + krep = kpar; + xdfs = xplore[krep]; + maxdfs = xprune[krep]; + + } while ( kpar != EMPTY ); /* Until empty stack */ + + } /* else */ + + } /* else */ + + } /* for each nonzero ... */ + + /* Check to see if j belongs in the same supernode as j-1 */ + if ( jcol == 0 ) { /* Do nothing for column 0 */ + nsuper = supno[0] = 0; + } else { + fsupc = xsup[nsuper]; + jptr = xlsub[jcol]; /* Not compressed yet */ + jm1ptr = xlsub[jcolm1]; + +#ifdef T2_SUPER + if ( (nextl-jptr != jptr-jm1ptr-1) ) jsuper = EMPTY; +#endif + /* Make sure the number of columns in a supernode doesn't + exceed threshold. */ + if ( jcol - fsupc >= maxsuper ) jsuper = EMPTY; + + /* If jcol starts a new supernode, reclaim storage space in + * lsub from the previous supernode. Note we only store + * the subscript set of the first and last columns of + * a supernode. (first for num values, last for pruning) + */ + if ( jsuper == EMPTY ) { /* starts a new supernode */ + if ( (fsupc < jcolm1-1) ) { /* >= 3 columns in nsuper */ +#ifdef CHK_COMPRESS + printf(" Compress lsub[] at super %d-%d\n", fsupc, jcolm1); +#endif + ito = xlsub[fsupc+1]; + xlsub[jcolm1] = ito; + istop = ito + jptr - jm1ptr; + xprune[jcolm1] = istop; /* Initialize xprune[jcol-1] */ + xlsub[jcol] = istop; + for (ifrom = jm1ptr; ifrom < nextl; ++ifrom, ++ito) + lsub[ito] = lsub[ifrom]; + nextl = ito; /* = istop + length(jcol) */ + } + nsuper++; + supno[jcol] = nsuper; + } /* if a new supernode */ + + } /* else: jcol > 0 */ + + /* Tidy up the pointers before exit */ + xsup[nsuper+1] = jcolp1; + supno[jcolp1] = nsuper; + xprune[jcol] = nextl; /* Initialize upper bound for pruning */ + xlsub[jcolp1] = nextl; + + return 0; +} diff --git a/intern/opennl/superlu/scopy_to_ucol.c b/intern/opennl/superlu/scopy_to_ucol.c new file mode 100644 index 00000000000..fd97352923f --- /dev/null +++ b/intern/opennl/superlu/scopy_to_ucol.c @@ -0,0 +1,105 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" +#include "util.h" + +int +scopy_to_ucol( + int jcol, /* in */ + int nseg, /* in */ + int *segrep, /* in */ + int *repfnz, /* in */ + int *perm_r, /* in */ + float *dense, /* modified - reset to zero on return */ + GlobalLU_t *Glu /* modified */ + ) +{ +/* + * Gather from SPA dense[*] to global ucol[*]. + */ + int ksub, krep, ksupno; + int i, k, kfnz, segsze; + int fsupc, isub, irow; + int jsupno, nextu; + int new_next, mem_error; + int *xsup, *supno; + int *lsub, *xlsub; + float *ucol; + int *usub, *xusub; + int nzumax; + + float zero = 0.0; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + ucol = Glu->ucol; + usub = Glu->usub; + xusub = Glu->xusub; + nzumax = Glu->nzumax; + + jsupno = supno[jcol]; + nextu = xusub[jcol]; + k = nseg - 1; + for (ksub = 0; ksub < nseg; ksub++) { + krep = segrep[k--]; + ksupno = supno[krep]; + + if ( ksupno != jsupno ) { /* Should go into ucol[] */ + kfnz = repfnz[krep]; + if ( kfnz != EMPTY ) { /* Nonzero U-segment */ + + fsupc = xsup[ksupno]; + isub = xlsub[fsupc] + kfnz - fsupc; + segsze = krep - kfnz + 1; + + new_next = nextu + segsze; + while ( new_next > nzumax ) { + if ((mem_error = sLUMemXpand(jcol, nextu, UCOL, &nzumax, Glu))) + return (mem_error); + ucol = Glu->ucol; + if ((mem_error = sLUMemXpand(jcol, nextu, USUB, &nzumax, Glu))) + return (mem_error); + usub = Glu->usub; + lsub = Glu->lsub; + } + + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + usub[nextu] = perm_r[irow]; + ucol[nextu] = dense[irow]; + dense[irow] = zero; + nextu++; + isub++; + } + + } + + } + + } /* for each segment... */ + + xusub[jcol + 1] = nextu; /* Close U[*,jcol] */ + return 0; +} diff --git a/intern/opennl/superlu/sgssv.c b/intern/opennl/superlu/sgssv.c new file mode 100644 index 00000000000..ede3dc83907 --- /dev/null +++ b/intern/opennl/superlu/sgssv.c @@ -0,0 +1,221 @@ + + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +#include "ssp_defs.h" + +void +sgssv(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r, + SuperMatrix *L, SuperMatrix *U, SuperMatrix *B, + SuperLUStat_t *stat, int *info ) +{ +/* + * Purpose + * ======= + * + * SGSSV solves the system of linear equations A*X=B, using the + * LU factorization from SGSTRF. It performs the following steps: + * + * 1. If A is stored column-wise (A->Stype = SLU_NC): + * + * 1.1. Permute the columns of A, forming A*Pc, where Pc + * is a permutation matrix. For more details of this step, + * see sp_preorder.c. + * + * 1.2. Factor A as Pr*A*Pc=L*U with the permutation Pr determined + * by Gaussian elimination with partial pivoting. + * L is unit lower triangular with offdiagonal entries + * bounded by 1 in magnitude, and U is upper triangular. + * + * 1.3. Solve the system of equations A*X=B using the factored + * form of A. + * + * 2. If A is stored row-wise (A->Stype = SLU_NR), apply the + * above algorithm to the transpose of A: + * + * 2.1. Permute columns of transpose(A) (rows of A), + * forming transpose(A)*Pc, where Pc is a permutation matrix. + * For more details of this step, see sp_preorder.c. + * + * 2.2. Factor A as Pr*transpose(A)*Pc=L*U with the permutation Pr + * determined by Gaussian elimination with partial pivoting. + * L is unit lower triangular with offdiagonal entries + * bounded by 1 in magnitude, and U is upper triangular. + * + * 2.3. Solve the system of equations A*X=B using the factored + * form of A. + * + * See supermatrix.h for the definition of 'SuperMatrix' structure. + * + * Arguments + * ========= + * + * options (input) superlu_options_t* + * The structure defines the input parameters to control + * how the LU decomposition will be performed and how the + * system will be solved. + * + * A (input) SuperMatrix* + * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number + * of linear equations is A->nrow. Currently, the type of A can be: + * Stype = SLU_NC or SLU_NR; Dtype = SLU_S; Mtype = SLU_GE. + * In the future, more general A may be handled. + * + * perm_c (input/output) int* + * If A->Stype = SLU_NC, column permutation vector of size A->ncol + * which defines the permutation matrix Pc; perm_c[i] = j means + * column i of A is in position j in A*Pc. + * If A->Stype = SLU_NR, column permutation vector of size A->nrow + * which describes permutation of columns of transpose(A) + * (rows of A) as described above. + * + * If options->ColPerm = MY_PERMC or options->Fact = SamePattern or + * options->Fact = SamePattern_SameRowPerm, it is an input argument. + * On exit, perm_c may be overwritten by the product of the input + * perm_c and a permutation that postorders the elimination tree + * of Pc'*A'*A*Pc; perm_c is not changed if the elimination tree + * is already in postorder. + * Otherwise, it is an output argument. + * + * perm_r (input/output) int* + * If A->Stype = SLU_NC, row permutation vector of size A->nrow, + * which defines the permutation matrix Pr, and is determined + * by partial pivoting. perm_r[i] = j means row i of A is in + * position j in Pr*A. + * If A->Stype = SLU_NR, permutation vector of size A->ncol, which + * determines permutation of rows of transpose(A) + * (columns of A) as described above. + * + * If options->RowPerm = MY_PERMR or + * options->Fact = SamePattern_SameRowPerm, perm_r is an + * input argument. + * otherwise it is an output argument. + * + * L (output) SuperMatrix* + * The factor L from the factorization + * Pr*A*Pc=L*U (if A->Stype = SLU_NC) or + * Pr*transpose(A)*Pc=L*U (if A->Stype = SLU_NR). + * Uses compressed row subscripts storage for supernodes, i.e., + * L has types: Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU. + * + * U (output) SuperMatrix* + * The factor U from the factorization + * Pr*A*Pc=L*U (if A->Stype = SLU_NC) or + * Pr*transpose(A)*Pc=L*U (if A->Stype = SLU_NR). + * Uses column-wise storage scheme, i.e., U has types: + * Stype = SLU_NC, Dtype = SLU_S, Mtype = SLU_TRU. + * + * B (input/output) SuperMatrix* + * B has types: Stype = SLU_DN, Dtype = SLU_S, Mtype = SLU_GE. + * On entry, the right hand side matrix. + * On exit, the solution matrix if info = 0; + * + * stat (output) SuperLUStat_t* + * Record the statistics on runtime and floating-point operation count. + * See util.h for the definition of 'SuperLUStat_t'. + * + * info (output) int* + * = 0: successful exit + * > 0: if info = i, and i is + * <= A->ncol: U(i,i) is exactly zero. The factorization has + * been completed, but the factor U is exactly singular, + * so the solution could not be computed. + * > A->ncol: number of bytes allocated when memory allocation + * failure occurred, plus A->ncol. + * + */ + DNformat *Bstore; + SuperMatrix *AA = NULL;/* A in SLU_NC format used by the factorization routine.*/ + SuperMatrix AC; /* Matrix postmultiplied by Pc */ + int lwork = 0, *etree, i; + + /* Set default values for some parameters */ + int panel_size; /* panel size */ + int relax; /* no of columns in a relaxed snodes */ + int permc_spec; + trans_t trans = NOTRANS; + double *utime; + double t; /* Temporary time */ + + /* Test the input parameters ... */ + *info = 0; + Bstore = B->Store; + if ( options->Fact != DOFACT ) *info = -1; + else if ( A->nrow != A->ncol || A->nrow < 0 || + (A->Stype != SLU_NC && A->Stype != SLU_NR) || + A->Dtype != SLU_S || A->Mtype != SLU_GE ) + *info = -2; + else if ( B->ncol < 0 || Bstore->lda < SUPERLU_MAX(0, A->nrow) || + B->Stype != SLU_DN || B->Dtype != SLU_S || B->Mtype != SLU_GE ) + *info = -7; + if ( *info != 0 ) { + i = -(*info); + xerbla_("sgssv", &i); + return; + } + + utime = stat->utime; + + /* Convert A to SLU_NC format when necessary. */ + if ( A->Stype == SLU_NR ) { + NRformat *Astore = A->Store; + AA = (SuperMatrix *) SUPERLU_MALLOC( sizeof(SuperMatrix) ); + sCreate_CompCol_Matrix(AA, A->ncol, A->nrow, Astore->nnz, + Astore->nzval, Astore->colind, Astore->rowptr, + SLU_NC, A->Dtype, A->Mtype); + trans = TRANS; + } else { + if ( A->Stype == SLU_NC ) AA = A; + } + + t = SuperLU_timer_(); + /* + * Get column permutation vector perm_c[], according to permc_spec: + * permc_spec = NATURAL: natural ordering + * permc_spec = MMD_AT_PLUS_A: minimum degree on structure of A'+A + * permc_spec = MMD_ATA: minimum degree on structure of A'*A + * permc_spec = COLAMD: approximate minimum degree column ordering + * permc_spec = MY_PERMC: the ordering already supplied in perm_c[] + */ + permc_spec = options->ColPerm; + if ( permc_spec != MY_PERMC && options->Fact == DOFACT ) + get_perm_c(permc_spec, AA, perm_c); + utime[COLPERM] = SuperLU_timer_() - t; + + etree = intMalloc(A->ncol); + + t = SuperLU_timer_(); + sp_preorder(options, AA, perm_c, etree, &AC); + utime[ETREE] = SuperLU_timer_() - t; + + panel_size = sp_ienv(1); + relax = sp_ienv(2); + + /*printf("Factor PA = LU ... relax %d\tw %d\tmaxsuper %d\trowblk %d\n", + relax, panel_size, sp_ienv(3), sp_ienv(4));*/ + t = SuperLU_timer_(); + /* Compute the LU factorization of A. */ + sgstrf(options, &AC, relax, panel_size, + etree, NULL, lwork, perm_c, perm_r, L, U, stat, info); + utime[FACT] = SuperLU_timer_() - t; + + t = SuperLU_timer_(); + if ( *info == 0 ) { + /* Solve the system A*X=B, overwriting B with X. */ + sgstrs (trans, L, U, perm_c, perm_r, B, stat, info); + } + utime[SOLVE] = SuperLU_timer_() - t; + + SUPERLU_FREE (etree); + Destroy_CompCol_Permuted(&AC); + if ( A->Stype == SLU_NR ) { + Destroy_SuperMatrix_Store(AA); + SUPERLU_FREE(AA); + } + +} diff --git a/intern/opennl/superlu/sgstrf.c b/intern/opennl/superlu/sgstrf.c new file mode 100644 index 00000000000..42f8dc9d0ee --- /dev/null +++ b/intern/opennl/superlu/sgstrf.c @@ -0,0 +1,433 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +void +sgstrf (superlu_options_t *options, SuperMatrix *A, + int relax, int panel_size, int *etree, void *work, int lwork, + int *perm_c, int *perm_r, SuperMatrix *L, SuperMatrix *U, + SuperLUStat_t *stat, int *info) +{ +/* + * Purpose + * ======= + * + * SGSTRF computes an LU factorization of a general sparse m-by-n + * matrix A using partial pivoting with row interchanges. + * The factorization has the form + * Pr * A = L * U + * where Pr is a row permutation matrix, L is lower triangular with unit + * diagonal elements (lower trapezoidal if A->nrow > A->ncol), and U is upper + * triangular (upper trapezoidal if A->nrow < A->ncol). + * + * See supermatrix.h for the definition of 'SuperMatrix' structure. + * + * Arguments + * ========= + * + * options (input) superlu_options_t* + * The structure defines the input parameters to control + * how the LU decomposition will be performed. + * + * A (input) SuperMatrix* + * Original matrix A, permuted by columns, of dimension + * (A->nrow, A->ncol). The type of A can be: + * Stype = SLU_NCP; Dtype = SLU_S; Mtype = SLU_GE. + * + * drop_tol (input) float (NOT IMPLEMENTED) + * Drop tolerance parameter. At step j of the Gaussian elimination, + * if abs(A_ij)/(max_i abs(A_ij)) < drop_tol, drop entry A_ij. + * 0 <= drop_tol <= 1. The default value of drop_tol is 0. + * + * relax (input) int + * To control degree of relaxing supernodes. If the number + * of nodes (columns) in a subtree of the elimination tree is less + * than relax, this subtree is considered as one supernode, + * regardless of the row structures of those columns. + * + * panel_size (input) int + * A panel consists of at most panel_size consecutive columns. + * + * etree (input) int*, dimension (A->ncol) + * Elimination tree of A'*A. + * Note: etree is a vector of parent pointers for a forest whose + * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol. + * On input, the columns of A should be permuted so that the + * etree is in a certain postorder. + * + * work (input/output) void*, size (lwork) (in bytes) + * User-supplied work space and space for the output data structures. + * Not referenced if lwork = 0; + * + * lwork (input) int + * Specifies the size of work array in bytes. + * = 0: allocate space internally by system malloc; + * > 0: use user-supplied work array of length lwork in bytes, + * returns error if space runs out. + * = -1: the routine guesses the amount of space needed without + * performing the factorization, and returns it in + * *info; no other side effects. + * + * perm_c (input) int*, dimension (A->ncol) + * Column permutation vector, which defines the + * permutation matrix Pc; perm_c[i] = j means column i of A is + * in position j in A*Pc. + * When searching for diagonal, perm_c[*] is applied to the + * row subscripts of A, so that diagonal threshold pivoting + * can find the diagonal of A, rather than that of A*Pc. + * + * perm_r (input/output) int*, dimension (A->nrow) + * Row permutation vector which defines the permutation matrix Pr, + * perm_r[i] = j means row i of A is in position j in Pr*A. + * If options->Fact = SamePattern_SameRowPerm, the pivoting routine + * will try to use the input perm_r, unless a certain threshold + * criterion is violated. In that case, perm_r is overwritten by + * a new permutation determined by partial pivoting or diagonal + * threshold pivoting. + * Otherwise, perm_r is output argument; + * + * L (output) SuperMatrix* + * The factor L from the factorization Pr*A=L*U; use compressed row + * subscripts storage for supernodes, i.e., L has type: + * Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU. + * + * U (output) SuperMatrix* + * The factor U from the factorization Pr*A*Pc=L*U. Use column-wise + * storage scheme, i.e., U has types: Stype = SLU_NC, + * Dtype = SLU_S, Mtype = SLU_TRU. + * + * stat (output) SuperLUStat_t* + * Record the statistics on runtime and floating-point operation count. + * See util.h for the definition of 'SuperLUStat_t'. + * + * info (output) int* + * = 0: successful exit + * < 0: if info = -i, the i-th argument had an illegal value + * > 0: if info = i, and i is + * <= A->ncol: U(i,i) is exactly zero. The factorization has + * been completed, but the factor U is exactly singular, + * and division by zero will occur if it is used to solve a + * system of equations. + * > A->ncol: number of bytes allocated when memory allocation + * failure occurred, plus A->ncol. If lwork = -1, it is + * the estimated amount of space needed, plus A->ncol. + * + * ====================================================================== + * + * Local Working Arrays: + * ====================== + * m = number of rows in the matrix + * n = number of columns in the matrix + * + * xprune[0:n-1]: xprune[*] points to locations in subscript + * vector lsub[*]. For column i, xprune[i] denotes the point where + * structural pruning begins. I.e. only xlsub[i],..,xprune[i]-1 need + * to be traversed for symbolic factorization. + * + * marker[0:3*m-1]: marker[i] = j means that node i has been + * reached when working on column j. + * Storage: relative to original row subscripts + * NOTE: There are 3 of them: marker/marker1 are used for panel dfs, + * see spanel_dfs.c; marker2 is used for inner-factorization, + * see scolumn_dfs.c. + * + * parent[0:m-1]: parent vector used during dfs + * Storage: relative to new row subscripts + * + * xplore[0:m-1]: xplore[i] gives the location of the next (dfs) + * unexplored neighbor of i in lsub[*] + * + * segrep[0:nseg-1]: contains the list of supernodal representatives + * in topological order of the dfs. A supernode representative is the + * last column of a supernode. + * The maximum size of segrep[] is n. + * + * repfnz[0:W*m-1]: for a nonzero segment U[*,j] that ends at a + * supernodal representative r, repfnz[r] is the location of the first + * nonzero in this segment. It is also used during the dfs: repfnz[r]>0 + * indicates the supernode r has been explored. + * NOTE: There are W of them, each used for one column of a panel. + * + * panel_lsub[0:W*m-1]: temporary for the nonzeros row indices below + * the panel diagonal. These are filled in during spanel_dfs(), and are + * used later in the inner LU factorization within the panel. + * panel_lsub[]/dense[] pair forms the SPA data structure. + * NOTE: There are W of them. + * + * dense[0:W*m-1]: sparse accumulating (SPA) vector for intermediate values; + * NOTE: there are W of them. + * + * tempv[0:*]: real temporary used for dense numeric kernels; + * The size of this array is defined by NUM_TEMPV() in ssp_defs.h. + * + */ + /* Local working arrays */ + NCPformat *Astore; + int *iperm_r = NULL; /* inverse of perm_r; + used when options->Fact == SamePattern_SameRowPerm */ + int *iperm_c; /* inverse of perm_c */ + int *iwork; + float *swork; + int *segrep, *repfnz, *parent, *xplore; + int *panel_lsub; /* dense[]/panel_lsub[] pair forms a w-wide SPA */ + int *xprune; + int *marker; + float *dense, *tempv; + int *relax_end; + float *a; + int *asub; + int *xa_begin, *xa_end; + int *xsup, *supno; + int *xlsub, *xlusup, *xusub; + int nzlumax; + static GlobalLU_t Glu; /* persistent to facilitate multiple factors. */ + + /* Local scalars */ + fact_t fact = options->Fact; + double diag_pivot_thresh = options->DiagPivotThresh; + int pivrow; /* pivotal row number in the original matrix A */ + int nseg1; /* no of segments in U-column above panel row jcol */ + int nseg; /* no of segments in each U-column */ + register int jcol; + register int kcol; /* end column of a relaxed snode */ + register int icol; + register int i, k, jj, new_next, iinfo; + int m, n, min_mn, jsupno, fsupc, nextlu, nextu; + int w_def; /* upper bound on panel width */ + int usepr, iperm_r_allocated = 0; + int nnzL, nnzU; + int *panel_histo = stat->panel_histo; + flops_t *ops = stat->ops; + + iinfo = 0; + m = A->nrow; + n = A->ncol; + min_mn = SUPERLU_MIN(m, n); + Astore = A->Store; + a = Astore->nzval; + asub = Astore->rowind; + xa_begin = Astore->colbeg; + xa_end = Astore->colend; + + /* Allocate storage common to the factor routines */ + *info = sLUMemInit(fact, work, lwork, m, n, Astore->nnz, + panel_size, L, U, &Glu, &iwork, &swork); + if ( *info ) return; + + xsup = Glu.xsup; + supno = Glu.supno; + xlsub = Glu.xlsub; + xlusup = Glu.xlusup; + xusub = Glu.xusub; + + SetIWork(m, n, panel_size, iwork, &segrep, &parent, &xplore, + &repfnz, &panel_lsub, &xprune, &marker); + sSetRWork(m, panel_size, swork, &dense, &tempv); + + usepr = (fact == SamePattern_SameRowPerm); + if ( usepr ) { + /* Compute the inverse of perm_r */ + iperm_r = (int *) intMalloc(m); + for (k = 0; k < m; ++k) iperm_r[perm_r[k]] = k; + iperm_r_allocated = 1; + } + iperm_c = (int *) intMalloc(n); + for (k = 0; k < n; ++k) iperm_c[perm_c[k]] = k; + + /* Identify relaxed snodes */ + relax_end = (int *) intMalloc(n); + if ( options->SymmetricMode == YES ) { + heap_relax_snode(n, etree, relax, marker, relax_end); + } else { + relax_snode(n, etree, relax, marker, relax_end); + } + + ifill (perm_r, m, EMPTY); + ifill (marker, m * NO_MARKER, EMPTY); + supno[0] = -1; + xsup[0] = xlsub[0] = xusub[0] = xlusup[0] = 0; + w_def = panel_size; + + /* + * Work on one "panel" at a time. A panel is one of the following: + * (a) a relaxed supernode at the bottom of the etree, or + * (b) panel_size contiguous columns, defined by the user + */ + for (jcol = 0; jcol < min_mn; ) { + + if ( relax_end[jcol] != EMPTY ) { /* start of a relaxed snode */ + kcol = relax_end[jcol]; /* end of the relaxed snode */ + panel_histo[kcol-jcol+1]++; + + /* -------------------------------------- + * Factorize the relaxed supernode(jcol:kcol) + * -------------------------------------- */ + /* Determine the union of the row structure of the snode */ + if ( (*info = ssnode_dfs(jcol, kcol, asub, xa_begin, xa_end, + xprune, marker, &Glu)) != 0 ) + return; + + nextu = xusub[jcol]; + nextlu = xlusup[jcol]; + jsupno = supno[jcol]; + fsupc = xsup[jsupno]; + new_next = nextlu + (xlsub[fsupc+1]-xlsub[fsupc])*(kcol-jcol+1); + nzlumax = Glu.nzlumax; + while ( new_next > nzlumax ) { + if ( (*info = sLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, &Glu)) ) + return; + } + + for (icol = jcol; icol<= kcol; icol++) { + xusub[icol+1] = nextu; + + /* Scatter into SPA dense[*] */ + for (k = xa_begin[icol]; k < xa_end[icol]; k++) + dense[asub[k]] = a[k]; + + /* Numeric update within the snode */ + ssnode_bmod(icol, fsupc, dense, tempv, &Glu, stat); + + if ( (*info = spivotL(icol, diag_pivot_thresh, &usepr, perm_r, + iperm_r, iperm_c, &pivrow, &Glu, stat)) ) + if ( iinfo == 0 ) iinfo = *info; + +#ifdef DEBUG + sprint_lu_col("[1]: ", icol, pivrow, xprune, &Glu); +#endif + + } + + jcol = icol; + + } else { /* Work on one panel of panel_size columns */ + + /* Adjust panel_size so that a panel won't overlap with the next + * relaxed snode. + */ + panel_size = w_def; + for (k = jcol + 1; k < SUPERLU_MIN(jcol+panel_size, min_mn); k++) + if ( relax_end[k] != EMPTY ) { + panel_size = k - jcol; + break; + } + if ( k == min_mn ) panel_size = min_mn - jcol; + panel_histo[panel_size]++; + + /* symbolic factor on a panel of columns */ + spanel_dfs(m, panel_size, jcol, A, perm_r, &nseg1, + dense, panel_lsub, segrep, repfnz, xprune, + marker, parent, xplore, &Glu); + + /* numeric sup-panel updates in topological order */ + spanel_bmod(m, panel_size, jcol, nseg1, dense, + tempv, segrep, repfnz, &Glu, stat); + + /* Sparse LU within the panel, and below panel diagonal */ + for ( jj = jcol; jj < jcol + panel_size; jj++) { + k = (jj - jcol) * m; /* column index for w-wide arrays */ + + nseg = nseg1; /* Begin after all the panel segments */ + + if ((*info = scolumn_dfs(m, jj, perm_r, &nseg, &panel_lsub[k], + segrep, &repfnz[k], xprune, marker, + parent, xplore, &Glu)) != 0) return; + + /* Numeric updates */ + if ((*info = scolumn_bmod(jj, (nseg - nseg1), &dense[k], + tempv, &segrep[nseg1], &repfnz[k], + jcol, &Glu, stat)) != 0) return; + + /* Copy the U-segments to ucol[*] */ + if ((*info = scopy_to_ucol(jj, nseg, segrep, &repfnz[k], + perm_r, &dense[k], &Glu)) != 0) + return; + + if ( (*info = spivotL(jj, diag_pivot_thresh, &usepr, perm_r, + iperm_r, iperm_c, &pivrow, &Glu, stat)) ) + if ( iinfo == 0 ) iinfo = *info; + + /* Prune columns (0:jj-1) using column jj */ + spruneL(jj, perm_r, pivrow, nseg, segrep, + &repfnz[k], xprune, &Glu); + + /* Reset repfnz[] for this column */ + resetrep_col (nseg, segrep, &repfnz[k]); + +#ifdef DEBUG + sprint_lu_col("[2]: ", jj, pivrow, xprune, &Glu); +#endif + + } + + jcol += panel_size; /* Move to the next panel */ + + } /* else */ + + } /* for */ + + *info = iinfo; + + if ( m > n ) { + k = 0; + for (i = 0; i < m; ++i) + if ( perm_r[i] == EMPTY ) { + perm_r[i] = n + k; + ++k; + } + } + + countnz(min_mn, xprune, &nnzL, &nnzU, &Glu); + fixupL(min_mn, perm_r, &Glu); + + sLUWorkFree(iwork, swork, &Glu); /* Free work space and compress storage */ + + if ( fact == SamePattern_SameRowPerm ) { + /* L and U structures may have changed due to possibly different + pivoting, even though the storage is available. + There could also be memory expansions, so the array locations + may have changed, */ + ((SCformat *)L->Store)->nnz = nnzL; + ((SCformat *)L->Store)->nsuper = Glu.supno[n]; + ((SCformat *)L->Store)->nzval = Glu.lusup; + ((SCformat *)L->Store)->nzval_colptr = Glu.xlusup; + ((SCformat *)L->Store)->rowind = Glu.lsub; + ((SCformat *)L->Store)->rowind_colptr = Glu.xlsub; + ((NCformat *)U->Store)->nnz = nnzU; + ((NCformat *)U->Store)->nzval = Glu.ucol; + ((NCformat *)U->Store)->rowind = Glu.usub; + ((NCformat *)U->Store)->colptr = Glu.xusub; + } else { + sCreate_SuperNode_Matrix(L, A->nrow, A->ncol, nnzL, Glu.lusup, + Glu.xlusup, Glu.lsub, Glu.xlsub, Glu.supno, + Glu.xsup, SLU_SC, SLU_S, SLU_TRLU); + sCreate_CompCol_Matrix(U, min_mn, min_mn, nnzU, Glu.ucol, + Glu.usub, Glu.xusub, SLU_NC, SLU_S, SLU_TRU); + } + + ops[FACT] += ops[TRSV] + ops[GEMV]; + + if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r); + SUPERLU_FREE (iperm_c); + SUPERLU_FREE (relax_end); + +} diff --git a/intern/opennl/superlu/sgstrs.c b/intern/opennl/superlu/sgstrs.c new file mode 100644 index 00000000000..b83545f8ce6 --- /dev/null +++ b/intern/opennl/superlu/sgstrs.c @@ -0,0 +1,331 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + + +/* + * Function prototypes + */ +void susolve(int, int, float*, float*); +void slsolve(int, int, float*, float*); +void smatvec(int, int, int, float*, float*, float*); +void sprint_soln(int , float *); + +void +sgstrs (trans_t trans, SuperMatrix *L, SuperMatrix *U, + int *perm_c, int *perm_r, SuperMatrix *B, + SuperLUStat_t *stat, int *info) +{ +/* + * Purpose + * ======= + * + * SGSTRS solves a system of linear equations A*X=B or A'*X=B + * with A sparse and B dense, using the LU factorization computed by + * SGSTRF. + * + * See supermatrix.h for the definition of 'SuperMatrix' structure. + * + * Arguments + * ========= + * + * trans (input) trans_t + * Specifies the form of the system of equations: + * = NOTRANS: A * X = B (No transpose) + * = TRANS: A'* X = B (Transpose) + * = CONJ: A**H * X = B (Conjugate transpose) + * + * L (input) SuperMatrix* + * The factor L from the factorization Pr*A*Pc=L*U as computed by + * sgstrf(). Use compressed row subscripts storage for supernodes, + * i.e., L has types: Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU. + * + * U (input) SuperMatrix* + * The factor U from the factorization Pr*A*Pc=L*U as computed by + * sgstrf(). Use column-wise storage scheme, i.e., U has types: + * Stype = SLU_NC, Dtype = SLU_S, Mtype = SLU_TRU. + * + * perm_c (input) int*, dimension (L->ncol) + * Column permutation vector, which defines the + * permutation matrix Pc; perm_c[i] = j means column i of A is + * in position j in A*Pc. + * + * perm_r (input) int*, dimension (L->nrow) + * Row permutation vector, which defines the permutation matrix Pr; + * perm_r[i] = j means row i of A is in position j in Pr*A. + * + * B (input/output) SuperMatrix* + * B has types: Stype = SLU_DN, Dtype = SLU_S, Mtype = SLU_GE. + * On entry, the right hand side matrix. + * On exit, the solution matrix if info = 0; + * + * stat (output) SuperLUStat_t* + * Record the statistics on runtime and floating-point operation count. + * See util.h for the definition of 'SuperLUStat_t'. + * + * info (output) int* + * = 0: successful exit + * < 0: if info = -i, the i-th argument had an illegal value + * + */ +#ifdef _CRAY + _fcd ftcs1, ftcs2, ftcs3, ftcs4; +#endif +#ifdef USE_VENDOR_BLAS + float alpha = 1.0, beta = 1.0; + float *work_col; +#endif + DNformat *Bstore; + float *Bmat; + SCformat *Lstore; + NCformat *Ustore; + float *Lval, *Uval; + int fsupc, nrow, nsupr, nsupc, luptr, istart, irow; + int i, j, k, iptr, jcol, n, ldb, nrhs; + float *work, *rhs_work, *soln; + flops_t solve_ops; + void sprint_soln(); + + /* Test input parameters ... */ + *info = 0; + Bstore = B->Store; + ldb = Bstore->lda; + nrhs = B->ncol; + if ( trans != NOTRANS && trans != TRANS && trans != CONJ ) *info = -1; + else if ( L->nrow != L->ncol || L->nrow < 0 || + L->Stype != SLU_SC || L->Dtype != SLU_S || L->Mtype != SLU_TRLU ) + *info = -2; + else if ( U->nrow != U->ncol || U->nrow < 0 || + U->Stype != SLU_NC || U->Dtype != SLU_S || U->Mtype != SLU_TRU ) + *info = -3; + else if ( ldb < SUPERLU_MAX(0, L->nrow) || + B->Stype != SLU_DN || B->Dtype != SLU_S || B->Mtype != SLU_GE ) + *info = -6; + if ( *info ) { + i = -(*info); + xerbla_("sgstrs", &i); + return; + } + + n = L->nrow; + work = floatCalloc(n * nrhs); + if ( !work ) ABORT("Malloc fails for local work[]."); + soln = floatMalloc(n); + if ( !soln ) ABORT("Malloc fails for local soln[]."); + + Bmat = Bstore->nzval; + Lstore = L->Store; + Lval = Lstore->nzval; + Ustore = U->Store; + Uval = Ustore->nzval; + solve_ops = 0; + + if ( trans == NOTRANS ) { + /* Permute right hand sides to form Pr*B */ + for (i = 0; i < nrhs; i++) { + rhs_work = &Bmat[i*ldb]; + for (k = 0; k < n; k++) soln[perm_r[k]] = rhs_work[k]; + for (k = 0; k < n; k++) rhs_work[k] = soln[k]; + } + + /* Forward solve PLy=Pb. */ + for (k = 0; k <= Lstore->nsuper; k++) { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + nsupc = L_FST_SUPC(k+1) - fsupc; + nrow = nsupr - nsupc; + + solve_ops += nsupc * (nsupc - 1) * nrhs; + solve_ops += 2 * nrow * nsupc * nrhs; + + if ( nsupc == 1 ) { + for (j = 0; j < nrhs; j++) { + rhs_work = &Bmat[j*ldb]; + luptr = L_NZ_START(fsupc); + for (iptr=istart+1; iptr < L_SUB_START(fsupc+1); iptr++){ + irow = L_SUB(iptr); + ++luptr; + rhs_work[irow] -= rhs_work[fsupc] * Lval[luptr]; + } + } + } else { + luptr = L_NZ_START(fsupc); +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + ftcs1 = _cptofcd("L", strlen("L")); + ftcs2 = _cptofcd("N", strlen("N")); + ftcs3 = _cptofcd("U", strlen("U")); + STRSM( ftcs1, ftcs1, ftcs2, ftcs3, &nsupc, &nrhs, &alpha, + &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); + + SGEMM( ftcs2, ftcs2, &nrow, &nrhs, &nsupc, &alpha, + &Lval[luptr+nsupc], &nsupr, &Bmat[fsupc], &ldb, + &beta, &work[0], &n ); +#else + strsm_("L", "L", "N", "U", &nsupc, &nrhs, &alpha, + &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); + + sgemm_( "N", "N", &nrow, &nrhs, &nsupc, &alpha, + &Lval[luptr+nsupc], &nsupr, &Bmat[fsupc], &ldb, + &beta, &work[0], &n ); +#endif + for (j = 0; j < nrhs; j++) { + rhs_work = &Bmat[j*ldb]; + work_col = &work[j*n]; + iptr = istart + nsupc; + for (i = 0; i < nrow; i++) { + irow = L_SUB(iptr); + rhs_work[irow] -= work_col[i]; /* Scatter */ + work_col[i] = 0.0; + iptr++; + } + } +#else + for (j = 0; j < nrhs; j++) { + rhs_work = &Bmat[j*ldb]; + slsolve (nsupr, nsupc, &Lval[luptr], &rhs_work[fsupc]); + smatvec (nsupr, nrow, nsupc, &Lval[luptr+nsupc], + &rhs_work[fsupc], &work[0] ); + + iptr = istart + nsupc; + for (i = 0; i < nrow; i++) { + irow = L_SUB(iptr); + rhs_work[irow] -= work[i]; + work[i] = 0.0; + iptr++; + } + } +#endif + } /* else ... */ + } /* for L-solve */ + +#ifdef DEBUG + printf("After L-solve: y=\n"); + sprint_soln(n, Bmat); +#endif + + /* + * Back solve Ux=y. + */ + for (k = Lstore->nsuper; k >= 0; k--) { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + + solve_ops += nsupc * (nsupc + 1) * nrhs; + + if ( nsupc == 1 ) { + rhs_work = &Bmat[0]; + for (j = 0; j < nrhs; j++) { + rhs_work[fsupc] /= Lval[luptr]; + rhs_work += ldb; + } + } else { +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + ftcs1 = _cptofcd("L", strlen("L")); + ftcs2 = _cptofcd("U", strlen("U")); + ftcs3 = _cptofcd("N", strlen("N")); + STRSM( ftcs1, ftcs2, ftcs3, ftcs3, &nsupc, &nrhs, &alpha, + &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); +#else + strsm_("L", "U", "N", "N", &nsupc, &nrhs, &alpha, + &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); +#endif +#else + for (j = 0; j < nrhs; j++) + susolve ( nsupr, nsupc, &Lval[luptr], &Bmat[fsupc+j*ldb] ); +#endif + } + + for (j = 0; j < nrhs; ++j) { + rhs_work = &Bmat[j*ldb]; + for (jcol = fsupc; jcol < fsupc + nsupc; jcol++) { + solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); + for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++ ){ + irow = U_SUB(i); + rhs_work[irow] -= rhs_work[jcol] * Uval[i]; + } + } + } + + } /* for U-solve */ + +#ifdef DEBUG + printf("After U-solve: x=\n"); + sprint_soln(n, Bmat); +#endif + + /* Compute the final solution X := Pc*X. */ + for (i = 0; i < nrhs; i++) { + rhs_work = &Bmat[i*ldb]; + for (k = 0; k < n; k++) soln[k] = rhs_work[perm_c[k]]; + for (k = 0; k < n; k++) rhs_work[k] = soln[k]; + } + + stat->ops[SOLVE] = solve_ops; + + } else { /* Solve A'*X=B or CONJ(A)*X=B */ + /* Permute right hand sides to form Pc'*B. */ + for (i = 0; i < nrhs; i++) { + rhs_work = &Bmat[i*ldb]; + for (k = 0; k < n; k++) soln[perm_c[k]] = rhs_work[k]; + for (k = 0; k < n; k++) rhs_work[k] = soln[k]; + } + + stat->ops[SOLVE] = 0; + for (k = 0; k < nrhs; ++k) { + + /* Multiply by inv(U'). */ + sp_strsv("U", "T", "N", L, U, &Bmat[k*ldb], stat, info); + + /* Multiply by inv(L'). */ + sp_strsv("L", "T", "U", L, U, &Bmat[k*ldb], stat, info); + + } + /* Compute the final solution X := Pr'*X (=inv(Pr)*X) */ + for (i = 0; i < nrhs; i++) { + rhs_work = &Bmat[i*ldb]; + for (k = 0; k < n; k++) soln[k] = rhs_work[perm_r[k]]; + for (k = 0; k < n; k++) rhs_work[k] = soln[k]; + } + + } + + SUPERLU_FREE(work); + SUPERLU_FREE(soln); +} + +/* + * Diagnostic print of the solution vector + */ +void +sprint_soln(int n, float *soln) +{ + int i; + + for (i = 0; i < n; i++) + printf("\t%d: %.4f\n", i, soln[i]); +} diff --git a/intern/opennl/superlu/smemory.c b/intern/opennl/superlu/smemory.c new file mode 100644 index 00000000000..79da748671a --- /dev/null +++ b/intern/opennl/superlu/smemory.c @@ -0,0 +1,676 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +#include "ssp_defs.h" + +/* Constants */ +#define NO_MEMTYPE 4 /* 0: lusup; + 1: ucol; + 2: lsub; + 3: usub */ +#define GluIntArray(n) (5 * (n) + 5) + +/* Internal prototypes */ +void *sexpand (int *, MemType,int, int, GlobalLU_t *); +int sLUWorkInit (int, int, int, int **, float **, LU_space_t); +void copy_mem_float (int, void *, void *); +void sStackCompress (GlobalLU_t *); +void sSetupSpace (void *, int, LU_space_t *); +void *suser_malloc (int, int); +void suser_free (int, int); + +/* External prototypes (in memory.c - prec-indep) */ +extern void copy_mem_int (int, void *, void *); +extern void user_bcopy (char *, char *, int); + +/* Headers for 4 types of dynamatically managed memory */ +typedef struct e_node { + int size; /* length of the memory that has been used */ + void *mem; /* pointer to the new malloc'd store */ +} ExpHeader; + +typedef struct { + int size; + int used; + int top1; /* grow upward, relative to &array[0] */ + int top2; /* grow downward */ + void *array; +} LU_stack_t; + +/* Variables local to this file */ +static ExpHeader *expanders = 0; /* Array of pointers to 4 types of memory */ +static LU_stack_t stack; +static int no_expand; + +/* Macros to manipulate stack */ +#define StackFull(x) ( x + stack.used >= stack.size ) +#define NotDoubleAlign(addr) ( (long int)addr & 7 ) +#define DoubleAlign(addr) ( ((long int)addr + 7) & ~7L ) +#define TempSpace(m, w) ( (2*w + 4 + NO_MARKER) * m * sizeof(int) + \ + (w + 1) * m * sizeof(float) ) +#define Reduce(alpha) ((alpha + 1) / 2) /* i.e. (alpha-1)/2 + 1 */ + + + + +/* + * Setup the memory model to be used for factorization. + * lwork = 0: use system malloc; + * lwork > 0: use user-supplied work[] space. + */ +void sSetupSpace(void *work, int lwork, LU_space_t *MemModel) +{ + if ( lwork == 0 ) { + *MemModel = SYSTEM; /* malloc/free */ + } else if ( lwork > 0 ) { + *MemModel = USER; /* user provided space */ + stack.used = 0; + stack.top1 = 0; + stack.top2 = (lwork/4)*4; /* must be word addressable */ + stack.size = stack.top2; + stack.array = (void *) work; + } +} + + + +void *suser_malloc(int bytes, int which_end) +{ + void *buf; + + if ( StackFull(bytes) ) return (NULL); + + if ( which_end == HEAD ) { + buf = (char*) stack.array + stack.top1; + stack.top1 += bytes; + } else { + stack.top2 -= bytes; + buf = (char*) stack.array + stack.top2; + } + + stack.used += bytes; + return buf; +} + + +void suser_free(int bytes, int which_end) +{ + if ( which_end == HEAD ) { + stack.top1 -= bytes; + } else { + stack.top2 += bytes; + } + stack.used -= bytes; +} + + + +/* + * mem_usage consists of the following fields: + * - for_lu (float) + * The amount of space used in bytes for the L\U data structures. + * - total_needed (float) + * The amount of space needed in bytes to perform factorization. + * - expansions (int) + * Number of memory expansions during the LU factorization. + */ +int sQuerySpace(SuperMatrix *L, SuperMatrix *U, mem_usage_t *mem_usage) +{ + SCformat *Lstore; + NCformat *Ustore; + register int n, iword, dword, panel_size = sp_ienv(1); + + Lstore = L->Store; + Ustore = U->Store; + n = L->ncol; + iword = sizeof(int); + dword = sizeof(float); + + /* For LU factors */ + mem_usage->for_lu = (float)( (4*n + 3) * iword + Lstore->nzval_colptr[n] * + dword + Lstore->rowind_colptr[n] * iword ); + mem_usage->for_lu += (float)( (n + 1) * iword + + Ustore->colptr[n] * (dword + iword) ); + + /* Working storage to support factorization */ + mem_usage->total_needed = mem_usage->for_lu + + (float)( (2 * panel_size + 4 + NO_MARKER) * n * iword + + (panel_size + 1) * n * dword ); + + mem_usage->expansions = --no_expand; + + return 0; +} /* sQuerySpace */ + +/* + * Allocate storage for the data structures common to all factor routines. + * For those unpredictable size, make a guess as FILL * nnz(A). + * Return value: + * If lwork = -1, return the estimated amount of space required, plus n; + * otherwise, return the amount of space actually allocated when + * memory allocation failure occurred. + */ +int +sLUMemInit(fact_t fact, void *work, int lwork, int m, int n, int annz, + int panel_size, SuperMatrix *L, SuperMatrix *U, GlobalLU_t *Glu, + int **iwork, float **dwork) +{ + int info, iword, dword; + SCformat *Lstore; + NCformat *Ustore; + int *xsup, *supno; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + float *ucol; + int *usub, *xusub; + int nzlmax, nzumax, nzlumax; + int FILL = sp_ienv(6); + + Glu->n = n; + no_expand = 0; + iword = sizeof(int); + dword = sizeof(float); + + if ( !expanders ) + expanders = (ExpHeader*)SUPERLU_MALLOC(NO_MEMTYPE * sizeof(ExpHeader)); + if ( !expanders ) ABORT("SUPERLU_MALLOC fails for expanders"); + + if ( fact != SamePattern_SameRowPerm ) { + /* Guess for L\U factors */ + nzumax = nzlumax = FILL * annz; + nzlmax = SUPERLU_MAX(1, FILL/4.) * annz; + + if ( lwork == -1 ) { + return ( GluIntArray(n) * iword + TempSpace(m, panel_size) + + (nzlmax+nzumax)*iword + (nzlumax+nzumax)*dword + n ); + } else { + sSetupSpace(work, lwork, &Glu->MemModel); + } + +#ifdef DEBUG + printf("sLUMemInit() called: annz %d, MemModel %d\n", + annz, Glu->MemModel); +#endif + + /* Integer pointers for L\U factors */ + if ( Glu->MemModel == SYSTEM ) { + xsup = intMalloc(n+1); + supno = intMalloc(n+1); + xlsub = intMalloc(n+1); + xlusup = intMalloc(n+1); + xusub = intMalloc(n+1); + } else { + xsup = (int *)suser_malloc((n+1) * iword, HEAD); + supno = (int *)suser_malloc((n+1) * iword, HEAD); + xlsub = (int *)suser_malloc((n+1) * iword, HEAD); + xlusup = (int *)suser_malloc((n+1) * iword, HEAD); + xusub = (int *)suser_malloc((n+1) * iword, HEAD); + } + + lusup = (float *) sexpand( &nzlumax, LUSUP, 0, 0, Glu ); + ucol = (float *) sexpand( &nzumax, UCOL, 0, 0, Glu ); + lsub = (int *) sexpand( &nzlmax, LSUB, 0, 0, Glu ); + usub = (int *) sexpand( &nzumax, USUB, 0, 1, Glu ); + + while ( !lusup || !ucol || !lsub || !usub ) { + if ( Glu->MemModel == SYSTEM ) { + SUPERLU_FREE(lusup); + SUPERLU_FREE(ucol); + SUPERLU_FREE(lsub); + SUPERLU_FREE(usub); + } else { + suser_free((nzlumax+nzumax)*dword+(nzlmax+nzumax)*iword, HEAD); + } + nzlumax /= 2; + nzumax /= 2; + nzlmax /= 2; + if ( nzlumax < annz ) { + printf("Not enough memory to perform factorization.\n"); + return (smemory_usage(nzlmax, nzumax, nzlumax, n) + n); + } + lusup = (float *) sexpand( &nzlumax, LUSUP, 0, 0, Glu ); + ucol = (float *) sexpand( &nzumax, UCOL, 0, 0, Glu ); + lsub = (int *) sexpand( &nzlmax, LSUB, 0, 0, Glu ); + usub = (int *) sexpand( &nzumax, USUB, 0, 1, Glu ); + } + + } else { + /* fact == SamePattern_SameRowPerm */ + Lstore = L->Store; + Ustore = U->Store; + xsup = Lstore->sup_to_col; + supno = Lstore->col_to_sup; + xlsub = Lstore->rowind_colptr; + xlusup = Lstore->nzval_colptr; + xusub = Ustore->colptr; + nzlmax = Glu->nzlmax; /* max from previous factorization */ + nzumax = Glu->nzumax; + nzlumax = Glu->nzlumax; + + if ( lwork == -1 ) { + return ( GluIntArray(n) * iword + TempSpace(m, panel_size) + + (nzlmax+nzumax)*iword + (nzlumax+nzumax)*dword + n ); + } else if ( lwork == 0 ) { + Glu->MemModel = SYSTEM; + } else { + Glu->MemModel = USER; + stack.top2 = (lwork/4)*4; /* must be word-addressable */ + stack.size = stack.top2; + } + + lsub = expanders[LSUB].mem = Lstore->rowind; + lusup = expanders[LUSUP].mem = Lstore->nzval; + usub = expanders[USUB].mem = Ustore->rowind; + ucol = expanders[UCOL].mem = Ustore->nzval;; + expanders[LSUB].size = nzlmax; + expanders[LUSUP].size = nzlumax; + expanders[USUB].size = nzumax; + expanders[UCOL].size = nzumax; + } + + Glu->xsup = xsup; + Glu->supno = supno; + Glu->lsub = lsub; + Glu->xlsub = xlsub; + Glu->lusup = lusup; + Glu->xlusup = xlusup; + Glu->ucol = ucol; + Glu->usub = usub; + Glu->xusub = xusub; + Glu->nzlmax = nzlmax; + Glu->nzumax = nzumax; + Glu->nzlumax = nzlumax; + + info = sLUWorkInit(m, n, panel_size, iwork, dwork, Glu->MemModel); + if ( info ) + return ( info + smemory_usage(nzlmax, nzumax, nzlumax, n) + n); + + ++no_expand; + return 0; + +} /* sLUMemInit */ + +/* Allocate known working storage. Returns 0 if success, otherwise + returns the number of bytes allocated so far when failure occurred. */ +int +sLUWorkInit(int m, int n, int panel_size, int **iworkptr, + float **dworkptr, LU_space_t MemModel) +{ + int isize, dsize, extra; + float *old_ptr; + int maxsuper = sp_ienv(3), + rowblk = sp_ienv(4); + + isize = ( (2 * panel_size + 3 + NO_MARKER ) * m + n ) * sizeof(int); + dsize = (m * panel_size + + NUM_TEMPV(m,panel_size,maxsuper,rowblk)) * sizeof(float); + + if ( MemModel == SYSTEM ) + *iworkptr = (int *) intCalloc(isize/sizeof(int)); + else + *iworkptr = (int *) suser_malloc(isize, TAIL); + if ( ! *iworkptr ) { + fprintf(stderr, "sLUWorkInit: malloc fails for local iworkptr[]\n"); + return (isize + n); + } + + if ( MemModel == SYSTEM ) + *dworkptr = (float *) SUPERLU_MALLOC(dsize); + else { + *dworkptr = (float *) suser_malloc(dsize, TAIL); + if ( NotDoubleAlign(*dworkptr) ) { + old_ptr = *dworkptr; + *dworkptr = (float*) DoubleAlign(*dworkptr); + *dworkptr = (float*) ((double*)*dworkptr - 1); + extra = (char*)old_ptr - (char*)*dworkptr; +#ifdef DEBUG + printf("sLUWorkInit: not aligned, extra %d\n", extra); +#endif + stack.top2 -= extra; + stack.used += extra; + } + } + if ( ! *dworkptr ) { + fprintf(stderr, "malloc fails for local dworkptr[]."); + return (isize + dsize + n); + } + + return 0; +} + + +/* + * Set up pointers for real working arrays. + */ +void +sSetRWork(int m, int panel_size, float *dworkptr, + float **dense, float **tempv) +{ + float zero = 0.0; + + int maxsuper = sp_ienv(3), + rowblk = sp_ienv(4); + *dense = dworkptr; + *tempv = *dense + panel_size*m; + sfill (*dense, m * panel_size, zero); + sfill (*tempv, NUM_TEMPV(m,panel_size,maxsuper,rowblk), zero); +} + +/* + * Free the working storage used by factor routines. + */ +void sLUWorkFree(int *iwork, float *dwork, GlobalLU_t *Glu) +{ + if ( Glu->MemModel == SYSTEM ) { + SUPERLU_FREE (iwork); + SUPERLU_FREE (dwork); + } else { + stack.used -= (stack.size - stack.top2); + stack.top2 = stack.size; +/* sStackCompress(Glu); */ + } + + SUPERLU_FREE (expanders); + expanders = 0; +} + +/* Expand the data structures for L and U during the factorization. + * Return value: 0 - successful return + * > 0 - number of bytes allocated when run out of space + */ +int +sLUMemXpand(int jcol, + int next, /* number of elements currently in the factors */ + MemType mem_type, /* which type of memory to expand */ + int *maxlen, /* modified - maximum length of a data structure */ + GlobalLU_t *Glu /* modified - global LU data structures */ + ) +{ + void *new_mem; + +#ifdef DEBUG + printf("sLUMemXpand(): jcol %d, next %d, maxlen %d, MemType %d\n", + jcol, next, *maxlen, mem_type); +#endif + + if (mem_type == USUB) + new_mem = sexpand(maxlen, mem_type, next, 1, Glu); + else + new_mem = sexpand(maxlen, mem_type, next, 0, Glu); + + if ( !new_mem ) { + int nzlmax = Glu->nzlmax; + int nzumax = Glu->nzumax; + int nzlumax = Glu->nzlumax; + fprintf(stderr, "Can't expand MemType %d: jcol %d\n", mem_type, jcol); + return (smemory_usage(nzlmax, nzumax, nzlumax, Glu->n) + Glu->n); + } + + switch ( mem_type ) { + case LUSUP: + Glu->lusup = (float *) new_mem; + Glu->nzlumax = *maxlen; + break; + case UCOL: + Glu->ucol = (float *) new_mem; + Glu->nzumax = *maxlen; + break; + case LSUB: + Glu->lsub = (int *) new_mem; + Glu->nzlmax = *maxlen; + break; + case USUB: + Glu->usub = (int *) new_mem; + Glu->nzumax = *maxlen; + break; + } + + return 0; + +} + + + +void +copy_mem_float(int howmany, void *old, void *new) +{ + register int i; + float *dold = old; + float *dnew = new; + for (i = 0; i < howmany; i++) dnew[i] = dold[i]; +} + +/* + * Expand the existing storage to accommodate more fill-ins. + */ +void +*sexpand ( + int *prev_len, /* length used from previous call */ + MemType type, /* which part of the memory to expand */ + int len_to_copy, /* size of the memory to be copied to new store */ + int keep_prev, /* = 1: use prev_len; + = 0: compute new_len to expand */ + GlobalLU_t *Glu /* modified - global LU data structures */ + ) +{ + float EXPAND = 1.5; + float alpha; + void *new_mem, *old_mem; + int new_len, tries, lword, extra, bytes_to_copy; + + alpha = EXPAND; + + if ( no_expand == 0 || keep_prev ) /* First time allocate requested */ + new_len = *prev_len; + else { + new_len = alpha * *prev_len; + } + + if ( type == LSUB || type == USUB ) lword = sizeof(int); + else lword = sizeof(float); + + if ( Glu->MemModel == SYSTEM ) { + new_mem = (void *) SUPERLU_MALLOC(new_len * lword); +/* new_mem = (void *) calloc(new_len, lword); */ + if ( no_expand != 0 ) { + tries = 0; + if ( keep_prev ) { + if ( !new_mem ) return (NULL); + } else { + while ( !new_mem ) { + if ( ++tries > 10 ) return (NULL); + alpha = Reduce(alpha); + new_len = alpha * *prev_len; + new_mem = (void *) SUPERLU_MALLOC(new_len * lword); +/* new_mem = (void *) calloc(new_len, lword); */ + } + } + if ( type == LSUB || type == USUB ) { + copy_mem_int(len_to_copy, expanders[type].mem, new_mem); + } else { + copy_mem_float(len_to_copy, expanders[type].mem, new_mem); + } + SUPERLU_FREE (expanders[type].mem); + } + expanders[type].mem = (void *) new_mem; + + } else { /* MemModel == USER */ + if ( no_expand == 0 ) { + new_mem = suser_malloc(new_len * lword, HEAD); + if ( NotDoubleAlign(new_mem) && + (type == LUSUP || type == UCOL) ) { + old_mem = new_mem; + new_mem = (void *)DoubleAlign(new_mem); + extra = (char*)new_mem - (char*)old_mem; +#ifdef DEBUG + printf("expand(): not aligned, extra %d\n", extra); +#endif + stack.top1 += extra; + stack.used += extra; + } + expanders[type].mem = (void *) new_mem; + } + else { + tries = 0; + extra = (new_len - *prev_len) * lword; + if ( keep_prev ) { + if ( StackFull(extra) ) return (NULL); + } else { + while ( StackFull(extra) ) { + if ( ++tries > 10 ) return (NULL); + alpha = Reduce(alpha); + new_len = alpha * *prev_len; + extra = (new_len - *prev_len) * lword; + } + } + + if ( type != USUB ) { + new_mem = (void*)((char*)expanders[type + 1].mem + extra); + bytes_to_copy = (char*)stack.array + stack.top1 + - (char*)expanders[type + 1].mem; + user_bcopy(expanders[type+1].mem, new_mem, bytes_to_copy); + + if ( type < USUB ) { + Glu->usub = expanders[USUB].mem = + (void*)((char*)expanders[USUB].mem + extra); + } + if ( type < LSUB ) { + Glu->lsub = expanders[LSUB].mem = + (void*)((char*)expanders[LSUB].mem + extra); + } + if ( type < UCOL ) { + Glu->ucol = expanders[UCOL].mem = + (void*)((char*)expanders[UCOL].mem + extra); + } + stack.top1 += extra; + stack.used += extra; + if ( type == UCOL ) { + stack.top1 += extra; /* Add same amount for USUB */ + stack.used += extra; + } + + } /* if ... */ + + } /* else ... */ + } + + expanders[type].size = new_len; + *prev_len = new_len; + if ( no_expand ) ++no_expand; + + return (void *) expanders[type].mem; + +} /* sexpand */ + + +/* + * Compress the work[] array to remove fragmentation. + */ +void +sStackCompress(GlobalLU_t *Glu) +{ + register int iword, dword, ndim; + char *last, *fragment; + int *ifrom, *ito; + float *dfrom, *dto; + int *xlsub, *lsub, *xusub, *usub, *xlusup; + float *ucol, *lusup; + + iword = sizeof(int); + dword = sizeof(float); + ndim = Glu->n; + + xlsub = Glu->xlsub; + lsub = Glu->lsub; + xusub = Glu->xusub; + usub = Glu->usub; + xlusup = Glu->xlusup; + ucol = Glu->ucol; + lusup = Glu->lusup; + + dfrom = ucol; + dto = (float *)((char*)lusup + xlusup[ndim] * dword); + copy_mem_float(xusub[ndim], dfrom, dto); + ucol = dto; + + ifrom = lsub; + ito = (int *) ((char*)ucol + xusub[ndim] * iword); + copy_mem_int(xlsub[ndim], ifrom, ito); + lsub = ito; + + ifrom = usub; + ito = (int *) ((char*)lsub + xlsub[ndim] * iword); + copy_mem_int(xusub[ndim], ifrom, ito); + usub = ito; + + last = (char*)usub + xusub[ndim] * iword; + fragment = (char*) (((char*)stack.array + stack.top1) - last); + stack.used -= (long int) fragment; + stack.top1 -= (long int) fragment; + + Glu->ucol = ucol; + Glu->lsub = lsub; + Glu->usub = usub; + +#ifdef DEBUG + printf("sStackCompress: fragment %d\n", fragment); + /* for (last = 0; last < ndim; ++last) + print_lu_col("After compress:", last, 0);*/ +#endif + +} + +/* + * Allocate storage for original matrix A + */ +void +sallocateA(int n, int nnz, float **a, int **asub, int **xa) +{ + *a = (float *) floatMalloc(nnz); + *asub = (int *) intMalloc(nnz); + *xa = (int *) intMalloc(n+1); +} + + +float *floatMalloc(int n) +{ + float *buf; + buf = (float *) SUPERLU_MALLOC(n * sizeof(float)); + if ( !buf ) { + ABORT("SUPERLU_MALLOC failed for buf in floatMalloc()\n"); + } + return (buf); +} + +float *floatCalloc(int n) +{ + float *buf; + register int i; + float zero = 0.0; + buf = (float *) SUPERLU_MALLOC(n * sizeof(float)); + if ( !buf ) { + ABORT("SUPERLU_MALLOC failed for buf in floatCalloc()\n"); + } + for (i = 0; i < n; ++i) buf[i] = zero; + return (buf); +} + + +int smemory_usage(const int nzlmax, const int nzumax, + const int nzlumax, const int n) +{ + register int iword, dword; + + iword = sizeof(int); + dword = sizeof(float); + + return (10 * n * iword + + nzlmax * iword + nzumax * (iword + dword) + nzlumax * dword); + +} diff --git a/intern/opennl/superlu/smyblas2.c b/intern/opennl/superlu/smyblas2.c new file mode 100644 index 00000000000..cb2d5cb65af --- /dev/null +++ b/intern/opennl/superlu/smyblas2.c @@ -0,0 +1,232 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + * File name: smyblas2.c + * Purpose: + * Level 2 BLAS operations: solves and matvec, written in C. + * Note: + * This is only used when the system lacks an efficient BLAS library. + */ + +/* + * Solves a dense UNIT lower triangular system. The unit lower + * triangular matrix is stored in a 2D array M(1:nrow,1:ncol). + * The solution will be returned in the rhs vector. + */ + +/* local prototypes*/ +void slsolve ( int, int, float *, float *); +void susolve ( int, int, float *, float *); +void smatvec ( int, int, int, float *, float *, float *); + + +void slsolve ( int ldm, int ncol, float *M, float *rhs ) +{ + int k; + float x0, x1, x2, x3, x4, x5, x6, x7; + float *M0; + register float *Mki0, *Mki1, *Mki2, *Mki3, *Mki4, *Mki5, *Mki6, *Mki7; + register int firstcol = 0; + + M0 = &M[0]; + + while ( firstcol < ncol - 7 ) { /* Do 8 columns */ + Mki0 = M0 + 1; + Mki1 = Mki0 + ldm + 1; + Mki2 = Mki1 + ldm + 1; + Mki3 = Mki2 + ldm + 1; + Mki4 = Mki3 + ldm + 1; + Mki5 = Mki4 + ldm + 1; + Mki6 = Mki5 + ldm + 1; + Mki7 = Mki6 + ldm + 1; + + x0 = rhs[firstcol]; + x1 = rhs[firstcol+1] - x0 * *Mki0++; + x2 = rhs[firstcol+2] - x0 * *Mki0++ - x1 * *Mki1++; + x3 = rhs[firstcol+3] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++; + x4 = rhs[firstcol+4] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++ + - x3 * *Mki3++; + x5 = rhs[firstcol+5] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++ + - x3 * *Mki3++ - x4 * *Mki4++; + x6 = rhs[firstcol+6] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++ + - x3 * *Mki3++ - x4 * *Mki4++ - x5 * *Mki5++; + x7 = rhs[firstcol+7] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++ + - x3 * *Mki3++ - x4 * *Mki4++ - x5 * *Mki5++ + - x6 * *Mki6++; + + rhs[++firstcol] = x1; + rhs[++firstcol] = x2; + rhs[++firstcol] = x3; + rhs[++firstcol] = x4; + rhs[++firstcol] = x5; + rhs[++firstcol] = x6; + rhs[++firstcol] = x7; + ++firstcol; + + for (k = firstcol; k < ncol; k++) + rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++ + - x2 * *Mki2++ - x3 * *Mki3++ + - x4 * *Mki4++ - x5 * *Mki5++ + - x6 * *Mki6++ - x7 * *Mki7++; + + M0 += 8 * ldm + 8; + } + + while ( firstcol < ncol - 3 ) { /* Do 4 columns */ + Mki0 = M0 + 1; + Mki1 = Mki0 + ldm + 1; + Mki2 = Mki1 + ldm + 1; + Mki3 = Mki2 + ldm + 1; + + x0 = rhs[firstcol]; + x1 = rhs[firstcol+1] - x0 * *Mki0++; + x2 = rhs[firstcol+2] - x0 * *Mki0++ - x1 * *Mki1++; + x3 = rhs[firstcol+3] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++; + + rhs[++firstcol] = x1; + rhs[++firstcol] = x2; + rhs[++firstcol] = x3; + ++firstcol; + + for (k = firstcol; k < ncol; k++) + rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++ + - x2 * *Mki2++ - x3 * *Mki3++; + + M0 += 4 * ldm + 4; + } + + if ( firstcol < ncol - 1 ) { /* Do 2 columns */ + Mki0 = M0 + 1; + Mki1 = Mki0 + ldm + 1; + + x0 = rhs[firstcol]; + x1 = rhs[firstcol+1] - x0 * *Mki0++; + + rhs[++firstcol] = x1; + ++firstcol; + + for (k = firstcol; k < ncol; k++) + rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++; + + } + +} + +/* + * Solves a dense upper triangular system. The upper triangular matrix is + * stored in a 2-dim array M(1:ldm,1:ncol). The solution will be returned + * in the rhs vector. + */ +void +susolve ( ldm, ncol, M, rhs ) +int ldm; /* in */ +int ncol; /* in */ +float *M; /* in */ +float *rhs; /* modified */ +{ + float xj; + int jcol, j, irow; + + jcol = ncol - 1; + + for (j = 0; j < ncol; j++) { + + xj = rhs[jcol] / M[jcol + jcol*ldm]; /* M(jcol, jcol) */ + rhs[jcol] = xj; + + for (irow = 0; irow < jcol; irow++) + rhs[irow] -= xj * M[irow + jcol*ldm]; /* M(irow, jcol) */ + + jcol--; + + } +} + + +/* + * Performs a dense matrix-vector multiply: Mxvec = Mxvec + M * vec. + * The input matrix is M(1:nrow,1:ncol); The product is returned in Mxvec[]. + */ +void smatvec ( ldm, nrow, ncol, M, vec, Mxvec ) + +int ldm; /* in -- leading dimension of M */ +int nrow; /* in */ +int ncol; /* in */ +float *M; /* in */ +float *vec; /* in */ +float *Mxvec; /* in/out */ + +{ + float vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7; + float *M0; + register float *Mki0, *Mki1, *Mki2, *Mki3, *Mki4, *Mki5, *Mki6, *Mki7; + register int firstcol = 0; + int k; + + M0 = &M[0]; + while ( firstcol < ncol - 7 ) { /* Do 8 columns */ + + Mki0 = M0; + Mki1 = Mki0 + ldm; + Mki2 = Mki1 + ldm; + Mki3 = Mki2 + ldm; + Mki4 = Mki3 + ldm; + Mki5 = Mki4 + ldm; + Mki6 = Mki5 + ldm; + Mki7 = Mki6 + ldm; + + vi0 = vec[firstcol++]; + vi1 = vec[firstcol++]; + vi2 = vec[firstcol++]; + vi3 = vec[firstcol++]; + vi4 = vec[firstcol++]; + vi5 = vec[firstcol++]; + vi6 = vec[firstcol++]; + vi7 = vec[firstcol++]; + + for (k = 0; k < nrow; k++) + Mxvec[k] += vi0 * *Mki0++ + vi1 * *Mki1++ + + vi2 * *Mki2++ + vi3 * *Mki3++ + + vi4 * *Mki4++ + vi5 * *Mki5++ + + vi6 * *Mki6++ + vi7 * *Mki7++; + + M0 += 8 * ldm; + } + + while ( firstcol < ncol - 3 ) { /* Do 4 columns */ + + Mki0 = M0; + Mki1 = Mki0 + ldm; + Mki2 = Mki1 + ldm; + Mki3 = Mki2 + ldm; + + vi0 = vec[firstcol++]; + vi1 = vec[firstcol++]; + vi2 = vec[firstcol++]; + vi3 = vec[firstcol++]; + for (k = 0; k < nrow; k++) + Mxvec[k] += vi0 * *Mki0++ + vi1 * *Mki1++ + + vi2 * *Mki2++ + vi3 * *Mki3++ ; + + M0 += 4 * ldm; + } + + while ( firstcol < ncol ) { /* Do 1 column */ + + Mki0 = M0; + vi0 = vec[firstcol++]; + for (k = 0; k < nrow; k++) + Mxvec[k] += vi0 * *Mki0++; + + M0 += ldm; + } + +} + diff --git a/intern/opennl/superlu/sp_coletree.c b/intern/opennl/superlu/sp_coletree.c new file mode 100644 index 00000000000..d49919167f5 --- /dev/null +++ b/intern/opennl/superlu/sp_coletree.c @@ -0,0 +1,332 @@ + +/* Elimination tree computation and layout routines */ + +#include +#include +#include "ssp_defs.h" + +/* + * Implementation of disjoint set union routines. + * Elements are integers in 0..n-1, and the + * names of the sets themselves are of type int. + * + * Calls are: + * initialize_disjoint_sets (n) initial call. + * s = make_set (i) returns a set containing only i. + * s = link (t, u) returns s = t union u, destroying t and u. + * s = find (i) return name of set containing i. + * finalize_disjoint_sets final call. + * + * This implementation uses path compression but not weighted union. + * See Tarjan's book for details. + * John Gilbert, CMI, 1987. + * + * Implemented path-halving by XSL 07/05/95. + */ + +static int *pp; /* parent array for sets */ + +static +int *mxCallocInt(int n) +{ + register int i; + int *buf; + + buf = (int *) SUPERLU_MALLOC( n * sizeof(int) ); + if ( !buf ) { + ABORT("SUPERLU_MALLOC fails for buf in mxCallocInt()"); + } + for (i = 0; i < n; i++) buf[i] = 0; + return (buf); +} + +static +void initialize_disjoint_sets ( + int n + ) +{ + pp = mxCallocInt(n); +} + + +static +int make_set ( + int i + ) +{ + pp[i] = i; + return i; +} + + +static +int link ( + int s, + int t + ) +{ + pp[s] = t; + return t; +} + + +/* PATH HALVING */ +static +int find (int i) +{ + register int p, gp; + + p = pp[i]; + gp = pp[p]; + while (gp != p) { + pp[i] = gp; + i = gp; + p = pp[i]; + gp = pp[p]; + } + return (p); +} + +#if 0 +/* PATH COMPRESSION */ +static +int find ( + int i + ) +{ + if (pp[i] != i) + pp[i] = find (pp[i]); + return pp[i]; +} +#endif + +static +void finalize_disjoint_sets ( + void + ) +{ + SUPERLU_FREE(pp); +} + + +/* + * Find the elimination tree for A'*A. + * This uses something similar to Liu's algorithm. + * It runs in time O(nz(A)*log n) and does not form A'*A. + * + * Input: + * Sparse matrix A. Numeric values are ignored, so any + * explicit zeros are treated as nonzero. + * Output: + * Integer array of parents representing the elimination + * tree of the symbolic product A'*A. Each vertex is a + * column of A, and nc means a root of the elimination forest. + * + * John R. Gilbert, Xerox, 10 Dec 1990 + * Based on code by JRG dated 1987, 1988, and 1990. + */ + +/* + * Nonsymmetric elimination tree + */ +int +sp_coletree( + int *acolst, int *acolend, /* column start and end past 1 */ + int *arow, /* row indices of A */ + int nr, int nc, /* dimension of A */ + int *parent /* parent in elim tree */ + ) +{ + int *root; /* root of subtee of etree */ + int *firstcol; /* first nonzero col in each row*/ + int rset, cset; + int row, col; + int rroot; + int p; + + root = mxCallocInt (nc); + initialize_disjoint_sets (nc); + + /* Compute firstcol[row] = first nonzero column in row */ + + firstcol = mxCallocInt (nr); + for (row = 0; row < nr; firstcol[row++] = nc); + for (col = 0; col < nc; col++) + for (p = acolst[col]; p < acolend[col]; p++) { + row = arow[p]; + firstcol[row] = SUPERLU_MIN(firstcol[row], col); + } + + /* Compute etree by Liu's algorithm for symmetric matrices, + except use (firstcol[r],c) in place of an edge (r,c) of A. + Thus each row clique in A'*A is replaced by a star + centered at its first vertex, which has the same fill. */ + + for (col = 0; col < nc; col++) { + cset = make_set (col); + root[cset] = col; + parent[col] = nc; /* Matlab */ + for (p = acolst[col]; p < acolend[col]; p++) { + row = firstcol[arow[p]]; + if (row >= col) continue; + rset = find (row); + rroot = root[rset]; + if (rroot != col) { + parent[rroot] = col; + cset = link (cset, rset); + root[cset] = col; + } + } + } + + SUPERLU_FREE (root); + SUPERLU_FREE (firstcol); + finalize_disjoint_sets (); + return 0; +} + +/* + * q = TreePostorder (n, p); + * + * Postorder a tree. + * Input: + * p is a vector of parent pointers for a forest whose + * vertices are the integers 0 to n-1; p[root]==n. + * Output: + * q is a vector indexed by 0..n-1 such that q[i] is the + * i-th vertex in a postorder numbering of the tree. + * + * ( 2/7/95 modified by X.Li: + * q is a vector indexed by 0:n-1 such that vertex i is the + * q[i]-th vertex in a postorder numbering of the tree. + * That is, this is the inverse of the previous q. ) + * + * In the child structure, lower-numbered children are represented + * first, so that a tree which is already numbered in postorder + * will not have its order changed. + * + * Written by John Gilbert, Xerox, 10 Dec 1990. + * Based on code written by John Gilbert at CMI in 1987. + */ + +static int *first_kid, *next_kid; /* Linked list of children. */ +static int *post, postnum; + +static +/* + * Depth-first search from vertex v. + */ +void etdfs ( + int v + ) +{ + int w; + + for (w = first_kid[v]; w != -1; w = next_kid[w]) { + etdfs (w); + } + /* post[postnum++] = v; in Matlab */ + post[v] = postnum++; /* Modified by X.Li on 2/14/95 */ +} + + +/* + * Post order a tree + */ +int *TreePostorder( + int n, + int *parent +) +{ + int v, dad; + + /* Allocate storage for working arrays and results */ + first_kid = mxCallocInt (n+1); + next_kid = mxCallocInt (n+1); + post = mxCallocInt (n+1); + + /* Set up structure describing children */ + for (v = 0; v <= n; first_kid[v++] = -1); + for (v = n-1; v >= 0; v--) { + dad = parent[v]; + next_kid[v] = first_kid[dad]; + first_kid[dad] = v; + } + + /* Depth-first search from dummy root vertex #n */ + postnum = 0; + etdfs (n); + + SUPERLU_FREE (first_kid); + SUPERLU_FREE (next_kid); + return post; +} + + +/* + * p = spsymetree (A); + * + * Find the elimination tree for symmetric matrix A. + * This uses Liu's algorithm, and runs in time O(nz*log n). + * + * Input: + * Square sparse matrix A. No check is made for symmetry; + * elements below and on the diagonal are ignored. + * Numeric values are ignored, so any explicit zeros are + * treated as nonzero. + * Output: + * Integer array of parents representing the etree, with n + * meaning a root of the elimination forest. + * Note: + * This routine uses only the upper triangle, while sparse + * Cholesky (as in spchol.c) uses only the lower. Matlab's + * dense Cholesky uses only the upper. This routine could + * be modified to use the lower triangle either by transposing + * the matrix or by traversing it by rows with auxiliary + * pointer and link arrays. + * + * John R. Gilbert, Xerox, 10 Dec 1990 + * Based on code by JRG dated 1987, 1988, and 1990. + * Modified by X.S. Li, November 1999. + */ + +/* + * Symmetric elimination tree + */ +int +sp_symetree( + int *acolst, int *acolend, /* column starts and ends past 1 */ + int *arow, /* row indices of A */ + int n, /* dimension of A */ + int *parent /* parent in elim tree */ + ) +{ + int *root; /* root of subtree of etree */ + int rset, cset; + int row, col; + int rroot; + int p; + + root = mxCallocInt (n); + initialize_disjoint_sets (n); + + for (col = 0; col < n; col++) { + cset = make_set (col); + root[cset] = col; + parent[col] = n; /* Matlab */ + for (p = acolst[col]; p < acolend[col]; p++) { + row = arow[p]; + if (row >= col) continue; + rset = find (row); + rroot = root[rset]; + if (rroot != col) { + parent[rroot] = col; + cset = link (cset, rset); + root[cset] = col; + } + } + } + SUPERLU_FREE (root); + finalize_disjoint_sets (); + return 0; +} /* SP_SYMETREE */ diff --git a/intern/opennl/superlu/sp_ienv.c b/intern/opennl/superlu/sp_ienv.c new file mode 100644 index 00000000000..5b0ba7b2151 --- /dev/null +++ b/intern/opennl/superlu/sp_ienv.c @@ -0,0 +1,65 @@ +/* + * File name: sp_ienv.c + * History: Modified from lapack routine ILAENV + */ + +#include "ssp_defs.h" +#include "util.h" + +int +sp_ienv(int ispec) +{ +/* + Purpose + ======= + + sp_ienv() is inquired to choose machine-dependent parameters for the + local environment. See ISPEC for a description of the parameters. + + This version provides a set of parameters which should give good, + but not optimal, performance on many of the currently available + computers. Users are encouraged to modify this subroutine to set + the tuning parameters for their particular machine using the option + and problem size information in the arguments. + + Arguments + ========= + + ISPEC (input) int + Specifies the parameter to be returned as the value of SP_IENV. + = 1: the panel size w; a panel consists of w consecutive + columns of matrix A in the process of Gaussian elimination. + The best value depends on machine's cache characters. + = 2: the relaxation parameter relax; if the number of + nodes (columns) in a subtree of the elimination tree is less + than relax, this subtree is considered as one supernode, + regardless of their row structures. + = 3: the maximum size for a supernode; + = 4: the minimum row dimension for 2-D blocking to be used; + = 5: the minimum column dimension for 2-D blocking to be used; + = 6: the estimated fills factor for L and U, compared with A; + + (SP_IENV) (output) int + >= 0: the value of the parameter specified by ISPEC + < 0: if SP_IENV = -k, the k-th argument had an illegal value. + + ===================================================================== +*/ + int i; + + switch (ispec) { + case 1: return (10); + case 2: return (5); + case 3: return (100); + case 4: return (200); + case 5: return (40); + case 6: return (20); + } + + /* Invalid value for ISPEC */ + i = 1; + xerbla_("sp_ienv", &i); + return 0; + +} /* sp_ienv_ */ + diff --git a/intern/opennl/superlu/sp_preorder.c b/intern/opennl/superlu/sp_preorder.c new file mode 100644 index 00000000000..c40ebc9a4f7 --- /dev/null +++ b/intern/opennl/superlu/sp_preorder.c @@ -0,0 +1,206 @@ +#include "ssp_defs.h" + +int check_perm(char *, int , int *); + + +void +sp_preorder(superlu_options_t *options, SuperMatrix *A, int *perm_c, + int *etree, SuperMatrix *AC) +{ +/* + * Purpose + * ======= + * + * sp_preorder() permutes the columns of the original matrix. It performs + * the following steps: + * + * 1. Apply column permutation perm_c[] to A's column pointers to form AC; + * + * 2. If options->Fact = DOFACT, then + * (1) Compute column elimination tree etree[] of AC'AC; + * (2) Post order etree[] to get a postordered elimination tree etree[], + * and a postorder permutation post[]; + * (3) Apply post[] permutation to columns of AC; + * (4) Overwrite perm_c[] with the product perm_c * post. + * + * Arguments + * ========= + * + * options (input) superlu_options_t* + * Specifies whether or not the elimination tree will be re-used. + * If options->Fact == DOFACT, this means first time factor A, + * etree is computed, postered, and output. + * Otherwise, re-factor A, etree is input, unchanged on exit. + * + * A (input) SuperMatrix* + * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number + * of the linear equations is A->nrow. Currently, the type of A can be: + * Stype = NC or SLU_NCP; Mtype = SLU_GE. + * In the future, more general A may be handled. + * + * perm_c (input/output) int* + * Column permutation vector of size A->ncol, which defines the + * permutation matrix Pc; perm_c[i] = j means column i of A is + * in position j in A*Pc. + * If options->Fact == DOFACT, perm_c is both input and output. + * On output, it is changed according to a postorder of etree. + * Otherwise, perm_c is input. + * + * etree (input/output) int* + * Elimination tree of Pc'*A'*A*Pc, dimension A->ncol. + * If options->Fact == DOFACT, etree is an output argument, + * otherwise it is an input argument. + * Note: etree is a vector of parent pointers for a forest whose + * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol. + * + * AC (output) SuperMatrix* + * The resulting matrix after applied the column permutation + * perm_c[] to matrix A. The type of AC can be: + * Stype = SLU_NCP; Dtype = A->Dtype; Mtype = SLU_GE. + * + */ + + NCformat *Astore; + NCPformat *ACstore; + int *iwork, *post; + register int n, i; + + n = A->ncol; + + /* Apply column permutation perm_c to A's column pointers so to + obtain NCP format in AC = A*Pc. */ + AC->Stype = SLU_NCP; + AC->Dtype = A->Dtype; + AC->Mtype = A->Mtype; + AC->nrow = A->nrow; + AC->ncol = A->ncol; + Astore = A->Store; + ACstore = AC->Store = (void *) SUPERLU_MALLOC( sizeof(NCPformat) ); + if ( !ACstore ) ABORT("SUPERLU_MALLOC fails for ACstore"); + ACstore->nnz = Astore->nnz; + ACstore->nzval = Astore->nzval; + ACstore->rowind = Astore->rowind; + ACstore->colbeg = (int*) SUPERLU_MALLOC(n*sizeof(int)); + if ( !(ACstore->colbeg) ) ABORT("SUPERLU_MALLOC fails for ACstore->colbeg"); + ACstore->colend = (int*) SUPERLU_MALLOC(n*sizeof(int)); + if ( !(ACstore->colend) ) ABORT("SUPERLU_MALLOC fails for ACstore->colend"); + +#ifdef DEBUG + print_int_vec("pre_order:", n, perm_c); + check_perm("Initial perm_c", n, perm_c); +#endif + + for (i = 0; i < n; i++) { + ACstore->colbeg[perm_c[i]] = Astore->colptr[i]; + ACstore->colend[perm_c[i]] = Astore->colptr[i+1]; + } + + if ( options->Fact == DOFACT ) { +#undef ETREE_ATplusA +#ifdef ETREE_ATplusA + /*-------------------------------------------- + COMPUTE THE ETREE OF Pc*(A'+A)*Pc'. + --------------------------------------------*/ + int *b_colptr, *b_rowind, bnz, j; + int *c_colbeg, *c_colend; + + /*printf("Use etree(A'+A)\n");*/ + + /* Form B = A + A'. */ + at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind, + &bnz, &b_colptr, &b_rowind); + + /* Form C = Pc*B*Pc'. */ + c_colbeg = (int*) SUPERLU_MALLOC(2*n*sizeof(int)); + c_colend = c_colbeg + n; + if (!c_colbeg ) ABORT("SUPERLU_MALLOC fails for c_colbeg/c_colend"); + for (i = 0; i < n; i++) { + c_colbeg[perm_c[i]] = b_colptr[i]; + c_colend[perm_c[i]] = b_colptr[i+1]; + } + for (j = 0; j < n; ++j) { + for (i = c_colbeg[j]; i < c_colend[j]; ++i) { + b_rowind[i] = perm_c[b_rowind[i]]; + } + } + + /* Compute etree of C. */ + sp_symetree(c_colbeg, c_colend, b_rowind, n, etree); + + SUPERLU_FREE(b_colptr); + if ( bnz ) SUPERLU_FREE(b_rowind); + SUPERLU_FREE(c_colbeg); + +#else + /*-------------------------------------------- + COMPUTE THE COLUMN ELIMINATION TREE. + --------------------------------------------*/ + sp_coletree(ACstore->colbeg, ACstore->colend, ACstore->rowind, + A->nrow, A->ncol, etree); +#endif +#ifdef DEBUG + print_int_vec("etree:", n, etree); +#endif + + /* In symmetric mode, do not do postorder here. */ + if ( options->SymmetricMode == NO ) { + /* Post order etree */ + post = (int *) TreePostorder(n, etree); + /* for (i = 0; i < n+1; ++i) inv_post[post[i]] = i; + iwork = post; */ + +#ifdef DEBUG + print_int_vec("post:", n+1, post); + check_perm("post", n, post); +#endif + iwork = (int*) SUPERLU_MALLOC((n+1)*sizeof(int)); + if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]"); + + /* Renumber etree in postorder */ + for (i = 0; i < n; ++i) iwork[post[i]] = post[etree[i]]; + for (i = 0; i < n; ++i) etree[i] = iwork[i]; + +#ifdef DEBUG + print_int_vec("postorder etree:", n, etree); +#endif + + /* Postmultiply A*Pc by post[] */ + for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colbeg[i]; + for (i = 0; i < n; ++i) ACstore->colbeg[i] = iwork[i]; + for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colend[i]; + for (i = 0; i < n; ++i) ACstore->colend[i] = iwork[i]; + + for (i = 0; i < n; ++i) + iwork[i] = post[perm_c[i]]; /* product of perm_c and post */ + for (i = 0; i < n; ++i) perm_c[i] = iwork[i]; + +#ifdef DEBUG + print_int_vec("Pc*post:", n, perm_c); + check_perm("final perm_c", n, perm_c); +#endif + SUPERLU_FREE (post); + SUPERLU_FREE (iwork); + } /* end postordering */ + + } /* if options->Fact == DOFACT ... */ + +} + +int check_perm(char *what, int n, int *perm) +{ + register int i; + int *marker; + marker = (int *) calloc(n, sizeof(int)); + + for (i = 0; i < n; ++i) { + if ( marker[perm[i]] == 1 || perm[i] >= n ) { + printf("%s: Not a valid PERM[%d] = %d\n", what, i, perm[i]); + ABORT("check_perm"); + } else { + marker[perm[i]] = 1; + } + } + + SUPERLU_FREE(marker); + return 0; +} diff --git a/intern/opennl/superlu/spanel_bmod.c b/intern/opennl/superlu/spanel_bmod.c new file mode 100644 index 00000000000..a59a9086df1 --- /dev/null +++ b/intern/opennl/superlu/spanel_bmod.c @@ -0,0 +1,449 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include +#include "ssp_defs.h" + +/* + * Function prototypes + */ +void slsolve(int, int, float *, float *); +void smatvec(int, int, int, float *, float *, float *); +extern void scheck_tempv(); + +void +spanel_bmod ( + const int m, /* in - number of rows in the matrix */ + const int w, /* in */ + const int jcol, /* in */ + const int nseg, /* in */ + float *dense, /* out, of size n by w */ + float *tempv, /* working array */ + int *segrep, /* in */ + int *repfnz, /* in, of size n by w */ + GlobalLU_t *Glu, /* modified */ + SuperLUStat_t *stat /* output */ + ) +{ +/* + * Purpose + * ======= + * + * Performs numeric block updates (sup-panel) in topological order. + * It features: col-col, 2cols-col, 3cols-col, and sup-col updates. + * Special processing on the supernodal portion of L\U[*,j] + * + * Before entering this routine, the original nonzeros in the panel + * were already copied into the spa[m,w]. + * + * Updated/Output parameters- + * dense[0:m-1,w]: L[*,j:j+w-1] and U[*,j:j+w-1] are returned + * collectively in the m-by-w vector dense[*]. + * + */ + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + _fcd ftcs1 = _cptofcd("L", strlen("L")), + ftcs2 = _cptofcd("N", strlen("N")), + ftcs3 = _cptofcd("U", strlen("U")); +#endif + int incx = 1, incy = 1; + float alpha, beta; +#endif + + register int k, ksub; + int fsupc, nsupc, nsupr, nrow; + int krep, krep_ind; + float ukj, ukj1, ukj2; + int luptr, luptr1, luptr2; + int segsze; + int block_nrow; /* no of rows in a block row */ + register int lptr; /* Points to the row subscripts of a supernode */ + int kfnz, irow, no_zeros; + register int isub, isub1, i; + register int jj; /* Index through each column in the panel */ + int *xsup, *supno; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + int *repfnz_col; /* repfnz[] for a column in the panel */ + float *dense_col; /* dense[] for a column in the panel */ + float *tempv1; /* Used in 1-D update */ + float *TriTmp, *MatvecTmp; /* used in 2-D update */ + float zero = 0.0; + register int ldaTmp; + register int r_ind, r_hi; + static int first = 1, maxsuper, rowblk, colblk; + flops_t *ops = stat->ops; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + + if ( first ) { + maxsuper = sp_ienv(3); + rowblk = sp_ienv(4); + colblk = sp_ienv(5); + first = 0; + } + ldaTmp = maxsuper + rowblk; + + /* + * For each nonz supernode segment of U[*,j] in topological order + */ + k = nseg - 1; + for (ksub = 0; ksub < nseg; ksub++) { /* for each updating supernode */ + + /* krep = representative of current k-th supernode + * fsupc = first supernodal column + * nsupc = no of columns in a supernode + * nsupr = no of rows in a supernode + */ + krep = segrep[k--]; + fsupc = xsup[supno[krep]]; + nsupc = krep - fsupc + 1; + nsupr = xlsub[fsupc+1] - xlsub[fsupc]; + nrow = nsupr - nsupc; + lptr = xlsub[fsupc]; + krep_ind = lptr + nsupc - 1; + + repfnz_col = repfnz; + dense_col = dense; + + if ( nsupc >= colblk && nrow > rowblk ) { /* 2-D block update */ + + TriTmp = tempv; + + /* Sequence through each column in panel -- triangular solves */ + for (jj = jcol; jj < jcol + w; jj++, + repfnz_col += m, dense_col += m, TriTmp += ldaTmp ) { + + kfnz = repfnz_col[krep]; + if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ + + segsze = krep - kfnz + 1; + luptr = xlusup[fsupc]; + + ops[TRSV] += segsze * (segsze - 1); + ops[GEMV] += 2 * nrow * segsze; + + /* Case 1: Update U-segment of size 1 -- col-col update */ + if ( segsze == 1 ) { + ukj = dense_col[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc; + + for (i = lptr + nsupc; i < xlsub[fsupc+1]; i++) { + irow = lsub[i]; + dense_col[irow] -= ukj * lusup[luptr]; + ++luptr; + } + + } else if ( segsze <= 3 ) { + ukj = dense_col[lsub[krep_ind]]; + ukj1 = dense_col[lsub[krep_ind - 1]]; + luptr += nsupr*(nsupc-1) + nsupc-1; + luptr1 = luptr - nsupr; + + if ( segsze == 2 ) { + ukj -= ukj1 * lusup[luptr1]; + dense_col[lsub[krep_ind]] = ukj; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + luptr++; luptr1++; + dense_col[irow] -= (ukj*lusup[luptr] + + ukj1*lusup[luptr1]); + } + } else { + ukj2 = dense_col[lsub[krep_ind - 2]]; + luptr2 = luptr1 - nsupr; + ukj1 -= ukj2 * lusup[luptr2-1]; + ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; + dense_col[lsub[krep_ind]] = ukj; + dense_col[lsub[krep_ind-1]] = ukj1; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + luptr++; luptr1++; luptr2++; + dense_col[irow] -= ( ukj*lusup[luptr] + + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); + } + } + + } else { /* segsze >= 4 */ + + /* Copy U[*,j] segment from dense[*] to TriTmp[*], which + holds the result of triangular solves. */ + no_zeros = kfnz - fsupc; + isub = lptr + no_zeros; + for (i = 0; i < segsze; ++i) { + irow = lsub[isub]; + TriTmp[i] = dense_col[irow]; /* Gather */ + ++isub; + } + + /* start effective triangle */ + luptr += nsupr * no_zeros + no_zeros; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], + &nsupr, TriTmp, &incx ); +#else + strsv_( "L", "N", "U", &segsze, &lusup[luptr], + &nsupr, TriTmp, &incx ); +#endif +#else + slsolve ( nsupr, segsze, &lusup[luptr], TriTmp ); +#endif + + + } /* else ... */ + + } /* for jj ... end tri-solves */ + + /* Block row updates; push all the way into dense[*] block */ + for ( r_ind = 0; r_ind < nrow; r_ind += rowblk ) { + + r_hi = SUPERLU_MIN(nrow, r_ind + rowblk); + block_nrow = SUPERLU_MIN(rowblk, r_hi - r_ind); + luptr = xlusup[fsupc] + nsupc + r_ind; + isub1 = lptr + nsupc + r_ind; + + repfnz_col = repfnz; + TriTmp = tempv; + dense_col = dense; + + /* Sequence through each column in panel -- matrix-vector */ + for (jj = jcol; jj < jcol + w; jj++, + repfnz_col += m, dense_col += m, TriTmp += ldaTmp) { + + kfnz = repfnz_col[krep]; + if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ + + segsze = krep - kfnz + 1; + if ( segsze <= 3 ) continue; /* skip unrolled cases */ + + /* Perform a block update, and scatter the result of + matrix-vector to dense[]. */ + no_zeros = kfnz - fsupc; + luptr1 = luptr + nsupr * no_zeros; + MatvecTmp = &TriTmp[maxsuper]; + +#ifdef USE_VENDOR_BLAS + alpha = one; + beta = zero; +#ifdef _CRAY + SGEMV(ftcs2, &block_nrow, &segsze, &alpha, &lusup[luptr1], + &nsupr, TriTmp, &incx, &beta, MatvecTmp, &incy); +#else + sgemv_("N", &block_nrow, &segsze, &alpha, &lusup[luptr1], + &nsupr, TriTmp, &incx, &beta, MatvecTmp, &incy); +#endif +#else + smatvec(nsupr, block_nrow, segsze, &lusup[luptr1], + TriTmp, MatvecTmp); +#endif + + /* Scatter MatvecTmp[*] into SPA dense[*] temporarily + * such that MatvecTmp[*] can be re-used for the + * the next blok row update. dense[] will be copied into + * global store after the whole panel has been finished. + */ + isub = isub1; + for (i = 0; i < block_nrow; i++) { + irow = lsub[isub]; + dense_col[irow] -= MatvecTmp[i]; + MatvecTmp[i] = zero; + ++isub; + } + + } /* for jj ... */ + + } /* for each block row ... */ + + /* Scatter the triangular solves into SPA dense[*] */ + repfnz_col = repfnz; + TriTmp = tempv; + dense_col = dense; + + for (jj = jcol; jj < jcol + w; jj++, + repfnz_col += m, dense_col += m, TriTmp += ldaTmp) { + kfnz = repfnz_col[krep]; + if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ + + segsze = krep - kfnz + 1; + if ( segsze <= 3 ) continue; /* skip unrolled cases */ + + no_zeros = kfnz - fsupc; + isub = lptr + no_zeros; + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + dense_col[irow] = TriTmp[i]; + TriTmp[i] = zero; + ++isub; + } + + } /* for jj ... */ + + } else { /* 1-D block modification */ + + + /* Sequence through each column in the panel */ + for (jj = jcol; jj < jcol + w; jj++, + repfnz_col += m, dense_col += m) { + + kfnz = repfnz_col[krep]; + if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ + + segsze = krep - kfnz + 1; + luptr = xlusup[fsupc]; + + ops[TRSV] += segsze * (segsze - 1); + ops[GEMV] += 2 * nrow * segsze; + + /* Case 1: Update U-segment of size 1 -- col-col update */ + if ( segsze == 1 ) { + ukj = dense_col[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc; + + for (i = lptr + nsupc; i < xlsub[fsupc+1]; i++) { + irow = lsub[i]; + dense_col[irow] -= ukj * lusup[luptr]; + ++luptr; + } + + } else if ( segsze <= 3 ) { + ukj = dense_col[lsub[krep_ind]]; + luptr += nsupr*(nsupc-1) + nsupc-1; + ukj1 = dense_col[lsub[krep_ind - 1]]; + luptr1 = luptr - nsupr; + + if ( segsze == 2 ) { + ukj -= ukj1 * lusup[luptr1]; + dense_col[lsub[krep_ind]] = ukj; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + ++luptr; ++luptr1; + dense_col[irow] -= (ukj*lusup[luptr] + + ukj1*lusup[luptr1]); + } + } else { + ukj2 = dense_col[lsub[krep_ind - 2]]; + luptr2 = luptr1 - nsupr; + ukj1 -= ukj2 * lusup[luptr2-1]; + ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; + dense_col[lsub[krep_ind]] = ukj; + dense_col[lsub[krep_ind-1]] = ukj1; + for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { + irow = lsub[i]; + ++luptr; ++luptr1; ++luptr2; + dense_col[irow] -= ( ukj*lusup[luptr] + + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); + } + } + + } else { /* segsze >= 4 */ + /* + * Perform a triangular solve and block update, + * then scatter the result of sup-col update to dense[]. + */ + no_zeros = kfnz - fsupc; + + /* Copy U[*,j] segment from dense[*] to tempv[*]: + * The result of triangular solve is in tempv[*]; + * The result of matrix vector update is in dense_col[*] + */ + isub = lptr + no_zeros; + for (i = 0; i < segsze; ++i) { + irow = lsub[isub]; + tempv[i] = dense_col[irow]; /* Gather */ + ++isub; + } + + /* start effective triangle */ + luptr += nsupr * no_zeros + no_zeros; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], + &nsupr, tempv, &incx ); +#else + strsv_( "L", "N", "U", &segsze, &lusup[luptr], + &nsupr, tempv, &incx ); +#endif + + luptr += segsze; /* Dense matrix-vector */ + tempv1 = &tempv[segsze]; + alpha = one; + beta = zero; +#ifdef _CRAY + SGEMV( ftcs2, &nrow, &segsze, &alpha, &lusup[luptr], + &nsupr, tempv, &incx, &beta, tempv1, &incy ); +#else + sgemv_( "N", &nrow, &segsze, &alpha, &lusup[luptr], + &nsupr, tempv, &incx, &beta, tempv1, &incy ); +#endif +#else + slsolve ( nsupr, segsze, &lusup[luptr], tempv ); + + luptr += segsze; /* Dense matrix-vector */ + tempv1 = &tempv[segsze]; + smatvec (nsupr, nrow, segsze, &lusup[luptr], tempv, tempv1); +#endif + + /* Scatter tempv[*] into SPA dense[*] temporarily, such + * that tempv[*] can be used for the triangular solve of + * the next column of the panel. They will be copied into + * ucol[*] after the whole panel has been finished. + */ + isub = lptr + no_zeros; + for (i = 0; i < segsze; i++) { + irow = lsub[isub]; + dense_col[irow] = tempv[i]; + tempv[i] = zero; + isub++; + } + + /* Scatter the update from tempv1[*] into SPA dense[*] */ + /* Start dense rectangular L */ + for (i = 0; i < nrow; i++) { + irow = lsub[isub]; + dense_col[irow] -= tempv1[i]; + tempv1[i] = zero; + ++isub; + } + + } /* else segsze>=4 ... */ + + } /* for each column in the panel... */ + + } /* else 1-D update ... */ + + } /* for each updating supernode ... */ + +} + + + diff --git a/intern/opennl/superlu/spanel_dfs.c b/intern/opennl/superlu/spanel_dfs.c new file mode 100644 index 00000000000..7f5f3c7532a --- /dev/null +++ b/intern/opennl/superlu/spanel_dfs.c @@ -0,0 +1,249 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" +#include "util.h" + +void +spanel_dfs ( + const int m, /* in - number of rows in the matrix */ + const int w, /* in */ + const int jcol, /* in */ + SuperMatrix *A, /* in - original matrix */ + int *perm_r, /* in */ + int *nseg, /* out */ + float *dense, /* out */ + int *panel_lsub, /* out */ + int *segrep, /* out */ + int *repfnz, /* out */ + int *xprune, /* out */ + int *marker, /* out */ + int *parent, /* working array */ + int *xplore, /* working array */ + GlobalLU_t *Glu /* modified */ + ) +{ +/* + * Purpose + * ======= + * + * Performs a symbolic factorization on a panel of columns [jcol, jcol+w). + * + * A supernode representative is the last column of a supernode. + * The nonzeros in U[*,j] are segments that end at supernodal + * representatives. + * + * The routine returns one list of the supernodal representatives + * in topological order of the dfs that generates them. This list is + * a superset of the topological order of each individual column within + * the panel. + * The location of the first nonzero in each supernodal segment + * (supernodal entry location) is also returned. Each column has a + * separate list for this purpose. + * + * Two marker arrays are used for dfs: + * marker[i] == jj, if i was visited during dfs of current column jj; + * marker1[i] >= jcol, if i was visited by earlier columns in this panel; + * + * marker: A-row --> A-row/col (0/1) + * repfnz: SuperA-col --> PA-row + * parent: SuperA-col --> SuperA-col + * xplore: SuperA-col --> index to L-structure + * + */ + NCPformat *Astore; + float *a; + int *asub; + int *xa_begin, *xa_end; + int krep, chperm, chmark, chrep, oldrep, kchild, myfnz; + int k, krow, kmark, kperm; + int xdfs, maxdfs, kpar; + int jj; /* index through each column in the panel */ + int *marker1; /* marker1[jj] >= jcol if vertex jj was visited + by a previous column within this panel. */ + int *repfnz_col; /* start of each column in the panel */ + float *dense_col; /* start of each column in the panel */ + int nextl_col; /* next available position in panel_lsub[*,jj] */ + int *xsup, *supno; + int *lsub, *xlsub; + + /* Initialize pointers */ + Astore = A->Store; + a = Astore->nzval; + asub = Astore->rowind; + xa_begin = Astore->colbeg; + xa_end = Astore->colend; + marker1 = marker + m; + repfnz_col = repfnz; + dense_col = dense; + *nseg = 0; + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + + /* For each column in the panel */ + for (jj = jcol; jj < jcol + w; jj++) { + nextl_col = (jj - jcol) * m; + +#ifdef CHK_DFS + printf("\npanel col %d: ", jj); +#endif + + /* For each nonz in A[*,jj] do dfs */ + for (k = xa_begin[jj]; k < xa_end[jj]; k++) { + krow = asub[k]; + dense_col[krow] = a[k]; + kmark = marker[krow]; + if ( kmark == jj ) + continue; /* krow visited before, go to the next nonzero */ + + /* For each unmarked nbr krow of jj + * krow is in L: place it in structure of L[*,jj] + */ + marker[krow] = jj; + kperm = perm_r[krow]; + + if ( kperm == EMPTY ) { + panel_lsub[nextl_col++] = krow; /* krow is indexed into A */ + } + /* + * krow is in U: if its supernode-rep krep + * has been explored, update repfnz[*] + */ + else { + + krep = xsup[supno[kperm]+1] - 1; + myfnz = repfnz_col[krep]; + +#ifdef CHK_DFS + printf("krep %d, myfnz %d, perm_r[%d] %d\n", krep, myfnz, krow, kperm); +#endif + if ( myfnz != EMPTY ) { /* Representative visited before */ + if ( myfnz > kperm ) repfnz_col[krep] = kperm; + /* continue; */ + } + else { + /* Otherwise, perform dfs starting at krep */ + oldrep = EMPTY; + parent[krep] = oldrep; + repfnz_col[krep] = kperm; + xdfs = xlsub[krep]; + maxdfs = xprune[krep]; + +#ifdef CHK_DFS + printf(" xdfs %d, maxdfs %d: ", xdfs, maxdfs); + for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); + printf("\n"); +#endif + do { + /* + * For each unmarked kchild of krep + */ + while ( xdfs < maxdfs ) { + + kchild = lsub[xdfs]; + xdfs++; + chmark = marker[kchild]; + + if ( chmark != jj ) { /* Not reached yet */ + marker[kchild] = jj; + chperm = perm_r[kchild]; + + /* Case kchild is in L: place it in L[*,j] */ + if ( chperm == EMPTY ) { + panel_lsub[nextl_col++] = kchild; + } + /* Case kchild is in U: + * chrep = its supernode-rep. If its rep has + * been explored, update its repfnz[*] + */ + else { + + chrep = xsup[supno[chperm]+1] - 1; + myfnz = repfnz_col[chrep]; +#ifdef CHK_DFS + printf("chrep %d,myfnz %d,perm_r[%d] %d\n",chrep,myfnz,kchild,chperm); +#endif + if ( myfnz != EMPTY ) { /* Visited before */ + if ( myfnz > chperm ) + repfnz_col[chrep] = chperm; + } + else { + /* Cont. dfs at snode-rep of kchild */ + xplore[krep] = xdfs; + oldrep = krep; + krep = chrep; /* Go deeper down G(L) */ + parent[krep] = oldrep; + repfnz_col[krep] = chperm; + xdfs = xlsub[krep]; + maxdfs = xprune[krep]; +#ifdef CHK_DFS + printf(" xdfs %d, maxdfs %d: ", xdfs, maxdfs); + for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); + printf("\n"); +#endif + } /* else */ + + } /* else */ + + } /* if... */ + + } /* while xdfs < maxdfs */ + + /* krow has no more unexplored nbrs: + * Place snode-rep krep in postorder DFS, if this + * segment is seen for the first time. (Note that + * "repfnz[krep]" may change later.) + * Backtrack dfs to its parent. + */ + if ( marker1[krep] < jcol ) { + segrep[*nseg] = krep; + ++(*nseg); + marker1[krep] = jj; + } + + kpar = parent[krep]; /* Pop stack, mimic recursion */ + if ( kpar == EMPTY ) break; /* dfs done */ + krep = kpar; + xdfs = xplore[krep]; + maxdfs = xprune[krep]; + +#ifdef CHK_DFS + printf(" pop stack: krep %d,xdfs %d,maxdfs %d: ", krep,xdfs,maxdfs); + for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); + printf("\n"); +#endif + } while ( kpar != EMPTY ); /* do-while - until empty stack */ + + } /* else */ + + } /* else */ + + } /* for each nonz in A[*,jj] */ + + repfnz_col += m; /* Move to next column */ + dense_col += m; + + } /* for jj ... */ + +} diff --git a/intern/opennl/superlu/spivotL.c b/intern/opennl/superlu/spivotL.c new file mode 100644 index 00000000000..6243065bb5b --- /dev/null +++ b/intern/opennl/superlu/spivotL.c @@ -0,0 +1,173 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include +#include "ssp_defs.h" + +#undef DEBUG + +int +spivotL( + const int jcol, /* in */ + const float u, /* in - diagonal pivoting threshold */ + int *usepr, /* re-use the pivot sequence given by perm_r/iperm_r */ + int *perm_r, /* may be modified */ + int *iperm_r, /* in - inverse of perm_r */ + int *iperm_c, /* in - used to find diagonal of Pc*A*Pc' */ + int *pivrow, /* out */ + GlobalLU_t *Glu, /* modified - global LU data structures */ + SuperLUStat_t *stat /* output */ + ) +{ +/* + * Purpose + * ======= + * Performs the numerical pivoting on the current column of L, + * and the CDIV operation. + * + * Pivot policy: + * (1) Compute thresh = u * max_(i>=j) abs(A_ij); + * (2) IF user specifies pivot row k and abs(A_kj) >= thresh THEN + * pivot row = k; + * ELSE IF abs(A_jj) >= thresh THEN + * pivot row = j; + * ELSE + * pivot row = m; + * + * Note: If you absolutely want to use a given pivot order, then set u=0.0. + * + * Return value: 0 success; + * i > 0 U(i,i) is exactly zero. + * + */ + int fsupc; /* first column in the supernode */ + int nsupc; /* no of columns in the supernode */ + int nsupr; /* no of rows in the supernode */ + int lptr; /* points to the starting subscript of the supernode */ + int pivptr, old_pivptr, diag, diagind; + float pivmax, rtemp, thresh; + float temp; + float *lu_sup_ptr; + float *lu_col_ptr; + int *lsub_ptr; + int isub, icol, k, itemp; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + flops_t *ops = stat->ops; + + /* Initialize pointers */ + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + fsupc = (Glu->xsup)[(Glu->supno)[jcol]]; + nsupc = jcol - fsupc; /* excluding jcol; nsupc >= 0 */ + lptr = xlsub[fsupc]; + nsupr = xlsub[fsupc+1] - lptr; + lu_sup_ptr = &lusup[xlusup[fsupc]]; /* start of the current supernode */ + lu_col_ptr = &lusup[xlusup[jcol]]; /* start of jcol in the supernode */ + lsub_ptr = &lsub[lptr]; /* start of row indices of the supernode */ + +#ifdef DEBUG +if ( jcol == MIN_COL ) { + printf("Before cdiv: col %d\n", jcol); + for (k = nsupc; k < nsupr; k++) + printf(" lu[%d] %f\n", lsub_ptr[k], lu_col_ptr[k]); +} +#endif + + /* Determine the largest abs numerical value for partial pivoting; + Also search for user-specified pivot, and diagonal element. */ + if ( *usepr ) *pivrow = iperm_r[jcol]; + diagind = iperm_c[jcol]; + pivmax = 0.0; + pivptr = nsupc; + diag = EMPTY; + old_pivptr = nsupc; + for (isub = nsupc; isub < nsupr; ++isub) { + rtemp = fabs (lu_col_ptr[isub]); + if ( rtemp > pivmax ) { + pivmax = rtemp; + pivptr = isub; + } + if ( *usepr && lsub_ptr[isub] == *pivrow ) old_pivptr = isub; + if ( lsub_ptr[isub] == diagind ) diag = isub; + } + + /* Test for singularity */ + if ( pivmax == 0.0 ) { + *pivrow = lsub_ptr[pivptr]; + perm_r[*pivrow] = jcol; + *usepr = 0; + return (jcol+1); + } + + thresh = u * pivmax; + + /* Choose appropriate pivotal element by our policy. */ + if ( *usepr ) { + rtemp = fabs (lu_col_ptr[old_pivptr]); + if ( rtemp != 0.0 && rtemp >= thresh ) + pivptr = old_pivptr; + else + *usepr = 0; + } + if ( *usepr == 0 ) { + /* Use diagonal pivot? */ + if ( diag >= 0 ) { /* diagonal exists */ + rtemp = fabs (lu_col_ptr[diag]); + if ( rtemp != 0.0 && rtemp >= thresh ) pivptr = diag; + } + *pivrow = lsub_ptr[pivptr]; + } + + /* Record pivot row */ + perm_r[*pivrow] = jcol; + + /* Interchange row subscripts */ + if ( pivptr != nsupc ) { + itemp = lsub_ptr[pivptr]; + lsub_ptr[pivptr] = lsub_ptr[nsupc]; + lsub_ptr[nsupc] = itemp; + + /* Interchange numerical values as well, for the whole snode, such + * that L is indexed the same way as A. + */ + for (icol = 0; icol <= nsupc; icol++) { + itemp = pivptr + icol * nsupr; + temp = lu_sup_ptr[itemp]; + lu_sup_ptr[itemp] = lu_sup_ptr[nsupc + icol*nsupr]; + lu_sup_ptr[nsupc + icol*nsupr] = temp; + } + } /* if */ + + /* cdiv operation */ + ops[FACT] += nsupr - nsupc; + + temp = 1.0 / lu_col_ptr[nsupc]; + for (k = nsupc+1; k < nsupr; k++) + lu_col_ptr[k] *= temp; + + return 0; +} + diff --git a/intern/opennl/superlu/spruneL.c b/intern/opennl/superlu/spruneL.c new file mode 100644 index 00000000000..59702706375 --- /dev/null +++ b/intern/opennl/superlu/spruneL.c @@ -0,0 +1,149 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" +#include "util.h" + +void +spruneL( + const int jcol, /* in */ + const int *perm_r, /* in */ + const int pivrow, /* in */ + const int nseg, /* in */ + const int *segrep, /* in */ + const int *repfnz, /* in */ + int *xprune, /* out */ + GlobalLU_t *Glu /* modified - global LU data structures */ + ) +{ +/* + * Purpose + * ======= + * Prunes the L-structure of supernodes whose L-structure + * contains the current pivot row "pivrow" + * + */ + float utemp; + int jsupno, irep, irep1, kmin, kmax, krow, movnum; + int i, ktemp, minloc, maxloc; + int do_prune; /* logical variable */ + int *xsup, *supno; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + + /* + * For each supernode-rep irep in U[*,j] + */ + jsupno = supno[jcol]; + for (i = 0; i < nseg; i++) { + + irep = segrep[i]; + irep1 = irep + 1; + do_prune = FALSE; + + /* Don't prune with a zero U-segment */ + if ( repfnz[irep] == EMPTY ) + continue; + + /* If a snode overlaps with the next panel, then the U-segment + * is fragmented into two parts -- irep and irep1. We should let + * pruning occur at the rep-column in irep1's snode. + */ + if ( supno[irep] == supno[irep1] ) /* Don't prune */ + continue; + + /* + * If it has not been pruned & it has a nonz in row L[pivrow,i] + */ + if ( supno[irep] != jsupno ) { + if ( xprune[irep] >= xlsub[irep1] ) { + kmin = xlsub[irep]; + kmax = xlsub[irep1] - 1; + for (krow = kmin; krow <= kmax; krow++) + if ( lsub[krow] == pivrow ) { + do_prune = TRUE; + break; + } + } + + if ( do_prune ) { + + /* Do a quicksort-type partition + * movnum=TRUE means that the num values have to be exchanged. + */ + movnum = FALSE; + if ( irep == xsup[supno[irep]] ) /* Snode of size 1 */ + movnum = TRUE; + + while ( kmin <= kmax ) { + + if ( perm_r[lsub[kmax]] == EMPTY ) + kmax--; + else if ( perm_r[lsub[kmin]] != EMPTY ) + kmin++; + else { /* kmin below pivrow, and kmax above pivrow: + * interchange the two subscripts + */ + ktemp = lsub[kmin]; + lsub[kmin] = lsub[kmax]; + lsub[kmax] = ktemp; + + /* If the supernode has only one column, then we + * only keep one set of subscripts. For any subscript + * interchange performed, similar interchange must be + * done on the numerical values. + */ + if ( movnum ) { + minloc = xlusup[irep] + (kmin - xlsub[irep]); + maxloc = xlusup[irep] + (kmax - xlsub[irep]); + utemp = lusup[minloc]; + lusup[minloc] = lusup[maxloc]; + lusup[maxloc] = utemp; + } + + kmin++; + kmax--; + + } + + } /* while */ + + xprune[irep] = kmin; /* Pruning */ + +#ifdef CHK_PRUNE + printf(" After spruneL(),using col %d: xprune[%d] = %d\n", + jcol, irep, kmin); +#endif + } /* if do_prune */ + + } /* if */ + + } /* for each U-segment... */ +} diff --git a/intern/opennl/superlu/ssnode_bmod.c b/intern/opennl/superlu/ssnode_bmod.c new file mode 100644 index 00000000000..fe97abd9ff6 --- /dev/null +++ b/intern/opennl/superlu/ssnode_bmod.c @@ -0,0 +1,117 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" + +void slsolve(int, int, float*, float*); +void smatvec(int, int, int, float*, float*, float*); + +/* + * Performs numeric block updates within the relaxed snode. + */ +int +ssnode_bmod ( + const int jcol, /* in */ + const int fsupc, /* in */ + float *dense, /* in */ + float *tempv, /* working array */ + GlobalLU_t *Glu, /* modified */ + SuperLUStat_t *stat /* output */ + ) +{ +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + _fcd ftcs1 = _cptofcd("L", strlen("L")), + ftcs2 = _cptofcd("N", strlen("N")), + ftcs3 = _cptofcd("U", strlen("U")); +#endif + int incx = 1, incy = 1; + float alpha = -1.0, beta = 1.0; +#endif + + int luptr, nsupc, nsupr, nrow; + int isub, irow, i, iptr; + register int ufirst, nextlu; + int *lsub, *xlsub; + float *lusup; + int *xlusup; + flops_t *ops = stat->ops; + + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + + nextlu = xlusup[jcol]; + + /* + * Process the supernodal portion of L\U[*,j] + */ + for (isub = xlsub[fsupc]; isub < xlsub[fsupc+1]; isub++) { + irow = lsub[isub]; + lusup[nextlu] = dense[irow]; + dense[irow] = 0; + ++nextlu; + } + + xlusup[jcol + 1] = nextlu; /* Initialize xlusup for next column */ + + if ( fsupc < jcol ) { + + luptr = xlusup[fsupc]; + nsupr = xlsub[fsupc+1] - xlsub[fsupc]; + nsupc = jcol - fsupc; /* Excluding jcol */ + ufirst = xlusup[jcol]; /* Points to the beginning of column + jcol in supernode L\U(jsupno). */ + nrow = nsupr - nsupc; + + ops[TRSV] += nsupc * (nsupc - 1); + ops[GEMV] += 2 * nrow * nsupc; + +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &lusup[luptr], &nsupr, + &lusup[ufirst], &incx ); + SGEMV( ftcs2, &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, + &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); +#else + strsv_( "L", "N", "U", &nsupc, &lusup[luptr], &nsupr, + &lusup[ufirst], &incx ); + sgemv_( "N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, + &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); +#endif +#else + slsolve ( nsupr, nsupc, &lusup[luptr], &lusup[ufirst] ); + smatvec ( nsupr, nrow, nsupc, &lusup[luptr+nsupc], + &lusup[ufirst], &tempv[0] ); + + /* Scatter tempv[*] into lusup[*] */ + iptr = ufirst + nsupc; + for (i = 0; i < nrow; i++) { + lusup[iptr++] -= tempv[i]; + tempv[i] = 0.0; + } +#endif + + } + + return 0; +} diff --git a/intern/opennl/superlu/ssnode_dfs.c b/intern/opennl/superlu/ssnode_dfs.c new file mode 100644 index 00000000000..c8974237a9a --- /dev/null +++ b/intern/opennl/superlu/ssnode_dfs.c @@ -0,0 +1,106 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include "ssp_defs.h" +#include "util.h" + +int +ssnode_dfs ( + const int jcol, /* in - start of the supernode */ + const int kcol, /* in - end of the supernode */ + const int *asub, /* in */ + const int *xa_begin, /* in */ + const int *xa_end, /* in */ + int *xprune, /* out */ + int *marker, /* modified */ + GlobalLU_t *Glu /* modified */ + ) +{ +/* Purpose + * ======= + * ssnode_dfs() - Determine the union of the row structures of those + * columns within the relaxed snode. + * Note: The relaxed snodes are leaves of the supernodal etree, therefore, + * the portion outside the rectangular supernode must be zero. + * + * Return value + * ============ + * 0 success; + * >0 number of bytes allocated when run out of memory. + * + */ + register int i, k, ifrom, ito, nextl, new_next; + int nsuper, krow, kmark, mem_error; + int *xsup, *supno; + int *lsub, *xlsub; + int nzlmax; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + nzlmax = Glu->nzlmax; + + nsuper = ++supno[jcol]; /* Next available supernode number */ + nextl = xlsub[jcol]; + + for (i = jcol; i <= kcol; i++) { + /* For each nonzero in A[*,i] */ + for (k = xa_begin[i]; k < xa_end[i]; k++) { + krow = asub[k]; + kmark = marker[krow]; + if ( kmark != kcol ) { /* First time visit krow */ + marker[krow] = kcol; + lsub[nextl++] = krow; + if ( nextl >= nzlmax ) { + if ( (mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu)) ) + return (mem_error); + lsub = Glu->lsub; + } + } + } + supno[i] = nsuper; + } + + /* Supernode > 1, then make a copy of the subscripts for pruning */ + if ( jcol < kcol ) { + new_next = nextl + (nextl - xlsub[jcol]); + while ( new_next > nzlmax ) { + if ( (mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu)) ) + return (mem_error); + lsub = Glu->lsub; + } + ito = nextl; + for (ifrom = xlsub[jcol]; ifrom < nextl; ) + lsub[ito++] = lsub[ifrom++]; + for (i = jcol+1; i <= kcol; i++) xlsub[i] = nextl; + nextl = ito; + } + + xsup[nsuper+1] = kcol + 1; + supno[kcol+1] = nsuper; + xprune[kcol] = nextl; + xlsub[kcol+1] = nextl; + + return 0; +} + diff --git a/intern/opennl/superlu/ssp_blas2.c b/intern/opennl/superlu/ssp_blas2.c new file mode 100644 index 00000000000..e9f8f53128a --- /dev/null +++ b/intern/opennl/superlu/ssp_blas2.c @@ -0,0 +1,472 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + * File name: ssp_blas2.c + * Purpose: Sparse BLAS 2, using some dense BLAS 2 operations. + */ + +#include "ssp_defs.h" + +/* + * Function prototypes + */ +void susolve(int, int, float*, float*); +void slsolve(int, int, float*, float*); +void smatvec(int, int, int, float*, float*, float*); +int strsv_(char*, char*, char*, int*, float*, int*, float*, int*); + +int +sp_strsv(char *uplo, char *trans, char *diag, SuperMatrix *L, + SuperMatrix *U, float *x, SuperLUStat_t *stat, int *info) +{ +/* + * Purpose + * ======= + * + * sp_strsv() solves one of the systems of equations + * A*x = b, or A'*x = b, + * where b and x are n element vectors and A is a sparse unit , or + * non-unit, upper or lower triangular matrix. + * No test for singularity or near-singularity is included in this + * routine. Such tests must be performed before calling this routine. + * + * Parameters + * ========== + * + * uplo - (input) char* + * On entry, uplo specifies whether the matrix is an upper or + * lower triangular matrix as follows: + * uplo = 'U' or 'u' A is an upper triangular matrix. + * uplo = 'L' or 'l' A is a lower triangular matrix. + * + * trans - (input) char* + * On entry, trans specifies the equations to be solved as + * follows: + * trans = 'N' or 'n' A*x = b. + * trans = 'T' or 't' A'*x = b. + * trans = 'C' or 'c' A'*x = b. + * + * diag - (input) char* + * On entry, diag specifies whether or not A is unit + * triangular as follows: + * diag = 'U' or 'u' A is assumed to be unit triangular. + * diag = 'N' or 'n' A is not assumed to be unit + * triangular. + * + * L - (input) SuperMatrix* + * The factor L from the factorization Pr*A*Pc=L*U. Use + * compressed row subscripts storage for supernodes, + * i.e., L has types: Stype = SC, Dtype = SLU_S, Mtype = TRLU. + * + * U - (input) SuperMatrix* + * The factor U from the factorization Pr*A*Pc=L*U. + * U has types: Stype = NC, Dtype = SLU_S, Mtype = TRU. + * + * x - (input/output) float* + * Before entry, the incremented array X must contain the n + * element right-hand side vector b. On exit, X is overwritten + * with the solution vector x. + * + * info - (output) int* + * If *info = -i, the i-th argument had an illegal value. + * + */ +#ifdef _CRAY + _fcd ftcs1 = _cptofcd("L", strlen("L")), + ftcs2 = _cptofcd("N", strlen("N")), + ftcs3 = _cptofcd("U", strlen("U")); +#endif + SCformat *Lstore; + NCformat *Ustore; + float *Lval, *Uval; + int incx = 1; + int nrow; + int fsupc, nsupr, nsupc, luptr, istart, irow; + int i, k, iptr, jcol; + float *work; + flops_t solve_ops; + + /* Test the input parameters */ + *info = 0; + if ( !lsame_(uplo,"L") && !lsame_(uplo, "U") ) *info = -1; + else if ( !lsame_(trans, "N") && !lsame_(trans, "T") && + !lsame_(trans, "C")) *info = -2; + else if ( !lsame_(diag, "U") && !lsame_(diag, "N") ) *info = -3; + else if ( L->nrow != L->ncol || L->nrow < 0 ) *info = -4; + else if ( U->nrow != U->ncol || U->nrow < 0 ) *info = -5; + if ( *info ) { + i = -(*info); + xerbla_("sp_strsv", &i); + return 0; + } + + Lstore = L->Store; + Lval = Lstore->nzval; + Ustore = U->Store; + Uval = Ustore->nzval; + solve_ops = 0; + + if ( !(work = floatCalloc(L->nrow)) ) + ABORT("Malloc fails for work in sp_strsv()."); + + if ( lsame_(trans, "N") ) { /* Form x := inv(A)*x. */ + + if ( lsame_(uplo, "L") ) { + /* Form x := inv(L)*x */ + if ( L->nrow == 0 ) { + SUPERLU_FREE(work); + return 0; /* Quick return */ + } + + for (k = 0; k <= Lstore->nsuper; k++) { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + nrow = nsupr - nsupc; + + solve_ops += nsupc * (nsupc - 1); + solve_ops += 2 * nrow * nsupc; + + if ( nsupc == 1 ) { + for (iptr=istart+1; iptr < L_SUB_START(fsupc+1); ++iptr) { + irow = L_SUB(iptr); + ++luptr; + x[irow] -= x[fsupc] * Lval[luptr]; + } + } else { +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV(ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); + + SGEMV(ftcs2, &nrow, &nsupc, &alpha, &Lval[luptr+nsupc], + &nsupr, &x[fsupc], &incx, &beta, &work[0], &incy); +#else + strsv_("L", "N", "U", &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); + + sgemv_("N", &nrow, &nsupc, &alpha, &Lval[luptr+nsupc], + &nsupr, &x[fsupc], &incx, &beta, &work[0], &incy); +#endif +#else + slsolve ( nsupr, nsupc, &Lval[luptr], &x[fsupc]); + + smatvec ( nsupr, nsupr-nsupc, nsupc, &Lval[luptr+nsupc], + &x[fsupc], &work[0] ); +#endif + + iptr = istart + nsupc; + for (i = 0; i < nrow; ++i, ++iptr) { + irow = L_SUB(iptr); + x[irow] -= work[i]; /* Scatter */ + work[i] = 0.0; + + } + } + } /* for k ... */ + + } else { + /* Form x := inv(U)*x */ + + if ( U->nrow == 0 ) return 0; /* Quick return */ + + for (k = Lstore->nsuper; k >= 0; k--) { + fsupc = L_FST_SUPC(k); + nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc); + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + + solve_ops += nsupc * (nsupc + 1); + + if ( nsupc == 1 ) { + x[fsupc] /= Lval[luptr]; + for (i = U_NZ_START(fsupc); i < U_NZ_START(fsupc+1); ++i) { + irow = U_SUB(i); + x[irow] -= x[fsupc] * Uval[i]; + } + } else { +#ifdef USE_VENDOR_BLAS +#ifdef _CRAY + STRSV(ftcs3, ftcs2, ftcs2, &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#else + strsv_("U", "N", "N", &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#endif +#else + susolve ( nsupr, nsupc, &Lval[luptr], &x[fsupc] ); +#endif + + for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { + solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); + for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); + i++) { + irow = U_SUB(i); + x[irow] -= x[jcol] * Uval[i]; + } + } + } + } /* for k ... */ + + } + } else { /* Form x := inv(A')*x */ + + if ( lsame_(uplo, "L") ) { + /* Form x := inv(L')*x */ + if ( L->nrow == 0 ) return 0; /* Quick return */ + + for (k = Lstore->nsuper; k >= 0; --k) { + fsupc = L_FST_SUPC(k); + istart = L_SUB_START(fsupc); + nsupr = L_SUB_START(fsupc+1) - istart; + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + + solve_ops += 2 * (nsupr - nsupc) * nsupc; + + for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { + iptr = istart + nsupc; + for (i = L_NZ_START(jcol) + nsupc; + i < L_NZ_START(jcol+1); i++) { + irow = L_SUB(iptr); + x[jcol] -= x[irow] * Lval[i]; + iptr++; + } + } + + if ( nsupc > 1 ) { + solve_ops += nsupc * (nsupc - 1); +#ifdef _CRAY + ftcs1 = _cptofcd("L", strlen("L")); + ftcs2 = _cptofcd("T", strlen("T")); + ftcs3 = _cptofcd("U", strlen("U")); + STRSV(ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#else + strsv_("L", "T", "U", &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#endif + } + } + } else { + /* Form x := inv(U')*x */ + if ( U->nrow == 0 ) return 0; /* Quick return */ + + for (k = 0; k <= Lstore->nsuper; k++) { + fsupc = L_FST_SUPC(k); + nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc); + nsupc = L_FST_SUPC(k+1) - fsupc; + luptr = L_NZ_START(fsupc); + + for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { + solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); + for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++) { + irow = U_SUB(i); + x[jcol] -= x[irow] * Uval[i]; + } + } + + solve_ops += nsupc * (nsupc + 1); + + if ( nsupc == 1 ) { + x[fsupc] /= Lval[luptr]; + } else { +#ifdef _CRAY + ftcs1 = _cptofcd("U", strlen("U")); + ftcs2 = _cptofcd("T", strlen("T")); + ftcs3 = _cptofcd("N", strlen("N")); + STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#else + strsv_("U", "T", "N", &nsupc, &Lval[luptr], &nsupr, + &x[fsupc], &incx); +#endif + } + } /* for k ... */ + } + } + + stat->ops[SOLVE] += solve_ops; + SUPERLU_FREE(work); + return 0; +} + + + + +int +sp_sgemv(char *trans, float alpha, SuperMatrix *A, float *x, + int incx, float beta, float *y, int incy) +{ +/* Purpose + ======= + + sp_sgemv() performs one of the matrix-vector operations + y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, + where alpha and beta are scalars, x and y are vectors and A is a + sparse A->nrow by A->ncol matrix. + + Parameters + ========== + + TRANS - (input) char* + On entry, TRANS specifies the operation to be performed as + follows: + TRANS = 'N' or 'n' y := alpha*A*x + beta*y. + TRANS = 'T' or 't' y := alpha*A'*x + beta*y. + TRANS = 'C' or 'c' y := alpha*A'*x + beta*y. + + ALPHA - (input) float + On entry, ALPHA specifies the scalar alpha. + + A - (input) SuperMatrix* + Matrix A with a sparse format, of dimension (A->nrow, A->ncol). + Currently, the type of A can be: + Stype = NC or NCP; Dtype = SLU_S; Mtype = GE. + In the future, more general A can be handled. + + X - (input) float*, array of DIMENSION at least + ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. + Before entry, the incremented array X must contain the + vector x. + + INCX - (input) int + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + + BETA - (input) float + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + + Y - (output) float*, array of DIMENSION at least + ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. + Before entry with BETA non-zero, the incremented array Y + must contain the vector y. On exit, Y is overwritten by the + updated vector y. + + INCY - (input) int + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + + ==== Sparse Level 2 Blas routine. +*/ + + /* Local variables */ + NCformat *Astore; + float *Aval; + int info; + float temp; + int lenx, leny, i, j, irow; + int iy, jx, jy, kx, ky; + int notran; + + notran = lsame_(trans, "N"); + Astore = A->Store; + Aval = Astore->nzval; + + /* Test the input parameters */ + info = 0; + if ( !notran && !lsame_(trans, "T") && !lsame_(trans, "C")) info = 1; + else if ( A->nrow < 0 || A->ncol < 0 ) info = 3; + else if (incx == 0) info = 5; + else if (incy == 0) info = 8; + if (info != 0) { + xerbla_("sp_sgemv ", &info); + return 0; + } + + /* Quick return if possible. */ + if (A->nrow == 0 || A->ncol == 0 || (alpha == 0. && beta == 1.)) + return 0; + + /* Set LENX and LENY, the lengths of the vectors x and y, and set + up the start points in X and Y. */ + if (lsame_(trans, "N")) { + lenx = A->ncol; + leny = A->nrow; + } else { + lenx = A->nrow; + leny = A->ncol; + } + if (incx > 0) kx = 0; + else kx = - (lenx - 1) * incx; + if (incy > 0) ky = 0; + else ky = - (leny - 1) * incy; + + /* Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. */ + /* First form y := beta*y. */ + if (beta != 1.) { + if (incy == 1) { + if (beta == 0.) + for (i = 0; i < leny; ++i) y[i] = 0.; + else + for (i = 0; i < leny; ++i) y[i] = beta * y[i]; + } else { + iy = ky; + if (beta == 0.) + for (i = 0; i < leny; ++i) { + y[iy] = 0.; + iy += incy; + } + else + for (i = 0; i < leny; ++i) { + y[iy] = beta * y[iy]; + iy += incy; + } + } + } + + if (alpha == 0.) return 0; + + if ( notran ) { + /* Form y := alpha*A*x + y. */ + jx = kx; + if (incy == 1) { + for (j = 0; j < A->ncol; ++j) { + if (x[jx] != 0.) { + temp = alpha * x[jx]; + for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { + irow = Astore->rowind[i]; + y[irow] += temp * Aval[i]; + } + } + jx += incx; + } + } else { + ABORT("Not implemented."); + } + } else { + /* Form y := alpha*A'*x + y. */ + jy = ky; + if (incx == 1) { + for (j = 0; j < A->ncol; ++j) { + temp = 0.; + for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { + irow = Astore->rowind[i]; + temp += Aval[i] * x[irow]; + } + y[jy] += alpha * temp; + jy += incy; + } + } else { + ABORT("Not implemented."); + } + } + return 0; +} /* sp_sgemv */ + + + diff --git a/intern/opennl/superlu/ssp_blas3.c b/intern/opennl/superlu/ssp_blas3.c new file mode 100644 index 00000000000..19086077c4c --- /dev/null +++ b/intern/opennl/superlu/ssp_blas3.c @@ -0,0 +1,121 @@ + + +/* + * -- SuperLU routine (version 2.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * November 15, 1997 + * + */ +/* + * File name: sp_blas3.c + * Purpose: Sparse BLAS3, using some dense BLAS3 operations. + */ + +#include "ssp_defs.h" +#include "util.h" + +int +sp_sgemm(char *transa, int n, + float alpha, SuperMatrix *A, float *b, int ldb, + float beta, float *c, int ldc) +{ +/* Purpose + ======= + + sp_s performs one of the matrix-matrix operations + + C := alpha*op( A )*op( B ) + beta*C, + + where op( X ) is one of + + op( X ) = X or op( X ) = X' or op( X ) = conjg( X' ), + + alpha and beta are scalars, and A, B and C are matrices, with op( A ) + an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. + + + Parameters + ========== + + TRANSA - (input) char* + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + TRANSA = 'N' or 'n', op( A ) = A. + TRANSA = 'T' or 't', op( A ) = A'. + TRANSA = 'C' or 'c', op( A ) = conjg( A' ). + Unchanged on exit. + + TRANSB - (input) char* + On entry, TRANSB specifies the form of op( B ) to be used in + the matrix multiplication as follows: + TRANSB = 'N' or 'n', op( B ) = B. + TRANSB = 'T' or 't', op( B ) = B'. + TRANSB = 'C' or 'c', op( B ) = conjg( B' ). + Unchanged on exit. + + M - (input) int + On entry, M specifies the number of rows of the matrix + op( A ) and of the matrix C. M must be at least zero. + Unchanged on exit. + + N - (input) int + On entry, N specifies the number of columns of the matrix + op( B ) and the number of columns of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - (input) int + On entry, K specifies the number of columns of the matrix + op( A ) and the number of rows of the matrix op( B ). K must + be at least zero. + Unchanged on exit. + + ALPHA - (input) float + On entry, ALPHA specifies the scalar alpha. + + A - (input) SuperMatrix* + Matrix A with a sparse format, of dimension (A->nrow, A->ncol). + Currently, the type of A can be: + Stype = NC or NCP; Dtype = SLU_S; Mtype = GE. + In the future, more general A can be handled. + + B - FLOAT PRECISION array of DIMENSION ( LDB, kb ), where kb is + n when TRANSB = 'N' or 'n', and is k otherwise. + Before entry with TRANSB = 'N' or 'n', the leading k by n + part of the array B must contain the matrix B, otherwise + the leading n by k part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - (input) int + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least max( 1, n ). + Unchanged on exit. + + BETA - (input) float + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + + C - FLOAT PRECISION array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n matrix + ( alpha*op( A )*B + beta*C ). + + LDC - (input) int + On entry, LDC specifies the first dimension of C as declared + in the calling (sub)program. LDC must be at least max(1,m). + Unchanged on exit. + + ==== Sparse Level 3 Blas routine. +*/ + int incx = 1, incy = 1; + int j; + + for (j = 0; j < n; ++j) { + sp_sgemv(transa, alpha, A, &b[ldb*j], incx, beta, &c[ldc*j], incy); + } + return 0; +} diff --git a/intern/opennl/superlu/ssp_defs.h b/intern/opennl/superlu/ssp_defs.h new file mode 100644 index 00000000000..61b324e74d8 --- /dev/null +++ b/intern/opennl/superlu/ssp_defs.h @@ -0,0 +1,237 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +#ifndef __SUPERLU_sSP_DEFS /* allow multiple inclusions */ +#define __SUPERLU_sSP_DEFS + +/* + * File name: ssp_defs.h + * Purpose: Sparse matrix types and function prototypes + * History: + */ + +#ifdef _CRAY +#include +#include +#endif + +/* Define my integer type int_t */ +typedef int int_t; /* default */ + +#include "Cnames.h" +#include "supermatrix.h" +#include "util.h" + + +/* + * Global data structures used in LU factorization - + * + * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. + * (xsup,supno): supno[i] is the supernode no to which i belongs; + * xsup(s) points to the beginning of the s-th supernode. + * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) + * xsup 0 1 2 4 7 12 + * Note: dfs will be performed on supernode rep. relative to the new + * row pivoting ordering + * + * (xlsub,lsub): lsub[*] contains the compressed subscript of + * rectangular supernodes; xlsub[j] points to the starting + * location of the j-th column in lsub[*]. Note that xlsub + * is indexed by column. + * Storage: original row subscripts + * + * During the course of sparse LU factorization, we also use + * (xlsub,lsub) for the purpose of symmetric pruning. For each + * supernode {s,s+1,...,t=s+r} with first column s and last + * column t, the subscript set + * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 + * is the structure of column s (i.e. structure of this supernode). + * It is used for the storage of numerical values. + * Furthermore, + * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 + * is the structure of the last column t of this supernode. + * It is for the purpose of symmetric pruning. Therefore, the + * structural subscripts can be rearranged without making physical + * interchanges among the numerical values. + * + * However, if the supernode has only one column, then we + * only keep one set of subscripts. For any subscript interchange + * performed, similar interchange must be done on the numerical + * values. + * + * The last column structures (for pruning) will be removed + * after the numercial LU factorization phase. + * + * (xlusup,lusup): lusup[*] contains the numerical values of the + * rectangular supernodes; xlusup[j] points to the starting + * location of the j-th column in storage vector lusup[*] + * Note: xlusup is indexed by column. + * Each rectangular supernode is stored by column-major + * scheme, consistent with Fortran 2-dim array storage. + * + * (xusub,ucol,usub): ucol[*] stores the numerical values of + * U-columns outside the rectangular supernodes. The row + * subscript of nonzero ucol[k] is stored in usub[k]. + * xusub[i] points to the starting location of column i in ucol. + * Storage: new row subscripts; that is subscripts of PA. + */ +typedef struct { + int *xsup; /* supernode and column mapping */ + int *supno; + int *lsub; /* compressed L subscripts */ + int *xlsub; + float *lusup; /* L supernodes */ + int *xlusup; + float *ucol; /* U columns */ + int *usub; + int *xusub; + int nzlmax; /* current max size of lsub */ + int nzumax; /* " " " ucol */ + int nzlumax; /* " " " lusup */ + int n; /* number of columns in the matrix */ + LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ +} GlobalLU_t; + +typedef struct { + float for_lu; + float total_needed; + int expansions; +} mem_usage_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Driver routines */ +extern void +sgssv(superlu_options_t *, SuperMatrix *, int *, int *, SuperMatrix *, + SuperMatrix *, SuperMatrix *, SuperLUStat_t *, int *); +extern void +sgssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *, + char *, float *, float *, SuperMatrix *, SuperMatrix *, + void *, int, SuperMatrix *, SuperMatrix *, + float *, float *, float *, float *, + mem_usage_t *, SuperLUStat_t *, int *); + +/* Supernodal LU factor related */ +extern void +sCreate_CompCol_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +sCreate_CompRow_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, Stype_t, Dtype_t, Mtype_t); +extern void +sCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); +extern void +sCreate_Dense_Matrix(SuperMatrix *, int, int, float *, int, + Stype_t, Dtype_t, Mtype_t); +extern void +sCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, float *, + int *, int *, int *, int *, int *, + Stype_t, Dtype_t, Mtype_t); +extern void +sCopy_Dense_Matrix(int, int, float *, int, float *, int); + +extern void countnz (const int, int *, int *, int *, GlobalLU_t *); +extern void fixupL (const int, const int *, GlobalLU_t *); + +extern void sallocateA (int, int, float **, int **, int **); +extern void sgstrf (superlu_options_t*, SuperMatrix*, + int, int, int*, void *, int, int *, int *, + SuperMatrix *, SuperMatrix *, SuperLUStat_t*, int *); +extern int ssnode_dfs (const int, const int, const int *, const int *, + const int *, int *, int *, GlobalLU_t *); +extern int ssnode_bmod (const int, const int, float *, + float *, GlobalLU_t *, SuperLUStat_t*); +extern void spanel_dfs (const int, const int, const int, SuperMatrix *, + int *, int *, float *, int *, int *, int *, + int *, int *, int *, int *, GlobalLU_t *); +extern void spanel_bmod (const int, const int, const int, const int, + float *, float *, int *, int *, + GlobalLU_t *, SuperLUStat_t*); +extern int scolumn_dfs (const int, const int, int *, int *, int *, int *, + int *, int *, int *, int *, int *, GlobalLU_t *); +extern int scolumn_bmod (const int, const int, float *, + float *, int *, int *, int, + GlobalLU_t *, SuperLUStat_t*); +extern int scopy_to_ucol (int, int, int *, int *, int *, + float *, GlobalLU_t *); +extern int spivotL (const int, const float, int *, int *, + int *, int *, int *, GlobalLU_t *, SuperLUStat_t*); +extern void spruneL (const int, const int *, const int, const int, + const int *, const int *, int *, GlobalLU_t *); +extern void sreadmt (int *, int *, int *, float **, int **, int **); +extern void sGenXtrue (int, int, float *, int); +extern void sFillRHS (trans_t, int, float *, int, SuperMatrix *, + SuperMatrix *); +extern void sgstrs (trans_t, SuperMatrix *, SuperMatrix *, int *, int *, + SuperMatrix *, SuperLUStat_t*, int *); + + +/* Driver related */ + +extern void sgsequ (SuperMatrix *, float *, float *, float *, + float *, float *, int *); +extern void slaqgs (SuperMatrix *, float *, float *, float, + float, float, char *); +extern void sgscon (char *, SuperMatrix *, SuperMatrix *, + float, float *, SuperLUStat_t*, int *); +extern float sPivotGrowth(int, SuperMatrix *, int *, + SuperMatrix *, SuperMatrix *); +extern void sgsrfs (trans_t, SuperMatrix *, SuperMatrix *, + SuperMatrix *, int *, int *, char *, float *, + float *, SuperMatrix *, SuperMatrix *, + float *, float *, SuperLUStat_t*, int *); + +extern int sp_strsv (char *, char *, char *, SuperMatrix *, + SuperMatrix *, float *, SuperLUStat_t*, int *); +extern int sp_sgemv (char *, float, SuperMatrix *, float *, + int, float, float *, int); + +extern int sp_sgemm (char *, int, float, + SuperMatrix *, float *, int, float, + float *, int); + +/* Memory-related */ +extern int sLUMemInit (fact_t, void *, int, int, int, int, int, + SuperMatrix *, SuperMatrix *, + GlobalLU_t *, int **, float **); +extern void sSetRWork (int, int, float *, float **, float **); +extern void sLUWorkFree (int *, float *, GlobalLU_t *); +extern int sLUMemXpand (int, int, MemType, int *, GlobalLU_t *); + +extern float *floatMalloc(int); +extern float *floatCalloc(int); +extern int smemory_usage(const int, const int, const int, const int); +extern int sQuerySpace (SuperMatrix *, SuperMatrix *, mem_usage_t *); + +/* Auxiliary routines */ +extern void sreadhb(int *, int *, int *, float **, int **, int **); +extern void sCompRow_to_CompCol(int, int, int, float*, int*, int*, + float **, int **, int **); +extern void sfill (float *, int, float); +extern void sinf_norm_error (int, SuperMatrix *, float *); +extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *, + float, float, float *, float *, char *); + +/* Routines for debugging */ +extern void sPrint_CompCol_Matrix(char *, SuperMatrix *); +extern void sPrint_SuperNode_Matrix(char *, SuperMatrix *); +extern void sPrint_Dense_Matrix(char *, SuperMatrix *); +extern void print_lu_col(char *, int, int, int *, GlobalLU_t *); +extern void check_tempv(int, float *); +extern int print_int_vec(char *what, int n, int *vec); + +extern int sp_symetree(int *acolst, int *acolend, int *arow, int n, int *parent); + +#ifdef __cplusplus + } +#endif + +#endif /* __SUPERLU_sSP_DEFS */ + diff --git a/intern/opennl/superlu/strsv.c b/intern/opennl/superlu/strsv.c new file mode 100644 index 00000000000..415f96f5f74 --- /dev/null +++ b/intern/opennl/superlu/strsv.c @@ -0,0 +1,333 @@ +int strsv_(char *, char *, char *, int *, float *, int *, float *, int *); + + +/* Subroutine */ int strsv_(char *uplo, char *trans, char *diag, int *n, + float *a, int *lda, float *x, int *incx) +{ + + + /* System generated locals */ + int i__1, i__2; + + /* Local variables */ + static int info; + static float temp; + static int i, j; + extern int lsame_(char *, char *); + static int ix, jx, kx; + extern /* Subroutine */ int xerbla_(char *, int *); + static int nounit; + + +/* Purpose + ======= + + STRSV solves one of the systems of equations + + A*x = b, or A'*x = b, + + where b and x are n element vectors and A is an n by n unit, or + non-unit, upper or lower triangular matrix. + + No test for singularity or near-singularity is included in this + routine. Such tests must be performed before calling this routine. + + Parameters + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the equations to be solved as + follows: + + TRANS = 'N' or 'n' A*x = b. + + TRANS = 'T' or 't' A'*x = b. + + TRANS = 'C' or 'c' A'*x = b. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit + triangular as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix A. + N must be at least zero. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array A must contain the upper + + triangular matrix and the strictly lower triangular part of + + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array A must contain the lower + + triangular matrix and the strictly upper triangular part of + + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + + in the calling (sub) program. LDA must be at least + max( 1, n ). + Unchanged on exit. + + X - REAL array of dimension at least + ( 1 + ( n - 1 )*abs( INCX ) ). + Before entry, the incremented array X must contain the n + element right-hand side vector b. On exit, X is overwritten + + with the solution vector x. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + + + Test the input parameters. + + + Parameter adjustments + Function Body */ +#define X(I) x[(I)-1] + +#define A(I,J) a[(I)-1 + ((J)-1)* ( *lda)] + + info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, "T") && + ! lsame_(trans, "C")) { + info = 2; + } else if (! lsame_(diag, "U") && ! lsame_(diag, "N")) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < ((1 > *n)? 1: *n)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } + if (info != 0) { + xerbla_("STRSV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + nounit = lsame_(diag, "N"); + +/* Set up the start point in X if the increment is not unity. This + will be ( N - 1 )*INCX too small for descending loops. */ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. */ + + if (lsame_(trans, "N")) { + +/* Form x := inv( A )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + if (X(j) != 0.f) { + if (nounit) { + X(j) /= A(j,j); + } + temp = X(j); + for (i = j - 1; i >= 1; --i) { + X(i) -= temp * A(i,j); +/* L10: */ + } + } +/* L20: */ + } + } else { + jx = kx + (*n - 1) * *incx; + for (j = *n; j >= 1; --j) { + if (X(jx) != 0.f) { + if (nounit) { + X(jx) /= A(j,j); + } + temp = X(jx); + ix = jx; + for (i = j - 1; i >= 1; --i) { + ix -= *incx; + X(ix) -= temp * A(i,j); +/* L30: */ + } + } + jx -= *incx; +/* L40: */ + } + } + } else { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= *n; ++j) { + if (X(j) != 0.f) { + if (nounit) { + X(j) /= A(j,j); + } + temp = X(j); + i__2 = *n; + for (i = j + 1; i <= *n; ++i) { + X(i) -= temp * A(i,j); +/* L50: */ + } + } +/* L60: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= *n; ++j) { + if (X(jx) != 0.f) { + if (nounit) { + X(jx) /= A(j,j); + } + temp = X(jx); + ix = jx; + i__2 = *n; + for (i = j + 1; i <= *n; ++i) { + ix += *incx; + X(ix) -= temp * A(i,j); +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } + } else { + +/* Form x := inv( A' )*x. */ + + if (lsame_(uplo, "U")) { + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= *n; ++j) { + temp = X(j); + i__2 = j - 1; + for (i = 1; i <= j-1; ++i) { + temp -= A(i,j) * X(i); +/* L90: */ + } + if (nounit) { + temp /= A(j,j); + } + X(j) = temp; +/* L100: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= *n; ++j) { + temp = X(jx); + ix = kx; + i__2 = j - 1; + for (i = 1; i <= j-1; ++i) { + temp -= A(i,j) * X(ix); + ix += *incx; +/* L110: */ + } + if (nounit) { + temp /= A(j,j); + } + X(jx) = temp; + jx += *incx; +/* L120: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + temp = X(j); + i__1 = j + 1; + for (i = *n; i >= j+1; --i) { + temp -= A(i,j) * X(i); +/* L130: */ + } + if (nounit) { + temp /= A(j,j); + } + X(j) = temp; +/* L140: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + temp = X(jx); + ix = kx; + i__1 = j + 1; + for (i = *n; i >= j+1; --i) { + temp -= A(i,j) * X(ix); + ix -= *incx; +/* L150: */ + } + if (nounit) { + temp /= A(j,j); + } + X(jx) = temp; + jx -= *incx; +/* L160: */ + } + } + } + } + + return 0; + +/* End of STRSV . */ + +} /* strsv_ */ + diff --git a/intern/opennl/superlu/superlu_timer.c b/intern/opennl/superlu/superlu_timer.c new file mode 100644 index 00000000000..f9e130c8c5a --- /dev/null +++ b/intern/opennl/superlu/superlu_timer.c @@ -0,0 +1,58 @@ +/* + * Purpose + * ======= + * Returns the time in seconds used by the process. + * + * Note: the timer function call is machine dependent. Use conditional + * compilation to choose the appropriate function. + * + */ + +/* We want this flag, safer than putting in build system */ +#define NO_TIMER + +double SuperLU_timer_ (); + +#ifdef SUN +/* + * It uses the system call gethrtime(3C), which is accurate to + * nanoseconds. +*/ +#include + +double SuperLU_timer_() { + return ( (double)gethrtime() / 1e9 ); +} + +#else + +#ifndef NO_TIMER +#include +#include +#include +#include +#endif + +#ifndef CLK_TCK +#define CLK_TCK 60 +#endif +double SuperLU_timer_(void); + +double SuperLU_timer_(void) +{ +#ifdef NO_TIMER + /* no sys/times.h on WIN32 */ + double tmp; + tmp = 0.0; +#else + struct tms use; + double tmp; + times(&use); + tmp = use.tms_utime; + tmp += use.tms_stime; +#endif + return (double)(tmp) / CLK_TCK; +} + +#endif + diff --git a/intern/opennl/superlu/supermatrix.h b/intern/opennl/superlu/supermatrix.h new file mode 100644 index 00000000000..665e22dc91f --- /dev/null +++ b/intern/opennl/superlu/supermatrix.h @@ -0,0 +1,140 @@ +#ifndef __SUPERLU_SUPERMATRIX /* allow multiple inclusions */ +#define __SUPERLU_SUPERMATRIX + +/******************************************** + * The matrix types are defined as follows. * + ********************************************/ +typedef enum { + SLU_NC, /* column-wise, no supernode */ + SLU_NR, /* row-wize, no supernode */ + SLU_SC, /* column-wise, supernode */ + SLU_SR, /* row-wise, supernode */ + SLU_NCP, /* column-wise, column-permuted, no supernode + (The consecutive columns of nonzeros, after permutation, + may not be stored contiguously.) */ + SLU_DN /* Fortran style column-wise storage for dense matrix */ +} Stype_t; + +typedef enum { + SLU_S, /* single */ + SLU_D, /* double */ + SLU_C, /* single complex */ + SLU_Z /* double complex */ +} Dtype_t; + +typedef enum { + SLU_GE, /* general */ + SLU_TRLU, /* lower triangular, unit diagonal */ + SLU_TRUU, /* upper triangular, unit diagonal */ + SLU_TRL, /* lower triangular */ + SLU_TRU, /* upper triangular */ + SLU_SYL, /* symmetric, store lower half */ + SLU_SYU, /* symmetric, store upper half */ + SLU_HEL, /* Hermitian, store lower half */ + SLU_HEU /* Hermitian, store upper half */ +} Mtype_t; + +typedef struct { + Stype_t Stype; /* Storage type: interprets the storage structure + pointed to by *Store. */ + Dtype_t Dtype; /* Data type. */ + Mtype_t Mtype; /* Matrix type: describes the mathematical property of + the matrix. */ + int_t nrow; /* number of rows */ + int_t ncol; /* number of columns */ + void *Store; /* pointer to the actual storage of the matrix */ +} SuperMatrix; + +/*********************************************** + * The storage schemes are defined as follows. * + ***********************************************/ + +/* Stype == NC (Also known as Harwell-Boeing sparse matrix format) */ +typedef struct { + int_t nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int_t *rowind; /* pointer to array of row indices of the nonzeros */ + int_t *colptr; /* pointer to array of beginning of columns in nzval[] + and rowind[] */ + /* Note: + Zero-based indexing is used; + colptr[] has ncol+1 entries, the last one pointing + beyond the last column, so that colptr[ncol] = nnz. */ +} NCformat; + +/* Stype == NR (Also known as row compressed storage (RCS). */ +typedef struct { + int_t nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by row */ + int_t *colind; /* pointer to array of column indices of the nonzeros */ + int_t *rowptr; /* pointer to array of beginning of rows in nzval[] + and colind[] */ + /* Note: + Zero-based indexing is used; + nzval[] and colind[] are of the same length, nnz; + rowptr[] has nrow+1 entries, the last one pointing + beyond the last column, so that rowptr[nrow] = nnz. */ +} NRformat; + +/* Stype == SC */ +typedef struct { + int_t nnz; /* number of nonzeros in the matrix */ + int_t nsuper; /* number of supernodes, minus 1 */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int_t *nzval_colptr;/* pointer to array of beginning of columns in nzval[] */ + int_t *rowind; /* pointer to array of compressed row indices of + rectangular supernodes */ + int_t *rowind_colptr;/* pointer to array of beginning of columns in rowind[] */ + int_t *col_to_sup; /* col_to_sup[j] is the supernode number to which column + j belongs; mapping from column to supernode number. */ + int_t *sup_to_col; /* sup_to_col[s] points to the start of the s-th + supernode; mapping from supernode number to column. + e.g.: col_to_sup: 0 1 2 2 3 3 3 4 4 4 4 4 4 (ncol=12) + sup_to_col: 0 1 2 4 7 12 (nsuper=4) */ + /* Note: + Zero-based indexing is used; + nzval_colptr[], rowind_colptr[], col_to_sup and + sup_to_col[] have ncol+1 entries, the last one + pointing beyond the last column. + For col_to_sup[], only the first ncol entries are + defined. For sup_to_col[], only the first nsuper+2 + entries are defined. */ +} SCformat; + +/* Stype == NCP */ +typedef struct { + int_t nnz; /* number of nonzeros in the matrix */ + void *nzval; /* pointer to array of nonzero values, packed by column */ + int_t *rowind;/* pointer to array of row indices of the nonzeros */ + /* Note: nzval[]/rowind[] always have the same length */ + int_t *colbeg;/* colbeg[j] points to the beginning of column j in nzval[] + and rowind[] */ + int_t *colend;/* colend[j] points to one past the last element of column + j in nzval[] and rowind[] */ + /* Note: + Zero-based indexing is used; + The consecutive columns of the nonzeros may not be + contiguous in storage, because the matrix has been + postmultiplied by a column permutation matrix. */ +} NCPformat; + +/* Stype == DN */ +typedef struct { + int_t lda; /* leading dimension */ + void *nzval; /* array of size lda*ncol to represent a dense matrix */ +} DNformat; + + + +/********************************************************* + * Macros used for easy access of sparse matrix entries. * + *********************************************************/ +#define L_SUB_START(col) ( Lstore->rowind_colptr[col] ) +#define L_SUB(ptr) ( Lstore->rowind[ptr] ) +#define L_NZ_START(col) ( Lstore->nzval_colptr[col] ) +#define L_FST_SUPC(superno) ( Lstore->sup_to_col[superno] ) +#define U_NZ_START(col) ( Ustore->colptr[col] ) +#define U_SUB(ptr) ( Ustore->rowind[ptr] ) + + +#endif /* __SUPERLU_SUPERMATRIX */ diff --git a/intern/opennl/superlu/sutil.c b/intern/opennl/superlu/sutil.c new file mode 100644 index 00000000000..78f0b8bc5cc --- /dev/null +++ b/intern/opennl/superlu/sutil.c @@ -0,0 +1,486 @@ + +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include "ssp_defs.h" + +/* prototypes */ +void sprint_lu_col(char *msg, int jcol, int pivrow, int *xprune, GlobalLU_t *Glu); +void scheck_tempv(int n, float *tempv); +void sPrintPerf(SuperMatrix *, SuperMatrix *, mem_usage_t *,float , float , + float *, float *, char *, SuperLUStat_t *); +int print_float_vec(char *what, int n, float *vec); +/* ********** */ + +void +sCreate_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz, + float *nzval, int *rowind, int *colptr, + Stype_t stype, Dtype_t dtype, Mtype_t mtype) +{ + NCformat *Astore; + + A->Stype = stype; + A->Dtype = dtype; + A->Mtype = mtype; + A->nrow = m; + A->ncol = n; + A->Store = (void *) SUPERLU_MALLOC( sizeof(NCformat) ); + if ( !(A->Store) ) ABORT("SUPERLU_MALLOC fails for A->Store"); + Astore = A->Store; + Astore->nnz = nnz; + Astore->nzval = nzval; + Astore->rowind = rowind; + Astore->colptr = colptr; +} + +void +sCreate_CompRow_Matrix(SuperMatrix *A, int m, int n, int nnz, + float *nzval, int *colind, int *rowptr, + Stype_t stype, Dtype_t dtype, Mtype_t mtype) +{ + NRformat *Astore; + + A->Stype = stype; + A->Dtype = dtype; + A->Mtype = mtype; + A->nrow = m; + A->ncol = n; + A->Store = (void *) SUPERLU_MALLOC( sizeof(NRformat) ); + if ( !(A->Store) ) ABORT("SUPERLU_MALLOC fails for A->Store"); + Astore = A->Store; + Astore->nnz = nnz; + Astore->nzval = nzval; + Astore->colind = colind; + Astore->rowptr = rowptr; +} + +/* Copy matrix A into matrix B. */ +void +sCopy_CompCol_Matrix(SuperMatrix *A, SuperMatrix *B) +{ + NCformat *Astore, *Bstore; + int ncol, nnz, i; + + B->Stype = A->Stype; + B->Dtype = A->Dtype; + B->Mtype = A->Mtype; + B->nrow = A->nrow;; + B->ncol = ncol = A->ncol; + Astore = (NCformat *) A->Store; + Bstore = (NCformat *) B->Store; + Bstore->nnz = nnz = Astore->nnz; + for (i = 0; i < nnz; ++i) + ((float *)Bstore->nzval)[i] = ((float *)Astore->nzval)[i]; + for (i = 0; i < nnz; ++i) Bstore->rowind[i] = Astore->rowind[i]; + for (i = 0; i <= ncol; ++i) Bstore->colptr[i] = Astore->colptr[i]; +} + + +void +sCreate_Dense_Matrix(SuperMatrix *X, int m, int n, float *x, int ldx, + Stype_t stype, Dtype_t dtype, Mtype_t mtype) +{ + DNformat *Xstore; + + X->Stype = stype; + X->Dtype = dtype; + X->Mtype = mtype; + X->nrow = m; + X->ncol = n; + X->Store = (void *) SUPERLU_MALLOC( sizeof(DNformat) ); + if ( !(X->Store) ) ABORT("SUPERLU_MALLOC fails for X->Store"); + Xstore = (DNformat *) X->Store; + Xstore->lda = ldx; + Xstore->nzval = (float *) x; +} + +void +sCopy_Dense_Matrix(int M, int N, float *X, int ldx, + float *Y, int ldy) +{ +/* + * + * Purpose + * ======= + * + * Copies a two-dimensional matrix X to another matrix Y. + */ + int i, j; + + for (j = 0; j < N; ++j) + for (i = 0; i < M; ++i) + Y[i + j*ldy] = X[i + j*ldx]; +} + +void +sCreate_SuperNode_Matrix(SuperMatrix *L, int m, int n, int nnz, + float *nzval, int *nzval_colptr, int *rowind, + int *rowind_colptr, int *col_to_sup, int *sup_to_col, + Stype_t stype, Dtype_t dtype, Mtype_t mtype) +{ + SCformat *Lstore; + + L->Stype = stype; + L->Dtype = dtype; + L->Mtype = mtype; + L->nrow = m; + L->ncol = n; + L->Store = (void *) SUPERLU_MALLOC( sizeof(SCformat) ); + if ( !(L->Store) ) ABORT("SUPERLU_MALLOC fails for L->Store"); + Lstore = L->Store; + Lstore->nnz = nnz; + Lstore->nsuper = col_to_sup[n]; + Lstore->nzval = nzval; + Lstore->nzval_colptr = nzval_colptr; + Lstore->rowind = rowind; + Lstore->rowind_colptr = rowind_colptr; + Lstore->col_to_sup = col_to_sup; + Lstore->sup_to_col = sup_to_col; + +} + + +/* + * Convert a row compressed storage into a column compressed storage. + */ +void +sCompRow_to_CompCol(int m, int n, int nnz, + float *a, int *colind, int *rowptr, + float **at, int **rowind, int **colptr) +{ + register int i, j, col, relpos; + int *marker; + + /* Allocate storage for another copy of the matrix. */ + *at = (float *) floatMalloc(nnz); + *rowind = (int *) intMalloc(nnz); + *colptr = (int *) intMalloc(n+1); + marker = (int *) intCalloc(n); + + /* Get counts of each column of A, and set up column pointers */ + for (i = 0; i < m; ++i) + for (j = rowptr[i]; j < rowptr[i+1]; ++j) ++marker[colind[j]]; + (*colptr)[0] = 0; + for (j = 0; j < n; ++j) { + (*colptr)[j+1] = (*colptr)[j] + marker[j]; + marker[j] = (*colptr)[j]; + } + + /* Transfer the matrix into the compressed column storage. */ + for (i = 0; i < m; ++i) { + for (j = rowptr[i]; j < rowptr[i+1]; ++j) { + col = colind[j]; + relpos = marker[col]; + (*rowind)[relpos] = i; + (*at)[relpos] = a[j]; + ++marker[col]; + } + } + + SUPERLU_FREE(marker); +} + + +void +sPrint_CompCol_Matrix(char *what, SuperMatrix *A) +{ + NCformat *Astore; + register int i,n; + float *dp; + + printf("\nCompCol matrix %s:\n", what); + printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); + n = A->ncol; + Astore = (NCformat *) A->Store; + dp = (float *) Astore->nzval; + printf("nrow %d, ncol %d, nnz %d\n", A->nrow,A->ncol,Astore->nnz); + printf("nzval: "); + for (i = 0; i < Astore->colptr[n]; ++i) printf("%f ", dp[i]); + printf("\nrowind: "); + for (i = 0; i < Astore->colptr[n]; ++i) printf("%d ", Astore->rowind[i]); + printf("\ncolptr: "); + for (i = 0; i <= n; ++i) printf("%d ", Astore->colptr[i]); + printf("\n"); + fflush(stdout); +} + +void +sPrint_SuperNode_Matrix(char *what, SuperMatrix *A) +{ + SCformat *Astore; + register int i, j, k, c, d, n, nsup; + float *dp; + int *col_to_sup, *sup_to_col, *rowind, *rowind_colptr; + + printf("\nSuperNode matrix %s:\n", what); + printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); + n = A->ncol; + Astore = (SCformat *) A->Store; + dp = (float *) Astore->nzval; + col_to_sup = Astore->col_to_sup; + sup_to_col = Astore->sup_to_col; + rowind_colptr = Astore->rowind_colptr; + rowind = Astore->rowind; + printf("nrow %d, ncol %d, nnz %d, nsuper %d\n", + A->nrow,A->ncol,Astore->nnz,Astore->nsuper); + printf("nzval:\n"); + for (k = 0; k <= Astore->nsuper; ++k) { + c = sup_to_col[k]; + nsup = sup_to_col[k+1] - c; + for (j = c; j < c + nsup; ++j) { + d = Astore->nzval_colptr[j]; + for (i = rowind_colptr[c]; i < rowind_colptr[c+1]; ++i) { + printf("%d\t%d\t%e\n", rowind[i], j, dp[d++]); + } + } + } +#if 0 + for (i = 0; i < Astore->nzval_colptr[n]; ++i) printf("%f ", dp[i]); +#endif + printf("\nnzval_colptr: "); + for (i = 0; i <= n; ++i) printf("%d ", Astore->nzval_colptr[i]); + printf("\nrowind: "); + for (i = 0; i < Astore->rowind_colptr[n]; ++i) + printf("%d ", Astore->rowind[i]); + printf("\nrowind_colptr: "); + for (i = 0; i <= n; ++i) printf("%d ", Astore->rowind_colptr[i]); + printf("\ncol_to_sup: "); + for (i = 0; i < n; ++i) printf("%d ", col_to_sup[i]); + printf("\nsup_to_col: "); + for (i = 0; i <= Astore->nsuper+1; ++i) + printf("%d ", sup_to_col[i]); + printf("\n"); + fflush(stdout); +} + +void +sPrint_Dense_Matrix(char *what, SuperMatrix *A) +{ + DNformat *Astore; + register int i; + float *dp; + + printf("\nDense matrix %s:\n", what); + printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); + Astore = (DNformat *) A->Store; + dp = (float *) Astore->nzval; + printf("nrow %d, ncol %d, lda %d\n", A->nrow,A->ncol,Astore->lda); + printf("\nnzval: "); + for (i = 0; i < A->nrow; ++i) printf("%f ", dp[i]); + printf("\n"); + fflush(stdout); +} + +/* + * Diagnostic print of column "jcol" in the U/L factor. + */ +void +sprint_lu_col(char *msg, int jcol, int pivrow, int *xprune, GlobalLU_t *Glu) +{ + int i, k, fsupc; + int *xsup, *supno; + int *xlsub, *lsub; + float *lusup; + int *xlusup; + float *ucol; + int *usub, *xusub; + + xsup = Glu->xsup; + supno = Glu->supno; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + lusup = Glu->lusup; + xlusup = Glu->xlusup; + ucol = Glu->ucol; + usub = Glu->usub; + xusub = Glu->xusub; + + printf("%s", msg); + printf("col %d: pivrow %d, supno %d, xprune %d\n", + jcol, pivrow, supno[jcol], xprune[jcol]); + + printf("\tU-col:\n"); + for (i = xusub[jcol]; i < xusub[jcol+1]; i++) + printf("\t%d%10.4f\n", usub[i], ucol[i]); + printf("\tL-col in rectangular snode:\n"); + fsupc = xsup[supno[jcol]]; /* first col of the snode */ + i = xlsub[fsupc]; + k = xlusup[jcol]; + while ( i < xlsub[fsupc+1] && k < xlusup[jcol+1] ) { + printf("\t%d\t%10.4f\n", lsub[i], lusup[k]); + i++; k++; + } + fflush(stdout); +} + + +/* + * Check whether tempv[] == 0. This should be true before and after + * calling any numeric routines, i.e., "panel_bmod" and "column_bmod". + */ +void scheck_tempv(int n, float *tempv) +{ + int i; + + for (i = 0; i < n; i++) { + if (tempv[i] != 0.0) + { + fprintf(stderr,"tempv[%d] = %f\n", i,tempv[i]); + ABORT("scheck_tempv"); + } + } +} + + +void +sGenXtrue(int n, int nrhs, float *x, int ldx) +{ + int i, j; + for (j = 0; j < nrhs; ++j) + for (i = 0; i < n; ++i) { + x[i + j*ldx] = 1.0;/* + (float)(i+1.)/n;*/ + } +} + +/* + * Let rhs[i] = sum of i-th row of A, so the solution vector is all 1's + */ +void +sFillRHS(trans_t trans, int nrhs, float *x, int ldx, + SuperMatrix *A, SuperMatrix *B) +{ + NCformat *Astore; + float *Aval; + DNformat *Bstore; + float *rhs; + float one = 1.0; + float zero = 0.0; + int ldc; + char transc[1]; + + Astore = A->Store; + Aval = (float *) Astore->nzval; + Bstore = B->Store; + rhs = Bstore->nzval; + ldc = Bstore->lda; + + if ( trans == NOTRANS ) *(unsigned char *)transc = 'N'; + else *(unsigned char *)transc = 'T'; + + sp_sgemm(transc, nrhs, one, A, + x, ldx, zero, rhs, ldc); + +} + +/* + * Fills a float precision array with a given value. + */ +void +sfill(float *a, int alen, float dval) +{ + register int i; + for (i = 0; i < alen; i++) a[i] = dval; +} + + + +/* + * Check the inf-norm of the error vector + */ +void sinf_norm_error(int nrhs, SuperMatrix *X, float *xtrue) +{ + DNformat *Xstore; + float err, xnorm; + float *Xmat, *soln_work; + int i, j; + + Xstore = X->Store; + Xmat = Xstore->nzval; + + for (j = 0; j < nrhs; j++) { + soln_work = &Xmat[j*Xstore->lda]; + err = xnorm = 0.0; + for (i = 0; i < X->nrow; i++) { + err = SUPERLU_MAX(err, fabs(soln_work[i] - xtrue[i])); + xnorm = SUPERLU_MAX(xnorm, fabs(soln_work[i])); + } + err = err / xnorm; + printf("||X - Xtrue||/||X|| = %e\n", err); + } +} + + + +/* Print performance of the code. */ +void +sPrintPerf(SuperMatrix *L, SuperMatrix *U, mem_usage_t *mem_usage, + float rpg, float rcond, float *ferr, + float *berr, char *equed, SuperLUStat_t *stat) +{ + SCformat *Lstore; + NCformat *Ustore; + double *utime; + flops_t *ops; + + utime = stat->utime; + ops = stat->ops; + + if ( utime[FACT] != 0. ) + printf("Factor flops = %e\tMflops = %8.2f\n", ops[FACT], + ops[FACT]*1e-6/utime[FACT]); + printf("Identify relaxed snodes = %8.2f\n", utime[RELAX]); + if ( utime[SOLVE] != 0. ) + printf("Solve flops = %.0f, Mflops = %8.2f\n", ops[SOLVE], + ops[SOLVE]*1e-6/utime[SOLVE]); + + Lstore = (SCformat *) L->Store; + Ustore = (NCformat *) U->Store; + printf("\tNo of nonzeros in factor L = %d\n", Lstore->nnz); + printf("\tNo of nonzeros in factor U = %d\n", Ustore->nnz); + printf("\tNo of nonzeros in L+U = %d\n", Lstore->nnz + Ustore->nnz); + + printf("L\\U MB %.3f\ttotal MB needed %.3f\texpansions %d\n", + mem_usage->for_lu/1e6, mem_usage->total_needed/1e6, + mem_usage->expansions); + + printf("\tFactor\tMflops\tSolve\tMflops\tEtree\tEquil\tRcond\tRefine\n"); + printf("PERF:%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f\n", + utime[FACT], ops[FACT]*1e-6/utime[FACT], + utime[SOLVE], ops[SOLVE]*1e-6/utime[SOLVE], + utime[ETREE], utime[EQUIL], utime[RCOND], utime[REFINE]); + + printf("\tRpg\t\tRcond\t\tFerr\t\tBerr\t\tEquil?\n"); + printf("NUM:\t%e\t%e\t%e\t%e\t%s\n", + rpg, rcond, ferr[0], berr[0], equed); + +} + + + + +int print_float_vec(char *what, int n, float *vec) +{ + int i; + printf("%s: n %d\n", what, n); + for (i = 0; i < n; ++i) printf("%d\t%f\n", i, vec[i]); + return 0; +} + diff --git a/intern/opennl/superlu/util.c b/intern/opennl/superlu/util.c new file mode 100644 index 00000000000..824cabacee5 --- /dev/null +++ b/intern/opennl/superlu/util.c @@ -0,0 +1,397 @@ +/* + * -- SuperLU routine (version 3.0) -- + * Univ. of California Berkeley, Xerox Palo Alto Research Center, + * and Lawrence Berkeley National Lab. + * October 15, 2003 + * + */ +/* + Copyright (c) 1994 by Xerox Corporation. All rights reserved. + + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY + EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + + Permission is hereby granted to use or copy this program for any + purpose, provided the above notices are retained on all copies. + Permission to modify the code and to distribute modified code is + granted, provided the above notices are retained, and a notice that + the code was modified is included with the above copyright notice. +*/ + +#include +#include "ssp_defs.h" +#include "util.h" + +/* prototypes */ +flops_t LUFactFlops(SuperLUStat_t *stat); +flops_t LUSolveFlops(SuperLUStat_t *stat); +float SpaSize(int n, int np, float sum_npw); +float DenseSize(int n, float sum_nw); + +/* + * Global statistics variale + */ + +void superlu_abort_and_exit(char* msg) +{ + fprintf(stderr, msg); + exit (-1); +} + +/* + * Set the default values for the options argument. + */ +void set_default_options(superlu_options_t *options) +{ + options->Fact = DOFACT; + options->Equil = YES; + options->ColPerm = COLAMD; + options->DiagPivotThresh = 1.0; + options->Trans = NOTRANS; + options->IterRefine = NOREFINE; + options->SymmetricMode = NO; + options->PivotGrowth = NO; + options->ConditionNumber = NO; + options->PrintStat = YES; +} + +/* Deallocate the structure pointing to the actual storage of the matrix. */ +void +Destroy_SuperMatrix_Store(SuperMatrix *A) +{ + SUPERLU_FREE ( A->Store ); +} + +void +Destroy_CompCol_Matrix(SuperMatrix *A) +{ + SUPERLU_FREE( ((NCformat *)A->Store)->rowind ); + SUPERLU_FREE( ((NCformat *)A->Store)->colptr ); + SUPERLU_FREE( ((NCformat *)A->Store)->nzval ); + SUPERLU_FREE( A->Store ); +} + +void +Destroy_CompRow_Matrix(SuperMatrix *A) +{ + SUPERLU_FREE( ((NRformat *)A->Store)->colind ); + SUPERLU_FREE( ((NRformat *)A->Store)->rowptr ); + SUPERLU_FREE( ((NRformat *)A->Store)->nzval ); + SUPERLU_FREE( A->Store ); +} + +void +Destroy_SuperNode_Matrix(SuperMatrix *A) +{ + SUPERLU_FREE ( ((SCformat *)A->Store)->rowind ); + SUPERLU_FREE ( ((SCformat *)A->Store)->rowind_colptr ); + SUPERLU_FREE ( ((SCformat *)A->Store)->nzval ); + SUPERLU_FREE ( ((SCformat *)A->Store)->nzval_colptr ); + SUPERLU_FREE ( ((SCformat *)A->Store)->col_to_sup ); + SUPERLU_FREE ( ((SCformat *)A->Store)->sup_to_col ); + SUPERLU_FREE ( A->Store ); +} + +/* A is of type Stype==NCP */ +void +Destroy_CompCol_Permuted(SuperMatrix *A) +{ + SUPERLU_FREE ( ((NCPformat *)A->Store)->colbeg ); + SUPERLU_FREE ( ((NCPformat *)A->Store)->colend ); + SUPERLU_FREE ( A->Store ); +} + +/* A is of type Stype==DN */ +void +Destroy_Dense_Matrix(SuperMatrix *A) +{ + DNformat* Astore = A->Store; + SUPERLU_FREE (Astore->nzval); + SUPERLU_FREE ( A->Store ); +} + +/* + * Reset repfnz[] for the current column + */ +void +resetrep_col (const int nseg, const int *segrep, int *repfnz) +{ + int i, irep; + + for (i = 0; i < nseg; i++) { + irep = segrep[i]; + repfnz[irep] = EMPTY; + } +} + + +/* + * Count the total number of nonzeros in factors L and U, and in the + * symmetrically reduced L. + */ +void +countnz(const int n, int *xprune, int *nnzL, int *nnzU, GlobalLU_t *Glu) +{ + int nsuper, fsupc, i, j; + int nnzL0, jlen, irep; + int *xsup, *xlsub; + + xsup = Glu->xsup; + xlsub = Glu->xlsub; + *nnzL = 0; + *nnzU = (Glu->xusub)[n]; + nnzL0 = 0; + nsuper = (Glu->supno)[n]; + + if ( n <= 0 ) return; + + /* + * For each supernode + */ + for (i = 0; i <= nsuper; i++) { + fsupc = xsup[i]; + jlen = xlsub[fsupc+1] - xlsub[fsupc]; + + for (j = fsupc; j < xsup[i+1]; j++) { + *nnzL += jlen; + *nnzU += j - fsupc + 1; + jlen--; + } + irep = xsup[i+1] - 1; + nnzL0 += xprune[irep] - xlsub[irep]; + } + + /* printf("\tNo of nonzeros in symm-reduced L = %d\n", nnzL0);*/ +} + + + +/* + * Fix up the data storage lsub for L-subscripts. It removes the subscript + * sets for structural pruning, and applies permuation to the remaining + * subscripts. + */ +void +fixupL(const int n, const int *perm_r, GlobalLU_t *Glu) +{ + register int nsuper, fsupc, nextl, i, j, k, jstrt; + int *xsup, *lsub, *xlsub; + + if ( n <= 1 ) return; + + xsup = Glu->xsup; + lsub = Glu->lsub; + xlsub = Glu->xlsub; + nextl = 0; + nsuper = (Glu->supno)[n]; + + /* + * For each supernode ... + */ + for (i = 0; i <= nsuper; i++) { + fsupc = xsup[i]; + jstrt = xlsub[fsupc]; + xlsub[fsupc] = nextl; + for (j = jstrt; j < xlsub[fsupc+1]; j++) { + lsub[nextl] = perm_r[lsub[j]]; /* Now indexed into P*A */ + nextl++; + } + for (k = fsupc+1; k < xsup[i+1]; k++) + xlsub[k] = nextl; /* Other columns in supernode i */ + + } + + xlsub[n] = nextl; +} + + +/* + * Diagnostic print of segment info after panel_dfs(). + */ +void print_panel_seg(int n, int w, int jcol, int nseg, + int *segrep, int *repfnz) +{ + int j, k; + + for (j = jcol; j < jcol+w; j++) { + printf("\tcol %d:\n", j); + for (k = 0; k < nseg; k++) + printf("\t\tseg %d, segrep %d, repfnz %d\n", k, + segrep[k], repfnz[(j-jcol)*n + segrep[k]]); + } + +} + + +void +StatInit(SuperLUStat_t *stat) +{ + register int i, w, panel_size, relax; + + panel_size = sp_ienv(1); + relax = sp_ienv(2); + w = SUPERLU_MAX(panel_size, relax); + stat->panel_histo = intCalloc(w+1); + stat->utime = (double *) SUPERLU_MALLOC(NPHASES * sizeof(double)); + if (!stat->utime) ABORT("SUPERLU_MALLOC fails for stat->utime"); + stat->ops = (flops_t *) SUPERLU_MALLOC(NPHASES * sizeof(flops_t)); + if (!stat->ops) ABORT("SUPERLU_MALLOC fails for stat->ops"); + for (i = 0; i < NPHASES; ++i) { + stat->utime[i] = 0.; + stat->ops[i] = 0.; + } +} + + +void +StatPrint(SuperLUStat_t *stat) +{ + double *utime; + flops_t *ops; + + utime = stat->utime; + ops = stat->ops; + printf("Factor time = %8.2f\n", utime[FACT]); + if ( utime[FACT] != 0.0 ) + printf("Factor flops = %e\tMflops = %8.2f\n", ops[FACT], + ops[FACT]*1e-6/utime[FACT]); + + printf("Solve time = %8.2f\n", utime[SOLVE]); + if ( utime[SOLVE] != 0.0 ) + printf("Solve flops = %e\tMflops = %8.2f\n", ops[SOLVE], + ops[SOLVE]*1e-6/utime[SOLVE]); + +} + + +void +StatFree(SuperLUStat_t *stat) +{ + SUPERLU_FREE(stat->panel_histo); + SUPERLU_FREE(stat->utime); + SUPERLU_FREE(stat->ops); +} + + +flops_t +LUFactFlops(SuperLUStat_t *stat) +{ + return (stat->ops[FACT]); +} + +flops_t +LUSolveFlops(SuperLUStat_t *stat) +{ + return (stat->ops[SOLVE]); +} + + + + + +/* + * Fills an integer array with a given value. + */ +void ifill(int *a, int alen, int ival) +{ + register int i; + for (i = 0; i < alen; i++) a[i] = ival; +} + + + +/* + * Get the statistics of the supernodes + */ +#define NBUCKS 10 +static int max_sup_size; + +void super_stats(int nsuper, int *xsup) +{ + register int nsup1 = 0; + int i, isize, whichb, bl, bh; + int bucket[NBUCKS]; + + max_sup_size = 0; + + for (i = 0; i <= nsuper; i++) { + isize = xsup[i+1] - xsup[i]; + if ( isize == 1 ) nsup1++; + if ( max_sup_size < isize ) max_sup_size = isize; + } + + printf(" Supernode statistics:\n\tno of super = %d\n", nsuper+1); + printf("\tmax supernode size = %d\n", max_sup_size); + printf("\tno of size 1 supernodes = %d\n", nsup1); + + /* Histogram of the supernode sizes */ + ifill (bucket, NBUCKS, 0); + + for (i = 0; i <= nsuper; i++) { + isize = xsup[i+1] - xsup[i]; + whichb = (float) isize / max_sup_size * NBUCKS; + if (whichb >= NBUCKS) whichb = NBUCKS - 1; + bucket[whichb]++; + } + + printf("\tHistogram of supernode sizes:\n"); + for (i = 0; i < NBUCKS; i++) { + bl = (float) i * max_sup_size / NBUCKS; + bh = (float) (i+1) * max_sup_size / NBUCKS; + printf("\tsnode: %d-%d\t\t%d\n", bl+1, bh, bucket[i]); + } + +} + + +float SpaSize(int n, int np, float sum_npw) +{ + return (sum_npw*8 + np*8 + n*4)/1024.; +} + +float DenseSize(int n, float sum_nw) +{ + return (sum_nw*8 + n*8)/1024.;; +} + + + +/* + * Check whether repfnz[] == EMPTY after reset. + */ +void check_repfnz(int n, int w, int jcol, int *repfnz) +{ + int jj, k; + + for (jj = jcol; jj < jcol+w; jj++) + for (k = 0; k < n; k++) + if ( repfnz[(jj-jcol)*n + k] != EMPTY ) { + fprintf(stderr, "col %d, repfnz_col[%d] = %d\n", jj, + k, repfnz[(jj-jcol)*n + k]); + ABORT("check_repfnz"); + } +} + + +/* Print a summary of the testing results. */ +void +PrintSumm(char *type, int nfail, int nrun, int nerrs) +{ + if ( nfail > 0 ) + printf("%3s driver: %d out of %d tests failed to pass the threshold\n", + type, nfail, nrun); + else + printf("All tests for %3s driver passed the threshold (%6d tests run)\n", type, nrun); + + if ( nerrs > 0 ) + printf("%6d error messages recorded\n", nerrs); +} + + +int print_int_vec(char *what, int n, int *vec) +{ + int i; + printf("%s\n", what); + for (i = 0; i < n; ++i) printf("%d\t%d\n", i, vec[i]); + return 0; +} diff --git a/intern/opennl/superlu/util.h b/intern/opennl/superlu/util.h new file mode 100644 index 00000000000..1a3526d4e7e --- /dev/null +++ b/intern/opennl/superlu/util.h @@ -0,0 +1,267 @@ +#ifndef __SUPERLU_UTIL /* allow multiple inclusions */ +#define __SUPERLU_UTIL + +#include +#include +#include +/* +#ifndef __STDC__ +#include +#endif +*/ +#include + +/*********************************************************************** + * Macros + ***********************************************************************/ +#define FIRSTCOL_OF_SNODE(i) (xsup[i]) +/* No of marker arrays used in the symbolic factorization, + each of size n */ +#define NO_MARKER 3 +#define NUM_TEMPV(m,w,t,b) ( SUPERLU_MAX(m, (t + b)*w) ) + +#ifndef USER_ABORT +#define USER_ABORT(msg) superlu_abort_and_exit(msg) +#endif + +#define ABORT(err_msg) \ + { char msg[256];\ + sprintf(msg,"%s at line %d in file %s\n",err_msg,__LINE__, __FILE__);\ + USER_ABORT(msg); } + + +#ifndef USER_MALLOC +#if 1 +#define USER_MALLOC(size) superlu_malloc(size) +#else +/* The following may check out some uninitialized data */ +#define USER_MALLOC(size) memset (superlu_malloc(size), '\x0F', size) +#endif +#endif + +#define SUPERLU_MALLOC(size) USER_MALLOC(size) + +#ifndef USER_FREE +#define USER_FREE(addr) superlu_free(addr) +#endif + +#define SUPERLU_FREE(addr) USER_FREE(addr) + +#define CHECK_MALLOC(where) { \ + extern int superlu_malloc_total; \ + printf("%s: malloc_total %d Bytes\n", \ + where, superlu_malloc_total); \ +} + +#define SUPERLU_MAX(x, y) ( (x) > (y) ? (x) : (y) ) +#define SUPERLU_MIN(x, y) ( (x) < (y) ? (x) : (y) ) + +/*********************************************************************** + * Constants + ***********************************************************************/ +#define EMPTY (-1) +/*#define NO (-1)*/ +#define FALSE 0 +#define TRUE 1 + +/*********************************************************************** + * Enumerate types + ***********************************************************************/ +typedef enum {NO, YES} yes_no_t; +typedef enum {DOFACT, SamePattern, SamePattern_SameRowPerm, FACTORED} fact_t; +typedef enum {NOROWPERM, LargeDiag, MY_PERMR} rowperm_t; +typedef enum {NATURAL, MMD_ATA, MMD_AT_PLUS_A, COLAMD, MY_PERMC}colperm_t; +typedef enum {NOTRANS, TRANS, CONJ} trans_t; +typedef enum {NOEQUIL, ROW, COL, BOTH} DiagScale_t; +typedef enum {NOREFINE, SINGLE=1, SLU_DOUBLE, EXTRA} IterRefine_t; +typedef enum {LUSUP, UCOL, LSUB, USUB} MemType; +typedef enum {HEAD, TAIL} stack_end_t; +typedef enum {SYSTEM, USER} LU_space_t; + +/* + * The following enumerate type is used by the statistics variable + * to keep track of flop count and time spent at various stages. + * + * Note that not all of the fields are disjoint. + */ +typedef enum { + COLPERM, /* find a column ordering that minimizes fills */ + RELAX, /* find artificial supernodes */ + ETREE, /* compute column etree */ + EQUIL, /* equilibrate the original matrix */ + FACT, /* perform LU factorization */ + RCOND, /* estimate reciprocal condition number */ + SOLVE, /* forward and back solves */ + REFINE, /* perform iterative refinement */ + SLU_FLOAT, /* time spent in floating-point operations */ + TRSV, /* fraction of FACT spent in xTRSV */ + GEMV, /* fraction of FACT spent in xGEMV */ + FERR, /* estimate error bounds after iterative refinement */ + NPHASES /* total number of phases */ +} PhaseType; + + +/*********************************************************************** + * Type definitions + ***********************************************************************/ +typedef float flops_t; +typedef unsigned char Logical; + +/* + *-- This contains the options used to control the solve process. + * + * Fact (fact_t) + * Specifies whether or not the factored form of the matrix + * A is supplied on entry, and if not, how the matrix A should + * be factorizaed. + * = DOFACT: The matrix A will be factorized from scratch, and the + * factors will be stored in L and U. + * = SamePattern: The matrix A will be factorized assuming + * that a factorization of a matrix with the same sparsity + * pattern was performed prior to this one. Therefore, this + * factorization will reuse column permutation vector + * ScalePermstruct->perm_c and the column elimination tree + * LUstruct->etree. + * = SamePattern_SameRowPerm: The matrix A will be factorized + * assuming that a factorization of a matrix with the same + * sparsity pattern and similar numerical values was performed + * prior to this one. Therefore, this factorization will reuse + * both row and column scaling factors R and C, and the + * both row and column permutation vectors perm_r and perm_c, + * distributed data structure set up from the previous symbolic + * factorization. + * = FACTORED: On entry, L, U, perm_r and perm_c contain the + * factored form of A. If DiagScale is not NOEQUIL, the matrix + * A has been equilibrated with scaling factors R and C. + * + * Equil (yes_no_t) + * Specifies whether to equilibrate the system (scale A's row and + * columns to have unit norm). + * + * ColPerm (colperm_t) + * Specifies what type of column permutation to use to reduce fill. + * = NATURAL: use the natural ordering + * = MMD_ATA: use minimum degree ordering on structure of A'*A + * = MMD_AT_PLUS_A: use minimum degree ordering on structure of A'+A + * = COLAMD: use approximate minimum degree column ordering + * = MY_PERMC: use the ordering specified in ScalePermstruct->perm_c[] + * + * Trans (trans_t) + * Specifies the form of the system of equations: + * = NOTRANS: A * X = B (No transpose) + * = TRANS: A**T * X = B (Transpose) + * = CONJ: A**H * X = B (Transpose) + * + * IterRefine (IterRefine_t) + * Specifies whether to perform iterative refinement. + * = NO: no iterative refinement + * = WorkingPrec: perform iterative refinement in working precision + * = ExtraPrec: perform iterative refinement in extra precision + * + * PrintStat (yes_no_t) + * Specifies whether to print the solver's statistics. + * + * DiagPivotThresh (double, in [0.0, 1.0]) (only for sequential SuperLU) + * Specifies the threshold used for a diagonal entry to be an + * acceptable pivot. + * + * PivotGrowth (yes_no_t) + * Specifies whether to compute the reciprocal pivot growth. + * + * ConditionNumber (ues_no_t) + * Specifies whether to compute the reciprocal condition number. + * + * RowPerm (rowperm_t) (only for SuperLU_DIST) + * Specifies whether to permute rows of the original matrix. + * = NO: not to permute the rows + * = LargeDiag: make the diagonal large relative to the off-diagonal + * = MY_PERMR: use the permutation given in ScalePermstruct->perm_r[] + * + * ReplaceTinyPivot (yes_no_t) (only for SuperLU_DIST) + * Specifies whether to replace the tiny diagonals by + * sqrt(epsilon)*||A|| during LU factorization. + * + * SolveInitialized (yes_no_t) (only for SuperLU_DIST) + * Specifies whether the initialization has been performed to the + * triangular solve. + * + * RefineInitialized (yes_no_t) (only for SuperLU_DIST) + * Specifies whether the initialization has been performed to the + * sparse matrix-vector multiplication routine needed in iterative + * refinement. + */ +typedef struct { + fact_t Fact; + yes_no_t Equil; + colperm_t ColPerm; + trans_t Trans; + IterRefine_t IterRefine; + yes_no_t PrintStat; + yes_no_t SymmetricMode; + double DiagPivotThresh; + yes_no_t PivotGrowth; + yes_no_t ConditionNumber; + rowperm_t RowPerm; + yes_no_t ReplaceTinyPivot; + yes_no_t SolveInitialized; + yes_no_t RefineInitialized; +} superlu_options_t; + +typedef struct { + int *panel_histo; /* histogram of panel size distribution */ + double *utime; /* running time at various phases */ + flops_t *ops; /* operation count at various phases */ + int TinyPivots; /* number of tiny pivots */ + int RefineSteps; /* number of iterative refinement steps */ +} SuperLUStat_t; + + +/*********************************************************************** + * Prototypes + ***********************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +extern void Destroy_SuperMatrix_Store(SuperMatrix *); +extern void Destroy_CompCol_Matrix(SuperMatrix *); +extern void Destroy_CompRow_Matrix(SuperMatrix *); +extern void Destroy_SuperNode_Matrix(SuperMatrix *); +extern void Destroy_CompCol_Permuted(SuperMatrix *); +extern void Destroy_Dense_Matrix(SuperMatrix *); +extern void get_perm_c(int, SuperMatrix *, int *); +extern void set_default_options(superlu_options_t *options); +extern void sp_preorder (superlu_options_t *, SuperMatrix*, int*, int*, + SuperMatrix*); +extern void superlu_abort_and_exit(char*); +extern void *superlu_malloc (size_t); +extern int *intMalloc (int); +extern int *intCalloc (int); +extern void superlu_free (void*); +extern void SetIWork (int, int, int, int *, int **, int **, int **, + int **, int **, int **, int **); +extern int sp_coletree (int *, int *, int *, int, int, int *); +extern void relax_snode (const int, int *, const int, int *, int *); +extern void heap_relax_snode (const int, int *, const int, int *, int *); +extern void resetrep_col (const int, const int *, int *); +extern int spcoletree (int *, int *, int *, int, int, int *); +extern int *TreePostorder (int, int *); +extern double SuperLU_timer_ (); +extern int sp_ienv (int); +extern int lsame_ (char *, char *); +extern int xerbla_ (char *, int *); +extern void ifill (int *, int, int); +extern void snode_profile (int, int *); +extern void super_stats (int, int *); +extern void PrintSumm (char *, int, int, int); +extern void StatInit(SuperLUStat_t *); +extern void StatPrint (SuperLUStat_t *); +extern void StatFree(SuperLUStat_t *); +extern void print_panel_seg(int, int, int, int, int *, int *); +extern void check_repfnz(int, int, int, int *); + +#ifdef __cplusplus + } +#endif + +#endif /* __SUPERLU_UTIL */ diff --git a/intern/opennl/superlu/xerbla.c b/intern/opennl/superlu/xerbla.c new file mode 100644 index 00000000000..68cef9d84e4 --- /dev/null +++ b/intern/opennl/superlu/xerbla.c @@ -0,0 +1,44 @@ + +#include +int xerbla_(char *, int *); + +/* Subroutine */ int xerbla_(char *srname, int *info) +{ +/* -- LAPACK auxiliary routine (version 2.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 + + + Purpose + ======= + + XERBLA is an error handler for the LAPACK routines. + It is called by an LAPACK routine if an input parameter has an + invalid value. A message is printed and execution stops. + + Installers may consider modifying the STOP statement in order to + call system-specific exception-handling facilities. + + Arguments + ========= + + SRNAME (input) CHARACTER*6 + The name of the routine which called XERBLA. + + INFO (input) INT + The position of the invalid parameter in the parameter list + + of the calling routine. + + ===================================================================== +*/ + + printf("** On entry to %6s, parameter number %2d had an illegal value\n", + srname, *info); + +/* End of XERBLA */ + + return 0; +} /* xerbla_ */ + diff --git a/intern/string/CMakeLists.txt b/intern/string/CMakeLists.txt new file mode 100644 index 00000000000..bee946d3c15 --- /dev/null +++ b/intern/string/CMakeLists.txt @@ -0,0 +1,35 @@ +# $Id$ +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +SET(INC .) + +FILE(GLOB SRC intern/*.cpp) + +BLENDERLIB(bf_string "${SRC}" "${INC}") +#, libtype=['core', 'player'], priority = [30,10] ) diff --git a/intern/string/Makefile b/intern/string/Makefile new file mode 100644 index 00000000000..e3dffbe9e44 --- /dev/null +++ b/intern/string/Makefile @@ -0,0 +1,56 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Hans Lambermont +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# string main makefile. +# + +include nan_definitions.mk + +LIBNAME = string +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +# not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_STRING) ] || mkdir $(NAN_STRING) + @[ -d $(NAN_STRING)/include ] || mkdir $(NAN_STRING)/include + @[ -d $(NAN_STRING)/lib ] || mkdir $(NAN_STRING)/lib + @[ -d $(NAN_STRING)/lib/debug ] || mkdir $(NAN_STRING)/lib/debug + @../tools/cpifdiff.sh $(DIR)/libstring.a $(NAN_STRING)/lib/ + @../tools/cpifdiff.sh $(DIR)/debug/libstring.a $(NAN_STRING)/lib/debug/ +ifeq ($(OS),darwin) + ranlib $(NAN_STRING)/lib/libstring.a + ranlib $(NAN_STRING)/lib/debug/libstring.a +endif + @../tools/cpifdiff.sh *.h $(NAN_STRING)/include/ + diff --git a/intern/string/SConscript b/intern/string/SConscript new file mode 100644 index 00000000000..7f817f82759 --- /dev/null +++ b/intern/string/SConscript @@ -0,0 +1,7 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('intern/*.cpp') +incs = '.' + +env.BlenderLib ('bf_string', sources, Split(incs), [], libtype=['core', 'player'], priority = [30,10] ) diff --git a/intern/string/STR_HashedString.h b/intern/string/STR_HashedString.h new file mode 100644 index 00000000000..bf18a4e4da6 --- /dev/null +++ b/intern/string/STR_HashedString.h @@ -0,0 +1,154 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * This file was formerly known as: GEN_StdString.cpp. + * @date November, 14, 2001 + */ + +#ifndef __STR_HASHSTRING +#define __STR_HASHSTRING + +#include "STR_String.h" + + +// Hash Mix utility function, by Bob Jenkins - Mix 3 32-bit values reversibly +// +// - If gHashMix() is run forward or backward, at least 32 bits in a,b,c have at +// least 1/4 probability of changing. +// +// - If gHashMix() is run forward, every bit of c will change between 1/3 and +// 2/3 of the time. +// +static inline void STR_gHashMix(dword& a, dword& b, dword& c) +{ + a -= b; a -= c; a ^= (c>>13); + b -= c; b -= a; b ^= (a<<8); + c -= a; c -= b; c ^= (b>>13); + a -= b; a -= c; a ^= (c>>12); + b -= c; b -= a; b ^= (a<<16); + c -= a; c -= b; c ^= (b>>5); + a -= b; a -= c; a ^= (c>>3); + b -= c; b -= a; b ^= (a<<10); + c -= a; c -= b; c ^= (b>>15); +} + +// +// Fast Hashable functionality +// http://www.concentric.net/~Ttwang/tech/inthash.htm +// +static inline dword STR_gHash(dword inDWord) +{ + dword key = inDWord; + key += ~(key << 16); + key ^= (key >> 5); + key += (key << 3); + key ^= (key >> 13); + key += ~(key << 9); + key ^= (key >> 17); + return key; +} + +enum { GOLDEN_RATIO = 0x9e3779b9 }; // arbitrary value to initialize hash funtion, well not so arbitrary + // as this value is taken from the pigs library (Orange Games/Lost Boys) + + + +static dword STR_gHash(const void* in, int len, dword init_val) +{ + unsigned int length = len; + dword a = (dword)GOLDEN_RATIO; + dword b = (dword)GOLDEN_RATIO; + dword c = init_val; // the previous hash value + byte *p_in = (byte *)in; + + // Do the largest part of the key + while (length >= 12) + { + a += (p_in[0] + ((dword)p_in[1]<<8) + ((dword)p_in[2] <<16) + ((dword)p_in[3] <<24)); + b += (p_in[4] + ((dword)p_in[5]<<8) + ((dword)p_in[6] <<16) + ((dword)p_in[7] <<24)); + c += (p_in[8] + ((dword)p_in[9]<<8) + ((dword)p_in[10]<<16) + ((dword)p_in[11]<<24)); + STR_gHashMix(a, b, c); + p_in += 12; length -= 12; + } + + // Handle the last 11 bytes + c += len; + switch(length) { + case 11: c+=((dword)p_in[10]<<24); + case 10: c+=((dword)p_in[9]<<16); + case 9 : c+=((dword)p_in[8]<<8); // the first byte of c is reserved for the length + case 8 : b+=((dword)p_in[7]<<24); + case 7 : b+=((dword)p_in[6]<<16); + case 6 : b+=((dword)p_in[5]<<8); + case 5 : b+=p_in[4]; + case 4 : a+=((dword)p_in[3]<<24); + case 3 : a+=((dword)p_in[2]<<16); + case 2 : a+=((dword)p_in[1]<<8); + case 1 : a+=p_in[0]; + } + STR_gHashMix(a, b, c); + + return c; +} + + + + +class STR_HashedString : public STR_String +{ +public: + STR_HashedString() : STR_String(),m_Hashed(false) {} + STR_HashedString(const char* str) : STR_String(str),m_Hashed(false) {} + STR_HashedString(const STR_String& str) : STR_String(str),m_Hashed(false) {} + + inline dword hash(dword init=0) const + { + if (!m_Hashed) + { + const char* str = *this; + int length = this->Length(); + m_CachedHash = STR_gHash(str,length,init); + m_Hashed=true; + } + return m_CachedHash; + } + +private: + mutable bool m_Hashed; + mutable dword m_CachedHash; +}; + +#endif //__STR_HASHSTRING + diff --git a/intern/string/STR_String.h b/intern/string/STR_String.h new file mode 100644 index 00000000000..2da2b57c6f2 --- /dev/null +++ b/intern/string/STR_String.h @@ -0,0 +1,203 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * This file was formerly known as: GEN_StdString.h. + * @date April, 25, 2001 + */ + +#ifndef _STR_String_H_ +#define _STR_String_H_ + +#ifndef STR_NO_ASSERTD +#undef assertd +#define assertd(exp) ((void)NULL) +#endif + +#include +#include +using namespace std; + + +class STR_String; + +typedef unsigned long dword; +typedef const STR_String& rcSTR_String; +typedef unsigned char byte; + +/** + * Smart String Value class. Is used by parser when an expression tree is build containing string. +*/ + +class STR_String +{ +public: + // Initialization + STR_String(); + STR_String(char c); + STR_String(char c, int len); + STR_String(const char *str); + STR_String(const char *str, int len); + STR_String(const STR_String &str); + STR_String(const STR_String & str, int len); + STR_String(const char *src1, int src1_len, const char *src2, int src2_len); + explicit STR_String(int val); + explicit STR_String(dword val); + explicit STR_String(float val); + explicit STR_String(double val); + inline ~STR_String() { delete[] pData; } + + // Operations + STR_String& Format(const char *fmt, ...); // Set formatted text to string + STR_String& FormatAdd(const char *fmt, ...); // Add formatted text to string + inline void Clear() { Len = pData[0] = 0; } + inline const STR_String & Reverse() + { + for (int i1=0, i2=Len-1; i1 Explode(char c) const; + + // Formatting + STR_String& Upper(); + STR_String& Lower(); + STR_String& Capitalize(); + STR_String& TrimLeft(); + STR_String& TrimLeft(char *set); + STR_String& TrimRight(); + STR_String& TrimRight(char *set); + STR_String& Trim(); + STR_String& Trim(char *set); + STR_String& TrimQuotes(); + + // Conversions +// inline operator char*() { return pData; } + inline operator const char *() const { return pData; } + inline char *Ptr() { return pData; } + inline const char *ReadPtr() const { return pData; } + inline float ToFloat() const { float x=atof(pData); return x; } + inline int ToInt() const { return atoi(pData); } + + // Operators + inline rcSTR_String operator=(const byte *rhs) { return Copy((const char *)rhs, strlen((const char *)rhs)); } + inline rcSTR_String operator=(rcSTR_String rhs) { return Copy(rhs.ReadPtr(), rhs.Length()); } + inline rcSTR_String operator=(char rhs) { return Copy(&rhs, 1); } + inline rcSTR_String operator=(const char *rhs) { return Copy(rhs, strlen(rhs)); } + + inline rcSTR_String operator+=(const char *rhs) { return Concat(rhs, strlen(rhs)); } + inline rcSTR_String operator+=(rcSTR_String rhs) { return Concat(rhs.ReadPtr(), rhs.Length()); } + inline rcSTR_String operator+=(char rhs) { return Concat(&rhs, 1); } + + + inline friend bool operator<(rcSTR_String lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)<0); } + inline friend bool operator<(rcSTR_String lhs, const char *rhs) { return (strcmp(lhs, rhs)<0); }; + inline friend bool operator<(const char *lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)<0); } + inline friend bool operator>(rcSTR_String lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)>0); } + inline friend bool operator>(rcSTR_String lhs, const char *rhs) { return (strcmp(lhs, rhs)>0); } + inline friend bool operator>(const char *lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)>0); } + inline friend bool operator<=(rcSTR_String lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)<=0); } + inline friend bool operator<=(rcSTR_String lhs, const char *rhs) { return (strcmp(lhs, rhs)<=0); } + inline friend bool operator<=(const char *lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)<=0); } + inline friend bool operator>=(rcSTR_String lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)>=0); } + inline friend bool operator>=(rcSTR_String lhs, const char *rhs) { return (strcmp(lhs, rhs)>=0); } + inline friend bool operator>=(const char *lhs, rcSTR_String rhs) { return (strcmp(lhs, rhs)>=0); } + inline friend bool operator==(rcSTR_String lhs, rcSTR_String rhs) { return ((lhs.Length() == rhs.Length()) && (memcmp(lhs, rhs, lhs.Length())==0)); } + inline friend bool operator==(rcSTR_String lhs, const char *rhs) { return (memcmp(lhs, rhs, lhs.Length()+1)==0); } + inline friend bool operator==(const char *lhs, rcSTR_String rhs) { return (memcmp(lhs, rhs, rhs.Length()+1)==0); } + inline friend bool operator!=(rcSTR_String lhs, rcSTR_String rhs) { return ((lhs.Length() != rhs.Length()) || (memcmp(lhs, rhs, lhs.Length())!=0)); } + inline friend bool operator!=(rcSTR_String lhs, const char *rhs) { return (memcmp(lhs, rhs, lhs.Length()+1)!=0); } + inline friend bool operator!=(const char *lhs, rcSTR_String rhs) { return (memcmp(lhs, rhs, rhs.Length()+1)!=0); } + + // serializing + //int Serialize(pCStream stream); + +protected: + // Implementation + void AllocBuffer(int len, bool keep_contents); + rcSTR_String Copy(const char *src, int len); + rcSTR_String Concat(const char *data, int len); + + static bool isLower(char c) { return !isUpper(c); } + static bool isUpper(char c) { return (c>='A') && (c <= 'Z'); } + static bool isSpace(char c) { return (c==' ') || (c=='\t'); } + + char *pData; // -> STR_String data + int Len; // Data length + int Max; // Space in data buffer +}; + +inline STR_String operator+(rcSTR_String lhs, rcSTR_String rhs) { return STR_String(lhs.ReadPtr(), lhs.Length(), rhs.ReadPtr(), rhs.Length()); } +inline STR_String operator+(rcSTR_String lhs, char rhs) { return STR_String(lhs.ReadPtr(), lhs.Length(), &rhs, 1); } +inline STR_String operator+(char lhs, rcSTR_String rhs) { return STR_String(&lhs, 1, rhs.ReadPtr(), rhs.Length()); } +inline STR_String operator+(rcSTR_String lhs, const char *rhs) { return STR_String(lhs.ReadPtr(), lhs.Length(), rhs, strlen(rhs)); } +inline STR_String operator+(const char *lhs, rcSTR_String rhs) { return STR_String(lhs, strlen(lhs), rhs.ReadPtr(), rhs.Length()); } + + +#endif //_STR_String_H_ + diff --git a/intern/string/intern/Makefile b/intern/string/intern/Makefile new file mode 100644 index 00000000000..925cdfed54a --- /dev/null +++ b/intern/string/intern/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# string intern Makefile +# + +LIBNAME = string +DIR = $(OCGDIR)/intern/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I.. + diff --git a/intern/string/intern/STR_String.cpp b/intern/string/intern/STR_String.cpp new file mode 100644 index 00000000000..af8f0d11445 --- /dev/null +++ b/intern/string/intern/STR_String.cpp @@ -0,0 +1,746 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * This file was formerly known as: GEN_StdString.cpp. + * @date April, 25, 2001 + */ + +#include +#include +#include +#include +#include +#include "STR_String.h" + +/*------------------------------------------------------------------------------------------------- + Construction / destruction +-------------------------------------------------------------------------------------------------*/ + + + +// +// Construct an empty string +// +STR_String::STR_String() : + pData(new char [32]), + Len(0), + Max(32) +{ + pData[0] = 0; +} + + + +// +// Construct a string of one character +// +STR_String::STR_String(char c) : + pData(new char [9]), + Len(1), + Max(9) +{ + pData[0] = c; + pData[1] = 0; +} + + + +// +// Construct a string of multiple repeating characters +// +STR_String::STR_String(char c, int len) : + pData(new char [len+8]), + Len(len), + Max(len+8) +{ + assertd(pData != NULL); + memset(pData, c, len); + pData[len] = 0; +} + + + +// +// Construct a string from a pointer-to-ASCIIZ-string +// +// MAART: Changed to test for null strings +STR_String::STR_String(const char *str) +{ + if (str) { + Len = ::strlen(str); + Max = Len + 8; + pData = new char [Max]; + assertd(pData != NULL); + ::memcpy(pData, str, Len); + pData[Len] = 0; + } + else { + pData = 0; + Len = 0; + Max = 8; + } +} + + + +// +// Construct a string from a pointer-to-ASCII-string and a length +// +STR_String::STR_String(const char *str, int len) : + pData(new char [len+8]), + Len(len), + Max(len+8) +{ + assertd(pData != NULL); + memcpy(pData, str, len); + pData[len] = 0; +} + + + +// +// Construct a string from another string +// +STR_String::STR_String(rcSTR_String str) : + pData(new char [str.Length()+8]), + Len(str.Length()), + Max(str.Length()+8) +{ + assertd(pData != NULL); + assertd(str.pData != NULL); + memcpy(pData, str.pData, str.Length()); + pData[str.Length()] = 0; +} + + + +// +// Construct a string from the first number of characters in another string +// +STR_String::STR_String(rcSTR_String str, int len) : + pData(new char [len+8]), + Len(len), + Max(len+8) +{ + assertd(pData != NULL); + assertd(str.pData != NULL); + memcpy(pData, str.pData, str.Length()); + pData[str.Length()] = 0; +} + + + +// +// Create a string by concatenating two sources +// +STR_String::STR_String(const char *src1, int len1, const char *src2, int len2) : + pData(new char [len1+len2+8]), + Len(len1+len2), + Max(len1+len2+8) +{ + assertd(pData != NULL); + memcpy(pData, src1, len1); + memcpy(pData+len1, src2, len2); + pData[len1+len2] = 0; +} + + + +// +// Create a string with an integer value +// +STR_String::STR_String(int val) : + pData(new char [32]), + Max(32) +{ + assertd(pData != NULL); + Len=sprintf(pData, "%d", val); +} + + + + +// +// Create a string with a dword value +// +STR_String::STR_String(dword val) : + pData(new char [32]), + Max(32) +{ + assertd(pData != NULL); + Len=sprintf(pData, "%lu", val); +} + + + +// +// Create a string with a floating point value +// +STR_String::STR_String(float val) : + pData(new char [32]), + Max(32) +{ + assertd(pData != NULL); + Len=sprintf(pData, "%g", val); +} + + + +// +// Create a string with a double value +// +STR_String::STR_String(double val) : + pData(new char [32]), + Max(32) +{ + assertd(pData != NULL); + Len=sprintf(pData, "%g", val); +} + + + +/*------------------------------------------------------------------------------------------------- + Buffer management +-------------------------------------------------------------------------------------------------*/ + + + +// +// Make sure that the allocated buffer is at least in size +// +void STR_String::AllocBuffer(int len, bool keep_contents) +{ + // Check if we have enough space + if (len+1 <= Max) return; + + // Reallocate string + char *new_data = new char [len+8]; + if (keep_contents) memcpy(new_data, pData, Len); + delete[] pData; + + // Accept new data + Max = len+8; + pData = new_data; + assertd(pData != NULL); +} + + + +/*------------------------------------------------------------------------------------------------- + Basic string operations +-------------------------------------------------------------------------------------------------*/ + + + +// +// Format string (as does sprintf) +// +STR_String& STR_String::Format(const char *fmt, ...) +{ + AllocBuffer(2048, false); + + assertd(pData != NULL); + // Expand arguments and format to string + va_list args; + va_start(args, fmt); + Len = vsprintf(pData, fmt, args); + assertd(Len <= 2048); + va_end(args); + + return *this; +} + + + +// +// Format string (as does sprintf) +// +STR_String& STR_String::FormatAdd(const char *fmt, ...) +{ + AllocBuffer(2048, false); + + assertd(pData != NULL); + // Expand arguments and format to string + va_list args; + va_start(args, fmt); + Len += vsprintf(pData+Len, fmt, args); + assertd(Len <= 2048); + va_end(args); + + return *this; +} + + + +/*------------------------------------------------------------------------------------------------- + Properties +-------------------------------------------------------------------------------------------------*/ + + + +// +// Check if string is entirely in UPPERCase +// +bool STR_String::IsUpper() const +{ + for (int i=0; i in the string +// +int STR_String::Find(char c, int pos) const +{ + assertd(pos >= 0); + assertd(Len==0 || pos in the string +// +int STR_String::Find(const char *str, int pos) const +{ + assertd(pos >= 0); + assertd(Len==0 || pos in the string +// +int STR_String::Find(rcSTR_String str, int pos) const +{ + assertd(pos >= 0); + assertd(Len==0 || pos in the string +// +int STR_String::RFind(char c) const +{ + assertd(pData != NULL); + char *pos = strrchr(pData, c); + return (pos) ? (pos-pData) : -1; +} + + + +// +// Find the first occurence of any character in character set in the string +// +int STR_String::FindOneOf(const char *set, int pos) const +{ + assertd(pos >= 0); + assertd(Len==0 || pos= 1); + + if (str.Length() < num) + { + // Remove some data from the string by replacement + memcpy(pData+pos+str.Length(), pData+pos+num, Len-pos-num+1); + memcpy(pData+pos, str.ReadPtr(), str.Length()); + } + else + { + // Insert zero or more characters into the string + AllocBuffer(Len + str.Length() - num, true); + if (str.Length() != num) memcpy(pData+pos+str.Length(), pData+pos+num, Length()-pos-num+1); + memcpy(pData+pos, str.ReadPtr(), str.Length()); + } + + Len += str.Length()-num; +} + + + +/*------------------------------------------------------------------------------------------------- + Comparison +-------------------------------------------------------------------------------------------------*/ + + + +// +// Compare two strings and return the result, <0 if *this0 if *this>rhs or 0 if *this==rhs +// +int STR_String::Compare(rcSTR_String rhs) const +{ + return strcmp(pData, rhs.pData); +} + + + +// +// Compare two strings without respecting case and return the result, <0 if *this0 if *this>rhs or 0 if *this==rhs +// +int STR_String::CompareNoCase(rcSTR_String rhs) const +{ +#ifdef WIN32 + return stricmp(pData, rhs.pData); +#else + return strcasecmp(pData, rhs.pData); +#endif +} + + + +/*------------------------------------------------------------------------------------------------- + Formatting +-------------------------------------------------------------------------------------------------*/ + + + +// +// Capitalize string, "heLLo" -> "HELLO" +// +STR_String& STR_String::Upper() +{ + assertd(pData != NULL); +#ifdef WIN32 + _strupr(pData); +#else + for (int i=0;i= 'a' && pData[i] <= 'z')?pData[i]+'A'-'a':pData[i]; +#endif + return *this; +} + + + +// +// Lower string, "heLLo" -> "hello" +// +STR_String& STR_String::Lower() +{ + assertd(pData != NULL); +#ifdef WIN32 + _strlwr(pData); +#else + for (int i=0;i= 'A' && pData[i] <= 'Z')?pData[i]+'a'-'A':pData[i]; +#endif + return *this; +} + + + +// +// Capitalize string, "heLLo" -> "Hello" +// +STR_String& STR_String::Capitalize() +{ + assertd(pData != NULL); +#ifdef WIN32 + if (Len>0) pData[0] = toupper(pData[0]); + if (Len>1) _strlwr(pData+1); +#else + if (Len > 0) + pData[0] = (pData[0] >= 'A' && pData[0] <= 'A')?pData[0]+'a'-'A':pData[0]; + for (int i=1;i= 'a' && pData[i] <= 'z')?pData[i]+'A'-'a':pData[i]; +#endif + return *this; +} + + + +// +// Trim whitespace from the left side of the string +// +STR_String& STR_String::TrimLeft() +{ + int skip; + assertd(pData != NULL); + for (skip=0; isSpace(pData[skip]); skip++, Len--); + memmove(pData, pData+skip, Len+1); + return *this; +} + + + +// +// Trim whitespaces from the right side of the string +// +STR_String& STR_String::TrimRight() +{ + assertd(pData != NULL); + while (Len && isSpace(pData[Len-1])) Len--; + pData[Len]=0; + return *this; +} + + + +// +// Trim spaces from both sides of the character set +// +STR_String& STR_String::Trim() +{ + TrimRight(); + TrimLeft(); + return *this; +} + + + +// +// Trim characters from the character set from the left side of the string +// +STR_String& STR_String::TrimLeft(char *set) +{ + int skip; + assertd(pData != NULL); + for (skip=0; Len && strchr(set, pData[skip]); skip++, Len--); + memmove(pData, pData+skip, Len+1); + return *this; +} + + + +// +// Trim characters from the character set from the right side of the string +// +STR_String& STR_String::TrimRight(char *set) +{ + assertd(pData != NULL); + while (Len && strchr(set, pData[Len-1])) Len--; + pData[Len]=0; + return *this; +} + + + +// +// Trim characters from the character set from both sides of the character set +// +STR_String& STR_String::Trim(char *set) +{ + TrimRight(set); + TrimLeft(set); + return *this; +} + + + +// +// Trim quotes from both sides of the string +// +STR_String& STR_String::TrimQuotes() +{ + // Trim quotes if they are on both sides of the string + assertd(pData != NULL); + if ((Len >= 2) && (pData[0] == '\"') && (pData[Len-1] == '\"')) + { + memmove(pData, pData+1, Len-2+1); + Len-=2; + } + return *this; +} + + + +/*------------------------------------------------------------------------------------------------- + Assignment/Concatenation +-------------------------------------------------------------------------------------------------*/ + + + +// +// Set the string's conents to a copy of with length +// +rcSTR_String STR_String::Copy(const char *src, int len) +{ + assertd(len>=0); + assertd(src); + assertd(pData != NULL); + + AllocBuffer(len, false); + Len = len; + memcpy(pData, src, len); + pData[Len] = 0; + + return *this; +} + + + +// +// Concate a number of bytes to the current string +// +rcSTR_String STR_String::Concat(const char *data, int len) +{ + assertd(Len>=0); + assertd(len>=0); + assertd(data); + assertd(pData != NULL); + + AllocBuffer(Len+len, true); + memcpy(pData+Len, data, len); + Len+=len; + pData[Len] = 0; + + return *this; +} + + + + + +vector STR_String::Explode(char c) const +{ + STR_String lcv = *this; + vector uc; + + while (lcv.Length()) + { + int pos = lcv.Find(c); + if (pos < 0) + { + uc.push_back(lcv); + lcv.Clear(); + } else + { + uc.push_back(lcv.Left(pos)); + lcv = lcv.Mid(pos+1); + } + } + + //uc. -= STR_String(""); + + return uc; +} + + +/* + +int STR_String::Serialize(pCStream stream) +{ + if (stream->GetAccess() == CStream::Access_Read) + { + int ln; + stream->Read(&ln, sizeof(ln)); + AllocBuffer(ln, false); + stream->Read(pData, ln); + pData[ln] = '\0'; + Len = ln; + } else + { + stream->Write(&Len, sizeof(Len)); + stream->Write(pData, Len); + } + + return Len + sizeof(Len); +} +*/ + diff --git a/intern/string/make/msvc_6_0/string.dsp b/intern/string/make/msvc_6_0/string.dsp new file mode 100644 index 00000000000..c6ac70e193a --- /dev/null +++ b/intern/string/make/msvc_6_0/string.dsp @@ -0,0 +1,122 @@ +# Microsoft Developer Studio Project File - Name="string" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=string - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "string.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "string.mak" CFG="string - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "string - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "string - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "string - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\intern\string" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\intern\string" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../.." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\intern\string\libstring.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\string\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\string\*.lib ..\..\..\..\..\lib\windows\string\lib\*.a ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "string - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../../../../obj/windows/intern/string/debug" +# PROP Intermediate_Dir "../../../../obj/windows/intern/string/debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../.." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../../../../obj/windows/intern/string/debug\libstring.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files XCOPY /Y ..\..\*.h ..\..\..\..\..\lib\windows\string\include\ ECHO Copying lib XCOPY /Y ..\..\..\..\obj\windows\intern\string\debug\*.lib ..\..\..\..\..\lib\windows\string\lib\debug\*.a ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "string - Win32 Release" +# Name "string - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\intern\STR_String.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "intern" + +# PROP Default_Filter "" +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\STR_HashedString.h +# End Source File +# Begin Source File + +SOURCE=..\..\STR_String.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/intern/string/make/msvc_6_0/string.dsw b/intern/string/make/msvc_6_0/string.dsw new file mode 100644 index 00000000000..b599b6407c5 --- /dev/null +++ b/intern/string/make/msvc_6_0/string.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "string"=".\string.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/string/make/msvc_7_0/string.sln b/intern/string/make/msvc_7_0/string.sln new file mode 100644 index 00000000000..53981b212ea --- /dev/null +++ b/intern/string/make/msvc_7_0/string.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string", "string.vcproj", "{0607A77B-49DD-42D8-A767-D0D60769DC90}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {0607A77B-49DD-42D8-A767-D0D60769DC90}.Debug.ActiveCfg = Debug|Win32 + {0607A77B-49DD-42D8-A767-D0D60769DC90}.Debug.Build.0 = Debug|Win32 + {0607A77B-49DD-42D8-A767-D0D60769DC90}.Release.ActiveCfg = Release|Win32 + {0607A77B-49DD-42D8-A767-D0D60769DC90}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/intern/string/make/msvc_7_0/string.vcproj b/intern/string/make/msvc_7_0/string.vcproj new file mode 100644 index 00000000000..deb342c26e8 --- /dev/null +++ b/intern/string/make/msvc_7_0/string.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/po/Makefile b/po/Makefile new file mode 100644 index 00000000000..b7288c0e64c --- /dev/null +++ b/po/Makefile @@ -0,0 +1,62 @@ +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2002 by Stichting Blender Foundation, +# Amsterdam, the Netherlands. +# All rights reserved. +# +# The Original Code is: revision 1.1 +# +# Contributor(s): Wouter van Heyst +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# po Makefile for blender. Compiles the translations and places them +# where release can pick them up. + +SOURCEDIR = blender/po + +include nan_definitions.mk + +ifeq ($(INTERNTIONAL),true) + LINGUAS = ar bg ca cs de es fr hr it ja nl pl pt_BR ro ru sr sr@Latn sv uk zh_CN +else + LINGUAS = +endif + +ifeq ($(OS), darwin) +DIR = $(OCGDIR)/bin/blender.app/Contents/Resources/locale/$@/LC_MESSAGES/ +else +DIR = $(OCGDIR)/bin/.blender/locale/$@/LC_MESSAGES/ +endif + +all debug:: $(LINGUAS) + +clean:: +ifeq ($(OS), darwin) + rm -rf $(OCGDIR)/bin/blender.app/Contents/Resources/locale/ +else + rm -rf $(OCGDIR)/bin/.blender/locale/ +endif + +$(LINGUAS): + mkdir -p $(DIR) + msgfmt -o $(DIR)/blender.mo $@.po diff --git a/projectfiles/blender/BLO_readblenfile/BLO_readblenfile.dsp b/projectfiles/blender/BLO_readblenfile/BLO_readblenfile.dsp new file mode 100644 index 00000000000..8e478f425d9 --- /dev/null +++ b/projectfiles/blender/BLO_readblenfile/BLO_readblenfile.dsp @@ -0,0 +1,155 @@ +# Microsoft Developer Studio Project File - Name="BLO_readblenfile" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BLO_readblenfile - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BLO_readblenfile.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BLO_readblenfile.mak" CFG="BLO_readblenfile - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BLO_readblenfile - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_readblenfile - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_readblenfile - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_readblenfile - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BLO_readblenfile - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\readblenfile" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\readblenfile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\blenloader\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_readblenfile - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\readblenfile\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\readblenfile\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\blender\readstreamglue\\" /I "..\..\..\source\blender\blenloader\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_readblenfile - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BLO_readblenfile___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BLO_readblenfile___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\readblenfile\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\readblenfile\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\blenloader\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_readblenfile - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BLO_readblenfile___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BLO_readblenfile___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\readblenfile\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\readblenfile\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\readstreamglue\\" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\source\blender\readstreamglue\\" /I "..\..\..\source\blender\blenloader\\" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readstreamglue" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BLO_readblenfile - Win32 Release" +# Name "BLO_readblenfile - Win32 Debug" +# Name "BLO_readblenfile - Win32 MT DLL Release" +# Name "BLO_readblenfile - Win32 MT DLL Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\readblenfile\intern\BLO_readblenfile.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\readblenfile\BLO_readblenfile.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/BPY_python/BPY_python.dsp b/projectfiles/blender/BPY_python/BPY_python.dsp new file mode 100644 index 00000000000..e122f0ffe90 --- /dev/null +++ b/projectfiles/blender/BPY_python/BPY_python.dsp @@ -0,0 +1,588 @@ +# Microsoft Developer Studio Project File - Name="BPY_python" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BPY_python - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BPY_python.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BPY_python.mak" CFG="BPY_python - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BPY_python - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BPY_python - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BPY_python - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\bpython" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\bpython" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\img" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\source\blender\misc" /I "..\..\..\lib\windows\guardedalloc\include" /I "..\..\source\blender\blenlib" /I "..\..\source\kernel\gen_messaging" /I "..\..\source\blender\include" /I "..\..\source\blender" /I "..\..\source\blender\makesdna" /I "..\..\source\blender\blenkernel" /I "..\..\source\blender\blenloader" /I "..\..\source\blender\bpython\include" /I "..\..\source\blender\imbuf" /I "..\..\source\blender\render\extern\include" /I "..\..\source\blender\radiosity\extern\include" /I "..\..\source\kernel\gen_system" /I "..\..\source\blender\renderconverter\\" /I "..\..\source\blender\renderui\\" /I "..\..\source\blender\python" /I "../../../../lib/windows/bsp/include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\bpython\include" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "..\..\..\source\blender\python" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BPY_python - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\bpython\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\bpython\debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /w /W0 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\img" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\source\blender\misc" /I "..\..\..\lib\windows\guardedalloc\include" /I "..\..\source\blender\blenlib" /I "..\..\source\kernel\gen_messaging" /I "..\..\source\blender\include" /I "..\..\source\blender" /I "..\..\source\blender\makesdna" /I "..\..\source\blender\blenkernel" /I "..\..\source\blender\blenloader" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\source\blender\bpython\include" /I "..\..\source\blender\imbuf" /I "..\..\source\blender\render\extern\include" /I "..\..\source\kernel\gen_system" /I "..\..\source\blender\renderconverter\\" /I "..\..\source\blender\renderui\\" /I "..\..\source\blender\python" /I "../../../../lib/windows/bsp/include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\bpython\include" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "..\..\..\source\blender\python" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BPY_python - Win32 Release" +# Name "BPY_python - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Armature.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\BezTriple.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\BGL.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Blender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Bone.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\BPY_interface.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\BPY_menus.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Camera.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\charRGBA.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\constant.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Constraint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\CurNurb.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Curve.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Draw.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Effect.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\euler.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\EXPP_interface.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Font.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\gen_utils.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Geometry.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Group.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\IDProp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Image.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Ipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Ipocurve.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Key.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Lamp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Lattice.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Library.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\logic.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Material.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Mathutils.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\matrix.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Mesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\meshPrimitive.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Metaball.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Modifier.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\MTex.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\NLA.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\NMesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Noise.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Object.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Particle.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\point.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Pose.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\quat.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Registry.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\rgbTuple.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Scene.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneRadio.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneRender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneTimeLine.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Sound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\SurfNurb.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Sys.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Text.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Text3d.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Texture.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Types.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\vector.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Window.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\windowTheme.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\World.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Armature.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\BezTriple.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\BGL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Blender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Bone.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\BPY_extern.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\BPY_menus.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\bpy_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Camera.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\charRGBA.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\constant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Constraint.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\CurNurb.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Curve.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Draw.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Effect.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\euler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\EXPP_interface.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Font.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\gen_utils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Geometry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Group.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Image.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Ipo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Ipocurve.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Key.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Lamp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Lattice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Material.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Mathutils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\matrix.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Mesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\meshPrimitive.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Metaball.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Modifier.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\modules.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\MTex.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\NLA.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\NMesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Object.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Particle.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\point.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\quat.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\rgbTuple.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneRadio.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneRender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\sceneTimeLine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Sound.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\SurfNurb.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Sys.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Text.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Text3d.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Texture.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\vector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\Window.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\windowTheme.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\python\api2_2x\World.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/avi/BL_avi.dsp b/projectfiles/blender/avi/BL_avi.dsp new file mode 100644 index 00000000000..1237ddcec47 --- /dev/null +++ b/projectfiles/blender/avi/BL_avi.dsp @@ -0,0 +1,199 @@ +# Microsoft Developer Studio Project File - Name="BL_avi" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_avi - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BL_avi.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BL_avi.mak" CFG="BL_avi - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_avi - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_avi - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_avi - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_avi - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_avi - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\avi" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\avi" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_avi - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\avi\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\avi\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_avi - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BL_avi___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BL_avi___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\avi\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\avi\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\avi\debug\BL_avi.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_avi - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BL_avi___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BL_avi___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\avi\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\avi\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DWORDS_LITTLEENDIAN" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\avi\BL_avi.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BL_avi - Win32 Release" +# Name "BL_avi - Win32 Debug" +# Name "BL_avi - Win32 MT DLL Debug" +# Name "BL_avi - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\avi.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\avirgb.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\codecs.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\endian.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\mjpeg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\options.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\rgb32.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\AVI_avi.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\avi_intern.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\avirgb.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\endian.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\mjpeg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\avi\intern\rgb32.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/blender.dsp b/projectfiles/blender/blender.dsp new file mode 100644 index 00000000000..17cd7022d82 --- /dev/null +++ b/projectfiles/blender/blender.dsp @@ -0,0 +1,124 @@ +# Microsoft Developer Studio Project File - Name="blender" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=blender - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "blender.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "blender.mak" CFG="blender - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "blender - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "blender - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "blender - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\obj\windows\blender" +# PROP Intermediate_Dir "..\..\obj\windows\blender" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\source\blender\misc" /I "..\..\..\lib\windows\guardedalloc\include" /I "..\..\source\blender\blenlib" /I "..\..\source\kernel\gen_messaging" /I "..\..\source\blender\include" /I "..\..\source\blender" /I "..\..\source\blender\makesdna" /I "..\..\source\blender\blenkernel" /I "..\..\source\blender\blenloader" /I "..\..\source\blender\python" /I "..\..\source\blender\imbuf" /I "..\..\source\blender\render\extern\include" /I "..\..\source\blender\radiosity\extern\include" /I "..\..\source\kernel\gen_system" /I "..\..\source\blender\renderconverter\\" /I "..\..\source\blender\renderui\\" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WITH_QUICKTIME" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 solid.lib SDL.lib freetype2ST.lib ftgl_static_ST.lib gnu_gettext.lib qtmlClient.lib openal_static.lib libsoundsystem.a libopenalsoundsystem.lib libdummysoundsystem.lib libguardedalloc.a libbsp.a libbmfont.a libghost.a libstring.a ws2_32.lib dxguid.lib opengl32.lib libjpeg.a glu32.lib user32.lib shell32.lib gdi32.lib vfw32.lib advapi32.lib winmm.lib ole32.lib libdecimation.a libiksolver.a libpng.a zlib.lib libmoto.a blender_ONL.lib blender_elbeem.lib boolop.lib BLI_bullet.lib pthreadVC2.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcprt.lib" /nodefaultlib:"msvcrt.lib" /nodefaultlib:"glut32.lib" /nodefaultlib:"libcd.lib" /nodefaultlib:"libc.lib" /nodefaultlib:"libcpd.lib" /nodefaultlib:"libcp.lib" /nodefaultlib:"libcmtd.lib" /out:"..\..\bin\blender.exe" /libpath:"..\..\..\lib\windows\sdl\lib" /libpath:"..\..\..\lib\windows\freetype\lib" /libpath:"..\..\..\lib\windows\ftgl\lib" /libpath:"..\..\..\lib\windows\gettext\lib" /libpath:"..\..\..\lib\windows\ode\lib" /libpath:"..\..\..\lib\windows\bsp\lib" /libpath:"..\..\..\lib\windows\moto\lib" /libpath:"..\..\..\lib\windows\bmfont\lib" /libpath:"..\..\..\lib\windows\ghost\lib" /libpath:"..\..\..\lib\windows\python\frozen" /libpath:"..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\lib\windows\string\lib" /libpath:"..\..\..\lib\windows\solid\lib" /libpath:"..\..\..\lib\windows\python\lib" /libpath:"..\..\..\lib\windows\iksolver\lib" /libpath:"..\..\..\lib\windows\decimation\lib" /libpath:"..\..\..\lib\windows\openal\lib" /libpath:"..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\lib\windows\openssl\lib" /libpath:"..\..\obj\windows\intern\soundsystem\dummy" /libpath:"..\..\obj\windows\intern\soundsystem\openal" /libpath:"..\..\..\lib\windows\soundsystem\lib\\" /libpath:"..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\lib\windows\png\lib\\" /libpath:"..\..\..\lib\windows\opennl" /libpath:"..\..\..\lib\windows\elbeem\lib" /libpath:"..\..\..\lib\windows\boolop\lib" /libpath:"..\..\..\lib\windows\bullet\lib" /libpath:"..\..\..\lib\windows\pthreads\lib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying required 3rd party dlls... XCOPY /Y ..\..\..\lib\windows\gettext\lib\*.dll ..\..\bin\ XCOPY /Y ..\..\..\lib\windows\sdl\lib\*dll ..\..\bin\ ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "blender - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\obj\windows\blender\debug" +# PROP Intermediate_Dir "..\..\obj\windows\blender\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\source\blender\misc" /I "..\..\..\lib\windows\guardedalloc\include" /I "..\..\source\blender\blenlib" /I "..\..\source\kernel\gen_messaging" /I "..\..\source\blender\include" /I "..\..\source\blender" /I "..\..\source\blender\makesdna" /I "..\..\source\blender\blenkernel" /I "..\..\source\blender\blenloader" /I "..\..\source\blender\python" /I "..\..\source\blender\imbuf" /I "..\..\source\blender\render\extern\include" /I "..\..\source\blender\radiosity\extern\include" /I "..\..\source\kernel\gen_system" /I "..\..\source\blender\renderconverter\\" /I "..\..\source\blender\renderui" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WITH_QUICKTIME" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 solid.lib SDL.lib freetype2ST.lib ftgl_static_ST.lib gnu_gettext.lib qtmlClient.lib openal_static.lib libsoundsystem.a libopenalsoundsystem.lib libdummysoundsystem.lib libguardedalloc.a libbsp.a libbmfont.a libghost.a libstring.a ws2_32.lib dxguid.lib opengl32.lib libjpeg.a glu32.lib user32.lib gdi32.lib shell32.lib vfw32.lib advapi32.lib winmm.lib ole32.lib libdecimation.a libiksolver.a libpng.a zlib.lib libmoto.a blender_ONL.lib blender_elbeem.lib boolop.lib BLI_bullet_d.lib pthreadVC2.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"glut32.lib" /nodefaultlib:"libcd.lib" /nodefaultlib:"libc.lib" /nodefaultlib:"libcpd.lib" /nodefaultlib:"libcp.lib" /nodefaultlib:"libcmt.lib" /nodefaultlib:"libcpmtd.lib" /nodefaultlib:"msvcprtd.lib" /out:"..\..\bin\debug\blender.exe" /pdbtype:sept /libpath:"..\..\..\lib\windows\sdl\lib" /libpath:"..\..\..\lib\windows\freetype\lib" /libpath:"..\..\..\lib\windows\ftgl\lib" /libpath:"..\..\..\lib\windows\gettext\lib" /libpath:"..\..\..\lib\windows\ode\lib" /libpath:"..\..\..\lib\windows\bsp\lib\debug" /libpath:"..\..\..\lib\windows\moto\lib\debug" /libpath:"..\..\..\lib\windows\bmfont\lib\debug" /libpath:"..\..\..\lib\windows\ghost\lib\debug" /libpath:"..\..\..\lib\windows\python\frozen" /libpath:"..\..\..\lib\windows\guardedalloc\lib\debug" /libpath:"..\..\..\lib\windows\string\lib\debug" /libpath:"..\..\..\lib\windows\solid\lib\\" /libpath:"..\..\..\lib\windows\python\lib" /libpath:"..\..\..\lib\windows\iksolver\lib\debug" /libpath:"..\..\..\lib\windows\decimation\lib\debug" /libpath:"..\..\..\lib\windows\openal\lib" /libpath:"..\..\obj\windows\intern\soundsystem\dummy\debug" /libpath:"..\..\obj\windows\intern\soundsystem\openal\debug" /libpath:"..\..\..\lib\windows\soundsystem\lib\debug\\" /libpath:"..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\lib\windows\blenkey\lib\debug" /libpath:"..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\lib\windows\png\lib\\" /libpath:"..\..\..\lib\windows\opennl\debug" /libpath:"..\..\..\lib\windows\elbeem\lib\debug" /libpath:"..\..\..\lib\windows\boolop\lib" /libpath:"..\..\..\lib\windows\bullet\lib" /libpath:"..\..\..\lib\windows\elbeem\lib" /libpath:"..\..\..\lib\windows\pthreads\lib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying required 3rd party dlls... XCOPY /Y ..\..\..\lib\windows\gettext\lib\*.dll ..\..\bin\ ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "blender - Win32 Release" +# Name "blender - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\source\creator\creator.c +# End Source File +# Begin Source File + +SOURCE=..\..\source\icons\winblender.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\source\icons\winblender.ico +# End Source File +# Begin Source File + +SOURCE=..\..\source\icons\winblenderfile.ico +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/blender.dsw b/projectfiles/blender/blender.dsw new file mode 100644 index 00000000000..3a69055807e --- /dev/null +++ b/projectfiles/blender/blender.dsw @@ -0,0 +1,743 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BKE_blenkernel"=.\blenkernel\BKE_blenkernel.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BLI_blenlib"=.\blenlib\BLI_blenlib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BLO_loader"=.\loader\BLO_loader.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BLO_readblenfile"=.\BLO_readblenfile\BLO_readblenfile.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BL_avi"=.\avi\BL_avi.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BL_imbuf"=.\imbuf\BL_imbuf.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BL_src"=.\src\BL_src.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BL_src_cre"=.\src\BL_src_cre.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BPY_python"=.\BPY_python\BPY_python.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BRA_radiosity"=.\radiosity\BRA_radiosity.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BRE_render"=.\render\BRE_render.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name BRE_yafray + End Project Dependency +}}} + +############################################################################### + +Project: "BRE_renderconverter"=.\renderconverter\BRE_renderconverter.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BRE_yafray"=.\yafray\BRE_yafray.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "Bullet"=..\..\extern\bullet\Bullet\BLI_Bullet.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "BulletDynamics"=..\..\extern\bullet\BulletDynamics\BLI_BulletDynamics.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "DNA_makesdna"=.\makesdna\DNA_makesdna.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "EXP_expressions"=..\gameengine\expression\EXP_expressions.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "FTF_ftfont"=.\ftfont\FTF_ftfont.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "GP_axctl"=..\gameengine\gameplayer\axctl\GP_axctl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name KX_converter + End Project Dependency + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_ketsji + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency + Begin Project Dependency + Project_Dep_Name GP_common + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name DNA_makesdna + End Project Dependency + Begin Project Dependency + Project_Dep_Name gen_messaging + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_verify + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_decrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_loader + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_readblenfile + End Project Dependency + Begin Project Dependency + Project_Dep_Name BKE_blenkernel + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_avi + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_imbuf + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLI_blenlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_OpenAL + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Physics + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Ode + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Dummy + End Project Dependency +}}} + +############################################################################### + +Project: "GP_common"=..\gameengine\gameplayer\common\GP_common.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "GP_ghost"=..\gameengine\gameplayer\ghost\GP_ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name BKE_blenkernel + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_avi + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_imbuf + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLI_blenlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_loader + End Project Dependency + Begin Project Dependency + Project_Dep_Name DNA_makesdna + End Project Dependency + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_converter + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_ketsji + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency + Begin Project Dependency + Project_Dep_Name gen_messaging + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_readblenfile + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_decrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_verify + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_OpenAL + End Project Dependency + Begin Project Dependency + Project_Dep_Name GP_common + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Physics + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Dummy + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Sumo + End Project Dependency +}}} + +############################################################################### + +Project: "KX_blenderhook"=..\gameengine\blenderhook\KX_blenderhook.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_converter"=..\gameengine\converter\KX_converter.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_ketsji"=..\gameengine\ketsji\KX_ketsji.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_network"=..\gameengine\ketsji\network\KX_network.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "NG_loopbacknetwork"=..\gameengine\network\loopbacknetwork\NG_loopbacknetwork.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "NG_network"=..\gameengine\network\network\NG_network.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PHY_Dummy"=..\GAMEENGINE\PHYSICS\PHY_PHYSICS\PHY_Dummy\PHY_Dummy.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PHY_Ode"=..\gameengine\physics\PHY_Physics\PHY_Ode\PHY_Ode.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PHY_Physics"=..\gameengine\physics\PHY_Physics\PHY_Physics.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "PHY_Sumo"=..\gameengine\physics\PHY_Physics\PHY_Sumo\PHY_Sumo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "RAS_openglrasterizer"=..\gameengine\rasterizer\openglrasterizer\RAS_openglrasterizer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "RAS_rasterizer"=..\gameengine\rasterizer\RAS_rasterizer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SCA_GameLogic"=..\gameengine\gamelogic\SCA_GameLogic.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SG_SceneGraph"=..\gameengine\scenegraph\SG_SceneGraph.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SYS_system"=..\kernel\system\SYS_system.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "blender"=.\blender.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name BKE_blenkernel + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_avi + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_imbuf + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLI_blenlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_decrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_encrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_loader + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_sign + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_verify + End Project Dependency + Begin Project Dependency + Project_Dep_Name BRA_radiosity + End Project Dependency + Begin Project Dependency + Project_Dep_Name BRE_render + End Project Dependency + Begin Project Dependency + Project_Dep_Name DNA_makesdna + End Project Dependency + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name gen_messaging + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_src_pub + End Project Dependency + Begin Project Dependency + Project_Dep_Name blenpluginapi + End Project Dependency + Begin Project Dependency + Project_Dep_Name BL_src + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_OpenAL + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Dummy + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Physics + End Project Dependency + Begin Project Dependency + Project_Dep_Name FTF_ftfont + End Project Dependency + Begin Project Dependency + Project_Dep_Name BPY_python + End Project Dependency + Begin Project Dependency + Project_Dep_Name PHY_Sumo + End Project Dependency + Begin Project Dependency + Project_Dep_Name BLO_readblenfile + End Project Dependency + Begin Project Dependency + Project_Dep_Name Bullet + End Project Dependency + Begin Project Dependency + Project_Dep_Name BulletDynamics + End Project Dependency +}}} + +############################################################################### + +Project: "blenpluginapi"=.\blenpluginapi\blenpluginapi\blenpluginapi.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gen_messaging"=..\KERNEL\gen_messaging\gen_messaging.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/projectfiles/blender/blenkernel/BKE_blenkernel.dsp b/projectfiles/blender/blenkernel/BKE_blenkernel.dsp new file mode 100644 index 00000000000..171bfab7dad --- /dev/null +++ b/projectfiles/blender/blenkernel/BKE_blenkernel.dsp @@ -0,0 +1,564 @@ +# Microsoft Developer Studio Project File - Name="BKE_blenkernel" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BKE_blenkernel - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BKE_blenkernel.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BKE_blenkernel.mak" CFG="BKE_blenkernel - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BKE_blenkernel - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BKE_blenkernel - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BKE_blenkernel - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BKE_blenkernel - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BKE_blenkernel - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenkernel" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenkernel" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\decimation\include" /I "../../../../lib/windows/zlib/include" /I "..\..\..\intern\elbeem\extern" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "../../../../lib/windows/bsp/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_FREETYPE2" /D "USE_CCGSUBSURFLIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BKE_blenkernel - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenkernel\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenkernel\debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\decimation\include" /I "../../../../lib/windows/zlib/include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "../../../../lib/windows/bsp/include" /I "..\..\..\intern\elbeem\extern" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_FREETYPE2" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BKE_blenkernel - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BKE_blenkernel___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BKE_blenkernel___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenkernel\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenkernel\mtdll_debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT BASE CPP /WX +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\blenloader" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "../../../../lib/windows/bsp/include" /I "..\..\..\intern\elbeem\extern" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /WX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\blenkernel\debug\BKE_blenkernel.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BKE_blenkernel - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BKE_blenkernel___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BKE_blenkernel___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenkernel\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenkernel\mtdll" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenlib" /I "../../../source/gameengine\SoundSystem\\" /I "../../../../lib/windows/iksolver/include" /I "../../../../lib/windows/bsp/include" /I "..\..\..\intern\elbeem\extern" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\blenkernel\BKE_blenkernel.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BKE_blenkernel - Win32 Release" +# Name "BKE_blenkernel - Win32 Debug" +# Name "BKE_blenkernel - Win32 MT DLL Debug" +# Name "BKE_blenkernel - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\action.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\idprop.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\anim.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\armature.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\blender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\bmfont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\brush.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\CCGSubSurf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\cdderivedmesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\colortools.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\constraint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\curve.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\customdata.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\deform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\depsgraph.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\DerivedMesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\displist.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\effect.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\exotic.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\font.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\group.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\icons.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\image.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\ipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\key.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\lattice.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\library.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\material.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\mball.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\mesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\modifier.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\nla.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\node.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\node_composite.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\node_shaders.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\object.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\packedFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\property.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\sca.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\scene.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\screen.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\script.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\softbody.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\sound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\subsurf_ccg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\text.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\texture.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\world.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\writeavi.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\writeframeserver.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_action.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_anim.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_armature.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_bad_level_calls.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_blender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_bmfont.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_bmfont_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_booleanops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_booleanops_mesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_brush.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_cdderivedmesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_constraint.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_curve.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_customdata.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_deform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_depsgraph.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_DerivedMesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_displist.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_effect.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_endian.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_exotic.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_font.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_global.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_group.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_image.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_ipo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_key.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_lattice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_library.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_main.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_material.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_mball.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_mesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_modifier.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_nla.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_object.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_packedFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_plugin_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_property.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_sca.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_screen.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_script.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_softbody.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_sound.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_subsurf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_text.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_texture.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_utildefines.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_world.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\BKE_writeavi.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\intern\CCGSubSurf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenkernel\depsgraph_private.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/blenlib/BLI_blenlib.dsp b/projectfiles/blender/blenlib/BLI_blenlib.dsp new file mode 100644 index 00000000000..137725d3f7f --- /dev/null +++ b/projectfiles/blender/blenlib/BLI_blenlib.dsp @@ -0,0 +1,318 @@ +# Microsoft Developer Studio Project File - Name="BLI_blenlib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BLI_blenlib - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BLI_blenlib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BLI_blenlib.mak" CFG="BLI_blenlib - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BLI_blenlib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BLI_blenlib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLI_blenlib - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLI_blenlib - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BLI_blenlib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenlib" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenlib" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\lib\windows\freetype\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /I "../../../../lib/windows/zlib/include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_FREETYPE2" /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLI_blenlib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenlib\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenlib\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\lib\windows\freetype\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /I "../../../../lib/windows/zlib/include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_FREETYPE2" /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLI_blenlib - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BLI_blenlib___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BLI_blenlib___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenlib\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenlib\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\blenlib\debug\BLI_blenlib.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLI_blenlib - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BLI_blenlib___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BLI_blenlib___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\blenlib\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\blenlib\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\blenlib\BLI_blenlib.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BLI_blenlib - Win32 Release" +# Name "BLI_blenlib - Win32 Debug" +# Name "BLI_blenlib - Win32 MT DLL Debug" +# Name "BLI_blenlib - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\arithb.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_dynstr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_ghash.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_heap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_linklist.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_memarena.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\dynlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\edgehash.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\fileops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\freetypefont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\gsqueue.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\jitter.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\matrixops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\noise.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\psfont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\rand.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\rct.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\scanfill.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\storage.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\time.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\util.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\vectorops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\winstuff.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_arithb.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_blenlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_callbacks.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_edgehash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_editVert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_fileops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_ghash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_linklist.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_memarena.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_scanfill.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_storage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_storage_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\intern\BLI_util.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\BLI_winstuff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\MTC_matrixops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\MTC_vectorops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\PIL_dynlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenlib\PIL_time.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/blenpluginapi/blenpluginapi/blenpluginapi.dsp b/projectfiles/blender/blenpluginapi/blenpluginapi/blenpluginapi.dsp new file mode 100644 index 00000000000..6b219ffad19 --- /dev/null +++ b/projectfiles/blender/blenpluginapi/blenpluginapi/blenpluginapi.dsp @@ -0,0 +1,119 @@ +# Microsoft Developer Studio Project File - Name="blenpluginapi" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=blenpluginapi - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "blenpluginapi.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "blenpluginapi.mak" CFG="blenpluginapi - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "blenpluginapi - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "blenpluginapi - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "blenpluginapi - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\blender\blenpluginapi" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\blender\blenpluginapi" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\blender" /I "..\..\..\..\source\blender\blenpluginapi" /I "..\..\..\..\source\blender\blenlib" /I "..\..\..\..\source\blender\imbuf" /I "..\..\..\..\source\blender\makesdna" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\blender\blenpluginapi.lib" + +!ELSEIF "$(CFG)" == "blenpluginapi - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\blender\blenpluginapi\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\blender\blenpluginapi\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\blender" /I "..\..\..\..\source\blender\blenpluginapi" /I "..\..\..\..\source\blender\blenlib" /I "..\..\..\..\source\blender\imbuf" /I "..\..\..\..\source\blender\makesdna" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /X +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\blender\debug\blenpluginapi.lib" + +!ENDIF + +# Begin Target + +# Name "blenpluginapi - Win32 Release" +# Name "blenpluginapi - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\intern\pluginapi.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\documentation.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\floatpatch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\iff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\plugin.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenpluginapi\util.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/ftfont/FTF_ftfont.dsp b/projectfiles/blender/ftfont/FTF_ftfont.dsp new file mode 100644 index 00000000000..7ecd50aa75f --- /dev/null +++ b/projectfiles/blender/ftfont/FTF_ftfont.dsp @@ -0,0 +1,118 @@ +# Microsoft Developer Studio Project File - Name="FTF_ftfont" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=FTF_ftfont - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "FTF_ftfont.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "FTF_ftfont.mak" CFG="FTF_ftfont - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "FTF_ftfont - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "FTF_ftfont - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "FTF_ftfont - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\ftfont" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\ftfont" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../../source\blender\makesdna" /I "../../../source\blender\blenloader" /I "../../../source\blender\blenlib" /I "../../../../lib/windows/ftgl/include" /I "../../../../lib/windows/freetype/include" /I "../../../lib/windows/iconv/include" /I "../../../../lib/windows/gettext/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "WCHAR_T16" /D "HAVE_LC_MESSAGES" /YX /FD /c +# ADD BASE RSC /l 0x411 /d "NDEBUG" +# ADD RSC /l 0x411 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "FTF_ftfont - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\ftfont" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\ftfont" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../source\blender\blenlib" /I "../../../source\blender\makesdna" /I "../../../../lib/windows/ftgl/include" /I "../../../../lib/windows/freetype/include" /I "../../../lib/windows/iconv/include" /I "../../../../lib/windows/gettext/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "WCHAR_T16" /D "HAVE_LC_MESSAGES" /D "FTGL_LIBRARY_STATIC" /YX /FD /GZ /c +# ADD BASE RSC /l 0x411 /d "_DEBUG" +# ADD RSC /l 0x411 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "FTF_ftfont - Win32 Release" +# Name "FTF_ftfont - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\intern\FTF_Api.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\intern\FTF_TTFont.cpp +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\FTF_Api.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\FTF_Settings.h +# End Source File +# End Group +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\blender\ftfont\intern\FTF_TTFont.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/glut/BL_glut.dsp b/projectfiles/blender/glut/BL_glut.dsp new file mode 100644 index 00000000000..2e351603e67 --- /dev/null +++ b/projectfiles/blender/glut/BL_glut.dsp @@ -0,0 +1,324 @@ +# Microsoft Developer Studio Project File - Name="BL_glut" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_glut - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BL_glut.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BL_glut.mak" CFG="BL_glut - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_glut - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_glut - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_glut - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_glut - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\blender\glut" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\source\blender\\" /I "..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\source\blender\glut-win" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\blender\glut\BL_glut.lib" + +!ELSEIF "$(CFG)" == "BL_glut - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\blender\glut\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\source\blender\glut-win" /I "..\..\..\source\blender\\" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\blender\glut\debug\BL_glut.lib" + +!ELSEIF "$(CFG)" == "BL_glut - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BL_glut___Win32_Profile" +# PROP BASE Intermediate_Dir "BL_glut___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "BL_glut___Win32_Profile" +# PROP Intermediate_Dir "BL_glut___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\source\blender\glut-win" /I "..\..\..\source\blender\\" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\source\blender\glut-win" /I "..\..\..\source\blender\\" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\obj\windows\blender\glut\debug\BL_glut.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\blender\glut\profile\BL_glut.lib" + +!ENDIF + +# Begin Target + +# Name "BL_glut - Win32 Release" +# Name "BL_glut - Win32 Debug" +# Name "BL_glut - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_8x13.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_9x15.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_bitmap.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_blender.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_bwidth.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_cindex.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_cmap.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_cursor.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_dials.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_draw.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_dstr.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_event.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_ext.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_fullscrn.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_get.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_hel10.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_hel12.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_hel18.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_helb10.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_helb12.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_helb14.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_helb8.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_init.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_input.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_mesa.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_modifier.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_mroman.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_overlay.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_roman.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_scr12.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_scr14.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_scr15.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_shapes.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_space.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_stroke.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_swap.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_swidth.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_tablet.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_teapot.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_tr10.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_tr24.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_util.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_vidresize.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_warp.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_win.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\glut_winmisc.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\win32_glx.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\win32_menu.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\win32_util.c" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\blender\glut-win\win32_x11.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\glut\blenderglut.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/imbuf/BL_imbuf.dsp b/projectfiles/blender/imbuf/BL_imbuf.dsp new file mode 100644 index 00000000000..002426124b6 --- /dev/null +++ b/projectfiles/blender/imbuf/BL_imbuf.dsp @@ -0,0 +1,438 @@ +# Microsoft Developer Studio Project File - Name="BL_imbuf" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_imbuf - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BL_imbuf.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BL_imbuf.mak" CFG="BL_imbuf - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_imbuf - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_imbuf - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_imbuf - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_imbuf - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_imbuf - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\imbuf" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\imbuf" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\blender\imbuf\intern" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\..\lib\windows\png\include" /I "..\..\..\..\lib\windows\tiff\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_QUICKTIME" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_imbuf - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\imbuf\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\imbuf\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\blender\imbuf\intern" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\..\lib\windows\png\include" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\tiff\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_QUICKTIME" /YX /FD /I /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_imbuf - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BL_imbuf___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BL_imbuf___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\imbuf\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\imbuf\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\blender\makesdna..\..\..\lib\windows\\" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\..\lib\windows\png\include" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\tiff\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\imbuf\debug\BL_imbuf.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_imbuf - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BL_imbuf___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BL_imbuf___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\imbuf\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\imbuf\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\source\blender\makesdna" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\blender\makesdna..\..\..\lib\windows\\" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\avi" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\include" /I "..\..\..\..\lib\windows\jpeg\include" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\..\lib\windows\png\include" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\tiff\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\imbuf\BL_imbuf.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BL_imbuf - Win32 Release" +# Name "BL_imbuf - Win32 Debug" +# Name "BL_imbuf - Win32 MT DLL Debug" +# Name "BL_imbuf - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\allocimbuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\amiga.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\anim.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\anim5.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\antialias.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\bitplanes.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\bmp.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cineon_dpx.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cineonlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cmap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cspace.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\data.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\dither.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\divers.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\dpxlib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\dynlibtiff.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\filter.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\ham.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\hamx.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\iff.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\imageprocess.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\iris.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\jpeg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logImageCore.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logImageLib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logmemfile.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\png.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\quicktime\apple\quicktime_export.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\quicktime\apple\quicktime_import.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\radiance_hdr.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\readimage.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\rectop.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\rotate.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\scaling.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\targa.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\tiff.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\util.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\writeimage.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cin_debug_stuff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cineonfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\cineonlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\dpxfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\dpxlib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\dynlibtiff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_allocimbuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_amiga.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_anim.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_anim5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_bitplanes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_bmp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_cmap.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_divers.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_filter.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_ham.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_hamx.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_iff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\IMB_imbuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\IMB_imbuf_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_iris.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_jpeg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_png.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_radiance_hdr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_targa.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\IMB_tiff.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\imbuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\imbuf_patch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logImageCore.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logImageLib.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\cineon\logmemfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\imbuf\intern\matrix.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\quicktime\quicktime_export.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\quicktime\quicktime_import.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/img/BL_img.dsp b/projectfiles/blender/img/BL_img.dsp new file mode 100644 index 00000000000..16f0827fbe9 --- /dev/null +++ b/projectfiles/blender/img/BL_img.dsp @@ -0,0 +1,171 @@ +# Microsoft Developer Studio Project File - Name="BL_img" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_IMG - WIN32 DEBUG +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BL_img.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BL_img.mak" CFG="BL_IMG - WIN32 DEBUG" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_img - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_img - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_img - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\img" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\img" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_img - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\img\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\img\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BL_img - Win32 Release" +# Name "BL_img - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Api.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_BrushRGBA32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_CanvasRGBA32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Line.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Pixmap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_PixmapRGBA32.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Rect.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_BrushRGBA32.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_CanvasRGBA32.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Color.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Line.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_MemPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Pixmap.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_PixmapRGBA32.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Rect.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\img\intern\IMG_Types.h +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\blender\img\IMG_Api.h +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/loader/BLO_loader.dsp b/projectfiles/blender/loader/BLO_loader.dsp new file mode 100644 index 00000000000..13b32246652 --- /dev/null +++ b/projectfiles/blender/loader/BLO_loader.dsp @@ -0,0 +1,186 @@ +# Microsoft Developer Studio Project File - Name="BLO_loader" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BLO_loader - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BLO_loader.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BLO_loader.mak" CFG="BLO_loader - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BLO_loader - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_loader - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_loader - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "BLO_loader - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BLO_loader - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\loader" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\loader" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\blender\blenloader" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\writeblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readblenfile" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\blender\writestreamglue" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_loader - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\loader\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\loader\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\writeblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readblenfile" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\blender\writestreamglue" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_loader - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BLO_loader___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "BLO_loader___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\loader\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\loader\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\writeblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readblenfile" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\blender\writestreamglue" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\loader\debug\BLO_loader.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BLO_loader - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "BLO_loader___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "BLO_loader___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\loader\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\loader\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\streamglue\\" /I "..\..\..\source\blender\readblenfile\\" /I "..\..\..\source\blender\writeblenfile\\" /I "..\..\..\source\blender\deflate\\" /I "..\..\..\source\blender\inflate\\" /I "..\..\..\..\lib\windows\zlib\include" /I "..\..\..\source\blender\readblenfile" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\blender\writestreamglue" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\python" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\blender\loader\BLO_loader.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BLO_loader - Win32 Release" +# Name "BLO_loader - Win32 Debug" +# Name "BLO_loader - Win32 MT DLL Debug" +# Name "BLO_loader - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\genfile.c +# ADD CPP /I "..\..\..\source\blender" +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\readblenentry.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\readfile.c +# ADD CPP /I "..\..\..\source\blender" +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\undofile.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\intern\writefile.c +# ADD CPP /I "..\..\..\source\blender" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\BLO_genfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\BLO_readfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\BLO_soundfile.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenloader\BLO_undofile.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/makesdna/DNA_makesdna.dsp b/projectfiles/blender/makesdna/DNA_makesdna.dsp new file mode 100644 index 00000000000..993968c2f6d --- /dev/null +++ b/projectfiles/blender/makesdna/DNA_makesdna.dsp @@ -0,0 +1,373 @@ +# Microsoft Developer Studio Project File - Name="DNA_makesdna" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=DNA_makesdna - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "DNA_makesdna.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "DNA_makesdna.mak" CFG="DNA_makesdna - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "DNA_makesdna - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "DNA_makesdna - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "DNA_makesdna - Win32 MT DLL Release" (based on "Win32 (x86) Console Application") +!MESSAGE "DNA_makesdna - Win32 MT DLL Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "DNA_makesdna - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\source\blender\makesdna\intern" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\makesdna" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo /o"DNA_makesdna.bsc" +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libguardedalloc.a BLI_blenlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /machine:I386 /nodefaultlib:"libc.lib" /libpath:"..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\obj\windows\blender\blenlib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Building DNA +PostBuild_Cmds=CD ..\..\..\source\blender\makesdna\intern\ DNA_makesdna.exe dna.c +# End Special Build Tool + +!ELSEIF "$(CFG)" == "DNA_makesdna - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\source\blender\makesdna\intern" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\makesdna\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo /o"DNA_makesdna.bsc" +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libguardedalloc.a BLI_blenlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"..\..\..\..\lib\windows\guardedalloc\lib\debug" /libpath:"..\..\..\obj\windows\blender\blenlib\debug" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Building DNA +PostBuild_Cmds=CD ..\..\..\source\blender\makesdna\intern\ DNA_makesdna.exe dna.c +# End Special Build Tool + +!ELSEIF "$(CFG)" == "DNA_makesdna - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "DNA_makesdna___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "DNA_makesdna___Win32_MT_DLL_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\source\blender\makesdna\intern" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\makesdna\mtdll" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo /o"DNA_makesdna.bsc" +# ADD BSC32 /nologo /o"DNA_makesdna.bsc" +LINK32=link.exe +# ADD BASE LINK32 BLI_blenlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /machine:I386 /out:"..\..\..\source\blender\makesdna\intern\DNA_makesdna.exe" /libpath:"..\..\..\..\obj\windows\blender\blenlib" +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 libguardedalloc.a /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /machine:I386 /libpath:"..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\obj\windows\blender\blenlib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=CD ..\..\..\source\blender\makesdna\intern\ DNA_makesdna.exe dna.c +# End Special Build Tool + +!ELSEIF "$(CFG)" == "DNA_makesdna - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DNA_makesdna___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "DNA_makesdna___Win32_MT_DLL_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\source\blender\makesdna\intern" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\makesdna\mtdll_debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo /o"DNA_makesdna.bsc" +# ADD BSC32 /nologo /o"DNA_makesdna.bsc" +LINK32=link.exe +# ADD BASE LINK32 BLI_blenlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /debug /machine:I386 /out:"..\..\..\source\blender\makesdna\debug\DNA_makesdna.exe" /pdbtype:sept /libpath:"..\..\..\..\obj\windows\blender\blenlib\debug" +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 libguardedalloc.a /nologo /subsystem:console /pdb:"DNA_makesdna.pdb" /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\lib\windows\guardedalloc\lib" +# SUBTRACT LINK32 /pdb:none +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=CD ..\..\..\source\blender\makesdna\intern\ DNA_makesdna.exe dna.c +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "DNA_makesdna - Win32 Release" +# Name "DNA_makesdna - Win32 Debug" +# Name "DNA_makesdna - Win32 MT DLL Release" +# Name "DNA_makesdna - Win32 MT DLL Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\intern\makesdna.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_action_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_actuator_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_armature_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_camera_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_constraint_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_controller_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_curve_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_customdata_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_documentation.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_effect_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_fileglobal_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_group_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_ID.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_image_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_ipo_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_key_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_lamp_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_lattice_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_listBase.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_material_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_mesh_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_meshdata_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_meta_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_modifier_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_nla_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_object_force.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_object_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_oops_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_packedFile_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_property_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_radio_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_scene_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_screen_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_scriptlink_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_sdna_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_sensor_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_sequence_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_sound_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_space_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_text_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_texture_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_userdef_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_vec_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_vfont_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_view2d_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_view3d_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_wave_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\DNA_world_types.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/radiosity/BRA_radiosity.dsp b/projectfiles/blender/radiosity/BRA_radiosity.dsp new file mode 100644 index 00000000000..be9e33e311f --- /dev/null +++ b/projectfiles/blender/radiosity/BRA_radiosity.dsp @@ -0,0 +1,133 @@ +# Microsoft Developer Studio Project File - Name="BRA_radiosity" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BRA_radiosity - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BRA_radiosity.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BRA_radiosity.mak" CFG="BRA_radiosity - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BRA_radiosity - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BRA_radiosity - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BRA_radiosity - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\radiosity" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\radiosity" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\intern\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BRA_radiosity - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\radiosity\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\radiosity\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\render\intern\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BRA_radiosity - Win32 Release" +# Name "BRA_radiosity - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\raddisplay.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radfactors.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radio.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radnode.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radpostprocess.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radpreprocess.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\intern\source\radrender.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\extern\include\radio.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\radiosity\extern\include\radio_types.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/render/BRE_render.dsp b/projectfiles/blender/render/BRE_render.dsp new file mode 100644 index 00000000000..7d29bce934c --- /dev/null +++ b/projectfiles/blender/render/BRE_render.dsp @@ -0,0 +1,192 @@ +# Microsoft Developer Studio Project File - Name="BRE_render" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BRE_render - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BRE_render.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BRE_render.mak" CFG="BRE_render - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BRE_render - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BRE_render - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BRE_render - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\render" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\render" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\kernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\intern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender" /I "..\..\..\source\blender\yafray" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_QUICKTIME" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BRE_render - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\render\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\render\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\kernel\gen_messaging" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\kernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\intern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender" /I "..\..\..\source\blender\yafray" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "WITH_QUICKTIME" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BRE_render - Win32 Release" +# Name "BRE_render - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\convertblender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\envmap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\gammaCorrectionTables.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\imagetexture.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\initrender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\pipeline.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\pixelblending.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\pixelshading.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\ray.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\rendercore.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\renderdatabase.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\shadbuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\texture.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\source\zbuf.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\edgeRender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\envmap.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\gammaCorrectionTables.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\initrender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\pixelblending.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\pixelshading.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\rendercore.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\shadbuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\texture.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\render\intern\include\zbuf.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/renderconverter/BRE_renderconverter.dsp b/projectfiles/blender/renderconverter/BRE_renderconverter.dsp new file mode 100644 index 00000000000..4b3729061a8 --- /dev/null +++ b/projectfiles/blender/renderconverter/BRE_renderconverter.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="BRE_renderconverter" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BRE_renderconverter - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BRE_renderconverter.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BRE_renderconverter.mak" CFG="BRE_renderconverter - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BRE_renderconverter - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BRE_renderconverter - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BRE_renderconverter - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\renderconverter" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\renderconverter" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\yafray" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\render\extern\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BRE_renderconverter - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BRE_renderconverter___Win32_Debug" +# PROP BASE Intermediate_Dir "BRE_renderconverter___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\render\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\render\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\yafray" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\render\extern\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\obj\windows\blender\renderconverter\debug\BRE_renderconverter.lib" + +!ENDIF + +# Begin Target + +# Name "BRE_renderconverter - Win32 Release" +# Name "BRE_renderconverter - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\renderconverter\intern\convertBlenderScene.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\renderconverter\RE_renderconverter.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/src/BL_src.dsp b/projectfiles/blender/src/BL_src.dsp new file mode 100644 index 00000000000..d6a1c3945e9 --- /dev/null +++ b/projectfiles/blender/src/BL_src.dsp @@ -0,0 +1,1040 @@ +# Microsoft Developer Studio Project File - Name="BL_src" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_SRC - WIN32 DEBUG +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BL_src.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BL_src.mak" CFG="BL_SRC - WIN32 DEBUG" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_src - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_src - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_src - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\src" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\src" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\sdl\include\\" /I "..\..\..\source\blender\img" /I "..\..\..\source\blender\renderui" /I "..\..\..\..\lib\windows\soundsystem\include\\" /I "..\..\..\..\lib\windows\python\include\python2.0\\" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\source\blender\ftfont" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\verify" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\..\lib\windows\decimation\include" /I "..\..\..\source\blender\blenpluginapi\\" /I "..\..\..\..\lib\windows\blenkey\include" /I "..\..\..\..\lib\windows\ghost\include" /I "..\..\..\..\lib\windows\bsp\include" /I "..\..\..\..\lib\windows\opennl\include" /I "..\..\..\intern\elbeem\extern" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "_CONSOLE" /D "xGAMEBLENDER" /D "WITH_QUICKTIME" /D "INTERNATIONAL" /FR /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BL_src - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\src\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\src\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\sdl\include\\" /I "..\..\..\source\blender\img" /I "..\..\..\source\blender\renderui" /I "..\..\..\..\lib\windows\soundsystem\include\\" /I "..\..\..\..\lib\windows\python\include\python2.0\\" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\source\blender\ftfont" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\verify" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\blender\quicktime" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\..\lib\windows\decimation\include" /I "..\..\..\source\blender\blenpluginapi\\" /I "..\..\..\..\lib\windows\blenkey\include" /I "..\..\..\..\lib\windows\ghost\include" /I "..\..\..\..\lib\windows\bsp\include" /I "..\..\..\..\lib\windows\opennl\include" /I "..\..\..\intern\elbeem\extern" /I "..\..\..\..\lib\windows\memutil\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "WIN32" /D "_MBCS" /D "_LIB" /D "_CONSOLE" /D "xGAMEBLENDER" /D "WITH_QUICKTIME" /D "INTERNATIONAL" /U "_DEBUG" /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BL_src - Win32 Release" +# Name "BL_src - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\src\B.blend.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\Bfont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\bfont.ttf.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\blenderbuttons.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\booleanops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\booleanops_mesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\butspace.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_editing.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_logic.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_object.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_scene.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_script.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\buttons_shading.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cmap.tga.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cmovie.tga.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cursors.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawaction.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawarmature.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawdeps.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawimage.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawimasel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawmesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawnla.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawnode.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawobject.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawoops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawscene.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawscript.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawseq.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawsound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawtext.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawtime.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\drawview.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\edit.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editaction.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editarmature.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editconstraint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editcurve.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editdeform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editface.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editfont.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editgroup.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editimasel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editipo_lib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editipo_mods.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editkey.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editlattice.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmball.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_add.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_lib.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_loop.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_mods.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmesh_tools.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editmode_undo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editnla.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editnode.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editobject.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editoops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editscreen.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editseq.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editsima.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editsound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\edittime.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\editview.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\eventdebug.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\filesel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\fluidsim.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\ghostwinlay.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\glutil.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\hddaudio.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_action.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_buttonswin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_filesel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_image.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_imasel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_info.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_ipo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_nla.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_node.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_oops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_script.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_seq.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_sound.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_text.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_time.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\header_view3d.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\headerbuttons.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\imagepaint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\imasel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\interface.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\interface_draw.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\interface_icons.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\interface_panel.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\keyval.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\language.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\lorem.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\mainqueue.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\meshtools.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\multires.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\mywindow.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\oops.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\outliner.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\parametrizer.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\playanim.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\blenpluginapi\intern\pluginapi.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\poseobject.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\preview.blend.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\previewrender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\renderwin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\resources.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\retopo.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\scrarea.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\screendump.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\sculptmode.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\seqaudio.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\seqeffects.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\seqscopes.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\sequence.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\space.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\spacetypes.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\splash.jpg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\swapbuffers.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\toets.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\toolbox.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_constraints.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_conversions.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_generics.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_manipulator.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_numinput.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\transform_snap.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\unwrapper.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\usiblender.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\view.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\vpaint.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\writeavicodec.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\writeimage.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\writemovie.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_drawaction.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_drawmesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_drawobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_editcurve.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_editface.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_editmball.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_editobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_sculptmode.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_unwrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BDR_vpaint.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_butspace.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_cursors.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawimage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawoops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawscene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawscript.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawseq.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_drawtext.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editaction.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editarmature.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editconstraint.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editdeform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editfont.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editgroup.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editkey.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editlattice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editmesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editmode_undo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editnla.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editoops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editsca.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editseq.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editsima.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editsound.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_editview.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_fsmenu.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_gl.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_glutil.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_graphics.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_imasel.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_interface.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_keyval.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_language.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_mainqueue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_meshtools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_mywindow.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_oops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_outliner.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_poseobject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_previewrender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_renderwin.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_resources.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_retopo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_scrarea.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_screen.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_space.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_spacetypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_tbcallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_toets.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_toolbox.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_usiblender.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_writeavicodec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_writeimage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BIF_writemovie.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\blendef.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BPI_script.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_buttons.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawimasel.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawipo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawnla.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawoops.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_drawview.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_edit.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editaction.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editaction_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editipo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editipo_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_editnla_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_filesel.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_headerbuttons.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_seqaudio.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_sequence.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_time.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_trans_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\BSE_view.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\butspace.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\editmesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\multires.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\parametrizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\parametrizer_intern.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\include\transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\winlay.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/src/BL_src_cre.dsp b/projectfiles/blender/src/BL_src_cre.dsp new file mode 100644 index 00000000000..1705b45a96f --- /dev/null +++ b/projectfiles/blender/src/BL_src_cre.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="BL_src_cre" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BL_src_cre - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BL_src_cre.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BL_src_cre.mak" CFG="BL_src_cre - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BL_src_cre - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BL_src_cre - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BL_src_cre - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\src_cre" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\src_cre" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderui" /I "..\..\..\source\gameengine\soundsystem\\" /I "..\..\..\..\lib\windows\python\include\python2.2\\" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\verify" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\..\lib\windows\decimation\include" /I "..\..\..\source\blender\blenpluginapi\\" /I "..\..\..\..\lib\windows\blenkey\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "_CONSOLE" /D "NAN_GAME" /D "GAME" /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\obj\windows\blender\src\BL_src_cre.lib" + +!ELSEIF "$(CFG)" == "BL_src_cre - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\blender\src_cre\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\src_cre\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\renderui" /I "..\..\..\source\gameengine\soundsystem\\" /I "..\..\..\..\lib\windows\python\include\python2.2\\" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\verify" /I "..\..\..\source\blender\readstreamglue" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\blender\blenloader" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\radiosity\extern\include" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\..\lib\windows\decimation\include" /I "..\..\..\source\blender\blenpluginapi\\" /I "..\..\..\..\lib\windows\blenkey\include" /I "..\..\..\..\lib\windows\pthreads\include" /D "WIN32" /D "_MBCS" /D "_LIB" /D "_CONSOLE" /D "NAN_GAME" /D "GAME" /U "_DEBUG" /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\obj\windows\blender\src\debug\BL_src_cre.lib" + +!ENDIF + +# Begin Target + +# Name "BL_src_cre - Win32 Release" +# Name "BL_src_cre - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cre\license.jpeg.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\src\cre\license_key.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# End Target +# End Project diff --git a/projectfiles/blender/yafray/BRE_yafray.dsp b/projectfiles/blender/yafray/BRE_yafray.dsp new file mode 100644 index 00000000000..cf6d6ddc308 --- /dev/null +++ b/projectfiles/blender/yafray/BRE_yafray.dsp @@ -0,0 +1,134 @@ +# Microsoft Developer Studio Project File - Name="BRE_yafray" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=BRE_yafray - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BRE_yafray.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BRE_yafray.mak" CFG="BRE_yafray - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BRE_yafray - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "BRE_yafray - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BRE_yafray - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\blender\yafray" +# PROP Intermediate_Dir "..\..\..\obj\windows\blender\yafray" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\render\intern\include" /I "..\..\..\source\blender\imbuf" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "BRE_yafray - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\renderconverter" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\render\extern\include" /I "..\..\..\source\blender\render\intern\include" /I "..\..\..\source\blender\imbuf" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Fp"..\..\..\obj\windows\blender\render\debug/BRE_yafray.pch" /YX /Fo"..\..\..\obj\windows\blender\render\debug/" /Fd"..\..\..\obj\windows\blender\render\debug/" /J /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "BRE_yafray - Win32 Release" +# Name "BRE_yafray - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\api.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\export_File.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\export_Plugin.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\yafexternal.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\yafexternal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\yafray_Render.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\export_File.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\export_Plugin.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\YafRay_Api.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\blender\yafray\intern\yafray_Render.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/datatoc/datatoc.dsp b/projectfiles/datatoc/datatoc.dsp new file mode 100644 index 00000000000..4e55182bb2c --- /dev/null +++ b/projectfiles/datatoc/datatoc.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="datatoc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=datatoc - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "datatoc.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "datatoc.mak" CFG="datatoc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "datatoc - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "datatoc - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "datatoc - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "datatoc - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "datatoc - Win32 Release" +# Name "datatoc - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\release\datafiles\datatoc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/blenderhook/KX_blenderhook.dsp b/projectfiles/gameengine/blenderhook/KX_blenderhook.dsp new file mode 100644 index 00000000000..c3657ed30c5 --- /dev/null +++ b/projectfiles/gameengine/blenderhook/KX_blenderhook.dsp @@ -0,0 +1,161 @@ +# Microsoft Developer Studio Project File - Name="KX_blenderhook" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=KX_blenderhook - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "KX_blenderhook.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "KX_blenderhook.mak" CFG="KX_blenderhook - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KX_blenderhook - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_blenderhook - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "KX_blenderhook - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\blenderhook" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\blenderhook" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\extern\solid" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\source\gameengine\Converter\\" /I "..\..\..\source\blender\imbuf" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\gameengine\ketsji" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\blenloader" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_blenderhook - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\blenderhook\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\blenderhook\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\extern\solid" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\source\gameengine\Converter\\" /I "..\..\..\source\blender\imbuf" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\gameengine\ketsji" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\blender\misc" /I "..\..\..\source\blender\blenloader" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "KX_blenderhook - Win32 Release" +# Name "KX_blenderhook - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\BL_KetsjiEmbedStart.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderCanvas.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderGL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderInputDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderMouseDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderPolyMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderRenderTools.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderSystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderCanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderGL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderMouseDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderPolyMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\BlenderRoutines\KX_BlenderSystem.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/converter/KX_converter.dsp b/projectfiles/gameengine/converter/KX_converter.dsp new file mode 100644 index 00000000000..96826d3004b --- /dev/null +++ b/projectfiles/gameengine/converter/KX_converter.dsp @@ -0,0 +1,278 @@ +# Microsoft Developer Studio Project File - Name="KX_converter" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=KX_converter - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "KX_converter.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "KX_converter.mak" CFG="KX_converter - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KX_converter - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_converter - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_converter - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_converter - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "KX_converter - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\converter" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\converter" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\BlOde" /I "..\..\..\source\gameengine\physics\Dummy" /I "..\..\..\extern\solid" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\\gameengine\physics\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\ode" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\bullet" /I "..\..\..\extern\bullet\linearmath" /I "..\..\..\extern\bullet\Bulletdynamics" /I "..\..\..\extern\bullet\Bullet" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SUMO_SOLID" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_converter - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\converter\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\converter\debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\BlOde" /I "..\..\..\source\gameengine\physics\Dummy" /I "..\..\..\extern\solid" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\\gameengine\physics\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\ode" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\bullet" /I "..\..\..\extern\bullet\linearmath" /I "..\..\..\extern\bullet\Bulletdynamics" /I "..\..\..\extern\bullet\Bullet" /D "WIN32" /D "_MBCS" /D "_LIB" /D "USE_SUMO_SOLID" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_converter - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "KX_converter___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "KX_converter___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\converter\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\converter\mtdll_debug" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\ode" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\BlOde" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\converter\debug\KX_converter.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_converter - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "KX_converter___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "KX_converter___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\converter\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\converter\mtdll" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\ode" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\gameengine\BlenderRoutines" /I "..\..\..\source\sumo\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\source\gameengine\Ketsji" /I "..\..\..\source\gameengine\SceneGraph" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\source\gameengine\soundsystem\snd_blenderwavecache" /I "..\..\..\source\blender\blenlib" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\BlOde" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\converter\KX_converter.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "KX_converter - Win32 Release" +# Name "KX_converter - Win32 Debug" +# Name "KX_converter - Win32 MT DLL Debug" +# Name "KX_converter - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_ActionActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_ArmatureObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_BlenderDataConversion.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_DeformableGameObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_MeshDeformer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_SkinDeformer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_SkinMeshObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BlenderWorldInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Bullet\CcdPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Bullet\CcdPhysicsEnvironment.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_BlenderScalarInterpolator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_BlenderSceneConverter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertActuators.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertControllers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertSensors.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_IpoConvert.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_ActionActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_ArmatureObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_BlenderDataConversion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_DeformableGameObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_MeshDeformer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_SkinDeformer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BL_SkinMeshObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\BlenderWorldInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_BlenderScalarInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_BlenderSceneConverter.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertActuators.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertControllers.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_ConvertSensors.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Converter\KX_IpoConvert.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/expression/EXP_expressions.dsp b/projectfiles/gameengine/expression/EXP_expressions.dsp new file mode 100644 index 00000000000..94ded903d41 --- /dev/null +++ b/projectfiles/gameengine/expression/EXP_expressions.dsp @@ -0,0 +1,302 @@ +# Microsoft Developer Studio Project File - Name="EXP_expressions" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=EXP_expressions - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "EXP_expressions.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "EXP_expressions.mak" CFG="EXP_expressions - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "EXP_expressions - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "EXP_expressions - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "EXP_expressions - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "EXP_expressions - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "EXP_expressions - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\expressions" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\expressions" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\intern\moto\include" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "EXP_expressions - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\expressions\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\expressions\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\intern\moto\include" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "EXP_expressions - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "EXP_expressions___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "EXP_expressions___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\expressions\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\expressions\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_system" /I "..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\expressions\debug\EXP_expressions.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "EXP_expressions - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "EXP_expressions___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "EXP_expressions___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\expressions\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\expressions\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\kernel\gen_system" /I "..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\expressions\EXP_expressions.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "EXP_expressions - Win32 Release" +# Name "EXP_expressions - Win32 Debug" +# Name "EXP_expressions - Win32 MT DLL Debug" +# Name "EXP_expressions - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\BoolValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ConstExpr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\EmptyValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ErrorValue.cpp +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Expressions\EXP_C-Api.cpp" +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Expression.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\FloatValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IdentifierExpr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IfExpr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\InputParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IntValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\KX_HashedPtr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ListValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Operator1Expr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Operator2Expr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\PyObjectPlus.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\StringValue.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Value.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\VectorValue.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\BoolValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ConstExpr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\EmptyValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ErrorValue.h +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Expressions\EXP_C-Api.h" +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Expression.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\FloatValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IdentifierExpr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IfExpr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\InputParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\IntValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\KX_HashedPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\ListValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Operator1Expr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Operator2Expr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\PyObjectPlus.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\StringValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\Value.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\VectorValue.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Expressions\VoidValue.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gamelogic/SCA_gamelogic.dsp b/projectfiles/gameengine/gamelogic/SCA_gamelogic.dsp new file mode 100644 index 00000000000..45be1cf2772 --- /dev/null +++ b/projectfiles/gameengine/gamelogic/SCA_gamelogic.dsp @@ -0,0 +1,406 @@ +# Microsoft Developer Studio Project File - Name="SCA_GameLogic" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SCA_GameLogic - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SCA_GameLogic.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SCA_GameLogic.mak" CFG="SCA_GameLogic - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SCA_GameLogic - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SCA_GameLogic - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SCA_GameLogic - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SCA_GameLogic - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SCA_GameLogic - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\gamelogic" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\gamelogic" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SCA_GameLogic - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SCA_GameLogic___Win32_Debug" +# PROP BASE Intermediate_Dir "SCA_GameLogic___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\gamelogic\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\gamelogic\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SCA_GameLogic - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SCA_GameLogic___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SCA_GameLogic___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\gamelogic\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\gamelogic\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\gamelogic\debug\SCA_GameLogic.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SCA_GameLogic - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SCA_GameLogic___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SCA_GameLogic___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\gamelogic\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\gamelogic\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\sdl\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\..\lib\windows\moto\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\gamelogic\SCA_GameLogic.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SCA_GameLogic - Win32 Release" +# Name "SCA_GameLogic - Win32 Debug" +# Name "SCA_GameLogic - Win32 MT DLL Debug" +# Name "SCA_GameLogic - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "JoystickImp" + +# PROP Default_Filter "cpp" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_Joystick.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_JoystickEvents.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_AlwaysEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_AlwaysSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ANDController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_EventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ExpressionController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ILogicBrick.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IScene.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ISensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_JoystickManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_JoystickSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_KeyboardManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_KeyboardSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_LogicManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_MouseManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_MouseSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ORController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertyActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertyEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertySensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PythonController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomNumberGenerator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_TimeEventManager.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "Joystick" + +# PROP Default_Filter "h" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_Joystick.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_JoystickDefines.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\Joystick\SCA_JoystickPrivate.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_AlwaysEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_AlwaysSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ANDController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_EventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ExpressionController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ILogicBrick.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_IScene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ISensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_JoystickManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_JoystickSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_KeyboardManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_KeyboardSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_LogicManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_MouseManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_MouseSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_ORController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertyActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertyEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PropertySensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_PythonController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomNumberGenerator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_RandomSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\GameLogic\SCA_TimeEventManager.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/axctl/GP_axctl.dsp b/projectfiles/gameengine/gameplayer/axctl/GP_axctl.dsp new file mode 100644 index 00000000000..99b6798bf59 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/axctl/GP_axctl.dsp @@ -0,0 +1,253 @@ +# Microsoft Developer Studio Project File - Name="GP_axctl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GP_axctl - Win32 MT DLL Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GP_axctl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GP_axctl.mak" CFG="GP_axctl - Win32 MT DLL Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_axctl - Win32 MT DLL Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_axctl - Win32 MT DLL Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_axctl - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_axctl___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "GP_axctl___Win32_MT_DLL_Debug" +# PROP BASE Target_Ext "ocx" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\axctl\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\axctl\mtdll_debug" +# PROP Target_Ext "ocx" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\GamePlayer\common" /I "..\..\..\..\source\gameengine\GamePlayer\common\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "WIN32" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /U "_DEBUG" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 opengl32.lib glu32.lib glaux.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/ActiveXgp.ocx" /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" +# SUBTRACT BASE LINK32 /nodefaultlib +# ADD LINK32 openal_static.lib libmoto.a libguardedalloc.a libbmfont.a libstring.a ws2_32.lib opengl32.lib glu32.lib glaux.lib dxguid.lib ole32.lib vfw32.lib libblenkey.a libeay32.lib libz.a libpng.a libjpeg.a odelib.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"libc.lib" /nodefaultlib:"libcmt.lib" /nodefaultlib:"msvcrt.lib" /out:"..\..\..\..\obj\windows\debug\Blender3DPlugin.ocx" /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\ode\lib\mt_dll" /libpath:"..\..\..\..\..\lib\windows\openal\lib" /libpath:"..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\..\lib\windows\moto\lib" /libpath:"../../../../../lib/windows/bmfont/lib" /libpath:"../../../../../lib/windows/string/lib" /libpath:"../../../../../lib/windows/python/lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib\mt_dll" /libpath:"..\..\..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\..\..\lib\windows\bmfont/lib" /libpath:"..\..\..\..\..\lib\windows\string\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib\\" /libpath:"..\..\..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib\\" /libpath:"..\..\..\..\..\lib\windows\png\lib" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "GP_axctl - Win32 MT DLL Release" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "GP_axctl___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "GP_axctl___Win32_MT_DLL_Release" +# PROP BASE Target_Ext "ocx" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\axctl\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\axctl\mtdll" +# PROP Target_Ext "ocx" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\GamePlayer\common" /I "..\..\..\..\source\gameengine\GamePlayer\common\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 opengl32.lib glu32.lib glaux.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/ActiveXgp.ocx" +# ADD LINK32 openal_static.lib libmoto.a libguardedalloc.a libbmfont.a libstring.a ws2_32.lib opengl32.lib glu32.lib glaux.lib dxguid.lib ole32.lib vfw32.lib libblenkey.a libeay32.lib libz.a libpng.a libjpeg.a odelib.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib:"libc.lib" /nodefaultlib:"libcmt.lib" /nodefaultlib:"msvcrtd.lib" /out:"..\..\..\..\obj\windows\Blender3DPlugin.ocx" /libpath:"..\..\..\..\..\lib\windows\ode\lib\mt_dll" /libpath:"..\..\..\..\..\lib\windows\openal\lib" /libpath:"..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\..\lib\windows\moto\lib" /libpath:"..\..\..\..\..\lib\windows\bmfont/lib" /libpath:"..\..\..\..\..\lib\windows\string\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib\mt_dll" /libpath:"..\..\..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib\\" /libpath:"..\..\..\..\..\lib\windows\png\lib" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "GP_axctl - Win32 MT DLL Debug" +# Name "GP_axctl - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderDataPathProperty.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.def +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.odl +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.rc +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerCtl.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerPpg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\CControlRefresher.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\MemoryResource.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\RawImageRsrc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\SafeControl.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\StdAfx.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderDataPathProperty.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerCtl.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerPpg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\CControlRefresher.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\MemoryResource.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\RawImageRsrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\Resource.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\SafeControl.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.ico +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerCtl.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\splash.bmp +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\ActiveXandNetscapeTest.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayer.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\BlenderPlayerDuo.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\load.blend +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\logo_blender.raw +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\logo_blender3d.raw +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\logo_nan.raw +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\ReadMe.txt +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ActiveX\ReadMeBuilding.txt +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/common/GP_common.dsp b/projectfiles/gameengine/gameplayer/common/GP_common.dsp new file mode 100644 index 00000000000..c1509608731 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/common/GP_common.dsp @@ -0,0 +1,255 @@ +# Microsoft Developer Studio Project File - Name="GP_common" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=GP_common - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GP_common.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GP_common.mak" CFG="GP_common - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_common - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "GP_common - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "GP_common - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "GP_common - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_common - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\gameengine\Converter" /I "..\..\..\..\source\gameengine\soundsystem\snd_dummy" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\GamePlayer\common\\" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "GP_common - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\gameengine\Converter" /I "..\..\..\..\source\gameengine\soundsystem\snd_dummy" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\GamePlayer\common\\" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /FD /GZ /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "GP_common - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_common___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "GP_common___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\gameengine\Converter" /I "..\..\..\..\source\gameengine\soundsystem\snd_dummy" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\GamePlayer\common\\" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\gameplayer\common\debug\GP_common.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "GP_common - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "GP_common___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "GP_common___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\common\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\..\source\gameengine\Converter" /I "..\..\..\..\source\gameengine\soundsystem\snd_dummy" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\GamePlayer\common\\" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\gameplayer\common\GP_common.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "GP_common - Win32 Release" +# Name "GP_common - Win32 Debug" +# Name "GP_common - Win32 MT DLL Debug" +# Name "GP_common - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\bmfont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_Canvas.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_Engine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_KeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_MouseDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_PolygonMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RawImage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RawLoadDotBlendArray.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RawLogoArrays.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RenderTools.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_Canvas.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_Engine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_KeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_System.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_Canvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_Engine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_KeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_MouseDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_PolygonMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_RenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\GPC_System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_Canvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_Engine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_KeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\windows\GPW_System.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\common\Makefile +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/ghost/GP_ghost.dsp b/projectfiles/gameengine/gameplayer/ghost/GP_ghost.dsp new file mode 100644 index 00000000000..d569d6fceac --- /dev/null +++ b/projectfiles/gameengine/gameplayer/ghost/GP_ghost.dsp @@ -0,0 +1,156 @@ +# Microsoft Developer Studio Project File - Name="GP_ghost" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GP_ghost - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GP_ghost.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GP_ghost.mak" CFG="GP_ghost - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_ghost - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_ghost - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_ghost - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\ghost\" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\gameengine\Physics\Ode" /I "..\..\..\..\source\gameengine\Physics" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/readblenfile" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\..\lib\windows\ghost\include" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libguardedalloc.a libstring.a libghost.a odelib.lib fmodvc.lib libbmfont.a ws2_32.lib kernel32.lib user32.lib gdi32.lib vfw32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.a opengl32.lib glu32.lib openal_static.lib dxguid.lib libblenkey.a libeay32.lib libpng.a libz.a libmoto.a /nologo /subsystem:console /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"libc.lib" /nodefaultlib:"msvcrt.lib" /nodefaultlib:"msvcrtd.lib" /nodefaultlib:"msvcprt.lib" /out:"..\..\..\..\obj\windows\blenderplayer.exe" /libpath:"..\..\..\..\..\lib\windows\ode\lib" /libpath:"..\..\..\..\..\lib\windows\bmfont\lib" /libpath:"..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\..\lib\windows\string\lib" /libpath:"..\..\..\..\..\lib\windows\ghost\lib" /libpath:"..\..\..\..\..\lib\windows\jpeg/lib" /libpath:"..\..\..\..\..\lib\windows\moto\lib\\" /libpath:"..\..\..\..\..\lib\windows\png\lib" /libpath:"..\..\..\..\..\lib\windows\zlib\lib" /libpath:"..\..\..\..\..\lib\windows\ode-0.03\lib" /libpath:"../../../../../lib/windows/fmod/lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"../../../../../lib/windows/openal/lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib\\" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "GP_ghost - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\ghost\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Physics\Ode" /I "..\..\..\..\source\gameengine\Physics" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\bmfont\include" /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/readblenfile" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\..\lib\windows\ghost\include" /I "../../../../../lib/windows/iksolver/include" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "dSINGLE" /U "_DEBUG" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libguardedalloc.a libstring.a libghost.a odelib.lib fmodvc.lib libbmfont.a ws2_32.lib kernel32.lib user32.lib gdi32.lib vfw32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib openal_static.lib libjpeg.a dxguid.lib libblenkey.a libeay32.lib libpng.a libz.a libmoto.a /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"libc.lib" /nodefaultlib:"libcmt.lib" /nodefaultlib:"msvcrt.lib" /nodefaultlib:"msvcrtd.lib" /nodefaultlib:"msvcprtd.lib" /out:"..\..\..\..\obj\windows\debug\blenderplayer.exe" /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\ode\lib" /libpath:"..\..\..\..\..\lib\windows\bmfont\lib\\" /libpath:"..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"..\..\..\..\..\lib\windows\string\lib\\" /libpath:"..\..\..\..\..\lib\windows\ghost\lib\\" /libpath:"..\..\..\..\..\lib\windows\jpeg\lib" /libpath:"..\..\..\..\..\lib\windows\moto\lib\\" /libpath:"..\..\..\..\..\lib\windows\zlib\lib\\" /libpath:"..\..\..\..\..\lib\windows\png\lib\\" /libpath:"..\..\..\..\..\lib\windows\ode-0.03\lib" /libpath:"../../../../../lib/windows/fmod/lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"../../../../../lib/windows/openal/lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib\\" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "GP_ghost - Win32 Release" +# Name "GP_ghost - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_Application.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_Canvas.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_ghost.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_KeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\icons\winplayer.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_Application.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_Canvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_KeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\GPG_System.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\..\..\source\icons\winplayer.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\ghost\Makefile +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/glut/GP_glut.dsp b/projectfiles/gameengine/gameplayer/glut/GP_glut.dsp new file mode 100644 index 00000000000..64315293ac6 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/glut/GP_glut.dsp @@ -0,0 +1,205 @@ +# Microsoft Developer Studio Project File - Name="GP_glut" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GP_glut - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GP_glut.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GP_glut.mak" CFG="GP_glut - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_glut - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_glut - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_glut - Win32 Profile" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_glut - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\glut" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\source\gameengine\SoundSystem" /I "../../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ELSEIF "$(CFG)" == "GP_glut - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\glut\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\source\gameengine\SoundSystem" /I "../../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ELSEIF "$(CFG)" == "GP_glut - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_glut___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_glut___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_glut___Win32_Profile" +# PROP Intermediate_Dir "GP_glut___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\source\gameengine\SoundSystem" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\glut-3.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\source\gameengine\SoundSystem" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 glu32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" +# ADD LINK32 glu32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\glut-3.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ENDIF + +# Begin Target + +# Name "GP_glut - Win32 Release" +# Name "GP_glut - Win32 Debug" +# Name "GP_glut - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutGamePlayer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutSystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutCanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutPolygonMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Glut\GlutSystem.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alc\ALc.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alu\ALu.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alut\ALut.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alBuffer.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alEax.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alError.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alExtension.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alListener.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alSource.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alState.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\OpenAL32.obj +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/loader/BlenderLoader/BlenderLoader.dsp b/projectfiles/gameengine/gameplayer/loader/BlenderLoader/BlenderLoader.dsp new file mode 100644 index 00000000000..1af82b0644f --- /dev/null +++ b/projectfiles/gameengine/gameplayer/loader/BlenderLoader/BlenderLoader.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="BlenderLoader" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=BlenderLoader - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BlenderLoader.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BlenderLoader.mak" CFG="BlenderLoader - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BlenderLoader - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "BlenderLoader - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "BlenderLoader - Win32 Profile" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BlenderLoader - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\..\obj\windows\gameengine\gameplayer\BlenderLoader" +# PROP Intermediate_Dir "..\..\..\..\..\..\obj\windows\gameengine\gameplayer\BlenderLoader" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../../../../../lib/windows/python/include/python2.0" /I "../../../../../source/blender/encrypt" /I "../../../../../source/blender/blenkernel" /I "../../../../../source/blender/makesdna" /I "../../../../../source/blender/blenlib" /I "../../../../../source/blender/blenloader" /I "../../../../../source/blender/render/extern/include" /I "../../../../../source/gameengine/Rasterizer" /I "../../../../../../lib\windows\sdl\SDL-1.1.7\include" /I "../../../../../source/gameengine/GameLogic" /I "..\..\..\..\..\source\sumo\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\source\kernel\gen_system" /I "../../../../../source/blender/imbuf" /I "../../../../../source/gameengine/SoundSystem" /I "../../../../../source/gameengine/SoundSystem/SND_OpenAL" /I "../../../../../source/gameengine/Ketsji" /I "../../../../../source/gameengine/Expressions" /I "../../../../../source/gameengine/SceneGraph" /I "../../../../../source/gameengine/ketsji/kxnetwork" /I "../../../../../source/gameengine/network" /I "../../../../../source/gameengine/network/loopbacknetwork" /I "../../../../../source/gameengine/GamePlayer/common" /I "../../../../../../lib/windows/iksolver/include" /I "../../../../../source/gameengine/SoundSystem/SND_Dummy" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 libguardedalloc.a libmoto.a sdlmain.lib sdl.lib dxguid.lib ole32.lib libjpeg.lib glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\..\..\..\..\obj\windows\BlenderLoader.exe" /libpath:"../../../../../../lib/windows/moto/lib" /libpath:"..\..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"../../../../../../lib/windows/python/lib" /libpath:"../../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../../lib/windows/sdl/SDL-1.1.7\Lib" + +!ELSEIF "$(CFG)" == "BlenderLoader - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\..\obj\windows\gameengine\gameplayer\BlenderLoader\debug" +# PROP Intermediate_Dir "..\..\..\..\..\..\obj\windows\gameengine\gameplayer\BlenderLoader\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "../../../../../../lib/windows/python/include/python1.5" /I "../../../../../source/blender/encrypt" /I "../../../../../source/blender/blenkernel" /I "../../../../../source/blender/makesdna" /I "../../../../../source/blender/blenlib" /I "../../../../../source/blender/blenloader" /I "../../../../../source/blender/render/extern/include" /I "../../../../../source/gameengine/Rasterizer" /I "../../../../../../lib\windows\sdl\SDL-1.1.7\include" /I "../../../../../source/gameengine/GameLogic" /I "..\..\..\..\..\source\sumo\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\source\kernel\gen_system" /I "../../../../../source/blender/imbuf" /I "../../../../../source/gameengine/SoundSystem" /I "../../../../../source/gameengine/SoundSystem/SND_OpenAL" /I "../../../../../source/gameengine/Ketsji" /I "../../../../../source/gameengine/Expressions" /I "../../../../../source/gameengine/SceneGraph" /I "../../../../../source/gameengine/ketsji/kxnetwork" /I "../../../../../source/gameengine/network" /I "../../../../../source/gameengine/network/loopbacknetwork" /I "../../../../../source/gameengine/GamePlayer/common" /I "../../../../../../lib/windows/iksolver/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fr /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 sdldebug.lib libguardedalloc.a libmoto.a sdlmain.lib sdl.lib dxguid.lib ole32.lib libjpeg.lib glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\..\..\..\..\..\obj\windows\debug\BlenderLoader.exe" /pdbtype:sept /libpath:"..\..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"../../../../../../lib/windows/python/lib" /libpath:"../../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../../lib/windows/sdl/SDL-1.1.7\Lib" + +!ELSEIF "$(CFG)" == "BlenderLoader - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "BlenderLoader___Win32_Profile" +# PROP BASE Intermediate_Dir "BlenderLoader___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "BlenderLoader___Win32_Profile" +# PROP Intermediate_Dir "BlenderLoader___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../../../../lib/windows/python/include/python1.5" /I "../../../../../source/blender/blenkernel" /I "../../../../../source/blender/makesdna" /I "../../../../../source/blender/blenlib" /I "../../../../../source/blender/blenloader" /I "../../../../../source/blender/render/extern/include" /I "../../../../../source/gameengine/Rasterizer" /I "../../../../../../lib\windows\sdl\SDL-1.1.7\include" /I "../../../../../source/gameengine/GameLogic" /I "..\..\..\..\..\source\sumo\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\source\kernel\gen_system" /I "../../../../../source/blender/imbuf" /I "../../../../../source/gameengine/SoundSystem" /I "../../../../../source/gameengine/SoundSystem/SND_OpenAL" /I "../../../../../source/gameengine/Ketsji" /I "../../../../../source/gameengine/Expressions" /I "../../../../../source/gameengine/SceneGraph" /I "../../../../../source/gameengine/ketsji/kxnetwork" /I "../../../../../source/gameengine/network" /I "../../../../../source/gameengine/network/loopbacknetwork" /I "../../../../../source/gameengine/GamePlayer/common" /I "../../../../../../lib/windows/iksolver/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# SUBTRACT BASE CPP /Fr +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "../../../../../../lib/windows/python/include/python1.5" /I "../../../../../source/blender/encrypt" /I "../../../../../source/blender/blenkernel" /I "../../../../../source/blender/makesdna" /I "../../../../../source/blender/blenlib" /I "../../../../../source/blender/blenloader" /I "../../../../../source/blender/render/extern/include" /I "../../../../../source/gameengine/Rasterizer" /I "../../../../../../lib\windows\sdl\SDL-1.1.7\include" /I "../../../../../source/gameengine/GameLogic" /I "..\..\..\..\..\source\sumo\include" /I "..\..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\source\kernel\gen_system" /I "../../../../../source/blender/imbuf" /I "../../../../../source/gameengine/SoundSystem" /I "../../../../../source/gameengine/SoundSystem/SND_OpenAL" /I "../../../../../source/gameengine/Ketsji" /I "../../../../../source/gameengine/Expressions" /I "../../../../../source/gameengine/SceneGraph" /I "../../../../../source/gameengine/ketsji/kxnetwork" /I "../../../../../source/gameengine/network" /I "../../../../../source/gameengine/network/loopbacknetwork" /I "../../../../../source/gameengine/GamePlayer/common" /I "../../../../../../lib/windows/iksolver/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 sdldebug.lib sdlmain.lib sdl.lib dxguid.lib ole32.lib libjpeg.lib glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\..\..\..\..\..\obj\windows\debug\BlenderLoader.exe" /pdbtype:sept /libpath:"../../../../../../lib/windows/python/lib" /libpath:"../../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../../lib/windows/sdl/SDL-1.1.7\Lib" +# ADD LINK32 sdldebug.lib libguardedalloc.a libmoto.a sdlmain.lib sdl.lib dxguid.lib ole32.lib libjpeg.lib glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\..\..\..\..\..\obj\windows\profile\BlenderLoader.exe" /pdbtype:sept /libpath:"..\..\..\..\..\..\lib\windows\guardedalloc\lib" /libpath:"../../../../../../lib/windows/python/lib" /libpath:"../../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../../lib/windows/sdl/SDL-1.1.7\Lib" + +!ENDIF + +# Begin Target + +# Name "BlenderLoader - Win32 Release" +# Name "BlenderLoader - Win32 Debug" +# Name "BlenderLoader - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\loader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLCanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\GamePlayer\Loaders\Blender\SDLSystem.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\alc\ALc.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\alu\ALu.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\alut\ALut.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alBuffer.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alEax.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alError.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alExtension.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alListener.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alSource.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alState.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\..\lib\windows\openal\lib\OpenAL32\OpenAL32.obj +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/netscape/GP_netscape.dsp b/projectfiles/gameengine/gameplayer/netscape/GP_netscape.dsp new file mode 100644 index 00000000000..60dc29e4918 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/netscape/GP_netscape.dsp @@ -0,0 +1,173 @@ +# Microsoft Developer Studio Project File - Name="GP_netscape" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GP_netscape - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GP_netscape.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GP_netscape.mak" CFG="GP_netscape - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_netscape - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_netscape - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_netscape - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_netscape - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "C:\Program Files\Netscape\Communicator\Program\Plugins" +# PROP Intermediate_Dir ".\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\..\lib\windows\iksolver\include" /I "../../../../../lib/windows/moto/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib libblenkey.a libz.a /nologo /subsystem:windows /dll /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/zlib/lib/" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\iksolver\lib\\" + +!ELSEIF "$(CFG)" == "GP_netscape - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "C:\Program Files\Netscape\Communicator\Program\Plugins" +# PROP Intermediate_Dir ".\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /I "../../../../../lib/windows/moto/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib libblenkey.a libz.a kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib python15.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" /libpath:"../../../../../lib/windows/zlib/lib/" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\iksolver\lib\\" + +!ELSEIF "$(CFG)" == "GP_netscape - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_netscape___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_netscape___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_netscape___Win32_Profile" +# PROP Intermediate_Dir "GP_netscape___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" + +!ENDIF + +# Begin Target + +# Name "GP_netscape - Win32 Release" +# Name "GP_netscape - Win32 Debug" +# Name "GP_netscape - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\BlenderPlayer.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\netscape_plugin_Plugin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\npblender.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\npblender.def +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\npblender.rc +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\windows\npwin.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\NSPlugin\autodownload.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\Testing\NetscapeExample.html +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/netscape2/GP_netscape.dsp b/projectfiles/gameengine/gameplayer/netscape2/GP_netscape.dsp new file mode 100644 index 00000000000..e065ac280b7 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/netscape2/GP_netscape.dsp @@ -0,0 +1,181 @@ +# Microsoft Developer Studio Project File - Name="GP_netscape2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=GP_netscape2 - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GP_netscape.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GP_netscape.mak" CFG="GP_netscape2 - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_netscape2 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_netscape2 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "GP_netscape2 - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_netscape2 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "C:\Program Files\Netscape\Communicator\Program\Plugins" +# PROP Intermediate_Dir ".\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\source\gameengine\gameplayer\Netscape2\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 libblenkey.a libeay32.lib libz.a ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\npBlender3DPlugin.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/zlib/lib/" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\..\..\lib\windows\iksolver\lib\\" /libpath:"../../../../../lib/windows/openal/lib" + +!ELSEIF "$(CFG)" == "GP_netscape2 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "C:\Program Files\Netscape\Communicator\Program\Plugins" +# PROP Intermediate_Dir ".\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\source\gameengine\gameplayer\Netscape2\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 libblenkey.a libeay32.lib libz.a ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\npBlender3DPlugin.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" /libpath:"../../../../../lib/windows/zlib/lib/" /libpath:"..\..\..\..\..\lib\windows\blenkey\lib" /libpath:"..\..\..\lib\windows\openssl\lib" /libpath:"..\..\..\lib\windows\iksolver\lib\\" + +!ELSEIF "$(CFG)" == "GP_netscape2 - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_netscape2___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_netscape2___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_netscape2___Win32_Profile" +# PROP Intermediate_Dir "GP_netscape2___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\kernel\gen_messaging" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\rasterizer\ras_openglrasterizer" /I "..\..\..\..\source\gameengine\scenegraph" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\soundsystem" /I "..\..\..\..\source\gameengine\soundsystem\snd_openal" /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows_sdk" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\..\lib\windows\openal\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "../../../../source/blender/blenkernel" /I "../../../../source/blender/makesdna" /I "../../../../source/blender/blenlib" /I "../../../../source/blender/blenloader" /I "../../../../source/blender/render/extern/include" /I "../../../../source/blender/imbuf" /I "..\..\..\..\source\gameengine\converter" /I "..\..\..\..\source\gameengine\gameplayer\common\windows" /I "..\..\..\..\source\gameengine\gameplayer\Netscape2\windows" /I "..\..\..\..\..\lib\windows\iksolver\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\NPBlender.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" +# ADD LINK32 libblenkey.a libeay32.lib libz.a ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libjpeg.lib opengl32.lib glu32.lib openal_static.lib dxguid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"C:\Program Files\Netscape\Communicator\Program\Plugins\npBlender3DPlugin.dll" /libpath:"../../../../../lib/windows/python/lib" /libpath:"../../../../../lib/windows/jpeg/lib" /libpath:"../../../../../lib/windows/openal/lib" + +!ENDIF + +# Begin Target + +# Name "GP_netscape2 - Win32 Release" +# Name "GP_netscape2 - Win32 Debug" +# Name "GP_netscape2 - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\Blender3DPlugin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\makesdna\intern\dna.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\netscape_plugin_Plugin.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\npblender.def +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\npblender.rc +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\npshell.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\npwin.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape2\windows\plgwnd.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\blender\blenkernel\bad_level_call_stubs\stubs.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\plgwnd.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\NSPlugin\autodownload.html +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Netscape\Testing\NetscapeExample.html +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/ps2/GP_ps2.dsp b/projectfiles/gameengine/gameplayer/ps2/GP_ps2.dsp new file mode 100644 index 00000000000..84aa94ef1a5 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/ps2/GP_ps2.dsp @@ -0,0 +1,182 @@ +# Microsoft Developer Studio Project File - Name="GP_ps2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GP_ps2 - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GP_ps2.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GP_ps2.mak" CFG="GP_ps2 - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_ps2 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_ps2 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_ps2 - Win32 Profile" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_ps2 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\ps2" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "GP_ps2 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\ps2\debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "GP_ps2 - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_ps2___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_ps2___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_ps2___Win32_Profile" +# PROP Intermediate_Dir "GP_ps2___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\rasterizer" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "GP_ps2 - Win32 Release" +# Name "GP_ps2 - Win32 Debug" +# Name "GP_ps2 - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\DebugActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\GPC_Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2DualShockDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2GamePlayer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2System.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\DebugActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\ExampleEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\GPC_Init.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2Canvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2DualShockDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2InputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2Rasterizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2RenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\PS2System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\PS2\SamplePolygonMaterial.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/qt/gp.dsp b/projectfiles/gameengine/gameplayer/qt/gp.dsp new file mode 100644 index 00000000000..512c5b69de6 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/qt/gp.dsp @@ -0,0 +1,164 @@ +# Microsoft Developer Studio Project File - Name="gp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=gp - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gp.mak" CFG="gp - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gp - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "gp - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gp" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gp" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "h:\qtwin\include" /I "..\..\..\..\source\gameengine\Expressions" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\Ketsji" /I "..\..\..\..\source\gameengine\Ketsji\KXNetwork" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\source\gameengine\Network\LoopBackNetwork" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\..\source\gameengine\SceneGraph" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib h:\qtwin\lib\qt.lib h:\qtwin\lib\qnp.lib python20.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\..\..\..\obj\windows\gp.exe" /libpath:"..\..\..\..\..\lib\windows\python\lib\\" + +!ELSEIF "$(CFG)" == "gp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gp\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gp\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /GX /Od /I "h:\qtwin\include" /I "..\..\..\..\source\gameengine\Expressions" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\Ketsji" /I "..\..\..\..\source\gameengine\Ketsji\KXNetwork" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\source\gameengine\Network\LoopBackNetwork" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\..\source\gameengine\SceneGraph" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib h:\qtwin\lib\qt.lib python15_d.lib /nologo /subsystem:windows /debug /machine:I386 /out:"..\..\..\..\..\obj\windows\debug\gp.exe" /libpath:"..\..\..\..\..\lib\windows\python\lib\\" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "gp - Win32 Release" +# Name "gp - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\DebugActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\SamplePolygonMaterial.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/qt/gpplugin.dsp b/projectfiles/gameengine/gameplayer/qt/gpplugin.dsp new file mode 100644 index 00000000000..180f147c79a --- /dev/null +++ b/projectfiles/gameengine/gameplayer/qt/gpplugin.dsp @@ -0,0 +1,824 @@ +# Microsoft Developer Studio Project File - Name="gpplugin" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=gpplugin - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gpplugin.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gpplugin.mak" CFG="gpplugin - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gpplugin - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gpplugin - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gpplugin - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gpplugin" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gpplugin" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GPPLUGIN_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "h:\qtwin\include" /I "..\..\..\..\source\gameengine\Expressions" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\Ketsji" /I "..\..\..\..\source\gameengine\Ketsji\KXNetwork" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\source\gameengine\Network\LoopBackNetwork" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\..\source\gameengine\SceneGraph" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GPPLUGIN_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib h:\qtwin\lib\qnp.lib h:\qtwin\lib\qt.lib opengl32.lib glu32.lib python20.lib /nologo /dll /machine:I386 /out:"..\..\..\..\..\obj\windows\npWebGP.dll" /libpath:"..\..\..\..\..\lib\windows\python\lib\\" + +!ELSEIF "$(CFG)" == "gpplugin - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gpplugin\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\gameplayer\qt\gpplugin\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GPPLUGIN_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I "h:\qtwin\include" /I "..\..\..\..\source\gameengine\Expressions" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\Ketsji" /I "..\..\..\..\source\gameengine\Ketsji\KXNetwork" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\source\gameengine\Network\LoopBackNetwork" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\..\source\gameengine\SceneGraph" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "WIN32" /D "PLUGIN" /D "_DEBUG" +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib h:\qtwin\lib\qnp.lib h:\qtwin\lib\qt.lib opengl32.lib glu32.lib python15_d.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:"..\..\..\..\source\gameengine\GamePlayer\Qt\GP.def" /out:"..\..\..\..\..\obj\windows\debug\npWebGP.dll" /libpath:"..\..\..\..\..\lib\windows\python\lib" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "gpplugin - Win32 Release" +# Name "gpplugin - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP.cpp +DEP_CPP_GP_CP=\ + "..\..\..\..\..\qtwin\include\qapplication.h"\ + "..\..\..\..\..\qtwin\include\qarray.h"\ + "..\..\..\..\..\qtwin\include\qasciidict.h"\ + "..\..\..\..\..\qtwin\include\qbrush.h"\ + "..\..\..\..\..\qtwin\include\qcollection.h"\ + "..\..\..\..\..\qtwin\include\qcolor.h"\ + "..\..\..\..\..\qtwin\include\qconfig-large.h"\ + "..\..\..\..\..\qtwin\include\qconfig-medium.h"\ + "..\..\..\..\..\qtwin\include\qconfig-minimal.h"\ + "..\..\..\..\..\qtwin\include\qconfig-small.h"\ + "..\..\..\..\..\qtwin\include\qconfig.h"\ + "..\..\..\..\..\qtwin\include\qcstring.h"\ + "..\..\..\..\..\qtwin\include\qcursor.h"\ + "..\..\..\..\..\qtwin\include\qdatastream.h"\ + "..\..\..\..\..\qtwin\include\qdialog.h"\ + "..\..\..\..\..\qtwin\include\qevent.h"\ + "..\..\..\..\..\qtwin\include\qfeatures.h"\ + "..\..\..\..\..\qtwin\include\qfont.h"\ + "..\..\..\..\..\qtwin\include\qfontinfo.h"\ + "..\..\..\..\..\qtwin\include\qfontmetrics.h"\ + "..\..\..\..\..\qtwin\include\qframe.h"\ + "..\..\..\..\..\qtwin\include\qgarray.h"\ + "..\..\..\..\..\qtwin\include\qgdict.h"\ + "..\..\..\..\..\qtwin\include\qgl.h"\ + "..\..\..\..\..\qtwin\include\qglist.h"\ + "..\..\..\..\..\qtwin\include\qglobal.h"\ + "..\..\..\..\..\qtwin\include\qiconset.h"\ + "..\..\..\..\..\qtwin\include\qimage.h"\ + "..\..\..\..\..\qtwin\include\qintdict.h"\ + "..\..\..\..\..\qtwin\include\qiodevice.h"\ + "..\..\..\..\..\qtwin\include\qlist.h"\ + "..\..\..\..\..\qtwin\include\qmenudata.h"\ + "..\..\..\..\..\qtwin\include\qmessagebox.h"\ + "..\..\..\..\..\qtwin\include\qmime.h"\ + "..\..\..\..\..\qtwin\include\qnamespace.h"\ + "..\..\..\..\..\qtwin\include\qnp.h"\ + "..\..\..\..\..\qtwin\include\qobject.h"\ + "..\..\..\..\..\qtwin\include\qobjectdefs.h"\ + "..\..\..\..\..\qtwin\include\qpaintdevice.h"\ + "..\..\..\..\..\qtwin\include\qpainter.h"\ + "..\..\..\..\..\qtwin\include\qpalette.h"\ + "..\..\..\..\..\qtwin\include\qpen.h"\ + "..\..\..\..\..\qtwin\include\qpixmap.h"\ + "..\..\..\..\..\qtwin\include\qpngio.h"\ + "..\..\..\..\..\qtwin\include\qpoint.h"\ + "..\..\..\..\..\qtwin\include\qpointarray.h"\ + "..\..\..\..\..\qtwin\include\qpopupmenu.h"\ + "..\..\..\..\..\qtwin\include\qrect.h"\ + "..\..\..\..\..\qtwin\include\qregexp.h"\ + "..\..\..\..\..\qtwin\include\qregion.h"\ + "..\..\..\..\..\qtwin\include\qshared.h"\ + "..\..\..\..\..\qtwin\include\qsignal.h"\ + "..\..\..\..\..\qtwin\include\qsize.h"\ + "..\..\..\..\..\qtwin\include\qsizepolicy.h"\ + "..\..\..\..\..\qtwin\include\qstring.h"\ + "..\..\..\..\..\qtwin\include\qstringlist.h"\ + "..\..\..\..\..\qtwin\include\qstrlist.h"\ + "..\..\..\..\..\qtwin\include\qstyle.h"\ + "..\..\..\..\..\qtwin\include\qt_windows.h"\ + "..\..\..\..\..\qtwin\include\qtranslator.h"\ + "..\..\..\..\..\qtwin\include\qvaluelist.h"\ + "..\..\..\..\..\qtwin\include\qwidget.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs_win.h"\ + "..\..\..\..\..\qtwin\include\qwmatrix.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h"\ + "..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkScene.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.cpp +DEP_CPP_GP_IN=\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\Expressions\BoolValue.h"\ + "..\..\..\..\source\gameengine\Expressions\ListValue.h"\ + "..\..\..\..\source\gameengine\Expressions\PyObjectPlus.h"\ + "..\..\..\..\source\gameengine\Expressions\Value.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_AlwaysEventManager.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_AlwaysSensor.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ANDController.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_EventManager.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IActuator.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IController.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ILogicBrick.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IObject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISensor.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_KeyboardManager.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_KeyboardSensor.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_LogicManager.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_PythonController.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\DebugActuator.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\SamplePolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_GameObject.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_ObjectActuator.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_PythonInit.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_SoundActuator.h"\ + "..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkEventManager.h"\ + "..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkScene.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_BucketManager.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MeshObject.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_OpenGLRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_Polygon.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_IObject.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_Node.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_Spatial.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedPtr.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\source\sumo\include\solid.h"\ + "..\..\..\..\source\sumo\include\solid_types.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +NODEP_CPP_GP_IN=\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\GPC_OpenALWaveCache.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\OpenALScene.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\SND_SoundObject.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.cpp +DEP_CPP_QTEXA=\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\Expressions\BoolValue.h"\ + "..\..\..\..\source\gameengine\Expressions\IntValue.h"\ + "..\..\..\..\source\gameengine\Expressions\ListValue.h"\ + "..\..\..\..\source\gameengine\Expressions\PyObjectPlus.h"\ + "..\..\..\..\source\gameengine\Expressions\Value.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IActuator.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ILogicBrick.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IObject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_LogicManager.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_Camera.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_GameObject.h"\ + "..\..\..\..\source\gameengine\Ketsji\KX_ObjectActuator.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkScene.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_BucketManager.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_CameraData.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MeshObject.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_Polygon.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_IObject.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_Node.h"\ + "..\..\..\..\source\gameengine\SceneGraph\SG_Spatial.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedPtr.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\source\sumo\Fuzzics\include\SM_Scene.h"\ + "..\..\..\..\source\sumo\include\solid.h"\ + "..\..\..\..\source\sumo\include\solid_types.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +NODEP_CPP_QTEXA=\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\OpenALScene.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.cpp +DEP_CPP_QTKEY=\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.cpp +DEP_CPP_QTOPE=\ + "..\..\..\..\..\qtwin\include\qapplication.h"\ + "..\..\..\..\..\qtwin\include\qarray.h"\ + "..\..\..\..\..\qtwin\include\qasciidict.h"\ + "..\..\..\..\..\qtwin\include\qbrush.h"\ + "..\..\..\..\..\qtwin\include\qcollection.h"\ + "..\..\..\..\..\qtwin\include\qcolor.h"\ + "..\..\..\..\..\qtwin\include\qconfig-large.h"\ + "..\..\..\..\..\qtwin\include\qconfig-medium.h"\ + "..\..\..\..\..\qtwin\include\qconfig-minimal.h"\ + "..\..\..\..\..\qtwin\include\qconfig-small.h"\ + "..\..\..\..\..\qtwin\include\qconfig.h"\ + "..\..\..\..\..\qtwin\include\qcstring.h"\ + "..\..\..\..\..\qtwin\include\qcursor.h"\ + "..\..\..\..\..\qtwin\include\qdatastream.h"\ + "..\..\..\..\..\qtwin\include\qevent.h"\ + "..\..\..\..\..\qtwin\include\qfeatures.h"\ + "..\..\..\..\..\qtwin\include\qfont.h"\ + "..\..\..\..\..\qtwin\include\qfontinfo.h"\ + "..\..\..\..\..\qtwin\include\qfontmetrics.h"\ + "..\..\..\..\..\qtwin\include\qframe.h"\ + "..\..\..\..\..\qtwin\include\qgarray.h"\ + "..\..\..\..\..\qtwin\include\qgdict.h"\ + "..\..\..\..\..\qtwin\include\qgl.h"\ + "..\..\..\..\..\qtwin\include\qglist.h"\ + "..\..\..\..\..\qtwin\include\qglobal.h"\ + "..\..\..\..\..\qtwin\include\qiconset.h"\ + "..\..\..\..\..\qtwin\include\qintdict.h"\ + "..\..\..\..\..\qtwin\include\qiodevice.h"\ + "..\..\..\..\..\qtwin\include\qlist.h"\ + "..\..\..\..\..\qtwin\include\qmenudata.h"\ + "..\..\..\..\..\qtwin\include\qmime.h"\ + "..\..\..\..\..\qtwin\include\qnamespace.h"\ + "..\..\..\..\..\qtwin\include\qobject.h"\ + "..\..\..\..\..\qtwin\include\qobjectdefs.h"\ + "..\..\..\..\..\qtwin\include\qpaintdevice.h"\ + "..\..\..\..\..\qtwin\include\qpalette.h"\ + "..\..\..\..\..\qtwin\include\qpixmap.h"\ + "..\..\..\..\..\qtwin\include\qpoint.h"\ + "..\..\..\..\..\qtwin\include\qpopupmenu.h"\ + "..\..\..\..\..\qtwin\include\qrect.h"\ + "..\..\..\..\..\qtwin\include\qregexp.h"\ + "..\..\..\..\..\qtwin\include\qregion.h"\ + "..\..\..\..\..\qtwin\include\qshared.h"\ + "..\..\..\..\..\qtwin\include\qsignal.h"\ + "..\..\..\..\..\qtwin\include\qsize.h"\ + "..\..\..\..\..\qtwin\include\qsizepolicy.h"\ + "..\..\..\..\..\qtwin\include\qstring.h"\ + "..\..\..\..\..\qtwin\include\qstringlist.h"\ + "..\..\..\..\..\qtwin\include\qstyle.h"\ + "..\..\..\..\..\qtwin\include\qt_windows.h"\ + "..\..\..\..\..\qtwin\include\qtranslator.h"\ + "..\..\..\..\..\qtwin\include\qvaluelist.h"\ + "..\..\..\..\..\qtwin\include\qwidget.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs_win.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.cpp +DEP_CPP_QTSYS=\ + "..\..\..\..\..\qtwin\include\qapplication.h"\ + "..\..\..\..\..\qtwin\include\qarray.h"\ + "..\..\..\..\..\qtwin\include\qasciidict.h"\ + "..\..\..\..\..\qtwin\include\qbrush.h"\ + "..\..\..\..\..\qtwin\include\qcollection.h"\ + "..\..\..\..\..\qtwin\include\qcolor.h"\ + "..\..\..\..\..\qtwin\include\qconfig-large.h"\ + "..\..\..\..\..\qtwin\include\qconfig-medium.h"\ + "..\..\..\..\..\qtwin\include\qconfig-minimal.h"\ + "..\..\..\..\..\qtwin\include\qconfig-small.h"\ + "..\..\..\..\..\qtwin\include\qconfig.h"\ + "..\..\..\..\..\qtwin\include\qcstring.h"\ + "..\..\..\..\..\qtwin\include\qcursor.h"\ + "..\..\..\..\..\qtwin\include\qdatastream.h"\ + "..\..\..\..\..\qtwin\include\qevent.h"\ + "..\..\..\..\..\qtwin\include\qfeatures.h"\ + "..\..\..\..\..\qtwin\include\qfont.h"\ + "..\..\..\..\..\qtwin\include\qfontinfo.h"\ + "..\..\..\..\..\qtwin\include\qfontmetrics.h"\ + "..\..\..\..\..\qtwin\include\qframe.h"\ + "..\..\..\..\..\qtwin\include\qgarray.h"\ + "..\..\..\..\..\qtwin\include\qgdict.h"\ + "..\..\..\..\..\qtwin\include\qgl.h"\ + "..\..\..\..\..\qtwin\include\qglist.h"\ + "..\..\..\..\..\qtwin\include\qglobal.h"\ + "..\..\..\..\..\qtwin\include\qiconset.h"\ + "..\..\..\..\..\qtwin\include\qintdict.h"\ + "..\..\..\..\..\qtwin\include\qiodevice.h"\ + "..\..\..\..\..\qtwin\include\qlist.h"\ + "..\..\..\..\..\qtwin\include\qmenudata.h"\ + "..\..\..\..\..\qtwin\include\qmime.h"\ + "..\..\..\..\..\qtwin\include\qnamespace.h"\ + "..\..\..\..\..\qtwin\include\qobject.h"\ + "..\..\..\..\..\qtwin\include\qobjectdefs.h"\ + "..\..\..\..\..\qtwin\include\qpaintdevice.h"\ + "..\..\..\..\..\qtwin\include\qpalette.h"\ + "..\..\..\..\..\qtwin\include\qpixmap.h"\ + "..\..\..\..\..\qtwin\include\qpoint.h"\ + "..\..\..\..\..\qtwin\include\qpopupmenu.h"\ + "..\..\..\..\..\qtwin\include\qrect.h"\ + "..\..\..\..\..\qtwin\include\qregexp.h"\ + "..\..\..\..\..\qtwin\include\qregion.h"\ + "..\..\..\..\..\qtwin\include\qshared.h"\ + "..\..\..\..\..\qtwin\include\qsignal.h"\ + "..\..\..\..\..\qtwin\include\qsize.h"\ + "..\..\..\..\..\qtwin\include\qsizepolicy.h"\ + "..\..\..\..\..\qtwin\include\qstring.h"\ + "..\..\..\..\..\qtwin\include\qstringlist.h"\ + "..\..\..\..\..\qtwin\include\qstyle.h"\ + "..\..\..\..\..\qtwin\include\qt_windows.h"\ + "..\..\..\..\..\qtwin\include\qtranslator.h"\ + "..\..\..\..\..\qtwin\include\qvaluelist.h"\ + "..\..\..\..\..\qtwin\include\qwidget.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs.h"\ + "..\..\..\..\..\qtwin\include\qwindowdefs_win.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\abstract.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\bufferobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\ceval.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\classobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\cobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\complexobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\config.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\dictobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\fileobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\floatobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\funcobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\import.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\intrcheck.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\listobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\longobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\methodobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\modsupport.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\moduleobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\mymalloc.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\myproto.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\object.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\objimpl.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\patchlevel.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pydebug.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyerrors.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pyfpe.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pystate.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\Python.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\pythonrun.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\rangeobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sliceobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\stringobject.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\sysmodule.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\traceback.h"\ + "..\..\..\..\..\lib\windows\python\include\python1.5\tupleobject.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_IInputDevice.h"\ + "..\..\..\..\source\gameengine\GameLogic\SCA_ISystem.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h"\ + "..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkDeviceInterface.h"\ + "..\..\..\..\source\gameengine\Network\NG_NetworkScene.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h"\ + "..\..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_HashedString.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_Matrix4x4.h"\ + "..\..\..\..\source\kernel\gen_system\GEN_StdString.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Map.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_MinMax.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Optimize.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_random.h"\ + "..\..\..\..\..\lib\windows\moto\include\GEN_Stream.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_assert.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Matrix3x3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Point3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Quaternion.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Scalar.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Transform.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Tuple4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector2.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector3.inl"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.h"\ + "..\..\..\..\..\lib\windows\moto\include\MT_Vector4.inl"\ + "..\..\..\..\..\lib\windows\moto\include\NM_Scalar.h"\ + +NODEP_CPP_QTSYS=\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\BKE_bad_level_calls.h"\ + "..\..\..\..\source\gameengine\GamePlayer\Qt\BLO_readfile.h"\ + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\DebugActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP_Init.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtExampleEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtOpenGLWidget.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\QtSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\resource.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\SamplePolygonMaterial.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\Qt\GP.rc +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/gameplayer/qt/qtgp.dsw b/projectfiles/gameengine/gameplayer/qt/qtgp.dsw new file mode 100644 index 00000000000..22d9c5db23c --- /dev/null +++ b/projectfiles/gameengine/gameplayer/qt/qtgp.dsw @@ -0,0 +1,323 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BLO_loader"=..\..\..\blender\loader\BLO_loader.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "EXP_expressions"=..\..\expression\EXP_expressions.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SCA_GameLogic"=..\..\gamelogic\SCA_GameLogic.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_ketsji"=..\..\ketsji\KX_ketsji.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "KX_network"=..\..\ketsji\network\KX_network.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SG_SceneGraph"=..\..\scenegraph\SG_SceneGraph.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "NG_loopbacknetwork"=..\..\network\loopbacknetwork\NG_loopbacknetwork.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "NG_network"=..\..\network\network\NG_network.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "RAS_openglrasterizer"=..\..\rasterizer\openglrasterizer\RAS_openglrasterizer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "RAS_rasterizer"=..\..\rasterizer\RAS_rasterizer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SM_fuzzics"=..\..\..\sumo\fuzzics\SM_fuzzics.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SM_moto"=..\..\..\sumo\moto\SM_moto.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SM_solid"=..\..\..\sumo\solid\SM_solid.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SND_openal"=..\..\sound\openal\SND_openal.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SND_sound"=..\..\sound\SND_sound.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "SYS_system"=..\..\..\kernel\system\SYS_system.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gp"=.\gp.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_ketsji + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_fuzzics + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_moto + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_solid + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_openal + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_sound + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency +}}} + +############################################################################### + +Project: "gpplugin"=.\gpplugin.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name EXP_expressions + End Project Dependency + Begin Project Dependency + Project_Dep_Name SCA_GameLogic + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_ketsji + End Project Dependency + Begin Project Dependency + Project_Dep_Name KX_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name SG_SceneGraph + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_loopbacknetwork + End Project Dependency + Begin Project Dependency + Project_Dep_Name NG_network + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_openglrasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name RAS_rasterizer + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_fuzzics + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_moto + End Project Dependency + Begin Project Dependency + Project_Dep_Name SM_solid + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_openal + End Project Dependency + Begin Project Dependency + Project_Dep_Name SND_sound + End Project Dependency + Begin Project Dependency + Project_Dep_Name SYS_system + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/projectfiles/gameengine/gameplayer/sdl/GP_sdl.dsp b/projectfiles/gameengine/gameplayer/sdl/GP_sdl.dsp new file mode 100644 index 00000000000..56c758de7e9 --- /dev/null +++ b/projectfiles/gameengine/gameplayer/sdl/GP_sdl.dsp @@ -0,0 +1,205 @@ +# Microsoft Developer Studio Project File - Name="GP_sdl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=GP_sdl - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GP_sdl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GP_sdl.mak" CFG="GP_sdl - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GP_sdl - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_sdl - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "GP_sdl - Win32 Profile" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GP_sdl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\sdl" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\sdl\SDL-1.1.7\include" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 sdl.lib sdlmain.lib kernel32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\..\lib\windows\sdl\sdl-1.1.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" + +!ELSEIF "$(CFG)" == "GP_sdl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\gameplayer\sdl\debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\sdl\SDL-1.1.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib sdlmaindebug.lib sdldebug.lib opengl32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\sdl\sdl-1.1.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ELSEIF "$(CFG)" == "GP_sdl - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "GP_sdl___Win32_Profile" +# PROP BASE Intermediate_Dir "GP_sdl___Win32_Profile" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "GP_sdl___Win32_Profile" +# PROP Intermediate_Dir "GP_sdl___Win32_Profile" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\sdl\SDL-1.1.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\gameengine\network\loopbacknetwork" /I "..\..\..\..\source\gameengine\gameplayer\common" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\gamelogic" /I "..\..\..\..\source\gameengine\Rasterizer" /I "..\..\..\..\source\sumo\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\sumo\Fuzzics\include" /I "..\..\..\..\..\lib\windows\sdl\SDL-1.1.7\include" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 glu32.lib sdlmaindebug.lib sdldebug.lib opengl32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\sdl\sdl-1.1.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" +# ADD LINK32 glu32.lib sdlmaindebug.lib sdldebug.lib opengl32.lib user32.lib gdi32.lib advapi32.lib dxguid.lib ole32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\..\lib\windows\sdl\sdl-1.1.7\lib" /libpath:"..\..\..\..\..\lib\windows\python\lib" /libpath:"..\..\..\..\..\lib\windows\openal\lib\lib_release" + +!ENDIF + +# Begin Target + +# Name "GP_sdl - Win32 Release" +# Name "GP_sdl - Win32 Debug" +# Name "GP_sdl - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\main.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLKeyboardDevice.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLRenderTools.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLSystem.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLCanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLInputDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLKeyboardDevice.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\GamePlayer\SDL\SDLSystem.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alc\ALc.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alu\ALu.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\alut\ALut.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alBuffer.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alEax.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alError.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alExtension.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alListener.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alSource.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\alState.obj +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\lib\windows\openal\lib\OpenAL32\OpenAL32.obj +# End Source File +# End Target +# End Project diff --git a/projectfiles/gameengine/ketsji/KX_ketsji.dsp b/projectfiles/gameengine/ketsji/KX_ketsji.dsp new file mode 100644 index 00000000000..b7139d01bc3 --- /dev/null +++ b/projectfiles/gameengine/ketsji/KX_ketsji.dsp @@ -0,0 +1,690 @@ +# Microsoft Developer Studio Project File - Name="KX_ketsji" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=KX_ketsji - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "KX_ketsji.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "KX_ketsji.mak" CFG="KX_ketsji - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KX_ketsji - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_ketsji - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_ketsji - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_ketsji - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "KX_ketsji - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\ketsji" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\ketsji" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\source\gameengine\physics\common\dummy" /I "..\..\..\extern\solid" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\Converter" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\source\gameengine\physics\BlOde" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\gameengine\physics\bullet" /I "..\..\..\extern\bullet\linearmath" /I "..\..\..\extern\bullet\Bulletdynamics" /I "..\..\..\extern\bullet\Bullet" /I "..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\source\blender\blenlib" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /D "USE_SUMO_SOLID" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_ketsji - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\ketsji\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\ketsji\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\source\gameengine\physics\common\dummy" /I "..\..\..\extern\solid" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\..\lib\windows\soundsystem\include" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\Converter" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\source\gameengine\physics\BlOde" /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\blender\python" /I "..\..\..\source\blender\blenkernel" /I "..\..\..\source\blender\makesdna" /I "..\..\..\source\blender\include" /I "..\..\..\source\blender\imbuf" /I "..\..\..\..\lib\windows\guardedalloc\include" /I "..\..\..\source\gameengine\physics\bullet" /I "..\..\..\extern\bullet\linearmath" /I "..\..\..\extern\bullet\Bulletdynamics" /I "..\..\..\extern\bullet\Bullet" /I "..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer" /I "..\..\..\source\blender\blenlib" /D "JANCODEPANCO" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /D "USE_SUMO_SOLID" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_ketsji - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "KX_ketsji___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "KX_ketsji___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\ketsji\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\ketsji\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\gameengine\physics\common\dummy" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\source\gameengine\physics\BlOde" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\ketsji\debug\KX_ketsji.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_ketsji - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "KX_ketsji___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "KX_ketsji___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\ketsji\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\ketsji\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\source\gameengine\physics\common\dummy" /I "..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\..\lib\windows\moto\include" /I "..\..\..\source\kernel\gen_system" /I "..\..\..\source\gameengine\soundsystem" /I "..\..\..\source\gameengine\rasterizer" /I "..\..\..\source\gameengine\scenegraph" /I "..\..\..\source\gameengine\gamelogic" /I "..\..\..\source\gameengine\expressions" /I "..\..\..\source\sumo\include" /I "..\..\..\source\sumo\fuzzics\include" /I "..\..\..\source\gameengine\network" /I "..\..\..\source\gameengine\ketsji\kxnetwork" /I "..\..\..\source\gameengine\physics" /I "..\..\..\source\gameengine\physics\common" /I "..\..\..\source\gameengine\physics\dummy" /I "..\..\..\source\gameengine\physics\sumo" /I "..\..\..\source\gameengine\physics\sumo\fuzzics\include" /I "..\..\..\source\gameengine\physics\sumo\include" /I "..\..\..\source\gameengine\physics\BlOde" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "EXP_PYTHON_EMBEDDING" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\ketsji\KX_ketsji.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "KX_ketsji - Win32 Release" +# Name "KX_ketsji - Win32 Debug" +# Name "KX_ketsji - Win32 MT DLL Debug" +# Name "KX_ketsji - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "ActuatorsImp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CameraActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CDActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConstraintActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_GameActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IpoActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ObjectActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_AddObjectActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_EndObjectActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_ReplaceMeshActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SceneActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SoundActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TrackToActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VisibilityActuator.cpp +# End Source File +# End Group +# Begin Group "SG_ControllersImp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CameraIpoSGController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPO_SGController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_LightIpoSGController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ObColorIpoSGController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_WorldIpoController.cpp +# End Source File +# End Group +# Begin Group "SensorsImp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MouseFocusSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_NearSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RadarSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RaySensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TouchSensor.cpp +# End Source File +# End Group +# Begin Group "IposImp" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_OrientationInterpolator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PositionInterpolator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ScalarInterpolator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ScalingInterpolator.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Material.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Shader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Texture.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_BlenderMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_BulletPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Camera.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConstraintWrapper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConvertPhysicsObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_EmptyObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_GameObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_KetsjiEngine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Light.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MaterialIpoController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MeshProxy.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MotionState.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_OdePhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PhysicsObjectWrapper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PolygonMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PyConstraintBinding.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PyMath.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PythonInit.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RayCast.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RayEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Scene.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SG_BoneParentNodeRelationship.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SG_NodeRelationships.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SumoPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TimeCategoryLogger.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TimeLogger.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TouchEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VehicleWrapper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VertexProxy.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_WorldInfo.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Group "Actuators" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CameraActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CDActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConstraintActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_GameActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IpoActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ObjectActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_AddObjectActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_EndObjectActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SCA_ReplaceMeshActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SceneActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SoundActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TrackToActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VisibilityActuator.h +# End Source File +# End Group +# Begin Group "SG_Controllers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_CameraIpoSGController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPO_SGController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_LightIpoSGController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ObColorIpoSGController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_WorldIpoController.h +# End Source File +# End Group +# Begin Group "Sensors" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MouseFocusSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_NearSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RadarSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RaySensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TouchSensor.h +# End Source File +# End Group +# Begin Group "Ipos" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IScalarInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_OrientationInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PositionInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ScalarInterpolator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ScalingInterpolator.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Material.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Shader.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\BL_Texture.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_BlenderMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_BulletPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Camera.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConstraintWrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ConvertPhysicsObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_EmptyObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_GameObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_IPOTransform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ISceneConverter.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_ISystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_KetsjiEngine.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Light.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MaterialIpoController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MeshProxy.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_MotionState.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_OdePhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PhysicsObjectWrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PolygonMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PyConstraintBinding.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PyMath.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_PythonInit.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RayCast.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_RayEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_Scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SG_BoneParentNodeRelationship.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SG_NodeRelationships.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_SumoPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TimeCategoryLogger.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TimeLogger.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_TouchEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VehicleWrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_VertexProxy.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Ketsji\KX_WorldInfo.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/ketsji/network/KX_network.dsp b/projectfiles/gameengine/ketsji/network/KX_network.dsp new file mode 100644 index 00000000000..0c265e9dd56 --- /dev/null +++ b/projectfiles/gameengine/ketsji/network/KX_network.dsp @@ -0,0 +1,186 @@ +# Microsoft Developer Studio Project File - Name="KX_network" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=KX_network - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "KX_network.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "KX_network.mak" CFG="KX_network - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KX_network - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_network - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_network - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "KX_network - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "KX_network - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_network - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\..\lib\windows\python\include\python2.4" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_network - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "KX_network___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "KX_network___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\..\lib\windows\python\include\python1.5" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /D "WIN32" /D "_MBCS" /D "_LIB" /U "_DEBUG" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\ketsji\network\debug\KX_network.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "KX_network - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "KX_network___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "KX_network___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\ketsji\network\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /I "..\..\..\..\..\lib\windows\python\include\python2.0" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\python\include\python2.0" /I "..\..\..\..\..\lib\windows\python\include\python2.2" /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\gameengine\ketsji" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\GameLogic" /I "..\..\..\..\source\gameengine\expressions" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\ketsji\network\KX_network.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "KX_network - Win32 Release" +# Name "KX_network - Win32 Debug" +# Name "KX_network - Win32 MT DLL Debug" +# Name "KX_network - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkEventManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkMessageActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkMessageSensor.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkObjectActuator.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkObjectSensor.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkEventManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkMessageActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkMessageSensor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkObjectActuator.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Ketsji\KXNetwork\KX_NetworkObjectSensor.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/network/loopbacknetwork/NG_loopbacknetwork.dsp b/projectfiles/gameengine/network/loopbacknetwork/NG_loopbacknetwork.dsp new file mode 100644 index 00000000000..08bd4a1326d --- /dev/null +++ b/projectfiles/gameengine/network/loopbacknetwork/NG_loopbacknetwork.dsp @@ -0,0 +1,155 @@ +# Microsoft Developer Studio Project File - Name="NG_loopbacknetwork" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=NG_loopbacknetwork - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "NG_loopbacknetwork.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "NG_loopbacknetwork.mak" CFG="NG_loopbacknetwork - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "NG_loopbacknetwork - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_loopbacknetwork - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_loopbacknetwork - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_loopbacknetwork - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "NG_loopbacknetwork - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_loopbacknetwork - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_loopbacknetwork - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "NG_loopbacknetwork___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "NG_loopbacknetwork___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\debug\NG_loopbacknetwork.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_loopbacknetwork - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "NG_loopbacknetwork___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "NG_loopbacknetwork___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\source\gameengine\Network" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\network\loopbacknetwork\NG_loopbacknetwork.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "NG_loopbacknetwork - Win32 Release" +# Name "NG_loopbacknetwork - Win32 Debug" +# Name "NG_loopbacknetwork - Win32 MT DLL Debug" +# Name "NG_loopbacknetwork - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\LoopBackNetwork\NG_LoopBackNetworkDeviceInterface.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/network/network/NG_network.dsp b/projectfiles/gameengine/network/network/NG_network.dsp new file mode 100644 index 00000000000..8c13c01f7e7 --- /dev/null +++ b/projectfiles/gameengine/network/network/NG_network.dsp @@ -0,0 +1,174 @@ +# Microsoft Developer Studio Project File - Name="NG_network" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=NG_network - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "NG_network.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "NG_network.mak" CFG="NG_network - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "NG_network - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_network - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_network - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_network - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "NG_network - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\network" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\network" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_network - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\network\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\network\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\..\lib\windows\moto\include" /I "..\..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_network - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "NG_network___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "NG_network___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\network\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\network\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\network\network\debug\NG_network.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_network - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "NG_network___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "NG_network___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\network\network\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\network\network\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\network\network\NG_network.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "NG_network - Win32 Release" +# Name "NG_network - Win32 Debug" +# Name "NG_network - Win32 MT DLL Debug" +# Name "NG_network - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkMessage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkScene.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkDeviceInterface.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkMessage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\NG_NetworkScene.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/network/terraplaynetwork/NG_terraplaynetwork.dsp b/projectfiles/gameengine/network/terraplaynetwork/NG_terraplaynetwork.dsp new file mode 100644 index 00000000000..ce407eda0f7 --- /dev/null +++ b/projectfiles/gameengine/network/terraplaynetwork/NG_terraplaynetwork.dsp @@ -0,0 +1,180 @@ +# Microsoft Developer Studio Project File - Name="NG_terraplaynetwork" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=NG_terraplaynetwork - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "NG_terraplaynetwork.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "NG_terraplaynetwork.mak" CFG="NG_terraplaynetwork - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "NG_terraplaynetwork - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_terraplaynetwork - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_terraplaynetwork - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_terraplaynetwork - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NG_terraplaynetwork - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "NG_terraplaynetwork - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\NG_terraplaynetwork.lib" + +!ELSEIF "$(CFG)" == "NG_terraplaynetwork - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\debug\NG_terraplaynetwork.lib" + +!ELSEIF "$(CFG)" == "NG_terraplaynetwork - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "NG_terraplaynetwork___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "NG_terraplaynetwork___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\debug\NG_terraplaynetwork.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_terraplaynetwork - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "NG_terraplaynetwork___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "NG_terraplaynetwork___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\mtdll" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\NG_terraplaynetwork.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NG_terraplaynetwork - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "NG_terraplaynetwork___Win32_Profile" +# PROP BASE Intermediate_Dir "NG_terraplaynetwork___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "NG_terraplaynetwork___Win32_Profile" +# PROP Intermediate_Dir "NG_terraplaynetwork___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\..\source\gameengine\network" /I "..\..\..\..\source\kernel\gen_system" /I "..\..\..\..\..\lib\windows\terraplay\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\debug\NG_terraplaynetwork.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\network\terraplaynetwork\profile\NG_terraplaynetwork.lib" + +!ENDIF + +# Begin Target + +# Name "NG_terraplaynetwork - Win32 Release" +# Name "NG_terraplaynetwork - Win32 Debug" +# Name "NG_terraplaynetwork - Win32 MT DLL Debug" +# Name "NG_terraplaynetwork - Win32 MT DLL Release" +# Name "NG_terraplaynetwork - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\TerraplayNetwork\NG_TerraplayNetworkDeviceInterface.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Network\TerraplayNetwork\NG_TerraplayNetworkDeviceInterface.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.dsp b/projectfiles/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.dsp new file mode 100644 index 00000000000..0cc26260fd0 --- /dev/null +++ b/projectfiles/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.dsp @@ -0,0 +1,154 @@ +# Microsoft Developer Studio Project File - Name="PHY_Dummy" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PHY_Dummy - Win32 MT DLL Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PHY_Dummy.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PHY_Dummy.mak" CFG="PHY_Dummy - Win32 MT DLL Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PHY_Dummy - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Dummy - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Dummy - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Dummy - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PHY_Dummy - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GR /GX /O2 /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Dummy - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Dummy - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PHY_Dummy___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "PHY_Dummy___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Dummy - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "PHY_Dummy___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "PHY_Dummy___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\mtdll" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\dummy\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "PHY_Dummy - Win32 Release" +# Name "PHY_Dummy - Win32 Debug" +# Name "PHY_Dummy - Win32 MT DLL Debug" +# Name "PHY_Dummy - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Dummy\DummyPhysicsEnvironment.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Dummy\DummyPhysicsEnvironment.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.dsp b/projectfiles/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.dsp new file mode 100644 index 00000000000..fef5dbf63f5 --- /dev/null +++ b/projectfiles/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.dsp @@ -0,0 +1,162 @@ +# Microsoft Developer Studio Project File - Name="PHY_Ode" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PHY_Ode - Win32 MT DLL Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PHY_Ode.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PHY_Ode.mak" CFG="PHY_Ode - Win32 MT DLL Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PHY_Ode - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Ode - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Ode - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Ode - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PHY_Ode - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GR /GX /O2 /I "..\..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\source\gameengine\physics\common" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Ode - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\source\gameengine\physics\common" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Ode - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "PHY_Ode___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "PHY_Ode___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\mtdll" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "../../../../../source/ode/include" /I "..\..\..\..\..\..\lib\windows\ode\include" /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "dSINGLE" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\source\gameengine\physics\common" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Ode - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PHY_Ode___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "PHY_Ode___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\..\obj\windows\gameengine\physics\ode\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../../../../../lib/windows/ode/include" /I "../../../../../source/gameengine/physics/common" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "dSINGLE" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\..\..\lib\windows\ode\include" /I "..\..\..\..\..\source\gameengine\physics\common" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "PHY_Ode - Win32 Release" +# Name "PHY_Ode - Win32 Debug" +# Name "PHY_Ode - Win32 MT DLL Release" +# Name "PHY_Ode - Win32 MT DLL Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\BlOde\OdePhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\BlOde\OdePhysicsEnvironment.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\BlOde\OdePhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\BlOde\OdePhysicsEnvironment.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/physics/PHY_Physics/PHY_Physics.dsp b/projectfiles/gameengine/physics/PHY_Physics/PHY_Physics.dsp new file mode 100644 index 00000000000..f54875c2c18 --- /dev/null +++ b/projectfiles/gameengine/physics/PHY_Physics/PHY_Physics.dsp @@ -0,0 +1,178 @@ +# Microsoft Developer Studio Project File - Name="PHY_Physics" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PHY_Physics - Win32 MT DLL Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PHY_Physics.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PHY_Physics.mak" CFG="PHY_Physics - Win32 MT DLL Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PHY_Physics - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Physics - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Physics - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Physics - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PHY_Physics - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\physics" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\physics" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GR /GX /O2 /I "common" /I "dummy" /I "../../../../extern/solid/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Physics - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\physics\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\physics\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "common" /I "dummy" /I "../../../../extern/solid/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Physics - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "PHY_Physics___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "PHY_Physics___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\physics\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\physics\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "common" /I "dummy" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "common" /I "dummy" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "PHY_Physics - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "PHY_Physics___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "PHY_Physics___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\physics\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\physics\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "common" /I "dummy" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "common" /I "dummy" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "PHY_Physics - Win32 Release" +# Name "PHY_Physics - Win32 Debug" +# Name "PHY_Physics - Win32 MT DLL Debug" +# Name "PHY_Physics - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IMotionState.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IPhysicsEnvironment.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_DynamicTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IMotionState.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_IPhysicsEnvironment.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Physics\common\PHY_Pro.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.dsp b/projectfiles/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.dsp new file mode 100644 index 00000000000..8f148363add --- /dev/null +++ b/projectfiles/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.dsp @@ -0,0 +1,162 @@ +# Microsoft Developer Studio Project File - Name="PHY_Sumo" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=PHY_Sumo - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "PHY_Sumo.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "PHY_Sumo.mak" CFG="PHY_Sumo - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "PHY_Sumo - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "PHY_Sumo - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "PHY_Sumo - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "../../../../../extern/solid" /I "../../../../../source/gameengine/physics" /I "../../../../../source/gameengine/physics/common" /I "../../../../../source/gameengine/physics/sumo" /I "../../../../../source/gameengine/physics/sumo/include" /I "../../../../../source/gameengine/physics/sumo/fuzzics/include" /I "../../../../../../lib/windows/Moto/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\gameengine\physics\sumo\PHY_Sumo.lib" + +!ELSEIF "$(CFG)" == "PHY_Sumo - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../../../../../extern/solid" /I "../../../../../source/gameengine/physics" /I "../../../../../source/gameengine/physics/common" /I "../../../../../source/gameengine/physics/sumo" /I "../../../../../source/gameengine/physics/sumo/include" /I "../../../../../source/gameengine/physics/sumo/fuzzics/include" /I "../../../../../../lib/windows/Moto/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\gameengine\physics\sumo\debug\PHY_Sumo.lib" + +!ENDIF + +# Begin Target + +# Name "PHY_Sumo - Win32 Release" +# Name "PHY_Sumo - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_FhObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_MotionState.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_Object.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_Scene.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPHYCallbackBridge.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPhysicsController.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPhysicsEnvironment.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_ClientObjectInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_FhObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_MotionState.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Object.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Props.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Scene.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPHYCallbackBridge.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPhysicsController.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\..\source\gameengine\Physics\Sumo\SumoPhysicsEnvironment.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/rasterizer/RAS_rasterizer.dsp b/projectfiles/gameengine/rasterizer/RAS_rasterizer.dsp new file mode 100644 index 00000000000..c764823632e --- /dev/null +++ b/projectfiles/gameengine/rasterizer/RAS_rasterizer.dsp @@ -0,0 +1,243 @@ +# Microsoft Developer Studio Project File - Name="RAS_rasterizer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=RAS_rasterizer - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "RAS_rasterizer.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "RAS_rasterizer.mak" CFG="RAS_rasterizer - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "RAS_rasterizer - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_rasterizer - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_rasterizer - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_rasterizer - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "RAS_rasterizer - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\rasterizer" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\rasterizer" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\lib\windows\moto\include\\" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "RAS_rasterizer - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\rasterizer\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\rasterizer\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\lib\windows\moto\include\\" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "RAS_rasterizer - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "RAS_rasterizer___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "RAS_rasterizer___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\rasterizer\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\rasterizer\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "../../../../lib/windows/moto/include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\rasterizer\debug\RAS_rasterizer.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "RAS_rasterizer - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "RAS_rasterizer___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "RAS_rasterizer___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\rasterizer\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\rasterizer\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "../../../../lib/windows/moto/include" /I "..\..\..\..\lib\windows\string\include" /I "..\..\..\source\kernel\gen_system" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\rasterizer\RAS_rasterizer.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "RAS_rasterizer - Win32 Release" +# Name "RAS_rasterizer - Win32 Debug" +# Name "RAS_rasterizer - Win32 MT DLL Debug" +# Name "RAS_rasterizer - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_BucketManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_FramingManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_MeshObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_Polygon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_texmatrix.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_TexVert.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_BucketManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_CameraData.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_Deformer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_FramingManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_ICanvas.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IPolygonMaterial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IRasterizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_IRenderTools.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_LightObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_MaterialBucket.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_MeshObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_ObjectColor.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_Polygon.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_TexMatrix.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Rasterizer\RAS_TexVert.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.dsp b/projectfiles/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.dsp new file mode 100644 index 00000000000..1f1b95291ed --- /dev/null +++ b/projectfiles/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.dsp @@ -0,0 +1,183 @@ +# Microsoft Developer Studio Project File - Name="RAS_openglrasterizer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=RAS_openglrasterizer - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "RAS_openglrasterizer.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "RAS_openglrasterizer.mak" CFG="RAS_openglrasterizer - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "RAS_openglrasterizer - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_openglrasterizer - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_openglrasterizer - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "RAS_openglrasterizer - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "RAS_openglrasterizer - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "RAS_openglrasterizer - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "RAS_openglrasterizer - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "RAS_openglrasterizer___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "RAS_openglrasterizer___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\debug\RAS_openglrasterizer.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "RAS_openglrasterizer - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "RAS_openglrasterizer___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "RAS_openglrasterizer___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +MTL=midl.exe +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\..\source\kernel\gen_system" /I ".../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\..\lib\windows\string\include" /I "..\..\..\..\source\kernel\gen_system" /I "../../../../../lib/windows/moto/include" /I "..\..\..\..\source\gameengine\Rasterizer" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\..\obj\windows\gameengine\rasterizer\openglrasterizer\RAS_openglrasterizer.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "RAS_openglrasterizer - Win32 Release" +# Name "RAS_openglrasterizer - Win32 Debug" +# Name "RAS_openglrasterizer - Win32 MT DLL Debug" +# Name "RAS_openglrasterizer - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_GLExtensionManager.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_ListRasterizer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_OpenGLRasterizer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_VAOpenGLRasterizer.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_GLExtensionManager.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_ListRasterizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_OpenGLRasterizer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\source\gameengine\Rasterizer\RAS_OpenGLRasterizer\RAS_VAOpenGLRasterizer.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/gameengine/scenegraph/SG_scenegraph.dsp b/projectfiles/gameengine/scenegraph/SG_scenegraph.dsp new file mode 100644 index 00000000000..5a2b4c8cba3 --- /dev/null +++ b/projectfiles/gameengine/scenegraph/SG_scenegraph.dsp @@ -0,0 +1,199 @@ +# Microsoft Developer Studio Project File - Name="SG_SceneGraph" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SG_SceneGraph - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SG_SceneGraph.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SG_SceneGraph.mak" CFG="SG_SceneGraph - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SG_SceneGraph - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SG_SceneGraph - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SG_SceneGraph - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SG_SceneGraph - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SG_SceneGraph - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\scenegraph" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\scenegraph" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SG_SceneGraph - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\scenegraph\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\scenegraph\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SG_SceneGraph - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SG_SceneGraph___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SG_SceneGraph___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\scenegraph\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\scenegraph\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "../../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\scenegraph\debug\SG_SceneGraph.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SG_SceneGraph - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SG_SceneGraph___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SG_SceneGraph___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\scenegraph\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\scenegraph\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "../../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\scenegraph\SG_SceneGraph.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SG_SceneGraph - Win32 Release" +# Name "SG_SceneGraph - Win32 Debug" +# Name "SG_SceneGraph - Win32 MT DLL Debug" +# Name "SG_SceneGraph - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_BBox.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Controller.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_IObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Node.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Spatial.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Tree.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_BBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Controller.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_IObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Node.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_ParentRelation.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Spatial.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\SceneGraph\SG_Tree.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/kernel/gen_messaging/gen_messaging.dsp b/projectfiles/kernel/gen_messaging/gen_messaging.dsp new file mode 100644 index 00000000000..578f8971122 --- /dev/null +++ b/projectfiles/kernel/gen_messaging/gen_messaging.dsp @@ -0,0 +1,155 @@ +# Microsoft Developer Studio Project File - Name="gen_messaging" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=gen_messaging - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gen_messaging.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gen_messaging.mak" CFG="gen_messaging - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gen_messaging - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "gen_messaging - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "gen_messaging - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "gen_messaging - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gen_messaging - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\kernel\gen_messaging" +# PROP Intermediate_Dir "..\..\..\obj\windows\kernel\gen_messaging" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gen_messaging - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\kernel\gen_messaging\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\kernel\gen_messaging\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gen_messaging - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gen_messaging___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "gen_messaging___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\kernel\gen_messaging\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\kernel\gen_messaging\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gen_messaging - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "gen_messaging___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "gen_messaging___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\kernel\gen_messaging\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\kernel\gen_messaging\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\source\kernel\gen_messaging" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "gen_messaging - Win32 Release" +# Name "gen_messaging - Win32 Debug" +# Name "gen_messaging - Win32 MT DLL Release" +# Name "gen_messaging - Win32 MT DLL Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_messaging\intern\messaging.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_messaging\GEN_messaging.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/kernel/system/SYS_system.dsp b/projectfiles/kernel/system/SYS_system.dsp new file mode 100644 index 00000000000..b424839e4ba --- /dev/null +++ b/projectfiles/kernel/system/SYS_system.dsp @@ -0,0 +1,183 @@ +# Microsoft Developer Studio Project File - Name="SYS_system" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SYS_system - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SYS_system.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SYS_system.mak" CFG="SYS_system - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SYS_system - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SYS_system - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SYS_system - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SYS_system - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SYS_system - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\..\lib\windows\string\include" /I "../../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SYS_system - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\..\lib\windows\string\include" /I "../../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SYS_system - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SYS_system___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SYS_system___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /MDd /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\..\lib\windows\string\include" /I "../../../../../lib/windows/moto/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\kernel\gen_system\debug\SYS_system.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SYS_system - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SYS_system___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SYS_system___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\gameengine\kernel\gen_system\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\..\lib\windows\string\include" /I "../../../../../lib/windows/moto/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\gameengine\kernel\gen_system\SYS_system.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SYS_system - Win32 Release" +# Name "SYS_system - Win32 Debug" +# Name "SYS_system - Win32 MT DLL Debug" +# Name "SYS_system - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_HashedPtr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\SYS_SingletonSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\SYS_System.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_DataCache.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_HashedPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\GEN_SmartPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\SYS_SingletonSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\kernel\gen_system\SYS_System.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/sumo/fuzzics/SM_fuzzics.dsp b/projectfiles/sumo/fuzzics/SM_fuzzics.dsp new file mode 100644 index 00000000000..c415810d2c9 --- /dev/null +++ b/projectfiles/sumo/fuzzics/SM_fuzzics.dsp @@ -0,0 +1,216 @@ +# Microsoft Developer Studio Project File - Name="SM_fuzzics" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_fuzzics - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SM_fuzzics.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SM_fuzzics.mak" CFG="SM_fuzzics - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_fuzzics - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_fuzzics - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_fuzzics - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_fuzzics - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_fuzzics - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_fuzzics - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\sumo\fuzzics" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\fuzzics" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "../../../extern/solid" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_fuzzics - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\sumo\fuzzics\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\fuzzics\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\source\gameengine\physics\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "../../../extern/solid" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_fuzzics - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_fuzzics___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_fuzzics___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\fuzzics\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\fuzzics\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\fuzzics\debug\SM_fuzzics.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_fuzzics - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_fuzzics___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_fuzzics___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\fuzzics\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\fuzzics\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\fuzzics\SM_fuzzics.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_fuzzics - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_fuzzics___Win32_Profile" +# PROP BASE Intermediate_Dir "SM_fuzzics___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "SM_fuzzics___Win32_Profile" +# PROP Intermediate_Dir "SM_fuzzics___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\Fuzzics\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\fuzzics\debug\SM_fuzzics.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\fuzzics\profile\SM_fuzzics.lib" + +!ENDIF + +# Begin Target + +# Name "SM_fuzzics - Win32 Release" +# Name "SM_fuzzics - Win32 Debug" +# Name "SM_fuzzics - Win32 MT DLL Debug" +# Name "SM_fuzzics - Win32 MT DLL Release" +# Name "SM_fuzzics - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_FhObject.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_Object.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\src\SM_Scene.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Callback.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_ClientObjectInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Debug.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_FhObject.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_MotionState.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Object.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Props.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\gameengine\Physics\Sumo\Fuzzics\include\SM_Scene.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/sumo/moto/SM_moto.dsp b/projectfiles/sumo/moto/SM_moto.dsp new file mode 100644 index 00000000000..3fd627ce60d --- /dev/null +++ b/projectfiles/sumo/moto/SM_moto.dsp @@ -0,0 +1,332 @@ +# Microsoft Developer Studio Project File - Name="SM_moto" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_moto - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SM_moto.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SM_moto.mak" CFG="SM_moto - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_moto - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_moto - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\lib\windows\moto\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\SM_moto.lib" + +!ELSEIF "$(CFG)" == "SM_moto - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" + +!ELSEIF "$(CFG)" == "SM_moto - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_moto___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_moto___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_moto - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_moto___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_moto___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\MoTo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\sumo\MoTo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\moto\SM_moto.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_moto - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_moto___Win32_Profile" +# PROP BASE Intermediate_Dir "SM_moto___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "SM_moto___Win32_Profile" +# PROP Intermediate_Dir "SM_moto___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\profile\SM_moto.lib" + +!ENDIF + +# Begin Target + +# Name "SM_moto - Win32 Release" +# Name "SM_moto - Win32 Debug" +# Name "SM_moto - Win32 MT DLL Debug" +# Name "SM_moto - Win32 MT DLL Release" +# Name "SM_moto - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_CmMatrix4x4.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Matrix3x3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Matrix4x4.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Point3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Quaternion.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_random.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Transform.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector4.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\GEN_List.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\GEN_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_assert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_CmMatrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix3x3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix3x3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix4x4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_MinMax.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Optimize.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Quaternion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Quaternion.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_random.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Scalar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Stream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\NM_Scalar.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles/sumo/solid/SM_solid.dsp b/projectfiles/sumo/solid/SM_solid.dsp new file mode 100644 index 00000000000..dfaa85c35d8 --- /dev/null +++ b/projectfiles/sumo/solid/SM_solid.dsp @@ -0,0 +1,340 @@ +# Microsoft Developer Studio Project File - Name="SM_solid" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_solid - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SM_solid.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SM_solid.mak" CFG="SM_solid - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_solid - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_solid - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /J /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_solid - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_solid - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_solid___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_solid___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\SOLID-3.0\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\solid\debug\SM_solid.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_solid - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_solid___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_solid___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\SOLID-3.0\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\solid\SM_solid.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SM_solid - Win32 Release" +# Name "SM_solid - Win32 Debug" +# Name "SM_solid - Win32 MT DLL Debug" +# Name "SM_solid - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\BBoxTree.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Box.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Complex.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Cone.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Convex.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Cylinder.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Endpoint.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Proxy.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Scene.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_DoubleBase.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Encounter.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_FloatBase.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_LineSegment.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Object.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_RespTable.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Scene.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Polyhedron.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Polytope.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Sphere.cpp" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\AlgoTable.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\BBoxTree.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Box.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Complex.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Cone.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Convex.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Cylinder.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_AABBox.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BBox.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Endpoint.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Proxy.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Scene.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_DoubleBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Encounter.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_FloatBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_LineSegment.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Object.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Response.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_RespTable.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Scene.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_VertexBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_VertexBased.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\IndexArray.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Polyhedron.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Polytope.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Shape.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Sphere.h" +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles_vc7/blender/BLO_readblenfile/BLO_readblenfile.vcproj b/projectfiles_vc7/blender/BLO_readblenfile/BLO_readblenfile.vcproj new file mode 100644 index 00000000000..3618ac56296 --- /dev/null +++ b/projectfiles_vc7/blender/BLO_readblenfile/BLO_readblenfile.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/BPY_python/BPY_python.vcproj b/projectfiles_vc7/blender/BPY_python/BPY_python.vcproj new file mode 100644 index 00000000000..ac933502efb --- /dev/null +++ b/projectfiles_vc7/blender/BPY_python/BPY_python.vcproj @@ -0,0 +1,561 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/avi/BL_avi.vcproj b/projectfiles_vc7/blender/avi/BL_avi.vcproj new file mode 100644 index 00000000000..302586b1dc3 --- /dev/null +++ b/projectfiles_vc7/blender/avi/BL_avi.vcproj @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blender.sln b/projectfiles_vc7/blender/blender.sln new file mode 100644 index 00000000000..0888cf7971a --- /dev/null +++ b/projectfiles_vc7/blender/blender.sln @@ -0,0 +1,815 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blender", "blender.vcproj", "{F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}" + ProjectSection(ProjectDependencies) = postProject + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} = {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} + {6E24BF09-9653-4166-A871-F65CC9E98A9B} = {6E24BF09-9653-4166-A871-F65CC9E98A9B} + {FB88301F-F725-401B-ACD7-D2ABBF333B71} = {FB88301F-F725-401B-ACD7-D2ABBF333B71} + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} = {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} + {9625642D-6F20-4FB6-A089-BE7441B223E3} = {9625642D-6F20-4FB6-A089-BE7441B223E3} + {E645CC32-4823-463E-82F0-46ADDE664018} = {E645CC32-4823-463E-82F0-46ADDE664018} + {51FB3D48-2467-4BFA-A321-D848252B437E} = {51FB3D48-2467-4BFA-A321-D848252B437E} + {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718} + {EADC3C5A-6C51-4F03-8038-1553E7D7F740} = {EADC3C5A-6C51-4F03-8038-1553E7D7F740} + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} = {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} = {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} + {09222F5E-1625-4FF3-A89A-384D16875EE5} = {09222F5E-1625-4FF3-A89A-384D16875EE5} + {E013786A-9575-4F34-81B2-33290357EE87} = {E013786A-9575-4F34-81B2-33290357EE87} + {415BFD6E-64CF-422B-AF88-C07F040A7292} = {415BFD6E-64CF-422B-AF88-C07F040A7292} + {106AE171-0083-41D6-A949-20DB0E8DC251} = {106AE171-0083-41D6-A949-20DB0E8DC251} + {4C3AB78A-52CA-4276-A041-39776E52D8C8} = {4C3AB78A-52CA-4276-A041-39776E52D8C8} + {6B801390-5F95-4F07-81A7-97FBA046AACC} = {6B801390-5F95-4F07-81A7-97FBA046AACC} + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} = {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} + {F90BD995-FFA4-4B18-81E8-FA4322C939E8} = {F90BD995-FFA4-4B18-81E8-FA4322C939E8} + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} = {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} + {8154A59A-CAED-403D-AB94-BC4E7C032666} = {8154A59A-CAED-403D-AB94-BC4E7C032666} + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} = {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} = {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} = {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90} = {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90} + {E90C7BC2-CF30-4A60-A8F2-0050D592E358} = {E90C7BC2-CF30-4A60-A8F2-0050D592E358} + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879} = {9991A3C3-83FE-4AFE-9E18-9D01CB57E879} + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49} = {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49} + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA} = {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA} + {32CC75E2-EE85-45E6-8E3D-513F58464F43} = {32CC75E2-EE85-45E6-8E3D-513F58464F43} + {9A307EE5-CD77-47BC-BD87-62508C7E19D8} = {9A307EE5-CD77-47BC-BD87-62508C7E19D8} + {AB590CED-F71F-4A17-A89B-18583ECD633D} = {AB590CED-F71F-4A17-A89B-18583ECD633D} + {64019BFA-8C14-4FA6-B275-D7598D821FF6} = {64019BFA-8C14-4FA6-B275-D7598D821FF6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BKE_blenkernel", "blenkernel\BKE_blenkernel.vcproj", "{CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BLI_blenlib", "blenlib\BLI_blenlib.vcproj", "{31628053-825D-4C06-8A21-D13883489718}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BLO_loader", "loader\BLO_loader.vcproj", "{E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BLO_readblenfile", "BLO_readblenfile\BLO_readblenfile.vcproj", "{DB6BE55D-B6D9-494D-856A-8764FF7BA91D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_avi", "avi\BL_avi.vcproj", "{9A307EE5-CD77-47BC-BD87-62508C7E19D8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_imbuf", "imbuf\BL_imbuf.vcproj", "{415BFD6E-64CF-422B-AF88-C07F040A7292}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_src", "src\BL_src.vcproj", "{FB88301F-F725-401B-ACD7-D2ABBF333B71}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_src_cre", "src\BL_src_cre.vcproj", "{64019BFA-8C14-4FA6-B275-D7598D821FF6}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BPY_python", "BPY_python\BPY_python.vcproj", "{5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BRA_radiosity", "radiosity\BRA_radiosity.vcproj", "{2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BRE_render", "render\BRE_render.vcproj", "{106AE171-0083-41D6-A949-20DB0E8DC251}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DNA_makesdna", "makesdna\DNA_makesdna.vcproj", "{E013786A-9575-4F34-81B2-33290357EE87}" + ProjectSection(ProjectDependencies) = postProject + {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EXP_expressions", "..\gameengine\expression\EXP_expressions.vcproj", "{EADC3C5A-6C51-4F03-8038-1553E7D7F740}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FTF_ftfont", "ftfont\FTF_ftfont.vcproj", "{A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GP_axctl", "..\gameengine\gameplayer\axctl\GP_axctl.vcproj", "{DF25E6F2-780C-438B-8AAD-D10CF8B3820A}" + ProjectSection(ProjectDependencies) = postProject + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} = {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} + {6E24BF09-9653-4166-A871-F65CC9E98A9B} = {6E24BF09-9653-4166-A871-F65CC9E98A9B} + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} = {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} + {9625642D-6F20-4FB6-A089-BE7441B223E3} = {9625642D-6F20-4FB6-A089-BE7441B223E3} + {E645CC32-4823-463E-82F0-46ADDE664018} = {E645CC32-4823-463E-82F0-46ADDE664018} + {51FB3D48-2467-4BFA-A321-D848252B437E} = {51FB3D48-2467-4BFA-A321-D848252B437E} + {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718} + {EADC3C5A-6C51-4F03-8038-1553E7D7F740} = {EADC3C5A-6C51-4F03-8038-1553E7D7F740} + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} = {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} = {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} + {09222F5E-1625-4FF3-A89A-384D16875EE5} = {09222F5E-1625-4FF3-A89A-384D16875EE5} + {E013786A-9575-4F34-81B2-33290357EE87} = {E013786A-9575-4F34-81B2-33290357EE87} + {415BFD6E-64CF-422B-AF88-C07F040A7292} = {415BFD6E-64CF-422B-AF88-C07F040A7292} + {4C3AB78A-52CA-4276-A041-39776E52D8C8} = {4C3AB78A-52CA-4276-A041-39776E52D8C8} + {6B801390-5F95-4F07-81A7-97FBA046AACC} = {6B801390-5F95-4F07-81A7-97FBA046AACC} + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} = {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} + {F90BD995-FFA4-4B18-81E8-FA4322C939E8} = {F90BD995-FFA4-4B18-81E8-FA4322C939E8} + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} = {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} = {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0} = {D8ABD6A5-1B36-4D62-934E-B5C6801130B0} + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} = {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} = {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} + {E90C7BC2-CF30-4A60-A8F2-0050D592E358} = {E90C7BC2-CF30-4A60-A8F2-0050D592E358} + {32CC75E2-EE85-45E6-8E3D-513F58464F43} = {32CC75E2-EE85-45E6-8E3D-513F58464F43} + {9A307EE5-CD77-47BC-BD87-62508C7E19D8} = {9A307EE5-CD77-47BC-BD87-62508C7E19D8} + {AB590CED-F71F-4A17-A89B-18583ECD633D} = {AB590CED-F71F-4A17-A89B-18583ECD633D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GP_common", "..\gameengine\gameplayer\common\GP_common.vcproj", "{D8ABD6A5-1B36-4D62-934E-B5C6801130B0}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GP_ghost", "..\gameengine\gameplayer\ghost\GP_ghost.vcproj", "{3D310C60-6771-48E4-BCCA-D2718CDED898}" + ProjectSection(ProjectDependencies) = postProject + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} = {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F} + {6E24BF09-9653-4166-A871-F65CC9E98A9B} = {6E24BF09-9653-4166-A871-F65CC9E98A9B} + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} = {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE} + {9625642D-6F20-4FB6-A089-BE7441B223E3} = {9625642D-6F20-4FB6-A089-BE7441B223E3} + {E645CC32-4823-463E-82F0-46ADDE664018} = {E645CC32-4823-463E-82F0-46ADDE664018} + {51FB3D48-2467-4BFA-A321-D848252B437E} = {51FB3D48-2467-4BFA-A321-D848252B437E} + {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718} + {EADC3C5A-6C51-4F03-8038-1553E7D7F740} = {EADC3C5A-6C51-4F03-8038-1553E7D7F740} + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} = {DB6BE55D-B6D9-494D-856A-8764FF7BA91D} + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} = {0A73055E-4DED-40CD-9F72-9093ED3EEC7E} + {09222F5E-1625-4FF3-A89A-384D16875EE5} = {09222F5E-1625-4FF3-A89A-384D16875EE5} + {E013786A-9575-4F34-81B2-33290357EE87} = {E013786A-9575-4F34-81B2-33290357EE87} + {415BFD6E-64CF-422B-AF88-C07F040A7292} = {415BFD6E-64CF-422B-AF88-C07F040A7292} + {4C3AB78A-52CA-4276-A041-39776E52D8C8} = {4C3AB78A-52CA-4276-A041-39776E52D8C8} + {6B801390-5F95-4F07-81A7-97FBA046AACC} = {6B801390-5F95-4F07-81A7-97FBA046AACC} + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} = {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} + {F90BD995-FFA4-4B18-81E8-FA4322C939E8} = {F90BD995-FFA4-4B18-81E8-FA4322C939E8} + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} = {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23} + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} = {3648FB9A-C36F-43AB-AED0-1F1361E67FC7} + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0} = {D8ABD6A5-1B36-4D62-934E-B5C6801130B0} + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} = {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B} + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} = {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA} + {E90C7BC2-CF30-4A60-A8F2-0050D592E358} = {E90C7BC2-CF30-4A60-A8F2-0050D592E358} + {32CC75E2-EE85-45E6-8E3D-513F58464F43} = {32CC75E2-EE85-45E6-8E3D-513F58464F43} + {9A307EE5-CD77-47BC-BD87-62508C7E19D8} = {9A307EE5-CD77-47BC-BD87-62508C7E19D8} + {AB590CED-F71F-4A17-A89B-18583ECD633D} = {AB590CED-F71F-4A17-A89B-18583ECD633D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KX_blenderhook", "..\gameengine\blenderhook\KX_blenderhook.vcproj", "{8154A59A-CAED-403D-AB94-BC4E7C032666}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KX_converter", "..\gameengine\converter\KX_converter.vcproj", "{F90BD995-FFA4-4B18-81E8-FA4322C939E8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KX_ketsji", "..\gameengine\ketsji\KX_ketsji.vcproj", "{E645CC32-4823-463E-82F0-46ADDE664018}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KX_network", "..\gameengine\ketsji\network\KX_network.vcproj", "{6E24BF09-9653-4166-A871-F65CC9E98A9B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NG_loopbacknetwork", "..\gameengine\network\loopbacknetwork\NG_loopbacknetwork.vcproj", "{6B801390-5F95-4F07-81A7-97FBA046AACC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NG_network", "..\gameengine\network\network\NG_network.vcproj", "{0A73055E-4DED-40CD-9F72-9093ED3EEC7E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Dummy", "..\GAMEENGINE\PHYSICS\PHY_PHYSICS\PHY_Dummy\PHY_Dummy.vcproj", "{3648FB9A-C36F-43AB-AED0-1F1361E67FC7}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Ode", "..\gameengine\physics\PHY_Physics\PHY_Ode\PHY_Ode.vcproj", "{EC405272-28E3-4840-AAC2-53D6DE4E163D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Physics", "..\gameengine\physics\PHY_Physics\PHY_Physics.vcproj", "{E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RAS_openglrasterizer", "..\gameengine\rasterizer\openglrasterizer\RAS_openglrasterizer.vcproj", "{AB590CED-F71F-4A17-A89B-18583ECD633D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RAS_rasterizer", "..\gameengine\rasterizer\RAS_rasterizer.vcproj", "{51FB3D48-2467-4BFA-A321-D848252B437E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SCA_GameLogic", "..\gameengine\gamelogic\SCA_GameLogic.vcproj", "{32CC75E2-EE85-45E6-8E3D-513F58464F43}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SG_SceneGraph", "..\gameengine\scenegraph\SG_SceneGraph.vcproj", "{09222F5E-1625-4FF3-A89A-384D16875EE5}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SYS_system", "..\kernel\system\SYS_system.vcproj", "{BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blenpluginapi", "blenpluginapi\blenpluginapi\blenpluginapi.vcproj", "{BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gen_messaging", "..\KERNEL\gen_messaging\gen_messaging.vcproj", "{727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Sumo", "..\gameengine\physics\PHY_Physics\PHY_Sumo\PHY_Sumo.vcproj", "{9625642D-6F20-4FB6-A089-BE7441B223E3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BRE_yafray", "yafray\BRE_yafray.vcproj", "{9991A3C3-83FE-4AFE-9E18-9D01CB57E879}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PHY_Bullet", "..\gameengine\physics\PHY_Physics\PHY_Bullet\PHY_Bullet.vcproj", "{E90C7BC2-CF30-4A60-A8F2-0050D592E358}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_nodes", "nodes\nodes.vcproj", "{4C3AB78A-52CA-4276-A041-39776E52D8C8}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + 3D Plugin Debug = 3D Plugin Debug + 3D Plugin Release = 3D Plugin Release + Blender Debug = Blender Debug + Blender Release = Blender Release + BlenderPlayer Debug = BlenderPlayer Debug + BlenderPlayer Release = BlenderPlayer Release + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Blender Debug.Build.0 = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Blender Release.ActiveCfg = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Blender Release.Build.0 = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Debug.ActiveCfg = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Debug.Build.0 = Blender Debug|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Release.ActiveCfg = Blender Release|Win32 + {F78B7FC9-DE32-465E-9F26-BB0B6B7A2EAF}.Release.Build.0 = Blender Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Blender Debug.Build.0 = Blender Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Blender Release.ActiveCfg = Blender Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Blender Release.Build.0 = Blender Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}.Release.Build.0 = BlenderPlayer Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Blender Debug.Build.0 = Blender Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Blender Release.ActiveCfg = Blender Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Blender Release.Build.0 = Blender Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {31628053-825D-4C06-8A21-D13883489718}.Release.Build.0 = BlenderPlayer Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Blender Debug.Build.0 = Blender Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Blender Release.ActiveCfg = Blender Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Blender Release.Build.0 = Blender Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {E5F2F004-C704-4DCC-A08F-6EB1E38EAB9F}.Release.Build.0 = BlenderPlayer Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Blender Debug.Build.0 = Blender Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Blender Release.ActiveCfg = Blender Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Blender Release.Build.0 = Blender Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {DB6BE55D-B6D9-494D-856A-8764FF7BA91D}.Release.Build.0 = BlenderPlayer Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Blender Debug.Build.0 = Blender Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Blender Release.ActiveCfg = Blender Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Blender Release.Build.0 = Blender Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {9A307EE5-CD77-47BC-BD87-62508C7E19D8}.Release.Build.0 = BlenderPlayer Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Blender Debug.Build.0 = Blender Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Blender Release.ActiveCfg = Blender Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Blender Release.Build.0 = Blender Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {415BFD6E-64CF-422B-AF88-C07F040A7292}.Release.Build.0 = BlenderPlayer Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Blender Debug.Build.0 = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Blender Release.ActiveCfg = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Blender Release.Build.0 = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Debug.ActiveCfg = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Debug.Build.0 = Blender Debug|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Release.ActiveCfg = Blender Release|Win32 + {FB88301F-F725-401B-ACD7-D2ABBF333B71}.Release.Build.0 = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Blender Debug.Build.0 = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Blender Release.ActiveCfg = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Blender Release.Build.0 = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Debug.ActiveCfg = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Debug.Build.0 = Blender Debug|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Release.ActiveCfg = Blender Release|Win32 + {64019BFA-8C14-4FA6-B275-D7598D821FF6}.Release.Build.0 = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Blender Debug.Build.0 = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Blender Release.ActiveCfg = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Blender Release.Build.0 = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Debug.ActiveCfg = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Debug.Build.0 = Blender Debug|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Release.ActiveCfg = Blender Release|Win32 + {5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}.Release.Build.0 = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Blender Debug.Build.0 = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Blender Release.ActiveCfg = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Blender Release.Build.0 = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Debug.ActiveCfg = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Debug.Build.0 = Blender Debug|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Release.ActiveCfg = Blender Release|Win32 + {2AE0D2D9-6A7A-44DE-9EFF-99C9E3257B49}.Release.Build.0 = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Blender Debug.Build.0 = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Blender Release.ActiveCfg = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Blender Release.Build.0 = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Debug.ActiveCfg = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Debug.Build.0 = Blender Debug|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Release.ActiveCfg = Blender Release|Win32 + {106AE171-0083-41D6-A949-20DB0E8DC251}.Release.Build.0 = Blender Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Blender Debug.Build.0 = Blender Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Blender Release.ActiveCfg = Blender Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Blender Release.Build.0 = Blender Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {E013786A-9575-4F34-81B2-33290357EE87}.Release.Build.0 = BlenderPlayer Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Blender Debug.Build.0 = Blender Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Blender Release.ActiveCfg = Blender Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Blender Release.Build.0 = Blender Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {EADC3C5A-6C51-4F03-8038-1553E7D7F740}.Release.Build.0 = BlenderPlayer Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Blender Debug.Build.0 = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Blender Release.ActiveCfg = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Blender Release.Build.0 = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Debug.ActiveCfg = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Debug.Build.0 = Blender Debug|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Release.ActiveCfg = Blender Release|Win32 + {A1CCF5B0-08E1-4F00-B417-8BFAC34E5E90}.Release.Build.0 = Blender Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Blender Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Blender Release.ActiveCfg = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.BlenderPlayer Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.BlenderPlayer Release.ActiveCfg = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Debug.ActiveCfg = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Debug.Build.0 = 3D Plugin Debug|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Release.ActiveCfg = 3D Plugin Release|Win32 + {DF25E6F2-780C-438B-8AAD-D10CF8B3820A}.Release.Build.0 = 3D Plugin Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Blender Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Blender Release.ActiveCfg = BlenderPlayer Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {D8ABD6A5-1B36-4D62-934E-B5C6801130B0}.Release.Build.0 = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.3D Plugin Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.3D Plugin Release.ActiveCfg = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Blender Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Blender Release.ActiveCfg = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {3D310C60-6771-48E4-BCCA-D2718CDED898}.Release.Build.0 = BlenderPlayer Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Blender Debug.Build.0 = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Blender Release.ActiveCfg = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Blender Release.Build.0 = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Debug.ActiveCfg = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Debug.Build.0 = Blender Debug|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Release.ActiveCfg = Blender Release|Win32 + {8154A59A-CAED-403D-AB94-BC4E7C032666}.Release.Build.0 = Blender Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Blender Debug.Build.0 = Blender Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Blender Release.ActiveCfg = Blender Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Blender Release.Build.0 = Blender Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {F90BD995-FFA4-4B18-81E8-FA4322C939E8}.Release.Build.0 = BlenderPlayer Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Blender Debug.Build.0 = Blender Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Blender Release.ActiveCfg = Blender Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Blender Release.Build.0 = Blender Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {E645CC32-4823-463E-82F0-46ADDE664018}.Release.Build.0 = BlenderPlayer Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Blender Debug.Build.0 = Blender Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Blender Release.ActiveCfg = Blender Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Blender Release.Build.0 = Blender Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {6E24BF09-9653-4166-A871-F65CC9E98A9B}.Release.Build.0 = BlenderPlayer Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Blender Debug.Build.0 = Blender Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Blender Release.ActiveCfg = Blender Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Blender Release.Build.0 = Blender Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {6B801390-5F95-4F07-81A7-97FBA046AACC}.Release.Build.0 = BlenderPlayer Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Blender Debug.Build.0 = Blender Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Blender Release.ActiveCfg = Blender Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Blender Release.Build.0 = Blender Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {0A73055E-4DED-40CD-9F72-9093ED3EEC7E}.Release.Build.0 = BlenderPlayer Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Blender Debug.Build.0 = Blender Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Blender Release.ActiveCfg = Blender Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Blender Release.Build.0 = Blender Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {3648FB9A-C36F-43AB-AED0-1F1361E67FC7}.Release.Build.0 = BlenderPlayer Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Blender Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Blender Release.ActiveCfg = BlenderPlayer Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {EC405272-28E3-4840-AAC2-53D6DE4E163D}.Release.Build.0 = BlenderPlayer Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Blender Debug.Build.0 = Blender Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Blender Release.ActiveCfg = Blender Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Blender Release.Build.0 = Blender Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {E109F1A5-FDD3-4F56-A1C4-96867EEA4C5B}.Release.Build.0 = BlenderPlayer Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Blender Debug.Build.0 = Blender Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Blender Release.ActiveCfg = Blender Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Blender Release.Build.0 = Blender Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {AB590CED-F71F-4A17-A89B-18583ECD633D}.Release.Build.0 = BlenderPlayer Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Blender Debug.Build.0 = Blender Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Blender Release.ActiveCfg = Blender Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Blender Release.Build.0 = Blender Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {51FB3D48-2467-4BFA-A321-D848252B437E}.Release.Build.0 = BlenderPlayer Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Blender Debug.Build.0 = Blender Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Blender Release.ActiveCfg = Blender Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Blender Release.Build.0 = Blender Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {32CC75E2-EE85-45E6-8E3D-513F58464F43}.Release.Build.0 = BlenderPlayer Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Blender Debug.Build.0 = Blender Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Blender Release.ActiveCfg = Blender Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Blender Release.Build.0 = Blender Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {09222F5E-1625-4FF3-A89A-384D16875EE5}.Release.Build.0 = BlenderPlayer Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Blender Debug.Build.0 = Blender Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Blender Release.ActiveCfg = Blender Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Blender Release.Build.0 = Blender Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {BAAE3F2B-BCF8-4E84-B8BA-CFB2D64945FE}.Release.Build.0 = BlenderPlayer Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Blender Debug.Build.0 = Blender Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Blender Release.ActiveCfg = Blender Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Blender Release.Build.0 = Blender Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Debug.ActiveCfg = 3D Plugin Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Debug.Build.0 = 3D Plugin Debug|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {BB6AA598-B336-4F8B-9DF9-8CAE7BE71C23}.Release.Build.0 = BlenderPlayer Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Blender Debug.Build.0 = Blender Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Blender Release.ActiveCfg = Blender Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Blender Release.Build.0 = Blender Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Debug.Build.0 = BlenderPlayer Debug|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {727F90AC-ABE6-40BF-8937-C2F2F1D13DEA}.Release.Build.0 = BlenderPlayer Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Blender Debug.Build.0 = Blender Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Blender Release.ActiveCfg = Blender Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Blender Release.Build.0 = Blender Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Debug.ActiveCfg = 3D Plugin Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Debug.Build.0 = 3D Plugin Debug|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Release.ActiveCfg = BlenderPlayer Release|Win32 + {9625642D-6F20-4FB6-A089-BE7441B223E3}.Release.Build.0 = BlenderPlayer Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.3D Plugin Debug.ActiveCfg = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Blender Debug.Build.0 = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Blender Release.ActiveCfg = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Blender Release.Build.0 = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Debug.ActiveCfg = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Debug.Build.0 = Blender Debug|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Release.ActiveCfg = Blender Release|Win32 + {9991A3C3-83FE-4AFE-9E18-9D01CB57E879}.Release.Build.0 = Blender Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.3D Plugin Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.3D Plugin Debug.Build.0 = 3D Plugin Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.3D Plugin Release.ActiveCfg = 3D Plugin Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.3D Plugin Release.Build.0 = 3D Plugin Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Blender Debug.Build.0 = Blender Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Blender Release.ActiveCfg = Blender Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Blender Release.Build.0 = Blender Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.BlenderPlayer Debug.ActiveCfg = Blender Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.BlenderPlayer Debug.Build.0 = Blender Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.BlenderPlayer Release.ActiveCfg = BlenderPlayer Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.BlenderPlayer Release.Build.0 = BlenderPlayer Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Debug.ActiveCfg = 3D Plugin Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Debug.Build.0 = 3D Plugin Debug|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Release.ActiveCfg = 3D Plugin Release|Win32 + {E90C7BC2-CF30-4A60-A8F2-0050D592E358}.Release.Build.0 = 3D Plugin Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.3D Plugin Debug.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.3D Plugin Debug.Build.0 = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.3D Plugin Release.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.3D Plugin Release.Build.0 = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Blender Debug.ActiveCfg = Blender Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Blender Debug.Build.0 = Blender Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Blender Release.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Blender Release.Build.0 = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.BlenderPlayer Debug.ActiveCfg = BlenderPlayer Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.BlenderPlayer Debug.Build.0 = BlenderPlayer Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.BlenderPlayer Release.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.BlenderPlayer Release.Build.0 = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Debug.ActiveCfg = Blender Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Debug.Build.0 = Blender Debug|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Release.ActiveCfg = Blender Release|Win32 + {4C3AB78A-52CA-4276-A041-39776E52D8C8}.Release.Build.0 = Blender Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/projectfiles_vc7/blender/blender.vcproj b/projectfiles_vc7/blender/blender.vcproj new file mode 100644 index 00000000000..9761d94d746 --- /dev/null +++ b/projectfiles_vc7/blender/blender.vcproj @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blendercompact.sln b/projectfiles_vc7/blender/blendercompact.sln new file mode 100644 index 00000000000..f933457804c --- /dev/null +++ b/projectfiles_vc7/blender/blendercompact.sln @@ -0,0 +1,28 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makesdnacompact", "makesdnacompact.vcproj", "{14705769-A148-4DCC-B2C5-AFE8C20824E4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blendercompactNG", "blendercompactNG.vcproj", "{CB70E20D-75A2-497B-AD6E-60F3989F0622}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.0 = {14705769-A148-4DCC-B2C5-AFE8C20824E4} + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {14705769-A148-4DCC-B2C5-AFE8C20824E4}.Debug.ActiveCfg = Debug|Win32 + {14705769-A148-4DCC-B2C5-AFE8C20824E4}.Debug.Build.0 = Debug|Win32 + {14705769-A148-4DCC-B2C5-AFE8C20824E4}.Release.ActiveCfg = Release|Win32 + {14705769-A148-4DCC-B2C5-AFE8C20824E4}.Release.Build.0 = Release|Win32 + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.Debug.ActiveCfg = Debug|Win32 + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.Debug.Build.0 = Debug|Win32 + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.Release.ActiveCfg = Release|Win32 + {CB70E20D-75A2-497B-AD6E-60F3989F0622}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/projectfiles_vc7/blender/blendercompactNG.vcproj b/projectfiles_vc7/blender/blendercompactNG.vcproj new file mode 100644 index 00000000000..4eff6662659 --- /dev/null +++ b/projectfiles_vc7/blender/blendercompactNG.vcproj @@ -0,0 +1,3561 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blenkernel/BKE_blenkernel.vcproj b/projectfiles_vc7/blender/blenkernel/BKE_blenkernel.vcproj new file mode 100644 index 00000000000..4e58c6617aa --- /dev/null +++ b/projectfiles_vc7/blender/blenkernel/BKE_blenkernel.vcproj @@ -0,0 +1,685 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj b/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj new file mode 100644 index 00000000000..f7038e610f1 --- /dev/null +++ b/projectfiles_vc7/blender/blenlib/BLI_blenlib.vcproj @@ -0,0 +1,486 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/blenpluginapi/blenpluginapi/blenpluginapi.vcproj b/projectfiles_vc7/blender/blenpluginapi/blenpluginapi/blenpluginapi.vcproj new file mode 100644 index 00000000000..8a88ed9db50 --- /dev/null +++ b/projectfiles_vc7/blender/blenpluginapi/blenpluginapi/blenpluginapi.vcproj @@ -0,0 +1,361 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/ftfont/FTF_ftfont.vcproj b/projectfiles_vc7/blender/ftfont/FTF_ftfont.vcproj new file mode 100644 index 00000000000..ef756c7b67f --- /dev/null +++ b/projectfiles_vc7/blender/ftfont/FTF_ftfont.vcproj @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/imbuf/BL_imbuf.vcproj b/projectfiles_vc7/blender/imbuf/BL_imbuf.vcproj new file mode 100644 index 00000000000..b7518c0bc82 --- /dev/null +++ b/projectfiles_vc7/blender/imbuf/BL_imbuf.vcproj @@ -0,0 +1,648 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/img/BL_img.vcproj b/projectfiles_vc7/blender/img/BL_img.vcproj new file mode 100644 index 00000000000..cf94dbeed4f --- /dev/null +++ b/projectfiles_vc7/blender/img/BL_img.vcproj @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/loader/BLO_loader.vcproj b/projectfiles_vc7/blender/loader/BLO_loader.vcproj new file mode 100644 index 00000000000..49b0af17c01 --- /dev/null +++ b/projectfiles_vc7/blender/loader/BLO_loader.vcproj @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/makesdna/DNA_makesdna.vcproj b/projectfiles_vc7/blender/makesdna/DNA_makesdna.vcproj new file mode 100644 index 00000000000..f8d88f8640e --- /dev/null +++ b/projectfiles_vc7/blender/makesdna/DNA_makesdna.vcproj @@ -0,0 +1,596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/makesdnacompact.vcproj b/projectfiles_vc7/blender/makesdnacompact.vcproj new file mode 100644 index 00000000000..5ea0280e008 --- /dev/null +++ b/projectfiles_vc7/blender/makesdnacompact.vcproj @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/nodes/nodes.vcproj b/projectfiles_vc7/blender/nodes/nodes.vcproj new file mode 100644 index 00000000000..04403630664 --- /dev/null +++ b/projectfiles_vc7/blender/nodes/nodes.vcproj @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/radiosity/BRA_radiosity.vcproj b/projectfiles_vc7/blender/radiosity/BRA_radiosity.vcproj new file mode 100644 index 00000000000..8ef408c5a5d --- /dev/null +++ b/projectfiles_vc7/blender/radiosity/BRA_radiosity.vcproj @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/render/BRE_render.vcproj b/projectfiles_vc7/blender/render/BRE_render.vcproj new file mode 100644 index 00000000000..2383f41b69b --- /dev/null +++ b/projectfiles_vc7/blender/render/BRE_render.vcproj @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/renderconverter/BRE_renderconverter.vcproj b/projectfiles_vc7/blender/renderconverter/BRE_renderconverter.vcproj new file mode 100644 index 00000000000..ef830fe5905 --- /dev/null +++ b/projectfiles_vc7/blender/renderconverter/BRE_renderconverter.vcproj @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/src/BL_src.vcproj b/projectfiles_vc7/blender/src/BL_src.vcproj new file mode 100644 index 00000000000..685615e4b6d --- /dev/null +++ b/projectfiles_vc7/blender/src/BL_src.vcproj @@ -0,0 +1,894 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/src/BL_src_cre.vcproj b/projectfiles_vc7/blender/src/BL_src_cre.vcproj new file mode 100644 index 00000000000..70de861c91c --- /dev/null +++ b/projectfiles_vc7/blender/src/BL_src_cre.vcproj @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/blender/yafray/BRE_yafray.vcproj b/projectfiles_vc7/blender/yafray/BRE_yafray.vcproj new file mode 100644 index 00000000000..b51aaaab947 --- /dev/null +++ b/projectfiles_vc7/blender/yafray/BRE_yafray.vcproj @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/blenderhook/KX_blenderhook.vcproj b/projectfiles_vc7/gameengine/blenderhook/KX_blenderhook.vcproj new file mode 100644 index 00000000000..1721062b75c --- /dev/null +++ b/projectfiles_vc7/gameengine/blenderhook/KX_blenderhook.vcproj @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/converter/KX_converter.vcproj b/projectfiles_vc7/gameengine/converter/KX_converter.vcproj new file mode 100644 index 00000000000..36a49364dfc --- /dev/null +++ b/projectfiles_vc7/gameengine/converter/KX_converter.vcproj @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/expression/EXP_expressions.vcproj b/projectfiles_vc7/gameengine/expression/EXP_expressions.vcproj new file mode 100644 index 00000000000..e8516326a62 --- /dev/null +++ b/projectfiles_vc7/gameengine/expression/EXP_expressions.vcproj @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj b/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj new file mode 100644 index 00000000000..4336f0dd7cd --- /dev/null +++ b/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj @@ -0,0 +1,529 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/gameplayer/axctl/GP_axctl.vcproj b/projectfiles_vc7/gameengine/gameplayer/axctl/GP_axctl.vcproj new file mode 100644 index 00000000000..07189cf1f7f --- /dev/null +++ b/projectfiles_vc7/gameengine/gameplayer/axctl/GP_axctl.vcproj @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/gameplayer/common/GP_common.vcproj b/projectfiles_vc7/gameengine/gameplayer/common/GP_common.vcproj new file mode 100644 index 00000000000..cba8b1558c9 --- /dev/null +++ b/projectfiles_vc7/gameengine/gameplayer/common/GP_common.vcproj @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/gameplayer/ghost/GP_ghost.vcproj b/projectfiles_vc7/gameengine/gameplayer/ghost/GP_ghost.vcproj new file mode 100644 index 00000000000..ffa4c00f098 --- /dev/null +++ b/projectfiles_vc7/gameengine/gameplayer/ghost/GP_ghost.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj b/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj new file mode 100644 index 00000000000..a18b944a189 --- /dev/null +++ b/projectfiles_vc7/gameengine/ketsji/KX_ketsji.vcproj @@ -0,0 +1,760 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/ketsji/network/KX_network.vcproj b/projectfiles_vc7/gameengine/ketsji/network/KX_network.vcproj new file mode 100644 index 00000000000..a59c7fa145a --- /dev/null +++ b/projectfiles_vc7/gameengine/ketsji/network/KX_network.vcproj @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/network/loopbacknetwork/NG_loopbacknetwork.vcproj b/projectfiles_vc7/gameengine/network/loopbacknetwork/NG_loopbacknetwork.vcproj new file mode 100644 index 00000000000..400154a8533 --- /dev/null +++ b/projectfiles_vc7/gameengine/network/loopbacknetwork/NG_loopbacknetwork.vcproj @@ -0,0 +1,346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/network/network/NG_network.vcproj b/projectfiles_vc7/gameengine/network/network/NG_network.vcproj new file mode 100644 index 00000000000..60dc5655fb6 --- /dev/null +++ b/projectfiles_vc7/gameengine/network/network/NG_network.vcproj @@ -0,0 +1,361 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj new file mode 100644 index 00000000000..9a807f2d39a --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.vcproj new file mode 100644 index 00000000000..b1200e635d2 --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Dummy/PHY_Dummy.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.vcproj new file mode 100644 index 00000000000..a940d3a7f9b --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Ode/PHY_Ode.vcproj @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Physics.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Physics.vcproj new file mode 100644 index 00000000000..c46ba8f36de --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Physics.vcproj @@ -0,0 +1,367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.vcproj b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.vcproj new file mode 100644 index 00000000000..a8d6e77cd58 --- /dev/null +++ b/projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Sumo/PHY_Sumo.vcproj @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/rasterizer/RAS_rasterizer.vcproj b/projectfiles_vc7/gameengine/rasterizer/RAS_rasterizer.vcproj new file mode 100644 index 00000000000..129084f7b1b --- /dev/null +++ b/projectfiles_vc7/gameengine/rasterizer/RAS_rasterizer.vcproj @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.vcproj b/projectfiles_vc7/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.vcproj new file mode 100644 index 00000000000..40bd1369aae --- /dev/null +++ b/projectfiles_vc7/gameengine/rasterizer/openglrasterizer/RAS_openglrasterizer.vcproj @@ -0,0 +1,373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/gameengine/scenegraph/SG_SceneGraph.vcproj b/projectfiles_vc7/gameengine/scenegraph/SG_SceneGraph.vcproj new file mode 100644 index 00000000000..02bb647eb92 --- /dev/null +++ b/projectfiles_vc7/gameengine/scenegraph/SG_SceneGraph.vcproj @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/kernel/gen_messaging/gen_messaging.vcproj b/projectfiles_vc7/kernel/gen_messaging/gen_messaging.vcproj new file mode 100644 index 00000000000..e947f52bd6b --- /dev/null +++ b/projectfiles_vc7/kernel/gen_messaging/gen_messaging.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/kernel/system/SYS_system.vcproj b/projectfiles_vc7/kernel/system/SYS_system.vcproj new file mode 100644 index 00000000000..50ffc1fbb99 --- /dev/null +++ b/projectfiles_vc7/kernel/system/SYS_system.vcproj @@ -0,0 +1,367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/sumo/fuzzics/SM_fuzzics.vcproj b/projectfiles_vc7/sumo/fuzzics/SM_fuzzics.vcproj new file mode 100644 index 00000000000..1b454bd0316 --- /dev/null +++ b/projectfiles_vc7/sumo/fuzzics/SM_fuzzics.vcproj @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/sumo/fuzzics/fuzzics.vcproj b/projectfiles_vc7/sumo/fuzzics/fuzzics.vcproj new file mode 100644 index 00000000000..6976e66a0bc --- /dev/null +++ b/projectfiles_vc7/sumo/fuzzics/fuzzics.vcproj @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projectfiles_vc7/sumo/moto/SM_moto.dsp b/projectfiles_vc7/sumo/moto/SM_moto.dsp new file mode 100644 index 00000000000..3fd627ce60d --- /dev/null +++ b/projectfiles_vc7/sumo/moto/SM_moto.dsp @@ -0,0 +1,332 @@ +# Microsoft Developer Studio Project File - Name="SM_moto" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_moto - Win32 Profile +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SM_moto.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SM_moto.mak" CFG="SM_moto - Win32 Profile" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_moto - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_moto - Win32 Profile" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_moto - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\..\..\lib\windows\moto\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\SM_moto.lib" + +!ELSEIF "$(CFG)" == "SM_moto - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" + +!ELSEIF "$(CFG)" == "SM_moto - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_moto___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_moto___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /FR /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_moto - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_moto___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_moto___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll" +# PROP Intermediate_Dir "..\..\..\..\obj\windows\sumo\moto\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\MoTo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\sumo\MoTo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\moto\SM_moto.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_moto - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_moto___Win32_Profile" +# PROP BASE Intermediate_Dir "SM_moto___Win32_Profile" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "SM_moto___Win32_Profile" +# PROP Intermediate_Dir "SM_moto___Win32_Profile" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /O2 /I "..\..\..\source\sumo\MoTo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\debug\SM_moto.lib" +# ADD LIB32 /nologo /out:"..\..\..\..\obj\windows\sumo\moto\profile\SM_moto.lib" + +!ENDIF + +# Begin Target + +# Name "SM_moto - Win32 Release" +# Name "SM_moto - Win32 Debug" +# Name "SM_moto - Win32 MT DLL Debug" +# Name "SM_moto - Win32 MT DLL Release" +# Name "SM_moto - Win32 Profile" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_CmMatrix4x4.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Matrix3x3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Matrix4x4.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Point3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Quaternion.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_random.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Transform.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector3.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\src\MT_Vector4.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\GEN_List.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\GEN_Map.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_assert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_CmMatrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix3x3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix3x3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix4x4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Matrix4x4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_MinMax.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Optimize.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Point3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Quaternion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Quaternion.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_random.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Scalar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Stream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Transform.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Tuple4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector2.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector3.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector4.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\MT_Vector4.inl +# End Source File +# Begin Source File + +SOURCE=..\..\..\source\sumo\MoTo\include\NM_Scalar.h +# End Source File +# End Group +# End Target +# End Project diff --git a/projectfiles_vc7/sumo/solid/SM_solid.dsp b/projectfiles_vc7/sumo/solid/SM_solid.dsp new file mode 100644 index 00000000000..dfaa85c35d8 --- /dev/null +++ b/projectfiles_vc7/sumo/solid/SM_solid.dsp @@ -0,0 +1,340 @@ +# Microsoft Developer Studio Project File - Name="SM_solid" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=SM_solid - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SM_solid.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SM_solid.mak" CFG="SM_solid - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SM_solid - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 MT DLL Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "SM_solid - Win32 MT DLL Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SM_solid - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /J /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_solid - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# SUBTRACT CPP /Fr +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_solid - Win32 MT DLL Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "SM_solid___Win32_MT_DLL_Debug" +# PROP BASE Intermediate_Dir "SM_solid___Win32_MT_DLL_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\mtdll_debug" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\mtdll_debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /Gm /GX /ZI /Od /I "..\..\..\source\sumo\SOLID-3.0\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\solid\debug\SM_solid.lib" +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "SM_solid - Win32 MT DLL Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SM_solid___Win32_MT_DLL_Release" +# PROP BASE Intermediate_Dir "SM_solid___Win32_MT_DLL_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\..\..\obj\windows\sumo\solid\mtdll" +# PROP Intermediate_Dir "..\..\..\obj\windows\sumo\solid\mtdll" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /GX /O2 /I "..\..\..\source\sumo\SOLID-3.0\include" /I "../../../../../lib/windows/moto/include" /I "..\..\..\source\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\..\..\source\gameengine\physics\sumo\SOLID-3.0\include" /I "../../../../lib/windows/moto/include" /I "..\..\..\source\gameengine\physics\sumo\include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /J /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"..\..\..\..\..\obj\windows\sumo\solid\SM_solid.lib" +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "SM_solid - Win32 Release" +# Name "SM_solid - Win32 Debug" +# Name "SM_solid - Win32 MT DLL Debug" +# Name "SM_solid - Win32 MT DLL Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\BBoxTree.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Box.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Complex.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Cone.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Convex.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Cylinder.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Endpoint.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Proxy.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_BP_Scene.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_C-api.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_DoubleBase.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Encounter.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_FloatBase.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_LineSegment.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Object.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_RespTable.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\DT_Scene.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Polyhedron.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Polytope.cpp" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\src\Sphere.cpp" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\AlgoTable.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\BBoxTree.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Box.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Complex.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Cone.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Convex.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Cylinder.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_AABBox.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BBox.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Endpoint.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Proxy.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_BP_Scene.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_DoubleBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Encounter.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_FloatBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_LineSegment.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Object.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Response.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_RespTable.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_Scene.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_VertexBase.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\DT_VertexBased.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\IndexArray.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Polyhedron.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Polytope.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Shape.h" +# End Source File +# Begin Source File + +SOURCE="..\..\..\source\gameengine\Physics\Sumo\SOLID-3.0\include\Sphere.h" +# End Source File +# End Group +# End Target +# End Project diff --git a/release/Makefile b/release/Makefile new file mode 100644 index 00000000000..c55e62be003 --- /dev/null +++ b/release/Makefile @@ -0,0 +1,206 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +include nan_definitions.mk + +export VERSION := $(shell cat VERSION) + +BLENDNAME=blender-$(VERSION)-$(CONFIG_GUESS)-py$(NAN_PYTHON_VERSION)$(TYPE) +export DISTDIR=$(NAN_OBJDIR)/$(BLENDNAME) +export CONFDIR=$(DISTDIR)/.blender + +ifeq ($(OS),beos) + TAR="zip" + TARFLAGS="-ry9" + EXT0="" + EXT1=".zip" + COMPRESS="" + EXT2="" + NOPLUGINS="true" +endif + +ifeq ($(OS),$(findstring $(OS), "freebsd irix linux openbsd solaris")) + TAR="tar" + TARFLAGS="cf" + EXT0="" + EXT1=".tar" + COMPRESS="bzip2" + COMPRESSFLAGS="-f" + EXT2=".bz2" +endif + +ifeq ($(OS),windows) + TAR="zip" + TARFLAGS="-r9" + EXT0=".exe" + EXT1=".zip" + NOPLUGINS="true" + NOSTRIP="true" +endif + +ifeq ($(OS),darwin) + TAR="tar" + TARFLAGS="cf" + EXT0=".app" + EXT1=".tar" + COMPRESS="bzip2" + COMPRESSFLAGS="-f" + EXT2=".bz2" +endif + +release: all + +all: + @$(MAKE) pkg TYPE="" +ifeq ($(WITH_BF_STATICOPENGL), true) + @$(MAKE) pkg TYPE="-static" +endif + +# OS independent targets below: + +dist: all + +package: version makedirs + +install: package + @#echo "****> Install text" + @cp text/blender.html $(DISTDIR) + @cp text/*.txt $(DISTDIR) + @cp text/*.pdf $(DISTDIR) + ifeq ($(FREEDESKTOP), true) + @#echo "****> Install freedesktop icons" + @mkdir $(DISTDIR)/icons + @mkdir $(DISTDIR)/icons/16x16 + @cp freedesktop/icons/16x16/blender.png $(DISTDIR)/icons/16x16 + @mkdir $(DISTDIR)/icons/22x22 + @cp freedesktop/icons/22x22/blender.png $(DISTDIR)/icons/22x22 + @mkdir $(DISTDIR)/icons/32x32 + @cp freedesktop/icons/32x32/blender.png $(DISTDIR)/icons/32x32 + @mkdir $(DISTDIR)/icons/scalable + @cp freedesktop/icons/scalable/blender.svg $(DISTDIR)/icons/scalable + endif + @echo "----> Make Config dir .blender" + @mkdir -p $(CONFDIR) + @# possible overruling .txt text documents + @[ ! -d $(CONFIG_GUESS)/text ] || \ + cp -f $(CONFIG_GUESS)/text/*.txt $(DISTDIR) +#on OS X the contents of the .blender dir is already inside the bundle + ifneq ($(OS), darwin) + @[ ! -d $(OCGDIR)/bin/.blender ] || \ + cp -r $(OCGDIR)/bin/.blender $(DISTDIR) + @rm -rf $(DISTDIR)/.svn $(DISTDIR)/*/.svn $(DISTDIR)/*/*/.svn + @cp $(NANBLENDERHOME)/bin/.blender/.Blanguages $(CONFDIR) + @cp $(NANBLENDERHOME)/bin/.blender/.bfont.ttf $(CONFDIR) + endif + @echo "----> Copy blender$(EXT0) executable" + ifeq ($(TYPE),-static) + @cp $(OCGDIR)/bin/blenderstatic$(EXT0) $(DISTDIR)/blender$(EXT0) + else + ifeq ($(OS),darwin) + @cp -r $(OCGDIR)/bin/blender$(EXT0) $(DISTDIR)/Blender$(EXT0) + else + @cp $(OCGDIR)/bin/blender$(EXT0) $(DISTDIR)/blender$(EXT0) + endif + @if [ -f $(OCGDIR)/bin/blenderplayer$(EXTO) ]; then \ + cp $(OCGDIR)/bin/blenderplayer$(EXTO) \ + $(DISTDIR)/blenderplayer$(EXTO) ; \ + fi + endif + +ifneq ($(NOPLUGINS),true) + @echo "----> Copy and compile plugins" + @cp -r plugins $(DISTDIR)/plugins + @mkdir -p $(DISTDIR)/plugins/include + @cp ../source/blender/blenpluginapi/*.h $(DISTDIR)/plugins/include/ + @chmod 755 $(DISTDIR)/plugins/bmake + @$(MAKE) -C $(DISTDIR)/plugins all > /dev/null || exit 1; + @rm -fr $(DISTDIR)/plugins/.svn $(DISTDIR)/plugins/*/.svn \ + $(DISTDIR)/plugins/*/*.o + +#on OS X the plugins move to the installation directory + ifneq ($(OS),darwin) + @mkdir -p $(CONFDIR)/plugins/sequence + @mkdir -p $(CONFDIR)/plugins/texture + @mv $(DISTDIR)/plugins/sequence/*.so $(CONFDIR)/plugins/sequence + @mv $(DISTDIR)/plugins/texture/*.so $(CONFDIR)/plugins/texture + endif +endif + + @echo "----> Copy python infrastructure" + @[ ! -d scripts ] || cp -r scripts $(CONFDIR)/scripts + @[ ! -d $(CONFDIR)/scripts ] || rm -fr $(CONFDIR)/scripts/.svn $(CONFDIR)/scripts/*/.svn $(CONFDIR)/scripts/*/*/.svn + + ifeq ($(OS),darwin) + @echo "----> Move .blender to .app/Contents/MacOS/" + @rm -fr $(DISTDIR)/blender$(EXT0)/Contents/MacOS/.blender + @mv $(DISTDIR)/.blender $(DISTDIR)/blender$(EXT0)/Contents/MacOS/ + endif + + ifneq ($(NOSTRIP),true) + @echo "----> Strip blender executable" + ifeq ($(OS),darwin) + @strip -x $(DISTDIR)/blender$(EXT0)/Contents/MacOS/blender + else + @strip -x $(DISTDIR)/blender$(EXT0) + @if [ -f $(DISTDIR)/blenderplayer$(EXTO) ]; then \ + strip -x $(DISTDIR)/blender$(EXT0) ; \ + fi + endif + endif + @[ ! -x $(CONFIG_GUESS)/specific.sh ] || (\ + echo "**--> Execute specific.sh in $(CONFIG_GUESS)/" && \ + cd $(CONFIG_GUESS) && ./specific.sh ) + +pkg: install + @echo "----> Create distribution file $(BLENDNAME)$(EXT1)" + @#enable the next sleep if you get 'tar file changed while reading' + @#sleep 10 + rm -f $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)* + @cd $(NAN_OBJDIR) && $(TAR) $(TARFLAGS) $(VERSION)/$(BLENDNAME)$(EXT1) $(BLENDNAME) + ifdef COMPRESS + @echo "----> Compressing distribution to $(BLENDNAME)$(EXT1)$(EXT2)" + @$(COMPRESS) $(COMPRESSFLAGS) $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1) + endif + @#echo "****> Clean up temporary distribution directory" + @rm -fr $(DISTDIR) + @echo "****> $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)$(EXT2) is ready" + +version: FORCE + @echo "*---> Create $(BLENDNAME) package" + +makedirs: FORCE + @#echo "****> Create package directory $(VERSION) if necessary" + @[ -d $(NAN_OBJDIR)/$(VERSION) ] || mkdir $(NAN_OBJDIR)/$(VERSION) + @#echo "****> Prepare temporary distribution directory" + @rm -fr $(DISTDIR) + @mkdir $(DISTDIR) + +FORCE: diff --git a/release/VERSION b/release/VERSION new file mode 100644 index 00000000000..f454b8169e3 --- /dev/null +++ b/release/VERSION @@ -0,0 +1 @@ +2.44 diff --git a/release/beos-4.5-i386/specific.sh b/release/beos-4.5-i386/specific.sh new file mode 100644 index 00000000000..66ce08c4613 --- /dev/null +++ b/release/beos-4.5-i386/specific.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# OS specific stuff for the package, only to be executed by ../Makefile + +# Add Python .so to package +cp -f $NAN_PYTHON/lib/libpython$NAN_PYTHON_VERSION.so $DISTDIR/ + +# And create a drag'n'drop symlink for it +cd $DISTDIR && ln -s /boot/home/config/lib Drag_libpython$NAN_PYTHON_VERSION.so_here diff --git a/release/beos-5.0-i386/specific.sh b/release/beos-5.0-i386/specific.sh new file mode 100644 index 00000000000..66ce08c4613 --- /dev/null +++ b/release/beos-5.0-i386/specific.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# OS specific stuff for the package, only to be executed by ../Makefile + +# Add Python .so to package +cp -f $NAN_PYTHON/lib/libpython$NAN_PYTHON_VERSION.so $DISTDIR/ + +# And create a drag'n'drop symlink for it +cd $DISTDIR && ln -s /boot/home/config/lib Drag_libpython$NAN_PYTHON_VERSION.so_here diff --git a/release/datafiles/.Bfont b/release/datafiles/.Bfont new file mode 100644 index 00000000000..364194d9ff1 Binary files /dev/null and b/release/datafiles/.Bfont differ diff --git a/release/datafiles/.Bfs b/release/datafiles/.Bfs new file mode 100644 index 00000000000..80854424071 --- /dev/null +++ b/release/datafiles/.Bfs @@ -0,0 +1,2 @@ +/ +/tmp/ diff --git a/release/datafiles/DejaVuSans-Lite.sfd.bz2 b/release/datafiles/DejaVuSans-Lite.sfd.bz2 new file mode 100644 index 00000000000..0447c7c907d Binary files /dev/null and b/release/datafiles/DejaVuSans-Lite.sfd.bz2 differ diff --git a/release/datafiles/LICENSE-bfont.ttf.txt b/release/datafiles/LICENSE-bfont.ttf.txt new file mode 100644 index 00000000000..754089661b0 --- /dev/null +++ b/release/datafiles/LICENSE-bfont.ttf.txt @@ -0,0 +1,101 @@ +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. Glyphs imported from Arev fonts are (c) Tavmjung Bah (see below) + +'DeJaVu-Lite' changes (removing characters for lighter file size) are in public domain. Source file is accompanied in this directory, BZip2 compressed, DeJaVuSans-Lite.sfd.bz2 . + + +Bitstream Vera Fonts Copyright +------------------------------ + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is +a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute the +Font Software, including without limitation the rights to use, copy, merge, +publish, distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to the +following conditions: + +The above copyright and trademark notices and this permission notice shall +be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional glyphs or characters may be added to the Fonts, only if the fonts +are renamed to names not containing either the words "Bitstream" or the word +"Vera". + +This License becomes null and void to the extent applicable to Fonts or Font +Software that has been modified and is distributed under the "Bitstream +Vera" names. + +The Font Software may be sold as part of a larger software package but no +copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING +ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE +FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font Software +without prior written authorization from the Gnome Foundation or Bitstream +Inc., respectively. For further information, contact: fonts at gnome dot +org. + +Arev Fonts Copyright +------------------------------ + +Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and +associated documentation files (the "Font Software"), to reproduce +and distribute the modifications to the Bitstream Vera Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to +the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Tavmjong Bah" or the word "Arev". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Tavmjong Bah Arev" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the name of Tavmjong Bah shall not +be used in advertising or otherwise to promote the sale, use or other +dealings in this Font Software without prior written authorization +from Tavmjong Bah. For further information, contact: tavmjong @ free +. fr. + +$Id$ diff --git a/release/datafiles/bfont.ttf b/release/datafiles/bfont.ttf new file mode 100644 index 00000000000..2217f9d1aad Binary files /dev/null and b/release/datafiles/bfont.ttf differ diff --git a/release/datafiles/blenderbuttons b/release/datafiles/blenderbuttons new file mode 100644 index 00000000000..d34acb7be04 Binary files /dev/null and b/release/datafiles/blenderbuttons differ diff --git a/release/datafiles/datatoc.c b/release/datafiles/datatoc.c new file mode 100644 index 00000000000..ca101322c9a --- /dev/null +++ b/release/datafiles/datatoc.c @@ -0,0 +1,105 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include +#include +#include + +int main(int argc, char**argv) { + FILE *fpin, *fpout; + char cname[256]; + char sizest[256]; + long size; + int i; + + if (argc<1) { + printf ("Usage: datatoc \n"); + exit(1); + } + + fpin= fopen(argv[1], "rb"); + if (!fpin) { + printf ("Unable to open input <%s>\n", argv[1]); + exit(1); + } + + fseek (fpin, 0L, SEEK_END); + size= ftell(fpin); + fseek (fpin, 0L, SEEK_SET); + + if (argv[1][0]=='.') argv[1]++; + + sprintf(cname, "%s.c", argv[1]); + printf ("Making C file <%s>\n", cname); + + for (i=0; i < (int)strlen(argv[1]); i++) + if (argv[1][i]=='.') argv[1][i]='_'; + + sprintf(sizest, "%d", (int)size); + printf ("Input filesize is %d, Output size should be %d\n", size, ((int)size)*4 + strlen("/* DataToC output of file <> */\n\n") + strlen("char datatoc_[]= {\"") + strlen ("\"};\n") + (strlen(argv[1])*3) + strlen(sizest) + strlen("int datatoc__size= ;\n") +(((int)(size/256)+1)*5)); + + fpout= fopen(cname, "w"); + if (!fpout) { + printf ("Unable to open output <%s>\n", cname); + exit(1); + } + + fprintf (fpout, "/* DataToC output of file <%s> */\n\n",argv[1]); + fprintf (fpout, "int datatoc_%s_size= %s;\n", argv[1], sizest); + /* + fprintf (fpout, "char datatoc_%s[]= {\"", argv[1]); + + while (size--) { + if(size%256==0) + fprintf(fpout, "\" \\\n\""); + + fprintf (fpout, "\\x%02x", getc(fpin)); + } + + fprintf (fpout, "\"};\n"); + */ + + fprintf (fpout, "char datatoc_%s[]= {\n", argv[1]); + while (size--) { + if(size%32==31) + fprintf(fpout, "\n"); + + /* fprintf (fpout, "\\x%02x", getc(fpin)); */ + fprintf (fpout, "%3d,", getc(fpin)); + } + + fprintf (fpout, "\n};\n\n"); + + fclose(fpin); + fclose(fpout); + return 0; +} diff --git a/release/datafiles/preview.blend b/release/datafiles/preview.blend new file mode 100644 index 00000000000..8d67a88f679 Binary files /dev/null and b/release/datafiles/preview.blend differ diff --git a/release/datafiles/prvicons b/release/datafiles/prvicons new file mode 100644 index 00000000000..de3980f9676 Binary files /dev/null and b/release/datafiles/prvicons differ diff --git a/release/datafiles/splash.jpg b/release/datafiles/splash.jpg new file mode 100644 index 00000000000..da88c0b8eaa Binary files /dev/null and b/release/datafiles/splash.jpg differ diff --git a/release/freedesktop/icons/16x16/blender.png b/release/freedesktop/icons/16x16/blender.png new file mode 100644 index 00000000000..238d67321a7 Binary files /dev/null and b/release/freedesktop/icons/16x16/blender.png differ diff --git a/release/freedesktop/icons/16x16/blender.xcf.bz2 b/release/freedesktop/icons/16x16/blender.xcf.bz2 new file mode 100644 index 00000000000..67cb725ea79 Binary files /dev/null and b/release/freedesktop/icons/16x16/blender.xcf.bz2 differ diff --git a/release/freedesktop/icons/22x22/blender.png b/release/freedesktop/icons/22x22/blender.png new file mode 100644 index 00000000000..3178ddd58ee Binary files /dev/null and b/release/freedesktop/icons/22x22/blender.png differ diff --git a/release/freedesktop/icons/22x22/blender.xcf.bz2 b/release/freedesktop/icons/22x22/blender.xcf.bz2 new file mode 100644 index 00000000000..fb4396252ab Binary files /dev/null and b/release/freedesktop/icons/22x22/blender.xcf.bz2 differ diff --git a/release/freedesktop/icons/32x32/blender.png b/release/freedesktop/icons/32x32/blender.png new file mode 100644 index 00000000000..4c9acf10d63 Binary files /dev/null and b/release/freedesktop/icons/32x32/blender.png differ diff --git a/release/freedesktop/icons/32x32/blender.svg b/release/freedesktop/icons/32x32/blender.svg new file mode 100644 index 00000000000..241111c5c64 --- /dev/null +++ b/release/freedesktop/icons/32x32/blender.svg @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + + + + + + + + + + + + + + + + + + + diff --git a/release/freedesktop/icons/scalable/blender.svg b/release/freedesktop/icons/scalable/blender.svg new file mode 100644 index 00000000000..bc1a3a970f6 --- /dev/null +++ b/release/freedesktop/icons/scalable/blender.svg @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + + + + + + + + + + + + + + + + + + + diff --git a/release/irix-6.2-mips/extra/blender.icon b/release/irix-6.2-mips/extra/blender.icon new file mode 100644 index 00000000000..32b8bc3b94a Binary files /dev/null and b/release/irix-6.2-mips/extra/blender.icon differ diff --git a/release/irix-6.2-mips/specific.sh b/release/irix-6.2-mips/specific.sh new file mode 100644 index 00000000000..1b8911a2542 --- /dev/null +++ b/release/irix-6.2-mips/specific.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# OS specific stuff for the package, only to be executed by ../Makefile +# + +# Add icon to package +cp -f extra/blender.icon $DISTDIR/ diff --git a/release/plugins/Makefile b/release/plugins/Makefile new file mode 100644 index 00000000000..db013d6e08e --- /dev/null +++ b/release/plugins/Makefile @@ -0,0 +1,42 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +all: textures sequences + +textures: + $(MAKE) -C texture + +sequences: + $(MAKE) -C sequence + +clean: + $(MAKE) -C texture clean + $(MAKE) -C sequence clean diff --git a/release/plugins/bmake b/release/plugins/bmake new file mode 100644 index 00000000000..6e65f0bcbc8 --- /dev/null +++ b/release/plugins/bmake @@ -0,0 +1,146 @@ +#!/bin/sh +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +# detect the system + +UNAME=`uname` +EXT="so"; +if ( test "WIN32" = "$TARGET" ) then + CC="gcc"; + CFLAGS="-funsigned-char -O2"; + + LD="ld"; + LDFLAGS="-Bshareable -lm"; +elif ( test $UNAME = "IRIX64" -o $UNAME = "IRIX" ) then + CC="cc"; + CFLAGS="-KPIC -O2 -mips3"; + + LD="ld"; + LDFLAGS="-shared -U"; +elif ( test $UNAME = "FreeBSD" ) then + CC="gcc"; + CFLAGS="-fPIC -funsigned-char -O2"; + + LD="ld"; + LDFLAGS="-Bshareable"; +elif ( test $UNAME = "OpenBSD" ) then + CC="gcc"; + CFLAGS="-fPIC -funsigned-char -O2"; + + LD="ld"; + LDFLAGS="-Bshareable"; +elif ( test $UNAME = "Linux" ) then + CC="gcc"; + CFLAGS="-fPIC -funsigned-char -O2"; + + LD="ld"; + LDFLAGS="-Bshareable"; +elif ( test $UNAME = "SunOS" ) then + CC="cc"; + CFLAGS="-O"; + + LD="ld"; + LDFLAGS="-r"; +elif ( test $UNAME = "Darwin" ) then + CC="cc"; + CFLAGS="-fPIC -funsigned-char -O2 -fno-common"; + LD="cc"; + LDFLAGS="-flat_namespace -bundle -bundle_loader ../../blender.app/Contents/MacOS/blender -lm"; + EXT="so"; +fi + +if ( test "$#" = "1" ) then + if ( test -f $1 ) then + BASE_FILE=`echo $1 | sed -e "1 s/\.c//g"`; + else + BASE_FILE=$1; + fi + + CFILE="$BASE_FILE.c" + OFILE="$BASE_FILE.o" + SOFILE="$BASE_FILE.$EXT" +else + if ( test -f $1$2 ) then + BASE_FILE=`echo $2 | sed -e "1 s/\.c//g"`; + else + BASE_FILE=$2; + fi + + CFILE="$1$BASE_FILE.c" + if (test "$TARGET" = "WIN32" ) then + DLLFILE="$BASE_FILE.dll"; + fi + OFILE="$BASE_FILE.o" + SOFILE="$BASE_FILE.$EXT" +fi + +INCLUDES= +if ( test -f plugin.h ) then + INCLUDES=-I.; +elif ( test -f "include/plugin.h" ) then + INCLUDES=-Iinclude/ +elif ( test -f "../plugin.h" ) then + INCLUDES=-I..; +elif ( test -f "../include/plugin.h" ) then + INCLUDES=-I../include +else + echo "Couldn't find plugin.h"; + exit; +fi + +LIBM=`fgrep "#include " $CFILE` +LIBC=`fgrep "#include +#include "plugin.h" + +/* ******************** GLOBAL VARIABLES ***************** */ + + +char name[24]= "Blur"; + +/* structure for buttons, + * butcode name default min max 0 + */ + +VarStruct varstr[]= { + LABEL, "Input: 1 strip", 0.0, 0.0, 0.0, "", + NUMSLI|FLO, "Blur", 0.5, 0.0, 10.0, "Maximum filtersize", + NUMSLI|FLO, "Gamma", 1.0, 0.4, 2.0, "Gamma correction", + TOG|INT, "Animated", 0.0, 0.0, 1.0, "For (Ipo) animated blur", + NUM|INT, "debug", 0.0, 0.0, 2.0, + "0:off 1: show primary blur buffer 2: show 2nd blur buffer", + +}; + +/* The cast struct is for input in the main doit function + Varstr and Cast must have the same variables in the same order */ + +typedef struct Cast { + int dummy; /* because of the 'label' button */ + float blur; + float gamma; + float use_ipo; + int show; +} Cast; + + +/* cfra: the current frame */ + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +/* ******************** Fixed functions ***************** */ + +int plugin_seq_getversion(void) +{ + return B_PLUGIN_VERSION; +} + +void plugin_but_changed(int but) +{ +} + +void plugin_init(void) +{ +} + +void plugin_getinfo(PluginInfo *info) +{ + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + + +void blurbuf(struct ImBuf *ibuf, int nr, Cast *cast) +{ + /* nr = number of blurs */ + /* the ibuf->rect is replaced */ + struct ImBuf *tbuf, *ttbuf; + int i, x4; + + tbuf= dupImBuf(ibuf); + x4= ibuf->x/4; + + /* This doesn't seem to work... paprmh */ + if(cast->gamma != 1.0) gamwarp(tbuf, cast->gamma); + + /* reduce */ + for(i=0; ix<4 || tbuf->y<4) break; + } + + /* enlarge */ + for(i=0; ix > x4) { + scaleImBuf(tbuf, ibuf->x, ibuf->y); + break; + } + } + + /* this doesn't seem to work...paprmh*/ + if(cast->gamma != 1.0) gamwarp(tbuf, 1.0 / cast->gamma); + + if(ibuf->rect)memcpy(ibuf->rect, tbuf->rect, 4*ibuf->x*ibuf->y); + + if(ibuf->rect_float) + memcpy(ibuf->rect_float, tbuf->rect_float, 4*ibuf->x*ibuf->y*sizeof(float)); + + freeImBuf(tbuf); + +} + +void doblur(struct ImBuf *mbuf, float fac, Cast *cast) +{ + /* make two filtered images, like a mipmap structure + * fac is filtersize in pixels + */ + struct ImBuf *ibuf, *pbuf; + float ifac, pfac, infac; + int n, b1, b2; + char *irect, *prect, *mrect; + float *irectf, *prectf, *mrectf; + + /* wich buffers ? */ + + if(fac>7.0) fac= 7.0; + if(fac<=1.0) return; + + pfac= 2.0; + pbuf= dupImBuf(mbuf); + n= 1; + while(pfac < fac) { + blurbuf(pbuf, n, cast); + blurbuf(pbuf, n, cast); + + n++; + pfac+= 1.0; + } + + ifac= pfac; + pfac-= 1.0; + + ibuf= dupImBuf(pbuf); + blurbuf(ibuf, n, cast); + blurbuf(ibuf, n, cast); + + fac= (fac-pfac)/(ifac-pfac); + n= mbuf->x*mbuf->y; + + if(cast->show) fac=cast->show-1; + + if(mbuf->rect_float){ + if(fac>=1) { + memcpy(mbuf->rect_float, ibuf->rect_float, 4*n*sizeof(float)); + } + else if(fac<=0) { + memcpy(mbuf->rect_float, pbuf->rect_float, 4*n*sizeof(float)); + } + else { /* interpolate */ + infac= 1-fac; + + irectf= (float *)ibuf->rect_float; + prectf= (float *)pbuf->rect_float; + mrectf= (float *)mbuf->rect_float; + while(n--) { + mrectf[0]= irectf[0]*fac+ prectf[0]*infac; + mrectf[1]= irectf[1]*fac+ prectf[1]*infac; + mrectf[2]= irectf[2]*fac+ prectf[2]*infac; + mrectf[3]= irectf[3]*fac+ prectf[3]*infac; + mrectf+= 4; + irectf+= 4; + prectf+= 4; + } + } + } + else if(mbuf->rect){ + b1= (int)fac*255.0; + if(b1>255) b1= 255; + b2= 255-b1; + + if(b1==255) { + memcpy(mbuf->rect, ibuf->rect, 4*n); + } + else if(b1==0) { + memcpy(mbuf->rect, pbuf->rect, 4*n); + } + else { /* interpolate */ + irect= (char *)ibuf->rect; + prect= (char *)pbuf->rect; + mrect= (char *)mbuf->rect; + while(n--) { + mrect[0]= (irect[0]*b1+ prect[0]*b2)>>8; + mrect[1]= (irect[1]*b1+ prect[1]*b2)>>8; + mrect[2]= (irect[2]*b1+ prect[2]*b2)>>8; + mrect[3]= (irect[3]*b1+ prect[3]*b2)>>8; + mrect+= 4; + irect+= 4; + prect+= 4; + } + } + } + + freeImBuf(ibuf); + freeImBuf(pbuf); +} + + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int x, int y, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) +{ + float bfacf0, bfacf1; + + if(cast->use_ipo==0) { + bfacf0= bfacf1= cast->blur+1.0; + } + else { + bfacf0 = (facf0 * 6.0) + 1.0; + bfacf1 = (facf1 * 6.0) + 1.0; + } + + if(out->rect) memcpy(out->rect, ibuf1->rect, 4*out->x*out->y); + if(out->rect_float) memcpy(out->rect_float, ibuf1->rect_float, 4*out->x*out->y*sizeof(float)); + +/****************I can't get this field code to work... works ok without...paprmh****************/ + + + /* it blurs interlaced, only tested with even fields */ + +/* de_interlace(out);*/ + /* otherwise scaling goes wrong */ +/* out->flags &= ~IB_fields;*/ + + doblur(out, bfacf0, cast); /*fieldA*/ + +/* if(out->rect)out->rect += out->x * out->y; + if(out->rect_float)out->rect_float += out->x * out->y; + + doblur(out, bfacf1, cast);*/ /*fieldB*/ + +/* if(out->rect)out->rect -= out->x * out->y; + if(out->rect_float)out->rect_float -= out->x * out->y; + out->flags |= IB_fields; + + interlace(out);*/ + +} + diff --git a/release/plugins/sequence/color-correction-hsv.c b/release/plugins/sequence/color-correction-hsv.c new file mode 100644 index 00000000000..ec8478706f1 --- /dev/null +++ b/release/plugins/sequence/color-correction-hsv.c @@ -0,0 +1,291 @@ +/* + * Color Correction Plugin (YUV Version) 0.01 + * + * Copyright (c) 2005 Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "math.h" +#include "plugin.h" +#include + +char name[]= "Color Correction"; + +VarStruct varstr[]= { + { NUMSLI|FLO, "St Y:", 0.0, -1.0, 1.0, "Setup Y"}, + { NUMSLI|FLO, "Gn Y:", 1.0, 0.0, 10.0,"Gain Y"}, + { NUMSLI|FLO, "Ga Y:", 1.0, 0.0, 10.0, "Gamma Y"}, + + { NUMSLI|FLO, "Lo S:", 1.0, 0.0, 10.0,"Saturation Shadows"}, + { NUMSLI|FLO, "Md S:", 1.0, 0.0, 10.0,"Saturation Midtones"}, + { NUMSLI|FLO, "Hi S:", 1.0, 0.0, 10.0,"Saturation Highlights"}, + + { NUMSLI|FLO, "MA S:", 1.0, 0.0, 10.0,"Master Saturation"}, + + { NUMSLI|FLO, "Lo T:", 0.25, 0.0, 1.0, + "Saturation Shadow Thres"}, + { NUMSLI|FLO, "Hi T:", 0.75, 0.0, 1.0, + "Saturation Highlights Thres"}, + { TOG|INT, "Debug", 0.0, 0.0, 1.0, + "Show curves as overlay."}, +}; + +typedef struct Cast { + float setup_y; + float gain_y; + float gamma_y; + float sat_shadows; + float sat_midtones; + float sat_highlights; + + float master_sat; + float lo_thres; + float hi_thres; + int debug; +} Cast; + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +int plugin_seq_getversion(void) { return B_PLUGIN_VERSION;} +void plugin_but_changed(int but) {} +void plugin_init() {} + +void plugin_getinfo(PluginInfo *info) { + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + +static void hsv_to_rgb (double h, double s, double v, + double *r, double *g, double *b) +{ + int i; + double f, w, q, t; + + if (s == 0.0) + s = 0.000001; + + if (h == -1.0) + { + *r = v; + *g = v; + *b = v; + } + else + { + if (h == 360.0) + h = 0.0; + h = h / 60.0; + i = (int) h; + f = h - i; + w = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + switch (i) + { + case 0: + *r = v; + *g = t; + *b = w; + break; + case 1: + *r = q; + *g = v; + *b = w; + break; + case 2: + *r = w; + *g = v; + *b = t; + break; + case 3: + *r = w; + *g = q; + *b = v; + break; + case 4: + *r = t; + *g = w; + *b = v; + break; + case 5: + *r = v; + *g = w; + *b = q; + break; + } + } +} + +static void rgb_to_hsv (double r, double g, double b, + double *h, double *s, double *v) +{ + double max, min, delta; + + max = r; + if (g > max) + max = g; + if (b > max) + max = b; + + min = r; + if (g < min) + min = g; + if (b < min) + min = b; + + *v = max; + + if (max != 0.0) + *s = (max - min) / max; + else + *s = 0.0; + + if (*s == 0.0) + *h = -1.0; + else + { + delta = max - min; + + if (r == max) + *h = (g - b) / delta; + else if (g == max) + *h = 2.0 + (b - r) / delta; + else if (b == max) + *h = 4.0 + (r - g) / delta; + + *h = *h * 60.0; + + if (*h < 0.0) + *h = *h + 360; + } +} + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, + int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) { + char *dest, *src1; + int x, y, c; + double gamma_table[256]; + double uv_table[256]; + float *destf = out->rect_float; + float *src1f = ibuf1->rect_float; + + if (!ibuf1) return; + + dest= (char *) out->rect; + src1= (char *) ibuf1->rect; + + for (y = 0; y < 256; y++) { + float v = 1.0 * y / 255; + v += cast->setup_y; + v *= cast->gain_y; + v = pow(v, cast->gamma_y); + if ( v > 1.0) { + v = 1.0; + } else if (v < 0.0) { + v = 0.0; + } + gamma_table[y] = v * 255; + } + + for (y = 0; y < 256; y++) { + float v = 1.0; + v *= cast->master_sat; + if (y < cast->lo_thres * 255) { + v *= cast->sat_shadows; + } else if (y > cast->hi_thres * 255) { + v *= cast->sat_highlights; + } else { + v *= cast->sat_midtones; + } + uv_table[y] = v; + } + + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + double h,s,v,r,g,b; + double fac; + + if (ibuf1->rect_float) rgb_to_hsv(src1f[0], src1f[1], + src1f[2],&h,&s,&v); + else rgb_to_hsv((double) src1[0]/255.0, + (double) src1[1]/255.0, + (double) src1[2]/255.0, + &h, &s, &v); + v = gamma_table[(int) (v * 255.0)] / 255.0; + + fac = uv_table[(int) (255.0 * v)]; + + s *= fac; + if (s >= 1.0) { + s = 1.0; + } + hsv_to_rgb(h,s,v, &r, &g, &b); + + if (out->rect_float) { + destf[0] = r; + destf[1] = g; + destf[2] = b; + destf = destf + 4; + src1f +=4; + } else { + dest[0] = r*255.0; + dest[1] = g*255.0; + dest[2] = b*255.0; + dest += 4; + } + + src1 += 4; + } + } + + if (cast->debug) { + dest= (char *) out->rect; + for (c = 0; c < 10; c++) { + x = 0; + for (y = 0; y < 256; y++) { + char val = gamma_table[y]; + while (x < y * width / 255) { + *dest++ = val; + *dest++ = val; + *dest++ = val; + dest++; + x++; + } + } + } + for (c = 0; c < 10; c++) { + x = 0; + for (y = 0; y < 256; y++) { + char val = uv_table[y] * 255.0/10.0; + while (x < y * width / 255) { + *dest++ = val; + *dest++ = val; + *dest++ = val; + dest++; + x++; + } + } + } + } +} diff --git a/release/plugins/sequence/color-correction-yuv.c b/release/plugins/sequence/color-correction-yuv.c new file mode 100644 index 00000000000..54290ba37a2 --- /dev/null +++ b/release/plugins/sequence/color-correction-yuv.c @@ -0,0 +1,235 @@ +/* + * Color Correction Plugin (YUV Version) 0.01 + * + * Copyright (c) 2005 Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "math.h" +#include "plugin.h" +#include + +char name[]= "Color Correction"; + +VarStruct varstr[]= { + { NUMSLI|FLO, "St Y:", 0.0, -1.0, 1.0, "Setup Y"}, + { NUMSLI|FLO, "Gn Y:", 1.0, 0.0, 10.0,"Gain Y"}, + { NUMSLI|FLO, "Ga Y:", 1.0, 0.0, 10.0, "Gamma Y"}, + + { NUMSLI|FLO, "Lo S:", 1.0, 0.0, 10.0,"Saturation Shadows"}, + { NUMSLI|FLO, "Md S:", 1.0, 0.0, 10.0,"Saturation Midtones"}, + { NUMSLI|FLO, "Hi S:", 1.0, 0.0, 10.0,"Saturation Highlights"}, + + { NUMSLI|FLO, "MA S:", 1.0, 0.0, 10.0,"Master Saturation"}, + { NUMSLI|FLO, "Lo T:", 0.25, 0.0, 1.0, + "Saturation Shadow Thres"}, + { NUMSLI|FLO, "Hi T:", 0.75, 0.0, 1.0, + "Saturation Highlights Thres"}, + { TOG|INT, "Debug", 0.0, 0.0, 1.0, + "Show curves as overlay."}, +}; + +typedef struct Cast { + float setup_y; + float gain_y; + float gamma_y; + + float sat_shadows; + float sat_midtones; + float sat_highlights; + + float master_sat; + float lo_thres; + float hi_thres; + int debug; +} Cast; + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +int plugin_seq_getversion(void) { return B_PLUGIN_VERSION;} +void plugin_but_changed(int but) {} +void plugin_init() {} + +void plugin_getinfo(PluginInfo *info) { + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + +static void rgb_to_yuv(float rgb[3], float yuv[3]) { + yuv[0]= 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2]; + yuv[1]= 0.492*(rgb[2] - yuv[0]); + yuv[2]= 0.877*(rgb[0] - yuv[0]); + + /* Normalize */ + yuv[1] /= 0.436; + yuv[2] /= 0.615; +} + +static void yuv_to_rgb(float yuv[3], float rgb[3]) { + yuv[1] *= 0.436; + yuv[2] *= 0.615; + + rgb[0] = yuv[2]/0.877 + yuv[0]; + rgb[2] = yuv[1]/0.492 + yuv[0]; + rgb[1] = (yuv[0] - 0.299*rgb[0] - 0.114*rgb[2]) / 0.587; + if (rgb[0] > 1.0) { + rgb[0] = 1.0; + } + if (rgb[0] < 0.0) { + rgb[0] = 0.0; + } + if (rgb[1] > 1.0) { + rgb[1] = 1.0; + } + if (rgb[1] < 0.0) { + rgb[1] = 0.0; + } + if (rgb[2] > 1.0) { + rgb[2] = 1.0; + } + if (rgb[2] < 0.0) { + rgb[2] = 0.0; + } +} + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, + int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) { + char *dest, *src1, *src2; + int x, y, c; + float rgb[3]; + float yuv[3]; + float gamma_table[256]; + float uv_table[256]; + float *destf = out->rect_float; + float *src1f = ibuf1->rect_float; + + if (!ibuf1) return; + + dest= (char *) out->rect; + src1= (char *) ibuf1->rect; + + for (y = 0; y < 256; y++) { + float v = 1.0 * y / 255; + v += cast->setup_y; + v *= cast->gain_y; + v = pow(v, cast->gamma_y); + if ( v > 1.0) { + v = 1.0; + } else if (v < 0.0) { + v = 0.0; + } + gamma_table[y] = v * 255; + } + + for (y = 0; y < 256; y++) { + float v = 1.0; + v *= cast->master_sat; + if (y < cast->lo_thres * 255) { + v *= cast->sat_shadows; + } else if (y > cast->hi_thres * 255) { + v *= cast->sat_highlights; + } else { + v *= cast->sat_midtones; + } + uv_table[y] = v; + } + + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + float fac; + if (out->rect_float) { + rgb[0]= (float)src1f[0]/255.0; + rgb[1]= (float)src1f[1]/255.0; + rgb[2]= (float)src1f[2]/255.0; + } else { + rgb[0]= (float)src1[0]/255.0; + rgb[1]= (float)src1[1]/255.0; + rgb[2]= (float)src1[2]/255.0; + } + rgb_to_yuv(rgb, yuv); + + yuv[0] = gamma_table[(int) (yuv[0] * 255.0)] / 255.0; + fac = uv_table[(int) (255.0 * yuv[0])]; + + yuv[1] = yuv[1] * fac; + yuv[2] = yuv[2] * fac; + if (yuv[1] > 1.0) { + yuv[1] = 1.0; + } + if (yuv[1] < -1.0) { + yuv[1] = -1.0; + } + if (yuv[2] > 1.0) { + yuv[2] = 1.0; + } + if (yuv[2] < -1.0) { + yuv[2] = -1.0; + } + yuv_to_rgb(yuv, rgb); + + if (out->rect_float) { + *destf++ = rgb[0]; + *destf++ = rgb[1]; + *destf++ = rgb[2]; + destf++; + src1f += 4; + } else { + *dest++ = rgb[0]*255.0; + *dest++ = rgb[1]*255.0; + *dest++ = rgb[2]*255.0; + dest++; + src1 += 4; + } + } + } + + if (cast->debug) { + dest= (char *) out->rect; + for (c = 0; c < 10; c++) { + x = 0; + for (y = 0; y < 256; y++) { + char val = gamma_table[y]; + while (x < y * width / 255) { + *dest++ = val; + *dest++ = val; + *dest++ = val; + dest++; + x++; + } + } + } + for (c = 0; c < 10; c++) { + x = 0; + for (y = 0; y < 256; y++) { + char val = uv_table[y] * 255.0/10.0; + while (x < y * width / 255) { + *dest++ = val; + *dest++ = val; + *dest++ = val; + dest++; + x++; + } + } + } + } +} diff --git a/release/plugins/sequence/dnr.c b/release/plugins/sequence/dnr.c new file mode 100644 index 00000000000..7e7c168750e --- /dev/null +++ b/release/plugins/sequence/dnr.c @@ -0,0 +1,149 @@ +/* + * Dynamic Noise Reduction (based on the VirtualDub filter by Steven Don) + * + * Copyright (c) 2005 Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "math.h" +#include "plugin.h" +#include + +char name[]= "Dynamic Noise Reduction"; + +VarStruct varstr[]= { + { NUMSLI|INT, "Level:", 10.0, 0.0, 15.0, "Level"}, +}; + +typedef struct Cast { + int level; +} Cast; + +float cfra; +void * plugin_private_data; + +struct my_data { + unsigned char lookup_table[65536]; + int last_level; + float last_cfra; + int last_width; + int last_height; + unsigned char * last_frame; +}; + +void plugin_seq_doit(Cast *, float, float, int, int, + ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +int plugin_seq_getversion(void) { return B_PLUGIN_VERSION;} + +static void precalculate(unsigned char * table, int level) +{ + int ap_, bp; + + for (ap_ = 0; ap_ < 256; ap_++) { + for (bp = 0; bp < 256; bp++) { + int ap = ap_; + int diff = ap - bp; + if (diff < 0) { + diff = -diff; + } + if (diff < level) { + if (diff > (level >> 1)) { + ap = (ap + ap + bp)/3; + } else { + ap = bp; + } + } + + *table++ = ap; + } + } +} + +void plugin_but_changed(int but) { } +void plugin_init() { } + +void * plugin_seq_alloc_private_data() +{ + struct my_data * result = (struct my_data*) calloc( + sizeof(struct my_data), 1); + result->last_cfra = -1; + return result; +} + +void plugin_seq_free_private_data(void * data) +{ + struct my_data * d = (struct my_data*) data; + if (d->last_frame) { + free(d->last_frame); + } + free(d); +} + +void plugin_getinfo(PluginInfo *info) { + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + +static void doit(unsigned char * src_, unsigned char * dst_, + unsigned char * table, int width, int height) +{ + int count = width * height; + unsigned char * src = src_; + unsigned char * dst = dst_; + + while (count--) { + *dst++ = table[(*src++ << 8) | *dst]; + *dst++ = table[(*src++ << 8) | *dst]; + *dst++ = table[(*src++ << 8) | *dst]; + *dst++ = *src++; + } + + memcpy(src_, dst_, width * height * 4); +} + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, + int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) { + + struct my_data * d = (struct my_data*) plugin_private_data; + + if (!ibuf1) return; + + if (cast->level != d->last_level) { + precalculate(d->lookup_table, cast->level); + d->last_level = cast->level; + } + + if (width != d->last_width || height != d->last_height + || cfra != d->last_cfra + 1) { + free(d->last_frame); + d->last_frame = (unsigned char*) calloc(width * height, 4); + + d->last_width = width; + d->last_height = height; + } + + memcpy(out->rect, ibuf1->rect, width * height * 4); + + doit((unsigned char*) out->rect, + d->last_frame, d->lookup_table, width, height); + + d->last_cfra = cfra; +} diff --git a/release/plugins/sequence/gamma.c b/release/plugins/sequence/gamma.c new file mode 100644 index 00000000000..e1380746cea --- /dev/null +++ b/release/plugins/sequence/gamma.c @@ -0,0 +1,182 @@ +/* + * Gamma Correction Plugin (RGB Version) 0.01 + * + * Copyright (c) 2005 Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "math.h" +#include "plugin.h" +#include "util.h" +#include + +#define alpha_epsilon 0.0001f +char name[]= "Gamma Correction"; + +VarStruct varstr[]= { + { NUMSLI|FLO, "St M:", 0.0, -1.0, 1.0, "Setup Main"}, + { NUMSLI|FLO, "Gn M:", 1.0, 0.0, 10.0,"Gain Main"}, + { NUMSLI|FLO, "Ga M:", 1.0, 0.0, 10.0, "Gamma Main"}, + + { NUMSLI|FLO, "St R:", 0.0, -1.0, 1.0, "Setup Red"}, + { NUMSLI|FLO, "Gn R:", 1.0, 0.0, 10.0,"Gain Red"}, + { NUMSLI|FLO, "Ga R:", 1.0, 0.0, 10.0, "Gamma Red"}, + + { NUMSLI|FLO, "St G:", 0.0, -1.0, 1.0, "Setup Green"}, + { NUMSLI|FLO, "Gn G:", 1.0, 0.0, 10.0,"Gain Green"}, + { NUMSLI|FLO, "Ga G:", 1.0, 0.0, 10.0, "Gamma Green"}, + + { NUMSLI|FLO, "St B:", 0.0, -1.0, 1.0, "Setup Blue"}, + { NUMSLI|FLO, "Gn B:", 1.0, 0.0, 10.0,"Gain Blue"}, + { NUMSLI|FLO, "Ga B:", 1.0, 0.0, 10.0, "Gamma Blue"}, +}; + +typedef struct Cast { + float setup_m; + float gain_m; + float gamma_m; + + float setup_r; + float gain_r; + float gamma_r; + + float setup_g; + float gain_g; + float gamma_g; + + float setup_b; + float gain_b; + float gamma_b; +} Cast; + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + +int plugin_seq_getversion(void) { return B_PLUGIN_VERSION; } +void plugin_but_changed(int but) {} +void plugin_init() {} + +void plugin_getinfo(PluginInfo *info) { + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + +static void make_gamma_table(float setup, float gain, float gamma, + unsigned char * table) +{ + int y; + + for (y = 0; y < 256; y++) { + float v = 1.0 * y / 255; + v += setup; + v *= gain; + v = pow(v, gamma); + if ( v > 1.0) { + v = 1.0; + } else if (v < 0.0) { + v = 0.0; + } + table[y] = v * 255; + } + +} + + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, + int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) { + if (!out->rect_float) + { + unsigned char *dest, *src1, *src2; + int x, y, c; + unsigned char gamma_table_m[256]; + unsigned char gamma_table_r[256]; + unsigned char gamma_table_g[256]; + unsigned char gamma_table_b[256]; + + if (!ibuf1) return; + + dest= (unsigned char *) out->rect; + src1= (unsigned char *) ibuf1->rect; + + make_gamma_table(cast->setup_m, cast->gain_m, cast->gamma_m, + gamma_table_m); + make_gamma_table(cast->setup_r, cast->gain_r, cast->gamma_r, + gamma_table_r); + make_gamma_table(cast->setup_g, cast->gain_g, cast->gamma_g, + gamma_table_g); + make_gamma_table(cast->setup_b, cast->gain_b, cast->gamma_b, + gamma_table_b); + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + *dest++ = gamma_table_r[gamma_table_m[*src1++]]; + *dest++ = gamma_table_g[gamma_table_m[*src1++]]; + *dest++ = gamma_table_b[gamma_table_m[*src1++]]; + dest++; src1++; + } + } + } + else + { + float *i=ibuf1->rect_float; + float *o=out->rect_float; + unsigned int size=width*height; + unsigned int k; + float val_r[3]={cast->setup_r,cast->gain_r,cast->gamma_r}; + float val_g[3]={cast->setup_g,cast->gain_g,cast->gamma_g}; + float val_b[3]={cast->setup_b,cast->gain_b,cast->gamma_b}; + float *vals[3]={val_r,val_g,val_b}; + for (k=0;kgamma_m!=1.f || cast->setup_m!=0.f || cast->gain_m!=1.f) + { + float alpha=CLAMP(i[3],0.f,1.f); + if (alpha>alpha_epsilon) { + int l; + for (l=0;l<3;++l) + { + float *val=vals[l]; + o[l]=i[l]/alpha; + o[l]=pow((o[l]+cast->setup_m)*cast->gain_m,cast->gamma_m); + if (val[2]!=1.f || val[0]!=0.f || val[1]!=1.f) + { + o[l]=pow((o[l]+val[0])*val[1],val[2]); + } + o[l]*=alpha; + o[l]=CLAMP(o[l],0.f,1.f); + } + } else { + o[0]=o[1]=o[2]=0.0; + } + o[3]=1.0; + } + else + { + int l; + for (l=0;l<3;++l) + o[l]=CLAMP(i[l],0.f,1.f); + o[3]=1.0; + } + i+=4; + o+=4; + } + } +} diff --git a/release/plugins/sequence/scatter.c b/release/plugins/sequence/scatter.c new file mode 100644 index 00000000000..277529690c4 --- /dev/null +++ b/release/plugins/sequence/scatter.c @@ -0,0 +1,263 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "plugin.h" + +/* ******************** GLOBAL VARIABLES ***************** */ + + +char name[24]= "scatter"; + +/* structure for buttons, + * butcode name default min max 0 + */ + +VarStruct varstr[]= { + LABEL, "Input: 1 strip", 0.0, 0.0, 0.0, "", + NUM|INT, "seed: ", 1.0, 0.0, 10.0, "Offset in random table", + NUMSLI|FLO, "swing: ", 1.0, 0.0, 3.0, "The amplitude, width of the effect", + TOG|INT, "wrap", 0.0, 0.0, 1.0, "Cyclic wrap around the left/right edges", + NUM|INT, "type: ", 1.0, 0.0, 1.0, "Type 1 is random for each frame", +}; + +/* The cast struct is for input in the main doit function + Varstr and Cast must have the same variables in the same order */ + +typedef struct Cast { + int dummy; /* because of the 'label' button */ + int seed; + float swing; + int wrap; + int type; +} Cast; + +/* cfra: the current frame */ + +float cfra; + +void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); + + +/* ******************** Fixed functions ***************** */ + +int plugin_seq_getversion(void) +{ + return B_PLUGIN_VERSION; +} + +void plugin_but_changed(int but) +{ +} + +void plugin_init() +{ +} + +void plugin_getinfo(PluginInfo *info) +{ + info->name= name; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + info->cfra= &cfra; + + info->varstr= varstr; + + info->init= plugin_init; + info->seq_doit= (SeqDoit) plugin_seq_doit; + info->callback= plugin_but_changed; +} + + +/* ************************************************************ + Scatter + + ************************************************************ */ + +static void rectcpy(ImBuf *dbuf, ImBuf *sbuf, + int destx, int desty, + int srcx, int srcy, int width, int height) +{ + uint *drect,*srect; + float *dfrect, *sfrect; + int tmp; + + if (dbuf == 0) return; + + if (destx < 0){ + srcx -= destx ; + width += destx ; + destx = 0; + } + if (srcx < 0){ + destx -= srcx ; + width += destx ; + srcx = 0; + } + if (desty < 0){ + srcy -= desty ; + height += desty ; + desty = 0; + } + if (srcy < 0){ + desty -= srcy ; + height += desty ; + srcy = 0; + } + + if (width > dbuf->x - destx) width = dbuf->x - destx; + if (height > dbuf->y - desty) height = dbuf->y - desty; + if (sbuf){ + if (width > sbuf->x - srcx) width = sbuf->x - srcx; + if (height > sbuf->y - srcy) height = sbuf->y - srcy; + srect = sbuf->rect; + sfrect = sbuf->rect_float; + } + + if (width <= 0) return; + if (height <= 0) return; + + drect = dbuf->rect; + dfrect = dbuf->rect_float; + + tmp = (desty * dbuf->x + destx); + + if (dbuf->rect_float) dfrect += 4 * tmp; + else drect += tmp; + + destx = dbuf->x; + + if (sbuf) { + tmp = (srcy * sbuf->x + srcx ); + if (dbuf->rect_float) sfrect += 4 * tmp; + else srect += tmp; + srcx = sbuf->x; + } else{ + if (dbuf->rect_float) sfrect = dfrect; + else srect = drect; + srcx = destx; + } + + for (;height > 0; height--){ + if (dbuf->rect_float) { + memcpy(dfrect,sfrect, 4 * width * sizeof(float)); + dfrect += destx; + sfrect += srcx; + } else { + memcpy(drect,srect, width * sizeof(int)); + drect += destx; + srect += srcx; + } + } +} + +static void fill_out(ImBuf *out, float r, float g, float b, float a) +{ + int tot,x; + float *rectf = out->rect_float; + unsigned char *rect = (unsigned char *)out->rect; + + tot = out->x * out->y; + if (out->rect_float) { + for (x = 0;x < tot; x++) { + rectf[0] = r; + rectf[1] = g; + rectf[2] = b; + rectf[3] = a; + rectf += 4; + } + } else { + for (x=0;x < tot;x++) { + rect[0] = (int)(r * 255); + rect[1] = (int)(g * 255); + rect[2] = (int)(b * 255); + rect[3] = (int)(a * 255); + rect += 4; + } + } +} + + +void plugin_seq_doit(Cast *cast, float facf0, float facf1, int sx, int sy, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *out, ImBuf *use) +{ + float f1, f2, t1, t2, t3; + int x, y, lr; + + /* fill imbuf 'out' with black */ + fill_out(out, 0,0,0,0); + + + switch (cast->type) { + case 0: + srand48(cast->seed); + break; + case 1: + srand48(cast->seed + facf0 * 1000); + break; + } + + for (y = 0; y < sy; y++) { + switch (cast->type) { + case 0: + if ((y & 1) == 0) { + f1 = drand48() - 0.5; + f2 = drand48() - 0.5; + f1 = cast->swing * f1; + f2 = cast->swing * f2; + if (cast->wrap) f2 += 1.0; + lr = drand48()>0.5; + t1 = facf0; + } else t1 = facf1; + + t2 = 1.0 - t1; + t3 = 3.0 * (f1 * t1 * t1 * t2 + f2 * t1 * t2 * t2); + if (cast->wrap) t3 += t2 * t2 * t2; + x = sx * t3; + if (lr) x = -x; + break; + case 1: + f1 = drand48() - 0.5; + f1 = f1 * cast->swing; + if ((y & 1) == 0) f1 *= facf0; + else f1 *= facf1; + x = f1 * sx; + break; + } + + rectcpy(out, ibuf1, 0, y, x, y, 32767, 1); + if (cast->wrap) { + rectcpy(out, ibuf1, 0, y, x + sx, y, 32767, 1); + rectcpy(out, ibuf1, 0, y, x + sx + sx, y, 32767, 1); + rectcpy(out, ibuf1, 0, y, x - sx, y, 32767, 1); + rectcpy(out, ibuf1, 0, y, x - sx - sx, y, 32767, 1); + } + } +} + diff --git a/release/plugins/texture/Makefile b/release/plugins/texture/Makefile new file mode 100644 index 00000000000..dc632c5d2e7 --- /dev/null +++ b/release/plugins/texture/Makefile @@ -0,0 +1,38 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** + +all: plugins + +plugins: + @/bin/sh -c 'for i in *.c; do ../bmake $$i; done;' + +clean: + rm -rf *.o *.so diff --git a/release/plugins/texture/clouds2.c b/release/plugins/texture/clouds2.c new file mode 100644 index 00000000000..69f890e4df3 --- /dev/null +++ b/release/plugins/texture/clouds2.c @@ -0,0 +1,182 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "math.h" +#include "plugin.h" + +/* ******************** GLOBAL VARIABLES ***************** */ + +/* Texture name */ + +char name[24]= "Clouds2"; + +/* Subtype names must be less than 15 characters */ + +#define NR_TYPES 3 +char stnames[NR_TYPES][16]= {"Intens", "Col", "Bump" }; + +/* Structure for buttons, + * butcode name default min max 0 + */ + +VarStruct varstr[]= { +{ NUM|FLO, "Offset", -0.5, -20.0, 20.0, ""}, +{ NUM|INT, "Depth", 8.0, 1.0, 12.0, ""}, +{ NUM|FLO, "Scale", 2.2, -20.0, 20.0, ""}, +{ NUM|FLO, "Falloff", 1.0, -20.0, 20.0, ""} +}; + +/* The cast struct is for input in the main doit function + Varstr and Cast must have the same variables in the same order, + INCLUDING dummy variables for label fields. */ + +typedef struct Cast { + float offset; + int depth; + float txtscale; + float falloff; +} Cast; + +/* result: + Intensity, R, G, B, Alpha, nor.x, nor.y, nor.z + */ + +float result[8]; + +/* cfra: the current frame */ + +float cfra; + +int plugin_tex_doit(int, Cast*, float*, float*, float*); +void plugin_instance_init(Cast*); + +/* ******************** Fixed functions ***************** */ + +int plugin_tex_getversion(void) +{ + return B_PLUGIN_VERSION; +} + +void plugin_but_changed(int but) +{ +} + +void plugin_init(void) +{ + +} + +/* + * initialize any data for a particular instance of + * the plugin here + */ +void plugin_instance_init(Cast *cast) +{ +} + +/* this function should not be changed: */ + +void plugin_getinfo(PluginInfo *info) +{ + info->name= name; + info->stypes= NR_TYPES; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + + info->snames= stnames[0]; + info->result= result; + info->cfra= &cfra; + info->varstr= varstr; + + info->init= plugin_init; + info->tex_doit= (TexDoit) plugin_tex_doit; + info->callback= plugin_but_changed; + info->instance_init= (void (*)(void *)) plugin_instance_init; +} + +/* ********************* the texture ******************** */ + + +int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) +{ + float val = 0.0; + float a = 1.0; + float p[3]; + float tv[3]; + int i; + int res = TEX_INT; + + tv[0]=(texvec[0]+1.0)/2.0; + tv[1]=(texvec[1]+1.0)/2.0; + tv[2]=(texvec[2]+1.0)/2.0; + + p[0] = cast->txtscale * tv[0]; + p[1] = cast->txtscale * tv[1]; + p[2] = cast->txtscale * tv[2]; + + for (i=0; idepth; i++) { + val += a * hnoise(1.0, p[0], p[1], p[2]); + + p[0] *= 2.0; + p[1] *= 2.0; + p[2] *= 2.0; + a *= 0.5; + } + + /* always return this value */ + result[0] = CLAMP (val+cast->offset, 0.0, 1.0) * pow (fabs(sqrt(tv[0]*tv[0]+tv[1]*tv[1]+tv[2]*tv[2])), cast->falloff); + + if(stype==1) { + /* + * this is r, g, b, a: + */ + result[1]= 0.5*result[0]; + result[2]= 1.0-val; + result[3]= fsqrt(fabs(result[0])); + result[4]= 1.0; + + res |= TEX_RGB; + } + if(stype==2) { + /* + * This value is the displacement of the actual normal in + * the Material calculation. + */ + result[5]+= val; + result[6]+= 1.0-val; + result[7]= 0.0; + + res |= TEX_NOR; + } + + return res; +} + diff --git a/release/plugins/texture/tiles.c b/release/plugins/texture/tiles.c new file mode 100644 index 00000000000..2bdf669f9ca --- /dev/null +++ b/release/plugins/texture/tiles.c @@ -0,0 +1,181 @@ + /** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "math.h" +#include "plugin.h" + +/* ******************** GLOBAL VARIABLES ***************** */ + +char name[]= "tiles"; + +/* Subtype names must be less than 15 characters */ + +#define NR_TYPES 2 +char stnames[NR_TYPES][16]= {"Square", "Deformed"}; + +VarStruct varstr[]= { + NUM|FLO, "size", 1.0, 0.0, 1.0, "The size of each tile", + NUM|FLO, "Noise", 1.0, 0.01, 10.0, "" +}; + +/* The cast struct is for input in the main doit function + Varstr and Cast must have the same variables in the same order */ + +typedef struct Cast { + float size; + float noise; +} Cast; + +/* result: + Intensity, R, G, B, Alpha, nor.x, nor.y, nor.z + */ + +float result[8]; + +/* cfra: the current frame */ + +float cfra; + +int plugin_tex_doit(int, Cast *, float *, float *, float *); +void plugin_instance_init(Cast*); + +/* ******************** Fixed functions ***************** */ + +int plugin_tex_getversion(void) +{ + return B_PLUGIN_VERSION; +} + +void plugin_but_changed(int but) +{ +} + +void plugin_init(void) +{ +} + +/* + * initialize any data for a particular instance of + * the plugin here + */ +void plugin_instance_init(Cast *cast) +{ +} + +/* this function should not be changed: */ + +void plugin_getinfo(PluginInfo *info) +{ + info->name= name; + info->stypes= NR_TYPES; + info->nvars= sizeof(varstr)/sizeof(VarStruct); + + info->snames= stnames[0]; + info->result= result; + info->cfra= &cfra; + info->varstr= varstr; + + info->init= plugin_init; + info->tex_doit= (TexDoit) plugin_tex_doit; + info->callback= plugin_but_changed; + info->instance_init= (void (*)(void *)) plugin_instance_init; + +} + +/* ************************************************************ + Tiles + + Demonstration of a simple square wave function sampled + with anti-aliasing. + It is not mipmapped yet... + + ************************************************************ */ + + +/* square wave, antialiased, no mipmap! */ + +float sample_wave(float freq, float coord, float pixsize) +{ + float fac, frac, retval; + int part1, part2; + + if(pixsize > freq) return 0.5; + + pixsize/= freq; + + fac= coord/freq; + part1= ffloor(fac); + frac= fac - part1; + + if(part1 & 1) retval= 0.0; + else retval= 1.0; + + if(pixsize != 0.0) { + + /* is coord+pixsize another value? */ + + part2= ffloor(fac + pixsize); + if(part1==part2) return retval; + + /* antialias */ + if(retval==1.0) retval= (1.0-frac)/pixsize; + else retval= 1.0-(1.0-frac)/pixsize; + } + return retval; +} + +int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) +{ + float xwave, ywave; + + if(stype==1) { + texvec[0]+= hnoise(cast->noise, texvec[0], texvec[1], texvec[2]); + texvec[1]+= hnoise(cast->noise, texvec[1], texvec[2], texvec[0]); + } + + if(dxt && dyt) { + xwave= sample_wave(cast->size, texvec[0], fabs(dxt[0]) + fabs(dyt[0]) ); + ywave= sample_wave(cast->size, texvec[1], fabs(dxt[1]) + fabs(dyt[1]) ); + + if(xwave > ywave) result[0]= xwave-ywave; + else result[0]= ywave-xwave; + } + else { + xwave= sample_wave(cast->size, texvec[0], 0.0 ); + ywave= sample_wave(cast->size, texvec[1], 0.0 ); + + if(xwave > ywave) result[0]= xwave-ywave; + else result[0]= ywave-xwave; + } + + return TEX_INT; +} diff --git a/release/scripts/3ds_export.py b/release/scripts/3ds_export.py new file mode 100644 index 00000000000..0209b04844a --- /dev/null +++ b/release/scripts/3ds_export.py @@ -0,0 +1,1013 @@ +#!BPY + +""" +Name: '3D Studio (.3ds)...' +Blender: 243 +Group: 'Export' +Tooltip: 'Export to 3DS file format (.3ds).' +""" + +__author__ = ["Campbell Barton", "Bob Holcomb", "Richard Lärkäng", "Damien McGinnes", "Mark Stijnman"] +__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") +__version__ = "0.90a" +__bpydoc__ = """\ + +3ds Exporter + +This script Exports a 3ds file. + +Exporting is based on 3ds loader from www.gametutorials.com(Thanks DigiBen) and using information +from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +###################################################### +# Importing modules +###################################################### + +import Blender +import bpy +from BPyMesh import getMeshFromObject +from BPyObject import getDerivedObjects +import struct + +# So 3ds max can open files, limit names to 12 in length +# this is verry annoying for filenames! +name_unique = [] +name_mapping = {} +def sane_name(name): + name_fixed = name_mapping.get(name) + if name_fixed != None: + return name_fixed + + if len(name) > 12: + new_name = name[:12] + else: + new_name = name + + i = 0 + + while new_name in name_unique: + new_name = new_name[:-4] + '.%.3d' % i + i+=1 + + name_unique.append(new_name) + name_mapping[name] = new_name + return new_name + +###################################################### +# Data Structures +###################################################### + +#Some of the chunks that we will export +#----- Primary Chunk, at the beginning of each file +PRIMARY= long("0x4D4D",16) + +#------ Main Chunks +OBJECTINFO = long("0x3D3D",16); #This gives the version of the mesh and is found right before the material and object information +VERSION = long("0x0002",16); #This gives the version of the .3ds file +KFDATA = long("0xB000",16); #This is the header for all of the key frame info + +#------ sub defines of OBJECTINFO +MATERIAL=45055 #0xAFFF // This stored the texture info +OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... + +#>------ sub defines of MATERIAL +MATNAME = long("0xA000",16); # This holds the material name +MATAMBIENT = long("0xA010",16); # Ambient color of the object/material +MATDIFFUSE = long("0xA020",16); # This holds the color of the object/material +MATSPECULAR = long("0xA030",16); # SPecular color of the object/material +MATSHINESS = long("0xA040",16); # ?? +MATMAP = long("0xA200",16); # This is a header for a new material +MATMAPFILE = long("0xA300",16); # This holds the file name of the texture + +RGB1= long("0x0011",16) +RGB2= long("0x0012",16) + +#>------ sub defines of OBJECT +OBJECT_MESH = long("0x4100",16); # This lets us know that we are reading a new object +OBJECT_LIGHT = long("0x4600",16); # This lets un know we are reading a light object +OBJECT_CAMERA= long("0x4700",16); # This lets un know we are reading a camera object + +#>------ sub defines of CAMERA +OBJECT_CAM_RANGES= long("0x4720",16); # The camera range values + +#>------ sub defines of OBJECT_MESH +OBJECT_VERTICES = long("0x4110",16); # The objects vertices +OBJECT_FACES = long("0x4120",16); # The objects faces +OBJECT_MATERIAL = long("0x4130",16); # This is found if the object has a material, either texture map or color +OBJECT_UV = long("0x4140",16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = long("0x4160",16); # The Object Matrix + +#>------ sub defines of KFDATA +KFDATA_KFHDR = long("0xB00A",16); +KFDATA_KFSEG = long("0xB008",16); +KFDATA_KFCURTIME = long("0xB009",16); +KFDATA_OBJECT_NODE_TAG = long("0xB002",16); + +#>------ sub defines of OBJECT_NODE_TAG +OBJECT_NODE_ID = long("0xB030",16); +OBJECT_NODE_HDR = long("0xB010",16); +OBJECT_PIVOT = long("0xB013",16); +OBJECT_INSTANCE_NAME = long("0xB011",16); +POS_TRACK_TAG = long("0xB020",16); +ROT_TRACK_TAG = long("0xB021",16); +SCL_TRACK_TAG = long("0xB022",16); + +def uv_key(uv): + return round(uv.x, 6), round(uv.y, 6) + +# size defines: +SZ_SHORT = 2 +SZ_INT = 4 +SZ_FLOAT = 4 + +class _3ds_short(object): + '''Class representing a short (2-byte integer) for a 3ds file. + *** This looks like an unsigned short H is unsigned from the struct docs - Cam***''' + __slots__ = 'value' + def __init__(self, val=0): + self.value=val + + def get_size(self): + return SZ_SHORT + + def write(self,file): + file.write(struct.pack("= mat_ls_len: + mat_index = f.mat = 0 + mat = mat_ls[mat_index] + if mat: mat_name = mat.name + else: mat_name = None + # else there alredy set to none + + img = f.image + if img: img_name = img.name + else: img_name = None + + materialDict.setdefault((mat_name, img_name), (mat, img) ) + + + else: + for mat in mat_ls: + if mat: # material may be None so check its not. + materialDict.setdefault((mat.name, None), (mat, None) ) + + # Why 0 Why! + for f in data.faces: + if f.mat >= mat_ls_len: + f.mat = 0 + + # Make material chunks for all materials used in the meshes: + for mat_and_image in materialDict.itervalues(): + object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) + + # Give all objects a unique ID and build a dictionary from object name to object id: + """ + name_to_id = {} + for ob, data in mesh_objects: + name_to_id[ob.name]= len(name_to_id) + #for ob in empty_objects: + # name_to_id[ob.name]= len(name_to_id) + """ + + # Create object chunks for all meshes: + i = 0 + for ob, blender_mesh in mesh_objects: + # create a new object chunk + object_chunk = _3ds_chunk(OBJECT) + + # set the object name + object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) + + # make a mesh chunk out of the mesh: + object_chunk.add_subchunk(make_mesh_chunk(blender_mesh, materialDict)) + object_info.add_subchunk(object_chunk) + + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + # make a kf object node for the object: + kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) + ''' + blender_mesh.verts = None + i+=i + + # Create chunks for all empties: + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + for ob in empty_objects: + # Empties only require a kf object node: + kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) + pass + ''' + + # Add main object info chunk to primary chunk: + primary.add_subchunk(object_info) + + ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX + # Add main keyframe data chunk to primary chunk: + primary.add_subchunk(kfdata) + ''' + + # At this point, the chunk hierarchy is completely built. + + # Check the size: + primary.get_size() + # Open the file for writing: + file = open( filename, 'wb' ) + + # Recursively write the chunks to file: + primary.write(file) + + # Close the file: + file.close() + + # Debugging only: report the exporting time: + Blender.Window.WaitCursor(0) + print "3ds export time: %.2f" % (Blender.sys.time() - time1) + + # Debugging only: dump the chunk hierarchy: + #primary.dump() + + +if __name__=='__main__': + Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds')) +# save_3ds('/test_b.3ds') diff --git a/release/scripts/3ds_import.py b/release/scripts/3ds_import.py new file mode 100644 index 00000000000..07da4df1603 --- /dev/null +++ b/release/scripts/3ds_import.py @@ -0,0 +1,982 @@ +#!BPY +""" +Name: '3D Studio (.3ds)...' +Blender: 244 +Group: 'Import' +Tooltip: 'Import from 3DS file format (.3ds)' +""" + +__author__= ['Bob Holcomb', 'Richard L?rk?ng', 'Damien McGinnes', 'Campbell Barton'] +__url__ = ("blenderartists.org", "www.blender.org", "www.gametutorials.com", "lib3ds.sourceforge.net/") +__version__= '0.995' +__bpydoc__= '''\ + +3ds Importer + +This script imports a 3ds file and the materials into Blender for editing. + +Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen). + + +0.995 by Campbell Barton
+- workaround for buggy mesh vert delete +- minor tweaks + +0.99 by Bob Holcomb
+- added support for floating point color values that previously broke on import. + +0.98 by Campbell Barton
+- import faces and verts to lists instead of a mesh, convert to a mesh later +- use new index mapping feature of mesh to re-map faces that were not added. + +0.97 by Campbell Barton
+- Strip material names of spaces +- Added import as instance to import the 3ds into its own + scene and add a group instance to the current scene +- New option to scale down imported objects so they are within a limited bounding area. + +0.96 by Campbell Barton
+- Added workaround for bug in setting UV's for Zero vert index UV faces. +- Removed unique name function, let blender make the names unique. + +0.95 by Campbell Barton
+- Removed workarounds for Blender 2.41 +- Mesh objects split by material- many 3ds objects used more then 16 per mesh. +- Removed a lot of unneeded variable creation. + +0.94 by Campbell Barton
+- Face import tested to be about overall 16x speedup over 0.93. +- Material importing speedup. +- Tested with more models. +- Support some corrupt models. + +0.93 by Campbell Barton
+- Tested with 400 3ds files from turbosquid and samples. +- Tactfully ignore faces that used the same verts twice. +- Rollback to 0.83 sloppy un-reorganized code, this broke UV coord loading. +- Converted from NMesh to Mesh. +- Faster and cleaner new names. +- Use external comprehensive image loader. +- Re intergrated 0.92 and 0.9 changes +- Fixes for 2.41 compat. +- Non textured faces do not use a texture flag. + +0.92
+- Added support for diffuse, alpha, spec, bump maps in a single material + +0.9
+- Reorganized code into object/material block functions
+- Use of Matrix() to copy matrix data
+- added support for material transparency
+ +0.83 2005-08-07: Campell Barton +- Aggressive image finding and case insensitivy for posisx systems. + +0.82a 2005-07-22 +- image texture loading (both for face uv and renderer) + +0.82 - image texture loading (for face uv) + +0.81a (fork- not 0.9) Campbell Barton 2005-06-08 +- Simplified import code +- Never overwrite data +- Faster list handling +- Leaves import selected + +0.81 Damien McGinnes 2005-01-09 +- handle missing images better + +0.8 Damien McGinnes 2005-01-08 +- copies sticky UV coords to face ones +- handles images better +- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script + +''' + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +# Importing modules + +import Blender +import bpy +from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils +from Blender.Mathutils import Vector +import BPyImage + +import BPyMessages + +import struct +from struct import calcsize, unpack + +import os + +# If python version is less than 2.4, try to get set stuff from module +try: + set +except: + from sets import Set as set + +BOUNDS_3DS= [] + + +#this script imports uvcoords as sticky vertex coords +#this parameter enables copying these to face uv coords +#which shold be more useful. + +def createBlenderTexture(material, name, image): + texture= bpy.data.textures.new(name) + texture.setType('Image') + texture.image= image + material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + + + +###################################################### +# Data Structures +###################################################### + +#Some of the chunks that we will see +#----- Primary Chunk, at the beginning of each file +PRIMARY= long('0x4D4D',16) + +#------ Main Chunks +OBJECTINFO = long('0x3D3D',16); #This gives the version of the mesh and is found right before the material and object information +VERSION = long('0x0002',16); #This gives the version of the .3ds file +EDITKEYFRAME= long('0xB000',16); #This is the header for all of the key frame info + +#------ sub defines of OBJECTINFO +MATERIAL=45055 #0xAFFF // This stored the texture info +OBJECT=16384 #0x4000 // This stores the faces, vertices, etc... + +#>------ sub defines of MATERIAL +#------ sub defines of MATERIAL_BLOCK +MAT_NAME = long('0xA000',16) # This holds the material name +MAT_AMBIENT = long('0xA010',16) # Ambient color of the object/material +MAT_DIFFUSE = long('0xA020',16) # This holds the color of the object/material +MAT_SPECULAR = long('0xA030',16) # SPecular color of the object/material +MAT_SHINESS = long('0xA040',16) # ?? +MAT_TRANSPARENCY= long('0xA050',16) # Transparency value of material +MAT_SELF_ILLUM = long('0xA080',16) # Self Illumination value of material +MAT_WIRE = long('0xA085',16) # Only render's wireframe + +MAT_TEXTURE_MAP = long('0xA200',16) # This is a header for a new texture map +MAT_SPECULAR_MAP= long('0xA204',16) # This is a header for a new specular map +MAT_OPACITY_MAP = long('0xA210',16) # This is a header for a new opacity map +MAT_REFLECTION_MAP= long('0xA220',16) # This is a header for a new reflection map +MAT_BUMP_MAP = long('0xA230',16) # This is a header for a new bump map +MAT_MAP_FILENAME = long('0xA300',16) # This holds the file name of the texture + +MAT_FLOAT_COLOR = long ('0x0010', 16) #color defined as 3 floats +MAT_24BIT_COLOR = long ('0x0011', 16) #color defined as 3 bytes + +#>------ sub defines of OBJECT +OBJECT_MESH = long('0x4100',16); # This lets us know that we are reading a new object +OBJECT_LAMP = long('0x4600',16); # This lets un know we are reading a light object +OBJECT_LAMP_SPOT = long('0x4610',16); # The light is a spotloght. +OBJECT_LAMP_OFF = long('0x4620',16); # The light off. +OBJECT_LAMP_ATTENUATE = long('0x4625',16); +OBJECT_LAMP_RAYSHADE = long('0x4627',16); +OBJECT_LAMP_SHADOWED = long('0x4630',16); +OBJECT_LAMP_LOCAL_SHADOW = long('0x4640',16); +OBJECT_LAMP_LOCAL_SHADOW2 = long('0x4641',16); +OBJECT_LAMP_SEE_CONE = long('0x4650',16); +OBJECT_LAMP_SPOT_RECTANGULAR= long('0x4651',16); +OBJECT_LAMP_SPOT_OVERSHOOT= long('0x4652',16); +OBJECT_LAMP_SPOT_PROJECTOR= long('0x4653',16); +OBJECT_LAMP_EXCLUDE= long('0x4654',16); +OBJECT_LAMP_RANGE= long('0x4655',16); +OBJECT_LAMP_ROLL= long('0x4656',16); +OBJECT_LAMP_SPOT_ASPECT= long('0x4657',16); +OBJECT_LAMP_RAY_BIAS= long('0x4658',16); +OBJECT_LAMP_INNER_RANGE= long('0x4659',16); +OBJECT_LAMP_OUTER_RANGE= long('0x465A',16); +OBJECT_LAMP_MULTIPLIER = long('0x465B',16); +OBJECT_LAMP_AMBIENT_LIGHT = long('0x4680',16); + + + +OBJECT_CAMERA= long('0x4700',16); # This lets un know we are reading a camera object + +#>------ sub defines of CAMERA +OBJECT_CAM_RANGES= long('0x4720',16); # The camera range values + +#>------ sub defines of OBJECT_MESH +OBJECT_VERTICES = long('0x4110',16); # The objects vertices +OBJECT_FACES = long('0x4120',16); # The objects faces +OBJECT_MATERIAL = long('0x4130',16); # This is found if the object has a material, either texture map or color +OBJECT_UV = long('0x4140',16); # The UV texture coordinates +OBJECT_TRANS_MATRIX = long('0x4160',16); # The Object Matrix + +global scn +scn= None + +#the chunk class +class chunk: + ID=0 + length=0 + bytes_read=0 + + #we don't read in the bytes_read, we compute that + binary_format='3): + print '\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version + + #is it an object info chunk? + elif (new_chunk.ID==OBJECTINFO): + #print 'elif (new_chunk.ID==OBJECTINFO):' + # print 'found an OBJECTINFO chunk' + process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH) + + #keep track of how much we read in the main chunk + new_chunk.bytes_read+=temp_chunk.bytes_read + + #is it an object chunk? + elif (new_chunk.ID==OBJECT): + tempName= read_string(file) + contextObName= tempName + new_chunk.bytes_read += len(tempName)+1 + + #is it a material chunk? + elif (new_chunk.ID==MATERIAL): + #print 'elif (new_chunk.ID==MATERIAL):' + contextMaterial= bpy.data.materials.new('Material') + + elif (new_chunk.ID==MAT_NAME): + #print 'elif (new_chunk.ID==MAT_NAME):' + material_name= read_string(file) + + #plus one for the null character that ended the string + new_chunk.bytes_read+= len(material_name)+1 + + contextMaterial.name= material_name.rstrip() # remove trailing whitespace + MATDICT[material_name]= (contextMaterial.name, contextMaterial) + + elif (new_chunk.ID==MAT_AMBIENT): + #print 'elif (new_chunk.ID==MAT_AMBIENT):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_DIFFUSE): + #print 'elif (new_chunk.ID==MAT_DIFFUSE):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.rgbCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.rgbCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_SPECULAR): + #print 'elif (new_chunk.ID==MAT_SPECULAR):' + read_chunk(file, temp_chunk) + if (temp_chunk.ID==MAT_FLOAT_COLOR): + temp_data=file.read(calcsize('3f')) + temp_chunk.bytes_read+=12 + contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)] + elif (temp_chunk.ID==MAT_24BIT_COLOR): + temp_data=file.read(calcsize('3B')) + temp_chunk.bytes_read+= 3 + contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb + else: + skip_to_end(file, temp_chunk) + new_chunk.bytes_read+= temp_chunk.bytes_read + + elif (new_chunk.ID==MAT_TEXTURE_MAP): + #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):' + new_texture= bpy.data.textures.new('Diffuse') + new_texture.setType('Image') + img = None + while (new_chunk.bytes_read BOUNDS_3DS[i+3]: + BOUNDS_3DS[i+3]= v[i] # min + + # Get the max axis x/y/z + max_axis= max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2]) + # print max_axis + if max_axis < 1<<30: # Should never be false but just make sure. + + # Get a new scale factor if set as an option + SCALE=1.0 + while (max_axis*SCALE) > IMPORT_CONSTRAIN_BOUNDS: + SCALE/=10 + + # SCALE Matrix + SCALE_MAT= Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) + + for ob in importedObjects: + ob.setMatrix(ob.matrixWorld*SCALE_MAT) + + # Done constraining to bounds. + + # Select all new objects. + print 'finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1)) + file.close() + Blender.Window.WaitCursor(0) + + +DEBUG= False +if __name__=='__main__' and not DEBUG: + Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds') + +# For testing compatibility +#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False) +#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False) +''' + +else: + # DEBUG ONLY + TIME= Blender.sys.time() + import os + print 'Searching for files' + os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list') + # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list') + print '...Done' + file= open('/tmp/temp3ds_list', 'r') + lines= file.readlines() + file.close() + # sort by filesize for faster testing + lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] + lines_size.sort() + lines = [f[1] for f in lines_size] + + + def between(v,a,b): + if v <= max(a,b) and v >= min(a,b): + return True + return False + + for i, _3ds in enumerate(lines): + if between(i, 650,800): + #_3ds= _3ds[:-1] + print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines) + _3ds_file= _3ds.split('/')[-1].split('\\')[-1] + newScn= Blender.Scene.New(_3ds_file) + newScn.makeCurrent() + load_3ds(_3ds, False) + + print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) + +''' \ No newline at end of file diff --git a/release/scripts/Axiscopy.py b/release/scripts/Axiscopy.py new file mode 100644 index 00000000000..6a31432edb6 --- /dev/null +++ b/release/scripts/Axiscopy.py @@ -0,0 +1,125 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Axis Orientation Copy' +Blender: 242 +Group: 'Object' +Tip: 'Copy local axis orientation of active object to all selected meshes (changes mesh data)' +""" + +__author__ = "A Vanpoucke (xand)" +__url__ = ("blenderartists.org", "www.blender.org", +"French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") +__version__ = "2 17/12/05" + +__bpydoc__ = """\ +This script copies the axis orientation -- X, Y and Z rotations -- of the +active object to all selected meshes. + +It's useful to align the orientations of all meshes of a structure, a human +skeleton, for example. + +Usage: + +Select all mesh objects that need to have their orientations changed +(reminder: keep SHIFT pressed after the first, to add each new one to the +selection), then select the object whose orientation will be copied from and +finally run this script to update the angles. + +Notes:
+ This script changes mesh data: the vertices are transformed.
+ Before copying the orientation to each object, the script stores its +transformation matrix. Then the angles are copied and after that the object's +vertices are transformed "back" so that they still have the same positions as +before. In other words, the rotations are updated, but you won't notice that +just from looking at the objects.
+ Checking their X, Y and Z rotation values with "Transform Properties" in +the 3D View's Object menu shows the angles are now the same of the active +object. Or simply look at the transform manipulator handles in local transform +orientation. +""" + + +# $Id$ +# +#---------------------------------------------- +# A Vanpoucke (xand) +#from the previous script realignaxis +#---------------------------------------------- +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2003, 2004: A Vanpoucke +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * +from Blender import Mathutils +from Blender.Mathutils import * +import BPyMessages + +def realusers(data): + users = data.users + if data.fakeUser: users -= 1 + return users + + + +def main(): + + scn_obs= Scene.GetCurrent().objects + ob_act = scn_obs.active + scn_obs = scn_obs.context + + if not ob_act: + BPyMessages.Error_NoActive() + + obs = [(ob, ob.getData(mesh=1)) for ob in scn_obs if ob != ob_act] + + for ob, me in obs: + + if ob.type != 'Mesh': + Draw.PupMenu("Error%t|Selection must be made up of mesh objects only") + return + + if realusers(me) != 1: + Draw.PupMenu("Error%t|Meshes must be single user") + return + + if len(obs) < 1: + Draw.PupMenu("Error: you must select at least 2 objects") + return + + result = Draw.PupMenu("Copy axis orientation from: " + ob_act.name + " ?%t|OK") + if result == -1: + return + + for ob_target, me_target in obs: + if ob_act.rot != ob_target.rot: + rot_target = ob_target.matrixWorld.rotationPart().toEuler().toMatrix() + rot_source = ob_act.matrixWorld.rotationPart().toEuler().toMatrix() + rot_source_inv = rot_source.copy().invert() + tx_mat = rot_target * rot_source_inv + tx_mat.resize4x4() + me_target.transform(tx_mat) + ob_target.rot=ob_act.rot + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/DirectX8Exporter.py b/release/scripts/DirectX8Exporter.py new file mode 100644 index 00000000000..3dbd8d9d539 --- /dev/null +++ b/release/scripts/DirectX8Exporter.py @@ -0,0 +1,1167 @@ +#!BPY + +""" +# Name: 'DirectX (.x)...' +# Blender: 242 +# Group: 'Export' +# Tooltip: 'Export to DirectX text file format format for XNA Animation Component Library.' +""" +__author__ = "minahito (original:Arben (Ben) Omari)" +__url__ = ("blender", "elysiun", "Adjuster's site http://sunday-lab.blogspot.com/, Author's site http://www.omariben.too.it") +__version__ = "3.0" + +__bpydoc__ = """\ +This script exports a Blender mesh with armature to DirectX 8's text file +format. + +Notes:
+ Check author's site or the elYsiun forum for a new beta version of the +DX exporter. +""" +# DirectXExporter.py version 3.0 +# Copyright (C) 2006 Arben OMARI -- omariarben@everyday.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# This script export meshes created with Blender in DirectX8 file format +# it exports meshes,armatures,materials,normals,texturecoords and animations + +# Grab the latest version here :www.omariben.too.it + +# [Notice] +# This script is the custom version of Mr.Arben Omari's great work. +# If you have a question about the adjusted part, visit http://sunday-lab.blogspot.com/. + +import Blender +from Blender import Types, Object, NMesh, Material,Armature,Mesh +from Blender.Mathutils import * +from Blender import Draw, BGL +from Blender.BGL import * +import math + +global mat_flip,index_list,space,bone_list,mat_dict +global anim,flip_norm,swap_zy,flip_z,speed,ticks,no_light,recalc_norm,Bl_norm +bone_list =[] +index_list = [] +mat_dict = {} +space = 0;flip_z = 1;anim=0;swap_yz=0;flip_norm=0;speed=0;ticks= 25 +Bl_norm = 1;recalc_norm = 0;no_light = 0 + +toggle_val = 0 +toggle1_val = 0 +toggle2_val = 0 +toggle3_val = 1 +toggle4_val = 0 +toggle5_val = 1 +toggle6_val = 0 +toggle7_val = 0 +anim_tick = Draw.Create(25) + +#*********************************************** +# DirectX file spec only allows letters, digits, and +# underscore in Names. +#*********************************************** +def make_legal_name(starting_name): + new_name = starting_name.replace('.','_') + new_name = new_name.replace(' ','_') + if new_name[0].isdigit(): + new_name = '_' + new_name + return new_name + +#*********************************************** +# MAIN +#*********************************************** + +def my_callback(filename): + if filename.find('.x', -2) <= 0: filename += '.x' + xexport = xExport(filename) + xexport.SelectObjs() + +def my_callback_sel(filename): + if filename.find('.x', -2) <= 0: filename += '.x' + xexport = xExport(filename) + xexport.exportSelMesh() +def event(evt, val): + if evt == Draw.ESCKEY: + Draw.Exit() + return + +def button_event(evt): + global toggle_val,toggle1_val,toggle2_val,toggle3_val,toggle4_val,toggle5_val,toggle6_val,toggle7_val + global flip_z,swap_yz,flip_norm,anim,ticks,speed,no_light,Bl_norm,recalc_norm + arg = __script__['arg'] + if evt == 1: + toggle_val = 1 - toggle_val + anim = toggle_val + Draw.Redraw(1) + if evt == 2: + toggle1_val = 1 - toggle1_val + flip_norm = toggle1_val + Draw.Redraw(1) + if evt == 3: + toggle2_val = 1 - toggle2_val + swap_yz = toggle2_val + Draw.Redraw(1) + if evt == 4: + toggle3_val = 1 - toggle3_val + flip_z = toggle3_val + Draw.Redraw(1) + if evt == 5: + toggle4_val = 1 - toggle4_val + speed = toggle4_val + Draw.Redraw(1) + if evt == 10: + toggle5_val = 1 - toggle5_val + if toggle5_val==1: + toggle6_val = 0 + toggle7_val = 0 + else : + toggle6_val = 1 + toggle7_val = 1 + no_light = toggle7_val + recalc_norm = toggle6_val + Bl_norm = toggle5_val + Draw.Redraw(1) + if evt == 11: + toggle6_val = 1 - toggle6_val + if toggle6_val==1: + toggle5_val = 0 + toggle7_val = 0 + else : + toggle5_val = 1 + toggle7_val = 1 + no_light = toggle7_val + recalc_norm = toggle6_val + Bl_norm = toggle5_val + Draw.Redraw(1) + if evt == 12: + toggle7_val = 1 - toggle7_val + if toggle7_val==1: + toggle6_val = 0 + toggle5_val = 0 + else : + toggle6_val = 1 + toggle5_val = 1 + no_light = toggle7_val + recalc_norm = toggle6_val + Bl_norm = toggle5_val + Draw.Redraw(1) + if evt == 6: + ticks = anim_tick.val + if evt == 7: + fname = Blender.sys.makename(ext = ".x") + Blender.Window.FileSelector(my_callback, "Export DirectX", fname) + if evt == 8: + fname = Blender.sys.makename(ext = ".x") + Blender.Window.FileSelector(my_callback_sel, "Export DirectX", fname) + if evt == 9: + Draw.Exit() + + +def draw(): + global animsg,flipmsg,swapmsg,anim_tick + global flip_z,swap_yz,flip_norm,anim,ticks,speed,recalc_norm,Bl_norm,no_light + glClearColor(0.55,0.6,0.6,1) + glClear(BGL.GL_COLOR_BUFFER_BIT) + #external box + glColor3f(0.2,0.3,0.3) + rect(10,402,300,382) + #-- + #glColor3f(0.3,0.4,0.4) + #rect(11,399,298,398) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,398,292,30) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,366,292,160) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,202,292,60) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,138,292,40) + #-- + glColor3f(0.5,0.75,0.65) + rect(14,94,292,70) + + glColor3f(0.8,.8,0.6) + glRasterPos2i(20, 380) + Draw.Text("DirectX Exporter ",'large') + Draw.Text("(for Blender 2.41)", 'small') + #-------Aniamtion toggle--------------------------------------------- + Draw.Toggle("Anim", 1, 20, 330, 55, 20, toggle_val,"export animations") + if toggle_val : + anim = 1 + animsg = "animation will be exported" + else: + anim = 0 + animsg = "animation will be not exported" + glRasterPos2i(100,335) + Draw.Text(animsg) + #---Flip normals toggle----------------------------------------------- + Draw.Toggle("Flip norm", 2, 20, 300, 55, 20, toggle1_val,"invert normals") + if toggle1_val : + flip_norm = 1 + flipmsg = "flipped normals" + else: + flip_norm = 0 + flipmsg = "not flipped normals" + glRasterPos2i(100,305) + Draw.Text(flipmsg) + #------Swap yz toggle---------------------------------------------------------------- + Draw.Toggle("Swap zy", 3, 20, 270, 55, 20, toggle2_val,"swap z,y axis(y up)") + if toggle2_val : + swap_yz = 1 + swapmsg = "Y-axis up" + else: + swap_yz = 0 + swapmsg = "Z-axis up" + glRasterPos2i(100,275) + Draw.Text(swapmsg) + #------Flip z toggle---------------------------------------------------------------- + Draw.Toggle("Flip z", 4, 20, 240, 55, 20, toggle3_val,"flip z axis") + if toggle3_val : + flip_z = 1 + zmsg = "left handed system" + else: + flip_z = 0 + zmsg = "right handed system" + glRasterPos2i(100,245) + Draw.Text(zmsg) + #------Speed toggle---------------------------------------------------------------- + Draw.Toggle("Speed", 5, 20, 210, 55, 20, toggle4_val,"Animation speed") + if toggle4_val : + speed = 1 + spedmsg = "set speed" + anim_tick = Draw.Number("", 6,200, 210, 85, 20, anim_tick.val,1,100000,"ticks per second") + else: + speed = 0 + spedmsg = "" + glRasterPos2i(100,215) + Draw.Text(spedmsg) + #------Blender Normals toggle---------------------------------------------------------------- + Draw.Toggle("Bl.normals", 10, 20, 105, 75, 25, toggle5_val,"export normals as in Blender") + if toggle5_val : + Bl_norm = 1 + #------Recalculute Normals toggle---------------------------------------------------------------- + Draw.Toggle("recalc.no", 11, 120, 105, 75, 25, toggle6_val,"export recalculated normals") + if toggle6_val : + recalc_norm = 1 + #------Recalculute Normals toggle---------------------------------------------------------------- + Draw.Toggle("no smooth", 12, 220, 105, 75, 25, toggle7_val,"every vertex has the face normal,no smoothing") + if toggle7_val : + no_light = 1 + #------Draw Button export---------------------------------------------------------------- + exp_butt = Draw.Button("Export All",7,20, 155, 75, 30, "export all the scene objects") + sel_butt = Draw.Button("Export Sel",8,120, 155, 75, 30, "export the selected object") + exit_butt = Draw.Button("Exit",9,220, 155, 75, 30, "exit") + glRasterPos2i(20,75) + Draw.Text("(C) 2006 Arben OMARI ") + glRasterPos2i(20,55) + Draw.Text("http://www.omariben.too.it") + glRasterPos2i(20,35) + Draw.Text("aromar@tin.it") + +def rect(x,y,width,height): + glBegin(GL_LINE_LOOP) + glVertex2i(x,y) + glVertex2i(x+width,y) + glVertex2i(x+width,y-height) + glVertex2i(x,y-height) + glEnd() + +def rectFill(x,y,width,height): + glBegin(GL_POLYGON) + glVertex2i(x,y) + glVertex2i(x+width,y) + glVertex2i(x+width,y-height) + glVertex2i(x,y-height) + glEnd() + + + +Draw.Register(draw, event, button_event) + + +#*********************************************** +#*********************************************** +# EXPORTER +#*********************************************** +#*********************************************** + +class xExport: + def __init__(self, filename): + self.file = open(filename, "w") + +#********************************************************************************************************************************************* + #*********************************************** + #Select Scene objects + #*********************************************** + def analyzeScene(self): + parent_list = [] + for obj in Blender.Scene.GetCurrent().objects: + if obj.type in ('Mesh', 'Armature', 'Empty'): + if obj.parent == None : + parent_list.append(obj) + + return parent_list + + def getChildren(self,obj): + obs = Blender.Scene.GetCurrent().objects + return [ ob for ob in obs if ob.parent == obj ] + + def getArmChildren(self,obj): + for ob in Blender.Scene.GetCurrent().objects: #Object.Get(): + if ob.parent == obj : + return ob + + def getLocMat(self, obj): + pare = obj.parent + mat = obj.matrixWorld + mat_id = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) + if pare: + mat_p = pare.matrixWorld + mat_c = Matrix(mat_p) + mat_c.invert() + mat_f = mat * mat_c + else : + mat_id.invert() + mat_f = mat * mat_id + return mat_f + + def writeObjFrames(self,obj): + global space,chld_obj,ch_list + mesh = obj.getData() + if obj.type == "Empty" : + mat = self.getLocMat(obj) + mat_c = Matrix(mat) + self.writeArmFrames(mat_c, make_legal_name(obj.name)) + if type(mesh) == Types.ArmatureType : + Child_obj = self.getArmChildren(obj) + chld_obj = obj + ch_list.append(Child_obj) + self.writeRootBone(obj, Child_obj) + if obj.type == 'Mesh' and obj not in ch_list: + self.exportMesh(obj) + + + def writeChildObj(self,obj): + global space,ch_list + space += 1 + if obj : + for ob in obj: + if ob not in ch_list: + self.writeObjFrames(ob) + ch_list.append(ob) + ch_ob = self.getChildren(ob) + self.writeChildObj(ch_ob) + self.closeBrackets() + self.file.write(" // End of the Object %s \n" % (ob.name)) + + + def writeRootFrame(self): + global flip_z,swap_yz,speed + if speed: + self.writeAnimTicks() + if flip_z: + mat_flip = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]) + else : + mat_flip = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) + if swap_yz : + mat_rot = RotationMatrix(-90, 4, 'x') + mat_flip = mat_rot * mat_flip + self.writeArmFrames(mat_flip, "RootFrame") + + ################################################################## + def SelectObjs(self): + global space,chld_obj,ch_list,flip_z,swap_yz,speed + print "exporting..." + self.writeHeader() + self.writeRootFrame() + obj_list = self.analyzeScene() + space += 1 + ch_list = [] + for obj in obj_list: + self.writeObjFrames(obj) + ch_l = self.getChildren(obj) + for ch in ch_l: + + + if ch and ch.type == "Armature": + ch_list.append(ch) + self.writeObjFrames(ch) + else : + self.writeChildObj(ch_l) + if obj.type != "Armature": + self.file.write(" } // SI End of the Object %s \n" % (obj.name)) + + + + self.file.write("} // End of the Root Frame\n") + if anim : + self.file.write("AnimationSet AnimationSet0 {\n") + for obj in Blender.Scene.GetCurrent().objects: + if obj.type in ('Mesh', 'Empty'): + ip_list = obj.ipo + if ip_list != None : + self.writeAnimationObj(obj) + elif obj.type == 'Armature': + act_list = obj.getAction() + if act_list != None : + self.writeAnimation(obj) + #ip_list = obj.ipo + #if ip_list != None : + # self.writeAnimationObj(obj) + + self.file.write("} // End of Animation Set\n") + self.writeEnd() + ####################################################### + + + def writeAnimTicks(self): + global ticks + self.file.write("AnimTicksPerSecond {\n") + self.file.write("%d; \n" % (ticks)) + self.file.write("}\n") + + #*********************************************** + #Export Mesh without Armature + #*********************************************** + def exportMesh(self, obj): + tex = [] + mesh = obj.getData() + self.writeTextures(obj, tex) + self.writeMeshcoordArm(obj, arm_ob = None) + self.writeMeshMaterialList(obj, mesh, tex) + self.writeMeshNormals(obj, mesh) + self.writeMeshTextureCoords(obj, mesh) + self.file.write(" } // End of the Mesh %s \n" % (obj.name)) + + + #*********************************************** + #Export the Selected Mesh + #*********************************************** + def exportSelMesh(self): + print "exporting ..." + self.writeHeader() + self.writeRootFrame() + tex = [] + objs = Object.GetSelected() + for obj in objs: + if obj.type == 'Mesh': + mesh = obj.data + self.writeTextures(obj, tex) + self.writeMeshcoordArm(obj, arm_ob = None) + self.writeMeshMaterialList(obj, mesh, tex) + self.writeMeshNormals(obj, mesh) + self.writeMeshTextureCoords(obj, mesh) + self.file.write(" }\n") + self.file.write("}\n") + ind = objs.index(obj) + if ind == len(objs)-1: + self.file.write("}\n") + ip_list = obj.ipo + if ip_list != None : + self.file.write("AnimationSet AnimationSet0 {\n") + self.writeAnimationObj(obj) + self.file.write("}\n") + else : + print "The selected object is not a mesh" + print "...finished" + #*********************************************** + #Export Mesh with Armature + #*********************************************** + def exportMeshArm(self,arm,arm_ob,ch_obj): + tex = [] + mesh = ch_obj.getData() + self.writeTextures(ch_obj, tex) + self.writeMeshcoordArm(ch_obj ,arm_ob) + self.writeMeshMaterialList(ch_obj, mesh, tex) + self.writeMeshNormals(ch_obj, mesh) + self.writeMeshTextureCoords(ch_obj, mesh) + self.writeSkinWeights(arm,mesh) + #self.file.write(" } // End of the Frame %s \n" % (ch_obj.name)) + self.file.write(" } // End of the Object %s \n" % (ch_obj.name)) + + #*********************************************** + #Export Root Bone + #*********************************************** + def writeRootBone(self, chld_obj, child_obj): + global space,root_bon + arms = chld_obj.getData() + mat_arm = self.getLocMat(chld_obj) + for bon in arms.bones.values(): + if bon.hasParent(): + pass + else: + root_bon = bon + space += 1 + mat_r = self.writeAnimCombineMatrix(root_bon,1) + self.writeArmFrames(mat_r, make_legal_name(root_bon.name)) + + bon_c = root_bon.children + self.writeChildren(bon_c) + self.file.write(" } // End of the Bone %s \n" % (root_bon.name)) + self.exportMeshArm(arms, chld_obj ,child_obj) + + #*********************************************** + #Create Children structure + #*********************************************** + def writeBon(self,bon): + global space + mat_r = self.writeAnimCombineMatrix(bon,1) + self.writeArmFrames(mat_r, make_legal_name(bon.name)) + + + def writeChildren(self,bon_c): + global space,bone_list + space += 1 + if bon_c: + for bo in bon_c: + if bo.name not in bone_list: + self.writeBon(bo) + bone_list.append(bo.name) + bo_c = bo.children + self.writeChildren(bo_c) + self.closeBrackets() + + + + def closeBrackets(self): + global space + space = space-1 + tab = " " + self.file.write("%s" % (tab * space)) + self.file.write("}\n") + + + + #*********************************************** + #Offset Matrix + #*********************************************** + def writeMatrixOffset(self,bon): + global chld_obj + Blender.Set('curframe', 1) + pose = chld_obj.getPose() + pos_b = pose.bones[bon.name] + mat_b = pos_b.poseMatrix + mat_c = Matrix(mat_b) + mat_c.invert() + return mat_c + + + #*********************************************** + #Combine Matrix + #*********************************************** + def writeCombineMatrix(self,bon): + global chld_obj + + Blender.Set('curframe', 1) + pose = chld_obj.getPose() + pos_b = pose.bones[bon.name] + mat_b = pos_b.poseMatrix + if bon.hasParent(): + pare = bon.parent + pos_p = pose.bones[pare.name] + mat_p = pos_p.poseMatrix + + else: + mat_p = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) + mat_c = Matrix(mat_p) + mat_c.invert() + mat_f = mat_b * mat_c + + return mat_f + #*********************************************** + #Combine Matrix + #*********************************************** + def writeAnimCombineMatrix(self,bon,fre): + global chld_obj + Blender.Set('curframe', fre) + pose = chld_obj.getPose() + pos_b = pose.bones[bon.name] + mat_b = pos_b.poseMatrix + if bon.hasParent(): + pare = bon.parent + pos_p = pose.bones[pare.name] + mat_p = pos_p.poseMatrix + + else: + mat_p = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) + mat_c = Matrix(mat_p) + mat_c.invert() + mat_f = mat_b * mat_c + + return mat_f + + +#********************************************************************************************************************************************* + #*********************************************** + #Write SkinWeights + #*********************************************** + def writeSkinWeights(self, arm, mesh): + global index_list + v_dict = {} + Blender.Set('curframe',1) + self.file.write(" XSkinMeshHeader {\n") + max_infl = 0 + for bo in arm.bones.values() : + name = bo.name + try : + vertx_list = mesh.getVertsFromGroup(name,1) + for inde in vertx_list : + vert_infl = mesh.getVertexInfluences(inde[0]) + ln_infl = len(vert_infl) + if ln_infl > max_infl : + max_infl = ln_infl + + except: + pass + + self.file.write(" %d; \n" % (max_infl)) + self.file.write(" %d; \n" % (max_infl * 3)) + self.file.write(" %d; \n" % (len(arm.bones.values()))) + self.file.write(" }\n") + + for bo in arm.bones.values() : + bo_list = [] + weight_list = [] + name = bo.name + f_name = make_legal_name(name) + try : + vert_list = mesh.getVertsFromGroup(name,1) + le = 0 + for indx in vert_list: + ver_infl = mesh.getVertexInfluences(indx[0]) + infl = 0.0 + if len(ver_infl) != 0: + sum = 0.0 + for bone_n, weight in ver_infl: + if bone_n == name: + infl = weight + sum += weight + infl /= sum + + i = -1 + for el in index_list : + i += 1 + if el == indx[0] : + le +=1 + bo_list.append(i) + weight_list.append(infl) + + + self.file.write(" SkinWeights {\n") + self.file.write(' "%s"; \n' % (f_name)) + self.file.write(' %d; \n' % (le)) + count = 0 + for ind in bo_list : + count += 1 + if count == len(bo_list): + self.file.write(" %d; \n" % (ind)) + else : + self.file.write(" %d, \n" % (ind)) + cou = 0 + for wegh in weight_list : + cou += 1 + + if cou == len(weight_list): + self.file.write(" %f; \n" % (round(wegh,6))) + else : + self.file.write(" %f, \n" % (round(wegh,6))) + + + matx = self.writeMatrixOffset(bo) + self.writeOffsFrames(matx, name) + except : + pass + self.file.write(" } // End of XSkinMeshHeader\n") + + + #*********************************************** + # Write Matrices + #*********************************************** + def writeArmFrames(self, matx, name): + global space + tab = " " + self.file.write("%s" % (tab * space)) + self.file.write("Frame ") + self.file.write("%s {\n\n" % (name)) + self.file.write("%s" % (tab * space)) + self.file.write(" FrameTransformMatrix {\n") + self.writeFrame(matx) + + #*********************************************** + # Write Frames + #*********************************************** + def writeOffsFrames(self, matx, name): + space = 1 + self.writeFrame(matx) + + #*********************************************** + # Write Frames + #*********************************************** + def writeFrame(self, matx): + tab = " " + self.file.write("%s" % (tab * space)) + self.file.write(" %f,%f,%f,%f,\n" % + (round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4))) + self.file.write("%s" % (tab * space)) + self.file.write(" %f,%f,%f,%f,\n" % + (round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4))) + self.file.write("%s" % (tab * space)) + self.file.write(" %f,%f,%f,%f,\n" % + (round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4))) + self.file.write("%s" % (tab * space)) + self.file.write(" %f,%f,%f,%f;;\n" % + (round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],4))) + self.file.write("%s" % (tab * space)) + self.file.write(" }\n") +#********************************************************************************************************************************************* + + #*********************************************** + #HEADER + #*********************************************** + def writeHeader(self): + self.file.write("xof 0303txt 0032\n\n\n") + self.file.write("template VertexDuplicationIndices { \n\ + \n\ + DWORD nIndices;\n\ + DWORD nOriginalVertices;\n\ + array DWORD indices[nIndices];\n\ +}\n\ +template XSkinMeshHeader {\n\ + <3cf169ce-ff7c-44ab-93c0-f78f62d172e2>\n\ + WORD nMaxSkinWeightsPerVertex;\n\ + WORD nMaxSkinWeightsPerFace;\n\ + WORD nBones;\n\ +}\n\ +template SkinWeights {\n\ + <6f0d123b-bad2-4167-a0d0-80224f25fabb>\n\ + STRING transformNodeName;\n\ + DWORD nWeights;\n\ + array DWORD vertexIndices[nWeights];\n\ + array float weights[nWeights];\n\ + Matrix4x4 matrixOffset;\n\ +}\n\n") + + #*********************************************** + #CLOSE FILE + #*********************************************** + def writeEnd(self): + self.file.close() + print "... finished" + + + #*********************************************** + #EXPORT TEXTURES + #*********************************************** + def writeTextures(self,name, tex): + mesh = name.data + for face in mesh.faces: + if face.image and face.image.name not in tex: + tex.append(face.image.name) + + + + #*********************************************** + #EXPORT MESH DATA with Armature + #*********************************************** + def writeMeshcoordArm(self, obj ,arm_ob): + global index_list,flip_z + #TransformMatrix + mat = self.getLocMat(obj) + self.writeArmFrames(mat, make_legal_name(obj.name)) + mesh = NMesh.GetRawFromObject(obj.name) + self.file.write("Mesh {\n") + numface=len(mesh.faces) + #VERTICES NUMBER + numvert = 0 + for face in mesh.faces: + numvert = numvert + len(face.v) + self.file.write("%d;\n" % (numvert)) + if numvert == 0: + print "Mesh named",mesh.name,"has no vertices.Problems may occur using the .x file" + #VERTICES COORDINATES + counter = 0 + for face in mesh.faces: + counter += 1 + for n in range(len(face.v)): + index_list.append(face.v[n].index) + vec_vert = Vector([(face.v[n].co[0]), face.v[n].co[1], face.v[n].co[2], 1]) + if arm_ob : + f_vec_vert = vec_vert * mat + else : + f_vec_vert = vec_vert + self.file.write("%f; %f; %f;" % (round(f_vec_vert[0],4), round(f_vec_vert[1],4), round(f_vec_vert[2],4))) + if counter == numface : + if n == len(face.v)-1 : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + if flip_z: + a3 = 0;b3 = 2;c3 = 1 + a4 = 0;b4 = 3;c4 = 2;d4 = 1 + else: + a3 = 0;b3 = 1;c3 = 2 + a4 = 0;b4 = 1;c4 = 2;d4 = 3 + + #FACES NUMBER + self.file.write("%s;\n" % (numface)) + coun,counter = 0, 0 + for face in mesh.faces : + coun += 1 + separator = ',' + if coun == numface: + separator = ';' + if len(face.v) == 3: + self.file.write("3; %d, %d, %d;%c\n" % (counter + a3, counter + b3, counter + c3, separator)) + counter += 3 + elif len(face.v) == 4: + self.file.write("4; %d, %d, %d, %d;%c\n" % (counter + a4, counter + b4, counter + c4, counter + d4, separator)) + counter += 4 + elif len(face.v) < 3: + print "WARNING:the mesh has faces with less then 3 vertices" + print " It my be not exported correctly." + + + #*********************************************** + #MESH MATERIAL LIST + #*********************************************** + def writeMeshMaterialList(self, obj, mesh, tex): + self.file.write(" MeshMaterialList {\n") + #HOW MANY MATERIALS ARE USED + count = 0 + for mat in mesh.getMaterials(): + count+=1 + self.file.write(" %d;\n" % (len(tex) + count)) + #HOW MANY FACES IT HAS + numfaces=len(mesh.faces) + self.file.write(" %d;\n" % (numfaces)) + ##MATERIALS INDEX FOR EVERY FACE + counter = 0 + for face in mesh.faces : + counter += 1 + mater = face.materialIndex + if counter == numfaces: + if face.image and face.image.name in tex : + self.file.write(" %d;;\n" % (tex.index(face.image.name) + count)) + else : + self.file.write(" %d;;\n" % (mater)) + else : + if face.image and face.image.name in tex : + self.file.write(" %d,\n" % (tex.index(face.image.name) + count)) + else : + self.file.write(" %d,\n" % (mater)) + + ##MATERIAL NAME + for mat in mesh.getMaterials(): + self.file.write(" Material") + self.file.write(" %s "% (make_legal_name(mat.name))) + self.file.write("{\n") + self.file.write(" %f; %f; %f;" % (mat.R, mat.G, mat.B)) + self.file.write("%s;;\n" % (mat.alpha)) + self.file.write(" %f;\n" % (mat.spec)) + self.file.write(" %f; %f; %f;;\n" % (mat.specR, mat.specG, mat.specB)) + self.file.write(" 0.0; 0.0; 0.0;;\n") + self.file.write(" } //End of Material\n") + + for mat in tex: + self.file.write(" Material Mat") + self.file.write("%s "% (len(tex))) + self.file.write("{\n") + self.file.write(" 1.0; 1.0; 1.0; 1.0;;\n") + self.file.write(" 1.0;\n") + self.file.write(" 1.0; 1.0; 1.0;;\n") + self.file.write(" 0.0; 0.0; 0.0;;\n") + self.file.write(" TextureFilename {") + self.file.write(' "%s";'% (mat)) + self.file.write(" }\n") + self.file.write(" } // End of Material\n") + self.file.write(" } //End of MeshMaterialList\n") + + #*********************************************** + #MESH NORMALS + #*********************************************** + def writeMeshNormals(self,name,mesh): + global flip_norm,flip_z,no_light,recalc_norm,Bl_norm + + self.file.write(" MeshNormals {\n") + #VERTICES NUMBER + numvert = 0 + for face in mesh.faces: + numvert = numvert + len(face.v) + self.file.write("%d;\n" % (numvert)) + numfaces=len(mesh.faces) + if flip_norm : + fl = -1 + else : + fl = 1 + #VERTICES NORMAL + if Bl_norm: + self.writeBlenderNormals(mesh,fl) + if recalc_norm: + self.writeRecalcNormals(mesh,fl) + if no_light: + self.writeNoSmothing(mesh,fl) + + + + if flip_z: + a3 = 0;b3 = 2;c3 = 1 + a4 = 0;b4 = 3;c4 = 2;d4 = 1 + else: + a3 = 0;b3 = 1;c3 = 2 + a4 = 0;b4 = 1;c4 = 2;d4 = 3 + + #FACES NUMBER + self.file.write("%s;\n" % (numfaces)) + coun,counter = 0, 0 + for face in mesh.faces : + coun += 1 + if coun == numfaces: + if len(face.v) == 3: + self.file.write("3; %d, %d, %d;;\n" % (counter + a3, counter + b3, counter + c3)) + counter += 3 + else : + self.file.write("4; %d, %d, %d, %d;;\n" % (counter + a4, counter + b4, counter + c4, counter + d4)) + counter += 4 + else: + + if len(face.v) == 3: + self.file.write("3; %d, %d, %d;,\n" % (counter + a3, counter + b3, counter + c3)) + counter += 3 + else : + self.file.write("4; %d, %d, %d, %d;,\n" % (counter + a4, counter + b4, counter + c4, counter + d4)) + counter += 4 + self.file.write("} //End of MeshNormals\n") + + def writeBlenderNormals(self,mesh,fl): + numfaces=len(mesh.faces) + #VERTICES NORMAL + counter = 0 + for face in mesh.faces: + counter += 1 + for n in range(len(face.v)): + self.file.write(" %f; %f; %f;" % ( + (round(face.v[n].no[0],6)*fl),(round(face.v[n].no[1],6)*fl),(round(face.v[n].no[2],6)*fl))) + if counter == numfaces : + if n == len(face.v)-1 : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + + def writeRecalcNormals(self,mesh,fl): + numfaces=len(mesh.faces) + normal_list = {} + idx = 0 + for vertex in mesh.verts: + v_norm = Vector([0, 0, 0]) + normal_list[idx] = v_norm + idx += 1 + for face in mesh.faces: + for verts in face.v: + if verts.index == vertex.index : + v_norm[0] += face.no[0] + v_norm[1] += face.no[1] + v_norm[2] += face.no[2] + + v_norm.normalize() + + counter = 0 + for face in mesh.faces: + counter += 1 + n = 0 + for vert in face.v: + n += 1 + norm = normal_list[vert.index] + + self.file.write(" %f; %f; %f;" % ( + (round(norm[0],6)*fl),(round(norm[1],6)*fl),(round(norm[2],6)*fl))) + if counter == numfaces : + if n == len(face.v) : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + + def writeNoSmothing(self,mesh,fl): + numfaces=len(mesh.faces) + counter = 0 + for face in mesh.faces: + counter += 1 + n = 0 + for n in range(len(face.v)): + n += 1 + self.file.write(" %f; %f; %f;" % ( + (round(face.no[0],6)*fl),(round(face.no[1],6)*fl),(round(face.no[2],6)*fl))) + + + if counter == numfaces : + if n == len(face.v) : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + #*********************************************** + #MESH TEXTURE COORDS + #*********************************************** + def writeMeshTextureCoords(self, name, mesh): + if mesh.hasFaceUV(): + self.file.write("MeshTextureCoords {\n") + #VERTICES NUMBER + numvert = 0 + for face in mesh.faces: + numvert += len(face.v) + self.file.write("%d;\n" % (numvert)) + #UV COORDS + numfaces = len(mesh.faces) + counter = -1 + co = 0 + for face in mesh.faces: + counter += 1 + co += 1 + for n in range(len(face.v)): + self.file.write("%f;%f;" % (mesh.faces[counter].uv[n][0], -mesh.faces[counter].uv[n][1])) + if co == numfaces : + if n == len(face.v) - 1 : + self.file.write(";\n") + else : + self.file.write(",\n") + else : + self.file.write(",\n") + + self.file.write("} //End of MeshTextureCoords\n") +#***********************************************#***********************************************#*********************************************** + #*********************************************** + #FRAMES + #*********************************************** + def writeFrames(self, matx): + + self.file.write("%f,%f,%f,%f," % + (round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4))) + self.file.write("%f,%f,%f,%f," % + (round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4))) + self.file.write("%f,%f,%f,%f," % + (round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4))) + self.file.write("%f,%f,%f,%f;;" % + (round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],4))) + + + + + + #*********************************************** + #WRITE ANIMATION KEYS + #*********************************************** + def writeAnimation(self,arm_ob): + global mat_dict, root_bon + arm = arm_ob.getData() + act_list = arm_ob.getAction() + ip = act_list.getAllChannelIpos() + for bon in arm.bones.values() : + point_list = [] + name = bon.name + name_f = make_legal_name(name) + try : + ip_bon_channel = ip[bon.name] + ip_bon_name = ip_bon_channel.getName() + + ip_bon = Blender.Ipo.Get(ip_bon_name) + poi = ip_bon.getCurves() + + for po in poi[3].getPoints(): + a = po.getPoints() + point_list.append(int(a[0])) + #point_list.pop(0) + + self.file.write(" Animation { \n") + self.file.write(" { %s }\n" %(name_f)) + self.file.write(" AnimationKey { \n") + self.file.write(" 4;\n") + self.file.write(" %d; \n" % (len(point_list))) + + for fr in point_list: + + if name == root_bon.name : + + + mat_b = self.writeAnimCombineMatrix(bon,fr) + mat_arm = self.getLocMat(arm_ob) + mat = mat_b * mat_arm + else: + mat = self.writeAnimCombineMatrix(bon,fr) + + self.file.write(" %d;" % (fr)) + self.file.write("16;") + + self.writeFrames(mat) + + if fr == point_list[len(point_list)-1]: + self.file.write(";\n") + else: + self.file.write(",\n") + self.file.write(" }\n") + self.file.write(" }\n") + self.file.write("\n") + except: + pass + + + + #*********************************************** + #WRITE ANIMATION KEYS + #*********************************************** + def writeAnimationObj(self, obj): + point_list = [] + ip = obj.ipo + poi = ip.getCurves() + for po in poi[0].getPoints(): + a = po.getPoints() + point_list.append(int(a[0])) + + self.file.write(" Animation {\n") + self.file.write(" { ") + self.file.write("%s }\n" % (make_legal_name(obj.name))) + self.file.write(" AnimationKey { \n") + self.file.write(" 4;\n") + self.file.write(" %d; \n" % (len(point_list))) + for fr in point_list: + self.file.write(" %d;" % (fr)) + self.file.write("16;") + Blender.Set('curframe',fr) + + #mat_new = self.getLocMat(obj) + mat_new = obj.matrixLocal + self.writeFrames(mat_new) + + if fr == point_list[len(point_list)-1]: + self.file.write(";\n") + else: + self.file.write(",\n") + self.file.write(" }\n") + self.file.write(" }\n") + + + +#***********************************************#***********************************************#*********************************************** + + + + + diff --git a/release/scripts/DirectX8Importer.py b/release/scripts/DirectX8Importer.py new file mode 100644 index 00000000000..0dda654944d --- /dev/null +++ b/release/scripts/DirectX8Importer.py @@ -0,0 +1,238 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'DirectX(.x)...' +Blender: 244 +Group: 'Import' + +Tip: 'Import from DirectX text file format format.' +""" +# DirectXImporter.py version 1.2 +# Copyright (C) 2005 Arben OMARI -- omariarben@everyday.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# This script import meshes from DirectX text file format + +# Grab the latest version here :www.omariben.too.it +import bpy +import Blender +from Blender import Mesh,Object,Material,Texture,Image,Draw + + +class xImport: + def __init__(self, filename): + global my_path + self.file = open(filename, "r") + my_path = Blender.sys.dirname(filename) + + # + self.lines = [l_split for l in self.file.readlines() for l_split in (' '.join(l.split()),) if l_split] + + def Import(self): + lines = self.lines + print "importing into Blender ..." + scene = bpy.data.scenes.active + + mesh_indicies = {} # the index of each 'Mesh' is used as the key for those meshes indicies + context_indicies = None # will raise an error if used! + + + #Get the line of Texture Coords + nr_uv_ind = 0 + + #Get Materials + nr_fac_mat = 0 + i = -1 + mat_list = [] + tex_list = [] + mesh_line_indicies = [] + for j, line in enumerate(lines): + l = line.strip() + words = line.split() + if words[0] == "Material" : + #context_indicies["Material"] = j + self.loadMaterials(j, mat_list, tex_list) + elif words[0] == "MeshTextureCoords" : + context_indicies["MeshTextureCoords"] = j + #nr_uv_ind = j + elif words[0] == "MeshMaterialList" : + context_indicies["MeshMaterialList"] = j+2 + #nr_fac_mat = j + 2 + elif words[0] == "Mesh": # Avoid a second loop + context_indicies = mesh_indicies[j] = {'MeshTextureCoords':0, 'MeshMaterialList':0} + + for mesh_index, value in mesh_indicies.iteritems(): + mesh = Mesh.New() + self.loadVertices(mesh_index, mesh, value['MeshTextureCoords'], value['MeshMaterialList'], tex_list) + + mesh.materials = mat_list[:16] + if value['MeshMaterialList']: + self.loadMeshMaterials(value['MeshMaterialList'], mesh) + scene.objects.new(mesh) + + self.file.close() + print "... finished" + + #------------------------------------------------------------------------------ + # CREATE THE MESH + #------------------------------------------------------------------------------ + def loadVertices(self, nr_vr_ind, mesh, nr_uv, nr_fac_mat, tex_list): + v_ind = nr_vr_ind + 1 + lin = self.lines[v_ind] + if lin : + lin_c = self.CleanLine(lin) + nr_vert = int((lin_c.split()[0])) + else : + v_ind = nr_vr_ind + 2 + lin = self.lines[v_ind] + lin_c = self.CleanLine(lin) + nr_vert = int((lin_c.split()[0])) + + #-------------------------------------------------- + nr_fac_li = v_ind + nr_vert +1 + lin_f = self.lines[nr_fac_li] + if lin_f : + lin_fc = self.CleanLine(lin_f) + nr_face = int((lin_fc.split()[0])) + else : + nr_fac_li = v_ind + nr_vert +1 + lin_f = self.lines[nr_fac_li] + lin_fc = self.CleanLine(lin_f) + nr_face = int((lin_fc.split()[0])) + + #Get Coordinates + verts_list = [(0,0,0)] # WARNING - DUMMY VERT - solves EEKADOODLE ERROR + for l in xrange(v_ind + 1, (v_ind + nr_vert +1)): + line_v = self.lines[l] + lin_v = self.CleanLine(line_v) + words = lin_v.split() + if len(words)==3: + verts_list.append((float(words[0]),float(words[1]),float(words[2]))) + + mesh.verts.extend(verts_list) + del verts_list + + face_list = [] + #Make Faces + i = 0 + mesh_verts = mesh.verts + for f in xrange(nr_fac_li + 1, (nr_fac_li + nr_face + 1)): + i += 1 + line_f = self.lines[f] + lin_f = self.CleanLine(line_f) + + # +1 for dummy vert only! + words = lin_f.split() + if len(words) == 5: + face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]), 1+int(words[4]))) + elif len(words) == 4: + face_list.append((1+int(words[1]), 1+int(words[2]), 1+int(words[3]))) + + mesh.faces.extend(face_list) + del face_list + + if nr_uv : + mesh.faceUV = True + for f in mesh.faces: + fuv = f.uv + for ii, v in enumerate(f): + # _u, _v = self.CleanLine(self.lines[nr_uv + 2 + v.index]).split() + + # Use a dummy vert + _u, _v = self.CleanLine(self.lines[nr_uv + 1 + v.index]).split() + + fuv[ii].x = float(_u) + fuv[ii].y = float(_v) + + if nr_fac_mat : + fac_line = self.lines[nr_fac_mat + i] + fixed_fac = self.CleanLine(fac_line) + w_tex = int(fixed_fac.split()[0]) + f.image = tex_list[w_tex] + + # remove dummy vert + mesh.verts.delete([0,]) + + def CleanLine(self,line): + return line.replace(\ + ";", " ").replace(\ + '"', ' ').replace(\ + "{", " ").replace(\ + "}", " ").replace(\ + ",", " ").replace(\ + "'", " ") + + #------------------------------------------------------------------ + # CREATE MATERIALS + #------------------------------------------------------------------ + def loadMaterials(self, nr_mat, mat_list, tex_list): + + def load_image(name): + try: + return Image.Load(Blender.sys.join(my_path,name)) + except: + return None + + mat = bpy.data.materials.new() + line = self.lines[nr_mat + 1] + fixed_line = self.CleanLine(line) + words = fixed_line.split() + mat.rgbCol = [float(words[0]),float(words[1]),float(words[2])] + mat.setAlpha(float(words[3])) + mat_list.append(mat) + l = self.lines[nr_mat + 5] + fix_3_line = self.CleanLine(l) + tex_n = fix_3_line.split() + + if tex_n and tex_n[0] == "TextureFilename" : + + if len(tex_n) > 1: + tex_list.append(load_image(tex_n[1])) + + if len(tex_n) <= 1 : + + l_succ = self.lines[nr_mat + 6] + fix_3_succ = self.CleanLine(l_succ) + tex_n_succ = fix_3_succ.split() + tex_list.append(load_image(tex_n_succ[0])) + else : + tex_list.append(None) # no texture for this index + + return mat_list, tex_list + #------------------------------------------------------------------ + # SET MATERIALS + #------------------------------------------------------------------ + def loadMeshMaterials(self, nr_fc_mat, mesh): + for face in mesh.faces: + nr_fc_mat += 1 + line = self.lines[nr_fc_mat] + fixed_line = self.CleanLine(line) + wrd = fixed_line.split() + mat_idx = int(wrd[0]) + face.mat = mat_idx + +#------------------------------------------------------------------ +# MAIN +#------------------------------------------------------------------ +def my_callback(filename): + if not filename.lower().endswith('.x'): print "Not an .x file" + ximport = xImport(filename) + ximport.Import() + +arg = __script__['arg'] + +if __name__ == '__main__': + Blender.Window.FileSelector(my_callback, "Import DirectX", "*.x") + +#my_callback('/fe/x/directxterrain.x') +#my_callback('/fe/x/Male_Normal_MAX.X') +#my_callback('/fe/x/male_ms3d.x') diff --git a/release/scripts/IDPropBrowser.py b/release/scripts/IDPropBrowser.py new file mode 100644 index 00000000000..2a14760270a --- /dev/null +++ b/release/scripts/IDPropBrowser.py @@ -0,0 +1,523 @@ +#!BPY + +""" +Name: 'ID Property Browser' +Blender: 242 +Group: 'Help' +Tooltip: 'Browse ID properties' +""" + +__author__ = "Joe Eagar" +__version__ = "0.3.108" +__email__ = "joeedh@gmail.com" +__bpydoc__ = """\ + +Allows browsing, creating and editing of ID Properties +for various ID block types such as mesh, scene, object, +etc. +""" + +# -------------------------------------------------------------------------- +# ID Property Browser. +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +from Blender import * +from Blender.BGL import * +from Blender.Types import IDGroupType, IDArrayType +import Blender + +def IsInRectWH(mx, my, x, y, wid, hgt): + if mx >= x and mx <= x + wid: + if my >= y and my <= y + hgt: + return 1 + return 0 + +Button_Back = 1 +Button_New = 2 +Button_MatMenu = 3 +Button_TypeMenu = 4 + +ButStart = 55 + +IDP_String = 0 +IDP_Int = 1 +IDP_Float = 2 +IDP_Array = 5 +IDP_Group = 6 + +ButDelStart = 255 +#max limit for string input button +strmax = 100 + +State_Normal = 0 +State_InArray = 1 + +#IDTypeModules entries are of form [module, active_object_index, module_name] +IDTypeModules = [[Scene, 0, "Scenes"], [Object, 0, "Objects"], [Mesh, 0, "Meshes"]] +IDTypeModules += [[Material, 0, "Materials"], [Texture, 0, "Textures"]] +IDTypeModules += [[Image, 0, "Images"]] + +class IDArrayBrowser: + array = 0 + parentbrowser = 0 + buts = 0 + + def __init__(self): + self.buts = [] + + def Draw(self): + pb = self.parentbrowser + x = pb.x + y = pb.y + width = pb.width + height = pb.height + pad = pb.pad + itemhgt = pb.itemhgt + cellwid = 65 + y = y + height - itemhgt - pad + + Draw.PushButton("Back", Button_Back, x, y, 40, 20) + y -= itemhgt + pad + + self.buts = [] + Draw.BeginAlign() + for i in xrange(len(self.array)): + st = "" + if type(self.array[0]) == float: + st = "%.5f" % self.array[i] + else: st = str(self.array[i]) + + b = Draw.String("", ButStart+i, x, y, cellwid, itemhgt, st, 30) + self.buts.append(b) + x += cellwid + pad + if x + cellwid + pad > width: + x = 0 + y -= itemhgt + pad + Draw.EndAlign() + def Button(self, bval): + if bval == Button_Back: + self.parentbrowser.state = State_Normal + self.parentbrowser.array = 0 + self.buts = [] + Draw.Draw() + self.array = 0 + elif bval >= ButStart: + i = bval - ButStart + st = self.buts[i].val + n = 0 + if type(self.array[0]) == float: + try: + n = int(st) + except: + return + elif type(self.array[0]) == int: + try: + n = float(st) + except: + return + + self.array[i] = n + Draw.Draw() + + def Evt(self, evt, val): + if evt == Draw.ESCKEY: + Draw.Exit() + +class IDPropertyBrowser: + width = 0 + height = 0 + x = 0 + y = 0 + scrollx = 0 + scrolly = 0 + itemhgt = 22 + pad = 2 + + group = 0 + parents = 0 #list stack of parent groups + active_item = -1 + mousecursor = 0 + _i = 0 + buts = [] + + state = 0 + array = 0 + prop = 0 + + IDList = 0 + idindex = 0 + idblock = 0 + + type = 0 # attach buildin type() method to class + # since oddly it's not available to button + # callbacks! EEK! :( + + def __init__(self, idgroup, mat, x, y, wid, hgt): + self.group = idgroup + self.prop = idgroup + self.x = x + self.y = y + self.width = wid + self.height = hgt + self.mousecursor = [0, 0] + self.parents = [] + self.idblock = mat + self.type = type + + def DrawBox(self, glmode, x, y, width, height): + glBegin(glmode) + glVertex2f(x, y) + glVertex2f(x+width, y) + glVertex2f(x+width, y+height) + glVertex2f(x, y+height) + glEnd() + + def Draw(self): + global IDTypeModules + + #first draw outlining box :) + glColor3f(0, 0, 0) + self.DrawBox(GL_LINE_LOOP, self.x, self.y, self.width, self.height) + + itemhgt = self.itemhgt + pad = self.pad + x = self.x + y = self.y + self.height - itemhgt - pad + + if self.state == State_InArray: + self.array.Draw() + return + + plist = [] + self.buts = [] + for p in self.group.iteritems(): + plist.append(p) + + #-------do top buttons----------# + Draw.BeginAlign() + Draw.PushButton("New", Button_New, x, y, 40, 20) + x += 40 + pad + #do the menu button for all materials + st = "" + + blocks = IDTypeModules[self.IDList][0].Get() + i = 1 + mi = 0 + for m in blocks: + if m.name == self.idblock.name: + mi = i + st += m.name + " %x" + str(i) + "|" + i += 1 + + self.menubut = Draw.Menu(st, Button_MatMenu, x, y, 100, 20, mi) + + x += 100 + pad + + st = "" + i = 0 + for e in IDTypeModules: + st += e[2] + " %x" + str(i+1) + "|" + i += 1 + + cur = self.IDList + 1 + self.idmenu = Draw.Menu(st, Button_TypeMenu, x, y, 100, 20, cur) + x = self.x + y -= self.itemhgt + self.pad + Draw.EndAlign() + + + #-----------do property items---------# + i = 0 + while y > self.y - 20 - pad and i < len(plist): + k = plist[i][0] + p = plist[i][1] + if i == self.active_item: + glColor3f(0.5, 0.4, 0.3) + self.DrawBox(GL_POLYGON, x+pad, y, self.width-pad*2, itemhgt) + + glColor3f(0, 0, 0) + self.DrawBox(GL_LINE_LOOP, x+pad, y, self.width-pad*2, itemhgt) + + glRasterPos2f(x+pad*2, y+5) + Draw.Text(str(k)) #str(self.mousecursor) + " " + str(self.active_item)) #p.name) + tlen = Draw.GetStringWidth(str(k)) + + type_p = type(p) + if type_p == str: + b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 200, itemhgt, p, strmax) + self.buts.append(b) + elif type_p in [int, float]: + #only do precision to 5 points on floats + st = "" + if type_p == float: + st = "%.5f" % p + else: st = str(p) + b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 75, itemhgt, st, strmax) + self.buts.append(b) + else: + glRasterPos2f(x+pad*2 +tlen+10, y+5) + if type_p == Types.IDArrayType: + Draw.Text('(array, click to edit)') + elif type_p == Types.IDGroupType: + Draw.Text('(group, click to edit)') + + + self.buts.append(None) + + Draw.PushButton("Del", ButDelStart+i, x+self.width-35, y, 30, 20) + + i += 1 + y -= self.itemhgt + self.pad + + if len(self.parents) != 0: + Draw.PushButton("Back", Button_Back, x, y, 40, 20) + x = x + 40 + pad + + def SetActive(self): + m = self.mousecursor + itemhgt = self.itemhgt + pad = self.pad + + x = self.x + pad + y = self.y + self.height - itemhgt - pad - itemhgt + + plist = [] + for p in self.group.iteritems(): + plist.append(p) + + self.active_item = -1 + i = 0 + while y > self.y and i < len(plist): + p = plist[i] + if IsInRectWH(m[0], m[1], x, y, self.width-pad, itemhgt): + self.active_item = i + + i += 1 + y -= self.itemhgt + self.pad + + def EventIn(self, evt, val): + if self.state == State_InArray: + self.array.Evt(evt, val) + + if evt == Draw.ESCKEY: + Draw.Exit() + if evt == Draw.MOUSEX or evt == Draw.MOUSEY: + size = Buffer(GL_FLOAT, 4) + glGetFloatv(GL_SCISSOR_BOX, size) + if evt == Draw.MOUSEX: + self.mousecursor[0] = val - size[0] + else: + self.mousecursor[1] = val - size[1] + del size + + self.SetActive() + self._i += 1 + if self._i == 5: + Draw.Draw() + self._i = 0 + + + if evt == Draw.LEFTMOUSE and val == 1: + plist = list(self.group.iteritems()) + a = self.active_item + if a >= 0 and a < len(plist): + p = plist[a] + + basictypes = [IDGroupType, float, str, int] + if type(p[1]) == IDGroupType: + self.parents.append(self.group) + self.group = p[1] + self.active_item = -1 + Draw.Draw() + elif type(p[1]) == IDArrayType: + self.array = IDArrayBrowser() + self.array.array = p[1] + self.array.parentbrowser = self + self.state = State_InArray + Draw.Draw() + + if evt == Draw.TKEY and val == 1: + try: + self.prop['float'] = 0.0 + self.prop['int'] = 1 + self.prop['string'] = "hi!" + self.prop['float array'] = [0, 0, 1.0, 0] + self.prop['int array'] = [0, 0, 0, 0] + self.prop.data['a subgroup'] = {"int": 0, "float": 0.0, "anothergroup": {"a": 0.0, "intarr": [0, 0, 0, 0]}} + Draw.Draw() + except: + Draw.PupMenu("Can only do T once per block, the test names are already taken!") + + + def Button(self, bval): + global IDTypeModules + if self.state == State_InArray: + self.array.Button(bval) + return + + if bval == Button_MatMenu: + global IDTypeModules + + val = self.idindex = self.menubut.val - 1 + i = self.IDList + block = IDTypeModules[i][0].Get()[val] + self.idblock = block + self.prop = block.properties + self.group = self.prop + self.active_item = -1 + self.parents = [] + Draw.Draw() + + if bval == Button_TypeMenu: + i = IDTypeModules[self.idmenu.val-1] + if len(i[0].Get()) == 0: + Draw.PupMenu("Error%t|There are no " + i[2] + "!") + return + + IDTypeModules[self.IDList][1] = self.idindex + self.IDList = self.idmenu.val-1 + val = self.idindex = IDTypeModules[self.IDList][1] + i = self.IDList + block = IDTypeModules[i][0].Get()[val] + self.idblock = block + self.prop = block.properties + self.group = self.prop + self.active_item = -1 + self.parents = [] + Draw.Draw() + + if bval >= ButDelStart: + plist = [p for p in self.group] + prop = plist[bval - ButDelStart] + del self.group[prop] + Draw.Draw() + + elif bval >= ButStart: + plist = list(self.group.iteritems()) + + prop = plist[bval - ButStart] + print prop + + if self.type(prop[1]) == str: + self.group[prop[0]] = self.buts[bval - ButStart].val + elif self.type(prop[1]) == int: + i = self.buts[bval - ButStart].val + try: + i = int(i) + self.group[prop[0]] = i + except: + Draw.Draw() + return + Draw.Draw() + elif self.type(prop[1]) == float: + f = self.buts[bval - ButStart].val + try: + f = float(f) + self.group[prop[0]] = f + except: + Draw.Draw() + return + Draw.Draw() + + elif bval == Button_Back: + self.group = self.parents[len(self.parents)-1] + self.parents.pop(len(self.parents)-1) + Draw.Draw() + + elif bval == Button_New: + name = Draw.Create("untitled") + stype = Draw.Create(0) + gtype = Draw.Create(0) + ftype = Draw.Create(0) + itype = Draw.Create(0) + atype = Draw.Create(0) + + block = [] + block.append(("Name: ", name, 0, 30, "Click to type in the name of the new ID property")) + block.append("Type") + block.append(("String", stype)) + block.append(("Subgroup", gtype)) + block.append(("Float", ftype)) + block.append(("Int", itype)) + block.append(("Array", atype)) + + retval = Blender.Draw.PupBlock("New IDProperty", block) + if retval == 0: return + + name = name.val + i = 1 + stop = 0 + while stop == 0: + stop = 1 + for p in self.group: + if p == name: + d = name.rfind(".") + if d != -1: + name = name[:d] + name = name + "." + str(i).zfill(3) + i += 1 + stop = 0 + + type = "String" + if stype.val: + self.group[name] = "" + elif gtype.val: + self.group[name] = {} + elif ftype.val: + self.group[name] = 0.0 + elif itype.val: + self.group[name] = 0 #newProperty("Int", name, 0) + elif atype.val: + arrfloat = Draw.Create(1) + arrint = Draw.Create(0) + arrlen = Draw.Create(3) + block = [] + block.append("Type") + block.append(("Float", arrfloat, "Make a float array")) + block.append(("Int", arrint, "Make an integer array")) + block.append(("Len", arrlen, 2, 200)) + + if Blender.Draw.PupBlock("Array Properties", block): + if arrfloat.val: + tmpl = 0.0 + elif arrint.val: + tmpl = 0 + else: + return + + self.group[name] = [tmpl] * arrlen.val + + + def Go(self): + Draw.Register(self.Draw, self.EventIn, self.Button) + +scenes = Scene.Get() + +size = Window.GetAreaSize() +browser = IDPropertyBrowser(scenes[0].properties, scenes[0], 2, 2, size[0], size[1]) +browser.Go() + +#a = prop.newProperty("String", "hwello!", "bleh") +#b = prop.newProperty("Group", "subgroup") + +#for p in prop: + #print p.name diff --git a/release/scripts/ac3d_export.py b/release/scripts/ac3d_export.py new file mode 100644 index 00000000000..bccb7978f5f --- /dev/null +++ b/release/scripts/ac3d_export.py @@ -0,0 +1,828 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'AC3D (.ac)...' +Blender: 243 +Group: 'Export' +Tip: 'Export selected meshes to AC3D (.ac) format' +""" + +__author__ = "Willian P. Germano" +__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", + "PLib 3d gaming lib, http://plib.sf.net") +__version__ = "2.44 2007-05-05" + +__bpydoc__ = """\ +This script exports selected Blender meshes to AC3D's .ac file format. + +AC3D is a simple commercial 3d modeller also built with OpenGL. +The .ac file format is an easy to parse text format well supported, +for example, by the PLib 3d gaming library (AC3D 3.x). + +Supported:
+ UV-textured meshes with hierarchy (grouping) information. + +Missing:
+ The 'url' tag, specific to AC3D. It is easy to add by hand to the exported +file, if needed. + +Known issues:
+ The ambient and emit data we can retrieve from Blender are single values, +that this script copies to R, G, B, giving shades of gray.
+ Loose edges (lines) receive the first material found in the mesh, if any, or a default white material.
+ In AC3D 4 "compatibility mode":
+ - shininess of materials is taken from the shader specularity value in Blender, mapped from [0.0, 2.0] to [0, 128];
+ - crease angle is exported, but in Blender it is limited to [1, 80], since there are other more powerful ways to control surface smoothing. In AC3D 4.0 crease's range is [0.0, 180.0]; + +Config Options:
+ toggle:
+ - AC3D 4 mode: unset it to export without the 'crease' tag that was +introduced with AC3D 4.0 and with the old material handling;
+ - global coords: transform all vertices of all meshes to global coordinates;
+ - skip data: set it if you don't want mesh names (ME:, not OB: field) +to be exported as strings for AC's "data" tags (19 chars max);
+ - rgb mirror color can be exported as ambient and/or emissive if needed, +since Blender handles these differently;
+ - default mat: a default (white) material is added if some mesh was +left without mats -- it's better to always add your own materials;
+ - no split: don't split meshes (see above);
+ - set texture dir: override the actual textures path with a given default +path (or simply export the texture names, without dir info, if the path is +empty);
+ - per face 1 or 2 sided: override the "Double Sided" button that defines this behavior per whole mesh in favor of the UV Face Select mode "twosided" per face atribute;
+ - only selected: only consider selected objects when looking for meshes +to export (read notes below about tokens, too);
+ strings:
+ - export dir: default dir to export to;
+ - texture dir: override textures path with this path if 'set texture dir' +toggle is "on". + +Notes:
+ This version updates:
+ - modified meshes are correctly exported, no need to apply the modifiers in Blender;
+ - correctly export each used material, be it assigned to the object or to its mesh data;
+ - exporting lines (edges) is again supported; color comes from first material found in the mesh, if any, or a default white one.
+ - there's a new option to choose between exporting meshes with transformed (global) coordinates or local ones;
+ Multiple textures per mesh are supported (mesh gets split);
+ Parents are exported as a group containing both the parent and its children;
+ Start mesh object names (OB: field) with "!" or "#" if you don't want them to be exported;
+ Start mesh object names (OB: field) with "=" or "$" to prevent them from being split (meshes with multiple textures or both textured and non textured faces are split unless this trick is used or the "no split" option is set. +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# AC3DExport version 2.44 +# Program versions: Blender 2.42+ and AC3Db files (means version 0xb) +# new: updated for new Blender version and Mesh module; supports lines (edges) again; +# option to export vertices transformed to global coordinates or not; now the modified +# (by existing mesh modifiers) mesh is exported; materials are properly exported, no +# matter if each of them is linked to the mesh or to the object. New (2.43.1): loose +# edges use color of first material found in the mesh, if any. +# -------------------------------------------------------------------------- +# Thanks: Steve Baker for discussions and inspiration; for testing, bug +# reports, suggestions, patches: David Megginson, Filippo di Natale, +# Franz Melchior, Campbell Barton, Josh Babcock, Ralf Gerlich, Stewart Andreason. +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# -------------------------------------------------------------------------- + +import Blender +from Blender import Object, Mesh, Material, Image, Mathutils, Registry +from Blender import sys as bsys + +# Globals +REPORT_DATA = { + 'main': [], + 'errors': [], + 'warns': [], + 'nosplit': [], + 'noexport': [] +} +TOKENS_DONT_EXPORT = ['!', '#'] +TOKENS_DONT_SPLIT = ['=', '$'] + +MATIDX_ERROR = 0 + +# flags: +LOOSE = Mesh.EdgeFlags['LOOSE'] +FACE_TWOSIDED = Mesh.FaceModes['TWOSIDE'] +MESH_TWOSIDED = Mesh.Modes['TWOSIDED'] + +REG_KEY = 'ac3d_export' + +# config options: +GLOBAL_COORDS = True +SKIP_DATA = False +MIRCOL_AS_AMB = False +MIRCOL_AS_EMIS = False +ADD_DEFAULT_MAT = True +SET_TEX_DIR = True +TEX_DIR = '' +AC3D_4 = True # export crease value, compatible with AC3D 4 loaders +NO_SPLIT = False +ONLY_SELECTED = True +EXPORT_DIR = '' +PER_FACE_1_OR_2_SIDED = True + +tooltips = { + 'GLOBAL_COORDS': "transform all vertices of all meshes to global coordinates", + 'SKIP_DATA': "don't export mesh names as data fields", + 'MIRCOL_AS_AMB': "export mirror color as ambient color", + 'MIRCOL_AS_EMIS': "export mirror color as emissive color", + 'ADD_DEFAULT_MAT': "always add a default white material", + 'SET_TEX_DIR': "don't export default texture paths (edit also \"tex dir\")", + 'EXPORT_DIR': "default / last folder used to export .ac files to", + 'TEX_DIR': "(see \"set tex dir\") dir to prepend to all exported texture names (leave empty for no dir)", + 'AC3D_4': "compatibility mode, adds 'crease' tag and slightly better material support", + 'NO_SPLIT': "don't split meshes with multiple textures (or both textured and non textured polygons)", + 'ONLY_SELECTED': "export only selected objects", + 'PER_FACE_1_OR_2_SIDED': "override \"Double Sided\" button in favor of per face \"twosided\" attribute (UV Face Select mode)" +} + +def update_RegistryInfo(): + d = {} + d['SKIP_DATA'] = SKIP_DATA + d['MIRCOL_AS_AMB'] = MIRCOL_AS_AMB + d['MIRCOL_AS_EMIS'] = MIRCOL_AS_EMIS + d['ADD_DEFAULT_MAT'] = ADD_DEFAULT_MAT + d['SET_TEX_DIR'] = SET_TEX_DIR + d['TEX_DIR'] = TEX_DIR + d['AC3D_4'] = AC3D_4 + d['NO_SPLIT'] = NO_SPLIT + d['EXPORT_DIR'] = EXPORT_DIR + d['ONLY_SELECTED'] = ONLY_SELECTED + d['PER_FACE_1_OR_2_SIDED'] = PER_FACE_1_OR_2_SIDED + d['tooltips'] = tooltips + d['GLOBAL_COORDS'] = GLOBAL_COORDS + Registry.SetKey(REG_KEY, d, True) + +# Looking for a saved key in Blender.Registry dict: +rd = Registry.GetKey(REG_KEY, True) + +if rd: + try: + AC3D_4 = rd['AC3D_4'] + SKIP_DATA = rd['SKIP_DATA'] + MIRCOL_AS_AMB = rd['MIRCOL_AS_AMB'] + MIRCOL_AS_EMIS = rd['MIRCOL_AS_EMIS'] + ADD_DEFAULT_MAT = rd['ADD_DEFAULT_MAT'] + SET_TEX_DIR = rd['SET_TEX_DIR'] + TEX_DIR = rd['TEX_DIR'] + EXPORT_DIR = rd['EXPORT_DIR'] + ONLY_SELECTED = rd['ONLY_SELECTED'] + NO_SPLIT = rd['NO_SPLIT'] + PER_FACE_1_OR_2_SIDED = rd['PER_FACE_1_OR_2_SIDED'] + GLOBAL_COORDS = rd['GLOBAL_COORDS'] + except KeyError: update_RegistryInfo() + +else: + update_RegistryInfo() + +VERBOSE = True +CONFIRM_OVERWRITE = True + +# check General scripts config key for default behaviors +rd = Registry.GetKey('General', True) +if rd: + try: + VERBOSE = rd['verbose'] + CONFIRM_OVERWRITE = rd['confirm_overwrite'] + except: pass + + +# The default material to be used when necessary (see ADD_DEFAULT_MAT) +DEFAULT_MAT = \ +'MATERIAL "DefaultWhite" rgb 1 1 1 amb 1 1 1 emis 0 0 0 \ +spec 0.5 0.5 0.5 shi 64 trans 0' + +# This transformation aligns Blender and AC3D coordinate systems: +BLEND_TO_AC3D_MATRIX = Mathutils.Matrix([1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,0,0,1]) + +def Round_s(f): + "Round to default precision and turn value to a string" + r = round(f,6) # precision set to 10e-06 + if r == int(r): + return str(int(r)) + else: + return str(r) + +def transform_verts(verts, m): + vecs = [] + for v in verts: + x, y, z = v.co + vec = Mathutils.Vector([x, y, z, 1]) + vecs.append(vec*m) + return vecs + +def get_loose_edges(mesh): + loose = LOOSE + return [e for e in mesh.edges if e.flag & loose] + +# --- + +# meshes with more than one texture assigned +# are split and saved as these foomeshes +class FooMesh: + + class FooVert: + def __init__(self, v): + self.v = v + self.index = 0 + + class FooFace: + def __init__(self, foomesh, f): + self.f = f + foov = foomesh.FooVert + self.v = [foov(f.v[0]), foov(f.v[1])] + len_fv = len(f.v) + if len_fv > 2 and f.v[2]: + self.v.append(foov(f.v[2])) + if len_fv > 3 and f.v[3]: self.v.append(foov(f.v[3])) + + def __getattr__(self, attr): + if attr == 'v': return self.v + return getattr(self.f, attr) + + def __len__(self): + return len(self.f) + + def __init__(self, tex, faces, mesh): + self.name = mesh.name + self.mesh = mesh + self.looseEdges = [] + self.faceUV = mesh.faceUV + self.degr = mesh.degr + vidxs = [0]*len(mesh.verts) + foofaces = [] + for f in faces: + foofaces.append(self.FooFace(self, f)) + for v in f.v: + if v: vidxs[v.index] = 1 + i = 0 + fooverts = [] + for v in mesh.verts: + if vidxs[v.index]: + fooverts.append(v) + vidxs[v.index] = i + i += 1 + for f in foofaces: + for v in f.v: + if v: v.index = vidxs[v.v.index] + self.faces = foofaces + self.verts = fooverts + + +class AC3DExport: # the ac3d exporter part + + def __init__(self, scene_objects, file): + + global ARG, SKIP_DATA, ADD_DEFAULT_MAT, DEFAULT_MAT + + header = 'AC3Db' + self.file = file + self.buf = '' + self.mbuf = [] + self.mlist = [] + world_kids = 0 + parents_list = self.parents_list = [] + kids_dict = self.kids_dict = {} + objs = [] + exp_objs = self.exp_objs = [] + tree = {} + + file.write(header+'\n') + + objs = \ + [o for o in scene_objects if o.type in ['Mesh', 'Empty']] + + # create a tree from parents to children objects + + for obj in objs[:]: + parent = obj.parent + lineage = [obj] + + while parent: + parents_list.append(parent.name) + obj = parent + parent = parent.getParent() + lineage.insert(0, obj) + + d = tree + for i in xrange(len(lineage)): + lname = lineage[i].getType()[:2] + lineage[i].name + if lname not in d.keys(): + d[lname] = {} + d = d[lname] + + # traverse the tree to get an ordered list of names of objects to export + self.traverse_dict(tree) + + world_kids = len(tree.keys()) + + # get list of objects to export, start writing the .ac file + + objlist = [Object.Get(name) for name in exp_objs] + + meshlist = [o for o in objlist if o.type == 'Mesh'] + + # create a temporary mesh to hold actual (modified) mesh data + TMP_mesh = Mesh.New('tmp_for_ac_export') + + # write materials + + self.MATERIALS(meshlist, TMP_mesh) + mbuf = self.mbuf + if not mbuf or ADD_DEFAULT_MAT: + mbuf.insert(0, "%s\n" % DEFAULT_MAT) + mbuf = "".join(mbuf) + file.write(mbuf) + + file.write('OBJECT world\nkids %s\n' % world_kids) + + # write the objects + + for obj in objlist: + self.obj = obj + + objtype = obj.type + objname = obj.name + kidsnum = kids_dict[objname] + + # A parent plus its children are exported as a group. + # If the parent is a mesh, its rot and loc are exported as the + # group rot and loc and the mesh (w/o rot and loc) is added to the group. + if kidsnum: + self.OBJECT('group') + self.name(objname) + if objtype == 'Mesh': + kidsnum += 1 + if not GLOBAL_COORDS: + localmatrix = obj.getMatrix('localspace') + if not obj.getParent(): + localmatrix *= BLEND_TO_AC3D_MATRIX + self.rot(localmatrix.rotationPart()) + self.loc(localmatrix.translationPart()) + self.kids(kidsnum) + + if objtype == 'Mesh': + mesh = TMP_mesh # temporary mesh to hold actual (modified) mesh data + mesh.getFromObject(objname) + self.mesh = mesh + if mesh.faceUV: + meshes = self.split_mesh(mesh) + else: + meshes = [mesh] + if len(meshes) > 1: + if NO_SPLIT or self.dont_split(objname): + self.export_mesh(mesh, ob) + REPORT_DATA['nosplit'].append(objname) + else: + self.OBJECT('group') + self.name(objname) + self.kids(len(meshes)) + counter = 0 + for me in meshes: + self.export_mesh(me, obj, + name = '%s_%s' % (obj.name, counter), foomesh = True) + self.kids() + counter += 1 + else: + self.export_mesh(mesh, obj) + self.kids() + + + def traverse_dict(self, d): + kids_dict = self.kids_dict + exp_objs = self.exp_objs + keys = d.keys() + keys.sort() # sort for predictable output + keys.reverse() + for k in keys: + objname = k[2:] + klen = len(d[k]) + kids_dict[objname] = klen + if self.dont_export(objname): + d.pop(k) + parent = Object.Get(objname).getParent() + if parent: kids_dict[parent.name] -= 1 + REPORT_DATA['noexport'].append(objname) + continue + if klen: + self.traverse_dict(d[k]) + exp_objs.insert(0, objname) + else: + if k.find('Em', 0) == 0: # Empty w/o children + d.pop(k) + parent = Object.Get(objname).getParent() + if parent: kids_dict[parent.name] -= 1 + else: + exp_objs.insert(0, objname) + + def dont_export(self, name): # if name starts with '!' or '#' + length = len(name) + if length >= 1: + if name[0] in TOKENS_DONT_EXPORT: # '!' or '#' doubled (escaped): export + if length > 1 and name[1] == name[0]: + return 0 + return 1 + + def dont_split(self, name): # if name starts with '=' or '$' + length = len(name) + if length >= 1: + if name[0] in TOKENS_DONT_SPLIT: # '=' or '$' doubled (escaped): split + if length > 1 and name[1] == name[0]: + return 0 + return 1 + + def split_mesh(self, mesh): + tex_dict = {0:[]} + for f in mesh.faces: + if f.image: + if not f.image.name in tex_dict: tex_dict[f.image.name] = [] + tex_dict[f.image.name].append(f) + else: tex_dict[0].append(f) + keys = tex_dict.keys() + len_keys = len(keys) + if not tex_dict[0]: + len_keys -= 1 + tex_dict.pop(0) + keys.remove(0) + elif len_keys > 1: + lines = [] + anyimgkey = [k for k in keys if k != 0][0] + for f in tex_dict[0]: + if len(f.v) < 3: + lines.append(f) + if len(tex_dict[0]) == len(lines): + for l in lines: + tex_dict[anyimgkey].append(l) + len_keys -= 1 + tex_dict.pop(0) + if len_keys > 1: + foo_meshes = [] + for k in keys: + faces = tex_dict[k] + foo_meshes.append(FooMesh(k, faces, mesh)) + foo_meshes[0].edges = get_loose_edges(mesh) + return foo_meshes + return [mesh] + + def export_mesh(self, mesh, obj, name = None, foomesh = False): + file = self.file + self.OBJECT('poly') + if not name: name = obj.name + self.name(name) + if not SKIP_DATA: + meshname = obj.getData(name_only = True) + self.data(len(meshname), meshname) + if mesh.faceUV: + texline = self.texture(mesh.faces) + if texline: file.write(texline) + if AC3D_4: + self.crease(mesh.degr) + + # If exporting using local coordinates, children object coordinates should not be + # transformed to ac3d's coordinate system, since that will be accounted for in + # their topmost parents (the parents w/o parents) transformations. + if not GLOBAL_COORDS: + # We hold parents in a list, so they also don't get transformed, + # because for each parent we create an ac3d group to hold both the + # parent and its children. + if obj.name not in self.parents_list: + localmatrix = obj.getMatrix('localspace') + if not obj.getParent(): + localmatrix *= BLEND_TO_AC3D_MATRIX + self.rot(localmatrix.rotationPart()) + self.loc(localmatrix.translationPart()) + matrix = None + else: + matrix = obj.getMatrix() * BLEND_TO_AC3D_MATRIX + + self.numvert(mesh.verts, matrix) + self.numsurf(mesh, foomesh) + + def MATERIALS(self, meshlist, me): + for meobj in meshlist: + me.getFromObject(meobj) + mats = me.materials + mbuf = [] + mlist = self.mlist + for m in mats: + if not m: continue + name = m.name + if name not in mlist: + mlist.append(name) + M = Material.Get(name) + material = 'MATERIAL "%s"' % name + mirCol = "%s %s %s" % (Round_s(M.mirCol[0]), Round_s(M.mirCol[1]), + Round_s(M.mirCol[2])) + rgb = "rgb %s %s %s" % (Round_s(M.R), Round_s(M.G), Round_s(M.B)) + ambval = Round_s(M.amb) + amb = "amb %s %s %s" % (ambval, ambval, ambval) + spec = "spec %s %s %s" % (Round_s(M.specCol[0]), + Round_s(M.specCol[1]), Round_s(M.specCol[2])) + if AC3D_4: + emit = Round_s(M.emit) + emis = "emis %s %s %s" % (emit, emit, emit) + shival = int(M.spec * 64) + else: + emis = "emis 0 0 0" + shival = 72 + shi = "shi %s" % shival + trans = "trans %s" % (Round_s(1 - M.alpha)) + if MIRCOL_AS_AMB: + amb = "amb %s" % mirCol + if MIRCOL_AS_EMIS: + emis = "emis %s" % mirCol + mbuf.append("%s %s %s %s %s %s %s\n" \ + % (material, rgb, amb, emis, spec, shi, trans)) + self.mlist = mlist + self.mbuf.append("".join(mbuf)) + + def OBJECT(self, type): + self.file.write('OBJECT %s\n' % type) + + def name(self, name): + if name[0] in TOKENS_DONT_EXPORT or name[0] in TOKENS_DONT_SPLIT: + if len(name) > 1: name = name[1:] + self.file.write('name "%s"\n' % name) + + def kids(self, num = 0): + self.file.write('kids %s\n' % num) + + def data(self, num, str): + self.file.write('data %s\n%s\n' % (num, str)) + + def texture(self, faces): + tex = "" + for f in faces: + if f.image: + tex = f.image.name + break + if tex: + image = Image.Get(tex) + texfname = image.filename + if SET_TEX_DIR: + texfname = bsys.basename(texfname) + if TEX_DIR: + texfname = bsys.join(TEX_DIR, texfname) + buf = 'texture "%s"\n' % texfname + xrep = image.xrep + yrep = image.yrep + buf += 'texrep %s %s\n' % (xrep, yrep) + self.file.write(buf) + + def rot(self, matrix): + rot = '' + not_I = 0 # not identity + matstr = [] + for i in [0, 1, 2]: + r = map(Round_s, matrix[i]) + not_I += (r[0] != '0')+(r[1] != '0')+(r[2] != '0') + not_I -= (r[i] == '1') + for j in [0, 1, 2]: + matstr.append(' %s' % r[j]) + if not_I: # no need to write identity + self.file.write('rot%s\n' % "".join(matstr)) + + def loc(self, loc): + loc = map(Round_s, loc) + if loc != ['0', '0', '0']: # no need to write default + self.file.write('loc %s %s %s\n' % (loc[0], loc[1], loc[2])) + + def crease(self, crease): + self.file.write('crease %f\n' % crease) + + def numvert(self, verts, matrix): + file = self.file + nvstr = [] + nvstr.append("numvert %s\n" % len(verts)) + + if matrix: + verts = transform_verts(verts, matrix) + for v in verts: + v = map (Round_s, v) + nvstr.append("%s %s %s\n" % (v[0], v[1], v[2])) + else: + for v in verts: + v = map(Round_s, v.co) + nvstr.append("%s %s %s\n" % (v[0], v[1], v[2])) + + file.write("".join(nvstr)) + + def numsurf(self, mesh, foomesh = False): + + global MATIDX_ERROR + + # local vars are faster and so better in tight loops + lc_ADD_DEFAULT_MAT = ADD_DEFAULT_MAT + lc_MATIDX_ERROR = MATIDX_ERROR + lc_PER_FACE_1_OR_2_SIDED = PER_FACE_1_OR_2_SIDED + lc_FACE_TWOSIDED = FACE_TWOSIDED + lc_MESH_TWOSIDED = MESH_TWOSIDED + + faces = mesh.faces + hasFaceUV = mesh.faceUV + if foomesh: + looseEdges = mesh.looseEdges + else: + looseEdges = get_loose_edges(mesh) + + file = self.file + + file.write("numsurf %s\n" % (len(faces) + len(looseEdges))) + + if not foomesh: verts = list(self.mesh.verts) + + materials = self.mesh.materials + mlist = self.mlist + matidx_error_reported = False + objmats = [] + for omat in materials: + if omat: objmats.append(omat.name) + else: objmats.append(None) + for f in faces: + if not objmats: + m_idx = 0 + elif objmats[f.mat] in mlist: + m_idx = mlist.index(objmats[f.mat]) + else: + if not lc_MATIDX_ERROR: + rdat = REPORT_DATA['warns'] + rdat.append("Object %s" % self.obj.name) + rdat.append("has at least one material *index* assigned but not") + rdat.append("defined (not linked to an existing material).") + rdat.append("Result: some faces may be exported with a wrong color.") + rdat.append("You can assign materials in the Edit Buttons window (F9).") + elif not matidx_error_reported: + midxmsg = "- Same for object %s." % self.obj.name + REPORT_DATA['warns'].append(midxmsg) + lc_MATIDX_ERROR += 1 + matidx_error_reported = True + m_idx = 0 + if lc_ADD_DEFAULT_MAT: m_idx -= 1 + refs = len(f) + flaglow = 0 # polygon + if lc_PER_FACE_1_OR_2_SIDED and hasFaceUV: # per face attribute + two_side = f.mode & lc_FACE_TWOSIDED + else: # global, for the whole mesh + two_side = self.mesh.mode & lc_MESH_TWOSIDED + two_side = (two_side > 0) << 1 + flaghigh = f.smooth | two_side + surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow) + if lc_ADD_DEFAULT_MAT and objmats: m_idx += 1 + matstr = "mat %s\n" % m_idx + refstr = "refs %s\n" % refs + u, v, vi = 0, 0, 0 + fvstr = [] + if foomesh: + for vert in f.v: + fvstr.append(str(vert.index)) + if hasFaceUV: + u = f.uv[vi][0] + v = f.uv[vi][1] + vi += 1 + fvstr.append(" %s %s\n" % (u, v)) + else: + for vert in f.v: + fvstr.append(str(verts.index(vert))) + if hasFaceUV: + u = f.uv[vi][0] + v = f.uv[vi][1] + vi += 1 + fvstr.append(" %s %s\n" % (u, v)) + + fvstr = "".join(fvstr) + + file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr)) + + # material for loose edges + edges_mat = 0 # default to first material + for omat in objmats: # but look for a material from this mesh + if omat in mlist: + edges_mat = mlist.index(omat) + if lc_ADD_DEFAULT_MAT: edges_mat += 1 + break + + for e in looseEdges: + fvstr = [] + #flaglow = 2 # 1 = closed line, 2 = line + #flaghigh = 0 + #surfstr = "SURF 0x%d%d\n" % (flaghigh, flaglow) + surfstr = "SURF 0x02\n" + + fvstr.append("%d 0 0\n" % verts.index(e.v1)) + fvstr.append("%d 0 0\n" % verts.index(e.v2)) + fvstr = "".join(fvstr) + + matstr = "mat %d\n" % edges_mat # for now, use first material + refstr = "refs 2\n" # 2 verts + + file.write("%s%s%s%s" % (surfstr, matstr, refstr, fvstr)) + + MATIDX_ERROR = lc_MATIDX_ERROR + +# End of Class AC3DExport + +from Blender.Window import FileSelector + +def report_data(): + global VERBOSE + + if not VERBOSE: return + + d = REPORT_DATA + msgs = { + '0main': '%s\nExporting meshes to AC3D format' % str(19*'-'), + '1warns': 'Warnings', + '2errors': 'Errors', + '3nosplit': 'Not split (because name starts with "=" or "$")', + '4noexport': 'Not exported (because name starts with "!" or "#")' + } + if NO_SPLIT: + l = msgs['3nosplit'] + l = "%s (because OPTION NO_SPLIT is set)" % l.split('(')[0] + msgs['3nosplit'] = l + keys = msgs.keys() + keys.sort() + for k in keys: + msgk = msgs[k] + msg = '\n'.join(d[k[1:]]) + if msg: + print '\n-%s:' % msgk + print msg + +# File Selector callback: +def fs_callback(filename): + global EXPORT_DIR, OBJS, CONFIRM_OVERWRITE, VERBOSE + + if not filename.endswith('.ac'): filename = '%s.ac' % filename + + if bsys.exists(filename) and CONFIRM_OVERWRITE: + if Blender.Draw.PupMenu('OVERWRITE?%t|File exists') != 1: + return + + Blender.Window.WaitCursor(1) + starttime = bsys.time() + + export_dir = bsys.dirname(filename) + if export_dir != EXPORT_DIR: + EXPORT_DIR = export_dir + update_RegistryInfo() + + try: + file = open(filename, 'w') + except IOError, (errno, strerror): + error = "IOError #%s: %s" % (errno, strerror) + REPORT_DATA['errors'].append("Saving failed - %s." % error) + error_msg = "Couldn't save file!%%t|%s" % error + Blender.Draw.PupMenu(error_msg) + return + + try: + test = AC3DExport(OBJS, file) + except: + file.close() + raise + else: + file.close() + endtime = bsys.time() - starttime + REPORT_DATA['main'].append("Done. Saved to: %s" % filename) + REPORT_DATA['main'].append("Data exported in %.3f seconds." % endtime) + + if VERBOSE: report_data() + Blender.Window.WaitCursor(0) + + +# -- End of definitions + +scn = Blender.Scene.GetCurrent() + +if ONLY_SELECTED: + OBJS = list(scn.objects.context) +else: + OBJS = list(scn.objects) + +if not OBJS: + Blender.Draw.PupMenu('ERROR: no objects selected') +else: + fname = bsys.makename(ext=".ac") + if EXPORT_DIR: + fname = bsys.join(EXPORT_DIR, bsys.basename(fname)) + FileSelector(fs_callback, "Export AC3D", fname) diff --git a/release/scripts/ac3d_import.py b/release/scripts/ac3d_import.py new file mode 100644 index 00000000000..9a7004e4b4d --- /dev/null +++ b/release/scripts/ac3d_import.py @@ -0,0 +1,771 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'AC3D (.ac)...' +Blender: 243 +Group: 'Import' +Tip: 'Import an AC3D (.ac) file.' +""" + +__author__ = "Willian P. Germano" +__url__ = ("blender", "elysiun", "AC3D's homepage, http://www.ac3d.org", + "PLib 3d gaming lib, http://plib.sf.net") +__version__ = "2.43.1 2007-02-21" + +__bpydoc__ = """\ +This script imports AC3D models into Blender. + +AC3D is a simple and affordable commercial 3d modeller also built with OpenGL. +The .ac file format is an easy to parse text format well supported, +for example, by the PLib 3d gaming library. + +Supported:
+ UV-textured meshes with hierarchy (grouping) information. + +Missing:
+ The url tag is irrelevant for Blender. + +Known issues:
+ - Some objects may be imported with wrong normals due to wrong information in the model itself. This can be noticed by strange shading, like darker than expected parts in the model. To fix this, select the mesh with wrong normals, enter edit mode and tell Blender to recalculate the normals, either to make them point outside (the usual case) or inside.
+ +Config Options:
+ - display transp (toggle): if "on", objects that have materials with alpha < 1.0 are shown with translucency (transparency) in the 3D View.
+ - subdiv (toggle): if "on", ac3d objects meant to be subdivided receive a SUBSURF modifier in Blender.
+ - textures dir (string): if non blank, when imported texture paths are +wrong in the .ac file, Blender will also look for them at this dir. + +Notes:
+ - When looking for assigned textures, Blender tries in order: the actual +paths from the .ac file, the .ac file's dir and the default textures dir path +users can configure (see config options above). +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# AC3DImport version 2.43.1 Feb 21, 2007 +# Program versions: Blender 2.43 and AC3Db files (means version 0xb) +# changed: better triangulation of ngons, more fixes to support bad .ac files, +# option to display transp mats in 3d view, support "subdiv" tag (via SUBSURF modifier) +# -------------------------------------------------------------------------- +# Thanks: Melchior Franz for extensive bug testing and reporting, making this +# version cope much better with old or bad .ac files, among other improvements; +# Stewart Andreason for reporting a serious crash. +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004-2007: Willian P. Germano, wgermano _at_ ig.com.br +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from math import radians + +import Blender +from Blender import Scene, Object, Mesh, Lamp, Registry, sys as bsys, Window, Image, Material, Modifier +from Blender.sys import dirsep +from Blender.Mathutils import Vector, Matrix, Euler +from Blender.Geometry import PolyFill + +# Default folder for AC3D textures, to override wrong paths, change to your +# liking or leave as "": +TEXTURES_DIR = "" + +DISPLAY_TRANSP = True + +SUBDIV = True + +tooltips = { + 'DISPLAY_TRANSP': 'Turn transparency on in the 3d View for objects using materials with alpha < 1.0.', + 'SUBDIV': 'Apply a SUBSURF modifier to objects meant to appear subdivided.', + 'TEXTURES_DIR': 'Additional folder to look for missing textures.' +} + +def update_registry(): + global TEXTURES_DIR, DISPLAY_TRANSP + rd = dict([('tooltips', tooltips), ('TEXTURES_DIR', TEXTURES_DIR), ('DISPLAY_TRANSP', DISPLAY_TRANSP), ('SUBDIV', SUBDIV)]) + Registry.SetKey('ac3d_import', rd, True) + +rd = Registry.GetKey('ac3d_import', True) + +if rd: + if 'GROUP' in rd: + update_registry() + try: + TEXTURES_DIR = rd['TEXTURES_DIR'] + DISPLAY_TRANSP = rd['DISPLAY_TRANSP'] + SUBDIV = rd['SUBDIV'] + except: + update_registry() +else: update_registry() + +if TEXTURES_DIR: + oldtexdir = TEXTURES_DIR + if dirsep == '/': TEXTURES_DIR = TEXTURES_DIR.replace('\\', '/') + if TEXTURES_DIR[-1] != dirsep: TEXTURES_DIR = "%s%s" % (TEXTURES_DIR, dirsep) + if oldtexdir != TEXTURES_DIR: update_registry() + + +VERBOSE = True +rd = Registry.GetKey('General', True) +if rd: + if rd.has_key('verbose'): + VERBOSE = rd['verbose'] + + +errmsg = "" + +# Matrix to align ac3d's coordinate system with Blender's one, +# it's a -90 degrees rotation around the x axis: +AC_TO_BLEND_MATRIX = Matrix([1, 0, 0], [0, 0, 1], [0, -1, 0]) + +AC_WORLD = 0 +AC_GROUP = 1 +AC_POLY = 2 +AC_LIGHT = 3 +AC_OB_TYPES = { + 'world': AC_WORLD, + 'group': AC_GROUP, + 'poly': AC_POLY, + 'light': AC_LIGHT + } + +AC_OB_BAD_TYPES_LIST = [] # to hold references to unknown (wrong) ob types + +def inform(msg): + global VERBOSE + if VERBOSE: print msg + +def euler_in_radians(eul): + "Used while there's a bug in the BPY API" + eul.x = radians(eul.x) + eul.y = radians(eul.y) + eul.z = radians(eul.z) + return eul + +class Obj: + + def __init__(self, type): + self.type = type + self.dad = None + self.name = '' + self.data = '' + self.tex = '' + self.texrep = [1,1] + self.texoff = None + self.loc = [] + self.rot = [] + self.size = [] + self.crease = 30 + self.subdiv = 0 + self.vlist = [] + self.flist_cfg = [] + self.flist_v = [] + self.flist_uv = [] + self.elist = [] + self.matlist = [] + self.kids = 0 + + self.bl_obj = None # the actual Blender object created from this data + +class AC3DImport: + + def __init__(self, filename): + + global errmsg + + self.scene = Scene.GetCurrent() + + self.i = 0 + errmsg = '' + self.importdir = bsys.dirname(filename) + try: + file = open(filename, 'r') + except IOError, (errno, strerror): + errmsg = "IOError #%s: %s" % (errno, strerror) + Blender.Draw.PupMenu('ERROR: %s' % errmsg) + inform(errmsg) + return None + header = file.read(5) + header, version = header[:4], header[-1] + if header != 'AC3D': + file.close() + errmsg = 'AC3D header not found (invalid file)' + Blender.Draw.PupMenu('ERROR: %s' % errmsg) + inform(errmsg) + return None + elif version != 'b': + inform('AC3D file version 0x%s.' % version) + inform('This importer is for version 0xb, so it may fail.') + + self.token = {'OBJECT': self.parse_obj, + 'numvert': self.parse_vert, + 'numsurf': self.parse_surf, + 'name': self.parse_name, + 'data': self.parse_data, + 'kids': self.parse_kids, + 'loc': self.parse_loc, + 'rot': self.parse_rot, + 'MATERIAL': self.parse_mat, + 'texture': self.parse_tex, + 'texrep': self.parse_texrep, + 'texoff': self.parse_texoff, + 'subdiv': self.parse_subdiv, + 'crease': self.parse_crease} + + self.objlist = [] + self.mlist = [] + self.kidsnumlist = [] + self.dad = None + + self.lines = file.readlines() + self.lines.append('') + self.parse_file() + file.close() + + self.testAC3DImport() + + def parse_obj(self, value): + kidsnumlist = self.kidsnumlist + if kidsnumlist: + while not kidsnumlist[-1]: + kidsnumlist.pop() + if kidsnumlist: + self.dad = self.dad.dad + else: + inform('Ignoring unexpected data at end of file.') + return -1 # bad file with more objects than reported + kidsnumlist[-1] -= 1 + if value in AC_OB_TYPES: + new = Obj(AC_OB_TYPES[value]) + else: + if value not in AC_OB_BAD_TYPES_LIST: + AC_OB_BAD_TYPES_LIST.append(value) + inform('Unexpected object type keyword: "%s". Assuming it is of type: "poly".' % value) + new = Obj(AC_OB_TYPES['poly']) + new.dad = self.dad + new.name = value + self.objlist.append(new) + + def parse_kids(self, value): + kids = int(value) + if kids: + self.kidsnumlist.append(kids) + self.dad = self.objlist[-1] + self.objlist[-1].kids = kids + + def parse_name(self, value): + name = value.split('"')[1] + self.objlist[-1].name = name + + def parse_data(self, value): + data = self.lines[self.i].strip() + self.objlist[-1].data = data + + def parse_tex(self, value): + line = self.lines[self.i - 1] # parse again to properly get paths with spaces + texture = line.split('"')[1] + self.objlist[-1].tex = texture + + def parse_texrep(self, trash): + trep = self.lines[self.i - 1] + trep = trep.split() + trep = [float(trep[1]), float(trep[2])] + self.objlist[-1].texrep = trep + self.objlist[-1].texoff = [0, 0] + + def parse_texoff(self, trash): + toff = self.lines[self.i - 1] + toff = toff.split() + toff = [float(toff[1]), float(toff[2])] + self.objlist[-1].texoff = toff + + def parse_mat(self, value): + i = self.i - 1 + lines = self.lines + line = lines[i].split() + mat_name = '' + mat_col = mat_amb = mat_emit = mat_spec_col = [0,0,0] + mat_alpha = 1 + mat_spec = 1.0 + + while line[0] == 'MATERIAL': + mat_name = line[1].split('"')[1] + mat_col = map(float,[line[3],line[4],line[5]]) + v = map(float,[line[7],line[8],line[9]]) + mat_amb = (v[0]+v[1]+v[2]) / 3.0 + v = map(float,[line[11],line[12],line[13]]) + mat_emit = (v[0]+v[1]+v[2]) / 3.0 + mat_spec_col = map(float,[line[15],line[16],line[17]]) + mat_spec = float(line[19]) / 64.0 + mat_alpha = float(line[-1]) + mat_alpha = 1 - mat_alpha + self.mlist.append([mat_name, mat_col, mat_amb, mat_emit, mat_spec_col, mat_spec, mat_alpha]) + i += 1 + line = lines[i].split() + + self.i = i + + def parse_rot(self, trash): + i = self.i - 1 + ob = self.objlist[-1] + rot = self.lines[i].split(' ', 1)[1] + rot = map(float, rot.split()) + matrix = Matrix(rot[:3], rot[3:6], rot[6:]) + ob.rot = matrix + size = matrix.scalePart() # vector + ob.size = size + + def parse_loc(self, trash): + i = self.i - 1 + loc = self.lines[i].split(' ', 1)[1] + loc = map(float, loc.split()) + self.objlist[-1].loc = Vector(loc) + + def parse_crease(self, value): + # AC3D: range is [0.0, 180.0]; Blender: [1, 80] + value = float(value) + self.objlist[-1].crease = int(value) + + def parse_subdiv(self, value): + self.objlist[-1].subdiv = int(value) + + def parse_vert(self, value): + i = self.i + lines = self.lines + obj = self.objlist[-1] + vlist = obj.vlist + n = int(value) + + while n: + line = lines[i].split() + line = map(float, line) + vlist.append(line) + n -= 1 + i += 1 + + if vlist: # prepend a vertex at 1st position to deal with vindex 0 issues + vlist.insert(0, line) + + self.i = i + + def parse_surf(self, value): + i = self.i + is_smooth = 0 + double_sided = 0 + lines = self.lines + obj = self.objlist[-1] + vlist = obj.vlist + matlist = obj.matlist + numsurf = int(value) + NUMSURF = numsurf + + badface_notpoly = badface_multirefs = 0 + + while numsurf: + flags = lines[i].split()[1][2:] + if len(flags) > 1: + flaghigh = int(flags[0]) + flaglow = int(flags[1]) + else: + flaghigh = 0 + flaglow = int(flags[0]) + + is_smooth = flaghigh & 1 + twoside = flaghigh & 2 + nextline = lines[i+1].split() + if nextline[0] != 'mat': # the "mat" line may be missing (found in one buggy .ac file) + matid = 0 + if not matid in matlist: matlist.append(matid) + i += 2 + else: + matid = int(nextline[1]) + if not matid in matlist: matlist.append(matid) + nextline = lines[i+2].split() + i += 3 + refs = int(nextline[1]) + face = [] + faces = [] + edges = [] + fuv = [] + fuvs = [] + rfs = refs + + while rfs: + line = lines[i].split() + v = int(line[0]) + 1 # + 1 to avoid vindex == 0 + uv = [float(line[1]), float(line[2])] + face.append(v) + fuv.append(Vector(uv)) + rfs -= 1 + i += 1 + + if flaglow: # it's a line or closed line, not a polygon + while len(face) >= 2: + cut = face[:2] + edges.append(cut) + face = face[1:] + + if flaglow == 1 and edges: # closed line + face = [edges[-1][-1], edges[0][0]] + edges.append(face) + + else: # polygon + + # check for bad face, that references same vertex more than once + lenface = len(face) + if lenface < 3: + # less than 3 vertices, not a face + badface_notpoly += 1 + elif sum(map(face.count, face)) != lenface: + # multiple references to the same vertex + badface_multirefs += 1 + else: # ok, seems fine + if len(face) > 4: # ngon, triangulate it + polyline = [] + for vi in face: + polyline.append(Vector(vlist[vi])) + tris = PolyFill([polyline]) + for t in tris: + tri = [face[t[0]], face[t[1]], face[t[2]]] + triuvs = [fuv[t[0]], fuv[t[1]], fuv[t[2]]] + faces.append(tri) + fuvs.append(triuvs) + else: # tri or quad + faces.append(face) + fuvs.append(fuv) + + obj.flist_cfg.extend([[matid, is_smooth, twoside]] * len(faces)) + obj.flist_v.extend(faces) + obj.flist_uv.extend(fuvs) + obj.elist.extend(edges) # loose edges + + numsurf -= 1 + + if badface_notpoly or badface_multirefs: + inform('Object "%s" - ignoring bad faces:' % obj.name) + if badface_notpoly: + inform('\t%d face(s) with less than 3 vertices.' % badface_notpoly) + if badface_multirefs: + inform('\t%d face(s) with multiple references to a same vertex.' % badface_multirefs) + + self.i = i + + def parse_file(self): + i = 1 + lines = self.lines + line = lines[i].split() + + while line: + kw = '' + for k in self.token.keys(): + if line[0] == k: + kw = k + break + i += 1 + if kw: + self.i = i + result = self.token[kw](line[1]) + if result: + break # bad .ac file, stop parsing + i = self.i + line = lines[i].split() + + # for each group of meshes we try to find one that can be used as + # parent of the group in Blender. + # If not found, we can use an Empty as parent. + def found_parent(self, groupname, olist): + l = [o for o in olist if o.type == AC_POLY \ + and not o.kids and not o.rot and not o.loc] + if l: + for o in l: + if o.name == groupname: + return o + #return l[0] + return None + + def build_hierarchy(self): + blmatrix = AC_TO_BLEND_MATRIX + + olist = self.objlist[1:] + olist.reverse() + + scene = self.scene + + newlist = [] + + for o in olist: + kids = o.kids + if kids: + children = newlist[-kids:] + newlist = newlist[:-kids] + if o.type == AC_GROUP: + parent = self.found_parent(o.name, children) + if parent: + children.remove(parent) + o.bl_obj = parent.bl_obj + else: # not found, use an empty + empty = scene.objects.new('Empty', o.name) + o.bl_obj = empty + + bl_children = [c.bl_obj for c in children if c.bl_obj != None] + + o.bl_obj.makeParent(bl_children, 0, 1) + for child in children: + blob = child.bl_obj + if not blob: continue + if child.rot: + eul = euler_in_radians(child.rot.toEuler()) + blob.setEuler(eul) + if child.size: + blob.size = child.size + if not child.loc: + child.loc = Vector(0.0, 0.0, 0.0) + blob.setLocation(child.loc) + + newlist.append(o) + + for o in newlist: # newlist now only has objs w/o parents + blob = o.bl_obj + if not blob: + continue + if o.size: + o.bl_obj.size = o.size + if not o.rot: + blob.setEuler([1.5707963267948966, 0, 0]) + else: + matrix = o.rot * blmatrix + eul = euler_in_radians(matrix.toEuler()) + blob.setEuler(eul) + if o.loc: + o.loc *= blmatrix + else: + o.loc = Vector(0.0, 0.0, 0.0) + blob.setLocation(o.loc) # forces DAG update, so we do it even for 0, 0, 0 + + # XXX important: until we fix the BPy API so it doesn't increase user count + # when wrapping a Blender object, this piece of code is needed for proper + # object (+ obdata) deletion in Blender: + for o in self.objlist: + if o.bl_obj: + o.bl_obj = None + + def testAC3DImport(self): + + FACE_TWOSIDE = Mesh.FaceModes['TWOSIDE'] + FACE_TEX = Mesh.FaceModes['TEX'] + MESH_AUTOSMOOTH = Mesh.Modes['AUTOSMOOTH'] + + MAT_MODE_ZTRANSP = Material.Modes['ZTRANSP'] + MAT_MODE_TRANSPSHADOW = Material.Modes['TRANSPSHADOW'] + + scene = self.scene + + bl_images = {} # loaded texture images + missing_textures = [] # textures we couldn't find + + objlist = self.objlist[1:] # skip 'world' + + bmat = [] + has_transp_mats = False + for mat in self.mlist: + name = mat[0] + m = Material.New(name) + m.rgbCol = (mat[1][0], mat[1][1], mat[1][2]) + m.amb = mat[2] + m.emit = mat[3] + m.specCol = (mat[4][0], mat[4][1], mat[4][2]) + m.spec = mat[5] + m.alpha = mat[6] + if m.alpha < 1.0: + m.mode |= MAT_MODE_ZTRANSP + has_transp_mats = True + bmat.append(m) + + if has_transp_mats: + for mat in bmat: + mat.mode |= MAT_MODE_TRANSPSHADOW + + obj_idx = 0 # index of current obj in loop + for obj in objlist: + if obj.type == AC_GROUP: + continue + elif obj.type == AC_LIGHT: + light = Lamp.New('Lamp') + object = scene.objects.new(light, obj.name) + #object.select(True) + obj.bl_obj = object + if obj.data: + light.name = obj.data + continue + + # type AC_POLY: + + # old .ac files used empty meshes as groups, convert to a real ac group + if not obj.vlist and obj.kids: + obj.type = AC_GROUP + continue + + mesh = Mesh.New() + object = scene.objects.new(mesh, obj.name) + #object.select(True) + obj.bl_obj = object + if obj.data: mesh.name = obj.data + mesh.degr = obj.crease # will auto clamp to [1, 80] + + if not obj.vlist: # no vertices? nothing more to do + continue + + mesh.verts.extend(obj.vlist) + + objmat_indices = [] + for mat in bmat: + if bmat.index(mat) in obj.matlist: + objmat_indices.append(bmat.index(mat)) + mesh.materials += [mat] + if DISPLAY_TRANSP and mat.alpha < 1.0: + object.transp = True + + for e in obj.elist: + mesh.edges.extend(e) + + if obj.flist_v: + mesh.faces.extend(obj.flist_v) + + facesnum = len(mesh.faces) + + if facesnum == 0: # shouldn't happen, of course + continue + + mesh.faceUV = True + + # checking if the .ac file had duplicate faces (Blender ignores them) + if facesnum != len(obj.flist_v): + # it has, ugh. Let's clean the uv list: + lenfl = len(obj.flist_v) + flist = obj.flist_v + uvlist = obj.flist_uv + cfglist = obj.flist_cfg + for f in flist: + f.sort() + fi = lenfl + while fi > 0: # remove data related to duplicates + fi -= 1 + if flist[fi] in flist[:fi]: + uvlist.pop(fi) + cfglist.pop(fi) + + img = None + if obj.tex != '': + if obj.tex in bl_images.keys(): + img = bl_images[obj.tex] + elif obj.tex not in missing_textures: + texfname = None + objtex = obj.tex + baseimgname = bsys.basename(objtex) + if bsys.exists(objtex) == 1: + texfname = objtex + elif bsys.exists(bsys.join(self.importdir, objtex)): + texfname = bsys.join(self.importdir, objtex) + else: + if baseimgname.find('\\') > 0: + baseimgname = bsys.basename(objtex.replace('\\','/')) + objtex = bsys.join(self.importdir, baseimgname) + if bsys.exists(objtex) == 1: + texfname = objtex + else: + objtex = bsys.join(TEXTURES_DIR, baseimgname) + if bsys.exists(objtex): + texfname = objtex + if texfname: + try: + img = Image.Load(texfname) + # Commented because it's unnecessary: + #img.xrep = int(obj.texrep[0]) + #img.yrep = int(obj.texrep[1]) + if img: + bl_images[obj.tex] = img + except: + inform("Couldn't load texture: %s" % baseimgname) + else: + missing_textures.append(obj.tex) + inform("Couldn't find texture: %s" % baseimgname) + + for i in range(facesnum): + f = obj.flist_cfg[i] + fmat = f[0] + is_smooth = f[1] + twoside = f[2] + bface = mesh.faces[i] + bface.smooth = is_smooth + if twoside: bface.mode |= FACE_TWOSIDE + if img: + bface.mode |= FACE_TEX + bface.image = img + bface.mat = objmat_indices.index(fmat) + fuv = obj.flist_uv[i] + if obj.texoff: + uoff = obj.texoff[0] + voff = obj.texoff[1] + urep = obj.texrep[0] + vrep = obj.texrep[1] + for uv in fuv: + uv[0] *= urep + uv[1] *= vrep + uv[0] += uoff + uv[1] += voff + + mesh.faces[i].uv = fuv + + # finally, delete the 1st vertex we added to prevent vindices == 0 + mesh.verts.delete(0) + + mesh.calcNormals() + + mesh.mode = MESH_AUTOSMOOTH + + # subdiv: create SUBSURF modifier in Blender + if SUBDIV and obj.subdiv > 0: + subdiv = obj.subdiv + subdiv_render = subdiv + # just to be safe: + if subdiv_render > 6: subdiv_render = 6 + if subdiv > 3: subdiv = 3 + modif = object.modifiers.append(Modifier.Types.SUBSURF) + modif[Modifier.Settings.LEVELS] = subdiv + modif[Modifier.Settings.RENDLEVELS] = subdiv_render + + obj_idx += 1 + + self.build_hierarchy() + scene.update() + +# End of class AC3DImport + +def filesel_callback(filename): + + inform("\nTrying to import AC3D model(s) from:\n%s ..." % filename) + Window.WaitCursor(1) + starttime = bsys.time() + test = AC3DImport(filename) + Window.WaitCursor(0) + endtime = bsys.time() - starttime + inform('Done! Data imported in %.3f seconds.\n' % endtime) + +Window.EditMode(0) + +Window.FileSelector(filesel_callback, "Import AC3D", "*.ac") diff --git a/release/scripts/add_mesh_empty.py b/release/scripts/add_mesh_empty.py new file mode 100644 index 00000000000..537bd1e2c3d --- /dev/null +++ b/release/scripts/add_mesh_empty.py @@ -0,0 +1,13 @@ +#!BPY +""" +Name: 'Empty mesh' +Blender: 243 +Group: 'AddMesh' +""" +import BPyAddMesh +import Blender + +def main(): + BPyAddMesh.add_mesh_simple('EmptyMesh', [], [], []) + +main() \ No newline at end of file diff --git a/release/scripts/add_mesh_torus.py b/release/scripts/add_mesh_torus.py new file mode 100644 index 00000000000..de2db42d482 --- /dev/null +++ b/release/scripts/add_mesh_torus.py @@ -0,0 +1,64 @@ +#!BPY +""" +Name: 'Torus' +Blender: 243 +Group: 'AddMesh' +""" +import BPyAddMesh +import Blender +from math import cos, sin, pi + +def add_torus(PREF_MAJOR_RAD, PREF_MINOR_RAD, PREF_MAJOR_SEG, PREF_MINOR_SEG): + Vector = Blender.Mathutils.Vector + RotationMatrix = Blender.Mathutils.RotationMatrix + verts = [] + faces = [] + i1 = 0 + tot_verts = PREF_MAJOR_SEG * PREF_MINOR_SEG + for major_index in xrange(PREF_MAJOR_SEG): + verts_tmp = [] + mtx = RotationMatrix( 360 * float(major_index)/PREF_MAJOR_SEG, 3, 'z' ) + + for minor_index in xrange(PREF_MINOR_SEG): + angle = 2*pi*minor_index/PREF_MINOR_SEG + + verts.append( Vector(PREF_MAJOR_RAD+(cos(angle)*PREF_MINOR_RAD), 0, (sin(angle)*PREF_MINOR_RAD)) * mtx ) + if minor_index+1==PREF_MINOR_SEG: + i2 = (major_index)*PREF_MINOR_SEG + i3 = i1 + PREF_MINOR_SEG + i4 = i2 + PREF_MINOR_SEG + + else: + i2 = i1 + 1 + i3 = i1 + PREF_MINOR_SEG + i4 = i3 + 1 + + if i2>=tot_verts: i2 = i2-tot_verts + if i3>=tot_verts: i3 = i3-tot_verts + if i4>=tot_verts: i4 = i4-tot_verts + + faces.append( (i3,i4,i2,i1) ) + i1+=1 + + return verts, faces + +def main(): + Draw = Blender.Draw + PREF_MAJOR_RAD = Draw.Create(1.0) + PREF_MINOR_RAD = Draw.Create(0.25) + PREF_MAJOR_SEG = Draw.Create(48) + PREF_MINOR_SEG = Draw.Create(16) + + if not Draw.PupBlock('Add Torus', [\ + ('Major Radius:', PREF_MAJOR_RAD, 0.01, 100, 'Radius for the main ring of the torus'),\ + ('Minor Radius:', PREF_MINOR_RAD, 0.01, 100, 'Radius for the minor ring of the torus setting the thickness of the ring.'),\ + ('Major Segments:', PREF_MAJOR_SEG, 3, 256, 'Radius for the main ring of the torus'),\ + ('Minor Segments:', PREF_MINOR_SEG, 3, 256, 'Radius for the minor ring of the torus setting the thickness of the ring.'),\ + ]): + return + + verts, faces = add_torus(PREF_MAJOR_RAD.val, PREF_MINOR_RAD.val, PREF_MAJOR_SEG.val, PREF_MINOR_SEG.val) + + BPyAddMesh.add_mesh_simple('Torus', verts, [], faces) + +main() \ No newline at end of file diff --git a/release/scripts/animation_trajectory.py b/release/scripts/animation_trajectory.py new file mode 100644 index 00000000000..55a670b66b1 --- /dev/null +++ b/release/scripts/animation_trajectory.py @@ -0,0 +1,575 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Trajectory' +Blender: 243 +Group: 'Animation' +Tip: 'See Trajectory of selected object' +""" + +__author__ = '3R - R3gis' +__version__ = '2.43' +__url__ = ["Script's site , http://blenderfrance.free.fr/python/Trajectory_en.htm","Author's site , http://cybercreator.free.fr", "French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender"] +__email__=["3R, r3gis@free.fr"] + + +__bpydoc__ = """ + +Usage: + +* Launch with alt+P (or put it in .script folder) + +Allow to see in real time trajectory of selected object. + +On first run, it ask you +- If you want that actually selected object have they trajectory always shown +- If you want to use Space Handler or a Scriptlink in Redraw mode +- Future and Past : it is the frame in past and future +of the beggining and the end of the path +- Width of line that represent the trajectory + +Then the object's trajectory will be shown in all 3D areas. +When trajectory is red, you can modifiy it by moving object. +When trajectory is blue and you want to be able to modify it, inser a Key (I-Key) + +Points appears on trajectory : +- Left Clic to modify position +- Right Clic to go to the frame it represents + +Notes:
+In scriptlink mode, it create one script link so make sure that 'Enable Script Link' toogle is on +In SpaceHandler mode, you have to go in View>>SpaceHandlerScript menu to activate Trajectory + + +""" + + +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004-2006: Regis Montoya +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +################################# +# by 3R - 26/08/05 +# for any problem : +# r3gis@free.fr +# ou sur le newsgroup: +# http://zoo-logique.org/3D.Blender/ +################################# +#Many thanks to cambo for his fixes +################################# + + + +import Blender + + +scene= Blender.Scene.GetCurrent() + + +#Writing +def write_script(name, script): + global scene + #List texts and their name + #write : type of writing : 1->New, 2->Overwrite + scripting= None + for text in Blender.Text.Get(): + if text.name==name and text.asLines()[1] != "#"+str(__version__): + scripting = text + scripting.clear() + scripting.write(script) + break + + if not scripting: + scripting= Blender.Text.New(name) + scripting.write(script) + +def link_script(name, type): + global scene + scriptlinks = scene.getScriptLinks(type) # none or list + if not scriptlinks or name not in scriptlinks: + scene.addScriptLink(name, type) + + +#Deleting of a text +def text_remove(name): + global scene + #try to delete text if already linked + try: + text= Blender.Text.Get(name) + # Texte.clear() + scene.clearScriptLinks([name]) + Blender.Text.unlink(text) + except: + print('---Initialisation of Trajectory_'+str(__version__)+'.py---') + +#Whether is already running, also check if it's the last version of the script : second line contain the version fo the script +ask_modif= 0 # Default +for text in Blender.Text.Get(): + if text.name == 'Trajectory' and text.asLines()[1] == "#"+str(__version__): + #We ask if script modify his seetings, keep it or stop script + ask_modif= Blender.Draw.PupMenu("Script already launch %t|Modify settings%x0|Keep settings%x1|Stop script%x2|") + if ask_modif==-1: # user canceled. + ask_modif= 1 + break + +selection_mode= 0 +future= 35 +past= 20 +width= 2 + +#In modify case +if ask_modif==0: + handle_mode= Blender.Draw.Create(0) + selection_mode= Blender.Draw.Create(0) + future= Blender.Draw.Create(35) + past= Blender.Draw.Create(20) + width= Blender.Draw.Create(2) + + block= [] + block.append(("Space Handlers", handle_mode, "You have to activate for each area by View>>SpaceHandler")) #You can delete this option... + block.append(("Always Draw", selection_mode, "Selected object will have their trajectory always shown")) + block.append(("Past :", past, 1, 900)) + block.append(("Futur:", future, 1, 900)) + block.append(("Width:", width, 1,5)) + + if not Blender.Draw.PupBlock("Trajectory seetings", block): + ask_modif=1 + + handle_mode= handle_mode.val + selection_mode= selection_mode.val + future= future.val + past= past.val + width= width.val + + +#put names of selected objects in objects_select if option choosen by user +if selection_mode==1: + objects_select= [ob.name for ob in scene.objects.context] +else: + objects_select= [] + + +try: + if handle_mode==1: + DrawPart="#SPACEHANDLER.VIEW3D.DRAW\n" + else: + DrawPart="#!BPY\n" +except:DrawPart="#BadlyMade" + + +#Here is the script to write in Blender and to link, options are also written now +DrawPart=DrawPart+"#"+str(__version__)+""" +#This script is a part of Trajectory.py and have to be linked to the scene in Redraw if not in HANDLER mode. +#Author : 3R - Regis Montoya +#It's better to use the Trajectory_"version_number".py +#You can modify the two following value to change the path settings +future="""+str(future)+""" +past="""+str(past)+""" +object_init_names="""+str(objects_select)+""" + + +import Blender, math +from Blender import BGL, Draw, Ipo +from Blender.BGL import * +from Blender.Draw import * +from math import * + +from Blender.Mathutils import Vector + +#take actual frame +frameC=Blender.Get('curframe') +scene = Blender.Scene.GetCurrent() +render_context=scene.getRenderingContext() +#ajust number of frames with NewMap and OldMapvalue values +k=1.00*render_context.oldMapValue()/render_context.newMapValue() +if k<1: + tr=-1*int(log(k*0.1, 10)) +else: + tr=-1*int(log(k, 10)) +#The real and integer frame to compare to ipos keys frames +frameCtr=round(frameC*k, tr) +frameCr=frameC*k +frameC=int(round(frameC*k, 0)) + + +#List objects that we have to show trajectory in $objects +# In this case, using a dict for unique objects is the fastest way. +object_dict= dict([(ob.name, ob) for ob in scene.objects.context]) +for obname in object_init_names: + if not object_dict.has_key(obname): + try: # Object may be removed. + object_dict[obname]= Blender.Object.Get(obname) + except: + pass # object was removed. + +#This fonction give the resulting matrix of all parents at a given frame +#parent_list is the list of all parents [object, matrix, locX_ipo, locY, Z, rotX, Y, Z, sizeX, Y, Z] of current object +def matrixForTraj(frame, parent_list): + DecMatC=Blender.Mathutils.Matrix([1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]) + + for parent_data in parent_list: + parent_ob= parent_data[0] + + try: X= parent_data[5][frame]*pi/18 + except: X= parent_ob.RotX + try: Y= parent_data[6][frame]*pi/18 + except: Y= parent_ob.RotY + try: Z= parent_data[7][frame]*pi/18 + except: Z= parent_ob.RotZ + try: LX= parent_data[2][frame] + except: LX= parent_ob.LocX + try: LY= parent_data[3][frame] + except: LY= parent_ob.LocY + try: LZ= parent_data[4][frame] + except: LZ= parent_ob.LocZ + try: SX= parent_data[8][frame] + except: SX= parent_ob.SizeX + try: SY= parent_data[9][frame] + except: SY= parent_ob.SizeY + try: SZ= parent_data[10][frame] + except: SZ= parent_ob.SizeZ + + NMat=Blender.Mathutils.Matrix([cos(Y)*cos(Z)*SX,SX*cos(Y)*sin(Z),-SX*sin(Y),0], + [(-cos(X)*sin(Z)+sin(Y)*sin(X)*cos(Z))*SY,(sin(X)*sin(Y)*sin(Z)+cos(X)*cos(Z))*SY,sin(X)*cos(Y)*SY,0], + [(cos(X)*sin(Y)*cos(Z)+sin(X)*sin(Z))*SZ,(cos(X)*sin(Y)*sin(Z)-sin(X)*cos(Z))*SZ,SZ*cos(X)*cos(Y),0], + [LX,LY,LZ,1]) + DecMatC=DecMatC*parent_data[1]*NMat + return DecMatC + +##### +TestLIST=[] +matview=Blender.Window.GetPerspMatrix() +########### +#Fonction to draw trajectories +########### + +def Trace_Traj(ob): + global TestLIST, matview + #we draw trajectories for all objects in list + + LocX=[] + LocY=[] + LocZ=[] + #List with trajectories' vertexs + vertexX=[] + + contextIpo= ob.ipo + if contextIpo: + ipoLocX=contextIpo[Ipo.OB_LOCX] + ipoLocY=contextIpo[Ipo.OB_LOCY] + ipoLocZ=contextIpo[Ipo.OB_LOCZ] + ipoTime=contextIpo[Ipo.OB_TIME] + else: # only do if there is no IPO (if no ipo curves : return None object and don't go in this except) + ipoLocX= ipoLocY= ipoLocZ= ipoTime= None + + if ipoTime: + return 0 + + #Get all parents of ob + parent=ob.parent + backup_ob= ob + child= ob + parent_list= [] + + #Get parents's infos : + #list of [name, initial matrix at make parent, ipo in X,Y,Z,rotX,rotY,rotZ,sizeX,Y,Z] + while parent: + Init_Mat=Blender.Mathutils.Matrix(child.getMatrix('worldspace')) #must be done like it (it isn't a matrix otherwise) + Init_Mat.invert() + Init_Mat=Init_Mat*child.getMatrix('localspace') + Init_Mat=parent.getMatrix()*Init_Mat + Init_Mat.invert() + + contextIpo= parent.ipo # None or IPO + if contextIpo: + ipo_Parent_LocX=contextIpo[Ipo.OB_LOCX] + ipo_Parent_LocY=contextIpo[Ipo.OB_LOCY] + ipo_Parent_LocZ=contextIpo[Ipo.OB_LOCZ] + ipo_Parent_RotX=contextIpo[Ipo.OB_ROTX] + ipo_Parent_RotY=contextIpo[Ipo.OB_ROTY] + ipo_Parent_RotZ=contextIpo[Ipo.OB_ROTZ] + ipo_Parent_SizeX=contextIpo[Ipo.OB_SIZEX] + ipo_Parent_SizeY=contextIpo[Ipo.OB_SIZEY] + ipo_Parent_SizeZ=contextIpo[Ipo.OB_SIZEZ] + else: + ipo_Parent_LocX=ipo_Parent_LocY=ipo_Parent_LocZ=\ + ipo_Parent_RotX=ipo_Parent_RotY=ipo_Parent_RotZ=\ + ipo_Parent_SizeX=ipo_Parent_SizeY=ipo_Parent_SizeZ= None + + parent_list.append([parent, Init_Mat, ipo_Parent_LocX, ipo_Parent_LocY, ipo_Parent_LocZ, ipo_Parent_RotX, ipo_Parent_RotY, ipo_Parent_RotZ, ipo_Parent_SizeX, ipo_Parent_SizeY, ipo_Parent_SizeZ]) + + child=parent + parent=parent.parent + + #security : if one of parents object are a path>>follow : trajectory don't work properly so it have to draw nothing + for parent in parent_list: + if parent[0].type == 'Curve': + if parent[0].data.flag & 1<<4: # Follow path, 4th bit + return 1 + + #ob >> re-assign obj and not parent + ob= backup_ob + ob= backup_ob + + + if ipoLocX: LXC= ipoLocX[frameC] + else: LXC= ob.LocX + if ipoLocY: LYC= ipoLocY[frameC] + else: LYC= ob.LocY + if ipoLocZ: LZC= ipoLocZ[frameC] + else: LZC= ob.LocZ + + vect= Vector([ob.LocX, ob.LocY, ob.LocZ, 1]) + color=[0, 1] + + #If trajectory is being modified and we are at a frame where a ipo key already exist + if round(ob.LocX, 5)!=round(LXC, 5): + for bez in ipoLocX.bezierPoints: + if round(bez.pt[0], tr)==frameCtr: + bez.pt = [frameCr, vect[0]] + ipoLocX.recalc() + if round(ob.LocY, 5)!=round(LYC, 5): + for bez in ipoLocY.bezierPoints: + if round(bez.pt[0], tr)==frameCtr: + bez.pt = [frameCr, vect[1]] + ipoLocY.recalc() + if round(ob.LocZ, 5)!=round(LZC, 5): + for bez in ipoLocZ.bezierPoints: + if round(bez.pt[0], tr)==frameCtr: + bez.pt = [frameCr, vect[2]] + ipoLocZ.recalc() + + #change trajectory color if at an ipoKey + VertexFrame=[] + bezier_Coord=0 + if ipoLocX: # FIXED like others it was just in case ipoLocX==None + for bez in ipoLocX.bezierPoints: + bezier_Coord=round(bez.pt[0], tr) + if bezier_Coord not in VertexFrame: + VertexFrame.append(bezier_Coord) + if bezier_Coord==frameCtr: + color=[1, color[1]-0.3] + if ipoLocY: # FIXED + for bez in ipoLocY.bezierPoints: + bezier_Coord=round(bez.pt[0], tr) + if bezier_Coord not in VertexFrame: + VertexFrame.append(bezier_Coord) + if round(bez.pt[0], tr)==frameCtr: + color=[1, color[1]-0.3] + if ipoLocZ: # FIXED + for bez in ipoLocZ.bezierPoints: + bezier_Coord=round(bez.pt[0], tr) + if bezier_Coord not in VertexFrame: + VertexFrame.append(bezier_Coord) + if round(bez.pt[0], tr)==frameCtr: + color=[1, color[1]-0.3] + + + #put in LocX, LocY and LocZ all points of trajectory + for frame in xrange(frameC-past, frameC+future): + DecMat=matrixForTraj(frame, parent_list) + + if ipoLocX: LX= ipoLocX[frame] + else: LX= ob.LocX + if ipoLocY: LY= ipoLocY[frame] + else: LY= ob.LocY + if ipoLocZ: LZ= ipoLocZ[frame] + else: LZ= ob.LocZ + + vect=Vector(LX, LY, LZ)*DecMat + LocX.append(vect[0]) + LocY.append(vect[1]) + LocZ.append(vect[2]) + + + #draw part : get current view + MatPreBuff= [matview[i][j] for i in xrange(4) for j in xrange(4)] + + MatBuff=BGL.Buffer(GL_FLOAT, 16, MatPreBuff) + + glLoadIdentity() + glMatrixMode(GL_PROJECTION) + glPushMatrix() + glLoadMatrixf(MatBuff) + + #draw trajectory line + glLineWidth("""+str(width)+""") + + glBegin(GL_LINE_STRIP) + for i in xrange(len(LocX)): + glColor3f((i+1)*1.00/len(LocX)*color[0], 0, (i+1)*1.00/len(LocX)*color[1]) + glVertex3f(LocX[i], LocY[i], LocZ[i]) + + glEnd() + + #draw trajectory's "vertexs" + if not Blender.Window.EditMode(): + glPointSize(5) + glBegin(GL_POINTS) + TestPOINTS=[] + TestFRAME=[] + i=0 + for frame in VertexFrame: + ix=int(frame)-frameC+past + if ix>=0 and ixpt[0]-4 and mouse_co[1]>pt[1]-4 and mouse_co[1]R and R>L can use the same code + def IS_XMIRROR_SOURCE(xval): + '''Source means is this the value we want to copy from''' + + if PREF_MODE_L2R: + if xval<0: return True + else: return False + else: # PREF_MODE_R2L + if xval<0: return False + else: return True + + if IS_XMIRROR_SOURCE( h1.x ):# head bone 1s negative, so copy it to h2 + editbone2.head= VecXFlip(h1) + else: + ''' + assume h2.x<0 - not a big deal if were wrong, + its unlikely to ever happen because the bones would both be on the same side. + ''' + + # head bone 2s negative, so copy it to h1 + editbone1.head= VecXFlip(h2) + + # Same as above for tail + if IS_XMIRROR_SOURCE(t1.x): + editbone2.tail= VecXFlip(t1) + else: + editbone1.tail= VecXFlip(t2) + + # Copy roll from 1 bone to another, use the head's location to decide which side it's on. + if IS_XMIRROR_SOURCE(editbone1.head): + editbone2.roll= -editbone1.roll + else: + editbone1.roll= -editbone2.roll + + +def armature_symetry(\ + arm_ob,\ + PREF_MAX_DIST,\ + PREF_XMID_SNAP,\ + PREF_XZERO_THRESH,\ + PREF_MODE_L2R,\ + PREF_MODE_R2L,\ + PREF_SEL_ONLY): + + ''' + Main function that does all the work, + return the number of + ''' + arm_data= arm_ob.data + arm_data.makeEditable() + + # Get the bones + bones= [] + HIDDEN_EDIT= Blender.Armature.HIDDEN_EDIT + BONE_SELECTED= Blender.Armature.BONE_SELECTED + + if PREF_SEL_ONLY: + for eb in arm_data.bones.values(): + options= eb.options + if HIDDEN_EDIT not in options and BONE_SELECTED in options: + bones.append(eb) + else: + # All non hidden bones + for eb in arm_data.bones.values(): + options= eb.options + if HIDDEN_EDIT not in options: + bones.append(eb) + + del HIDDEN_EDIT # remove temp variables + del BONE_SELECTED + + # Store the numder of bones we have modified for a message + tot_editbones= len(bones) + tot_editbones_modified= 0 + + if PREF_XMID_SNAP: + # Remove bones that are in the middle (X Zero) + # reverse loop so we can remove items in the list. + for eb_idx in xrange(len(bones)-1, -1, -1): + edit_bone= bones[eb_idx] + if abs(edit_bone.head.x) + abs(edit_bone.tail.x) <= PREF_XZERO_THRESH/2: + + # This is a center bone, clamp and remove from the bone list so we dont use again. + if edit_bone.tail.x or edit_bone.head.x: + tot_editbones_modified += 1 + + edit_bone.tail.x= edit_bone.head.x= 0 + del bones[eb_idx] + + + + + bone_comparisons= [] + + # Compare every bone with every other bone, shouldn't be too slow. + # These 2 "for" loops only compare once + for eb_idx_a in xrange(len(bones)-1, -1, -1): + edit_bone_a= bones[eb_idx_a] + for eb_idx_b in xrange(eb_idx_a-1, -1, -1): + edit_bone_b= bones[eb_idx_b] + # Error float the first value from editbone_mirror_diff() so we can sort the resulting list. + bone_comparisons.append(editbone_mirror_diff(edit_bone_a, edit_bone_b)) + + + bone_comparisons.sort() # best matches first + + # Make a dict() of bone names that have been used so we dont mirror more then once + bone_mirrored= {} + + for error, editbone1, editbone2 in bone_comparisons: + # print 'Trying to merge at error %.3f' % error + if error > PREF_MAX_DIST: + # print 'breaking, max error limit reached PREF_MAX_DIST: %.3f' % PREF_MAX_DIST + break + + if not bone_mirrored.has_key(editbone1.name) and not bone_mirrored.has_key(editbone2.name): + # Were not used, execute the mirror + editbone_mirror_merge(editbone1, editbone2, PREF_MODE_L2R, PREF_MODE_R2L) + # print 'Merging bones' + + # Add ourselves so we aren't touched again + bone_mirrored[editbone1.name] = None # dummy value, would use sets in python 2.4 + bone_mirrored[editbone2.name] = None + + # If both options are enabled, then we have changed 2 bones + tot_editbones_modified+= PREF_MODE_L2R + PREF_MODE_R2L + + arm_data.update() # get out of armature editmode + return tot_editbones, tot_editbones_modified + + +def main(): + ''' + User interface function that gets the options and calls armature_symetry() + ''' + + scn= bpy.data.scenes.active + arm_ob= scn.objects.active + + if not arm_ob or arm_ob.type!='Armature': + Blender.Draw.PupMenu('No Armature object selected.') + return + + # Cant be in editmode for armature.makeEditable() + is_editmode= Blender.Window.EditMode() + if is_editmode: Blender.Window.EditMode(0) + Draw= Blender.Draw + + # Defaults for the user input + PREF_XMID_SNAP= Draw.Create(1) + PREF_MAX_DIST= Draw.Create(0.4) + PREF_XZERO_THRESH= Draw.Create(0.02) + + PREF_MODE_L2R= Draw.Create(1) + PREF_MODE_R2L= Draw.Create(0) + PREF_SEL_ONLY= Draw.Create(1) + + pup_block = [\ + 'Left (-), Right (+)',\ + ('Left > Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc.'),\ + ('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc.'),\ + '',\ + ('MaxDist:', PREF_MAX_DIST, 0.0, 4.0, 'Maximum difference in mirror bones to match up pairs.'),\ + ('XZero limit:', PREF_XZERO_THRESH, 0.0, 2.0, 'Tolerance for locking bones into the middle (X/zero).'),\ + ('XMidSnap Bones', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\ + ('Selected Only', PREF_SEL_ONLY, 'Only xmirror selected bones.'),\ + ] + + # Popup, exit if the user doesn't click OK + if not Draw.PupBlock("X Mirror mesh tool", pup_block): + return + + # Replace the variables with their button values. + PREF_XMID_SNAP= PREF_XMID_SNAP.val + PREF_MAX_DIST= PREF_MAX_DIST.val + PREF_MODE_L2R= PREF_MODE_L2R.val + PREF_MODE_R2L= PREF_MODE_R2L.val + PREF_XZERO_THRESH= PREF_XZERO_THRESH.val + PREF_SEL_ONLY= PREF_SEL_ONLY.val + + # If both are off assume mid-point and enable both + if not PREF_MODE_R2L and not PREF_MODE_L2R: + PREF_MODE_R2L= PREF_MODE_L2R= True + + + tot_editbones, tot_editbones_modified = armature_symetry(\ + arm_ob,\ + PREF_MAX_DIST,\ + PREF_XMID_SNAP,\ + PREF_XZERO_THRESH,\ + PREF_MODE_L2R,\ + PREF_MODE_R2L,\ + PREF_SEL_ONLY) + + if is_editmode: Blender.Window.EditMode(1) + + # Redraw all views before popup + Blender.Window.RedrawAll() + + # Print results + if PREF_SEL_ONLY: + msg= 'moved %i bones of %i selected' % (tot_editbones_modified, tot_editbones) + else: + msg= 'moved %i bones of %i visible' % (tot_editbones_modified, tot_editbones) + + + Blender.Draw.PupMenu(msg) + +# Check for __main__ so this function can be imported by other scripts without running the script. +if __name__=='__main__': + main() diff --git a/release/scripts/bevel_center.py b/release/scripts/bevel_center.py new file mode 100644 index 00000000000..0ea305a0120 --- /dev/null +++ b/release/scripts/bevel_center.py @@ -0,0 +1,474 @@ +#!BPY + +""" Registration info for Blender menus +Name: 'Bevel Center' +Blender: 243 +Group: 'Mesh' +Tip: 'Bevel selected faces, edges, and vertices' +""" + +__author__ = "Loic BERTHE" +__url__ = ("blender", "elysiun") +__version__ = "2.0" + +__bpydoc__ = """\ +This script implements vertex and edges bevelling in Blender. + +Usage: + +Select the mesh you want to work on, enter Edit Mode and select the edges +to bevel. Then run this script from the 3d View's Mesh->Scripts menu. + +You can control the thickness of the bevel with the slider -- redefine the +end points for bigger or smaller ranges. The thickness can be changed even +after applying the bevel, as many times as needed. + +For an extra smoothing after or instead of direct bevel, set the level of +recursiveness and use the "Recursive" button. + +This "Recursive" Button, won't work in face select mode, unless you choose +"faces" in the select mode menu. + +Notes:
+ You can undo and redo your steps just like with normal mesh operations in +Blender. +""" + +###################################################################### +# Bevel Center v2.0 for Blender + +# This script lets you bevel the selected vertices or edges and control the +# thickness of the bevel + +# (c) 2004-2006 Loïc Berthe (loic+blender@lilotux.net) +# released under Blender Artistic License + +###################################################################### + +import Blender +from Blender import NMesh, Window, Scene +from Blender.Draw import * +from Blender.Mathutils import * +from Blender.BGL import * +import BPyMessages +#PY23 NO SETS# +''' +try: + set() +except: + from sets import set +''' + +###################################################################### +# Functions to handle the global structures of the script NF, NE and NC +# which contain informations about faces and corners to be created + +global E_selected +E_selected = NMesh.EdgeFlags['SELECT'] + +old_dist = None + +def act_mesh_ob(): + scn = Scene.GetCurrent() + ob = scn.objects.active + if ob == None or ob.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + if ob.getData(mesh=1).multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + return ob + +def make_sel_vert(*co): + v= NMesh.Vert(*co) + v.sel = 1 + me.verts.append(v) + return v + +def make_sel_face(verts): + f = NMesh.Face(verts) + f.sel = 1 + me.addFace(f) + +def add_to_NV(old,dir,new): + try: + NV[old][dir] = new + except: + NV[old] = {dir:new} + +def get_v(old, *neighbors): + # compute the direction of the new vert + if len(neighbors) == 1: dir = (neighbors[0].co - old.co).normalize() + #dir + else: dir = (neighbors[0].co - old.co).normalize() + (neighbors[1].co-old.co).normalize() + + # look in NV if this vert already exists + key = tuple(dir) + if old in NV and key in NV[old] : return NV[old][key] + + # else, create it + new = old.co + dist.val*dir + v = make_sel_vert(new.x,new.y,new.z) + add_to_NV(old,key,v) + return v + +def make_faces(): + """ Analyse the mesh, make the faces corresponding to selected faces and + fill the structures NE and NC """ + + # make the differents flags consistent + for e in me.edges: + if e.flag & E_selected : + e.v1.sel = 1 + e.v2.sel = 1 + + NF =[] # NF : New faces + for f in me.faces: + V = f.v + nV = len(V) + enumV = range(nV) + E = [me.findEdge(V[i],V[(i+1) % nV]) for i in enumV] + Esel = [x.flag & E_selected for x in E] + + # look for selected vertices and creates a list containing the new vertices + newV = V[:] + changes = False + for (i,v) in enumerate(V): + if v.sel : + changes = True + if Esel[i-1] == 0 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1]) + elif Esel[i-1] == 1 and Esel[i] == 0 : newV[i] = get_v(v,V[(i+1) % nV]) + elif Esel[i-1] == 1 and Esel[i] == 1 : newV[i] = get_v(v,V[i-1],V[(i+1) % nV]) + else : newV[i] = [get_v(v,V[i-1]),get_v(v,V[(i+1) % nV])] + + if changes: + # determine and store the face to be created + + lenV = [len(x) for x in newV] + if 2 not in lenV : + new_f = NMesh.Face(newV) + if sum(Esel) == nV : new_f.sel = 1 + NF.append(new_f) + + else : + nb2 = lenV.count(2) + + if nV == 4 : # f is a quad + if nb2 == 1 : + ind2 = lenV.index(2) + NF.append(NMesh.Face([newV[ind2-1],newV[ind2][0],newV[ind2][1],newV[ind2-3]])) + NF.append(NMesh.Face([newV[ind2-1],newV[ind2-2],newV[ind2-3]])) + + elif nb2 == 2 : + # We must know if the tuples are neighbours + ind2 = ''.join([str(x) for x in lenV+lenV[:1]]).find('22') + + if ind2 != -1 : # They are + NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-3][0],newV[ind2-3][1]])) + NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2],newV[ind2-3][1]])) + + else: # They aren't + ind2 = lenV.index(2) + NF.append(NMesh.Face([newV[ind2][0],newV[ind2][1],newV[ind2-2][0],newV[ind2-2][1]])) + NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3],newV[ind2-2][0]])) + NF.append(NMesh.Face([newV[ind2][0],newV[ind2-1],newV[ind2-2][1]])) + + elif nb2 == 3 : + ind2 = lenV.index(3) + NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-3][0]])) + NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2-3][0],newV[ind2-3][1]])) + NF.append(NMesh.Face([newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0]])) + + else: + if (newV[0][1].co-newV[3][0].co).length + (newV[1][0].co-newV[2][1].co).length \ + < (newV[0][0].co-newV[1][1].co).length + (newV[2][0].co-newV[3][1].co).length : + ind2 = 0 + else : + ind2 = 1 + NF.append(NMesh.Face([newV[ind2-1][0],newV[ind2-1][1],newV[ind2][0],newV[ind2][1]])) + NF.append(NMesh.Face([newV[ind2][1],newV[ind2-3][0],newV[ind2-2][1],newV[ind2-1][0]])) + NF.append(NMesh.Face([newV[ind2-3][0],newV[ind2-3][1],newV[ind2-2][0],newV[ind2-2][1]])) + + else : # f is a tri + if nb2 == 1: + ind2 = lenV.index(2) + NF.append(NMesh.Face([newV[ind2-2],newV[ind2-1],newV[ind2][0],newV[ind2][1]])) + + elif nb2 == 2: + ind2 = lenV.index(3) + NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2],newV[ind2-2][0]])) + NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]])) + + else: + ind2 = min( [((newV[i][1].co-newV[i-1][0].co).length, i) for i in enumV] )[1] + NF.append(NMesh.Face([newV[ind2-1][1],newV[ind2][0],newV[ind2][1],newV[ind2-2][0]])) + NF.append(NMesh.Face([newV[ind2-2][0],newV[ind2-2][1],newV[ind2-1][0],newV[ind2-1][1]])) + + # Preparing the corners + for i in enumV: + if lenV[i] == 2 : NC.setdefault(V[i],[]).append(newV[i]) + + + old_faces.append(f) + + # Preparing the Edges + for i in enumV: + if Esel[i]: + verts = [newV[i],newV[(i+1) % nV]] + if V[i].index > V[(i+1) % nV].index : verts.reverse() + NE.setdefault(E[i],[]).append(verts) + + # Create the faces + for f in NF: me.addFace(f) + +def make_edges(): + """ Make the faces corresponding to selected edges """ + + for old,new in NE.iteritems() : + if len(new) == 1 : # This edge was on a border + oldv = [old.v1, old.v2] + if old.v1.index < old.v2.index : oldv.reverse() + + make_sel_face(oldv+new[0]) + + me.findEdge(*oldv).flag |= E_selected + me.findEdge(*new[0]).flag |= E_selected + + #PY23 NO SETS# for v in oldv : NV_ext.add(v) + for v in oldv : NV_ext[v]= None + + else: + make_sel_face(new[0] + new[1][::-1]) + + me.findEdge(*new[0]).flag |= E_selected + me.findEdge(*new[1]).flag |= E_selected + +def make_corners(): + """ Make the faces corresponding to corners """ + + for v in NV.iterkeys(): + V = NV[v].values() + nV = len(V) + + if nV == 1: pass + + elif nV == 2 : + #PY23 NO SETS# if v in NV_ext: + if v in NV_ext.iterkeys(): + make_sel_face(V+[v]) + me.findEdge(*V).flag |= E_selected + + else: + #PY23 NO SETS# if nV == 3 and v not in NV_ext : make_sel_face(V) + if nV == 3 and v not in NV_ext.iterkeys() : make_sel_face(V) + + + else : + + # We need to know which are the edges around the corner. + # First, we look for the quads surrounding the corner. + eed = [] + for old, new in NE.iteritems(): + if v in (old.v1,old.v2) : + if v.index == min(old.v1.index,old.v2.index) : ind = 0 + else : ind = 1 + + if len(new) == 1: eed.append([v,new[0][ind]]) + else : eed.append([new[0][ind],new[1][ind]]) + + # We will add the edges coming from faces where only one vertice is selected. + # They are stored in NC. + if v in NC: eed = eed+NC[v] + + # Now we have to sort these vertices + hc = {} + for (a,b) in eed : + hc.setdefault(a,[]).append(b) + hc.setdefault(b,[]).append(a) + + for x0,edges in hc.iteritems(): + if len(edges) == 1 : break + + b = [x0] # b will contain the sorted list of vertices + + for i in xrange(len(hc)-1): + for x in hc[x0] : + if x not in b : break + b.append(x) + x0 = x + + b.append(b[0]) + + # Now we can create the faces + if len(b) == 5: make_sel_face(b[:4]) + + else: + New_V = Vector(0.0, 0.0,0.0) + New_d = [0.0, 0.0,0.0] + + for x in hc.iterkeys(): New_V += x.co + for dir in NV[v] : + for i in xrange(3): New_d[i] += dir[i] + + New_V *= 1./len(hc) + for i in xrange(3) : New_d[i] /= nV + + center = make_sel_vert(New_V.x,New_V.y,New_V.z) + add_to_NV(v,tuple(New_d),center) + + for k in xrange(len(b)-1): make_sel_face([center, b[k], b[k+1]]) + + if 2 < nV and v in NC : + for edge in NC[v] : me.findEdge(*edge).flag |= E_selected + +def clear_old(): + """ Erase old faces and vertices """ + + for f in old_faces: me.removeFace(f) + + for v in NV.iterkeys(): + #PY23 NO SETS# if v not in NV_ext : me.verts.remove(v) + if v not in NV_ext.iterkeys() : me.verts.remove(v) + + for e in me.edges: + if e.flag & E_selected : + e.v1.sel = 1 + e.v2.sel = 1 + + +###################################################################### +# Interface + +global dist + +dist = Create(0.2) +left = Create(0.0) +right = Create(1.0) +num = Create(2) + +# Events +EVENT_NOEVENT = 1 +EVENT_BEVEL = 2 +EVENT_UPDATE = 3 +EVENT_RECURS = 4 +EVENT_EXIT = 5 + +def draw(): + global dist, left, right, num, old_dist + global EVENT_NOEVENT, EVENT_BEVEL, EVENT_UPDATE, EVENT_RECURS, EVENT_EXIT + + glClear(GL_COLOR_BUFFER_BIT) + Button("Bevel",EVENT_BEVEL,10,100,280,25) + + BeginAlign() + left=Number('', EVENT_NOEVENT,10,70,45, 20,left.val,0,right.val,'Set the minimum of the slider') + dist=Slider("Thickness ",EVENT_UPDATE,60,70,180,20,dist.val,left.val,right.val,0, \ + "Thickness of the bevel, can be changed even after bevelling") + right = Number("",EVENT_NOEVENT,245,70,45,20,right.val,left.val,200,"Set the maximum of the slider") + + EndAlign() + glRasterPos2d(8,40) + Text('To finish, you can use recursive bevel to smooth it') + + + if old_dist != None: + num=Number('', EVENT_NOEVENT,10,10,40, 16,num.val,1,100,'Recursion level') + Button("Recursive",EVENT_RECURS,55,10,100,16) + + Button("Exit",EVENT_EXIT,210,10,80,20) + +def event(evt, val): + if ((evt == QKEY or evt == ESCKEY) and not val): Exit() + +def bevent(evt): + if evt == EVENT_EXIT : Exit() + elif evt == EVENT_BEVEL : bevel() + elif evt == EVENT_UPDATE : + try: bevel_update() + except NameError : pass + elif evt == EVENT_RECURS : recursive() + +Register(draw, event, bevent) + +###################################################################### +def bevel(): + """ The main function, which creates the bevel """ + global me,NV,NV_ext,NE,NC, old_faces,old_dist + + ob = act_mesh_ob() + if not ob: return + + Window.WaitCursor(1) # Change the Cursor + t= Blender.sys.time() + is_editmode = Window.EditMode() + if is_editmode: Window.EditMode(0) + + me = ob.data + + NV = {} + #PY23 NO SETS# NV_ext = set() + NV_ext= {} + NE = {} + NC = {} + old_faces = [] + + make_faces() + make_edges() + make_corners() + clear_old() + + old_dist = dist.val + print '\tbevel in %.6f sec' % (Blender.sys.time()-t) + me.update(1) + if is_editmode: Window.EditMode(1) + Window.WaitCursor(0) + Blender.Redraw() + +def bevel_update(): + """ Use NV to update the bevel """ + global dist, old_dist + + if old_dist == None: + # PupMenu('Error%t|Must bevel first.') + return + + is_editmode = Window.EditMode() + if is_editmode: Window.EditMode(0) + + fac = dist.val - old_dist + old_dist = dist.val + + for old_v in NV.iterkeys(): + for dir in NV[old_v].iterkeys(): + for i in xrange(3): + NV[old_v][dir].co[i] += fac*dir[i] + + me.update(1) + if is_editmode: Window.EditMode(1) + Blender.Redraw() + +def recursive(): + """ Make a recursive bevel... still experimental """ + global dist + from math import pi, sin + + if num.val > 1: + a = pi/4 + ang = [] + for k in xrange(num.val): + ang.append(a) + a = (pi+2*a)/4 + + l = [2*(1-sin(x))/sin(2*x) for x in ang] + R = dist.val/sum(l) + l = [x*R for x in l] + + dist.val = l[0] + bevel_update() + + for x in l[1:]: + dist.val = x + bevel() + diff --git a/release/scripts/blenderLipSynchro.py b/release/scripts/blenderLipSynchro.py new file mode 100644 index 00000000000..ef765086e25 --- /dev/null +++ b/release/scripts/blenderLipSynchro.py @@ -0,0 +1,729 @@ +#!BPY + +""" +Name: 'BlenderLipSynchro' +Blender: 242 +Group: 'Animation' +Tooltip: 'Import phonemes from Papagayo or JLipSync for lip synchronization' +""" + +__author__ = "Dienben: Benoit Foucque dienben_mail@yahoo.fr" +__url__ = ["blenderLipSynchro Blog, http://blenderlipsynchro.blogspot.com/", +"Papagayo (Python), http://www.lostmarble.com/papagayo/index.shtml", +"JLipSync (Java), http://jlipsync.sourceforge.net/"] +__version__ = "2.0" +__bpydoc__ = """\ +Description: + +This script imports Voice Export made by Papagayo or JLipSync and maps the export with your shapes. + +Usage: + +Import a Papagayo or JLipSync voice export file and link it with your shapes. + +Note:
+- Naturally, you need files exported from one of the supported lip synching +programs. Check their sites to learn more and download them. + +""" + +# -------------------------------------------------------------------------- +# BlenderLipSynchro +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + + +#il y a 3 etapes +#la deuxieme on charge le dictionnaire de correspondance +#la troisieme on fait le choix des correpondance +#la quatrieme on construit les cles a partir du fichiers frame + +#there are 3 stages +#the second one load the mapping dictionnary +#the tird make the mapping +#the fourth make the key in the IPO Curve + +#voici mes differents imports +#the imports +import os +import Blender + +from Blender import Ipo +from Blender.Draw import * +from Blender.BGL import * +from Blender.sys import basename + + + +#ici commencent mes fonctions +#here begin my functions +#cette fonction trace l'interface graphique +#this functions draw the User interface +def trace(): + #voici mes variables pouvant etre modifie + #my variables + global nbr_phoneme, mon_fichier_dico + global let01, let02, let03, let04,let05, let06, let07, let08, let09, let10 + global let11, let12, let13, let14,let15, let16, let17, let18, let19, let20 + global let21, let22, let23, let24 + + global let01selectkey,let02selectkey,let03selectkey,let04selectkey,let05selectkey + global let06selectkey,let07selectkey,let08selectkey,let09selectkey,let10selectkey,let11selectkey + global let12selectkey,let13selectkey,let14selectkey,let15selectkey,let16selectkey,let17selectkey + global let18selectkey,let19selectkey,let20selectkey,let21selectkey,let22selectkey,let23selectkey + global let24selectkey + + glClearColor(0.4,0.5,0.6 ,0.0) + glClear(GL_COLOR_BUFFER_BIT) + + glColor3d(1,1,1) + glRasterPos2i(87, 375) + Text("Blendersynchro V 2.0") + glColor3d(1,1,1) + glRasterPos2i(84, 360) + Text("Programming: Dienben") + + glColor3d(0,0,0) + glRasterPos2i(13, 342) + Text("Lip Synchronization Tool") + glColor3d(0,0,0) + glRasterPos2i(13, 326) + Text("Thanks to Chris Clawson and Liubomir Kovatchev") + + glColor3d(1,1,1) + glRasterPos2i(5, 320) + Text("_______________________________________________________") + glColor3d(0,0,0) + glRasterPos2i(6, 318) + Text("_______________________________________________________") + + + if (etape==1): + #cette etape permet de choisi la correspondance entre les phonemes et les cles + #this stage offer the possibility to choose the mapping between phonems and shapes + + glColor3d(1,1,1) + glRasterPos2i(140, 300) + Text("Objet: "+Blender.Object.GetSelected()[0].getName() ) + + glColor3d(1,1,1) + glRasterPos2i(5, 215) + Text("Assign phonems to shapes:") + + #on mesure la taille de la liste de phonemes + #this is the lenght of the phonem list + nbr_phoneme=len(liste_phoneme) + + #on dessine les listes de choix + #we draw the choice list + + # + if (nbr_phoneme > 0): + let01 = String(" ", 4, 5, 185, 30, 16, liste_phoneme[0], 3) + glColor3d(0,0,0) + glRasterPos2i(40, 188) + Text("=") + let01selectkey = Menu(key_menu, 50, 50, 185, 70, 16, let01selectkey.val) + + # + if (nbr_phoneme > 1): + let02 = String(" ", 4, 150, 185, 30, 16, liste_phoneme[1], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 188) + Text("=") + let02selectkey = Menu(key_menu, 51, 195, 185, 70, 16, let02selectkey.val) + + # + if (nbr_phoneme > 2): + let03 = String(" ", 4, 5, 165, 30, 16, liste_phoneme[2], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 168) + Text("=") + let03selectkey = Menu(key_menu, 52, 50, 165, 70, 16, let03selectkey.val) + + # + if (nbr_phoneme > 3): + let04 = String(" ", 4, 150, 165, 30, 16, liste_phoneme[3], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 168) + Text("=") + let04selectkey = Menu(key_menu, 53, 195, 165, 70, 16, let04selectkey.val) + + # + if (nbr_phoneme > 4): + let05 = String(" ", 4, 5, 145, 30, 16, liste_phoneme[4], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 148) + Text("=") + let05selectkey = Menu(key_menu, 54, 50, 145, 70, 16, let05selectkey.val) + + # + if (nbr_phoneme > 5): + let06 = String(" ", 4, 150, 145, 30, 16, liste_phoneme[5], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 148) + Text("=") + let06selectkey = Menu(key_menu, 55, 195, 145, 70, 16, let06selectkey.val) + + # + if (nbr_phoneme > 6): + let07 = String(" ", 4, 5, 125, 30, 16, liste_phoneme[6], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 128) + Text("=") + let07selectkey = Menu(key_menu, 56, 50, 125, 70, 16, let07selectkey.val) + + # + if (nbr_phoneme > 7): + let08 = String(" ", 4, 150, 125, 30, 16, liste_phoneme[7], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 128) + Text("=") + let08selectkey = Menu(key_menu, 57, 195, 125, 70, 16,let08selectkey.val) + + # + if (nbr_phoneme > 8): + let09 = String(" ", 4, 5, 105, 30, 16, liste_phoneme[8], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 108) + Text("=") + let09selectkey = Menu(key_menu, 58, 50, 105, 70, 16,let09selectkey.val) + + # + if (nbr_phoneme > 9): + let10 = String(" ", 4, 150, 105, 30, 16, liste_phoneme[9], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 108) + Text("=") + let10selectkey = Menu(key_menu, 59, 195, 105, 70, 16, let10selectkey.val) + + # + if (nbr_phoneme > 10): + let11 = String(" ", 4, 5, 85, 30, 16, liste_phoneme[10], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 88) + Text("=") + let11selectkey = Menu(key_menu, 60, 50, 85, 70, 16, let11selectkey.val) + + # + if (nbr_phoneme > 11): + let12 = String(" ", 4, 150, 85, 30, 16, liste_phoneme[11], 2) + glColor3d(0,0,0) + Text("=") + let12selectkey = Menu(key_menu, 61, 195, 85, 70, 16, let12selectkey.val) + + # + if (nbr_phoneme > 12): + let13 = String(" ", 4, 5, 65, 30, 16, liste_phoneme[12], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 68) + Text("=") + let13selectkey = Menu(key_menu, 62, 50, 65, 70, 16, let13selectkey.val) + + # + if (nbr_phoneme > 13): + let14 = String(" ", 4, 150, 65, 30, 16, liste_phoneme[13], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 68) + Text("=") + let14selectkey = Menu(key_menu, 63, 195, 65, 70, 16, let14selectkey.val) + + # + if (nbr_phoneme > 14): + let15 = String(" ", 4, 5, 45, 30, 16, liste_phoneme[14], 2) + glColor3d(0,0,0) + glRasterPos2i(40, 48) + Text("=") + let15selectkey = Menu(key_menu, 64, 50, 45, 70, 16, let15selectkey.val) + + # + if (nbr_phoneme > 15): + let16 = String(" ", 4, 150, 45, 30, 16, liste_phoneme[15], 2) + glColor3d(0,0,0) + glRasterPos2i(185, 48) + Text("=") + let16selectkey = Menu(key_menu, 65, 195, 45, 70, 16, let16selectkey.val) + + # + if (nbr_phoneme > 16): + let17 = String(" ", 4, 295, 185, 30, 16, liste_phoneme[16], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 188) + Text("=") + let17selectkey = Menu(key_menu, 66, 340, 185, 70, 16, let17selectkey.val) + + # + if (nbr_phoneme > 17): + let18 = String(" ", 4, 440, 185, 70, 16, liste_phoneme[17], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 188) + Text("=") + let18selectkey = Menu(key_menu, 67, 525, 185, 70, 16, let18selectkey.val) + + # + if (nbr_phoneme > 18): + let19 = String(" ", 4, 295, 165, 30, 16, liste_phoneme[18], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 168) + Text("=") + let19selectkey = Menu(key_menu, 68, 340, 165, 70, 16, let19selectkey.val) + + # + if (nbr_phoneme > 19): + let20 = String(" ", 4, 440, 165, 70, 16, liste_phoneme[19], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 168) + Text("=") + let20selectkey = Menu(key_menu, 69, 525, 165, 70, 16, let20selectkey.val) + + # + if (nbr_phoneme > 20): + let21 = String(" ", 4, 295, 145, 30, 16, liste_phoneme[20], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 148) + Text("=") + let21selectkey = Menu(key_menu, 70, 340, 145, 70, 16, let21selectkey.val) + + # + if (nbr_phoneme > 21): + let22 = String(" ", 4, 440, 145, 70, 16, liste_phoneme[21], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 148) + Text("=") + let22selectkey = Menu(key_menu, 71, 525, 145, 70, 16, let22selectkey.val) + + # + if (nbr_phoneme > 22): + let23 = String(" ", 4, 295, 125, 30, 16, liste_phoneme[22], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 128) + Text("=") + let23selectkey = Menu(key_menu, 72, 340, 125, 70, 16,let23selectkey.val) + + # + if (nbr_phoneme > 23): + let24 = String(" ", 4, 440, 125, 70, 16, liste_phoneme[23], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 128) + Text("=") + let24selectkey = Menu(key_menu, 73, 525, 125, 70, 16, let24selectkey.val) + + # + if (nbr_phoneme > 24): + let25 = String(" ", 4, 295, 105, 30, 16, liste_phoneme[24], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 108) + Text("=") + let25selectkey = Menu(key_menu, 74, 340, 105, 70, 16, let25selectkey.val) + + # + if (nbr_phoneme > 25): + let26 = String(" ", 4, 440, 105, 70, 16, liste_phoneme[25], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 108) + Text("=") + let26selectkey = Menu(key_menu, 75, 525, 105, 70, 16,let26selectkey.val) + + # + if (nbr_phoneme > 26): + let27 = String(" ", 4, 295, 85, 30, 16, liste_phoneme[26], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 88) + Text("=") + let27selectkey = Menu(key_menu, 76, 340, 85, 70, 16, let27selectkey.val) + + # + if (nbr_phoneme > 27): + let28 = String(" ", 4, 440, 85, 70, 16, liste_phoneme[27], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 88) + Text("=") + let28selectkey = Menu(key_menu, 77, 525, 85, 70, 16,let28selectkey.val) + + # + if (nbr_phoneme > 28): + let29 = String(" ", 4, 295, 65, 30, 16, liste_phoneme[28], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 68) + Text("=") + let29selectkey = Menu(key_menu, 78, 340, 65, 70, 16, let29selectkey.val) + + # + if (nbr_phoneme > 29): + let30 = String(" ", 4, 440, 65, 70, 16, liste_phoneme[29], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 68) + Text("=") + let30selectkey = Menu(key_menu, 79, 525, 65, 70, 16, let30selectkey.val) + + # + if (nbr_phoneme > 30): + let31 = String(" ", 4, 295, 45, 30, 16, liste_phoneme[30], 2) + glColor3d(0,0,0) + glRasterPos2i(330, 48) + Text("=") + let31selectkey = Menu(key_menu, 80, 340, 45, 70, 16, let31selectkey.val) + + # + if (nbr_phoneme > 31): + let32 = String(" ", 4, 440, 45, 70, 16, liste_phoneme[31], 8) + glColor3d(0,0,0) + glRasterPos2i(515, 48) + Text("=") + let32selectkey = Menu(key_menu, 81, 525, 45, 70, 16, let32selectkey.val) + + Button("Go", 3, 155, 5, 145, 22) + + if (etape==2): + glColor3d(1,1,1) + glRasterPos2i(125, 200) + Text("Operation Completed") + + if (etape==0): + glColor3d(1,1,1) + glRasterPos2i(125, 200) + Text("Please select a Mesh'Object and Create all the IPO Curves for your Shapes") + + if (etape==3): + #this stage permits to load a custom dictionnary + load_file_text = "Load File" + if mon_fichier_dico: + Button("Import Loaded File", 2, 5, 5, 145, 22) + glColor3d(1,1,1) + glRasterPos2i(6, 50) + Text("loaded file: %s" % basename(mon_fichier_dico)) + load_file_text = "Choose Another File" + Button(load_file_text, 8, 125, 180, 145, 22) + + glRasterPos2i(6, 40) + Text("_______________________________________________________") + glColor3d(0,0,0) + glRasterPos2i(6, 38) + Text("_______________________________________________________") + + Button("Exit", 1, 305, 5, 80, 22) + + + +#cette fonction sur evenement quite en cas d'ESC +#this functions catch the ESC event and quit +def event(evt,val): + if (evt == ESCKEY and not val): Exit() + +#cette fonction gere les evenements +#the event functions +def bevent(evt): + global etape,soft_type,liste_phoneme,dico_phoneme_export + + if (evt == 1): + Exit() + + elif (evt == 2): + #c'est l'import du dictionnaire + #we create and import the dictionnary + lecture_chaine(mon_fichier_dico,dico_phoneme_export) + construction_dictionnaire_phoneme() + #we change the stage + etape=1 + + elif (evt == 3): + #c'est l'import + #we import + lecture_chaine(mon_fichier_export,dico_phoneme_export) + construction_dico_correspondance() + construction_lipsynchro() + #on change d'etape + #we change the stage + etape=2 + + elif (evt == 8): + #we choose the file + Blender.Window.FileSelector(selectionner_fichier,"Select File") + + Blender.Redraw() + +#cette fonction recupere le nom et le chemin du fichier dictionnaire +#we catch the name and the path of the dictionnary +def selectionner_fichier(filename): + global mon_fichier_dico,mon_fichier_export + mon_fichier_dico=filename + mon_fichier_export=filename + +#fonction de lecture de la liste frame phoneme +#we read the frame and phonems +def lecture_chaine(fichier,liste): + mon_fichier=open(fichier) + #je lis la premiere ligne qui contiens la version de moho + #first, we read the moho version + mon_fichier.readline() + + #je lis jusqu'a la fin + #then we read until the end of the file + while 1: + ma_ligne=mon_fichier.readline() + if ma_ligne=='': + break + decoup=ma_ligne.split() + liste[decoup[0]]=decoup[1] + print liste + + + + +#fonction qui construit la liste dictionnaire simple +#we make the dictionnary +def construction_dictionnaire_phoneme(): + global liste_phoneme + index_liste=0 + #je transforme mon dictionnaire en list de tulpes + #we transform the list in tulpes + ma_liste=dico_phoneme_export.items() + #je parcours ma liste a la recherche d'elements non existant + #we read the list to find non existing elements + print dico_phoneme + for index in range(len(ma_liste)): + if ma_liste[index][1] not in liste_phoneme: + liste_phoneme[index_liste:index_liste]=[ma_liste[index][1]] + index_liste=index_liste+1 + print liste_phoneme + + +#cette fonction recupere les courbes cible +#this functon catch the IPO curve +def recuperation_courbe(): + global key_menu,dico_key + + #on recupere le nom des shapes + #we catch the shapes + key=Blender.Object.GetSelected()[0].getData().getKey().getBlocks() + for n in range(len(key)): + #on vire la première cle (en effet basic n'est pas une cle en tant que telle) + #we threw away the basic shapes + if (n>0): + key_menu=key_menu+key[n].name + " %x" + str(n-1) + "|" + dico_key[str(n-1)]=Blender.Object.GetSelected()[0].getData().getKey().getIpo().getCurves()[n-1] + + + print "dico_key" + print dico_key + print 'end dico_key' + +#cette fonction construit un dictionnaire de correspondance entre les phonemes prononces et les cles a utiliser +#we make the dictionnary for the mapping between shapes and phonems +def construction_dico_correspondance(): + global dico_correspondance + #je parcours les phonemes + #we read the phonems + if (nbr_phoneme>0): + dico_correspondance[liste_phoneme[0]]=dico_key[str(let01selectkey.val)] + if (nbr_phoneme>1): + dico_correspondance[liste_phoneme[1]]=dico_key[str(let02selectkey.val)] + if (nbr_phoneme>2): + dico_correspondance[liste_phoneme[2]]=dico_key[str(let03selectkey.val)] + if (nbr_phoneme>3): + dico_correspondance[liste_phoneme[3]]=dico_key[str(let04selectkey.val)] + if (nbr_phoneme>4): + dico_correspondance[liste_phoneme[4]]=dico_key[str(let05selectkey.val)] + if (nbr_phoneme>5): + dico_correspondance[liste_phoneme[5]]=dico_key[str(let06selectkey.val)] + if (nbr_phoneme>6): + dico_correspondance[liste_phoneme[6]]=dico_key[str(let07selectkey.val)] + if (nbr_phoneme>7): + dico_correspondance[liste_phoneme[7]]=dico_key[str(let08selectkey.val)] + if (nbr_phoneme>8): + dico_correspondance[liste_phoneme[8]]=dico_key[str(let09selectkey.val)] + if (nbr_phoneme>9): + dico_correspondance[liste_phoneme[9]]=dico_key[str(let10selectkey.val)] + if (nbr_phoneme>10): + dico_correspondance[liste_phoneme[10]]=dico_key[str(let11selectkey.val)] + if (nbr_phoneme>11): + dico_correspondance[liste_phoneme[11]]=dico_key[str(let12selectkey.val)] + if (nbr_phoneme>12): + dico_correspondance[liste_phoneme[12]]=dico_key[str(let13selectkey.val)] + if (nbr_phoneme>13): + dico_correspondance[liste_phoneme[13]]=dico_key[str(let14selectkey.val)] + if (nbr_phoneme>14): + dico_correspondance[liste_phoneme[14]]=dico_key[str(let15selectkey.val)] + if (nbr_phoneme>15): + dico_correspondance[liste_phoneme[15]]=dico_key[str(let16selectkey.val)] + if (nbr_phoneme>16): + dico_correspondance[liste_phoneme[16]]=dico_key[str(let17selectkey.val)] + if (nbr_phoneme>17): + dico_correspondance[liste_phoneme[17]]=dico_key[str(let18selectkey.val)] + if (nbr_phoneme>18): + dico_correspondance[liste_phoneme[18]]=dico_key[str(let19selectkey.val)] + if (nbr_phoneme>19): + dico_correspondance[liste_phoneme[19]]=dico_key[str(let20selectkey.val)] + if (nbr_phoneme>20): + dico_correspondance[liste_phoneme[20]]=dico_key[str(let21selectkey.val)] + if (nbr_phoneme>21): + dico_correspondance[liste_phoneme[21]]=dico_key[str(let22selectkey.val)] + if (nbr_phoneme>22): + dico_correspondance[liste_phoneme[22]]=dico_key[str(let23selectkey.val)] + if (nbr_phoneme>23): + dico_correspondance[liste_phoneme[23]]=dico_key[str(let24selectkey.val)] + if (nbr_phoneme>24): + dico_correspondance[liste_phoneme[24]]=dico_key[str(let25selectkey.val)] + if (nbr_phoneme>25): + dico_correspondance[liste_phoneme[25]]=dico_key[str(let26selectkey.val)] + if (nbr_phoneme>26): + dico_correspondance[liste_phoneme[26]]=dico_key[str(let27selectkey.val)] + if (nbr_phoneme>27): + dico_correspondance[liste_phoneme[27]]=dico_key[str(let28selectkey.val)] + if (nbr_phoneme>28): + dico_correspondance[liste_phoneme[28]]=dico_key[str(let29selectkey.val)] + if (nbr_phoneme>29): + dico_correspondance[liste_phoneme[29]]=dico_key[str(let30selectkey.val)] + if (nbr_phoneme>30): + dico_correspondance[liste_phoneme[30]]=dico_key[str(let31selectkey.val)] + if (nbr_phoneme>31): + dico_correspondance[liste_phoneme[31]]=dico_key[str(let32selectkey.val)] + + print dico_correspondance + + +#cette fonction ajoute un points a la cle donnee a la frame donnee +#we add a point to the IPO curve Target +def ajoute_point(cle,frame,valeur): + cle.setInterpolation('Linear') + cle.append((frame,valeur)) + cle.Recalc() + +#cette fonction parcours le dictionnaire des frame à ajouter et construit les points +#we add all the point to the IPO Curve +def construction_lipsynchro(): + print "je construit" + doublet_old="" + #construction de la liste des frame + cpt=0 + liste_frame=[] + for frame in dico_phoneme_export: + liste_frame.append(int(frame)) + cpt=cpt+1 + liste_frame.sort() + print "listeframe" + print liste_frame + print "fini" + + for doublet in liste_frame: + ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],doublet,1) + if (doublet_old==""): + ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0) + if (doublet_old!=''): + if (dico_correspondance[dico_phoneme_export[str(doublet)]]!=dico_correspondance[dico_phoneme_export[doublet_old]]): + print "doublet:"+str(doublet) + print "doublet old:"+doublet_old + ajoute_point(dico_correspondance[dico_phoneme_export[doublet_old]],(int(doublet_old)+2),0) + ajoute_point(dico_correspondance[dico_phoneme_export[str(doublet)]],(doublet-2),0) + doublet_old=str(doublet) + + +#end of my functions we begin the execution +#je commence l execution----------------------------------------------------------------------------------------------- +#voici mes variables + +#declaration et instanciation +#decleration and instanciation + + +#voici mon objet de travail +objet_travail=Create(0) + +#my soft type +soft_type=1 + +#voici la liste des phoneme effectivement utilise +#the phonems'list +#liste_phoneme_papagayo=['AI','E','O','U','FV','L','WQ','MBP','etc','rest'] +#liste_phoneme_jlipsinch=['A','B','C','Closed','D','E','F','G','I','K','L','M','N','O','P','Q','R','S','SH','T','TH','U','V','W'] + +liste_phoneme=[] +#voici mon dictionnaire des frames o +dico_phoneme_export = Create(0) +dico_phoneme_export={} +dico_phoneme={} + + +#voici mes cle +key_menu="" +dico_key={} + +#voici mes ipo +dico_bloc={} +iponame = Create(0) + +#voici mon dictionnaire de correspondance +dico_correspondance={} + +try: + #on verifie est bien une mesh et qu'il a des courbes + if ((Blender.Object.GetSelected()[0].getType()=='Mesh')): + #on verifie que l'objet a bien toute ses Courbes + if (len(Blender.Object.GetSelected()[0].getData().getKey().getBlocks())-1==Blender.Object.GetSelected()[0].getData().getKey().getIpo().getNcurves()): + etape=3 + #on lance la creation du dictionnaire + recuperation_courbe() + else: + print "not the good number of IPO Curve" + etape = 0 + else: + print "error: bad object Type:" + print Blender.Object.GetSelected()[0].getType() + etape = 0 +except: + print 'error: exception' + etape = 0 + + +#voici le fichier dictionnaire +mon_fichier_dico="" + +#voici le fichier export pamela +mon_fichier_export="" + + +let01selectkey = Create(0) +let02selectkey = Create(0) +let03selectkey = Create(0) +let04selectkey = Create(0) +let05selectkey = Create(0) +let06selectkey = Create(0) +let07selectkey = Create(0) +let08selectkey = Create(0) +let09selectkey = Create(0) +let10selectkey = Create(0) +let11selectkey = Create(0) +let12selectkey = Create(0) +let13selectkey = Create(0) +let14selectkey = Create(0) +let15selectkey = Create(0) +let16selectkey = Create(0) +let17selectkey = Create(0) +let18selectkey = Create(0) +let19selectkey = Create(0) +let20selectkey = Create(0) +let21selectkey = Create(0) +let22selectkey = Create(0) +let23selectkey = Create(0) +let24selectkey = Create(0) + + +Register (trace,event,bevent) diff --git a/release/scripts/bpydata/KUlang.txt b/release/scripts/bpydata/KUlang.txt new file mode 100644 index 00000000000..38605d69c9f --- /dev/null +++ b/release/scripts/bpydata/KUlang.txt @@ -0,0 +1,121 @@ +Version 3.233-2004 +****************** +Espanol +Sale del programa +Utilidades de...%t|Alinea objetos%x1|Creacion%x2|Edita mallas%x3|Edita objetos%x4 +11 +Mov +Esc +Encaja +Abarca +Separa +Alinea +Rota +Incr. +Crea nuevos objetos +Es+ +Es* +Separar entre:%t|Origenes%x1|Centros geometricos%x2|Minimos%x3|Maximos%x4|Baricentro%x5|Objetos%x6 +Crear%t|Arco (3 ptos.)%x1|Arco (interactivo)%x2|Circunferencia (3 ptos.)%x3 +12 +Puntos +Centro +Orden +Objeto +AngIni: +AngFin: +Angulo: +Radio: +Puntos: +Centro +Nombre: +Puntos +Modifica vertices%t|Subdivide%x1|Envia a un plano%x2|Aplica LocRotSize%x3 +Partes +Proyectar en el plano:%t|Coordenado global...%x1|Coordenado local...%x2 +Actuar sobre el plano%t|Yz%x1|Zx%x2|Xy%x3 +En la dirección%t|X%x1|Y%x2|Z%x3|Ortogonal al plano%x4 +Captura +Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacion%x3|Copia media LocRotSiz%x4|Ver buffer en consola%x5 +Transformar LocRotSize%t|Hacia el obj. activo%x1|Aleatoriamente%x2 +Poner a distancia fija%x1|Sumar (desp. absoluto)%x2|Multiplicar (desp. relativo)%x3 +******************** +English +Exit program +Utils about:%t|Align Objects%x1|Create%x2|Edit Meshes%x3|Edit Objects%x4 +11 +Mov +Sca +Fit +Embrace +Separate +Align +Rota +Incr. +Create new objects +Sc+ +Sc* +Separate between:%t|Origins%x1|Geometric centers%x2|Minimum%x3|Maximum%x4|Baricenter%x5|Objects%x6 +Create what%t|Arc (3 pts.)%x1|Arc (interactive)%x2|Circunference (3 pts.)%x3 +12 +Points +Centre +Sort +Object +AngIni: +AngEnd: +Angle: +Radius: +Points: +Centre +ObjName: +Points +Modify vertices%t|Subdivide edges%x1|Send to a plane%x2|Set LocRotSize%x3 +Parts +Project onto the plane:%t|Global coordinated...%x1|Local coordinated...%x2 +Act on plane%t|Yz%x1|Zx%x2|Xy%x3 +In direction%t|X%x1|Y%x2|Z%x3|Ortogonal to plane%x4 +Get +Buffer%t|Copy diference vector%x1|Copy distance%x2|Copy rot diference%x3|Copy LocRotSiz average%x4|Show Buffer in Console%x5 +Transform LocRotSize%t|Close to active%x1|Randomly%x2 +Set at fixed distance%x1|Add (absolute displ.)%x2|Multiply (relative displ.)%x3 +******************** +Catala +Surt del programa +Utilitats de...%t|Alinea objectes%x1|Creacio%x2|Edita malles%x3|Edita objetes%x4 +11 +Mov +Esc +Encaixa +Abarca +Separa +Alinea +Rotacio +Incr. +Crea objectes nous +Es+ +Es* +Separa entra:%t|Origens%x1|Centres geometrics%x2|Minims%x3|Maxims%x4|Baricentre%x5|Objectes%x6 +Crear%t|Arc (3 pts.)%x1|Arc (interactiu)%x2|Circumferencia (3 pts.)%x3 +12 +Punts +Centre +Ordre +Objecte +AngIni: +AngFi: +Angle: +Radi: +Punts: +Centre +Nom: +Punts +Modifica vertex%t|Subdivideix%x1|Envia a un pla%x2|Aplica LocRotSize%x3 +Parts +Projectar en el pla:%t|Coordenacio global...%x1|Coordenacio local...%x2 +Actuar sobre el pla%t|Yz%x1|Zx%x2|Xy%x3 +En la direccio%t|X%x1|Y%x2|Z%x3|Ortogonal al pla%x4 +Captura +Buffer%t|Copia vector diferencia%x1|Copia distancia%x2|Copia diferencia de rotacio%x3|Copia mitjana LocRotSiz%x4|Veure buffer en consola%x5 +Transformar LocRotSize%t|Cap al obj. actiu%x1|Aleatoriamente%x2 +Posar a distancia fixa%x1|Sumar (desp. absolut)%x2|Multiplicar (desp. relatiu)%x3 diff --git a/release/scripts/bpydata/config/readme.txt b/release/scripts/bpydata/config/readme.txt new file mode 100644 index 00000000000..4b5cb61b063 --- /dev/null +++ b/release/scripts/bpydata/config/readme.txt @@ -0,0 +1,6 @@ +This folder is for automatically saved scripts configuration data. + +To use this feature scripts just need to set a proper Blender.Registry key. + +To know more, check the API Reference doc (specifically the API_related and +Registry parts) and the documentation for the "Scripts Config Editor" script. diff --git a/release/scripts/bpydata/readme.txt b/release/scripts/bpydata/readme.txt new file mode 100644 index 00000000000..3e640e27c4b --- /dev/null +++ b/release/scripts/bpydata/readme.txt @@ -0,0 +1,9 @@ +This directory is the default place for scripts to put their data, +like internal files needed by the script and its saved configuration. + +Scripts can find the path to this dir using Blender.Get("datadir"). +Ex: + +import Blender +print Blender.Get("datadir") + diff --git a/release/scripts/bpymodules/BPyAddMesh.py b/release/scripts/bpymodules/BPyAddMesh.py new file mode 100644 index 00000000000..6ffb394320a --- /dev/null +++ b/release/scripts/bpymodules/BPyAddMesh.py @@ -0,0 +1,152 @@ +import Blender +from Blender.Window import EditMode, GetCursorPos, GetViewQuat +import bpy +import BPyMessages + +def add_mesh_simple(name, verts, edges, faces): + ''' + Adds a mesh from verts, edges and faces + + name - new object/mesh name + verts - list of 3d vectors + edges - list of int pairs + faces - list of int triplets/quads + ''' + + scn = bpy.data.scenes.active + if scn.lib: return + ob_act = scn.objects.active + + cursor = GetCursorPos() + try: quat = Blender.Mathutils.Quaternion(GetViewQuat()) + except: quat = None + + # Exist editmode for non mesh types + if ob_act and ob_act.type != 'Mesh' and EditMode(): + EditMode(0) + + # We are in mesh editmode + if EditMode(): + me = ob_act.getData(mesh=1) + + if me.multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + # Add to existing mesh + # must exit editmode to modify mesh + EditMode(0) + + me.sel = False + + vert_offset = len(me.verts) + edge_offset = len(me.edges) + face_offset = len(me.faces) + + # transform the verts + txmat = Blender.Mathutils.TranslationMatrix(Blender.Mathutils.Vector(cursor)) + if quat: + mat = quat.toMatrix() + mat.invert() + mat.resize4x4() + txmat = mat * txmat + + txmat = txmat * ob_act.matrixWorld.copy().invert() + + + me.verts.extend(verts) + # Transform the verts by the cursor and view rotation + me.transform(txmat, selected_only=True) + + if vert_offset: + me.edges.extend([[i+vert_offset for i in e] for e in edges]) + me.faces.extend([[i+vert_offset for i in f] for f in faces]) + else: + # Mesh with no data, unlikely + me.edges.extend(edges) + me.faces.extend(faces) + + EditMode(1) + + else: + + # Object mode add new + + me = bpy.data.meshes.new(name) + me.verts.extend(verts) + me.edges.extend(edges) + me.faces.extend(faces) + me.sel = True + + # Object creation and location + scn.objects.selected = [] + ob_act = scn.objects.new(me, name) + scn.objects.active = ob_act + + if quat: + mat = quat.toMatrix() + mat.invert() + mat.resize4x4() + ob_act.setMatrix(mat) + + ob_act.loc = cursor + + EditMode(1) + + +def write_mesh_script(filepath, me): + ''' + filepath - path to py file + me - mesh to write + ''' + + name = me.name + file = open(filepath, 'w') + + file.write('#!BPY\n') + file.write('"""\n') + file.write('Name: \'%s\'\n' % name) + file.write('Blender: 243\n') + file.write('Group: \'AddMesh\'\n') + file.write('"""\n\n') + file.write('import BPyAddMesh\n') + file.write('from Blender.Mathutils import Vector\n\n') + + file.write('verts = [\\\n') + for v in me.verts: + file.write('Vector(%f,%f,%f),\\\n' % tuple(v.co)) + file.write(']\n') + + file.write('edges = []\n') # TODO, write loose edges + + file.write('faces = [\\\n') + for f in me.faces: + file.write('%s,\\\n' % str(tuple([v.index for v in f]))) + file.write(']\n') + + file.write('BPyAddMesh.add_mesh_simple("%s", verts, edges, faces)\n' % name) + +# The script below can make a file from a mesh with teh above function... +''' +#!BPY +""" +Name: 'Mesh as AddMesh Script' +Blender: 242 +Group: 'Mesh' +Tip: '' +""" +import BPyAddMesh +reload(BPyAddMesh) + +import bpy + +def main(): + # Add error checking + scn = bpy.data.scenes.active + ob = scn.objects.active + me = ob.getData(mesh=1) + + BPyAddMesh.write_mesh_script('/test.py', me) + +main() +''' diff --git a/release/scripts/bpymodules/BPyArmature.py b/release/scripts/bpymodules/BPyArmature.py new file mode 100644 index 00000000000..d0b41dc35c5 --- /dev/null +++ b/release/scripts/bpymodules/BPyArmature.py @@ -0,0 +1,137 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import Blender +import bpy +def getBakedPoseData(ob_arm, start_frame, end_frame): + ''' + If you are currently getting IPO's this function can be used to + return a list of frame aligned bone dictionary's + + The data in these can be swaped in for the IPO loc and quat + + If you want to bake an action, this is not as hard and the ipo hack can be removed. + ''' + + # --------------------------------- Dummy Action! Only for this functon + backup_action = ob_arm.action + backup_frame = Blender.Get('curframe') + + DUMMY_ACTION_NAME = '~DONT_USE~' + # Get the dummy action if it has no users + try: + new_action = bpy.data.actions[DUMMY_ACTION_NAME] + if new_action.users: + new_action = None + except: + new_action = None + + if not new_action: + new_action = bpy.data.actions.new(DUMMY_ACTION_NAME) + new_action.fakeUser = False + # ---------------------------------- Done + + Matrix = Blender.Mathutils.Matrix + Quaternion = Blender.Mathutils.Quaternion + Vector = Blender.Mathutils.Vector + POSE_XFORM= [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT] + + # Each dict a frame + bake_data = [{} for i in xrange(1+end_frame-start_frame)] + + pose= ob_arm.getPose() + armature_data= ob_arm.getData(); + pose_bones= pose.bones + + # --------------------------------- Build a list of arma data for reuse + armature_bone_data = [] + bones_index = {} + for bone_name, rest_bone in armature_data.bones.items(): + pose_bone = pose_bones[bone_name] + rest_matrix = rest_bone.matrix['ARMATURESPACE'] + rest_matrix_inv = rest_matrix.copy().invert() + armature_bone_data.append( [len(bones_index), -1, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, None ]) + bones_index[bone_name] = len(bones_index) + + # Set the parent ID's + for bone_name, pose_bone in pose_bones.items(): + parent = pose_bone.parent + if parent: + bone_index= bones_index[bone_name] + parent_index= bones_index[parent.name] + armature_bone_data[ bone_index ][1]= parent_index + # ---------------------------------- Done + + + + # --------------------------------- Main loop to collect IPO data + frame_index = 0 + for current_frame in xrange(start_frame, end_frame+1): + ob_arm.action = backup_action + #pose.update() # not needed + Blender.Set('curframe', current_frame) + #Blender.Window.RedrawAll() + #frame_data = bake_data[frame_index] + ob_arm.action = new_action + ###for i,pose_bone in enumerate(pose_bones): + + for index, parent_index, bone_name, rest_bone, rest_matrix, rest_matrix_inv, pose_bone, ipo in armature_bone_data: + matrix= pose_bone.poseMatrix + + parent_bone= rest_bone.parent + + if parent_index != -1: + parent_pose_matrix = armature_bone_data[parent_index][6].poseMatrix + parent_bone_matrix_inv = armature_bone_data[parent_index][5] + matrix= matrix * parent_pose_matrix.copy().invert() + rest_matrix= rest_matrix * parent_bone_matrix_inv + + matrix=matrix * rest_matrix.copy().invert() + + pose_bone.quat= matrix.toQuat() + pose_bone.loc= matrix.translationPart() + pose_bone.insertKey(ob_arm, 1, POSE_XFORM) # always frame 1 + + # THIS IS A BAD HACK! IT SUCKS BIGTIME BUT THE RESULT ARE NICE + # - use a temp action and bake into that, always at the same frame + # so as not to make big IPO's, then collect the result from the IPOs + + # Now get the data from the IPOs + if not ipo: ipo = armature_bone_data[index][7] = new_action.getChannelIpo(bone_name) + + loc = Vector() + quat = Quaternion() + + for curve in ipo: + val = curve.evaluate(1) + curve_name= curve.name + if curve_name == 'LocX': loc[0] = val + elif curve_name == 'LocY': loc[1] = val + elif curve_name == 'LocZ': loc[2] = val + elif curve_name == 'QuatW': quat[3] = val + elif curve_name == 'QuatX': quat[0] = val + elif curve_name == 'QuatY': quat[1] = val + elif curve_name == 'QuatZ': quat[2] = val + + bake_data[frame_index][bone_name] = loc, quat + + + frame_index+=1 + + ob_arm.action = backup_action + Blender.Set('curframe', backup_frame) + return bake_data + + + diff --git a/release/scripts/bpymodules/BPyBlender.py b/release/scripts/bpymodules/BPyBlender.py new file mode 100644 index 00000000000..681dff63cf8 --- /dev/null +++ b/release/scripts/bpymodules/BPyBlender.py @@ -0,0 +1,36 @@ +# $Id$ +# +# -------------------------------------------------------------------------- +# BPyBlender.py version 0.3 Mar 20, 2005 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +# Basic set of modules Blender should have in all supported platforms. +# The second and third lines are the contents of the Python23.zip file +# included with Windows Blender binaries along with zlib.pyd. +# Other platforms are assumed to have Python installed. +basic_modules = [ +'Blender', +'chunk','colorsys','copy','copy_reg','gzip','os','random','repr','stat', +'string','StringIO','types','UserDict','webbrowser', 'zlib', 'math', +'BPyBlender', 'BPyRegistry' +] diff --git a/release/scripts/bpymodules/BPyCurve.py b/release/scripts/bpymodules/BPyCurve.py new file mode 100644 index 00000000000..3dd5f1784f2 --- /dev/null +++ b/release/scripts/bpymodules/BPyCurve.py @@ -0,0 +1,79 @@ +# -------------------------------------------------------------------------- +# BPyImage.py version 0.15 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * + +def curve2vecs(ob, WORLDSPACE= True): + ''' + Takes a curve object and retuirns a list of vec lists (polylines) + one list per curve + + This is usefull as a way to get a polyline per curve + so as not to have to deal with the spline types directly + ''' + if ob.type != 'Curve': + raise 'must be a curve object' + + me_dummy = Mesh.New() + me_dummy.getFromObject(ob) + + if WORLDSPACE: + me_dummy.transform(ob.matrixWorld) + + # build an edge dict + edges = {} # should be a set + + def sort_pair(i1, i2): + if i1 > i2: return i2, i1 + else: return i1, i2 + + for ed in me_dummy.edges: + edges[sort_pair(ed.v1.index,ed.v2.index)] = None # dummy value + + # now set the curves + first_time = True + + current_vecs = [] + vec_list = [current_vecs] + + for v in me_dummy.verts: + if first_time: + first_time = False + current_vecs.append(v.co.copy()) + last_index = v.index + else: + index = v.index + if edges.has_key(sort_pair(index, last_index)): + current_vecs.append( v.co.copy() ) + else: + current_vecs = [] + vec_list.append(current_vecs) + + last_index = index + + me_dummy.verts = None + + return vec_list + + diff --git a/release/scripts/bpymodules/BPyImage.py b/release/scripts/bpymodules/BPyImage.py new file mode 100644 index 00000000000..2c342ddec39 --- /dev/null +++ b/release/scripts/bpymodules/BPyImage.py @@ -0,0 +1,301 @@ +# -------------------------------------------------------------------------- +# BPyImage.py version 0.15 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +#===========================================================================# +# Comprehensive image loader, will search and find the image # +# Will return a blender image or a new image if the image is missing # +#===========================================================================# +import bpy +from Blender import sys +try: + import os +except: + os=None + +#==============================================# +# Return directory, where the file is # +#==============================================# +def stripFile(path): + lastSlash = max(path.rfind('\\'), path.rfind('/')) + if lastSlash != -1: + path = path[:lastSlash] + newpath= '%s%s' % (path, sys.sep) + else: + newpath= path + return newpath + +#==============================================# +# Strips the slashes from the back of a string # +#==============================================# +def stripPath(path): + return path.split('/')[-1].split('\\')[-1] + +#====================================================# +# Strips the prefix off the name before writing # +#====================================================# +def stripExt(name): # name is a string + index = name.rfind('.') + if index != -1: + return name[ : index ] + else: + return name + +def getExt(name): + index = name.rfind('.') + if index != -1: + return name[index+1:] + return name + +#====================================================# +# Adds a slash to the end of a path if its not there # +#====================================================# +def addSlash(path): + if not path: + return '' + + elif path.endswith('\\') or path.endswith('/'): + return path + return path + sys.sep + + +def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=True, VERBOSE=False): + ''' + imagePath: The image filename + If a path precedes it, this will be searched as well. + + filePath: is the directory where the image may be located - any file at teh end will be ignored. + + PLACE_HOLDER: if True a new place holder image will be created. + this is usefull so later you can relink the image to its original data. + + VERBOSE: If True debug info will be printed. + + RECURSIVE: If True, directories will be recursivly searched. + Be carefull with this if you have files in your root directory because it may take a long time. + ''' + + if VERBOSE: print 'img:', imagePath, 'file:', filePath + # When we have the file load it with this. try/except niceness. + def imageLoad(path): + #if path.endswith('\\') or path.endswith('/'): + # raise 'INVALID PATH' + try: + img = bpy.data.images.new(filename=path) + if VERBOSE: print '\t\tImage loaded "%s"' % path + return img + except: + if VERBOSE: + if sys.exists(path): print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path) + else: print '\t\tImage not found, making a place holder "%s"' % (path) + if PLACE_HOLDER: + img= bpy.data.images.new(stripPath(path),4,4) + img.filename= path + return img #blank image + else: + return None + + # Image formats blender can read + IMAGE_EXT = ['jpg', 'jpeg', 'png', 'tga', 'bmp', 'rgb', 'sgi', 'bw', 'iff', 'lbm', # Blender Internal + 'gif', 'psd', 'tif', 'tiff', 'pct', 'pict', 'pntg', 'qtif'] # Quacktime, worth a try. + + imageFileName = stripPath(imagePath) # image path only + imageFileName_lower = imageFileName.lower() # image path only + + if VERBOSE: print '\tSearchingExisting Images for "%s"' % imagePath + for i in bpy.data.images: + if stripPath(i.filename.lower()) == imageFileName_lower: + if VERBOSE: print '\t\tUsing existing image.' + return i + + + if VERBOSE: print '\tAttempting to load "%s"' % imagePath + if sys.exists(imagePath): + if VERBOSE: print '\t\tFile found where expected "%s".' % imagePath + return imageLoad(imagePath) + + + + imageFileName_noext = stripExt(imageFileName) # With no extension. + imageFileName_noext_lower = stripExt(imageFileName_lower) # With no extension. + imageFilePath = stripFile(imagePath) + + # Remove relative path from image path + if imageFilePath.startswith('./') or imageFilePath.startswith('.\\'): + imageFilePath = imageFilePath[2:] + + + # Attempt to load from obj path. + tmpPath = stripFile(filePath) + stripPath(imageFileName) + if sys.exists(tmpPath): + if VERBOSE: print '\t\tFile found in path (1)"%s".' % tmpPath + return imageLoad(tmpPath) + + + # os needed if we go any further. + if not os: + if VERBOSE: print '\t\tCreating a placeholder with a face path: "%s".' % imagePath + return imageLoad(imagePath) # Will jus treturn a placeholder. + + + # We have os. + # GATHER PATHS. + paths = {} # Store possible paths we may use, dict for no doubles. + tmpPath = addSlash(sys.expandpath('//')) # Blenders path + if sys.exists(tmpPath): + if VERBOSE: print '\t\tSearching in %s' % tmpPath + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + + tmpPath = imageFilePath + if sys.exists(tmpPath): + if VERBOSE: print '\t\tSearching in %s' % tmpPath + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + + tmpPath = stripFile(filePath) + if sys.exists(tmpPath): + if VERBOSE: print '\t\tSearching in %s' % tmpPath + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + + tmpPath = addSlash(bpy.config.textureDir) + if tmpPath and sys.exists(tmpPath): + if VERBOSE: print '\t\tSearching in %s' % tmpPath + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + + # Add path if relative image patrh was given. + tmp_paths= paths.keys() + for k in tmp_paths: + tmpPath = k + imageFilePath + if sys.exists(tmpPath): + paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading + paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. + paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext + else: + if VERBOSE: print '\tNo Path: "%s"' % tmpPath + # DONE + # + for path, files in paths.iteritems(): + if sys.exists(path + imageFileName): + if VERBOSE: print '\tFound image at path: "%s" file" "%s"' % (path, imageFileName) + return imageLoad(path + imageFileName) + + # If the files not there then well do a case insensitive seek. + filesOrigCase = files[0] + filesLower = files[1] + filesLowerNoExt = files[2] + + # We are going to try in index the file directly, if its not there just keep on + + index = None + try: + # Is it just a case mismatch? + index = filesLower.index(imageFileName_lower) + except: + try: + # Have the extensions changed? + index = filesLowerNoExt.index(imageFileName_noext_lower) + + ext = getExt( filesLower[index] ) # Get the extension of the file that matches all but ext. + + # Check that the ext is useable eg- not a 3ds file :) + if ext.lower() not in IMAGE_EXT: + index = None + + except: + index = None + + if index != None: + tmpPath = path + filesOrigCase[index] + img = imageLoad( tmpPath ) + if img != None: + if VERBOSE: print '\t\tImage Found "%s"' % tmpPath + return img + + if RECURSIVE: + # IMAGE NOT FOUND IN ANY OF THE DIRS!, DO A RECURSIVE SEARCH. + if VERBOSE: print '\t\tImage Not Found in any of the dirs, doing a recusrive search' + for path in paths.iterkeys(): + # Were not going to use files + if path == '/' or len(path) == 3 and path[1:] == ':\\': + continue + + # print path , 'ASS' + + #------------------ + # finds the file starting at the root. + # def findImage(findRoot, imagePath): + #W--------------- + + # ROOT, DIRS, FILES + pathWalk = os.walk(path) + pathList = [True] + + matchList = [] # Store a list of (match, size), choose the biggest. + while True: + try: + pathList = pathWalk.next() + except: + break + + for file in pathList[2]: + file_lower = file.lower() + # FOUND A MATCH + if (file_lower == imageFileName_lower) or\ + (stripExt(file_lower) == imageFileName_noext_lower and getExt(file_lower) in IMAGE_EXT): + name = pathList[0] + sys.sep + file + size = os.path.getsize(name) + if VERBOSE: print '\t\t\tfound:', name + matchList.append( (name, size) ) + + if matchList: + # Sort by file size + matchList.sort(lambda A, B: cmp(B[1], A[1]) ) + + if VERBOSE: print '\t\tFound "%s"' % matchList[0][0] + + # Loop through all we have found + img = None + for match in matchList: + img = imageLoad(match[0]) # 0 - first, 0 - pathname + if img != None: + break + return img + + # No go. + if VERBOSE: print '\t\tImage Not Found after looking everywhere! "%s"' % imagePath + return imageLoad(imagePath) # Will jus treturn a placeholder. diff --git a/release/scripts/bpymodules/BPyMathutils.py b/release/scripts/bpymodules/BPyMathutils.py new file mode 100644 index 00000000000..27736b4169e --- /dev/null +++ b/release/scripts/bpymodules/BPyMathutils.py @@ -0,0 +1,239 @@ +# $Id$ +# +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender.Mathutils import * + +# ------ Mersenne Twister - start + +# Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. +# Any feedback is very welcome. For any question, comments, +# see http://www.math.keio.ac.jp/matumoto/emt.html or email +# matumoto@math.keio.ac.jp + +# The link above is dead, this is the new one: +# http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/emt.html +# And here the license info, from Mr. Matsumoto's site: +# Until 2001/4/6, MT had been distributed under GNU Public License, +# but after 2001/4/6, we decided to let MT be used for any purpose, including +# commercial use. 2002-versions mt19937ar.c, mt19937ar-cok.c are considered +# to be usable freely. +# +# So from the year above (1997), this code is under GPL. + +# Period parameters +N = 624 +M = 397 +MATRIX_A = 0x9908b0dfL # constant vector a +UPPER_MASK = 0x80000000L # most significant w-r bits +LOWER_MASK = 0x7fffffffL # least significant r bits + +# Tempering parameters +TEMPERING_MASK_B = 0x9d2c5680L +TEMPERING_MASK_C = 0xefc60000L + +def TEMPERING_SHIFT_U(y): + return (y >> 11) + +def TEMPERING_SHIFT_S(y): + return (y << 7) + +def TEMPERING_SHIFT_T(y): + return (y << 15) + +def TEMPERING_SHIFT_L(y): + return (y >> 18) + +mt = [] # the array for the state vector +mti = N+1 # mti==N+1 means mt[N] is not initialized + +# initializing the array with a NONZERO seed +def sgenrand(seed): + # setting initial seeds to mt[N] using + # the generator Line 25 of Table 1 in + # [KNUTH 1981, The Art of Computer Programming + # Vol. 2 (2nd Ed.), pp102] + + global mt, mti + + mt = [] + + mt.append(seed & 0xffffffffL) + for i in xrange(1, N + 1): + mt.append((69069 * mt[i-1]) & 0xffffffffL) + + mti = i +# end sgenrand + + +def genrand(): + global mt, mti + + mag01 = [0x0L, MATRIX_A] + # mag01[x] = x * MATRIX_A for x=0,1 + y = 0 + + if mti >= N: # generate N words at one time + if mti == N+1: # if sgenrand() has not been called, + sgenrand(4357) # a default initial seed is used + + for kk in xrange((N-M) + 1): + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK) + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1] + + for kk in xrange(kk, N): + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK) + mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1] + + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK) + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1] + + mti = 0 + + y = mt[mti] + mti += 1 + y ^= TEMPERING_SHIFT_U(y) + y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B + y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C + y ^= TEMPERING_SHIFT_L(y) + + return ( float(y) / 0xffffffffL ) # reals + +#------ Mersenne Twister -- end + + + + +""" 2d convexhull +Based from Dinu C. Gherman's work, +modified for Blender/Mathutils by Campell Barton +""" +###################################################################### +# Public interface +###################################################################### +from Blender.Mathutils import DotVecs +def convexHull(point_list_2d): + """Calculate the convex hull of a set of vectors + The vectors can be 3 or 4d but only the Xand Y are used. + returns a list of convex hull indicies to the given point list + """ + + ###################################################################### + # Helpers + ###################################################################### + + def _myDet(p, q, r): + """Calc. determinant of a special matrix with three 2D points. + + The sign, "-" or "+", determines the side, right or left, + respectivly, on which the point r lies, when measured against + a directed vector from p to q. + """ + return (q.x*r.y + p.x*q.y + r.x*p.y) - (q.x*p.y + r.x*q.y + p.x*r.y) + + def _isRightTurn((p, q, r)): + "Do the vectors pq:qr form a right turn, or not?" + #assert p[0] != q[0] and q[0] != r[0] and p[0] != r[0] + if _myDet(p[0], q[0], r[0]) < 0: + return 1 + else: + return 0 + + # Get a local list copy of the points and sort them lexically. + points = [(p, i) for i, p in enumerate(point_list_2d)] + + try: points.sort(key = lambda a: (a[0].x, a[0].y)) + except: points.sort(lambda a,b: cmp((a[0].x, a[0].y), (b[0].x, b[0].y))) + + # Build upper half of the hull. + upper = [points[0], points[1]] # cant remove these. + for i in xrange(len(points)-2): + upper.append(points[i+2]) + while len(upper) > 2 and not _isRightTurn(upper[-3:]): + del upper[-2] + + # Build lower half of the hull. + points.reverse() + lower = [points.pop(0), points.pop(1)] + for p in points: + lower.append(p) + while len(lower) > 2 and not _isRightTurn(lower[-3:]): + del lower[-2] + + # Concatenate both halfs and return. + return [p[1] for ls in (upper, lower) for p in ls] + + +def plane2mat(plane, normalize= False): + ''' + Takes a plane and converts to a matrix + points between 0 and 1 are up + 1 and 2 are right + assumes the plane has 90d corners + ''' + cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0 + + + up= cent - ((plane[0]+plane[1])/2.0) + right= cent - ((plane[1]+plane[2])/2.0) + z= CrossVecs(up, right) + + if normalize: + up.normalize() + right.normalize() + z.normalize() + + mat= Matrix(up, right, z) + + # translate + mat.resize4x4() + tmat= Blender.Mathutils.TranslationMatrix(cent) + return mat * tmat + + +# Used for mesh_solidify.py and mesh_wire.py + +# returns a length from an angle +# Imaging a 2d space. +# there is a hoz line at Y1 going to inf on both X ends, never moves (LINEA) +# down at Y0 is a unit length line point up at (angle) from X0,Y0 (LINEB) +# This function returns the length of LINEB at the point it would intersect LINEA +# - Use this for working out how long to make the vector - differencing it from surrounding faces, +# import math +from math import pi, sin, cos, sqrt + +def angleToLength(angle): + # Alredy accounted for + if angle < 0.000001: + return 1.0 + + angle = 2*pi*angle/360 + x,y = cos(angle), sin(angle) + # print "YX", x,y + # 0 d is hoz to the right. + # 90d is vert upward. + fac=1/x + x=x*fac + y=y*fac + return sqrt((x*x)+(y*y)) diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py new file mode 100644 index 00000000000..415c2a12c69 --- /dev/null +++ b/release/scripts/bpymodules/BPyMesh.py @@ -0,0 +1,1328 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +import Blender +import bpy +import BPyMesh_redux # seperated because of its size. +# reload(BPyMesh_redux) +redux= BPyMesh_redux.redux + +# python 2.3 has no reversed() iterator. this will only work on lists and tuples +try: + reversed +except: + def reversed(l): return l[::-1] + + +# If python version is less than 2.4, try to get set stuff from module +try: + set +except: + try: + from sets import Set as set + except: + set= None + + + + + +def meshWeight2List(me): + ''' Takes a mesh and return its group names and a list of lists, one list per vertex. + aligning the each vert list with the group names, each list contains float value for the weight. + These 2 lists can be modified and then used with list2MeshWeight to apply the changes. + ''' + + # Clear the vert group. + groupNames= me.getVertGroupNames() + len_groupNames= len(groupNames) + + if not len_groupNames: + # no verts? return a vert aligned empty list + return [[] for i in xrange(len(me.verts))], [] + + else: + vWeightList= [[0.0]*len_groupNames for i in xrange(len(me.verts))] + + for group_index, group in enumerate(groupNames): + for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples. + vWeightList[vert_index][group_index]= weight + + # removed this because me may be copying teh vertex groups. + #for group in groupNames: + # me.removeVertGroup(group) + + return groupNames, vWeightList + + +def list2MeshWeight(me, groupNames, vWeightList): + ''' Takes a list of groups and a list of vertex Weight lists as created by meshWeight2List + and applys it to the mesh.''' + + if len(vWeightList) != len(me.verts): + raise 'Error, Lists Differ in size, do not modify your mesh.verts before updating the weights' + + act_group = me.activeGroup + + # Clear the vert group. + currentGroupNames= me.getVertGroupNames() + for group in currentGroupNames: + me.removeVertGroup(group) # messes up the active group. + + # Add clean unused vert groupNames back + currentGroupNames= me.getVertGroupNames() + for group in groupNames: + me.addVertGroup(group) + + add_ = Blender.Mesh.AssignModes.ADD + + vertList= [None] + for i, v in enumerate(me.verts): + vertList[0]= i + for group_index, weight in enumerate(vWeightList[i]): + if weight: + try: + me.assignVertsToGroup(groupNames[group_index], vertList, min(1, max(0, weight)), add_) + except: + pass # vert group is not used anymore. + + try: me.activeGroup = act_group + except: pass + + me.update() + + + + +def meshWeight2Dict(me): + ''' Takes a mesh and return its group names and a list of dicts, one dict per vertex. + using the group as a key and a float value for the weight. + These 2 lists can be modified and then used with dict2MeshWeight to apply the changes. + ''' + + vWeightDict= [dict() for i in xrange(len(me.verts))] # Sync with vertlist. + + # Clear the vert group. + groupNames= me.getVertGroupNames() + + for group in groupNames: + for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples. + vWeightDict[vert_index][group]= weight + + # removed this because me may be copying teh vertex groups. + #for group in groupNames: + # me.removeVertGroup(group) + + return groupNames, vWeightDict + + +def dict2MeshWeight(me, groupNames, vWeightDict): + ''' Takes a list of groups and a list of vertex Weight dicts as created by meshWeight2Dict + and applys it to the mesh.''' + + if len(vWeightDict) != len(me.verts): + raise 'Error, Lists Differ in size, do not modify your mesh.verts before updating the weights' + + act_group = me.activeGroup + + # Clear the vert group. + currentGroupNames= me.getVertGroupNames() + for group in currentGroupNames: + if group not in groupNames: + me.removeVertGroup(group) # messes up the active group. + else: + me.removeVertsFromGroup(group) + + # Add clean unused vert groupNames back + currentGroupNames= me.getVertGroupNames() + for group in groupNames: + if group not in currentGroupNames: + me.addVertGroup(group) + + add_ = Blender.Mesh.AssignModes.ADD + + vertList= [None] + for i, v in enumerate(me.verts): + vertList[0]= i + for group, weight in vWeightDict[i].iteritems(): + try: + me.assignVertsToGroup(group, vertList, min(1, max(0, weight)), add_) + except: + pass # vert group is not used anymore. + + try: me.activeGroup = act_group + except: pass + + me.update() + +def dictWeightMerge(dict_weights): + ''' + Takes dict weight list and merges into 1 weight dict item and returns it + ''' + + if not dict_weights: + return {} + + keys= [] + for weight in dict_weights: + keys.extend([ (k, 0.0) for k in weight.iterkeys() ]) + + new_wdict = dict(keys) + + len_dict_weights= len(dict_weights) + + for weight in dict_weights: + for group, value in weight.iteritems(): + new_wdict[group] += value/len_dict_weights + + return new_wdict + + +FLIPNAMES=[\ +('Left','Right'),\ +('_L','_R'),\ +('-L','-R'),\ +('.L','.R'),\ +] + +def dictWeightFlipGroups(dict_weight, groupNames, createNewGroups): + ''' + Returns a weight with flip names + dict_weight - 1 vert weight. + groupNames - because we may need to add new group names. + dict_weight - Weather to make new groups where needed. + ''' + + def flipName(name): + for n1,n2 in FLIPNAMES: + for nA, nB in ( (n1,n2), (n1.lower(),n2.lower()), (n1.upper(),n2.upper()) ): + if createNewGroups: + newName= name.replace(nA,nB) + if newName!=name: + if newName not in groupNames: + groupNames.append(newName) + return newName + + newName= name.replace(nB,nA) + if newName!=name: + if newName not in groupNames: + groupNames.append(newName) + return newName + + else: + newName= name.replace(nA,nB) + if newName!=name and newName in groupNames: + return newName + + newName= name.replace(nB,nA) + if newName!=name and newName in groupNames: + return newName + + return name + + if not dict_weight: + return dict_weight, groupNames + + + new_wdict = {} + for group, weight in dict_weight.iteritems(): + flipname= flipName(group) + new_wdict[flipname]= weight + + return new_wdict, groupNames + + +def mesh2linkedFaces(me): + ''' + Splits the mesh into connected parts, + these parts are returned as lists of faces. + used for seperating cubes from other mesh elements in the 1 mesh + ''' + + # Build vert face connectivity + vert_faces= [[] for i in xrange(len(me.verts))] + for f in me.faces: + for v in f: + vert_faces[v.index].append(f) + + # sort faces into connectivity groups + face_groups= [[f] for f in me.faces] + face_mapping = range(len(me.faces)) # map old, new face location + + # Now clump faces iterativly + ok= True + while ok: + ok= False + + for i, f in enumerate(me.faces): + mapped_index= face_mapping[f.index] + mapped_group= face_groups[mapped_index] + + for v in f: + for nxt_f in vert_faces[v.index]: + if nxt_f != f: + nxt_mapped_index= face_mapping[nxt_f.index] + + # We are not a part of the same group + if mapped_index != nxt_mapped_index: + + ok= True + + # Assign mapping to this group so they all map to this group + for grp_f in face_groups[nxt_mapped_index]: + face_mapping[grp_f.index] = mapped_index + + # Move faces into this group + mapped_group.extend(face_groups[nxt_mapped_index]) + + # remove reference to the list + face_groups[nxt_mapped_index]= None + + + # return all face groups that are not null + # this is all the faces that are connected in their own lists. + return [fg for fg in face_groups if fg] + + +def getFaceLoopEdges(faces, seams=[]): + ''' + Takes me.faces or a list of faces and returns the edge loops + These edge loops are the edges that sit between quads, so they dont touch + 1 quad, not not connected will make 2 edge loops, both only containing 2 edges. + + return a list of edge key lists + [ [(0,1), (4, 8), (3,8)], ...] + + optionaly, seams are edge keys that will be removed + ''' + + OTHER_INDEX = 2,3,0,1 # opposite face index + + edges = {} + + for f in faces: + if len(f) == 4: + edge_keys = f.edge_keys + for i, edkey in enumerate(f.edge_keys): + edges.setdefault(edkey, []).append(edge_keys[OTHER_INDEX[i]]) + + for edkey in seams: + edges[edkey] = [] + + # Collect edge loops here + edge_loops = [] + + for edkey, ed_adj in edges.iteritems(): + if 0 face indicies + face_edges[i] -> list referencs local faces v indicies 1,2,3 &| 4 + face_edges[i][j] -> list of faces that this edge uses. + crap this is tricky to explain :/ + ''' + face_edges= [ [-1] * len(f) for f in me.faces ] + + face_edges_dict= dict([(ed.key, []) for ed in me.edges]) + for fidx, f in enumerate(me.faces): + for i, edkey in enumerate(f.edge_keys): + edge_face_users= face_edges_dict[edkey] + edge_face_users.append(f) + face_edges[fidx][i]= edge_face_users + + return face_edges + + +def facesPlanerIslands(me): + DotVecs= Blender.Mathutils.DotVecs + + def roundvec(v): + return round(v[0], 4), round(v[1], 4), round(v[2], 4) + + face_props= [(cent, no, roundvec(no), DotVecs(cent, no)) for f in me.faces for no, cent in ((f.no, f.cent),)] + + face_edge_users= face_edges(me) + islands= [] + + used_faces= [0] * len(me.faces) + while True: + new_island= False + for i, used_val in enumerate(used_faces): + if used_val==0: + island= [i] + new_island= True + used_faces[i]= 1 + break + + if not new_island: + break + + island_growing= True + while island_growing: + island_growing= False + for fidx1 in island[:]: + if used_faces[fidx1]==1: + used_faces[fidx1]= 2 + face_prop1= face_props[fidx1] + for ed in face_edge_users[fidx1]: + for f2 in ed: + fidx2= f2.index + if fidx1 != fidx2 and used_faces[fidx2]==0: + island_growing= True + face_prop2= face_props[fidx2] + # normals are the same? + if face_prop1[2]==face_prop2[2]: + if abs(face_prop1[3] - DotVecs(face_prop1[1], face_prop2[0])) < 0.000001: + used_faces[fidx2]= 1 + island.append(fidx2) + islands.append([me.faces[i] for i in island]) + return islands + + + +def facesUvIslands(me, PREF_IMAGE_DELIMIT=True): + DotVecs= Blender.Mathutils.DotVecs + def roundvec(v): + return round(v[0], 4), round(v[1], 4) + + if not me.faceUV: + return [ list(me.faces), ] + + # make a list of uv dicts + face_uvs= [ [roundvec(uv) for uv in f.uv] for f in me.faces] + + # key - face uv || value - list of face idxs + uv_connect_dict= dict([ (uv, [] ) for f_uvs in face_uvs for uv in f_uvs]) + + for i, f_uvs in enumerate(face_uvs): + for uv in f_uvs: # loops through rounded uv values + uv_connect_dict[uv].append(i) + islands= [] + + used_faces= [0] * len(me.faces) + while True: + new_island= False + for i, used_val in enumerate(used_faces): + if used_val==0: + island= [i] + new_island= True + used_faces[i]= 1 + break + + if not new_island: + break + + island_growing= True + while island_growing: + island_growing= False + for fidx1 in island[:]: + if used_faces[fidx1]==1: + used_faces[fidx1]= 2 + for uv in face_uvs[fidx1]: + for fidx2 in uv_connect_dict[uv]: + if fidx1 != fidx2 and used_faces[fidx2]==0: + if not PREF_IMAGE_DELIMIT or me.faces[fidx1].image==me.faces[fidx2].image: + island_growing= True + used_faces[fidx2]= 1 + island.append(fidx2) + + islands.append([me.faces[i] for i in island]) + return islands + +#def faceUvBounds(me, faces= None): + + +def facesUvRotate(me, deg, faces= None, pivot= (0,0)): + ''' + Faces can be None an all faces will be used + pivot is just the x/y well rotated about + + positive deg value for clockwise rotation + ''' + if faces==None: faces= me.faces + pivot= Blender.Mathutils.Vector(pivot) + + rotmat= Blender.Mathutils.RotationMatrix(-deg, 2) + + for f in faces: + f.uv= [((uv-pivot)*rotmat)+pivot for uv in f.uv] + +def facesUvScale(me, sca, faces= None, pivot= (0,0)): + ''' + Faces can be None an all faces will be used + pivot is just the x/y well rotated about + sca can be wither an int/float or a vector if you want to + scale x/y seperately. + a sca or (1.0, 1.0) will do nothing. + ''' + def vecmulti(v1,v2): + '''V2 is unchanged''' + v1[:]= (v1.x*v2.x, v1.y*v2.y) + return v1 + + sca= Blender.Mathutils.Vector(sca) + if faces==None: faces= me.faces + pivot= Blender.Mathutils.Vector(pivot) + + for f in faces: + f.uv= [vecmulti(uv-pivot, sca)+pivot for uv in f.uv] + + +def facesUvTranslate(me, tra, faces= None, pivot= (0,0)): + ''' + Faces can be None an all faces will be used + pivot is just the x/y well rotated about + ''' + if faces==None: faces= me.faces + tra= Blender.Mathutils.Vector(tra) + + for f in faces: + f.uv= [uv+tra for uv in f.uv] + + + +def edgeFaceUserCount(me, faces= None): + ''' + Return an edge aligned list with the count for all the faces that use that edge. - + can spesify a subset of the faces, so only those will be counted. + ''' + if faces==None: + faces= me.faces + max_vert= len(me.verts) + else: + # find the lighest vert index + pass + + edge_users= [0] * len(me.edges) + + edges_idx_dict= dict([(ed.key, ed.index) for ed in me.edges]) + + for f in faces: + for edkey in f.edge_keys: + edge_users[edges_idx_dict[edkey]] += 1 + + return edge_users + + +#============================================================================# +# Takes a face, and a pixel x/y on the image and returns a worldspace x/y/z # +# will return none if the pixel is not inside the faces UV # +#============================================================================# +def getUvPixelLoc(face, pxLoc, img_size = None, uvArea = None): + TriangleArea= Blender.Mathutils.TriangleArea + Vector= Blender.Mathutils.Vector + + if not img_size: + w,h = face.image.size + else: + w,h= img_size + + scaled_uvs= [Vector(uv.x*w, uv.y*h) for uv in f.uv] + + if len(scaled_uvs)==3: + indicies= ((0,1,2),) + else: + indicies= ((0,1,2), (0,2,3)) + + for fidxs in indicies: + for i1,i2,i3 in fidxs: + # IS a point inside our triangle? + # UVArea could be cached? + uv_area = TriangleArea(scaled_uvs[i1], scaled_uvs[i2], scaled_uvs[i3]) + area0 = TriangleArea(pxLoc, scaled_uvs[i2], scaled_uvs[i3]) + area1 = TriangleArea(pxLoc, scaled_uvs[i1], scaled_uvs[i3]) + area2 = TriangleArea(pxLoc, scaled_uvs[i1], scaled_uvs[i2]) + if area0 + area1 + area2 > uv_area + 1: # 1 px bleed/error margin. + pass # if were a quad the other side may contain the pixel so keep looking. + else: + # We know the point is in the tri + area0 /= uv_area + area1 /= uv_area + area2 /= uv_area + + # New location + return Vector(\ + face.v[i1].co[0]*area0 + face.v[i2].co[0]*area1 + face.v[i3].co[0]*area2,\ + face.v[i1].co[1]*area0 + face.v[i2].co[1]*area1 + face.v[i3].co[1]*area2,\ + face.v[i1].co[2]*area0 + face.v[i2].co[2]*area1 + face.v[i3].co[2]*area2\ + ) + + return None + + +# Used for debugging ngon +""" +def draw_loops(loops): + + me= Blender.Mesh.New() + for l in loops: + #~ me= Blender.Mesh.New() + + + i= len(me.verts) + me.verts.extend([v[0] for v in l]) + try: + me.verts[0].sel= 1 + except: + pass + me.edges.extend([ (j-1, j) for j in xrange(i+1, len(me.verts)) ]) + # Close the edge? + me.edges.extend((i, len(me.verts)-1)) + + + #~ ob= Blender.Object.New('Mesh') + #~ ob.link(me) + #~ scn= Blender.Scene.GetCurrent() + #~ scn.link(ob) + #~ ob.Layers= scn.Layers + #~ ob.sel= 1 + + + + # Fill + #fill= Blender.Mathutils.PolyFill(loops) + #me.faces.extend(fill) + + + ob= Blender.Object.New('Mesh') + ob.link(me) + scn= Blender.Scene.GetCurrent() + scn.link(ob) + ob.Layers= scn.Layers + ob.sel= 1 + Blender.Window.RedrawAll() +""" + +def ngon(from_data, indices, PREF_FIX_LOOPS= True): + ''' + Takes a polyline of indices (fgon) + and returns a list of face indicie lists. + Designed to be used for importers that need indices for an fgon to create from existing verts. + + from_data: either a mesh, or a list/tuple of vectors. + indices: a list of indicies to use this list is the ordered closed polyline to fill, and can be a subset of the data given. + PREF_FIX_LOOPS: If this is enabled polylines that use loops to make multiple polylines are delt with correctly. + ''' + + if not set: # Need sets for this, otherwise do a normal fill. + PREF_FIX_LOOPS= False + + Vector= Blender.Mathutils.Vector + if not indices: + return [] + + # return [] + def rvec(co): return round(co.x, 6), round(co.y, 6), round(co.z, 6) + def mlen(co): return abs(co[0])+abs(co[1])+abs(co[2]) # manhatten length of a vector, faster then length + + def vert_treplet(v, i): + return v, rvec(v), i, mlen(v) + + def ed_key_mlen(v1, v2): + if v1[3] > v2[3]: + return v2[1], v1[1] + else: + return v1[1], v2[1] + + + if not PREF_FIX_LOOPS: + ''' + Normal single concave loop filling + ''' + if type(from_data) in (tuple, list): + verts= [Vector(from_data[i]) for ii, i in enumerate(indices)] + else: + verts= [from_data.verts[i].co for ii, i in enumerate(indices)] + + for i in xrange(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))): + if verts[i][1]==verts[i-1][0]: + verts.pop(i-1) + + fill= Blender.Geometry.PolyFill([verts]) + + else: + ''' + Seperate this loop into multiple loops be finding edges that are used twice + This is used by lightwave LWO files a lot + ''' + + if type(from_data) in (tuple, list): + verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)] + else: + verts= [vert_treplet(from_data.verts[i].co, ii) for ii, i in enumerate(indices)] + + edges= [(i, i-1) for i in xrange(len(verts))] + if edges: + edges[0]= (0,len(verts)-1) + + if not verts: + return [] + + + edges_used= set() + edges_doubles= set() + # We need to check if any edges are used twice location based. + for ed in edges: + edkey= ed_key_mlen(verts[ed[0]], verts[ed[1]]) + if edkey in edges_used: + edges_doubles.add(edkey) + else: + edges_used.add(edkey) + + # Store a list of unconnected loop segments split by double edges. + # will join later + loop_segments= [] + + v_prev= verts[0] + context_loop= [v_prev] + loop_segments= [context_loop] + + for v in verts: + if v!=v_prev: + # Are we crossing an edge we removed? + if ed_key_mlen(v, v_prev) in edges_doubles: + context_loop= [v] + loop_segments.append(context_loop) + else: + if context_loop and context_loop[-1][1]==v[1]: + #raise "as" + pass + else: + context_loop.append(v) + + v_prev= v + # Now join loop segments + + def join_seg(s1,s2): + if s2[-1][1]==s1[0][1]: # + s1,s2= s2,s1 + elif s1[-1][1]==s2[0][1]: + pass + else: + return False + + # If were stuill here s1 and s2 are 2 segments in the same polyline + s1.pop() # remove the last vert from s1 + s1.extend(s2) # add segment 2 to segment 1 + + if s1[0][1]==s1[-1][1]: # remove endpoints double + s1.pop() + + s2[:]= [] # Empty this segment s2 so we dont use it again. + return True + + joining_segments= True + while joining_segments: + joining_segments= False + segcount= len(loop_segments) + + for j in xrange(segcount-1, -1, -1): #reversed(xrange(segcount)): + seg_j= loop_segments[j] + if seg_j: + for k in xrange(j-1, -1, -1): # reversed(xrange(j)): + if not seg_j: + break + seg_k= loop_segments[k] + + if seg_k and join_seg(seg_j, seg_k): + joining_segments= True + + loop_list= loop_segments + + for verts in loop_list: + while verts and verts[0][1]==verts[-1][1]: + verts.pop() + + loop_list= [verts for verts in loop_list if len(verts)>2] + # DONE DEALING WITH LOOP FIXING + + + # vert mapping + vert_map= [None]*len(indices) + ii=0 + for verts in loop_list: + if len(verts)>2: + for i, vert in enumerate(verts): + vert_map[i+ii]= vert[2] + ii+=len(verts) + + fill= Blender.Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ]) + #draw_loops(loop_list) + #raise 'done loop' + # map to original indicies + fill= [[vert_map[i] for i in reversed(f)] for f in fill] + + + if not fill: + print 'Warning Cannot scanfill, fallback on a triangle fan.' + fill= [ [0, i-1, i] for i in xrange(2, len(indices)) ] + else: + # Use real scanfill. + # See if its flipped the wrong way. + flip= None + for fi in fill: + if flip != None: + break + for i, vi in enumerate(fi): + if vi==0 and fi[i-1]==1: + flip= False + break + elif vi==1 and fi[i-1]==0: + flip= True + break + + if not flip: + for i, fi in enumerate(fill): + fill[i]= tuple([ii for ii in reversed(fi)]) + + + + + return fill + + + +# EG +''' +scn= Scene.GetCurrent() +me = scn.getActiveObject().getData(mesh=1) +ind= [v.index for v in me.verts if v.sel] # Get indices + +indices = ngon(me, ind) # fill the ngon. + +# Extand the faces to show what the scanfill looked like. +print len(indices) +me.faces.extend([[me.verts[ii] for ii in i] for i in indices]) +''' + +def meshCalcNormals(me, vertNormals=None): + ''' + takes a mesh and returns very high quality normals 1 normal per vertex. + The normals should be correct, indipendant of topology + + vertNormals - a list of vectors at least as long as the number of verts in the mesh + ''' + Ang= Blender.Mathutils.AngleBetweenVecs + Vector= Blender.Mathutils.Vector + SMALL_NUM=0.000001 + # Weight the edge normals by total angle difference + # EDGE METHOD + + if not vertNormals: + vertNormals= [ Vector() for v in xrange(len(me.verts)) ] + else: + for v in vertNormals: + v.zero() + + edges={} + for f in me.faces: + f_v = f.v + for edkey in f.edge_keys: + edges.setdefault(edkey, []).append(f.no) + + # Weight the edge normals by total angle difference + for fnos in edges.itervalues(): + + len_fnos= len(fnos) + if len_fnos>1: + totAngDiff=0 + for j in xrange(len_fnos-1, -1, -1): # same as reversed(xrange(...)) + for k in xrange(j-1, -1, -1): # same as reversed(xrange(...)) + #print j,k + try: + totAngDiff+= (Ang(fnos[j], fnos[k])) # /180 isnt needed, just to keeop the vert small. + except: + pass # Zero length face + + # print totAngDiff + if totAngDiff > SMALL_NUM: + ''' + average_no= Vector() + for no in fnos: + average_no+=no + ''' + average_no= reduce(lambda a,b: a+b, fnos, Vector()) + fnos.append(average_no*totAngDiff) # average no * total angle diff + #else: + # fnos[0] + else: + fnos.append(fnos[0]) + + for ed, v in edges.iteritems(): + vertNormals[ed[0]]+= v[-1] + vertNormals[ed[1]]+= v[-1] + for i, v in enumerate(me.verts): + v.no= vertNormals[i] + + + + +def pointInsideMesh(ob, pt): + Intersect = Blender.Mathutils.Intersect # 2 less dict lookups. + Vector = Blender.Mathutils.Vector + + def ptInFaceXYBounds(f, pt): + f_v = f.v + co= f_v[0].co + xmax= xmin= co.x + ymax= ymin= co.y + + co= f_v[1].co + xmax= max(xmax, co.x) + xmin= min(xmin, co.x) + ymax= max(ymax, co.y) + ymin= min(ymin, co.y) + + co= f_v[2].co + xmax= max(xmax, co.x) + xmin= min(xmin, co.x) + ymax= max(ymax, co.y) + ymin= min(ymin, co.y) + + if len(f_v)==4: + co= f_v[3].co + xmax= max(xmax, co.x) + xmin= min(xmin, co.x) + ymax= max(ymax, co.y) + ymin= min(ymin, co.y) + + # Now we have the bounds, see if the point is in it. + if\ + pt.x < xmin or\ + pt.y < ymin or\ + pt.x > xmax or\ + pt.y > ymax: + return False # point is outside face bounds + else: + return True # point inside. + #return xmax, ymax, xmin, ymin + + def faceIntersect(f): + f_v = f.v + isect = Intersect(f_v[0].co, f_v[1].co, f_v[2].co, ray, obSpacePt, 1) # Clipped. + if not isect and len(f) == 4: + isect = Intersect(f_v[0].co, f_v[2].co, f_v[3].co, ray, obSpacePt, 1) # Clipped. + + if isect and isect.z > obSpacePt.z: # This is so the ray only counts if its above the point. + return True + else: + return False + + obSpacePt = pt*ob.matrixWorld.copy().invert() + ray = Vector(0,0,-1) + me= ob.getData(mesh=1) + + # Here we find the number on intersecting faces, return true if an odd number (inside), false (outside) if its true. + return len([None for f in me.faces if ptInFaceXYBounds(f, obSpacePt) if faceIntersect(f)]) % 2 + + +def faceAngles(f): + ''' + Returns the angle between all corners in a tri or a quad + + ''' + AngleBetweenVecs = Blender.Mathutils.AngleBetweenVecs + def Ang(a1,a2): + try: return AngleBetweenVecs(a1,a2) + except: return 180 + + if len(f) == 3: + if type(f) in (tuple, list): v1,v2,v3 = f + else: v1,v2,v3 = [v.co for v in f] + a1= Ang(v2-v1,v3-v1) + a2= Ang(v1-v2,v3-v2) + a3 = 180 - (a1+a2) # a3= Mathutils.AngleBetweenVecs(v2-v3,v1-v3) + return a1,a2,a3 + + else: + if type(f) in (tuple, list): v1,v2,v3,v4 = f + else: v1,v2,v3,v4 = [v.co for v in f] + a1= Ang(v2-v1,v4-v1) + a2= Ang(v1-v2,v3-v2) + a3= Ang(v2-v3,v4-v3) + a4= Ang(v3-v4,v1-v4) + return a1,a2,a3,a4 + +# NMesh wrapper +Vector= Blender.Mathutils.Vector +class NMesh(object): + __slots__= 'verts', 'faces', 'edges', 'faceUV', 'materials', 'realmesh' + def __init__(self, mesh): + ''' + This is an NMesh wrapper that + mesh is an Mesh as returned by Blender.Mesh.New() + This class wraps NMesh like access into Mesh + + Running NMesh.update() - with this wrapper, + Will update the realmesh. + ''' + self.verts= [] + self.faces= [] + self.edges= [] + self.faceUV= False + self.materials= [] + self.realmesh= mesh + + def addFace(self, nmf): + self.faces.append(nmf) + + def Face(self, v=[]): + return NMFace(v) + def Vert(self, x,y,z): + return NMVert(x,y,z) + + def hasFaceUV(self, flag): + if flag: + self.faceUV= True + else: + self.faceUV= False + + def addMaterial(self, mat): + self.materials.append(mat) + + def update(self, recalc_normals=False): # recalc_normals is dummy + mesh= self.realmesh + mesh.verts= None # Clears the + + # Add in any verts from faces we may have not added. + for nmf in self.faces: + for nmv in nmf.v: + if nmv.index==-1: + nmv.index= len(self.verts) + self.verts.append(nmv) + + + mesh.verts.extend([nmv.co for nmv in self.verts]) + for i, nmv in enumerate(self.verts): + nmv.index= i + mv= mesh.verts[i] + mv.sel= nmv.sel + + good_faces= [nmf for nmf in self.faces if len(nmf.v) in (3,4)] + #print len(good_faces), 'AAA' + + + #mesh.faces.extend([nmf.v for nmf in self.faces]) + mesh.faces.extend([[mesh.verts[nmv.index] for nmv in nmf.v] for nmf in good_faces]) + if len(mesh.faces): + if self.faceUV: + mesh.faceUV= 1 + + #for i, nmf in enumerate(self.faces): + for i, nmf in enumerate(good_faces): + mf= mesh.faces[i] + if self.faceUV: + if len(nmf.uv) == len(mf.v): + mf.uv= [Vector(uv[0], uv[1]) for uv in nmf.uv] + if len(nmf.col) == len(mf.v): + for c, i in enumerate(mf.col): + c.r, c.g, c.b= nmf.col[i].r, nmf.col[i].g, nmf.col[i].b + if nmf.image: + mf.image= nmf.image + + mesh.materials= self.materials[:16] + +class NMVert(object): + __slots__= 'co', 'index', 'no', 'sel', 'uvco' + def __init__(self, x,y,z): + self.co= Vector(x,y,z) + self.index= None # set on appending. + self.no= Vector(0,0,1) # dummy + self.sel= 0 + self.uvco= None +class NMFace(object): + __slots__= 'col', 'flag', 'hide', 'image', 'mat', 'materialIndex', 'mode', 'normal',\ + 'sel', 'smooth', 'transp', 'uv', 'v' + + def __init__(self, v=[]): + self.col= [] + self.flag= 0 + self.hide= 0 + self.image= None + self.mat= 0 # materialIndex needs support too. + self.mode= 0 + self.normal= Vector(0,0,1) + self.uv= [] + self.sel= 0 + self.smooth= 0 + self.transp= 0 + self.uv= [] + self.v= [] # a list of nmverts. + +class NMCol(object): + __slots__ = 'r', 'g', 'b', 'a' + def __init__(self): + self.r= 255 + self.g= 255 + self.b= 255 + self.a= 255 + + +''' +# +verts_split= [dict() for i in xrange(len(me.verts))] + +tot_verts= 0 +for f in me.faces: + f_uv= f.uv + for i, v in enumerate(f.v): + vert_index= v.index # mesh index + vert_dict= verts_split[vert_index] # get the dict for this vert + + uv= f_uv[i] + # now we have the vert and the face uv well make a unique dict. + + vert_key= v.x, v.y, v.x, uv.x, uv.y # ADD IMAGE NAME HETR IF YOU WANT TO SPLIT BY THAT TOO + value= vert_index, tot_verts # ADD WEIGHT HERE IF YOU NEED. + try: + vert_dict[vert_key] # if this is missing it will fail. + except: + # this stores a mapping between the split and orig vert indicies + vert_dict[vert_key]= value + tot_verts+= 1 + +# a flat list of split verts - can add custom weight data here too if you need +split_verts= [None]*tot_verts + +for vert_split_dict in verts_split: + for key, value in vert_split_dict.iteritems(): + local_index, split_index= value + split_verts[split_index]= key + +# split_verts - Now you have a list of verts split by their UV. +''' diff --git a/release/scripts/bpymodules/BPyMesh_octree.py b/release/scripts/bpymodules/BPyMesh_octree.py new file mode 100644 index 00000000000..368a33496eb --- /dev/null +++ b/release/scripts/bpymodules/BPyMesh_octree.py @@ -0,0 +1,332 @@ +from Blender import * + +try: + import psyco + psyco.full() +except: + print 'no psyco for you!' + +DotVecs= Mathutils.DotVecs +#======================================================== +# SPACIAL TREE - Seperate Class - use if you want to +# USed for getting vert is a proximity +LEAF_SIZE = 128 +class octreeNode: + def __init__(self, verts, parent): + + # Assunme we are a leaf node, until split is run. + self.verts = verts + self.children = [] + + if parent == None: # ROOT NODE, else set bounds when making children, + # BOUNDS + v= verts[0] + maxx,maxy,maxz= v.co + minx,miny,minz= maxx,maxy,maxz + + for v in verts: + x,y,z= v.co + if x>maxx: maxx= x + if y>maxy: maxy= y + if z>maxz: maxz= z + + if x LEAF_SIZE: + self.makeChildren() # 8 new children, + self.verts = None + # Alredy assumed a leaf not so dont do anything here. + + def makeChildren(self): + verts= self.verts + # Devide into 8 children. + axisDividedVerts = [[],[],[],[],[],[],[],[]] # Verts Only + + + divx = (self.maxx + self.minx) / 2 + divy = (self.maxy + self.miny) / 2 + divz = (self.maxz + self.minz) / 2 + + # Sort into 8 + for v in verts: + x,y,z = v.co + + if x > divx: + if y > divy: + if z > divz: + axisDividedVerts[0].append(v) + else: + axisDividedVerts[1].append(v) + else: + if z > divz: + axisDividedVerts[2].append(v) + else: + axisDividedVerts[3].append(v) + else: + if y > divy: + if z > divz: + axisDividedVerts[4].append(v) + else: + axisDividedVerts[5].append(v) + else: + if z > divz: + axisDividedVerts[6].append(v) + else: + axisDividedVerts[7].append(v) + + # populate self.children + for i in xrange(8): + octNode = octreeNode(axisDividedVerts[i], self) + # Set bounds manually + if i == 0: + octNode.minx = divx + octNode.maxx = self.maxx + octNode.miny = divy + octNode.maxy = self.maxy + octNode.minz = divz + octNode.maxz = self.maxz + elif i == 1: + octNode.minx = divx + octNode.maxx = self.maxx + octNode.miny = divy + octNode.maxy = self.maxy + octNode.minz = self.minz # + octNode.maxz = divz # + elif i == 2: + octNode.minx = divx + octNode.maxx = self.maxx + octNode.miny = self.miny # + octNode.maxy = divy # + octNode.minz = divz + octNode.maxz = self.maxz + elif i == 3: + octNode.minx = divx + octNode.maxx = self.maxx + octNode.miny = self.miny # + octNode.maxy = divy # + octNode.minz = self.minz # + octNode.maxz = divz # + elif i == 4: + octNode.minx = self.minx # + octNode.maxx = divx # + octNode.miny = divy + octNode.maxy = self.maxy + octNode.minz = divz + octNode.maxz = self.maxz + elif i == 5: + octNode.minx = self.minx # + octNode.maxx = divx # + octNode.miny = divy + octNode.maxy = self.maxy + octNode.minz = self.minz # + octNode.maxz = divz # + elif i == 6: + octNode.minx = self.minx # + octNode.maxx = divx # + octNode.miny = self.miny # + octNode.maxy = divy # + octNode.minz = divz + octNode.maxz = self.maxz + elif i == 7: + octNode.minx = self.minx # + octNode.maxx = divx # + octNode.miny = self.miny # + octNode.maxy = divy # + octNode.minz = self.minz # + octNode.maxz = divz # + #octNode.setCornerPoints() + octNode.splitNode() # Splits the node if it can. + self.children.append(octNode) + + # GETS VERTS IN A Distance RANGE- + def getVertsInRange(self, loc, normal, range_val, vertList): + #loc= Mathutils.Vector(loc) # MUST BE VECTORS + #normal= Mathutils.Vector(normal) + + ''' + loc: Vector of the location to search from + normal: None or Vector - if a vector- will only get verts on this side of the vector + range_val: maximum distance. A negative value will fill the list with teh closest vert only. + vertList: starts as an empty list + list that this function fills with verts that match + ''' + xloc,yloc,zloc= loc + + if range_val<0: + range_val= -range_val + FIND_CLOSEST= True + vertList.append(None) # just update the 1 vertex + else: + FIND_CLOSEST= False + + if self.children: + # Check if the bounds are in range_val, + for childNode in self.children: + # First test if we are surrounding the point. + if\ + childNode.minx - range_val < xloc and\ + childNode.maxx + range_val > xloc and\ + childNode.miny - range_val < yloc and\ + childNode.maxy + range_val > yloc and\ + childNode.minz - range_val < zloc and\ + childNode.maxz + range_val > zloc: + # Recurse down or get virts. + childNode.getVertsInRange(loc, normal, range_val, vertList) + #continue # Next please + + else: # we are a leaf node. Test vert locations. + if not normal: + # Length only check + for v in self.verts: + length = (loc - v.co).length + if length < range_val: + if FIND_CLOSEST: + # Just update the 1 vert + vertList[0]= (v, length) + range_val= length # Shink the length so we only get verts from their. + else: + vertList.append((v, length)) + else: + # Lengh and am I infront of the vert. + for v in self.verts: + length = (loc - v.co).length + if length < range_val: + # Check if the points in front + dot= DotVecs(normal, loc) - DotVecs(normal, v.co) + if dot<0: + vertList.append((v, length)) + +# END TREE + + + + +# EXAMPLE RADIO IN PYTHON USING THE ABOVE FUNCTION +""" +import BPyMesh +# Radio bake +def bake(): + + _AngleBetweenVecs_= Mathutils.AngleBetweenVecs + def AngleBetweenVecs(a1,a2): + try: + return _AngleBetweenVecs_(a1,a2) + except: + return 180 + + + + scn = Scene.GetCurrent() + ob = scn.getActiveObject() + me = ob.getData(mesh=1) + + dist= Draw.PupFloatInput('MaxDist:', 2.0, 0.1, 20.0, 0.1, 3) + if dist==None: + return + + # Make nice normals + BPyMesh.meshCalcNormals(me) + + + len_verts= len(me.verts) + #me.sel= False + meshOctTree = octreeNode(me.verts, None) + + + + # Store face areas + vertex_areas= [0.0] * len_verts + + # Get vertex areas - all areas of face users + for f in me.faces: + a= f.area + for v in f.v: + vertex_areas[v.index] += a + + + + bias= 0.001 + + t= sys.time() + + # Tone for the verts + vert_tones= [0.0] * len_verts + maxtone= 0.0 + mintone= 100000000 + for i, v in enumerate(me.verts): + if not i%10: + print 'verts to go', len_verts-i + v_co= v.co + v_no= v.no + verts_in_range= [] + meshOctTree.getVertsInRange(v_co, v_no, dist, verts_in_range) + + tone= 0.0 + # These are verts in our range + for test_v, length in verts_in_range: + if bias 90: # were facing this vert + #if 1: + # Current value us between zz90 and 180 + # make between 0 and 90 + # so 0 is right angles and 90 is direct opposite vertex normal + normal_diff= (normal_diff-90) + + # Vertex area needs to be taken into account so we dont have small faces over influencing. + vertex_area= vertex_areas[test_v.index] + + # Get the angle the vertex is in location from the location and normal of the vert. + above_diff= AngleBetweenVecs(test_v.co-v.co, v_no) + ## Result will be between 0 :above and 90: horizon.. invert this so horizon has littel effect + above_diff= 90-above_diff + # dist-length or 1.0/length both work well + tone= (dist-length) * vertex_area * above_diff * normal_diff + vert_tones[i] += tone + + if maxtonevert_tones[i]: + mintone= vert_tones[i] + + + if not maxtone: + Draw.PupMenu('No verts in range, use a larger range') + return + + # Apply tones + for f in me.faces: + f_col= f.col + for i, v in enumerate(f.v): + c= f_col[i] + v_index= v.index + tone= int(((maxtone - vert_tones[v.index]) / maxtone) * 255 ) + #print tone + c.r= c.g= c.b= tone + + print 'time', sys.time()-t + + +if __name__=="__main__": + bake() +""" \ No newline at end of file diff --git a/release/scripts/bpymodules/BPyMesh_redux.py b/release/scripts/bpymodules/BPyMesh_redux.py new file mode 100644 index 00000000000..1bcc6e9f7c8 --- /dev/null +++ b/release/scripts/bpymodules/BPyMesh_redux.py @@ -0,0 +1,653 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# (C) Copyright 2006 MetaVR, Inc. +# http://www.metavr.com +# Written by Campbell Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +import bpy +Vector= Blender.Mathutils.Vector +Ang= Blender.Mathutils.AngleBetweenVecs +CrossVecs= Blender.Mathutils.CrossVecs +MidpointVecs= Blender.Mathutils.MidpointVecs +import BPyMesh + +# If python version is less than 2.4, try to get set stuff from module + +try: + set +except: + try: + from sets import Set as set + except: + set= None + +def uv_key(uv): + return round(uv.x, 5), round(uv.y, 5) + +def uv_key_mix(uv1, uv2, w1, w2): + # Weighted mix. w1+w2==1.0 + return w1*uv1[0]+w2*uv2[0], w1*uv1[1]+w2*uv2[1] + +def col_key(col): + return col.r, col.g, col.b + +def col_key_mix(col1, col2, w1, w2): + # Weighted mix. w1+w2==1.0 + return int(w1*col1[0] + w2*col2[0]), int(w1*col1[1] + w2*col2[1]), int(w1*col1[2]+col2[2]*w2) + + +def redux(ob, REDUX=0.5, BOUNDRY_WEIGHT=2.0, REMOVE_DOUBLES=False, FACE_AREA_WEIGHT=1.0, FACE_TRIANGULATE=True, DO_UV=True, DO_VCOL=True, DO_WEIGHTS=True, VGROUP_INF_REDUX= None, VGROUP_INF_WEIGHT=0.5): + """ + BOUNDRY_WEIGHT - 0 is no boundry weighting. 2.0 will make them twice as unlikely to collapse. + FACE_AREA_WEIGHT - 0 is no weight. 1 is normal, 2.0 is higher. + """ + + if REDUX<0 or REDUX>1.0: + raise 'Error, factor must be between 0 and 1.0' + elif not set: + raise 'Error, this function requires Python 2.4 or a full install of Python 2.3' + + BOUNDRY_WEIGHT= 1+BOUNDRY_WEIGHT + + """ # DEBUG! + if Blender.Get('rt') == 1000: + DEBUG=True + else: + DEBUG= False + """ + + me= ob.getData(mesh=1) + me.hide= False # unhide all data,. + if len(me.faces)<5: + return + + + + if FACE_TRIANGULATE or REMOVE_DOUBLES: + me.sel= True + + if FACE_TRIANGULATE: + me.quadToTriangle() + + if REMOVE_DOUBLES: + me.remDoubles(0.0001) + + vgroups= me.getVertGroupNames() + + if not me.getVertGroupNames(): + DO_WEIGHTS= False + + if (VGROUP_INF_REDUX!= None and VGROUP_INF_REDUX not in vgroups) or\ + VGROUP_INF_WEIGHT==0.0: + VGROUP_INF_REDUX= None + + try: + VGROUP_INF_REDUX_INDEX= vgroups.index(VGROUP_INF_REDUX) + except: + VGROUP_INF_REDUX_INDEX= -1 + + # del vgroups + len_vgroups= len(vgroups) + + + + OLD_MESH_MODE= Blender.Mesh.Mode() + Blender.Mesh.Mode(Blender.Mesh.SelectModes.VERTEX) + + if DO_UV and not me.faceUV: + DO_UV= False + + if DO_VCOL and not me.vertexColors: + DO_VCOL = False + + current_face_count= len(me.faces) + target_face_count= int(current_face_count * REDUX) + # % of the collapseable faces to collapse per pass. + #collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster. + collapse_per_pass= 0.333 # between 0.1 - lots of small nibbles, slow but high q. and 0.9 - big passes and faster. + + """# DEBUG! + if DEBUG: + COUNT= [0] + def rd(): + if COUNT[0]< 330: + COUNT[0]+=1 + return + me.update() + Blender.Window.RedrawAll() + print 'Press key for next, count "%s"' % COUNT[0] + try: input() + except KeyboardInterrupt: + raise "Error" + except: + pass + + COUNT[0]+=1 + """ + + class collapseEdge(object): + __slots__ = 'length', 'key', 'faces', 'collapse_loc', 'v1', 'v2','uv1', 'uv2', 'col1', 'col2', 'collapse_weight' + def __init__(self, ed): + self.init_from_edge(ed) # So we can re-use the classes without using more memory. + + def init_from_edge(self, ed): + self.key= ed.key + self.length= ed.length + self.faces= [] + self.v1= ed.v1 + self.v2= ed.v2 + if DO_UV or DO_VCOL: + self.uv1= [] + self.uv2= [] + self.col1= [] + self.col2= [] + + # self.collapse_loc= None # new collapse location. + # Basic weighting. + #self.collapse_weight= self.length * (1+ ((ed.v1.no-ed.v2.no).length**2)) + self.collapse_weight= 1.0 + + def collapse_locations(self, w1, w2): + ''' + Generate a smart location for this edge to collapse to + w1 and w2 are vertex location bias + ''' + + v1co= self.v1.co + v2co= self.v2.co + v1no= self.v1.no + v2no= self.v2.no + + # Basic operation, works fine but not as good as predicting the best place. + #between= ((v1co*w1) + (v2co*w2)) + #self.collapse_loc= between + + # normalize the weights of each vert - se we can use them as scalers. + wscale= w1+w2 + if not wscale: # no scale? + w1=w2= 0.5 + else: + w1/=wscale + w2/=wscale + + length= self.length + between= MidpointVecs(v1co, v2co) + + # Collapse + # new_location = between # Replace tricky code below. this code predicts the best collapse location. + + # Make lines at right angles to the normals- these 2 lines will intersect and be + # the point of collapsing. + + # Enlarge so we know they intersect: self.length*2 + cv1= CrossVecs(v1no, CrossVecs(v1no, v1co-v2co)) + cv2= CrossVecs(v2no, CrossVecs(v2no, v2co-v1co)) + + # Scale to be less then the edge lengths. + cv2.length = cv1.length = 1 + + cv1 = cv1 * (length* 0.4) + cv2 = cv2 * (length* 0.4) + + smart_offset_loc= between + (cv1 + cv2) + + # Now we need to blend between smart_offset_loc and w1/w2 + # you see were blending between a vert and the edges midpoint, so we cant use a normal weighted blend. + if w1 > 0.5: # between v1 and smart_offset_loc + #self.collapse_loc= v1co*(w2+0.5) + smart_offset_loc*(w1-0.5) + w2*=2 + w1= 1-w2 + new_loc_smart= v1co*w1 + smart_offset_loc*w2 + else: # w between v2 and smart_offset_loc + w1*=2 + w2= 1-w1 + new_loc_smart= v2co*w2 + smart_offset_loc*w1 + + if new_loc_smart.x != new_loc_smart.x: # NAN LOCATION, revert to between + new_loc_smart= None + + return new_loc_smart, between, v1co*0.99999 + v2co*0.00001, v1co*0.00001 + v2co*0.99999 + + + class collapseFace(object): + __slots__ = 'verts', 'normal', 'area', 'index', 'orig_uv', 'orig_col', 'uv', 'col' # , 'collapse_edge_count' + def __init__(self, f): + self.init_from_face(f) + + def init_from_face(self, f): + self.verts= f.v + self.normal= f.no + self.area= f.area + self.index= f.index + if DO_UV: + self.orig_uv= [uv_key(uv) for uv in f.uv] + self.uv= f.uv + if DO_VCOL: + self.orig_col= [col_key(col) for col in f.col] + self.col= f.col + + collapse_edges= collapse_faces= None + + # So meshCalcNormals can avoid making a new list all the time. + reuse_vertNormals= [ Vector() for v in xrange(len(me.verts)) ] + + while target_face_count <= len(me.faces): + BPyMesh.meshCalcNormals(me, reuse_vertNormals) + + if DO_WEIGHTS: + #groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) + groupNames, vWeightList= BPyMesh.meshWeight2List(me) + + # THIS CRASHES? Not anymore. + verts= list(me.verts) + edges= list(me.edges) + faces= list(me.faces) + + # THIS WORKS + #verts= me.verts + #edges= me.edges + #faces= me.faces + + # if DEBUG: DOUBLE_CHECK= [0]*len(verts) + me.sel= False + + if not collapse_faces: # Initialize the list. + collapse_faces= [collapseFace(f) for f in faces] + collapse_edges= [collapseEdge(ed) for ed in edges] + else: + for i, ed in enumerate(edges): + collapse_edges[i].init_from_edge(ed) + + # Strip the unneeded end off the list + collapse_edges[i+1:]= [] + + for i, f in enumerate(faces): + collapse_faces[i].init_from_face(f) + + # Strip the unneeded end off the list + collapse_faces[i+1:]= [] + + + collapse_edges_dict= dict( [(ced.key, ced) for ced in collapse_edges] ) + + # Store verts edges. + vert_ed_users= [[] for i in xrange(len(verts))] + for ced in collapse_edges: + vert_ed_users[ced.key[0]].append(ced) + vert_ed_users[ced.key[1]].append(ced) + + # Store face users + vert_face_users= [[] for i in xrange(len(verts))] + + # Have decieded not to use this. area is better. + #face_perim= [0.0]* len(me.faces) + + for ii, cfa in enumerate(collapse_faces): + for i, v1 in enumerate(cfa.verts): + vert_face_users[v1.index].append( (i,cfa) ) + + # add the uv coord to the vert + v2 = cfa.verts[i-1] + i1= v1.index + i2= v2.index + + if i1>i2: ced= collapse_edges_dict[i2,i1] + else: ced= collapse_edges_dict[i1,i2] + + ced.faces.append(cfa) + if DO_UV or DO_VCOL: + # if the edge is flipped from its order in the face then we need to flip the order indicies. + if cfa.verts[i]==ced.v1: i1,i2 = i, i-1 + else: i1,i2 = i-1, i + + if DO_UV: + ced.uv1.append( cfa.orig_uv[i1] ) + ced.uv2.append( cfa.orig_uv[i2] ) + + if DO_VCOL: + ced.col1.append( cfa.orig_col[i1] ) + ced.col2.append( cfa.orig_col[i2] ) + + + # PERIMITER + #face_perim[ii]+= ced.length + + + + # How weight the verts by the area of their faces * the normal difference. + # when the edge collapses, to vert weights are taken into account + + vert_weights= [0.5] * len(verts) + + for ii, vert_faces in enumerate(vert_face_users): + for f in vert_faces: + try: + no_ang= (Ang(verts[ii].no, f[1].normal)/180) * f[1].area + except: + no_ang= 1.0 + + vert_weights[ii] += no_ang + + # Use a vertex group as a weighting. + if VGROUP_INF_REDUX!=None: + + # Get Weights from a vgroup. + """ + vert_weights_map= [1.0] * len(verts) + for i, wd in enumerate(vWeightDict): + try: vert_weights_map[i]= 1+(wd[VGROUP_INF_REDUX] * VGROUP_INF_WEIGHT) + except: pass + """ + vert_weights_map= [1+(wl[VGROUP_INF_REDUX_INDEX]*VGROUP_INF_WEIGHT) for wl in vWeightList ] + + + # BOUNDRY CHECKING AND WEIGHT EDGES. CAN REMOVE + # Now we know how many faces link to an edge. lets get all the boundry verts + if BOUNDRY_WEIGHT > 0: + verts_boundry= [1] * len(verts) + #for ed_idxs, faces_and_uvs in edge_faces_and_uvs.iteritems(): + for ced in collapse_edges: + if len(ced.faces) < 2: + for key in ced.key: # only ever 2 key indicies. + verts_boundry[key]= 2 + + for ced in collapse_edges: + b1= verts_boundry[ced.key[0]] + b2= verts_boundry[ced.key[1]] + if b1 != b2: + # Edge has 1 boundry and 1 non boundry vert. weight higher + ced.collapse_weight= BOUNDRY_WEIGHT + #elif b1==b2==2: # if both are on a seam then weigh half as bad. + # ced.collapse_weight= ((BOUNDRY_WEIGHT-1)/2) +1 + # weight the verts by their boundry status + del b1 + del b2 + + for ii, boundry in enumerate(verts_boundry): + if boundry==2: + vert_weights[ii] *= BOUNDRY_WEIGHT + + vert_collapsed= verts_boundry + del verts_boundry + else: + vert_collapsed= [1] * len(verts) + + + + + # Best method, no quick hacks here, Correction. Should be the best but needs tweaks. + def ed_set_collapse_error(ced): + # Use the vertex weights to bias the new location. + new_locs= ced.collapse_locations(vert_weights[ced.key[0]], vert_weights[ced.key[1]]) + + + # Find the connecting faces of the 2 verts. + i1, i2= ced.key + test_faces= set() + for i in (i1,i2): # faster then LC's + for f in vert_face_users[i]: + test_faces.add(f[1].index) + for f in ced.faces: + test_faces.remove(f.index) + + + v1_orig= Vector(ced.v1.co) + v2_orig= Vector(ced.v2.co) + + def test_loc(new_loc): + ''' + Takes a location and tests the error without changing anything + ''' + new_weight= ced.collapse_weight + ced.v1.co= ced.v2.co= new_loc + + new_nos= [faces[i].no for i in test_faces] + + # So we can compare the befire and after normals + ced.v1.co= v1_orig + ced.v2.co= v2_orig + + # now see how bad the normals are effected + angle_diff= 1.0 + + for ii, i in enumerate(test_faces): # local face index, global face index + cfa= collapse_faces[i] # this collapse face + try: + # can use perim, but area looks better. + if FACE_AREA_WEIGHT: + # Psudo code for wrighting + # angle_diff= The before and after angle difference between the collapsed and un-collapsed face. + # ... devide by 180 so the value will be between 0 and 1.0 + # ... add 1 so we can use it as a multiplyer and not make the area have no eefect (below) + # area_weight= The faces original area * the area weight + # ... add 1.0 so a small area face dosent make the angle_diff have no effect. + # + # Now multiply - (angle_diff * area_weight) + # ... The weight will be a minimum of 1.0 - we need to subtract this so more faces done give the collapse an uneven weighting. + + angle_diff+= ((1+(Ang(cfa.normal, new_nos[ii])/180)) * (1+(cfa.area * FACE_AREA_WEIGHT))) -1 # 4 is how much to influence area + else: + angle_diff+= (Ang(cfa.normal), new_nos[ii])/180 + + except: + pass + + + # This is very arbirary, feel free to modify + try: no_ang= (Ang(ced.v1.no, ced.v2.no)/180) + 1 + except: no_ang= 2.0 + + # do *= because we face the boundry weight to initialize the weight. 1.0 default. + new_weight *= ((no_ang * ced.length) * (1-(1/angle_diff)))# / max(len(test_faces), 1) + return new_weight + # End testloc + + + # Test the collapse locatons + collapse_loc_best= None + collapse_weight_best= 1000000000 + ii= 0 + for collapse_loc in new_locs: + if collapse_loc: # will only ever fail if smart loc is NAN + test_weight= test_loc(collapse_loc) + if test_weight < collapse_weight_best: + iii= ii + collapse_weight_best = test_weight + collapse_loc_best= collapse_loc + ii+=1 + + ced.collapse_loc= collapse_loc_best + ced.collapse_weight= collapse_weight_best + + + # are we using a weight map + if VGROUP_INF_REDUX: + v= vert_weights_map[i1]+vert_weights_map[i2] + ced.collapse_weight*= v + # End collapse Error + + # We can calculate the weights on __init__ but this is higher qualuity. + for ced in collapse_edges: + if ced.faces: # dont collapse faceless edges. + ed_set_collapse_error(ced) + + # Wont use the function again. + del ed_set_collapse_error + # END BOUNDRY. Can remove + + # sort by collapse weight + try: collapse_edges.sort(key = lambda ced: ced.collapse_weight) # edges will be used for sorting + except: collapse_edges.sort(lambda ced1, ced2: cmp(ced1.collapse_weight, ced2.collapse_weight)) # edges will be used for sorting + + + vert_collapsed= [0]*len(verts) + + collapse_edges_to_collapse= [] + + # Make a list of the first half edges we can collapse, + # these will better edges to remove. + collapse_count=0 + for ced in collapse_edges: + if ced.faces: + i1, i2= ced.key + # Use vert selections + if vert_collapsed[i1] or vert_collapsed[i2]: + pass + else: + # Now we know the verts havnyt been collapsed. + vert_collapsed[i2]= vert_collapsed[i1]= 1 # Dont collapse again. + collapse_count+=1 + collapse_edges_to_collapse.append(ced) + + # Get a subset of the entire list- the first "collapse_per_pass", that are best to collapse. + if collapse_count > 4: + collapse_count = int(collapse_count*collapse_per_pass) + else: + collapse_count = len(collapse_edges) + # We know edge_container_list_collapse can be removed. + for ced in collapse_edges_to_collapse: + """# DEBUG! + if DEBUG: + if DOUBLE_CHECK[ced.v1.index] or\ + DOUBLE_CHECK[ced.v2.index]: + raise 'Error' + else: + DOUBLE_CHECK[ced.v1.index]=1 + DOUBLE_CHECK[ced.v2.index]=1 + + tmp= (ced.v1.co+ced.v2.co)*0.5 + Blender.Window.SetCursorPos(tmp.x, tmp.y, tmp.z) + Blender.Window.RedrawAll() + """ + + # Chech if we have collapsed our quota. + collapse_count-=1 + if not collapse_count: + break + + current_face_count -= len(ced.faces) + + # Find and assign the real weights based on collapse loc. + + # Find the weights from the collapse error + if DO_WEIGHTS or DO_UV or DO_VCOL: + i1, i2= ced.key + # Dont use these weights since they may not have been used to make the collapse loc. + #w1= vert_weights[i1] + #w2= vert_weights[i2] + w1= (ced.v2.co-ced.collapse_loc).length + w2= (ced.v1.co-ced.collapse_loc).length + + # Normalize weights + wscale= w1+w2 + if not wscale: # no scale? + w1=w2= 0.5 + else: + w1/= wscale + w2/= wscale + + + # Interpolate the bone weights. + if DO_WEIGHTS: + + # add verts vgroups to eachother + wl1= vWeightList[i1] # v1 weight dict + wl2= vWeightList[i2] # v2 weight dict + for group_index in xrange(len_vgroups): + wl1[group_index]= wl2[group_index]= (wl1[group_index]*w1) + (wl2[group_index]*w2) + # Done finding weights. + + + + if DO_UV or DO_VCOL: + # Handel UV's and vert Colors! + for v, my_weight, other_weight, edge_my_uvs, edge_other_uvs, edge_my_cols, edge_other_cols in (\ + (ced.v1, w1, w2, ced.uv1, ced.uv2, ced.col1, ced.col2),\ + (ced.v2, w2, w1, ced.uv2, ced.uv1, ced.col2, ced.col1)\ + ): + uvs_mixed= [ uv_key_mix(edge_my_uvs[iii], edge_other_uvs[iii], my_weight, other_weight) for iii in xrange(len(edge_my_uvs)) ] + cols_mixed= [ col_key_mix(edge_my_cols[iii], edge_other_cols[iii], my_weight, other_weight) for iii in xrange(len(edge_my_cols)) ] + + for face_vert_index, cfa in vert_face_users[v.index]: + if len(cfa.verts)==3 and cfa not in ced.faces: # if the face is apart of this edge then dont bother finding the uvs since the face will be removed anyway. + + if DO_UV: + # UV COORDS + uvk= cfa.orig_uv[face_vert_index] + try: + tex_index= edge_my_uvs.index(uvk) + except: + tex_index= None + """ # DEBUG! + if DEBUG: + print 'not found', uvk, 'in', edge_my_uvs, 'ed index', ii, '\nwhat about', edge_other_uvs + """ + if tex_index != None: # This face uses a uv in the collapsing face. - do a merge + other_uv= edge_other_uvs[tex_index] + uv_vec= cfa.uv[face_vert_index] + uv_vec.x, uv_vec.y= uvs_mixed[tex_index] + + # TEXFACE COLORS + if DO_VCOL: + colk= cfa.orig_col[face_vert_index] + try: tex_index= edge_my_cols.index(colk) + except: pass + if tex_index != None: + other_col= edge_other_cols[tex_index] + col_ob= cfa.col[face_vert_index] + col_ob.r, col_ob.g, col_ob.b= cols_mixed[tex_index] + + # DEBUG! if DEBUG: rd() + + # Execute the collapse + ced.v1.sel= ced.v2.sel= True # Select so remove doubles removed the edges and faces that use it + ced.v1.co= ced.v2.co= ced.collapse_loc + + # DEBUG! if DEBUG: rd() + if current_face_count <= target_face_count: + break + + # Copy weights back to the mesh before we remove doubles. + if DO_WEIGHTS: + #BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) + BPyMesh.list2MeshWeight(me, groupNames, vWeightList) + + doubles= me.remDoubles(0.0001) + current_face_count= len(me.faces) + + if current_face_count <= target_face_count or not doubles: # not doubles shoule never happen. + break + + me.update() + Blender.Mesh.Mode(OLD_MESH_MODE) + + +# Example usage +def main(): + Blender.Window.EditMode(0) + scn= bpy.data.scenes.active + active_ob= scn.objects.active + t= Blender.sys.time() + redux(active_ob, 0.5) + print '%.4f' % (Blender.sys.time()-t) + +if __name__=='__main__': + main() diff --git a/release/scripts/bpymodules/BPyMessages.py b/release/scripts/bpymodules/BPyMessages.py new file mode 100644 index 00000000000..0ff8e178ac1 --- /dev/null +++ b/release/scripts/bpymodules/BPyMessages.py @@ -0,0 +1,59 @@ +from Blender import Draw, sys +def Error_NoMeshSelected(): + Draw.PupMenu('Error%t|No mesh objects selected') +def Error_NoActive(): + Draw.PupMenu('Error%t|No active object') +def Error_NoMeshActive(): + Draw.PupMenu('Error%t|Active object is not a mesh') +def Error_NoMeshUvSelected(): + Draw.PupMenu('Error%t|No mesh objects with texface selected') +def Error_NoMeshUvActive(): + Draw.PupMenu('Error%t|Active object is not a mesh with texface') +def Error_NoMeshMultiresEdit(): + Draw.PupMenu('Error%t|Unable to complete action with multires enabled') + +# File I/O messages +def Error_NoFile(path): + '''True if file missing, False if files there + + Use simply by doing... + if Error_NoFile(path): return + ''' + if not sys.exists(sys.expandpath(path)): + Draw.PupMenu("Error%t|Can't open file: " + path) + return True + return False + +def Error_NoDir(path): + '''True if dirs missing, False if dirs there + + Use simply by doing... + if Error_NoDir(path): return + ''' + if not sys.exists(sys.expandpath(path)): + Draw.PupMenu("Error%t|Path does not exist: " + path) + return True + return False + + +def Warning_MeshDistroyLayers(mesh): + '''Returns true if we can continue to edit the mesh, warn when using NMesh''' + if len(mesh.getUVLayerNames()) >1 and len(mesh.getColorLayerNames()) >1: + return True + + ret = Draw.PupMenu('Warning%t|This script will distroy inactive UV and Color layers, OK?') + if ret == -1: + return False + + return True + +def Warning_SaveOver(path): + '''Returns - True to save, False dont save''' + if sys.exists(sys.expandpath(path)): + ret= Draw.PupMenu('Save over%t|' + path) + if ret == -1: + return False + + return True + + diff --git a/release/scripts/bpymodules/BPyNMesh.py b/release/scripts/bpymodules/BPyNMesh.py new file mode 100644 index 00000000000..043d8514db9 --- /dev/null +++ b/release/scripts/bpymodules/BPyNMesh.py @@ -0,0 +1,48 @@ +# $Id$ +# +# -------------------------------------------------------------------------- +# BPyNMesh.py version 0.1 +# -------------------------------------------------------------------------- +# helper functions to be used by other scripts +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +# -------------------------------------------------------------------------- +# "Apply size and rotation" function by Jonas Petersen +# -------------------------------------------------------------------------- +# This function does (hopefully) exactly what the +# "Apply size and rotation" command does (CTRL-A in Object Mode). +def ApplySizeAndRotation(obj): + if obj.getType() != "Mesh": return + if obj.SizeX==1.0 and obj.SizeY==1.0 and obj.SizeZ==1.0 and obj.RotX == 0.0 and obj.RotY == 0.0 and obj.RotZ == 0.0: return + mesh = obj.getData() + matrix = obj.matrix + v = [0,0,0] + for vert in mesh.verts: + co = vert.co + v[0] = co[0]*matrix[0][0] + co[1]*matrix[1][0] + co[2]*matrix[2][0] + v[1] = co[0]*matrix[0][1] + co[1]*matrix[1][1] + co[2]*matrix[2][1] + v[2] = co[0]*matrix[0][2] + co[1]*matrix[1][2] + co[2]*matrix[2][2] + co[0], co[1], co[2] = v + obj.SizeX = obj.SizeY = obj.SizeZ = 1.0 + obj.RotX = obj.RotY = obj.RotZ = 0.0 + mesh.update() + diff --git a/release/scripts/bpymodules/BPyObject.py b/release/scripts/bpymodules/BPyObject.py new file mode 100644 index 00000000000..54ff949218d --- /dev/null +++ b/release/scripts/bpymodules/BPyObject.py @@ -0,0 +1,108 @@ +import Blender + +def getObjectArmature(ob): + ''' + This returns the first armature the mesh uses. + remember there can be more then 1 armature but most people dont do that. + ''' + if ob.type != 'Mesh': + return None + + arm = ob.parent + if arm and arm.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE: + return arm + + for m in ob.modifiers: + if m.type== Blender.Modifier.Types.ARMATURE: + arm = m[Blender.Modifier.Settings.OBJECT] + if arm: + return arm + + return None + + +def getDerivedObjects(ob, PARTICLES= True): + ''' + Takes an objects and returnes a list of (ob, maxrix4x4) pairs + that are derived from this object - + This will include the object its self if it would be rendered. + all dupli's for eg are not rendered themselves. + + currently supports + * dupligroups + * dupliverts + * dupliframes + * static particles as a mesh + + it is possible this function will return an empty list. + ''' + + ob_mtx_pairs = ob.DupObjects + effects= ob.effects + + # Ignore self if were a dupli* or our parent is a duplivert. + if ob.enableDupFrames or ob.enableDupGroup or ob.enableDupVerts: + pass + else: + parent= ob.parent + if parent and parent.enableDupVerts: + pass + else: + if effects and (not effects[0].flag & Blender.Effect.Flags.EMESH): + # Particles mesh wont render + pass + else: + ob_mtx_pairs.append((ob, ob.matrixWorld)) + + + if PARTICLES: + type_vec= type(Blender.Mathutils.Vector()) + type_tp= type((0,0)) + type_ls= type([]) + + # TODO, particles per child object. + # TODO Support materials + me= Blender.Mesh.New() + for eff in effects: + par= eff.getParticlesLoc() + + if par: + type_par= type(par[0]) + + if type_par == type_vec: + # point particles + me.verts.extend(par) + + elif type_par == type_tp: + # edge pairs + start_index= len(me.verts) + me.verts.extend([v for p in par for v in p]) + me.edges.extend( [(i, i+1) for i in xrange(start_index, start_index + len(par) - 1 )] ) + + elif type_par == type_ls: + # lines of edges + start_index= len(me.verts) + me.verts.extend([v for line in par for v in line]) + + edges= [] + for line in par: + edges.extend( [(i,i+1) for i in xrange(start_index, start_index+len(line)-1) ] ) + start_index+= len(line) + + me.edges.extend(edges) + + if me.verts: + # If we have verts, then add the mesh + ob_par = Blender.Object.New('Mesh') + ob_par.link( me ) + + LOOSE= Blender.Mesh.EdgeFlags.LOOSE + for ed in me.edges: + ed.flag |= LOOSE + + # Particle's are in worldspace so an identity matrix is fine. + ob_mtx_pairs.append( (ob_par, Blender.Mathutils.Matrix()) ) + + return ob_mtx_pairs + + diff --git a/release/scripts/bpymodules/BPyRegistry.py b/release/scripts/bpymodules/BPyRegistry.py new file mode 100644 index 00000000000..f0d6da82d52 --- /dev/null +++ b/release/scripts/bpymodules/BPyRegistry.py @@ -0,0 +1,258 @@ +# -------------------------------------------------------------------------- +# Module BPyRegistry version 0.1 +# Helper functions to store / restore configuration data. +# -------------------------------------------------------------------------- +# $Id$ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# -------------------------------------------------------------------------- + +# The Registry is a Python dictionary that is kept in Blender for as long as +# the program is running, where scripts can store / restore persistent data +# (data that is not lost when the script exits). This module provides +# functions to save and restore Registry entries as config data in the +# bpydata/config folder. Scripts just need to give an extra parameter to +# the Blender.Registry.Get/Set() functions to have their data automatically +# saved and restored when needed. +# +# Note: entries starting with an underscore are not saved, so script authors +# can use that fact to define data that is not meant to be stored in a +# config file. Example: data to be passed to another script and references to +# invalid data, like Blender objects and any function or method. +# +# Check the Blender.Registry documentation for more information. + +import Blender +from Blender import Registry, sys as bsys + +_EXT = '.cfg' # file extension for saved config data + +# limits: +#MAX_ITEMS_NUM = 60 # max number of keys per dict and itens per list and tuple +#MAX_STR_LEN = 300 # max string length (remember this is just for config data) + +_CFG_DIR = '' +if Blender.Get('udatadir'): + _CFG_DIR = Blender.sys.join(Blender.Get('udatadir'), 'config') +if not _CFG_DIR or not bsys.exists(_CFG_DIR): + _CFG_DIR = Blender.sys.join(Blender.Get('datadir'), 'config') +if not bsys.exists(_CFG_DIR): + _CFG_DIR = '' + +# to compare against, so we don't write to a cvs tree: +_CVS_SUBPATH = 'release/scripts/bpydata/config/' +if bsys.dirsep == '\\': + _CVS_SUBPATH = _CVS_SUBPATH.replace('/', '\\') + +_KEYS = [k for k in Registry.Keys() if k[0] != '_'] + +# _ITEMS_NUM = 0 + +def _sanitize(o): + "Check recursively that all objects are valid, set invalid ones to None" + + # global MAX_ITEMS_NUM, MAX_STR_LEN, _ITEMS_NUM + + valid_types = [int, float, bool, long, type] + valid_checked_types = [str, unicode] + # Only very simple types are considered valid for configuration data, + # functions, methods and Blender objects (use their names instead) aren't. + + t = type(o) + + if t == dict: + ''' + _ITEMS_NUM += len(o) + if _ITEMS_NUM > MAX_ITEMS_NUM: + return None + ''' + for k, v in o.iteritems(): + o[k] = _sanitize(v) + elif t in [list, tuple]: + ''' + _ITEMS_NUM += len(o) + if _ITEMS_NUM > MAX_ITEMS_NUM: + return None + ''' + return [_sanitize(i) for i in o] + elif t in valid_types: + return o + elif t in valid_checked_types: + ''' + if len(o) > MAX_STR_LEN: + o = o[:MAX_STR_LEN] + ''' + return o + else: return None + + return o + + +def _dict_to_str(name, d): + "Return a pretty-print version of the passed dictionary" + if not d: return 'None' # d can be None if there was no config to pass + + if name: l = ['%s = {' % name] + else: l = ['{'] + #keys = d.keys() + for k,v in d.iteritems(): # .keys() + if type(v) == dict: + l.append("'%s': %s" % (k, _dict_to_str(None, v))) + else: + l.append("'%s': %s," % (k, repr(v))) + if name: l.append('}') + else: l.append('},') + return "\n".join(l) + +_HELP_MSG = """ +Please create a valid scripts config dir tree either by +copying release/scripts/ tree to your dir +or by copying release/scripts/bpydata/ tree to a user +defined scripts dir that you can set in the +User Preferences -> Paths tab -> Python path input box. +""" + +def _check_dir(): + global _CFG_DIR, _CVS_SUBPATH, _HELP_MSG + + if not _CFG_DIR: + errmsg = "scripts config dir not found!\n%s" % _HELP_MSG + raise IOError, errmsg + elif _CFG_DIR.find(_CVS_SUBPATH) > 0: + errmsg = """ +Your scripts config dir:\n%s +seems to reside in your local Blender's cvs tree.\n%s""" % (_CFG_DIR, _HELP_MSG) + raise SystemError, errmsg + else: return + + +# API: + +BPY_KEY_MISSING = 0 +BPY_KEY_IN_REGISTRY = 1 +BPY_KEY_IN_FILE = 2 + +def HasConfigData (key): + """ + Check if the given key exists, either already loaded in the Registry dict or + as a file in the script data config dir. + @type key: string + @param key: a given key name. + @returns: + - 0: key does not exist; + - 1: key exists in the Registry dict only; + - 2: key exists as a file only; + - 3: key exists in the Registry dict and also as a file. + @note: for readability it's better to check against the constant bitmasks + BPY_KEY_MISSING = 0, BPY_KEY_IN_REGISTRY = 1 and BPY_KEY_IN_FILE = 2. + """ + + fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) + + result = BPY_KEY_MISSING + if key in Registry.Keys(): result |= BPY_KEY_IN_REGISTRY + if bsys.exists(fname): result |= BPY_KEY_IN_FILE + + return result + + +def LoadConfigData (key = None): + """ + Load config data from file(s) to the Registry dictionary. + @type key: string + @param key: a given key name. If None (default), all available keys are + loaded. + @returns: None + """ + + _check_dir() + + import os + + if not key: + files = \ + [bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f.endswith(_EXT)] + else: + files = [] + fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) + if bsys.exists(fname): files.append(fname) + + for p in files: + f = file(p, 'r') + lines = f.readlines() + f.close() + if lines: # Lines may be blank + mainkey = lines[0].split('=')[0].strip() + pysrc = "\n".join(lines) + exec(pysrc) + exec("Registry.SetKey('%s', %s)" % (str(mainkey), mainkey)) + + +def RemoveConfigData (key = None): + """ + Remove this key's config file from the <(u)datadir>/config/ folder. + @type key: string + @param key: the name of the key to be removed. If None (default) all + available config files are deleted. + """ + + _check_dir() + + if not key: + files = \ + [bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f.endswith(_EXT)] + else: + files = [] + fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT)) + if bsys.exists(fname): files.append(fname) + + import os + + for p in files: + os.remove(p) # remove the file(s) + + +def SaveConfigData (key = None): + """ + Save Registry key(s) as file(s) in the <(u)datadir>/config/ folder. + @type key: string + @param key: the name of the key to be saved. If None (default) all + available keys are saved. + """ + + global _KEYS, _CFG_DIR + + _check_dir() + + if key: keys = [key] + else: keys = _KEYS + + for mainkey in keys: + cfgdict = Registry.GetKey(mainkey).copy() + for k in cfgdict: # .keys() + if not k or k[0] == '_': + del cfgdict[k] + + if not cfgdict: continue + + filename = bsys.join(_CFG_DIR, "%s%s" % (mainkey, _EXT)) + f = file(filename, 'w') + output = _dict_to_str(mainkey, _sanitize(cfgdict)) + if output!='None': + f.write(output) + f.close() diff --git a/release/scripts/bpymodules/BPyRender.py b/release/scripts/bpymodules/BPyRender.py new file mode 100644 index 00000000000..e335ee7f6a8 --- /dev/null +++ b/release/scripts/bpymodules/BPyRender.py @@ -0,0 +1,498 @@ +import Blender +from Blender import Scene, sys, Camera, Object, Image +from Blender.Scene import Render +Vector= Blender.Mathutils.Vector + + +def extFromFormat(format): + if format == Render.TARGA: return 'tga' + if format == Render.RAWTGA: return 'tga' + if format == Render.HDR: return 'hdr' + if format == Render.PNG: return 'png' + if format == Render.BMP: return 'bmp' + if format == Render.JPEG: return 'jpg' + if format == Render.HAMX: return 'ham' + if format == Render.TIFF: return 'tif' + if format == Render.CINEON: return 'cine' + if format == Render.DPX: return 'tif' + if format == Render.OPENEXR: return 'exr' + if format == Render.IRIS: return 'rgb' + return '' + + + +def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, camera_matrix= None, format=Render.PNG): + ''' + Takes any number of objects and renders them on the z axis, between x:y-0 and x:y-1 + Usefull for making images from a mesh without per pixel operations + - objects must be alredy placed + - smooth, anti alias True/False + - path renders to a PNG image + - alpha weather to render background as alpha + + returns the blender image + ''' + ext = '.' + extFromFormat(format) + print ext + # remove an extension if its alredy there + if path.lower().endswith(ext): + path= path[:-4] + + path_expand= sys.expandpath(path) + ext + + print path_expand, 'path' + + # Touch the path + try: + f= open(path_expand, 'w') + f.close() + except: + raise 'Error, could not write to path:' + path_expand + + + # RENDER THE FACES. + scn= Scene.GetCurrent() + render_scn= Scene.New() + render_scn.makeCurrent() + render_scn.Layers |= (1<<20)-1 # all layers enabled + + # Add objects into the current scene + for ob in objects: + render_scn.link(ob) + + render_context= render_scn.getRenderingContext() + render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path. + + + render_context.imageSizeX(width) + render_context.imageSizeY(height) + + if smooth: + render_context.enableOversampling(True) + render_context.setOversamplingLevel(16) + else: + render_context.enableOversampling(False) + + render_context.setRenderWinSize(100) + render_context.setImageType(format) + render_context.enableExtensions(True) + #render_context.enableSky() # No alpha needed. + if alpha: + render_context.alphaMode= 1 + render_context.enableRGBAColor() + else: + render_context.alphaMode= 0 + render_context.enableRGBColor() + + render_context.displayMode= 0 # fullscreen + + # New camera and object + render_cam_data= Camera.New('ortho') + render_cam_ob= Object.New('Camera') + render_cam_ob.link(render_cam_data) + render_scn.link(render_cam_ob) + render_scn.objects.camera = render_cam_ob + + render_cam_data.type= 'ortho' + + + + # Position the camera + if camera_matrix: + render_cam_ob.setMatrix(camera_matrix) + # We need to take into account the matrix scaling when setting the size + # so we get the image bounds defined by the matrix + # first get the x and y factors from the matrix. + # To render the correct dimensions we must use the aspy and aspy to force the matrix scale to + # override the aspect enforced by the width and weight. + cent= Vector() * camera_matrix + xvec= Vector(1,0,0) * camera_matrix + yvec= Vector(0,1,0) * camera_matrix + # zvec= Vector(0,0,1) * camera_matrix + xlen = (cent-xvec).length # half height of the image + ylen = (cent-yvec).length # half width of the image + # zlen = (cent-zvec).length # dist to place the camera? - just use the loc for now. + + + # less then 1.0 portrate, 1.0 or more is portrate + asp_cam_mat= xlen/ylen # divide by zero? - possible but scripters fault. + asp_image_res= float(width)/height + #print 'asp quad', asp_cam_mat, 'asp_image', asp_image_res + #print 'xylen', xlen, ylen, 'w/h', width, height + # Setup the aspect + + if asp_cam_mat > asp_image_res: + # camera is wider then image res. + # to make the image wider, reduce the aspy + asp_diff= asp_image_res/asp_cam_mat + min_asp= int(round(asp_diff * 200)) + #print 'X', min_asp + + elif asp_cam_mat < asp_image_res: # asp_cam_mat < asp_image_res + # camera is narrower then image res + # to make the image narrower, reduce the aspx + asp_diff= asp_cam_mat/asp_image_res + min_asp= int(round(asp_diff * 200)) + #print 'Y', min_asp + else: + min_asp= 200 + + # set the camera size + if xlen > ylen: + if asp_cam_mat > asp_image_res: + render_context.aspectX= 200 # get the greatest range possible + render_context.aspectY= min_asp # get the greatest range possible + else: + render_context.aspectY= 200 # get the greatest range possible + render_context.aspectX= min_asp # get the greatest range possible + #print "xlen bigger" + render_cam_data.scale= xlen * 2 + elif xlen < ylen:# ylen is bigger + if asp_cam_mat > asp_image_res: + render_context.aspectX= 200 # get the greatest range possible + render_context.aspectY= min_asp # get the greatest range possible + else: + render_context.aspectY= 200 # get the greatest range possible + render_context.aspectX= min_asp # get the greatest range possible + #print "ylen bigger" + render_cam_data.scale= ylen *2 + else: + # asppect 1:1 + #print 'NOLEN Bigger' + render_cam_data.scale= xlen * 2 + + #print xlen, ylen, 'xlen, ylen' + + else: + if width > height: + min_asp = int((float(height) / width) * 200) + render_context.aspectX= min_asp + render_context.aspectY= 200 + else: + min_asp = int((float(width) / height) * 200) + render_context.aspectX= 200 + render_context.aspectY= min_asp + + + render_cam_data.scale= 1.0 + render_cam_ob.LocZ= 1.0 + render_cam_ob.LocX= 0.5 + render_cam_ob.LocY= 0.5 + + Blender.Window.RedrawAll() + + render_context.threads= 2 # good for dual core cpu's + render_context.render() + render_context.saveRenderedImage(path) + Render.CloseRenderWindow() + #if not B.sys.exists(PREF_IMAGE_PATH_EXPAND): + # raise 'Error!!!' + + scn.makeCurrent() + Scene.Unlink(render_scn) + + # NOW APPLY THE SAVED IMAGE TO THE FACES! + #print PREF_IMAGE_PATH_EXPAND + try: + target_image= Image.Load(path_expand) + return target_image + except: + raise 'Error: Could not render or load the image at path "%s"' % path_expand + return + + + +#-----------------------------------------------------------------------------# +# UV Baking functions, make a picture from mesh(es) uvs # +#-----------------------------------------------------------------------------# + +def mesh2uv(me_s, PREF_SEL_FACES_ONLY=False): + ''' + Converts a uv mapped mesh into a 2D Mesh from UV coords. + returns a triple - + (mesh2d, face_list, col_list) + "mesh" is the new mesh and... + "face_list" is the faces that were used to make the mesh, + "material_list" is a list of materials used by each face + These are in alligned with the meshes faces, so you can easerly copy data between them + + ''' + render_me= Blender.Mesh.New() + render_me.verts.extend( [Vector(0,0,0),] ) # 0 vert uv bugm dummy vert + face_list= [] + material_list= [] + for me in me_s: + me_materials= me.materials + if PREF_SEL_FACES_ONLY: + me_faces= [f for f in me.faces if f.sel] + else: + me_faces= me.faces + + face_list.extend(me_faces) + + # Dittro + if me_materials: + material_list.extend([me_materials[f.mat] for f in me_faces]) + else: + material_list.extend([None]*len(me_faces)) + + # Now add the verts + render_me.verts.extend( [ Vector(uv.x, uv.y, 0) for f in face_list for uv in f.uv ] ) + + # Now add the faces + tmp_faces= [] + vert_offset= 1 + for f in face_list: + tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] ) + vert_offset+= len(f) + + render_me.faces.extend(tmp_faces) + render_me.faceUV=1 + return render_me, face_list, material_list + + +def uvmesh_apply_normals(render_me, face_list): + '''Worldspace normals to vertex colors''' + for i, f in enumerate(render_me.faces): + face_orig= face_list[i] + f_col= f.col + for j, v in enumerate(face_orig): + c= f_col[j] + nx, ny, nz= v.no + c.r= int((nx+1)*128)-1 + c.g= int((ny+1)*128)-1 + c.b= int((nz+1)*128)-1 + +def uvmesh_apply_image(render_me, face_list): + '''Copy the image and uvs from the original faces''' + for i, f in enumerate(render_me.faces): + f.uv= face_list[i].uv + f.image= face_list[i].image + + +def uvmesh_apply_vcol(render_me, face_list): + '''Copy the vertex colors from the original faces''' + for i, f in enumerate(render_me.faces): + face_orig= face_list[i] + f_col= f.col + for j, c_orig in enumerate(face_orig.col): + c= f_col[j] + c.r= c_orig.r + c.g= c_orig.g + c.b= c_orig.b + +def uvmesh_apply_matcol(render_me, material_list): + '''Get the vertex colors from the original materials''' + for i, f in enumerate(render_me.faces): + mat_orig= material_list[i] + f_col= f.col + if mat_orig: + for c in f_col: + c.r= int(mat_orig.R*255) + c.g= int(mat_orig.G*255) + c.b= int(mat_orig.B*255) + else: + for c in f_col: + c.r= 255 + c.g= 255 + c.b= 255 + +def uvmesh_apply_col(render_me, color): + '''Get the vertex colors from the original materials''' + r,g,b= color + for i, f in enumerate(render_me.faces): + f_col= f.col + for c in f_col: + c.r= r + c.g= g + c.b= b + + +def vcol2image(me_s,\ + PREF_IMAGE_PATH,\ + PREF_IMAGE_SIZE,\ + PREF_IMAGE_BLEED,\ + PREF_IMAGE_SMOOTH,\ + PREF_IMAGE_WIRE,\ + PREF_IMAGE_WIRE_INVERT,\ + PREF_IMAGE_WIRE_UNDERLAY,\ + PREF_USE_IMAGE,\ + PREF_USE_VCOL,\ + PREF_USE_MATCOL,\ + PREF_USE_NORMAL,\ + PREF_USE_TEXTURE,\ + PREF_SEL_FACES_ONLY): + + + def rnd_mat(): + render_mat= Blender.Material.New() + mode= render_mat.mode + + # Dont use lights ever + mode |= Blender.Material.Modes.SHADELESS + + if PREF_IMAGE_WIRE: + # Set the wire color + if PREF_IMAGE_WIRE_INVERT: + render_mat.rgbCol= (1,1,1) + else: + render_mat.rgbCol= (0,0,0) + + mode |= Blender.Material.Modes.WIRE + if PREF_USE_VCOL or PREF_USE_MATCOL or PREF_USE_NORMAL: # both vcol and material color use vertex cols to avoid the 16 max limit in materials + mode |= Blender.Material.Modes.VCOL_PAINT + if PREF_USE_IMAGE: + mode |= Blender.Material.Modes.TEXFACE + + # Copy back the mode + render_mat.mode |= mode + return render_mat + + + render_me, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY) + + # Normals exclude all others + if PREF_USE_NORMAL: + uvmesh_apply_normals(render_me, face_list) + else: + if PREF_USE_IMAGE: + uvmesh_apply_image(render_me, face_list) + uvmesh_apply_vcol(render_me, face_list) + + elif PREF_USE_VCOL: + uvmesh_apply_vcol(render_me, face_list) + + elif PREF_USE_MATCOL: + uvmesh_apply_matcol(render_me, material_list) + + elif PREF_USE_TEXTURE: + # if we have more then 16 materials across all the mesh objects were stuffed :/ + # get unique materials + tex_unique_materials= dict([(mat.name, mat) for mat in material_list]).values()[:16] # just incase we have more then 16 + tex_me= Blender.Mesh.New() + + # Backup the original shadless setting + tex_unique_materials_shadeless= [ mat.mode & Blender.Material.Modes.SHADELESS for mat in tex_unique_materials ] + + # Turn shadeless on + for mat in tex_unique_materials: + mat.mode |= Blender.Material.Modes.SHADELESS + + # Assign materials + render_me.materials= tex_unique_materials + + + + tex_material_indicies= dict([(mat.name, i) for i, mat in enumerate(tex_unique_materials)]) + + tex_me.verts.extend([Vector(0,0,0),]) # dummy + tex_me.verts.extend( [ Vector(v.co) for f in face_list for v in f ] ) + + # Now add the faces + tmp_faces= [] + vert_offset= 1 + for f in face_list: + tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] ) + vert_offset+= len(f) + + tex_me.faces.extend(tmp_faces) + + # Now we have the faces, put materials and normal, uvs into the mesh + if len(tex_me.faces) != len(face_list): + # Should never happen + raise "Error face length mismatch" + + # Copy data to the mesh that could be used as texture coords + for i, tex_face in enumerate(tex_me.faces): + orig_face= face_list[i] + + # Set the material index + try: + render_face.mat= tex_material_indicies[ material_list[i].name ] + except: + # more then 16 materials + pass + + + # set the uvs on the texmesh mesh + tex_face.uv= orig_face.uv + + orig_face_v= orig_face.v + # Set the normals + for j, v in enumerate(tex_face): + v.no= orig_face_v[j].no + + # Set the texmesh + render_me.texMesh= tex_me + # END TEXMESH + + + # Handel adding objects + render_ob= Blender.Object.New('Mesh') + render_ob.link(render_me) + + if not PREF_USE_TEXTURE: # textures use the original materials + render_me.materials= [rnd_mat()] + + + obs= [render_ob] + + + if PREF_IMAGE_WIRE_UNDERLAY: + # Make another mesh with the material colors + render_me_under, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY) + + uvmesh_apply_matcol(render_me_under, material_list) + + # Handel adding objects + render_ob= Blender.Object.New('Mesh') + render_ob.link(render_me_under) + render_ob.LocZ= -0.01 + + # Add material and disable wire + mat= rnd_mat() + mat.rgbCol= 1,1,1 + mat.alpha= 0.5 + mat.mode &= ~Blender.Material.Modes.WIRE + mat.mode |= Blender.Material.Modes.VCOL_PAINT + + render_me_under.materials= [mat] + + obs.append(render_ob) + + elif PREF_IMAGE_BLEED and not PREF_IMAGE_WIRE: + # EVIL BLEEDING CODE!! - Just do copys of the mesh and place behind. Crufty but better then many other methods I have seen. - Cam + BLEED_PIXEL= 1.0/PREF_IMAGE_SIZE + z_offset= 0.0 + for i in xrange(PREF_IMAGE_BLEED): + for diag1, diag2 in ((-1,-1),(-1,1),(1,-1),(1,1), (1,0), (0,1), (-1,0), (0, -1)): # This line extends the object in 8 different directions, top avoid bleeding. + + render_ob= Blender.Object.New('Mesh') + render_ob.link(render_me) + + render_ob.LocX= (i+1)*diag1*BLEED_PIXEL + render_ob.LocY= (i+1)*diag2*BLEED_PIXEL + render_ob.LocZ= -z_offset + + obs.append(render_ob) + z_offset += 0.01 + + + + image= imageFromObjectsOrtho(obs, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_IMAGE_SIZE, PREF_IMAGE_SMOOTH) + + # Clear from memory as best as we can + render_me.verts= None + + if PREF_IMAGE_WIRE_UNDERLAY: + render_me_under.verts= None + + if PREF_USE_TEXTURE: + tex_me.verts= None + # Restire Shadeless setting + for i, mat in enumerate(tex_unique_materials): + # we know there all on so turn it off of its not set + if not tex_unique_materials_shadeless[i]: + mat.mode &= ~Blender.Material.Modes.SHADELESS + + return image diff --git a/release/scripts/bpymodules/BPySys.py b/release/scripts/bpymodules/BPySys.py new file mode 100644 index 00000000000..594264fad84 --- /dev/null +++ b/release/scripts/bpymodules/BPySys.py @@ -0,0 +1,14 @@ + +## This was used to make V, but faster not to do all that +##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_' +##v = range(255) +##for c in valid: v.remove(ord(c)) +v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,58,59,60,61,62,63,64,91,92,93,94,96,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254] +invalid = ''.join([chr(i) for i in v]) +## del v, c, i, valid +del v, i + +def cleanName(name): + for ch in invalid: name = name.replace(ch, '_') + return name + diff --git a/release/scripts/bpymodules/BPyWindow.py b/release/scripts/bpymodules/BPyWindow.py new file mode 100644 index 00000000000..f48f5dfc0ad --- /dev/null +++ b/release/scripts/bpymodules/BPyWindow.py @@ -0,0 +1,206 @@ +import Blender +from Blender import Mathutils, Window, Scene, Draw, Mesh +from Blender.Mathutils import CrossVecs, Matrix, Vector, Intersect + +# DESCRIPTION: +# screen_x, screen_y the origin point of the pick ray +# it is either the mouse location +# localMatrix is used if you want to have the returned values in an objects localspace. +# this is usefull when dealing with an objects data such as verts. +# or if useMid is true, the midpoint of the current 3dview +# returns +# Origin - the origin point of the pick ray +# Direction - the direction vector of the pick ray +# in global coordinates +epsilon = 1e-3 # just a small value to account for floating point errors + +def mouseViewRay(screen_x, screen_y, localMatrix=None, useMid = False): + + # Constant function variables + p = mouseViewRay.p + d = mouseViewRay.d + + for win3d in Window.GetScreenInfo(Window.Types.VIEW3D): # we search all 3dwins for the one containing the point (screen_x, screen_y) (could be the mousecoords for example) + win_min_x, win_min_y, win_max_x, win_max_y = win3d['vertices'] + # calculate a few geometric extents for this window + + win_mid_x = (win_max_x + win_min_x + 1.0) * 0.5 + win_mid_y = (win_max_y + win_min_y + 1.0) * 0.5 + win_size_x = (win_max_x - win_min_x + 1.0) * 0.5 + win_size_y = (win_max_y - win_min_y + 1.0) * 0.5 + + #useMid is for projecting the coordinates when we subdivide the screen into bins + if useMid: # == True + screen_x = win_mid_x + screen_y = win_mid_y + + # if the given screencoords (screen_x, screen_y) are within the 3dwin we fount the right one... + if (win_max_x > screen_x > win_min_x) and ( win_max_y > screen_y > win_min_y): + # first we handle all pending events for this window (otherwise the matrices might come out wrong) + Window.QHandle(win3d['id']) + + # now we get a few matrices for our window... + # sorry - i cannot explain here what they all do + # - if you're not familiar with all those matrices take a look at an introduction to OpenGL... + pm = Window.GetPerspMatrix() # the prespective matrix + pmi = Matrix(pm); pmi.invert() # the inverted perspective matrix + + if (1.0 - epsilon < pmi[3][3] < 1.0 + epsilon): + # pmi[3][3] is 1.0 if the 3dwin is in ortho-projection mode (toggled with numpad 5) + hms = mouseViewRay.hms + ortho_d = mouseViewRay.ortho_d + + # ortho mode: is a bit strange - actually there's no definite location of the camera ... + # but the camera could be displaced anywhere along the viewing direction. + + ortho_d.x, ortho_d.y, ortho_d.z = Window.GetViewVector() + ortho_d.w = 0 + + # all rays are parallel in ortho mode - so the direction vector is simply the viewing direction + #hms.x, hms.y, hms.z, hms.w = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0 + hms[:] = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0 + + # these are the homogenious screencoords of the point (screen_x, screen_y) ranging from -1 to +1 + p=(hms*pmi) + (1000*ortho_d) + p.resize3D() + d[:] = ortho_d[:3] + + + # Finally we shift the position infinitely far away in + # the viewing direction to make sure the camera if outside the scene + # (this is actually a hack because this function + # is used in sculpt_mesh to initialize backface culling...) + else: + # PERSPECTIVE MODE: here everything is well defined - all rays converge at the camera's location + vmi = Matrix(Window.GetViewMatrix()); vmi.invert() # the inverse viewing matrix + fp = mouseViewRay.fp + + dx = pm[3][3] * (((screen_x-win_min_x)/win_size_x)-1.0) - pm[3][0] + dy = pm[3][3] * (((screen_y-win_min_y)/win_size_y)-1.0) - pm[3][1] + + fp[:] = \ + pmi[0][0]*dx+pmi[1][0]*dy,\ + pmi[0][1]*dx+pmi[1][1]*dy,\ + pmi[0][2]*dx+pmi[1][2]*dy + + # fp is a global 3dpoint obtained from "unprojecting" the screenspace-point (screen_x, screen_y) + #- figuring out how to calculate this took me quite some time. + # The calculation of dxy and fp are simplified versions of my original code + #- so it's almost impossible to explain what's going on geometrically... sorry + + p[:] = vmi[3][:3] + + # the camera's location in global 3dcoords can be read directly from the inverted viewmatrix + #d.x, d.y, d.z =normalize_v3(sub_v3v3(p, fp)) + d[:] = p.x-fp.x, p.y-fp.y, p.z-fp.z + + #print 'd', d, 'p', p, 'fp', fp + + + # the direction vector is simply the difference vector from the virtual camera's position + #to the unprojected (screenspace) point fp + + # Do we want to return a direction in object's localspace? + + if localMatrix: + localInvMatrix = Matrix(localMatrix) + localInvMatrix.invert() + localInvMatrix_notrans = localInvMatrix.rotationPart() + p = p * localInvMatrix + d = d * localInvMatrix # normalize_v3 + + # remove the translation from d + d.x -= localInvMatrix[3][0] + d.y -= localInvMatrix[3][1] + d.z -= localInvMatrix[3][2] + + + d.normalize() + ''' + # Debugging + me = Blender.Mesh.New() + me.verts.extend([p[0:3]]) + me.verts.extend([(p-d)[0:3]]) + me.edges.extend([0,1]) + ob = Blender.Scene.GetCurrent().objects.new(me) + ''' + return True, p, d # Origin, Direction + + # Mouse is not in any view, return None. + return False, None, None + +# Constant function variables +mouseViewRay.d = Vector(0,0,0) # Perspective, 3d +mouseViewRay.p = Vector(0,0,0) +mouseViewRay.fp = Vector(0,0,0) + +mouseViewRay.hms = Vector(0,0,0,0) # ortho only 4d +mouseViewRay.ortho_d = Vector(0,0,0,0) # ortho only 4d + + +LMB= Window.MButs['L'] +def mouseup(): + # Loop until click + mouse_buttons = Window.GetMouseButtons() + while not mouse_buttons & LMB: + Blender.sys.sleep(10) + mouse_buttons = Window.GetMouseButtons() + while mouse_buttons & LMB: + Blender.sys.sleep(10) + mouse_buttons = Window.GetMouseButtons() + + +if __name__=='__main__': + mouseup() + x,y= Window.GetMouseCoords() + isect, point, dir= mouseViewRay(x,y) + if isect: + scn= Blender.Scene.GetCurrent() + me = Blender.Mesh.New() + ob= Blender.Object.New('Mesh') + ob.link(me) + scn.link(ob) + ob.sel= 1 + me.verts.extend([point, dir]) + me.verts[0].sel= 1 + + print isect, point, dir + + + +def spaceRect(): + ''' + Returns the space rect + xmin,ymin,width,height + ''' + + __UI_RECT__ = Blender.BGL.Buffer(Blender.BGL.GL_FLOAT, 4) + Blender.BGL.glGetFloatv(Blender.BGL.GL_SCISSOR_BOX, __UI_RECT__) + __UI_RECT__ = __UI_RECT__.list + __UI_RECT__ = int(__UI_RECT__[0]), int(__UI_RECT__[1]), int(__UI_RECT__[2])-1, int(__UI_RECT__[3]) + + return __UI_RECT__ + +def mouseRelativeLoc2d(__UI_RECT__= None): + if not __UI_RECT__: + __UI_RECT__ = spaceRect() + + mco = Window.GetMouseCoords() + if mco[0] > __UI_RECT__[0] and\ + mco[1] > __UI_RECT__[1] and\ + mco[0] < __UI_RECT__[0] + __UI_RECT__[2] and\ + mco[1] < __UI_RECT__[1] + __UI_RECT__[3]: + + return (mco[0] - __UI_RECT__[0], mco[1] - __UI_RECT__[1]) + + else: + return None + + + + + + + + + \ No newline at end of file diff --git a/release/scripts/bpymodules/defaultdoodads.py b/release/scripts/bpymodules/defaultdoodads.py new file mode 100644 index 00000000000..987b8b8ae71 --- /dev/null +++ b/release/scripts/bpymodules/defaultdoodads.py @@ -0,0 +1,941 @@ +# Default Doodad Set for Discombobulator +# by Evan J. Rosky, 2005 +# GPL- http://www.gnu.org/copyleft/gpl.html +# +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2005: Evan J. Rosky +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +#Run discombobulator.py, not this. + +import Blender +from Blender import NMesh,Object,Material +from Blender.NMesh import Vert,Face +from Blender.Mathutils import * + +import BPyMathutils +from BPyMathutils import genrand +a = BPyMathutils.sgenrand(4859) + +#Create random numbers +def randnum(low,high): + num = genrand() + num = num*(high-low) + num = num+low + return num + +face = Face() +xmin = Vector([0,0,0]) +xmax = Vector([0,0,0]) +ymin = Vector([0,0,0]) +ymax = Vector([0,0,0]) +mxmin = Vector([0,0,0]) +mxmax = Vector([0,0,0]) +mymin = Vector([0,0,0]) +mymax = Vector([0,0,0]) +doodadCenter = Vector([0,0,0]) +orientation = 0 +center = Vector([0,0,0]) +tosel = 0 +seltopsonly = 0 +tempx = [] +doodadMesh = NMesh.GetRaw() + +global materialArray +global reassignMats +global thereAreMats +global currmat +global doodSideMat +global doodTopMat + +#face is the face to add the doodad to. +#sizeX and sizeY are values from 0.0 to 1.0 that represents a percentage the face that is covered by the doodad. +#height is how tall the doodad is. + +def settings(seltops,matArr,reasMats,therMats,sidemat,topmat): + global seltopsonly + global materialArray + global reassignMats + global thereAreMats + global currmat + global doodSideMat + global doodTopMat + materialArray = matArr + reassignMats = reasMats + thereAreMats = therMats + seltopsonly = seltops + doodSideMat = sidemat + doodTopMat = topmat + +def setCurrMat(curma): + global currmat + currmat = curma + +#Find center and orientation of doodad +def findDoodadCenter(sizeX, sizeY): + #globalizing junk + global face + global xmin + global xmax + global ymin + global ymax + global orientation + global doodadCenter + global center + global tosel + global mxmin + global mxmax + global mymin + global mymax + global tempx + global seltopsonly + + #Find the center of the face + center = Vector([0,0,0]) + for pt in face.v: + center = center + pt.co + center = divideVectorByInt(center,len(face.v)) + + #Find Temp Location Range by looking at the sizes + txmin = ((divideVectorByInt((face.v[0].co + face.v[3].co),2)) - center)*(1-sizeX) + center + txmax = ((divideVectorByInt((face.v[1].co + face.v[2].co),2)) - center)*(1-sizeX) + center + tymin = ((divideVectorByInt((face.v[0].co + face.v[1].co),2)) - center)*(1-sizeY) + center + tymax = ((divideVectorByInt((face.v[2].co + face.v[3].co),2)) - center)*(1-sizeY) + center + + #Find Center of doodad + amtx = randnum(0.0,1.0) + amty = randnum(0.0,1.0) + thepoint = (((((txmin - txmax)*amtx + txmax) - ((tymin - tymax)*amty + tymax))*.5 + ((tymin - tymax)*amty + tymax)) - center)*2 + center + doodadCenter = Vector([thepoint[0],thepoint[1],thepoint[2]]) + + #Find Main Range by looking at the sizes + mxmin = divideVectorByInt((face.v[0].co + face.v[3].co),2) + mxmax = divideVectorByInt((face.v[1].co + face.v[2].co),2) + mymin = divideVectorByInt((face.v[0].co + face.v[1].co),2) + mymax = divideVectorByInt((face.v[2].co + face.v[3].co),2) + + #Find x/y equivs for whole face + ve1 = (txmin - txmax)*amtx + txmax + ve1 = ve1 - mxmax + nax = ve1.length + ve1 = (mxmin - mxmax) + nax = nax/ve1.length + + ve1 = (tymin - tymax)*amty + tymax + ve1 = ve1 - mymax + nay = ve1.length + ve1 = (mymin - mymax) + nay = nay/ve1.length + + #Find new box thing + tempx = [] + amtx = nax-sizeX/2 + amty = nay-sizeY/2 + tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) + + amtx = nax-sizeX/2 + amty = nay+sizeY/2 + tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) + + amtx = nax+sizeX/2 + amty = nay+sizeY/2 + tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) + + amtx = nax+sizeX/2 + amty = nay-sizeY/2 + tempx.append((((((mxmin - mxmax)*amtx + mxmax) - ((mymin - mymax)*amty + mymax))*.5 + ((mymin - mymax)*amty + mymax)) - center)*2 + center) + + #Find New Location Range by looking at the sizes + xmin = divideVectorByInt((tempx[0] + tempx[3]),2) + xmax = divideVectorByInt((tempx[1] + tempx[2]),2) + ymin = divideVectorByInt((tempx[0] + tempx[1]),2) + ymax = divideVectorByInt((tempx[2] + tempx[3]),2) + +#Make a point +def makePoint(x,y,z=0): + global xmin + global xmax + global ymin + global ymax + global doodadCenter + global tosel + global seltopsonly + global face + + amtx = x + amty = y + thepoint = (((((xmin - xmax)*amtx + xmax) - ((ymin - ymax)*amty + ymax))*.5 + ((ymin - ymax)*amty + ymax)) - doodadCenter)*2 + doodadCenter + thepoint = thepoint + z*Vector(face.no) + tver = Vert(thepoint[0],thepoint[1],thepoint[2]) + if tosel == 1 and seltopsonly == 0 and z == 0: + tver.sel = 1 + return tver + +#extrude ground-plane(s) +def extrudedoodad(vArray,heig): + global face + global doodadMesh + global tosel + + topVArray = [] + + doodadMesh.verts.extend(vArray) + + #Create array for extruded verts + for ind in range(0,(len(vArray))): + point = vArray[ind].co + heig*Vector(face.no) + ver = Vert(point[0],point[1],point[2]) + if tosel == 1: + ver.sel = 1 + topVArray.append(ver) + doodadMesh.verts.append(topVArray[ind]) + + #make faces around sides + for ind in range(0,(len(vArray) - 1)): + face = Face() + face.v.extend([vArray[ind],vArray[ind+1],topVArray[ind+1],topVArray[ind]]) + if tosel == 1 and seltopsonly == 0: face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodSideMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vArray[len(vArray) - 1],vArray[0],topVArray[0],topVArray[len(topVArray) - 1]]) + if tosel == 1 and seltopsonly == 0: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodSideMat-1 + doodadMesh.faces.append(face) + + return topVArray + +#For switching face vertices +def fixvertindex(ind): + if ind > 3: + indx = ind - 4 + else: + indx = ind + return indx + +#runs doodads +def createDoodad(indexArray,facec,minsi,maxsi,minhei,maxhei,selec,amtmin,amtmax,facpercent): + global doodadMesh + global seltopsonly + global tosel + + doodadMesh = NMesh.GetRaw() + + theamt = round(randnum(amtmin,amtmax),0) + theamt = int(theamt) + tosel = selec + + for i in range(0,(theamt)): + if randnum(0,1) <= facpercent: + index = round(randnum(1,len(indexArray)),0) + index = indexArray[(int(index) - 1)] + + Xsi = randnum(minsi,maxsi) + Ysi = randnum(minsi,maxsi) + hei = randnum(minhei,maxhei) + + #Determine orientation + orient = int(round(randnum(0.0,3.0))) + + #face to use as range + facer = Face() + facer.v.extend([facec.v[orient],facec.v[fixvertindex(1+orient)],facec.v[fixvertindex(2+orient)],facec.v[fixvertindex(3+orient)]]) + + if index == 1: + singleBox(facer,Xsi,Ysi,hei) + if index == 2: + doubleBox(facer,Xsi,Ysi,hei) + if index == 3: + tripleBox(facer,Xsi,Ysi,hei) + if index == 4: + LShape(facer,Xsi,Ysi,hei) + if index == 5: + TShape(facer,Xsi,Ysi,hei) + if index == 6: + if randnum(0.0,1.0) > .5: + SShape(facer,Xsi,Ysi,hei) + else: + ZShape(facer,Xsi,Ysi,hei) + + return doodadMesh + +def divideVectorByInt(thevect,theint): + thevect.x = thevect.x/theint + thevect.y = thevect.y/theint + thevect.z = thevect.z/theint + return thevect + +#Single Box Doodad +def singleBox(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + vertArray = [] + + #place four points + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#Double Box Doodad +def doubleBox(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + vertArray = [] + + #place first box + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,1)) + vertArray.append(makePoint(0.45,1)) + vertArray.append(makePoint(0.45,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + vertArray = [] + + #place second box + vertArray.append(makePoint(0.55,0)) + vertArray.append(makePoint(0.55,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#Triple Box Doodad +def tripleBox(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + vertArray = [] + + #place first box + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,1)) + vertArray.append(makePoint(0.3,1)) + vertArray.append(makePoint(0.3,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + vertArray = [] + + #place second box + vertArray.append(makePoint(0.35,0)) + vertArray.append(makePoint(0.35,1)) + vertArray.append(makePoint(0.65,1)) + vertArray.append(makePoint(0.65,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + vertArray = [] + + #place third box + vertArray.append(makePoint(0.7,0)) + vertArray.append(makePoint(0.7,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,0)) + topVertArray = extrudedoodad(vertArray,height) + + face = Face() + face.v.extend(vertArray) + face.v.reverse() + doodadMesh.faces.append(face) + face = Face() + face.v.extend(topVertArray) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#The "L" Shape +def LShape(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + rcon1 = randnum(0.2,0.8) + rcon2 = randnum(0.2,0.8) + + vertArray = [] + + #place L shape + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,rcon1)) + vertArray.append(makePoint(0,1)) + vertArray.append(makePoint(rcon2,1)) + vertArray.append(makePoint(rcon2,rcon1)) + vertArray.append(makePoint(1,rcon1)) + vertArray.append(makePoint(1,0)) + vertArray.append(makePoint(rcon2,0)) + topVertArray = extrudedoodad(vertArray,height) + + #This fills in the bottom of doodad with faceness + face = Face() + face.v.extend([vertArray[0],vertArray[1],vertArray[4],vertArray[7]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[1],vertArray[2],vertArray[3],vertArray[4]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[4],vertArray[5],vertArray[6],vertArray[7]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + #This fills in the top with faceness + face = Face() + face.v.extend([topVertArray[0],topVertArray[1],topVertArray[4],topVertArray[7]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[1],topVertArray[2],topVertArray[3],topVertArray[4]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[4],topVertArray[5],topVertArray[6],topVertArray[7]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#The "T" Shape +def TShape(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + rcony = randnum(0.25,0.75) + rconx1 = randnum(0.1,0.49) + rconx2 = randnum(0.51,0.9) + + vertArray = [] + + #place T shape + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,rcony)) + vertArray.append(makePoint(rconx1,rcony)) + vertArray.append(makePoint(rconx1,1)) + vertArray.append(makePoint(rconx2,1)) + vertArray.append(makePoint(rconx2,rcony)) + vertArray.append(makePoint(1,rcony)) + vertArray.append(makePoint(1,0)) + vertArray.append(makePoint(rconx2,0)) + vertArray.append(makePoint(rconx1,0)) + topVertArray = extrudedoodad(vertArray,height) + + #fills bottom with faceness + face = Face() + face.v.extend([vertArray[0],vertArray[1],vertArray[2],vertArray[9]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[2],vertArray[3],vertArray[4],vertArray[5]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[5],vertArray[6],vertArray[7],vertArray[8]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[8],vertArray[9],vertArray[2],vertArray[5]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + #fills top with faceness + face = Face() + face.v.extend([topVertArray[0],topVertArray[1],topVertArray[2],topVertArray[9]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[2],topVertArray[3],topVertArray[4],topVertArray[5]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[5],topVertArray[6],topVertArray[7],topVertArray[8]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[8],topVertArray[9],topVertArray[2],topVertArray[5]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +#The "S" or "Z" Shapes +def SShape(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + rcony1 = randnum(0.1,0.49) + rcony2 = randnum(0.51,0.9) + rconx1 = randnum(0.1,0.49) + rconx2 = randnum(0.51,0.9) + + vertArray = [] + + #place S shape + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,rcony1)) + vertArray.append(makePoint(rconx1,rcony1)) + vertArray.append(makePoint(rconx1,rcony2)) + vertArray.append(makePoint(rconx1,1)) + vertArray.append(makePoint(rconx2,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,rcony2)) + vertArray.append(makePoint(rconx2,rcony2)) + vertArray.append(makePoint(rconx2,rcony1)) + vertArray.append(makePoint(rconx2,0)) + vertArray.append(makePoint(rconx1,0)) + topVertArray = extrudedoodad(vertArray,height) + + #fills bottom with faceness + face = Face() + face.v.extend([vertArray[0],vertArray[1],vertArray[2],vertArray[11]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[2],vertArray[9],vertArray[10],vertArray[11]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[2],vertArray[3],vertArray[8],vertArray[9]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[3],vertArray[4],vertArray[5],vertArray[8]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[5],vertArray[6],vertArray[7],vertArray[8]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + #fills top with faceness + face = Face() + face.v.extend([topVertArray[0],topVertArray[1],topVertArray[2],topVertArray[11]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[2],topVertArray[9],topVertArray[10],topVertArray[11]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[2],topVertArray[3],topVertArray[8],topVertArray[9]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[3],topVertArray[4],topVertArray[5],topVertArray[8]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[5],topVertArray[6],topVertArray[7],topVertArray[8]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + +def ZShape(facel, Xsize, Ysize, height): + #globaling junk + global face + global tosel + global doodadMesh + + face = Face() + face = facel + + findDoodadCenter(Xsize, Ysize) + + rcony1 = randnum(0.1,0.49) + rcony2 = randnum(0.51,0.9) + rconx1 = randnum(0.1,0.49) + rconx2 = randnum(0.51,0.9) + + vertArray = [] + + #place Z shape + vertArray.append(makePoint(0,0)) + vertArray.append(makePoint(0,rcony1)) + vertArray.append(makePoint(0,rcony2)) + vertArray.append(makePoint(rconx1,rcony2)) + vertArray.append(makePoint(rconx2,rcony2)) + vertArray.append(makePoint(rconx2,1)) + vertArray.append(makePoint(1,1)) + vertArray.append(makePoint(1,rcony2)) + vertArray.append(makePoint(1,rcony1)) + vertArray.append(makePoint(rconx2,rcony1)) + vertArray.append(makePoint(rconx1,rcony1)) + vertArray.append(makePoint(rconx1,0)) + topVertArray = extrudedoodad(vertArray,height) + + #fills bottom with faceness + face = Face() + face.v.extend([vertArray[0],vertArray[1],vertArray[10],vertArray[11]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[1],vertArray[2],vertArray[3],vertArray[10]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[3],vertArray[4],vertArray[9],vertArray[10]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[4],vertArray[7],vertArray[8],vertArray[9]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([vertArray[4],vertArray[5],vertArray[6],vertArray[7]]) + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + + #fills top with faceness + face = Face() + face.v.extend([topVertArray[0],topVertArray[1],topVertArray[10],topVertArray[11]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[1],topVertArray[2],topVertArray[3],topVertArray[10]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[3],topVertArray[4],topVertArray[9],topVertArray[10]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[4],topVertArray[7],topVertArray[8],topVertArray[9]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + face = Face() + face.v.extend([topVertArray[4],topVertArray[5],topVertArray[6],topVertArray[7]]) + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or doodTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = doodTopMat-1 + doodadMesh.faces.append(face) + diff --git a/release/scripts/bpymodules/dxfColorMap.py b/release/scripts/bpymodules/dxfColorMap.py new file mode 100644 index 00000000000..66c0bd4e9a2 --- /dev/null +++ b/release/scripts/bpymodules/dxfColorMap.py @@ -0,0 +1,282 @@ +# dictionary mapping AutoCAD color indexes with Blender colors + +# -------------------------------------------------------------------------- +# color_map.py Final by Ed Blake (AKA Kitsu) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +color_map = { + 0:[0.0, 0.0, 0.0], + 1:[0.99609375, 0.0, 0.0], + 2:[0.99609375, 0.99609375, 0.0], + 3:[0.0, 0.99609375, 0.0], + 4:[0.0, 0.99609375, 0.99609375], + 5:[0.0, 0.0, 0.99609375], + 6:[0.99609375, 0.0, 0.99609375], + 7:[0.99609375, 0.99609375, 0.99609375], + 8:[0.25390625, 0.25390625, 0.25390625], + 9:[0.5, 0.5, 0.5], + 10:[0.99609375, 0.0, 0.0], + 11:[0.99609375, 0.6640625, 0.6640625], + 12:[0.73828125, 0.0, 0.0], + 13:[0.73828125, 0.4921875, 0.4921875], + 14:[0.50390625, 0.0, 0.0], + 15:[0.50390625, 0.3359375, 0.3359375], + 16:[0.40625, 0.0, 0.0], + 17:[0.40625, 0.26953125, 0.26953125], + 18:[0.30859375, 0.0, 0.0], + 19:[0.30859375, 0.20703125, 0.20703125], + 20:[0.99609375, 0.24609375, 0.0], + 21:[0.99609375, 0.74609375, 0.6640625], + 22:[0.73828125, 0.1796875, 0.0], + 23:[0.73828125, 0.55078125, 0.4921875], + 24:[0.50390625, 0.12109375, 0.0], + 25:[0.50390625, 0.375, 0.3359375], + 26:[0.40625, 0.09765625, 0.0], + 27:[0.40625, 0.3046875, 0.26953125], + 28:[0.30859375, 0.07421875, 0.0], + 29:[0.30859375, 0.23046875, 0.20703125], + 30:[0.99609375, 0.49609375, 0.0], + 31:[0.99609375, 0.828125, 0.6640625], + 32:[0.73828125, 0.3671875, 0.0], + 33:[0.73828125, 0.61328125, 0.4921875], + 34:[0.50390625, 0.25, 0.0], + 35:[0.50390625, 0.41796875, 0.3359375], + 36:[0.40625, 0.203125, 0.0], + 37:[0.40625, 0.3359375, 0.26953125], + 38:[0.30859375, 0.15234375, 0.0], + 39:[0.30859375, 0.2578125, 0.20703125], + 40:[0.99609375, 0.74609375, 0.0], + 41:[0.99609375, 0.9140625, 0.6640625], + 42:[0.73828125, 0.55078125, 0.0], + 43:[0.73828125, 0.67578125, 0.4921875], + 44:[0.50390625, 0.375, 0.0], + 45:[0.50390625, 0.4609375, 0.3359375], + 46:[0.40625, 0.3046875, 0.0], + 47:[0.40625, 0.37109375, 0.26953125], + 48:[0.30859375, 0.23046875, 0.0], + 49:[0.30859375, 0.28515625, 0.20703125], + 50:[0.99609375, 0.99609375, 0.0], + 51:[0.99609375, 0.99609375, 0.6640625], + 52:[0.73828125, 0.73828125, 0.0], + 53:[0.73828125, 0.73828125, 0.4921875], + 54:[0.50390625, 0.50390625, 0.0], + 55:[0.50390625, 0.50390625, 0.3359375], + 56:[0.40625, 0.40625, 0.0], + 57:[0.40625, 0.40625, 0.26953125], + 58:[0.30859375, 0.30859375, 0.0], + 59:[0.30859375, 0.30859375, 0.20703125], + 60:[0.74609375, 0.99609375, 0.0], + 61:[0.9140625, 0.99609375, 0.6640625], + 62:[0.55078125, 0.73828125, 0.0], + 63:[0.67578125, 0.73828125, 0.4921875], + 64:[0.375, 0.50390625, 0.0], + 65:[0.4609375, 0.50390625, 0.3359375], + 66:[0.3046875, 0.40625, 0.0], + 67:[0.37109375, 0.40625, 0.26953125], + 68:[0.23046875, 0.30859375, 0.0], + 69:[0.28515625, 0.30859375, 0.20703125], + 70:[0.49609375, 0.99609375, 0.0], + 71:[0.828125, 0.99609375, 0.6640625], + 72:[0.3671875, 0.73828125, 0.0], + 73:[0.61328125, 0.73828125, 0.4921875], + 74:[0.25, 0.50390625, 0.0], + 75:[0.41796875, 0.50390625, 0.3359375], + 76:[0.203125, 0.40625, 0.0], + 77:[0.3359375, 0.40625, 0.26953125], + 78:[0.15234375, 0.30859375, 0.0], + 79:[0.2578125, 0.30859375, 0.20703125], + 80:[0.24609375, 0.99609375, 0.0], + 81:[0.74609375, 0.99609375, 0.6640625], + 82:[0.1796875, 0.73828125, 0.0], + 83:[0.55078125, 0.73828125, 0.4921875], + 84:[0.12109375, 0.50390625, 0.0], + 85:[0.375, 0.50390625, 0.3359375], + 86:[0.09765625, 0.40625, 0.0], + 87:[0.3046875, 0.40625, 0.26953125], + 88:[0.07421875, 0.30859375, 0.0], + 89:[0.23046875, 0.30859375, 0.20703125], + 90:[0.0, 0.99609375, 0.0], + 91:[0.6640625, 0.99609375, 0.6640625], + 92:[0.0, 0.73828125, 0.0], + 93:[0.4921875, 0.73828125, 0.4921875], + 94:[0.0, 0.50390625, 0.0], + 95:[0.3359375, 0.50390625, 0.3359375], + 96:[0.0, 0.40625, 0.0], + 97:[0.26953125, 0.40625, 0.26953125], + 98:[0.0, 0.30859375, 0.0], + 99:[0.20703125, 0.30859375, 0.20703125], + 100:[0.0, 0.99609375, 0.24609375], + 101:[0.6640625, 0.99609375, 0.74609375], + 102:[0.0, 0.73828125, 0.1796875], + 103:[0.4921875, 0.73828125, 0.55078125], + 104:[0.0, 0.50390625, 0.12109375], + 105:[0.3359375, 0.50390625, 0.375], + 106:[0.0, 0.40625, 0.09765625], + 107:[0.26953125, 0.40625, 0.3046875], + 108:[0.0, 0.30859375, 0.07421875], + 109:[0.20703125, 0.30859375, 0.23046875], + 110:[0.0, 0.99609375, 0.49609375], + 111:[0.6640625, 0.99609375, 0.828125], + 112:[0.0, 0.73828125, 0.3671875], + 113:[0.4921875, 0.73828125, 0.61328125], + 114:[0.0, 0.50390625, 0.25], + 115:[0.3359375, 0.50390625, 0.41796875], + 116:[0.0, 0.40625, 0.203125], + 117:[0.26953125, 0.40625, 0.3359375], + 118:[0.0, 0.30859375, 0.15234375], + 119:[0.20703125, 0.30859375, 0.2578125], + 120:[0.0, 0.99609375, 0.74609375], + 121:[0.6640625, 0.99609375, 0.9140625], + 122:[0.0, 0.73828125, 0.55078125], + 123:[0.4921875, 0.73828125, 0.67578125], + 124:[0.0, 0.50390625, 0.375], + 125:[0.3359375, 0.50390625, 0.4609375], + 126:[0.0, 0.40625, 0.3046875], + 127:[0.26953125, 0.40625, 0.37109375], + 128:[0.0, 0.30859375, 0.23046875], + 129:[0.20703125, 0.30859375, 0.28515625], + 130:[0.0, 0.99609375, 0.99609375], + 131:[0.6640625, 0.99609375, 0.99609375], + 132:[0.0, 0.73828125, 0.73828125], + 133:[0.4921875, 0.73828125, 0.73828125], + 134:[0.0, 0.50390625, 0.50390625], + 135:[0.3359375, 0.50390625, 0.50390625], + 136:[0.0, 0.40625, 0.40625], + 137:[0.26953125, 0.40625, 0.40625], + 138:[0.0, 0.30859375, 0.30859375], + 139:[0.20703125, 0.30859375, 0.30859375], + 140:[0.0, 0.74609375, 0.99609375], + 141:[0.6640625, 0.9140625, 0.99609375], + 142:[0.0, 0.55078125, 0.73828125], + 143:[0.4921875, 0.67578125, 0.73828125], + 144:[0.0, 0.375, 0.50390625], + 145:[0.3359375, 0.4609375, 0.50390625], + 146:[0.0, 0.3046875, 0.40625], + 147:[0.26953125, 0.37109375, 0.40625], + 148:[0.0, 0.23046875, 0.30859375], + 149:[0.20703125, 0.28515625, 0.30859375], + 150:[0.0, 0.49609375, 0.99609375], + 151:[0.6640625, 0.828125, 0.99609375], + 152:[0.0, 0.3671875, 0.73828125], + 153:[0.4921875, 0.61328125, 0.73828125], + 154:[0.0, 0.25, 0.50390625], + 155:[0.3359375, 0.41796875, 0.50390625], + 156:[0.0, 0.203125, 0.40625], + 157:[0.26953125, 0.3359375, 0.40625], + 158:[0.0, 0.15234375, 0.30859375], + 159:[0.20703125, 0.2578125, 0.30859375], + 160:[0.0, 0.24609375, 0.99609375], + 161:[0.6640625, 0.74609375, 0.99609375], + 162:[0.0, 0.1796875, 0.73828125], + 163:[0.4921875, 0.55078125, 0.73828125], + 164:[0.0, 0.12109375, 0.50390625], + 165:[0.3359375, 0.375, 0.50390625], + 166:[0.0, 0.09765625, 0.40625], + 167:[0.26953125, 0.3046875, 0.40625], + 168:[0.0, 0.07421875, 0.30859375], + 169:[0.20703125, 0.23046875, 0.30859375], + 170:[0.0, 0.0, 0.99609375], + 171:[0.6640625, 0.6640625, 0.99609375], + 172:[0.0, 0.0, 0.73828125], + 173:[0.4921875, 0.4921875, 0.73828125], + 174:[0.0, 0.0, 0.50390625], + 175:[0.3359375, 0.3359375, 0.50390625], + 176:[0.0, 0.0, 0.40625], + 177:[0.26953125, 0.26953125, 0.40625], + 178:[0.0, 0.0, 0.30859375], + 179:[0.20703125, 0.20703125, 0.30859375], + 180:[0.24609375, 0.0, 0.99609375], + 181:[0.74609375, 0.6640625, 0.99609375], + 182:[0.1796875, 0.0, 0.73828125], + 183:[0.55078125, 0.4921875, 0.73828125], + 184:[0.12109375, 0.0, 0.50390625], + 185:[0.375, 0.3359375, 0.50390625], + 186:[0.09765625, 0.0, 0.40625], + 187:[0.3046875, 0.26953125, 0.40625], + 188:[0.07421875, 0.0, 0.30859375], + 189:[0.23046875, 0.20703125, 0.30859375], + 190:[0.49609375, 0.0, 0.99609375], + 191:[0.828125, 0.6640625, 0.99609375], + 192:[0.3671875, 0.0, 0.73828125], + 193:[0.61328125, 0.4921875, 0.73828125], + 194:[0.25, 0.0, 0.50390625], + 195:[0.41796875, 0.3359375, 0.50390625], + 196:[0.203125, 0.0, 0.40625], + 197:[0.3359375, 0.26953125, 0.40625], + 198:[0.15234375, 0.0, 0.30859375], + 199:[0.2578125, 0.20703125, 0.30859375], + 200:[0.74609375, 0.0, 0.99609375], + 201:[0.9140625, 0.6640625, 0.99609375], + 202:[0.55078125, 0.0, 0.73828125], + 203:[0.67578125, 0.4921875, 0.73828125], + 204:[0.375, 0.0, 0.50390625], + 205:[0.4609375, 0.3359375, 0.50390625], + 206:[0.3046875, 0.0, 0.40625], + 207:[0.37109375, 0.26953125, 0.40625], + 208:[0.23046875, 0.0, 0.30859375], + 209:[0.28515625, 0.20703125, 0.30859375], + 210:[0.99609375, 0.0, 0.99609375], + 211:[0.99609375, 0.6640625, 0.99609375], + 212:[0.73828125, 0.0, 0.73828125], + 213:[0.73828125, 0.4921875, 0.73828125], + 214:[0.50390625, 0.0, 0.50390625], + 215:[0.50390625, 0.3359375, 0.50390625], + 216:[0.40625, 0.0, 0.40625], + 217:[0.40625, 0.26953125, 0.40625], + 218:[0.30859375, 0.0, 0.30859375], + 219:[0.30859375, 0.20703125, 0.30859375], + 220:[0.99609375, 0.0, 0.74609375], + 221:[0.99609375, 0.6640625, 0.9140625], + 222:[0.73828125, 0.0, 0.55078125], + 223:[0.73828125, 0.4921875, 0.67578125], + 224:[0.50390625, 0.0, 0.375], + 225:[0.50390625, 0.3359375, 0.4609375], + 226:[0.40625, 0.0, 0.3046875], + 227:[0.40625, 0.26953125, 0.37109375], + 228:[0.30859375, 0.0, 0.23046875], + 229:[0.30859375, 0.20703125, 0.28515625], + 230:[0.99609375, 0.0, 0.49609375], + 231:[0.99609375, 0.6640625, 0.828125], + 232:[0.73828125, 0.0, 0.3671875], + 233:[0.73828125, 0.4921875, 0.61328125], + 234:[0.50390625, 0.0, 0.25], + 235:[0.50390625, 0.3359375, 0.41796875], + 236:[0.40625, 0.0, 0.203125], + 237:[0.40625, 0.26953125, 0.3359375], + 238:[0.30859375, 0.0, 0.15234375], + 239:[0.30859375, 0.20703125, 0.2578125], + 240:[0.99609375, 0.0, 0.24609375], + 241:[0.99609375, 0.6640625, 0.74609375], + 242:[0.73828125, 0.0, 0.1796875], + 243:[0.73828125, 0.4921875, 0.55078125], + 244:[0.50390625, 0.0, 0.12109375], + 245:[0.50390625, 0.3359375, 0.375], + 246:[0.40625, 0.0, 0.09765625], + 247:[0.40625, 0.26953125, 0.3046875], + 248:[0.30859375, 0.0, 0.07421875], + 249:[0.30859375, 0.20703125, 0.23046875], + 250:[0.19921875, 0.19921875, 0.19921875], + 251:[0.3125, 0.3125, 0.3125], + 252:[0.41015625, 0.41015625, 0.41015625], + 253:[0.5078125, 0.5078125, 0.5078125], + 254:[0.7421875, 0.7421875, 0.7421875], + 255:[0.99609375, 0.99609375, 0.99609375], +} diff --git a/release/scripts/bpymodules/dxfImportObjects.py b/release/scripts/bpymodules/dxfImportObjects.py new file mode 100644 index 00000000000..960c4c1ac15 --- /dev/null +++ b/release/scripts/bpymodules/dxfImportObjects.py @@ -0,0 +1,1326 @@ +"""This module provides wrapper objects for dxf entities. + + The wrappers expect a "dxf object" as input. The dxf object is + an object with a type and a data attribute. Type is a lowercase + string matching the 0 code of a dxf entity. Data is a list containing + dxf objects or lists of [code, data] pairs. + + This module is not general, and is only for dxf import. +""" + +# -------------------------------------------------------------------------- +# DXF Import Objects v0.8 by Ed Blake (AKA Kitsu) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +from math import * + + +# from Stani's dxf writer v1.1 (c)www.stani.be (GPL) +#---color values +BYBLOCK=0 +BYLAYER=256 + +#---block-type flags (bit coded values, may be combined): +ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application +NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) +XREF =4 # This block is an external reference (xref) +XREF_OVERLAY =8 # This block is an xref overlay +EXTERNAL =16 # This block is externally dependent +RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) +REFERENCED =64 # This definition is a referenced external reference (ignored on input) + +#---mtext flags +#attachment point +TOP_LEFT = 1 +TOP_CENTER = 2 +TOP_RIGHT = 3 +MIDDLE_LEFT = 4 +MIDDLE_CENTER = 5 +MIDDLE_RIGHT = 6 +BOTTOM_LEFT = 7 +BOTTOM_CENTER = 8 +BOTTOM_RIGHT = 9 +#drawing direction +LEFT_RIGHT = 1 +TOP_BOTTOM = 3 +BY_STYLE = 5 #the flow direction is inherited from the associated text style +#line spacing style (optional): +AT_LEAST = 1 #taller characters will override +EXACT = 2 #taller characters will not override + +#---polyline flags +CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) +CURVE_FIT =2 # Curve-fit vertices have been added +SPLINE_FIT =4 # Spline-fit vertices have been added +POLYLINE_3D =8 # This is a 3D polyline +POLYGON_MESH =16 # This is a 3D polygon mesh +CLOSED_N =32 # The polygon mesh is closed in the N direction +POLYFACE_MESH =64 # The polyline is a polyface mesh +CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline + +#---text flags +#horizontal +LEFT = 0 +CENTER = 1 +RIGHT = 2 +ALIGNED = 3 #if vertical alignment = 0 +MIDDLE = 4 #if vertical alignment = 0 +FIT = 5 #if vertical alignment = 0 +#vertical +BASELINE = 0 +BOTTOM = 1 +MIDDLE = 2 +TOP = 3 +class Object: + """Empty container class for dxf objects""" + + def __init__(self, _type=''): + """_type expects a string value.""" + self.type = _type + self.name = '' + self.data = [] + + def __str__(self): + if self.name: + return self.name + else: + return self.type + + def __repr__(self): + return str(self.data) + + def get_type(self, kind=''): + """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" + if type: + objects = [] + for item in self.data: + if type(item) != list and item.type == kind: + # we want this type of object + objects.append(item) + elif type(item) == list and item[0] == kind: + # we want this type of data + objects.append(item[1]) + return objects + + +class Layer: + """Class for objects representing dxf layers.""" + + def __init__(self, obj): + """Expects an entity object of type line as input.""" + self.type = obj.type + self.data = obj.data[:] + + self.name = obj.get_type(2)[0] + self.color = obj.get_type(62)[0] + self.flags = obj.get_type(70)[0] + self.frozen = self.flags&1 + + + + def __repr__(self): + return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color) + + + +class Line: + """Class for objects representing dxf lines.""" + + def __init__(self, obj): + """Expects an entity object of type line as input.""" + if not obj.type == 'line': + raise TypeError, "Wrong type %s for line object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + + self.points = self.get_points(obj.data) + + + + + def get_points(self, data): + """Gets start and end points for a line type object. + + Lines have a fixed number of points (two) and fixed codes for each value. + """ + + # start x, y, z and end x, y, z = 0 + sx, sy, sz, ex, ey, ez = 0, 0, 0, 0, 0, 0 + for item in data: + if item[0] == 10: # 10 = x + sx = item[1] + elif item[0] == 20: # 20 = y + sy = item[1] + elif item[0] == 30: # 30 = z + sz = item[1] + elif item[0] == 11: # 11 = x + ex = item[1] + elif item[0] == 21: # 21 = y + ey = item[1] + elif item[0] == 31: # 31 = z + ez = item[1] + return [[sx, sy, sz], [ex, ey, ez]] + + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + +class LWpolyline: + """Class for objects representing dxf LWpolylines.""" + + def __init__(self, obj): + """Expects an entity object of type lwpolyline as input.""" + if not obj.type == 'lwpolyline': + raise TypeError, "Wrong type %s for polyline object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.num_points = obj.get_type(90)[0] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + self.elevation = obj.get_type(38) + if self.elevation: + self.elevation = self.elevation[0] + else: + self.elevation = 0 + + self.flags = obj.get_type(70) + if self.flags: + self.flags = self.flags[0] + else: + self.flags = 0 + + self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.points = self.get_points(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + + def get_points(self, data): + """Gets points for a polyline type object. + + Polylines have no fixed number of verts, and + each vert can have a number of properties. + Verts should be coded as + 10:xvalue + 20:yvalue + 40:startwidth or 0 + 41:endwidth or 0 + 42:bulge or 0 + for each vert + """ + num = self.num_points + point = None + points = [] + for item in data: + if item[0] == 10: # 10 = x + if point: + points.append(point) + point = Vertex() + point.x = item[1] + elif item[0] == 20: # 20 = y + point.y = item[1] + elif item[0] == 40: # 40 = start width + point.swidth = item[1] + elif item[0] == 41: # 41 = end width + point.ewidth = item[1] + elif item[0] == 42: # 42 = bulge + point.bulge = item[1] + points.append(point) + return points + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + +class Polyline: + """Class for objects representing dxf LWpolylines.""" + + def __init__(self, obj): + """Expects an entity object of type polyline as input.""" + if not obj.type == 'polyline': + raise TypeError, "Wrong type %s for polyline object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + self.points = [] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + self.elevation = obj.get_type(30) + if self.elevation: + self.elevation = self.elevation[0] + else: + self.elevation = 0 + + self.flags = obj.get_type(70) + if self.flags: + self.flags = self.flags[0] + else: + self.flags = 0 + + self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + +class Vertex(object): + """Generic vertex object used by polylines (and maybe others).""" + + def __init__(self, obj=None): + """Initializes vertex data. + + The optional obj arg is an entity object of type vertex. + """ + self.loc = [0,0,0] + self.bulge = 0 + self.swidth = 0 + self.ewidth = 0 + self.flags = 0 + + if obj is not None: + if not obj.type == 'vertex': + raise TypeError, "Wrong type %s for vertex object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.get_props(obj.data) + + + def get_props(self, data): + """Gets coords for a vertex type object. + + Each vert can have a number of properties. + Verts should be coded as + 10:xvalue + 20:yvalue + 40:startwidth or 0 + 41:endwidth or 0 + 42:bulge or 0 + """ + for item in data: + if item[0] == 10: # 10 = x + self.x = item[1] + elif item[0] == 20: # 20 = y + self.y = item[1] + elif item[0] == 30: # 30 = z + self.z = item[1] + elif item[0] == 40: # 40 = start width + self.swidth = item[1] + elif item[0] == 41: # 41 = end width + self.ewidth = item[1] + elif item[0] == 42: # 42 = bulge + self.bulge = item[1] + elif item[0] == 70: # 70 = vert flags + self.flags = item[1] + + + def __len__(self): + return 3 + + + def __getitem__(self, key): + return self.loc[key] + + + def __setitem__(self, key, value): + if key in [0,1,2]: + self.loc[key] + + + def __iter__(self): + return self.loc.__iter__() + + + def __str__(self): + return str(self.loc) + + + def __repr__(self): + return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s" %(self.loc, self.swidth, self.ewidth, self.bulge) + + + def getx(self): + return self.loc[0] + + def setx(self, value): + self.loc[0] = value + + x = property(getx, setx) + + + def gety(self): + return self.loc[1] + + def sety(self, value): + self.loc[1] = value + + y = property(gety, sety) + + + def getz(self): + return self.loc[2] + + def setz(self, value): + self.loc[2] = value + + z = property(getz, setz) + + + +class Text: + """Class for objects representing dxf Text.""" + + def __init__(self, obj): + """Expects an entity object of type text as input.""" + if not obj.type == 'text': + raise TypeError, "Wrong type %s for text object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.height = obj.get_type(40)[0] + self.value = obj.get_type(1)[0] # The text string value + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + self.rotation = obj.get_type(50) # radians? + if not self.rotation: + self.rotation = 0 + else: + self.rotation = self.rotation[0] + + self.width_factor = obj.get_type(41) # Scaling factor along local x axis + if not self.width_factor: + self.width_factor = 1 + else: + self.width_factor = self.width_factor[0] + + self.oblique = obj.get_type(51) # skew in degrees -90 <= oblique <= 90 + if not self.oblique: + self.oblique = 0 + else: + self.oblique = self.oblique[0] + + self.halignment = obj.get_type(72) # horiz. alignment + if not self.halignment: # 0=left, 1=center, 2=right, 3=aligned, 4=middle, 5=fit + self.halignment = 0 + else: + self.halignment = self.halignment[0] + + self.valignment = obj.get_type(73) # vert. alignment + if not self.valignment: # 0=baseline, 1=bottom, 2=middle, 3=top + self.valignment = 0 + else: + self.valignment = self.valignment[0] + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data, self.halignment, self.valignment) + self.extrusion = self.get_extrusion(obj.data) + + + + + def get_loc(self, data, halign, valign): + """Gets adjusted location for text type objects. + + If group 72 and/or 73 values are nonzero then the first alignment point values + are ignored and AutoCAD calculates new values based on the second alignment + point and the length and height of the text string itself (after applying the + text style). If the 72 and 73 values are zero or missing, then the second + alignment point is meaningless. + + I don't know how to calc text size... + """ + # bottom left x, y, z and justification x, y, z = 0 + x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0 + for item in data: + if item[0] == 10: # 10 = x + x = item[1] + elif item[0] == 20: # 20 = y + y = item[1] + elif item[0] == 30: # 30 = z + z = item[1] + elif item[0] == 11: # 11 = x + jx = item[1] + elif item[0] == 21: # 21 = y + jy = item[1] + elif item[0] == 31: # 31 = z + jz = item[1] + + if halign or valign: + x, y, z = jx, jy, jz + return [x, y, z] + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) + + + +class Mtext: + """Class for objects representing dxf Mtext.""" + + def __init__(self, obj): + """Expects an entity object of type mtext as input.""" + if not obj.type == 'mtext': + raise TypeError, "Wrong type %s for mtext object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.height = obj.get_type(40)[0] + self.width = obj.get_type(41)[0] + self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR + self.value = self.get_text(obj.data) # The text string value + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + self.rotation = obj.get_type(50) # radians + if not self.rotation: + self.rotation = 0 + else: + self.rotation = self.rotation[0] + + self.width_factor = obj.get_type(42) # Scaling factor along local x axis + if not self.width_factor: + self.width_factor = 1 + else: + self.width_factor = self.width_factor[0] + + self.line_space = obj.get_type(44) # percentage of default + if not self.line_space: + self.line_space = 1 + else: + self.line_space = self.line_space[0] + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_text(self, data): + """Reconstructs mtext data from dxf codes.""" + primary = '' + secondary = [] + for item in data: + if item[0] == 1: # There should be only one primary... + primary = item[1] + elif item[0] == 3: # There may be any number of extra strings (in order) + secondary.append(item[1]) + if not primary: + #raise ValueError, "Empty Mtext Object!" + string = "Empty Mtext Object!" + if not secondary: + string = primary.replace(r'\P', '\n') + else: + string = ''.join(secondary)+primary + string = string.replace(r'\P', '\n') + return string + def get_loc(self, data): + """Gets location for a mtext type objects. + + Mtext objects have only one point indicating location. + """ + loc = [0,0,0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) + + + +class Circle: + """Class for objects representing dxf Circles.""" + + def __init__(self, obj): + """Expects an entity object of type circle as input.""" + if not obj.type == 'circle': + raise TypeError, "Wrong type %s for circle object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.radius = obj.get_type(40)[0] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_loc(self, data): + """Gets the center location for circle type objects. + + Circles have a single coord location. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + +class Arc: + """Class for objects representing dxf arcs.""" + + def __init__(self, obj): + """Expects an entity object of type arc as input.""" + if not obj.type == 'arc': + raise TypeError, "Wrong type %s for arc object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.radius = obj.get_type(40)[0] + self.start_angle = obj.get_type(50)[0] + self.end_angle = obj.get_type(51)[0] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_loc(self, data): + """Gets the center location for arc type objects. + + Arcs have a single coord location. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + +class BlockRecord: + """Class for objects representing dxf block_records.""" + + def __init__(self, obj): + """Expects an entity object of type block_record as input.""" + if not obj.type == 'block_record': + raise TypeError, "Wrong type %s for block_record object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.name = obj.get_type(2)[0] + + # optional data (with defaults) + self.insertion_units = obj.get_type(70) + if not self.insertion_units: + self.insertion_units = None + else: + self.insertion_units = self.insertion_units[0] + + self.insert_units = obj.get_type(1070) + if not self.insert_units: + self.insert_units = None + else: + self.insert_units = self.insert_units[0] + + + + + + + def __repr__(self): + return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units) + + + + +class Block: + """Class for objects representing dxf blocks.""" + + def __init__(self, obj): + """Expects an entity object of type block as input.""" + if not obj.type == 'block': + raise TypeError, "Wrong type %s for block object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.flags = obj.get_type(70)[0] + self.entities = Object('block_contents') + self.entities.data = objectify([ent for ent in obj.data if type(ent) != list]) + + # optional data (with defaults) + self.name = obj.get_type(3) + if self.name: + self.name = self.name[0] + else: + self.name = '' + + self.path = obj.get_type(1) + if self.path: + self.path = self.path[0] + else: + self.path = '' + + self.discription = obj.get_type(4) + if self.discription: + self.discription = self.discription[0] + else: + self.discription = '' + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + + + + + + def get_loc(self, data): + """Gets the insert point of the block.""" + loc = [0, 0, 0] + for item in data: + if type(item) != list: + continue + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def __repr__(self): + return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path) + + + + +class Insert: + """Class for objects representing dxf inserts.""" + + def __init__(self, obj): + """Expects an entity object of type insert as input.""" + if not obj.type == 'insert': + raise TypeError, "Wrong type %s for insert object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.block = obj.get_type(2)[0] + + # optional data (with defaults) + self.rotation = obj.get_type(50) + if self.rotation: + self.rotation = self.rotation[0] + else: + self.rotation = 0 + + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.scale = self.get_scale(obj.data) + self.rows, self.columns = self.get_array(obj.data) + self.extrusion = self.get_extrusion(obj.data) + + + + + + def get_loc(self, data): + """Gets the center location for circle type objects. + + Circles have a single coord location. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def get_scale(self, data): + """Gets the x/y/z scale factor for the block. + """ + scale = [1, 1, 1] + for item in data: + if item[0] == 41: # 41 = x scale + scale[0] = item[1] + elif item[0] == 42: # 42 = y scale + scale[1] = item[1] + elif item[0] == 43: # 43 = z scale + scale[2] = item[1] + return scale + + + + def get_array(self, data): + """Returns the pair (row number, row spacing), (column number, column spacing).""" + columns = 1 + rows = 1 + cspace = 0 + rspace = 0 + for item in data: + if item[0] == 70: # 70 = columns + columns = item[1] + elif item[0] == 71: # 71 = rows + rows = item[1] + if item[0] == 44: # 44 = columns + cspace = item[1] + elif item[0] == 45: # 45 = rows + rspace = item[1] + return (rows, rspace), (columns, cspace) + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, block - %s" %(self.__class__.__name__, self.layer, self.block) + + + + +class Ellipse: + """Class for objects representing dxf ellipses.""" + + def __init__(self, obj): + """Expects an entity object of type ellipse as input.""" + if not obj.type == 'ellipse': + raise TypeError, "Wrong type %s for ellipse object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.ratio = obj.get_type(40)[0] + self.start_angle = obj.get_type(41)[0] + self.end_angle = obj.get_type(42)[0] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.loc = self.get_loc(obj.data) + self.major = self.get_major(obj.data) + self.extrusion = self.get_extrusion(obj.data) + self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2) + + + + + def get_loc(self, data): + """Gets the center location for arc type objects. + + Arcs have a single coord location. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 10: # 10 = x + loc[0] = item[1] + elif item[0] == 20: # 20 = y + loc[1] = item[1] + elif item[0] == 30: # 30 = z + loc[2] = item[1] + return loc + + + + def get_major(self, data): + """Gets the major axis for ellipse type objects. + + The ellipse major axis defines the rotation of the ellipse and its radius. + """ + loc = [0, 0, 0] + for item in data: + if item[0] == 11: # 11 = x + loc[0] = item[1] + elif item[0] == 21: # 21 = y + loc[1] = item[1] + elif item[0] == 31: # 31 = z + loc[2] = item[1] + return loc + + + + def get_extrusion(self, data): + """Find the axis of extrusion. + + Used to get the objects Object Coordinate System (ocs). + """ + vec = [0,0,1] + for item in data: + if item[0] == 210: # 210 = x + vec[0] = item[1] + elif item[0] == 220: # 220 = y + vec[1] = item[1] + elif item[0] == 230: # 230 = z + vec[2] = item[1] + return vec + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + +class Face: + """Class for objects representing dxf 3d faces.""" + + def __init__(self, obj): + """Expects an entity object of type 3dfaceplot as input.""" + if not obj.type == '3dface': + raise TypeError, "Wrong type %s for 3dface object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # optional data (with defaults) + self.space = obj.get_type(67) + if self.space: + self.space = self.space[0] + else: + self.space = 0 + + self.color_index = obj.get_type(62) + if self.color_index: + self.color_index = self.color_index[0] + else: + self.color_index = BYLAYER + + discard, self.layer, discard_index = get_layer(obj.data) + del obj.data[discard_index] + self.points = self.get_points(obj.data) + + + + + def get_points(self, data): + """Gets 3-4 points for a 3d face type object. + + Faces have three or optionally four verts. + """ + + a = [0, 0, 0] + b = [0, 0, 0] + c = [0, 0, 0] + d = False + for item in data: + # ----------- a ------------- + if item[0] == 10: # 10 = x + a[0] = item[1] + elif item[0] == 20: # 20 = y + a[1] = item[1] + elif item[0] == 30: # 30 = z + a[2] = item[1] + # ----------- b ------------- + elif item[0] == 11: # 11 = x + b[0] = item[1] + elif item[0] == 21: # 21 = y + b[1] = item[1] + elif item[0] == 31: # 31 = z + b[2] = item[1] + # ----------- c ------------- + elif item[0] == 12: # 12 = x + c[0] = item[1] + elif item[0] == 22: # 22 = y + c[1] = item[1] + elif item[0] == 32: # 32 = z + c[2] = item[1] + # ----------- d ------------- + elif item[0] == 13: # 13 = x + d = [0, 0, 0] + d[0] = item[1] + elif item[0] == 23: # 23 = y + d[1] = item[1] + elif item[0] == 33: # 33 = z + d[2] = item[1] + out = [a,b,c] + if d: + out.append(d) + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + +def get_name(data): + """Get the name of an object from its object data. + + Returns a pair of (data_item, name) where data_item is the list entry where the name was found + (the data_item can be used to remove the entry from the object data). Be sure to check + name not None before using the returned values! + """ + value = None + for i, item in enumerate(data): + if item[0] == 2: + value = item[1] + break + return item, value, i + +def get_layer(data): + """Expects object data as input. + + Returns (entry, layer_name, entry_index) where entry is the data item that provided the layer name. + """ + value = None + for i, item in enumerate(data): + if item[0] == 8: + value = item[1] + break + return item, value, i + + +# type to object map +type_map = { + 'line':Line, + 'lwpolyline':LWpolyline, + 'text':Text, + 'mtext':Mtext, + 'circle':Circle, + 'arc':Arc, + 'layer':Layer, + 'block_record':BlockRecord, + 'block':Block, + 'insert':Insert, + 'ellipse':Ellipse, + '3dface':Face +} + +def objectify(data): + """Expects a section type object's data as input. + + Maps object data to the correct object type. + """ + objects = [] # colector for finished objects + known_types = type_map.keys() # so we don't have to call foo.keys() every iteration + index = 0 + while index < len(data): + item = data[index] + if type(item) != list and item.type in known_types: + # proccess the object and append the resulting object + objects.append(type_map[item.type](item)) + elif type(item) != list and item.type == 'table': + item.data = objectify(item.data) # tables have sub-objects + objects.append(item) + elif type(item) != list and item.type == 'polyline': + pline = Polyline(item) + while 1: + index += 1 + item = data[index] + if item.type == 'vertex': + v = Vertex(item) + pline.points.append(v) + elif item.type == 'seqend': + break + else: + print "Error: non-vertex found before seqend!" + index -= 1 + break + objects.append(pline) + else: + # we will just let the data pass un-harrased + objects.append(item) + index += 1 + return objects +if __name__ == "__main__": + print "No example yet!" \ No newline at end of file diff --git a/release/scripts/bpymodules/dxfReader.py b/release/scripts/bpymodules/dxfReader.py new file mode 100644 index 00000000000..d4a39cf63d6 --- /dev/null +++ b/release/scripts/bpymodules/dxfReader.py @@ -0,0 +1,382 @@ +"""This module provides a function for reading dxf files and parsing them into a useful tree of objects and data. + + The convert function is called by the readDXF fuction to convert dxf strings into the correct data based + on their type code. readDXF expects a (full path) file name as input. +""" + +# -------------------------------------------------------------------------- +# DXF Reader v0.9 by Ed Blake (AKA Kitsu) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +#from dxfImportObjects import * + +class Object: + """Empty container class for dxf objects""" + + def __init__(self, _type='', block=False): + """_type expects a string value.""" + self.type = _type + self.name = '' + self.data = [] + + def __str__(self): + if self.name: + return self.name + else: + return self.type + + def __repr__(self): + return str(self.data) + + def get_type(self, kind=''): + """Despite the name, this method actually returns all objects of type 'kind' from self.data.""" + if type: + objects = [] + for item in self.data: + if type(item) != list and item.type == kind: + # we want this type of object + objects.append(item) + elif type(item) == list and item[0] == kind: + # we want this type of data + objects.append(item[1]) + return objects + + +class InitializationError(Exception): pass + +class StateMachine: + """(finite) State Machine from the great David Mertz's great Charming Python article.""" + + def __init__(self): + self.handlers = [] + self.startState = None + self.endStates = [] + + def add_state(self, handler, end_state=0): + """All states and handlers are functions which return + a state and a cargo.""" + self.handlers.append(handler) + if end_state: + self.endStates.append(handler) + def set_start(self, handler): + """Sets the starting handler function.""" + self.startState = handler + + + def run(self, cargo=None): + if not self.startState: + raise InitializationError,\ + "must call .set_start() before .run()" + if not self.endStates: + raise InitializationError, \ + "at least one state must be an end_state" + handler = self.startState + while 1: + (newState, cargo) = handler(cargo) + #print cargo + if newState in self.endStates: + return newState(cargo) + #break + elif newState not in self.handlers: + raise RuntimeError, "Invalid target %s" % newState + else: + handler = newState + +def get_name(data): + """Get the name of an object from its object data. + + Returns a pair of (data_item, name) where data_item is the list entry where the name was found + (the data_item can be used to remove the entry from the object data). Be sure to check + name not None before using the returned values! + """ + value = None + for item in data: + if item[0] == 2: + value = item[1] + break + return item, value + +def get_layer(data): + """Expects object data as input. + + Returns (entry, layer_name) where entry is the data item that provided the layer name. + """ + value = None + for item in data: + if item[0] == 8: + value = item[1] + break + return item, value + + +def convert(code, value): + """Convert a string to the correct Python type based on its dxf code. + code types: + ints = 60-79, 170-179, 270-289, 370-389, 400-409, 1060-1070 + longs = 90-99, 420-429, 440-459, 1071 + floats = 10-39, 40-59, 110-139, 140-149, 210-239, 460-469, 1010-1059 + hex = 105, 310-379, 390-399 + strings = 0-9, 100, 102, 300-309, 410-419, 430-439, 470-479, 999, 1000-1009 + """ + if 59 < code < 80 or 169 < code < 180 or 269 < code < 290 or 369 < code < 390 or 399 < code < 410 or 1059 < code < 1071: + value = int(value) + elif 89 < code < 100 or 419 < code < 430 or 439 < code < 460 or code == 1071: + value = long(value) + elif 9 < code < 60 or 109 < code < 150 or 209 < code < 240 or 459 < code < 470 or 1009 < code < 1060: + value = float(value) + elif code == 105 or 309 < code < 380 or 389 < code < 400: + value = int(value, 16) # should be left as string? + else: # it's already a string so do nothing + pass + return value + + +def findObject(infile, kind=''): + """Finds the next occurance of an object.""" + obj = False + while 1: + line = infile.readline() + if not line: # readline returns '' at eof + return False + if not obj: # We're still looking for our object code + if line.lower().strip() == '0': + obj = True # found it + else: # we are in an object definition + if kind: # if we're looking for a particular kind + if line.lower().strip() == kind: + obj = Object(line.lower().strip()) + break + else: # otherwise take anything non-numeric + if line.lower().strip() not in string.digits: + obj = Object(line.lower().strip()) + break + obj = False # whether we found one or not it's time to start over + return obj + +def handleObject(infile): + """Add data to an object until end of object is found.""" + line = infile.readline() + if line.lower().strip() == 'section': + return 'section' # this would be a problem + elif line.lower().strip() == 'endsec': + return 'endsec' # this means we are done with a section + else: # add data to the object until we find a new object + obj = Object(line.lower().strip()) + obj.name = obj.type + done = False + data = [] + while not done: + line = infile.readline() + if not data: + if line.lower().strip() == '0': + #we've found an object, time to return + return obj + else: + # first part is always an int + data.append(int(line.lower().strip())) + else: + data.append(convert(data[0], line.strip())) + obj.data.append(data) + data = [] + +def handleTable(table, infile): + """Special handler for dealing with nested table objects.""" + item, name = get_name(table.data) + if name: # We should always find a name + table.data.remove(item) + table.name = name.lower() + # This next bit is from handleObject + # handleObject should be generalized to work with any section like object + while 1: + obj = handleObject(infile) + if obj.type == 'table': + print "Warning: previous table not closed!" + return table + elif obj.type == 'endtab': + return table # this means we are done with the table + else: # add objects to the table until one of the above is found + table.data.append(obj) + + + + +def handleBlock(block, infile): + """Special handler for dealing with nested table objects.""" + item, name = get_name(block.data) + if name: # We should always find a name + block.data.remove(item) + block.name = name + # This next bit is from handleObject + # handleObject should be generalized to work with any section like object + while 1: + obj = handleObject(infile) + if obj.type == 'block': + print "Warning: previous block not closed!" + return block + elif obj.type == 'endblk': + return block # this means we are done with the table + else: # add objects to the table until one of the above is found + block.data.append(obj) + + + + +"""These are the states/functions used in the State Machine. +states: + start - find first section + start_section - add data, find first object + object - add obj-data, watch for next obj (called directly by start_section) + end_section - look for next section or eof + end - return results +""" + +def start(cargo): + """Expects the infile as cargo, initializes the cargo.""" + #print "Entering start state!" + infile = cargo + drawing = Object('drawing') + section = findObject(infile, 'section') + if section: + return start_section, (infile, drawing, section) + else: + return error, (infile, "Failed to find any sections!") + +def start_section(cargo): + """Expects [infile, drawing, section] as cargo, builds a nested section object.""" + #print "Entering start_section state!" + infile = cargo[0] + drawing = cargo[1] + section = cargo[2] + # read each line, if it is an object declaration go to object mode + # otherwise create a [index, data] pair and add it to the sections data. + done = False + data = [] + while not done: + line = infile.readline() + + if not data: # if we haven't found a dxf code yet + if line.lower().strip() == '0': + # we've found an object + while 1: # no way out unless we find an end section or a new section + obj = handleObject(infile) + if obj == 'section': # shouldn't happen + print "Warning: failed to close previous section!" + return end_section, (infile, drawing) + elif obj == 'endsec': # This section is over, look for the next + drawing.data.append(section) + return end_section, (infile, drawing) + elif obj.type == 'table': # tables are collections of data + obj = handleTable(obj, infile) # we need to find all there contents + section.data.append(obj) # before moving on + elif obj.type == 'block': # the same is true of blocks + obj = handleBlock(obj, infile) # we need to find all there contents + section.data.append(obj) # before moving on + else: # found another sub-object + section.data.append(obj) + else: + data.append(int(line.lower().strip())) + else: # we have our code, now we just need to convert the data and add it to our list. + data.append(convert(data[0], line.strip())) + section.data.append(data) + data = [] +def end_section(cargo): + """Expects (infile, drawing) as cargo, searches for next section.""" + #print "Entering end_section state!" + infile = cargo[0] + drawing = cargo[1] + section = findObject(infile, 'section') + if section: + return start_section, (infile, drawing, section) + else: + return end, (infile, drawing) + +def end(cargo): + """Expects (infile, drawing) as cargo, called when eof has been reached.""" + #print "Entering end state!" + infile = cargo[0] + drawing = cargo[1] + #infile.close() + return drawing + +def error(cargo): + """Expects a (infile, string) as cargo, called when there is an error during processing.""" + #print "Entering error state!" + infile = cargo[0] + err = cargo[1] + infile.close() + print "There has been an error:" + print err + return False + +def readDXF(filename, objectify): + """Given a file name try to read it as a dxf file. + + Output is an object with the following structure + drawing + header + header data + classes + class data + tables + table data + blocks + block data + entities + entity data + objects + object data + where foo data is a list of sub-objects. True object data + is of the form [code, data]. +""" + infile = open(filename) + + sm = StateMachine() + sm.add_state(error, True) + sm.add_state(end, True) + sm.add_state(start_section) + sm.add_state(end_section) + sm.add_state(start) + sm.set_start(start) + try: + drawing = sm.run(infile) + if drawing: + drawing.name = filename + for obj in drawing.data: + item, name = get_name(obj.data) + if name: + obj.data.remove(item) + obj.name = name.lower() + setattr(drawing, name.lower(), obj) + # Call the objectify function to cast + # raw objects into the right types of object + obj.data = objectify(obj.data) + #print obj.name + finally: + infile.close() + return drawing +if __name__ == "__main__": + filename = r".\examples\block-test.dxf" + drawing = readDXF(filename) + for item in drawing.entities.data: + print item + + diff --git a/release/scripts/bpymodules/mesh_gradient.py b/release/scripts/bpymodules/mesh_gradient.py new file mode 100644 index 00000000000..936f4958467 --- /dev/null +++ b/release/scripts/bpymodules/mesh_gradient.py @@ -0,0 +1,229 @@ +# This is not to be used directly, vertexGradientPick can be used externaly + +import Blender +import BPyMesh +import BPyWindow + +mouseViewRay= BPyWindow.mouseViewRay +from Blender import Mathutils, Window, Scene, Draw, sys +from Blender.Mathutils import CrossVecs, Vector, Intersect, LineIntersect, AngleBetweenVecs +LMB= Window.MButs['L'] + +def mouseup(): + # Loop until click + mouse_buttons = Window.GetMouseButtons() + while not mouse_buttons & LMB: + sys.sleep(10) + mouse_buttons = Window.GetMouseButtons() + while mouse_buttons & LMB: + sys.sleep(10) + mouse_buttons = Window.GetMouseButtons() + +def mousedown_wait(): + # If the menu has just been pressed dont use its mousedown, + mouse_buttons = Window.GetMouseButtons() + while mouse_buttons & LMB: + mouse_buttons = Window.GetMouseButtons() + +eps= 0.0001 +def vertexGradientPick(ob, MODE): + #MODE 0 == VWEIGHT, 1 == VCOL + + me= ob.getData(mesh=1) + if not me.faceUV: me.faceUV= True + + Window.DrawProgressBar (0.0, '') + + mousedown_wait() + + if MODE==0: + act_group= me.activeGroup + if act_group == None: + mousedown_wait() + Draw.PupMenu('Error, mesh has no active group.') + return + + # Loop until click + Window.DrawProgressBar (0.25, 'Click to set gradient start') + mouseup() + + obmat= ob.matrixWorld + screen_x, screen_y = Window.GetMouseCoords() + mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat) + if not mouseInView or not OriginA: + return + + # get the mouse weight + + if MODE==0: + pickValA= BPyMesh.pickMeshGroupWeight(me, act_group, OriginA, DirectionA) + if MODE==1: + pickValA= BPyMesh.pickMeshGroupVCol(me, OriginA, DirectionA) + + Window.DrawProgressBar (0.75, 'Click to set gradient end') + mouseup() + + TOALPHA= Window.GetKeyQualifiers() & Window.Qual.SHIFT + + screen_x, screen_y = Window.GetMouseCoords() + mouseInView, OriginB, DirectionB = mouseViewRay(screen_x, screen_y, obmat) + if not mouseInView or not OriginB: + return + + if not TOALPHA: # Only get a second opaque value if we are not blending to alpha + if MODE==0: pickValB= BPyMesh.pickMeshGroupWeight(me, act_group, OriginB, DirectionB) + else: + pickValB= BPyMesh.pickMeshGroupVCol(me, OriginB, DirectionB) + else: + if MODE==0: pickValB= 0.0 + else: pickValB= [0.0, 0.0, 0.0] # Dummy value + + # Neither points touched a face + if pickValA == pickValB == None: + return + + # clicking on 1 non face is fine. just set the weight to 0.0 + if pickValA==None: + pickValA= 0.0 + + # swap A/B + OriginA, OriginB= OriginB, OriginA + DirectionA, DirectionB= DirectionB, DirectionA + pickValA, pickValB= pickValA, pickValB + + TOALPHA= True + + if pickValB==None: + pickValB= 0.0 + TOALPHA= True + + # set up 2 lines so we can measure their distances and calc the gradient + + # make a line 90d to the grad in screenspace. + if (OriginA-OriginB).length <= eps: # Persp view. same origin different direction + cross_grad= CrossVecs(DirectionA, DirectionB) + ORTHO= False + + else: # Ortho - Same direction, different origin + cross_grad= CrossVecs(DirectionA, OriginA-OriginB) + ORTHO= True + + cross_grad.normalize() + cross_grad= cross_grad * 100 + + lineA= (OriginA, OriginA+(DirectionA*100)) + lineB= (OriginB, OriginB+(DirectionB*100)) + + if not ORTHO: + line_angle= AngleBetweenVecs(lineA[1], lineB[1])/2 + line_mid= (lineA[1]+lineB[1])*0.5 + + VSEL= [False] * (len(me.verts)) + + # Get the selected faces and apply the selection to the verts. + for f in me.faces: + if f.sel: + for v in f.v: + VSEL[v.index]= True + groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) + + + + def grad_weight_from_co(v): + ''' + Takes a vert and retuens its gradient radio between A and B + ''' + + if not VSEL[v.index]: # Not bart of a selected face? + return None, None + + v_co= v.co + # make a line 90d to the 2 lines the user clicked. + vert_line= (v_co - cross_grad, v_co + cross_grad) + + xA= LineIntersect(vert_line[0], vert_line[1], lineA[0], lineA[1]) + xB= LineIntersect(vert_line[0], vert_line[1], lineB[0], lineB[1]) + + if not xA or not xB: # Should never happen but support it anyhow + return None, None + + wA= (xA[0]-xA[1]).length + wB= (xB[0]-xB[1]).length + + wTot= wA+wB + if not wTot: # lines are on the same point. + return None, None + + ''' + Get the length of the line between both intersections on the + 2x view lines. + if the dist between lineA+VertLine and lineB+VertLine is + greater then the lenth between lineA and lineB intersection points, it means + that the verts are not inbetween the 2 lines. + ''' + lineAB_length= (xA[1]-xB[1]).length + + # normalzie + wA= wA/wTot + wB= wB/wTot + + if ORTHO: # Con only use line length method with parelelle lines + if wTot > lineAB_length+eps: + # vert is outside the range on 1 side. see what side of the grad + if wA>wB: wA, wB= 1.0, 0.0 + else: wA, wB= 0.0, 1.0 + else: + # PERSP, lineA[0] is the same origin as lineB[0] + + # Either xA[0] or xB[0] can be used instead of a possible x_mid between the 2 + # as long as the point is inbetween lineA and lineB it dosent matter. + a= AngleBetweenVecs(lineA[0]-xA[0], line_mid) + if a>line_angle: + # vert is outside the range on 1 side. see what side of the grad + if wA>wB: wA, wB= 1.0, 0.0 + else: wA, wB= 0.0, 1.0 + + return wA, wB + + + grad_weights= [grad_weight_from_co(v) for v in me.verts] + + + if MODE==0: + for v in me.verts: + i= v.index + if VSEL[i]: + wA, wB = grad_weights[i] + if wA != None: # and wB + if TOALPHA: + # Do alpha by using the exiting weight for + try: pickValB= vWeightDict[i][act_group] + except: pickValB= 0.0 # The weights not there? assume zero + # Mix2 2 opaque weights + vWeightDict[i][act_group]= pickValB*wA + pickValA*wB + + else: # MODE==1 VCol + for f in me.faces: + if f.sel: + f_v= f.v + for i in xrange(len(f_v)): + v= f_v[i] + wA, wB = grad_weights[v.index] + + c= f.col[i] + + if TOALPHA: + pickValB= c.r, c.g, c.b + + c.r = int(pickValB[0]*wA + pickValA[0]*wB) + c.g = int(pickValB[1]*wA + pickValA[1]*wB) + c.b = int(pickValB[2]*wA + pickValA[2]*wB) + + + + + # Copy weights back to the mesh. + BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) + Window.DrawProgressBar (1.0, '') + + diff --git a/release/scripts/bpymodules/meshtools.py b/release/scripts/bpymodules/meshtools.py new file mode 100644 index 00000000000..274a12ea6da --- /dev/null +++ b/release/scripts/bpymodules/meshtools.py @@ -0,0 +1,355 @@ +# $Id$ +# +# +---------------------------------------------------------+ +# | Copyright (c) 2001 Anthony D'Agostino | +# | http://www.redrival.com/scorpius | +# | scorpius@netzero.com | +# | September 28, 2002 | +# +---------------------------------------------------------+ +# | Common Functions & Global Variables For All IO Modules | +# +---------------------------------------------------------+ + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +import Blender +import sys + +show_progress = 1 # Set to 0 for faster performance +average_vcols = 1 # Off for per-face, On for per-vertex +overwrite_mesh_name = 0 # Set to 0 to increment object-name version + +blender_version = Blender.Get('version') +blender_version_str = `blender_version`[0] + '.' + `blender_version`[1:] + +try: + import operator +except: + msg = "Error: you need a full Python install to run this script." + meshtools.print_boxed(msg) + Blender.Draw.PupMenu("ERROR%t|"+msg) + +# ================================= +# === Append Faces To Face List === +# ================================= +def append_faces(mesh, faces, facesuv, uvcoords): + for i in xrange(len(faces)): + if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(faces), "Generating Faces") + numfaceverts=len(faces[i]) + if numfaceverts == 2: #This is not a face is an edge + if mesh.edges == None: #first run + mesh.addEdgeData() + #rev_face = revert(cur_face) + i1 = faces[i][0] + i2 = faces[i][1] + ee = mesh.addEdge(mesh.verts[i1],mesh.verts[i2]) + ee.flag |= Blender.NMesh.EdgeFlags.EDGEDRAW + ee.flag |= Blender.NMesh.EdgeFlags.EDGERENDER + elif numfaceverts in [3,4]: # This face is a triangle or quad + face = Blender.NMesh.Face() + for j in xrange(numfaceverts): + index = faces[i][j] + face.v.append(mesh.verts[index]) + if len(uvcoords) > 1: + uvidx = facesuv[i][j] + face.uv.append(uvcoords[uvidx]) + face.mode = 0 + face.col = [Blender.NMesh.Col()]*4 + mesh.faces.append(face) + else: # Triangulate n-sided convex polygon. + a, b, c = 0, 1, 2 # Indices of first triangle. + for j in xrange(numfaceverts-2): # Number of triangles in polygon. + face = Blender.NMesh.Face() + face.v.append(mesh.verts[faces[i][a]]) + face.v.append(mesh.verts[faces[i][b]]) + face.v.append(mesh.verts[faces[i][c]]) + b = c; c += 1 + mesh.faces.append(face) + #face.smooth = 1 + +# =================================== +# === Append Verts to Vertex List === +# =================================== +def append_verts(mesh, verts, normals): + #print "Number of normals:", len(normals) + #print "Number of verts :", len(verts) + for i in xrange(len(verts)): + if not i%100 and show_progress: Blender.Window.DrawProgressBar(float(i)/len(verts), "Generating Verts") + x, y, z = verts[i] + mesh.verts.append(Blender.NMesh.Vert(x, y, z)) + if normals: + mesh.verts[i].no[0] = normals[i][0] + mesh.verts[i].no[1] = normals[i][1] + mesh.verts[i].no[2] = normals[i][2] + +# =========================== +# === Create Blender Mesh === +# =========================== +def create_mesh(verts, faces, objname, facesuv=[], uvcoords=[], normals=[]): + if normals: normal_flag = 0 + else: normal_flag = 1 + mesh = Blender.NMesh.GetRaw() + append_verts(mesh, verts, normals) + append_faces(mesh, faces, facesuv, uvcoords) + if not overwrite_mesh_name: + objname = versioned_name(objname) + ob= Blender.NMesh.PutRaw(mesh, objname, normal_flag) # Name the Mesh + ob.name= objname # Name the Object + Blender.Redraw() + +# ============================== +# === Increment Name Version === +# ============================== +def versioned_name(objname): + existing_names = [] + for object in Blender.Object.Get(): + existing_names.append(object.name) + existing_names.append(object.getData(name_only=1)) + if objname in existing_names: # don't over-write other names + try: + name, ext = objname.split('.') + except ValueError: + name, ext = objname, '' + try: + num = int(ext) + root = name + except ValueError: + root = objname + for i in xrange(1, 1000): + objname = "%s.%03d" % (root, i) + if objname not in existing_names: + break + return objname + +# =========================== +# === Print Text In A Box === +# =========================== +def print_boxed(text): + lines = text.splitlines() + maxlinelen = max(map(len, lines)) + if sys.platform[:3] == "win": + print chr(218)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(191) + for line in lines: + print chr(179) + ' ' + line.ljust(maxlinelen) + ' ' + chr(179) + print chr(192)+chr(196) + chr(196)*maxlinelen + chr(196)+chr(217) + else: + print '+-' + '-'*maxlinelen + '-+' + for line in lines: print '| ' + line.ljust(maxlinelen) + ' |' + print '+-' + '-'*maxlinelen + '-+' + print '\a\r', # beep when done + +# =============================================== +# === Get euler angles from a rotation matrix === +# =============================================== +def mat2euler(mat): + angle_y = -math.asin(mat[0][2]) + c = math.cos(angle_y) + if math.fabs(c) > 0.005: + angle_x = math.atan2(mat[1][2]/c, mat[2][2]/c) + angle_z = math.atan2(mat[0][1]/c, mat[0][0]/c) + else: + angle_x = 0.0 + angle_z = -math.atan2(mat[1][0], mat[1][1]) + return (angle_x, angle_y, angle_z) + +# ========================== +# === Transpose A Matrix === +# ========================== +def transpose(A): + S = len(A) + T = len(A[0]) + B = [[None]*S for i in xrange(T)] + for i in xrange(T): + for j in xrange(S): + B[i][j] = A[j][i] + return B + +# ======================= +# === Apply Transform === +# ======================= +def apply_transform(vertex, matrix): + x, y, z = vertex + xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2] + xcomponent = x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc + ycomponent = x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc + zcomponent = x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc + vertex = [xcomponent, ycomponent, zcomponent] + return vertex + +# ========================= +# === Has Vertex Colors === +# ========================= +def has_vertex_colors(mesh): + # My replacement/workaround for hasVertexColours() + # The docs say: + # "Warning: If a mesh has both vertex colours and textured faces, + # this function will return False. This is due to the way Blender + # deals internally with the vertex colours array (if there are + # textured faces, it is copied to the textured face structure and + # the original array is freed/deleted)." + try: + return mesh.faces[0].col[0] + except: + return 0 + +# =========================== +# === Generate Edge Table === +# =========================== +def generate_edgetable(mesh): + edge_table = {} + numfaces = len(mesh.faces) + + for i in xrange(numfaces): + if not i%100 and show_progress: + Blender.Window.DrawProgressBar(float(i)/numfaces, "Generating Edge Table") + if len(mesh.faces[i].v) == 4: # Process Quadrilaterals + generate_entry_from_quad(mesh, i, edge_table) + elif len(mesh.faces[i].v) == 3: # Process Triangles + generate_entry_from_tri(mesh, i, edge_table) + else: # Skip This Face + print "Face #", i, "was skipped." + + # === Sort Edge_Table Keys & Add Edge Indices === + i = 0 + keys = edge_table.keys() + keys.sort() + for key in keys: + edge_table[key][6] = i + i += 1 + + # === Replace Tuples With Indices === + for key in keys: + for i in [2,3,4,5]: + if edge_table.has_key(edge_table[key][i]): + edge_table[key][i] = edge_table[edge_table[key][i]][6] + else: + keyrev = (edge_table[key][i][1], edge_table[key][i][0]) + edge_table[key][i] = edge_table[keyrev][6] + + return edge_table + +# ================================ +# === Generate Entry From Quad === +# ================================ +def generate_entry_from_quad(mesh, i, edge_table): + vertex4, vertex3, vertex2, vertex1 = mesh.faces[i].v + + if has_vertex_colors(mesh): + vcolor4, vcolor3, vcolor2, vcolor1 = mesh.faces[i].col + Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0) + Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0) + Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0) + Dcol = (vcolor4.r/255.0, vcolor4.g/255.0, vcolor4.b/255.0) + + # === verts are upper case, edges are lower case === + A, B, C, D = vertex1.index, vertex2.index, vertex3.index, vertex4.index + a, b, c, d = (A, B), (B, C), (C, D), (D, A) + + if edge_table.has_key((B, A)): + edge_table[(B, A)][1] = i + edge_table[(B, A)][4] = d + edge_table[(B, A)][5] = b + if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol + else: + if has_vertex_colors(mesh): + edge_table[(A, B)] = [i, None, d, b, None, None, None, Bcol, None] + else: + edge_table[(A, B)] = [i, None, d, b, None, None, None] + + if edge_table.has_key((C, B)): + edge_table[(C, B)][1] = i + edge_table[(C, B)][4] = a + edge_table[(C, B)][5] = c + if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol + else: + if has_vertex_colors(mesh): + edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None] + else: + edge_table[(B, C)] = [i, None, a, c, None, None, None] + + if edge_table.has_key((D, C)): + edge_table[(D, C)][1] = i + edge_table[(D, C)][4] = b + edge_table[(D, C)][5] = d + if has_vertex_colors(mesh): edge_table[(D, C)][8] = Dcol + else: + if has_vertex_colors(mesh): + edge_table[(C, D)] = [i, None, b, d, None, None, None, Dcol, None] + else: + edge_table[(C, D)] = [i, None, b, d, None, None, None] + + if edge_table.has_key((A, D)): + edge_table[(A, D)][1] = i + edge_table[(A, D)][4] = c + edge_table[(A, D)][5] = a + if has_vertex_colors(mesh): edge_table[(A, D)][8] = Acol + else: + if has_vertex_colors(mesh): + edge_table[(D, A)] = [i, None, c, a, None, None, None, Acol, None] + else: + edge_table[(D, A)] = [i, None, c, a, None, None, None] + +# ==================================== +# === Generate Entry From Triangle === +# ==================================== +def generate_entry_from_tri(mesh, i, edge_table): + vertex3, vertex2, vertex1 = mesh.faces[i].v + + if has_vertex_colors(mesh): + vcolor3, vcolor2, vcolor1, _vcolor4_ = mesh.faces[i].col + Acol = (vcolor1.r/255.0, vcolor1.g/255.0, vcolor1.b/255.0) + Bcol = (vcolor2.r/255.0, vcolor2.g/255.0, vcolor2.b/255.0) + Ccol = (vcolor3.r/255.0, vcolor3.g/255.0, vcolor3.b/255.0) + + # === verts are upper case, edges are lower case === + A, B, C = vertex1.index, vertex2.index, vertex3.index + a, b, c = (A, B), (B, C), (C, A) + + if edge_table.has_key((B, A)): + edge_table[(B, A)][1] = i + edge_table[(B, A)][4] = c + edge_table[(B, A)][5] = b + if has_vertex_colors(mesh): edge_table[(B, A)][8] = Bcol + else: + if has_vertex_colors(mesh): + edge_table[(A, B)] = [i, None, c, b, None, None, None, Bcol, None] + else: + edge_table[(A, B)] = [i, None, c, b, None, None, None] + + if edge_table.has_key((C, B)): + edge_table[(C, B)][1] = i + edge_table[(C, B)][4] = a + edge_table[(C, B)][5] = c + if has_vertex_colors(mesh): edge_table[(C, B)][8] = Ccol + else: + if has_vertex_colors(mesh): + edge_table[(B, C)] = [i, None, a, c, None, None, None, Ccol, None] + else: + edge_table[(B, C)] = [i, None, a, c, None, None, None] + + if edge_table.has_key((A, C)): + edge_table[(A, C)][1] = i + edge_table[(A, C)][4] = b + edge_table[(A, C)][5] = a + if has_vertex_colors(mesh): edge_table[(A, C)][8] = Acol + else: + if has_vertex_colors(mesh): + edge_table[(C, A)] = [i, None, b, a, None, None, None, Acol, None] + else: + edge_table[(C, A)] = [i, None, b, a, None, None, None] + diff --git a/release/scripts/bpymodules/paths_ai2obj.py b/release/scripts/bpymodules/paths_ai2obj.py new file mode 100644 index 00000000000..dcf56853184 --- /dev/null +++ b/release/scripts/bpymodules/paths_ai2obj.py @@ -0,0 +1,502 @@ +""" +paths_ai2obj.py +# --------------------------------------------------------------- +Copyright (c) jm soler juillet/novembre 2004-april 2007, +# --------------------------------------------------------------- + released under GNU Licence + for the Blender 2.45 Python Scripts Bundle. +Ce programme est libre, vous pouvez le redistribuer et/ou +le modifier selon les termes de la Licence Publique Générale GNU +publiée par la Free Software Foundation (version 2 ou bien toute +autre version ultérieure choisie par vous). + +Ce programme est distribué car potentiellement utile, mais SANS +AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties +de commercialisation ou d'adaptation dans un but spécifique. +Reportez-vous à la Licence Publique Générale GNU pour plus de détails. + +Vous devez avoir reçu une copie de la Licence Publique Générale GNU +en même temps que ce programme ; si ce n'est pas le cas, écrivez à la +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +MA 02111-1307, États-Unis. + + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# --------------------------------------------------------------- +#---------------------------------------------- +# +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_ai_en.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#---------------------------------------------- +#---------------------------------------------- +#Chagelog +#---------------------------------------------- +# 0.1.1 : 2004/08/03, bug in boudingbox reading when Value are negative +# 0.1.2 : 2005/06/12, gmove tranformation properties +# 0.1.3 : 2005/06/25, added a __name__ test to use the script alone +# 0.1.4 : 2005/06/25, closepath improvements +# 0.1.5 : 2005/06/25, ... +# 0.1.6 : 2005/06/26, warning for compacted file + compatibility increased up to AI 10.0 plain text +# 0.1.7 : 2005/06/25, two more closepath improvements +# +# 0.1.8 : 2006/07/03, two more closepath improvements +# 0.1.9 : 2007/05/06, modif on the method that gets the last object on + the list data +""" +SHARP_IMPORT=0 +SCALE=1 +NOTHING_TODO=1 +AI_VERSION='' + +GSTACK = [] +GSCALE = [] +GTRANSLATE = [] + +import sys +#oldpath=sys.path +import Blender +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'rU') + t=f.readlines() + f.close() + + if len(t)>1 and t[0].find('EPSF')==-1: + return t + else: + name = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 + result = Blender.Draw.PupMenu(name) + + return 'false' + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + self.tag='' + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.0 0.0 +0.0 1.0 0.0 0.0 +0.0 0.0 1.0 0.0 +0.0 0.0 0.0 1.0 """ + self.ITEM = {} + +courbes=COURBE() + +PATTERN={} + +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in teh courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + + +# modifs 12/06/2005 +#===================================================================== +#====================== current transform ============================ +#===================================================================== +class transform: + def __init__(self,matrix=[1,0,01],x=0.0,y=0.0): + self.matrix=matrix[:] + self.xy=[x,y] + +def G_move(l,a): + global GSCALE, GTRANSLATE, GSTACK + #print GSCALE, GTRANSLATE, GSTACK + return str((float(l)+GTRANSLATE[a]+GSTACK[-1].xy[a])*GSCALE[a]) +# modifs 12/06/2005 + + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + if BLversion>=233: + in_editmode = Blender.Window.EditMode() + if in_editmode: Blender.Window.EditMode(0) + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Scene.GetCurrent().objects.active + BO.RotY=0.0 + BO.RotX=1.57 + BO.makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX + r=BOUNDINGBOX['rec'] + + if SCALE==1: + SCALE=1.0 + elif SCALE==2: + SCALE=r[2]-r[0] + elif SCALE==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + if len(courbes.ITEM[k].beziers_knot)>1 : + t.append("%s\n"%courbes.ITEM[k].type) + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =courbes.ITEM[k].flagUV[0] + + for k2 in range(len(courbes.ITEM[k].beziers_knot)): + #print k2 + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(warning) + + +#===================================================================== +#===== AI format : DEBUT ========================= +#===================================================================== +def mouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + n0+=1 + + CP=[l[-3].replace('d',''),l[-2]] + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=[0,0] + B.tag=l[-1] + + courbes.ITEM[n0].beziers_knot.append(B) + + return courbes,n0,CP + +def courbe_vers_c(l,l2, n0,CP): #c,C + + B=Bez() + B.co=[l[4],l[5],l[2],l[3],l[4],l[5]] + B.tag=l[-1] + B.ha=[0,0] + + BP=courbes.ITEM[n0].beziers_knot[-1] + + BP.co[0]=l[0] + BP.co[1]=l[1] + + courbes.ITEM[n0].beziers_knot.append(B) + + CP=[B.co[4],B.co[5]] + return courbes,n0,CP + + +def courbe_vers_v(l,n0,CP): #v-V + + B=Bez() + B.tag=l[-1] + B.co=[l[2],l[3],l[0],l[1],l[2],l[3]] + B.ha=[0,0] + + courbes.ITEM[n0].beziers_knot.append(B) + + CP=[B.co[4],B.co[5]] + return courbes,n0,CP + +def courbe_vers_y(l,n0,CP): #y + B=Bez() + B.tag=l[-1] + B.co=[l[2],l[3],l[2],l[3],l[2],l[3]] + B.ha=[0,0] + + BP=courbes.ITEM[n0].beziers_knot[-1] + BP.co[0]=l[0] + BP.co[1]=l[1] + + courbes.ITEM[n0].beziers_knot.append(B) + CP=[B.co[4],B.co[5]] + return courbes,n0,CP + + +def ligne_tracee_l(l,n0,CP): + B=Bez() + B.tag=l[-1] + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=[0,0] + + BP=courbes.ITEM[n0].beziers_knot[-1] + + courbes.ITEM[n0].beziers_knot.append(B) + CP=[B.co[4],B.co[5]] + return courbes,n0,CP + +def ligne_fermee(l,n0,CP): + courbes.ITEM[n0].flagUV[0]=1 + + if len(courbes.ITEM[n0].beziers_knot)>1: + BP=courbes.ITEM[n0].beziers_knot[-1] + BP0=courbes.ITEM[n0].beziers_knot[0] + + if BP.tag not in ['l','L']: + BP.co[0]=BP0.co[0] #4-5 point prec + BP.co[1]=BP0.co[1] + + del courbes.ITEM[n0].beziers_knot[0] + return courbes,n0,CP + +def passe(l,n0,CP): + return courbes,n0,CP + +Actions= { "C" : courbe_vers_c, + "c" : courbe_vers_c, + "V" : courbe_vers_v, + "v" : courbe_vers_v, + "Y" : courbe_vers_y, + "y" : courbe_vers_y, + "m" : mouvement_vers, + "l" : ligne_tracee_l, + "L" : ligne_tracee_l, + "F" : passe, + "f" : ligne_fermee, + "B" : passe, + "b" : ligne_fermee, + "S" : passe, + "s" : ligne_fermee, + "N" : ligne_fermee, + "n" : passe, + } + +TAGcourbe=Actions.keys() + +def pik_pattern(t,l): + global npat, PATTERN, BOUNDINGBOX, AI_VERSION + while t[l].find('%%EndSetup')!=0: + if t[l].find('%%Creator: Adobe Illustrator(R)')!=-1: + print t[l] + AI_VERSION=t[l].split()[-1] + print AI_VERSION + + if t[l].find('%%BoundingBox:')!=-1: + t[l]=t[l][t[l].find(':')+1:] + l0=t[l].split() + BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) + #print l, + if t[l].find('BeginPattern')!=-1: + nomPattern=t[l][t[l].find('(')+1:t[l].find(')')] + PATTERN[nomPattern]={} + + if t[l].find('BeginPatternLayer')!=-1: + npat+=1 + PATTERN[nomPattern][npat]=[] + while t[l].find('EndPatternLayer')==-1: + #print t[l] + PATTERN[nomPattern][npat].append(l) + l+=1 + if l+10: + if len(PATTERN.keys() )>0: + #print len(PATTERN.keys() ) + warning = "Pattern list (for info not used): %t| " + p0=1 + for P in PATTERN.keys(): + warning+="%s %%x%s|"%(P,p0) + p0+=1 + Padd = Blender.Draw.PupMenu(warning) + + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + + # 0.1.8 --------------------------------- + # [O.select(0) for O in Blender.Scene.getCurrent().getChildren()] + # 0.1.8 --------------------------------- + + Open_GEOfile(dir,name[0]) + + # 0.1.8 --------------------------------- + Blender.Object.Get()[-1].setName(name[0]) + # 0.1.8 --------------------------------- + + else: + pass +#===================================================================== +#====================== AI format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + global NOTHING_TODO,AI_VERSION + scan_FILE(nom) + if NOTHING_TODO==1: + warning = "AI %s compatible file "%AI_VERSION+" but nothing to do ? %t| Perhaps a compacted file ... " + NOTHING = Blender.Draw.PupMenu(warning) + +if __name__=="__main__": + Blender.Window.FileSelector (fonctionSELECT, 'SELECT AI FILE') +#sys.path=oldpath diff --git a/release/scripts/bpymodules/paths_eps2obj.py b/release/scripts/bpymodules/paths_eps2obj.py new file mode 100644 index 00000000000..e1643c3bf40 --- /dev/null +++ b/release/scripts/bpymodules/paths_eps2obj.py @@ -0,0 +1,452 @@ +#---------------------------------------------- +# (c) jm soler juillet 2004-juin 2005 , released under Blender Artistic Licence +# for the Blender 2.34-2.37 Python Scripts Bundle. +# +# last update: 06/05/2007 +#---------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_eps.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#---------------------------------------------- +SHARP_IMPORT = 0 +SCALE = 1.0 +scale = 1 + +import sys +#oldpath=sys.path + +import Blender +from Blender import Draw +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'rU') + t=f.readlines() + f.close() + if len(t)==1 and t[0].find('\r'): + t=t[0].split('\r') + if len(t)>1 and t[0].find('PS-Adobe-3.0')==-1 and t[0].find('EPSF')==-1: + return t + else: + name = "OK?%t| Not a valid file or an empty file or... %x1| not a pure PS-Adobe-2.0 file %x2 " + result = Blender.Draw.PupMenu(name) + return 'false' + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.0 0.0 +0.0 1.0 0.0 0.0 +0.0 0.0 1.0 0.0 +0.0 0.0 0.0 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size + self.ITEM = {} + +courbes=COURBE() +PATTERN={} +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in teh courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + +# modifs 12/06/2005 +#===================================================================== +#====================== current transform ============================ +#===================================================================== +class transform: + def __init__(self,matrix=[1,0,01],x=0.0,y=0.0): + self.matrix=matrix[:] + self.xy=[x,y] + +GSTACK = [] +stack=transform() +GSTACK.append(stack) + +GSCALE = [1.0,1.0] +GTRANSLATE = [0.0,0.0] + +def G_move(l,a): + global GSCALE, GTRANSLATE, GSTACK + #print GSCALE, GTRANSLATE, GSTACK + return str((float(l)+GTRANSLATE[a]+GSTACK[-1].xy[a])*GSCALE[a]) +# modifs 12/06/2005 + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + global SCALE,BOUNDINGBOX, scale + if BLversion>=233: + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Scene.GetCurrent().objects.active + BO.RotY=3.1416 + BO.RotZ=3.1416 + BO.RotX=3.1416/2.0 + if scale==1: + BO.LocY+=BOUNDINGBOX['rec'][3] + else: + BO.LocY+=BOUNDINGBOX['rec'][3]/SCALE + + BO.makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX,scale + r=BOUNDINGBOX['rec'] + + if scale==1: + SCALE=1.0 + elif scale==2: + SCALE=r[2]-r[0] + elif scale==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + t.append("%s\n"%courbes.ITEM[k].type) + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =courbes.ITEM[k].flagUV[0] + + for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + + #name = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(name) + + +#===================================================================== +#===== EPS format : DEBUT ========================= +#===================================================================== +def mouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): + # courbes.ITEM[n0].flagUV[0]=1 + n0+=1 + CP=[l[-3].replace('d',''),l[-2]] + else: + CP=[l[-3].replace('d',''),l[-2]] + #i= + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[G_move(CP[0],0), + G_move(CP[1],1), + G_move(CP[0],0), + G_move(CP[1],1), + G_move(CP[0],0), + G_move(CP[1],1)] + + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + + return courbes,n0,CP + +def rmouvement_vers(l,n0,CP): + if n0 in courbes.ITEM.keys(): + #if test_egalitedespositions(courbes.ITEM[n0].Origine,CP): + # courbes.ITEM[n0].flagUV[0]=1 + n0+=1 + CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))] + else: + CP=["%4f"%(float(l[-3])+float(CP[0])),"%4f"%(float(l[-2])+float(CP[1]))] + #i= + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3].replace('d',''),l[-2]] + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + return courbes,n0,CP + +def courbe_vers_c(l, l2, n0,CP): #c,C + """ + B=Bez() + B.co=[l[0],l[1],l[2],l[3],l[4],l[5]] + B.ha=[0,0] + + courbes.ITEM[n0].beziers_knot.append(B) + """ + B=Bez() + B.co=[G_move(l[2],0), + G_move(l[3],1), + G_move(l[4],0), + G_move(l[5],1), + G_move(l[0],0), + G_move(l[1],1)] + if len(courbes.ITEM[n0].beziers_knot)==1: + CP=[l[0],l[1]] + courbes.ITEM[n0].Origine=[l[0],l[1]] + if l[-1]=='C': + B.ha=[2,2] + else: + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + if len(l2)>1 and l2[-1] in Actions.keys(): + B.co[-2]=G_move(l2[0],0) + B.co[-1]=G_move(l2[1],1) + else: + B.co[-2]=G_move(CP[0],0) + B.co[-1]=G_move(CP[1],1) + return courbes,n0,CP + +def ligne_tracee_l(l,n0,CP): + B=Bez() + B.co=[G_move(l[0],0), + G_move(l[1],1), + G_move(l[0],0), + G_move(l[1],1), + G_move(l[0],0), + G_move(l[1],1)] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return courbes,n0,CP + +def rligne_tracee_l(l,n0,CP): + B=Bez() + B.co=["%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1])), + "%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1])), + "%4f"%(float(l[0])+float(CP[0])), + "%4f"%(float(l[1])+float(CP[1]))] + B.ha=[0,0] + courbes.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return courbes,n0,CP + +Actions= { "curveto" : courbe_vers_c, + "curveto" : courbe_vers_c, + "moveto" : mouvement_vers, + "rmoveto" : mouvement_vers, + "lineto" : ligne_tracee_l, + "rlineto" : rligne_tracee_l +} + +TAGcourbe=Actions.keys() + +""" +def pik_pattern(t,l): + global npat, PATTERN, BOUNDINGBOX + while t[l].find('%%EndSetup')!=0: + if t[l].find('%%BoundingBox:')!=-1: + l0=t[l].split() + BOUNDINGBOX['rec']=[float(l0[-4]),float(l0[-3]),float(l0[-2]),float(l0[-1])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[3]-r[1])/(r[2]-r[0]) + print l, + if t[l].find('BeginPatternLayer')!=-1: + npat+=1 + PATTERN[npat]=[] + while t[l].find('EndPatternLayer')==-1: + print t[l] + PATTERN[npat].append(l) + l+=1 + if l+10: + if len(PATTERN.keys() )>0: + #print len(PATTERN.keys() ) + pass + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + Open_GEOfile(dir,name[0]) + + # 03 juillet 2006 ---------------------- + Blender.Object.Get()[-1].setName(name[0]) + # 03 juillet 2006 ---------------------- + + else: + pass + + +#===================================================================== +#====================== EPS format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + scan_FILE(nom) + +if __name__=="__main__": + Blender.Window.FileSelector (fonctionSELECT, 'SELECT EPS FILE') + + diff --git a/release/scripts/bpymodules/paths_gimp2obj.py b/release/scripts/bpymodules/paths_gimp2obj.py new file mode 100644 index 00000000000..8b31c5d7294 --- /dev/null +++ b/release/scripts/bpymodules/paths_gimp2obj.py @@ -0,0 +1,359 @@ +""" +#---------------------------------------------- +# (c) jm soler juillet 2004, +#---------------------------------------------- + released under GNU Licence + for the Blender 2.45 Python Scripts Bundle. +Ce programme est libre, vous pouvez le redistribuer et/ou +le modifier selon les termes de la Licence Publique Générale GNU +publiée par la Free Software Foundation (version 2 ou bien toute +autre version ultérieure choisie par vous). + +Ce programme est distribué car potentiellement utile, mais SANS +AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties +de commercialisation ou d'adaptation dans un but spécifique. +Reportez-vous à la Licence Publique Générale GNU pour plus de détails. + +Vous devez avoir reçu une copie de la Licence Publique Générale GNU +en même temps que ce programme ; si ce n'est pas le cas, écrivez à la +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +MA 02111-1307, États-Unis. + + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +""" + +# --------------------------------------------------------------- +# last update : 07/05/2007 +#---------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_gimp.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------- + +SHARP_IMPORT=0 +SCALE=1 + +import sys +#oldpath=sys.path + +import Blender +BLversion=Blender.Get('version') + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if pathname.find(os.sep)!=-1: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filtreFICHIER(nom): + f=open(nom,'r') + t=f.readlines() + f.close() + if len(t)==1 and t[0].find('\r'): + t=t[0].split('\r') + if len(t)>1 and t[1].find('#POINTS:')==0: + return t + else: + warning = "OK?%t| Not a valid file or an empty file ... " # if no %xN int is set, indices start from 1 + result = Blender.Draw.PupMenu(warning) + return "false" + +#=============================== +# Data +#=============================== +#=============================== +# Blender Curve Data +#=============================== +objBEZIER=0 +objSURFACE=5 +typBEZIER3D=1 #3D +typBEZIER2D=9 #2D + +class Bez: + def __init__(self): + self.co=[] + self.ha=[0,0] + + def echo(self): + #print 'co = ', self.co + #print 'ha = ', self.ha + pass + +class ITEM: + def __init__(self): + self.type = typBEZIER3D, + self.pntsUV = [0,0] + self.resolUV = [32,0] + self.orderUV = [0,0] + self.flagUV = [0,0] + self.Origine = [0.0,0.0] + self.beziers_knot = [] + +class COURBE: + def __init__(self): + self.magic_number='3DG3' + self.type = objBEZIER + self.number_of_items = 0 + self.ext1_ext2 = [0,0] + self.matrix = """0.0 0.0 1.0 0.0 +0.0 1.0 0.0 0.0 +0.0 0.0 1.0 0.0 +0.0 0.0 0.0 1.0 """ #- right-handed object matrix. Used to determine position, rotation and size + self.ITEM = {} + +courbes=COURBE() +PATTERN={} +BOUNDINGBOX={'rec':[],'coef':1.0} +npat=0 +#===================================================================== +#======== name of the curve in the courbes dictionnary =============== +#===================================================================== +n0=0 + +#===================================================================== +#====================== current Point ================================ +#===================================================================== +CP=[0.0,0.0] #currentPoint + +def MINMAX(b): + global BOUNDINGBOX + r=BOUNDINGBOX['rec'] + for m in range(0,len(b)-2,2): + #print m, m+1 , len(b)-1 + #print b[m], r, r[0] + if float(b[m])r[2]: r[2]=float(b[m]) + + if float(b[m+1])r[3]: r[3]=float(b[m+1]) + +#===================================================================== +#===== to compare last position to the original move to displacement = +#===== needed for cyclic efinition ================================= +#===================================================================== +def test_egalitedespositions(f1,f2): + if f1[0]==f2[0] and f1[1]==f2[1]: + return Blender.TRUE + else: + return Blender.FALSE + + +def Open_GEOfile(dir,nom): + if BLversion>=233: + Blender.Load(dir+nom+'OOO.obj', 1) + BO=Blender.Scene.GetCurrent().objects.active + BO.LocZ=1.0 + BO.makeDisplayList() + Blender.Window.RedrawAll() + else: + print "Not yet implemented" + +def create_GEOtext(courbes): + global SCALE, B, BOUNDINGBOX + r=BOUNDINGBOX['rec'] + if SCALE==1: + SCALE=1.0 + elif SCALE==2: + SCALE=r[2]-r[0] + elif SCALE==3: + SCALE=r[3]-r[1] + + t=[] + t.append(courbes.magic_number+'\n') + t.append(str(courbes.type)+'\n') + t.append(str(courbes.number_of_items)+'\n') + t.append(str(courbes.ext1_ext2[0])+' '+str(courbes.ext1_ext2[1])+'\n') + t.append(courbes.matrix+'\n') + + for k in courbes.ITEM.keys(): + + t.append("%s\n"%courbes.ITEM[k].type) + + t.append("%s %s \n"%(courbes.ITEM[k].pntsUV[0],courbes.ITEM[k].pntsUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].resolUV[0],courbes.ITEM[k].resolUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].orderUV[0],courbes.ITEM[k].orderUV[1])) + t.append("%s %s \n"%(courbes.ITEM[k].flagUV[0],courbes.ITEM[k].flagUV[1])) + + flag =0#courbes.ITEM[k].flagUV[0] + + for k2 in range(flag,len(courbes.ITEM[k].beziers_knot)): + k1 =courbes.ITEM[k].beziers_knot[k2] + t.append("%4f 0.0 %4f \n"%(float(k1.co[0])/SCALE,float(k1.co[1])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[4])/SCALE,float(k1.co[5])/SCALE)) + t.append("%4f 0.0 %4f \n"%(float(k1.co[2])/SCALE,float(k1.co[3])/SCALE)) + t.append(str(k1.ha[0])+' '+str(k1.ha[1])+'\n') + return t + +def save_GEOfile(dir,nom,t): + f=open(dir+nom+'OOO.obj','w') + f.writelines(t) + f.close() + #warning = "REMINDER : %t | Do not forget to rename your blender file NOW ! %x1" + #result = Blender.Draw.PupMenu(warning) + + +#===================================================================== +#===== GIMP format : DEBUT ========================= +#===================================================================== +CLOSED=0 + +def mouvement_vers(l,l1,l2,n0): + global BOUNDINGBOX, CP + if l[1] == '3' : + n0+=1 + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3],l[-1],] + courbes.ITEM[n0-1].beziers_knot[0].co[0]=CP[0] + courbes.ITEM[n0-1].beziers_knot[0].co[1]=CP[1] + CP=[l2[-3], l2[-1]] + + elif l[1]=='1' and (n0 not in courbes.ITEM.keys()): + courbes.ITEM[n0]=ITEM() + courbes.ITEM[n0].Origine=[l[-3],l[-1],] + CP=[l2[-3], l2[-1]] + + B=Bez() + B.co=[ CP[0],CP[1], + l1[-3], l1[-1], + l[-3], l[-1]] + + CP=[l2[-3], l2[-1]] + + if BOUNDINGBOX['rec']==[]: + BOUNDINGBOX['rec']=[float(l2[-3]), float(l2[-1]), float(l[-3]), float(l[-1])] + B.ha=[0,0] + + """ + if len( courbes.ITEM[n0].beziers_knot)>=1: + courbes.ITEM[n0].beziers_knot[-1].co[2]=l1[-3] + courbes.ITEM[n0].beziers_knot[-1].co[3]=l1[-1] + """ + + MINMAX(B.co) + courbes.ITEM[n0].beziers_knot.append(B) + return courbes,n0 + +Actions= { "1" : mouvement_vers, + "3" : mouvement_vers } + +TAGcourbe=Actions.keys() + +def scan_FILE(nom): + global CP, courbes, SCALE, MAX, MIN, CLOSED + dir,name=split(nom) + name=name.split('.') + #print name + n0=0 + result=0 + t=filtreFICHIER(nom) + if t!="false": + if not SHARP_IMPORT: + warning = "Select Size : %t| As is %x1 | Scale on Height %x2| Scale on Width %x3" + SCALE = Blender.Draw.PupMenu(warning) + npat=0 + l=0 + while l 0: + t=create_GEOtext(courbes) + save_GEOfile(dir,name[0],t) + Open_GEOfile(dir,name[0]) + # 0.1.8 --------------------------------- + Blender.Object.Get()[-1].setName(name[0]) + # 0.1.8 --------------------------------- + + else: + pass + +#===================================================================== +#====================== GIMP Path format mouvements ========================= +#===================================================================== +#========================================================= +# une sorte de contournement qui permet d'utiliser la fonction +# et de documenter les variables Window.FileSelector +#========================================================= +def fonctionSELECT(nom): + scan_FILE(nom) + +if __name__=="__main__": + Blender.Window.FileSelector (fonctionSELECT, 'SELECT GIMP FILE') + diff --git a/release/scripts/bpymodules/paths_svg2obj.py b/release/scripts/bpymodules/paths_svg2obj.py new file mode 100644 index 00000000000..e535af705df --- /dev/null +++ b/release/scripts/bpymodules/paths_svg2obj.py @@ -0,0 +1,1585 @@ +# -*- coding: latin-1 -*- +""" +SVG 2 OBJ translater, 0.5.9h +Copyright (c) jm soler juillet/novembre 2004-april 2007, +# --------------------------------------------------------------- + released under GNU Licence + for the Blender 2.42 Python Scripts Bundle. +Ce programme est libre, vous pouvez le redistribuer et/ou +le modifier selon les termes de la Licence Publique Générale GNU +publiée par la Free Software Foundation (version 2 ou bien toute +autre version ultérieure choisie par vous). + +Ce programme est distribué car potentiellement utile, mais SANS +AUCUNE GARANTIE, ni explicite ni implicite, y compris les garanties +de commercialisation ou d'adaptation dans un but spécifique. +Reportez-vous à la Licence Publique Générale GNU pour plus de détails. + +Vous devez avoir reçu une copie de la Licence Publique Générale GNU +en même temps que ce programme ; si ce n'est pas le cas, écrivez à la +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, +MA 02111-1307, États-Unis. + + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# --------------------------------------------------------------- + +#--------------------------------------------------------------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_svg.htm +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_import_svg_en.htm +# Communiquer les problemes et erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------------------------------------- + +--Old Concept : translate SVG file in GEO .obj file and try to load it. + was removed for the Blender 2.4x release. + .-- Curiousity : the original matrix must be : + | + | 0.0 0.0 1.0 0.0 + | 0.0 1.0 0.0 0.0 + | 0.0 0.0 1.0 0.0 + | 0.0 0.0 0.0 1.0 + | + | and not: + | 1.0 0.0 0.0 0.0 + | 0.0 1.0 0.0 0.0 + | 0.0 0.0 1.0 0.0 + | 0.0 0.0 0.0 1.0 + | + '-- Possible bug : sometime, the new curves object's RotY value + jumps to -90.0 degrees without any reason. + +--Options : + SHARP_IMPORT = 0 + choise between "As is", "Devide by height" and "Devide by width" + SHARP_IMPORT = 1 + no choise + + + +All commands are managed: + M : absolute move to + Z : close path + L : absolute line to + C : absolute curve to + S : absolute curve to with only one handle + H : absolute horizontal line to + V : absolute vertical line to + + l : relative line to 2004/08/03 + c : relative curve to 2004/08/03 + s : relative curve to with only one handle + h : relative horizontal line to + v : relative vertical line to + + A : curve_to_a, + V : draw_line_v, + H : draw_line_h, + Z : close_z, + Q : curve_to_q, + T : curve_to_t, + a : curve_to_a, + v : draw_line_v, + h : draw_line_h, + z : close_z, + q : curve_to_q, + + transfrom for tag + transform for tag + +The circle, rectangle closed or open polygons lines are managed too. + +Changelog: + 0.1.1 : - control file without extension + 0.2.0 : - improved reading of several data of the same type + following the same command (for gimp import) + 0.2.1 : - better choice for viewboxing ( takes the viewbox if found, + instead of x,y,width and height + 0.2.2 : - read compact path data from Illustrator 10 + 0.2.3 : - read a few new relative displacements + 0.2.4 : - better hash for command followed by a lone data + (h,v) or uncommun number (a) + 0.2.5 : - correction for gimp import + 0.2.6 : - correction for illustrator 10 SVG + 0.2.7 : - correction for inskape 0.40 cvs SVG + 0.2.8 : - correction for inskape plain SVG + 0.3 : - reading of the transform properties added : + translate + 0.3.1 : - compatibility restored with gimp + 0.3.2 : - transform properties added (june, 15-16): + scale, + rotate, + matrix, + skew + - added a test on __name__ to load the script + outside from the blender menu + 0.3.3 : - matrix transform content control + 0.3.4 : - paths data reading rewritten (19/06/05) + 0.3.5 : - test on empty curve (22/06/05) + - removed overlayed points + 0.3.6 : - rewriting of the bezier point contruction to correct + a problem in the connection between L type point and + C or S type point + 0.3.7 : - code correction for bezier knot in Curveto command when + the command close a path + 0.3.8 : - code was aded to manage quadratic bezier, + Q,q command and T,t commands, as a normal blender's bezier point + - The last modications does not work with gimp 2.0 svg export . + corrected too . + 0.3.9 : - Path's A,a command for ellipse's arc . + 0.4.0 : - To speed up the function filter_DATA was removed and text + variables are changed into numeric variables + 0.4.1 : - svg, groups and shapes hierarchy added + - now transform properties are computed using a stack with all + parented groups + - removed or replaced useless functions : + - skewY, skewX transforms + - radians in rotate transform + 0.4.2 : - Added functon to translate others shapes in path + rect, line, polyline, polygon + 0.4.3 : - various corrections + text font (id property exported by Adobe Illustrator are between coma) + function to code s tag has been rewritten + 0.4.4 : - various corrections + to oblige the script to understand a line feed just after + a tag . Rarely encountered problem, but it exits in a svg file + format exported by a outliner script for mesh . + 0.4.5 : - update for CVS only, at least blender 2.38 and upper + no BezTriple module in older version + added a createCURVES function to avoid to use + the OBJ format export/import . + Perhaps problems with cyclic curves . If a closed curve + does not appear closed in blender, enter edit mode select + all knot with Akey, do a Hkey to set handle type (without + this the knot are recalculated) , and finally use the Ckey + to close the curve . + Should work ... not guaranted . + 0.4.6 : - cyclic flag ... + 0.4.7 : - Management of the svgz files . the complete python or the + gzip.py file is needed . + Little improvement of the curve drawing using the createCURVES + function + 0.4.8 : - short modif for a fantasy font case in the OOo svg format + ('viewbox' is written 'viewBox', for instance) . + Note that (at this time, 2006/05/01, 1OOo exports in svg + but does not read its own export + 0.4.9 : - skipped version : private test + 0.5.0 : - the script worked perfectly with Blender 2.41 but in Blender + 2.42, use the original svg name file + 'OOO.obj' to + write a videoscape file made blender crash under window XP when + the script loaded it . Curiously, use a more simple + name with a sole 'O' solved this problem . + - script returned errors on open path : corrected + - in b2.42, several successive imports seem to be added to + the same original curve . So now the script automaticaly + renames the last group of imported curve with the original + name file . + 0.5.1 : - without join option in the internal curve creation function + 0.5.2 : - the createCURVES() function has been cleanded . Now it works + fine but all bezier curves are joined in the same curve object . + 0.5.3 : - removed two things : + 1/ the ajustement function to increase speed . 35 % faster : + 5690 curves and 30254 points in 11 seconds . User should do + a ctrl-a on the object . + 2/ the import method menu . No reason to choose between the + old extern curve creat and the new intern curve creation + this last one is largely faster . + 0.5.4 : - translation of the functions' name + improvment in the dict lookup . + Quite 15% faster . 9.75 seconds instead of 11 to load the file test . + A test was also added to find the fill style so now the script closes + these curves even if they are not defined as closed in the strict path + commands . + The old non used functions have been completely removed . + 0.5.5 : - Modifs for architect users . + 0.5.6 : - Exec was removed from the collect_ATTRIBUTS function . + Other uses was evaluated. + 0.5.7 : - Wash down of some handle problems. + + 0.5.8 : - 2007/3/9 + Wash down of the last exec and correction of a + problem with the curve's first beztriple handle + which was not recorded at first time . + - Added some units managements + - Correction of the rotate matrix + - Correction of the skew matrix + - change in the wash_DATA function suggested by cambo + - added __slot__ in class Bez, ITEM and CURVE suggested by cambo + - remove unused properties in class ITEM and CURVE + + 0.5.9 : - 2007/3/28 + - many improvements for faster and clearer code suggested by cambo and martin. + replacement of "%s" statement by str function. + - correction of an error in the scale transform management + - correction in the management of the stack transformation that rise an error + under python 2.5 but curiously not with python 2.4 + + 0.5.9a : - 2007/3/29 + - Again a lot of minors corrections + - Backward to 0.5.8 of the function that manages float numbers exported + by the Adobe Illustrator's SVG. After a lot of tests it seems that this oldest + version is also faster too . + - correction (bad) on handle management with V and H commands. + + 0.5.9b : - 2007/3/31 + - one or two minor corrections + - now the new object curve is added in the current layer. + - short modif in the scale menu... + + 0.5.9d : - 2007/4/5 + - when a svg file containts several curves they can be imported in + separate object. + - managment of paths' name when paths are imported as separate curves. + - a menu was added to select between separate or joined curves + - management of colors + + 0.5.9e : - 2007/4/7 + - corrected a scale problem that only appears when one uses beveldepth + - in separate curve option, name is also given to the curve data + - added the list of svg's color names (147) and modified the color's method + to work with. + + 0.5.9h : - 2007/5/2 + - script was updated with the modifs by cambo + - removed all debug statements + - correction of a zero division error in the calc_arc function. + +================================================================================== +==================================================================================""" +SHARP_IMPORT=0 +SCALE=1 +scale_=1 +DEBUG = 0#print +DEVELOPPEMENT=0 +TESTCOLOR=0 + +LAST_ID='' +LAST_COLOR=[0.0,0.0,0.0,0.0] +SEPARATE_CURVES=0 +USE_COLORS=0 + +SVGCOLORNAMELIST={ 'aliceblue':[240, 248, 255] ,'antiquewhite':[250, 235, 215] +,'aqua':[ 0, 255, 255], 'aquamarine':[127, 255, 212] +,'azure':[240, 255, 255], 'beige':[245, 245, 220] +,'bisque':[255, 228, 196], 'black':[ 0, 0, 0] +,'blanchedalmond':[255, 235, 205] ,'blue':[ 0, 0, 255] +,'blueviolet':[138, 43, 226],'brown':[165, 42, 42] +,'burlywood':[222, 184, 135],'cadetblue':[ 95, 158, 160] +,'chartreuse':[127, 255, 0] ,'chocolate':[210, 105, 30] +,'coral':[255, 127, 80],'cornflowerblue':[100, 149, 237] +,'cornsilk':[255, 248, 220],'crimson':[220, 20, 60] +,'cyan':[ 0, 255, 255],'darkblue':[ 0, 0, 139] +,'darkcyan':[ 0, 139, 139],'darkgoldenrod':[184, 134, 11] +,'darkgray':[169, 169, 169],'darkgreen':[ 0, 100, 0] +,'darkgrey':[169, 169, 169],'darkkhaki':[189, 183, 107] +,'darkmagenta':[139, 0, 139],'darkolivegreen':[ 85, 107, 47] +,'darkorange':[255, 140, 0],'darkorchid':[153, 50, 204] +,'darkred':[139, 0, 0],'darksalmon':[233, 150, 122] +,'darkseagreen':[143, 188, 143],'darkslateblue':[ 72, 61, 139] +,'darkslategray':[ 47, 79, 79],'darkslategrey':[ 47, 79, 79] +,'darkturquoise':[ 0, 206, 209],'darkviolet':[148, 0, 211] +,'deeppink':[255, 20, 147],'deepskyblue':[ 0, 191, 255] +,'dimgray':[105, 105, 105],'dimgrey':[105, 105, 105] +,'dodgerblue':[ 30, 144, 255],'firebrick':[178, 34, 34] +,'floralwhite':[255, 250, 240],'forestgreen':[ 34, 139, 34] +,'fuchsia':[255, 0, 255],'gainsboro':[220, 220, 220] +,'ghostwhite':[248, 248, 255],'gold':[255, 215, 0] +,'goldenrod':[218, 165, 32],'gray':[128, 128, 128] +,'grey':[128, 128, 128],'green':[ 0, 128, 0] +,'greenyellow':[173, 255, 47],'honeydew':[240, 255, 240] +,'hotpink':[255, 105, 180],'indianred':[205, 92, 92] +,'indigo':[ 75, 0, 130],'ivory':[255, 255, 240] +,'khaki':[240, 230, 140],'lavender':[230, 230, 250] +,'lavenderblush':[255, 240, 245],'lawngreen':[124, 252, 0] +,'lemonchiffon':[255, 250, 205],'lightblue':[173, 216, 230] +,'lightcoral':[240, 128, 128],'lightcyan':[224, 255, 255] +,'lightgoldenrodyellow':[250, 250, 210],'lightgray':[211, 211, 211] +,'lightgreen':[144, 238, 144],'lightgrey':[211, 211, 211] +,'lightpink':[255, 182, 193],'lightsalmon':[255, 160, 122] +,'lightseagreen':[ 32, 178, 170],'lightskyblue':[135, 206, 250] +,'lightslategray':[119, 136, 153],'lightslategrey':[119, 136, 153] +,'lightsteelblue':[176, 196, 222],'lightyellow':[255, 255, 224] +,'lime':[ 0, 255, 0],'limegreen':[ 50, 205, 50] +,'linen':[250, 240, 230],'magenta':[255, 0, 255] +,'maroon':[128, 0, 0],'mediumaquamarine':[102, 205, 170] +,'mediumblue':[ 0, 0, 205],'mediumorchid':[186, 85, 211] +,'mediumpurple':[147, 112, 219],'mediumseagreen':[ 60, 179, 113] +,'mediumslateblue':[123, 104, 238],'mediumspringgreen':[ 0, 250, 154] +,'mediumturquoise':[ 72, 209, 204],'mediumvioletred':[199, 21, 133] +,'midnightblue':[ 25, 25, 112],'mintcream':[245, 255, 250] +,'mistyrose':[255, 228, 225],'moccasin':[255, 228, 181] +,'navajowhite':[255, 222, 173],'navy':[ 0, 0, 128] +,'oldlace':[253, 245, 230],'olive':[128, 128, 0] +,'olivedrab':[107, 142, 35],'orange':[255, 165, 0] +,'orangered':[255, 69, 0],'orchid':[218, 112, 214] +,'palegoldenrod':[238, 232, 170],'palegreen':[152, 251, 152] +,'paleturquoise':[175, 238, 238],'palevioletred':[219, 112, 147] +,'papayawhip':[255, 239, 213],'peachpuff':[255, 218, 185] +,'peru':[205, 133, 63],'pink':[255, 192, 203] +,'plum':[221, 160, 221],'powderblue':[176, 224, 230] +,'purple':[128, 0, 128],'red':[255, 0, 0] +,'rosybrown':[188, 143, 143],'royalblue':[ 65, 105, 225] +,'saddlebrown':[139, 69, 19],'salmon':[250, 128, 114] +,'sandybrown':[244, 164, 96],'seagreen':[ 46, 139, 87] +,'seashell':[255, 245, 238],'sienna':[160, 82, 45] +,'silver':[192, 192, 192],'skyblue':[135, 206, 235] +,'slateblue':[106, 90, 205],'slategray':[112, 128, 144] +,'slategrey':[112, 128, 144],'snow':[255, 250, 250] +,'springgreen':[ 0, 255, 127],'steelblue':[ 70, 130, 180] +,'tan':[210, 180, 140],'teal':[ 0, 128, 128] +,'thistle':[216, 191, 216],'tomato':[255, 99, 71] +,'turquoise':[ 64, 224, 208],'violet':[238, 130, 238] +,'wheat':[245, 222, 179],'white':[255, 255, 255] +,'whitesmoke':[245, 245, 245],'yellow':[255, 255, 0] +,'yellowgreen':[154, 205, 50]} + + +import sys +from math import cos,sin,tan, atan2, pi, ceil +PI=pi +import Blender +from Blender import Mathutils + +try: + import nt + os=nt + os.sep='\\' + +except: + import posix + os=posix + os.sep='/' + +def isdir(path): + try: + st = os.stat(path) + return 1 + except: + return 0 + +def split(pathname): + if os.sep in pathname: + k0=pathname.split(os.sep) + else: + if os.sep=='/': + k0=pathname.split('\\') + else: + k0=pathname.split('/') + directory=pathname.replace(k0[len(k0)-1],'') + Name=k0[len(k0)-1] + return directory, Name + +def join(l0,l1): + return l0+os.sep+l1 + +os.isdir=isdir +os.split=split +os.join=join + +def filterFILE(nom): + """ + Function filterFILE + + in : string nom , filename + out : string t , if correct filecontaint + + read the file's content and try to see if the format + is correct . + + Lit le contenu du fichier et en fait une pre-analyse + pour savoir s'il merite d'etre traite . + """ + # ---------- + # 0.4.7 + # ---------- + if nom.upper().endswith('.SVGZ'): + try : + import gzip + tz=gzip.GzipFile(nom) + t=tz.read() + except: + name = "ERROR: fail to import gzip module or gzip error ... " + result = Blender.Draw.PupMenu(name) + return "false" + else: + f=open(nom,'rU') + t=f.read() + f.close() + # ---------- + # 0.4.7 : end + # ---------- + # ----------------- + # pre-format ... + # ----------------- + # -------------------- + # 0.4.4 '\r','' --> '\r',' ' + # '\n','' --> '\n',' ' + #-------------------- + t=t.replace('\r',' ') + t=t.replace('\n',' ') + t=t.replace('svg:','') + #-------------------- + # may be needed in some import case when the + # file is saved from a mozilla display + #-------------------- + t=t.replace(chr(0),'') + if not '= 0.0\ + and abs(f1[5])-abs(f2[5])< EPSILON and abs(f1[5])-abs(f2[5])>= 0.0 : + return 1 + else: + return 0 + + +#-------------------- +# 0.4.5 : for blender cvs 2.38 .... +#-------------------- +def createCURVES(curves, name): + """ + internal curves creation + """ + global SCALE, B, BOUNDINGBOX,scale_, SEPARATE_CURVES + global USE_COLORS + from Blender import Curve, Object, Scene, BezTriple + HANDLE={'C':BezTriple.HandleTypes.FREE,'L':BezTriple.HandleTypes.VECT} + r=BOUNDINGBOX['rec'] + + if scale_==3: + SCALE=1.0 + elif scale_==1: + SCALE=r[2]-r[0] + elif scale_==2: + SCALE=r[3]-r[1] + + scene = Scene.GetCurrent() + scene.objects.selected = [] + + if not SEPARATE_CURVES: + c = Curve.New() + c.setResolu(24) + + MATNAME=[] + nloc=0.0 + + def new_MATERIAL(val): + # ----------------------- + # have to create a material + #------------------------ + if val.matname and val.matname in MATNAME: + mat = Blender.Material.Get(val.matname) + elif val.matname: + mat = Blender.Material.New(val.matname) + mat.rgbCol = [val.color[0]/255.0, val.color[1]/255.0, val.color[2]/255.0] + else: + mat = Blender.Material.New(val.id) + mat.rgbCol = [val.color[0]/255.0, val.color[1]/255.0, val.color[2]/255.0] + return [mat] + + for I,val in curves.ITEM.iteritems(): + if SEPARATE_CURVES: + c = Curve.New() + c.setResolu(24) + if USE_COLORS and val.mat: + c.materials=new_MATERIAL(val) + + bzn=0 + if val.beziers_knot[-1].tag in ['L','l','V','v','H','h'] and\ + test_samelocations(val.beziers_knot[-1].co,val.beziers_knot[0].co): + del val.beziers_knot[-1] + + for k2 in xrange(0,len(val.beziers_knot)): + bz= [co for co in val.beziers_knot[k2].co] + if bzn==0: + cp1 = bz[4]/SCALE, bz[5]/-SCALE,0.0, bz[0]/SCALE, bz[1]/-SCALE,0.0, bz[2]/SCALE,bz[3]/-SCALE,0.0, + beztriple1 = BezTriple.New(cp1) + bez = c.appendNurb(beztriple1) + bez[0].handleTypes=(HANDLE[val.beziers_knot[k2].ha[0]],HANDLE[val.beziers_knot[k2].ha[1]]) + bzn = 1 + else: + cp2 = bz[4]/SCALE,bz[5]/-SCALE,0.0 , bz[0]/SCALE, bz[1]/-SCALE,0.0, bz[2]/SCALE,bz[3]/-SCALE,0.0 + beztriple2 = BezTriple.New(cp2) + beztriple2.handleTypes= (HANDLE[val.beziers_knot[k2].ha[0]],HANDLE[val.beziers_knot[k2].ha[1]]) + bez.append(beztriple2) + + if val.flagUV[0]==1 or val.fill==1: + #-------------------- + # 0.4.6 : cyclic flag ... + #-------------------- + bez.flagU += 1 + + if SEPARATE_CURVES: + ob = scene.objects.new(c,val.id) + scene.objects.active = ob + ob.setLocation(0.0,0.0,nloc) + nloc+=0.0001 + c.update() + + if not SEPARATE_CURVES: + ob = scene.objects.new(c,name) + scene.objects.active = ob + c.update() + +#===================================================================== +#===== SVG format : DEBUT ========================= +#===================================================================== +#-------------------- +# 0.5.8, needed with the new +# tranform evaluation +#-------------------- +pxUNIT={'pt':1.25, + 'pc':15.0, + 'mm':3.543307, + 'cm':35.43307, + 'in':90.0, + 'em':1.0, # should be taken from font size + # but not currently managed + 'ex':1.0, # should be taken from font size + # but not currently managed + '%':1.0, + } + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def rect(prp): + """ + build rectangle paths + """ + D=[] + if 'x' not in prp: x=0.0 + else : x=float(prp['x']) + if 'y' not in prp: y=0.0 + else : y=float(prp['y']) + #-------------------- + # 0.5.8 + #-------------------- + try: + height=float(prp['height']) + except: + pxUNIT['%']=(BOUNDINGBOX['rec'][3]-BOUNDINGBOX['rec'][1])/100.0 + for key in pxUNIT:#.keys(): + if key in prp['height']: + height=float(prp['height'].replace(key,''))*pxUNIT[key] + try: + width=float(prp['width']) + except: + pxUNIT['%']=(BOUNDINGBOX['rec'][2]-BOUNDINGBOX['rec'][0])/100.0 + for key in pxUNIT:#.keys(): + if key in prp['width']: + width=float(prp['width'].replace(key,''))*pxUNIT[key] + #-------------------- + # 0.5.8, end + #-------------------- + """ + normal rect + x,y + h1 + *----------* + | | + | | + | | + *----------* v1 + h2 + """ + if 'rx' not in prp or 'rx' not in prp: + D=['M',str(x),str(y),'h',str(width),'v',str(height),'h',str(-width),'z'] + else : + rx=float(prp['rx']) + if 'ry' not in prp : + ry=float(prp['rx']) + else : ry=float(prp['ry']) + if 'rx' in prp and prp['rx']<0.0: rx*=-1 + if 'ry' in prp and prp['ry']<0.0: ry*=-1 + """ + rounded corner + + x,y M h1 + ---*----------* + / \ + / \ + v2 * * c1 + | | + | | + | | + c3 * * v2 + \ / + \ / + *----------* + h2 c2 + """ + + D=['M',str(x+rx),str(y), + 'h',str(width-2*rx), + 'c',str(rx),'0.0',str(rx),str(ry),str(rx),str(ry), + 'v',str(height-ry), + 'c','0.0',str(ry),str(-rx),str(ry),str(-rx),str(ry), + 'h',str(-width+2*rx), + 'c',str(-rx),'0.0',str(-rx),str(-ry),str(-rx),str(-ry), + 'v',str(-height+ry), + 'c','0.0','0.0','0.0',str(-ry),str(rx),str(-ry), + 'z'] + + return D + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def circle(prp): + if 'cx' not in prp: cx=0.0 + else : cx =float(prp['cx']) + if 'cy' not in prp: cy=0.0 + else : cy =float(prp['cy']) + #print prp.keys() + r = float(prp['r']) + D=['M',str(cx),str(cy+r), + 'C',str(cx-r), str(cy+r*0.552),str(cx-0.552*r),str(cy+r), str(cx),str(cy+r), + 'C',str(cx+r*0.552), str(cy+r), str(cx+r), str(cy+r*0.552), str(cx+r),str(cy), + 'C',str(cx+r), str(cy-r*0.552),str(cx+r*0.552),str(cy-r),str(cx), str(cy-r), + 'C',str(cx-r*0.552), str(cy-r), str(cx-r), str(cy-r*0.552),str(cx-r),str(cy), + 'Z'] + return D + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def ellipse(prp): + if 'cx' not in prp: cx=0.0 + else : cx =float(prp['cx']) + if 'cy' not in prp: cy=0.0 + else : cy =float(prp['cy']) + ry = float(prp['rx']) + rx = float(prp['ry']) + D=['M',str(cx),str(cy+rx), + 'C',str(cx-ry),str(cy+rx*0.552),str(cx-0.552*ry),str(cy+rx),str(cx),str(cy+rx), + 'C',str(cx+ry*0.552),str(cy+rx),str(cx+ry),str(cy+rx*0.552),str(cx+ry),str(cy), + 'C',str(cx+ry),str(cy-rx*0.552),str(cx+ry*0.552),str(cy-rx),str(cx),str(cy-rx), + 'C',str(cx-ry*0.552),str(cy-rx),str(cx-ry),str(cy-rx*0.552),str(cx-ry),str(cy), + 'z'] + return D + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def line(prp): + D=['M',str(prp['x1']),str(prp['y1']), + 'L',str(prp['x2']),str(prp['y2'])] + return D + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def polyline(prp): + if 'points' in prp: + points=prp['points'].split(' ') + np=0 + for p in points: + if p!='': + p=p.split(',') + if np==0: + D=['M',str(p[0]),str(p[1])] + np+=1 + else: + D.append('L'); D.append(str(p[0])); D.append(str(p[1])) + return D + else: + return [] + +#-------------------- +# 0.4.2 +# 0.5.8, to remove exec +#-------------------- +def polygon(prp): + D=polyline(prp) + if D!=[]: + D.append('Z') + return D + +#-------------------- +# 0.5.8, to remove exec +#-------------------- +OTHERSSHAPES={ 'rect' : rect, + 'line' : line, + 'polyline': polyline, + 'polygon' : polygon, + 'circle' : circle, + 'ellipse' : ellipse} + +#-------------------- +# 0.3.9 +#-------------------- +def calc_arc (cpx,cpy, rx, ry, ang, fa , fs , x, y) : + """ + Calc arc paths + """ + rx=abs(rx) + ry=abs(ry) + px=abs((cos(ang)*(cpx-x)+sin(ang)*(cpy-y))*0.5)**2.0 + py=abs((cos(ang)*(cpy-y)-sin(ang)*(cpx-x))*0.5)**2.0 + rpx=rpy=0.0 + if abs(rx)>0.0: rpx=px/(rx**2.0) + if abs(ry)>0.0: rpy=py/(ry**2.0) + pl=rpx+rpy + if pl>1.0: + pl=pl**0.5;rx*=pl;ry*=pl + carx=sarx=cary=sary=0.0 + if abs(rx)>0.0: + carx=cos(ang)/rx;sarx=sin(ang)/rx + if abs(ry)>0.0: + cary=cos(ang)/ry;sary=sin(ang)/ry + x0=(carx)*cpx+(sarx)*cpy + y0=(-sary)*cpx+(cary)*cpy + x1=(carx)*x+(sarx)*y + y1=(-sary)*x+(cary)*y + d=(x1-x0)*(x1-x0)+(y1-y0)*(y1-y0) + if abs(d)>0.0 :sq=1.0/d-0.25 + else: sq=-0.25 + if sq<0.0 :sq=0.0 + sf=sq**0.5 + if fs==fa :sf=-sf + xc=0.5*(x0+x1)-sf*(y1-y0) + yc=0.5*(y0+y1)+sf*(x1-x0) + ang_0=atan2(y0-yc,x0-xc) + ang_1=atan2(y1-yc,x1-xc) + ang_arc=ang_1-ang_0; + if (ang_arc < 0.0 and fs==1) : + ang_arc += 2.0 * PI + elif (ang_arc>0.0 and fs==0) : + ang_arc-=2.0*PI + n_segs=int(ceil(abs(ang_arc*2.0/(PI*0.5+0.001)))) + P=[] + for i in xrange(n_segs): + ang0=ang_0+i*ang_arc/n_segs + ang1=ang_0+(i+1)*ang_arc/n_segs + ang_demi=0.25*(ang1-ang0) + t=2.66666*sin(ang_demi)*sin(ang_demi)/sin(ang_demi*2.0) + x1=xc+cos(ang0)-t*sin(ang0) + y1=yc+sin(ang0)+t*cos(ang0) + x2=xc+cos(ang1) + y2=yc+sin(ang1) + x3=x2+t*sin(ang1) + y3=y2-t*cos(ang1) + P.append([[(cos(ang)*rx)*x1+(-sin(ang)*ry)*y1, + (sin(ang)*rx)*x1+(cos(ang)*ry)*y1], + [(cos(ang)*rx)*x3+(-sin(ang)*ry)*y3, + (sin(ang)*rx)*x3+(cos(ang)*ry)*y3], + [(cos(ang)*rx)*x2+(-sin(ang)*ry)*y2, + (sin(ang)*rx)*x2+(cos(ang)*ry)*y2]]) + return P + +#-------------------- +# 0.3.9 +#-------------------- +def curve_to_a(c,D,n0,CP): #A,a + global SCALE + l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]), + int(D[c[1]+4]),int(D[c[1]+5]),float(D[c[1]+6]),float(D[c[1]+7])] + if c[0]=='a': + l[5]=l[5] + CP[0] + l[6]=l[6] + CP[1] + B=Bez() + B.co=[ CP[0], CP[1], CP[0], CP[1], CP[0], CP[1] ] + B.ha=['C','C'] + B.tag=c[0] + POINTS= calc_arc (CP[0],CP[1], + l[0], l[1], l[2]*(PI / 180.0), + l[3], l[4], + l[5], l[6] ) + #if DEBUG == 1 : print POINTS + for p in POINTS : + B=Bez() + B.co=[ p[2][0],p[2][1], p[0][0],p[0][1], p[1][0],p[1][1]] + B.ha=['C','C'] + B.tag='C' + BP=curves.ITEM[n0].beziers_knot[-1] + BP.co[2]=B.co[2] + BP.co[3]=B.co[3] + curves.ITEM[n0].beziers_knot.append(B) + BP=curves.ITEM[n0].beziers_knot[-1] + BP.co[2]=BP.co[0] + BP.co[3]=BP.co[1] + CP=[l[5], l[6]] + return curves,n0,CP + +def move_to(c, D, n0,CP, proprietes): + global DEBUG,TAGcourbe, LAST_ID + global USE_COLORS + + l=[float(D[c[1]+1]),float(D[c[1]+2])] + if c[0]=='m': + l=[l[0]+CP[0], + l[1] + CP[1]] + if n0 in curves.ITEM: + n0+=1 + CP=[l[0],l[1]] + curves.ITEM[n0]=ITEM() + + if 'id' in proprietes: + curves.ITEM[n0].id=proprietes['id'] + else: + curves.ITEM[n0].id=LAST_ID + + proprietes['n'].append(n0) + if USE_COLORS: + pr= proprietes.get('fill') # None or the property + if pr != None: + if '#' in pr: + i=1 + curves.ITEM[n0].color=[int(pr[i:i+2],16),int(pr[i+2:i+4],16),int(pr[i+4:i+6],16)] + curves.ITEM[n0].mat=1 + elif pr in SVGCOLORNAMELIST: + Courbe[n].color=SVGCOLORNAMELIST[pr] + Courbe[n].mat=1 + + B=Bez() + B.co=[CP[0],CP[1],CP[0],CP[1],CP[0],CP[1]] + B.ha=['L','C'] + B.tag=c[0] + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print curves.ITEM[n0], CP + return curves,n0,CP + +def close_z(c,D,n0,CP): #Z,z + curves.ITEM[n0].flagUV[0]=1 + if len(curves.ITEM[n0].beziers_knot)>1: + #print len(curves.ITEM[n0].beziers_knot) + BP=curves.ITEM[n0].beziers_knot[-1] + BP0=curves.ITEM[n0].beziers_knot[0] + if BP.tag in ['c','C','s','S',]: + BP.co[2]=BP0.co[2] #4-5 point prec + BP.co[3]=BP0.co[3] + del curves.ITEM[n0].beziers_knot[0] + else: + del curves.ITEM[n0] + n0-=1 + return curves,n0,CP + +def curve_to_q(c,D,n0,CP): #Q,q + l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]),float(D[c[1]+4])] + if c[0]=='q': + l=[l[0]+CP[0], l[1]+CP[1], l[2]+CP[0], l[3]+CP[1]] + B=Bez() + B.co=[l[2], l[3], l[2], l[3], l[0], l[1]] #plus toucher au 2-3 + B.ha=['C','C'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + BP.co[2]=BP.co[0] + BP.co[3]=BP.co[1] + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print B.co,BP.co + CP=[l[2],l[3]] + #if DEBUG==1: pass + if len(D)>c[1]+5 and D[c[1]+5] not in TAGcourbe : + c[1]+=4 + curve_to_q(c, D, n0,CP) + return curves,n0,CP + +def curve_to_t(c,D,n0,CP): #T,t + l=[float(D[c[1]+1]),float(D[c[1]+2])] + if c[0]=='t': + l=[l[0]+CP[0], l[1]+CP[1]] + B=Bez() + B.co=[l[0], l[1], l[0], l[1], l[0], l[1]] #plus toucher au 2-3 + B.ha=['C','C'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + l0=build_SYMETRIC([BP.co[0],BP.co[1],BP.co[4],BP.co[5]]) + if BP.tag in ['q','Q','t','T','m','M']: + BP.co[2]=l0[2] + BP.co[3]=l0[3] + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print B.co,BP.co + CP=[l[0],l[1]] + if len(D)>c[1]+3 and D[c[1]+3] not in TAGcourbe : + c[1]+=4 + curve_to_t(c, D, n0,CP) + return curves,n0,CP + +#-------------------- +# 0.4.3 : rewritten +#-------------------- +def build_SYMETRIC(l): + X=l[2]-(l[0]-l[2]) + Y=l[3]-(l[1]-l[3]) + return X,Y + +def curve_to_s(c,D,n0,CP): #S,s + l=[float(D[c[1]+1]), + float(D[c[1]+2]), + float(D[c[1]+3]), + float(D[c[1]+4])] + if c[0]=='s': + l=[l[0]+CP[0], l[1]+CP[1], + l[2]+CP[0], l[3]+CP[1]] + B=Bez() + B.co=[l[2],l[3],l[2],l[3],l[0],l[1]] #plus toucher au 2-3 + B.ha=['C','C'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + #-------------------- + # 0.4.3 + #-------------------- + BP.co[2],BP.co[3]=build_SYMETRIC([BP.co[4],BP.co[5],BP.co[0],BP.co[1]]) + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print B.co,BP.co + #-------------------- + # 0.4.3 + #-------------------- + CP=[l[2],l[3]] + if len(D)>c[1]+5 and D[c[1]+5] not in TAGcourbe : + c[1]+=4 + curve_to_c(c, D, n0,CP) + return curves,n0,CP + +def curve_to_c(c, D, n0,CP): #c,C + l=[float(D[c[1]+1]),float(D[c[1]+2]),float(D[c[1]+3]), + float(D[c[1]+4]),float(D[c[1]+5]),float(D[c[1]+6])] + if c[0]=='c': + l=[l[0]+CP[0], + l[1]+CP[1], + l[2]+CP[0], + l[3]+CP[1], + l[4]+CP[0], + l[5]+CP[1]] + B=Bez() + B.co=[l[4], + l[5], + l[4], + l[5], + l[2], + l[3]] #plus toucher au 2-3 + B.ha=['C','C'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + BP.co[2]=l[0] + BP.co[3]=l[1] + BP.ha[1]='C' + curves.ITEM[n0].beziers_knot.append(B) + #if DEBUG==1: print B.co,BP.co + CP=[l[4],l[5]] + if len(D)>c[1]+7 and D[c[1]+7] not in TAGcourbe : + c[1]+=6 + curve_to_c(c, D, n0,CP) + return curves,n0,CP + +def draw_line_l(c, D, n0,CP): #L,l + l=[float(D[c[1]+1]),float(D[c[1]+2])] + if c[0]=='l': + l=[l[0]+CP[0], + l[1]+CP[1]] + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=['L','L'] + B.tag=c[0] + BP=curves.ITEM[n0].beziers_knot[-1] + BP.ha[1]='L' + curves.ITEM[n0].beziers_knot.append(B) + CP=[B.co[0],B.co[1]] + if len(D)>c[1]+3 and D[c[1]+3] not in TAGcourbe : + c[1]+=2 + draw_line_l(c, D, n0,CP) #L + return curves,n0,CP + +def draw_line_h(c,D,n0,CP): #H,h + if c[0]=='h': + l=[float(D[c[1]+1])+float(CP[0]),CP[1]] + else: + l=[float(D[c[1]+1]),CP[1]] + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=['L','L'] + B.tag=c[0] + #BP=curves.ITEM[n0].beziers_knot[-1] + #BP.ha[0]='L' + curves.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return curves,n0,CP + +def draw_line_v(c,D,n0,CP): #V, v + if c[0]=='v': + l=[CP[0], float(D[c[1]+1])+CP[1]] + else: + l=[CP[0], float(D[c[1]+1])] + + B=Bez() + B.co=[l[0],l[1],l[0],l[1],l[0],l[1]] + B.ha=['L','L'] + B.tag=c[0] + #BP=curves.ITEM[n0].beziers_knot[-1] + #BP.ha[0]='L' + curves.ITEM[n0].beziers_knot.append(B) + CP=[l[0],l[1]] + return curves,n0,CP + +Actions= { "C" : curve_to_c, + "A" : curve_to_a, + "S" : curve_to_s, + "M" : move_to, + "V" : draw_line_v, + "L" : draw_line_l, + "H" : draw_line_h, + "Z" : close_z, + "Q" : curve_to_q, + "T" : curve_to_t, + + "c" : curve_to_c, + "a" : curve_to_a, + "s" : curve_to_s, + "m" : move_to, + "v" : draw_line_v, + "l" : draw_line_l, + "h" : draw_line_h, + "z" : close_z, + "q" : curve_to_q, + "T" : curve_to_t +} + +TAGcourbe=Actions.keys() +TAGtransform=['M','L','C','S','H','V','T','Q'] +tagTRANSFORM=0 + +def wash_DATA(ndata): + if ndata: + #if DEBUG==1: print ndata + ndata = ndata.strip() + if ndata[0]==',':ndata=ndata[1:] + if ndata[-1]==',':ndata=ndata[:-1] + #-------------------- + # 0.4.0 : 'e' + #-------------------- + i = ndata.find('-') + if i != -1 and ndata[i-1] not in ' ,e': + ndata=ndata.replace('-',',-') + ndata=ndata.replace(',,',',') + ndata=ndata.replace(' ',',') + ndata=ndata.split(',') + ndata=[i for i in ndata if i] #059a + + return ndata + +#-------------------- +# 0.3.4 : - read data rewrittten +#-------------------- +def list_DATA(DATA): + """ + This function translate a text in a list of + correct commandswith the right number of waited + values for each of them . For example : + d="'M0,14.0 z" becomes ['M','0.0','14.0','z'] + """ + # ---------------------------------------- + # borner les differents segments qui devront etre + # traites + # pour cela construire une liste avec chaque + # la position de chaqe emplacement tag de type + # commande path... + # ---------------------------------------- + tagplace=[] + for d in Actions: + b1=0 + while True: + i = DATA.find(d,b1) + if i==-1: break + tagplace.append(i) + b1=i+1 + #------------------------------------------ + # cette liste doit etre traites dans l'ordre + # d'apparition des tags + #------------------------------------------ + tagplace.sort() + + tpn=range(len(tagplace)) + #-------------------- + # 0.3.5 :: short data, only one tag + #-------------------- + if len(tagplace)-1>0: + DATA2=[] + for t in tpn[:-1]: + DATA2.append(DATA[tagplace[t]:tagplace[t]+1]) + ndata=DATA[tagplace[t]+1:tagplace[t+1]] + if DATA2[-1] not in ['z','Z'] : + ndata=wash_DATA(ndata) + DATA2.extend(ndata) + DATA2.append(DATA[tagplace[t+1]:tagplace[t+1]+1]) + if DATA2[-1] not in ['z','Z'] and len(DATA)-1>=tagplace[t+1]+1: + ndata=DATA[tagplace[t+1]+1:] + ndata=wash_DATA(ndata) + DATA2.extend(ndata) #059a + else: + #-------------------- + # 0.3.5 : short data,only one tag + #-------------------- + DATA2=[] + DATA2.append(DATA[tagplace[0]:tagplace[0]+1]) + ndata=DATA[tagplace[0]+1:] + ndata=wash_DATA(ndata) + DATA2.extend(ndata) + return DATA2 + +#---------------------------------------------- +# 0.3 +# 0.5.8, to remove exec +#---------------------------------------------- +def translate(t): + tx=t[0] + ty=t[1] + return [1, 0, tx], [0, 1, ty],[0,0,1] + +#---------------------------------------------- +# 0.3.2 +# 0.5.8, to remove exec +#---------------------------------------------- +def scale(s): + sx=s[0] + if len(s)>1: sy=s[1] + else: sy=sx + return [sx, 0, 0], [0, sy, 0],[0,0,1] + +#---------------------------------------------- +# 0.4.1 : transslate a in radians +# 0.5.8, to remove exec +#---------------------------------------------- +def rotate(t): + a=t[0] + return [cos(a*3.1416/180.0), -sin(a*3.1416/180.0), 0], [sin(a*3.1416/180.0), cos(a*3.1416/180.0),0],[0,0,1] + +#---------------------------------------------- +# 0.3.2 +# 0.5.8, to remove exec +#---------------------------------------------- +def skewx(t): + a=t[0] + return [1, tan(a*3.1416/180.0), 0], [0, 1, 0],[0,0,1] + +#---------------------------------------------- +# 0.4.1 +# 0.5.8, to remove exec +#---------------------------------------------- +def skewy(t): + a=t[0] + return [1, 0, 0], [tan(a*3.1416/180.0), 1 , 0],[0,0,1] + +#---------------------------------------------- +# 0.3.2 +# 0.5.8, to remove exec +#---------------------------------------------- +def matrix(t): + a,b,c,d,e,f=t + return [a,c,e],[b,d,f],[0,0,1] + +#-------------------- +# 0.5.8, to remove exec +#-------------------- +matrixTRANSFORM={ 'translate':translate, + 'scale':scale, + 'rotate':rotate, + 'skewx':skewx, + 'skewy':skewy, + 'matrix':matrix + } + +#---------------------------------------------- +# 0.4.2 : rewritten +# 0.5.8 : to remove exec uses. +#---------------------------------------------- +def control_CONTAINT(txt): + """ + the transforms' descriptions can be sole or several + and separators might be forgotten + """ + t0=0 + tlist=[] + while txt.count(')',t0)>0: + t1=txt.find(')',t0) + nt0=txt[t0:t1+1] + t2=nt0[nt0.find('(')+1:-1] + val=nt0[:nt0.find('(')] + while t2.find(' ')!=-1: + t2=t2.replace(' ',' ') + t2=t2.replace(' ',',') + + """ + t2=t2.split(',') + for index, t in enumerate(t2): + t2[index]=float(t) + """ + t2=[float(t) for t in t2.split(',')] + + if val=='rotate' : + t3=t2 + if len(t3)==3: + tlist.append(['translate',[t3[1],t3[2]]]) + tlist.append(['rotate',[t3[0]/180.0*3.1416]]) + tlist.append(['translate',[-t3[1],-t3[2]]]) + else: + tlist.append(['rotate',[t3[0]]]) + else: + tlist.append([val,t2]) + t0=t1+1 + return tlist + + +def curve_FILL(Courbe,proprietes): + global USE_COLORS + for n in proprietes['n']: + pr = proprietes['style'] + if n in Courbe and 'fill:' in pr: + if not 'fill:none' in pr: + Courbe[n].fill=1 + if USE_COLORS: + if '#' in pr: + i= pr.find('fill:#')+6 + Courbe[n].color=[int(pr[i:i+2],16),int(pr[i+2:i+4],16),int(pr[i+4:i+6],16)] + Courbe[n].mat=1 + elif ';fill-opacity' in pr: + i= pr.find('fill:')+5 + i2= pr.find(';',i) + COLORNAME= pr[i:i2] + Courbe[n].color=SVGCOLORNAMELIST[COLORNAME] + Courbe[n].mat=1 +#---------------------------------------------- +# 0.4.1 : apply transform stack +#---------------------------------------------- +def curve_TRANSFORM(Courbe,proprietes): + # 1/ unpack the STACK + # create a matrix for each transform + ST=[] + for st in proprietes['stack'] : + if st and type(st)==list: + for t in st: + code = control_CONTAINT(t) + a,b,c=matrixTRANSFORM[code[0][0]](code[0][1][:]) + T=Mathutils.Matrix(a,b,c) + ST.append(T) + elif st : + code = control_CONTAINT(st) + a,b,c=matrixTRANSFORM[code[0][0]](code[0][1][:]) + T=Mathutils.Matrix(a,b,c) + ST.append(T) + if 'transform' in proprietes: + for trans in control_CONTAINT(proprietes['transform']): + #-------------------- + # 0.5.8, to remove exec + #-------------------- + a,b,c=matrixTRANSFORM[trans[0].strip()](trans[1][:]) #059 + T=Mathutils.Matrix(a,b,c) + ST.append(T) + ST.reverse() + for n in proprietes['n']: + if n in Courbe: + for bez0 in Courbe[n].beziers_knot: + bez=bez0.co + for b in [0,2,4]: + for t in ST: + v=t * Mathutils.Vector([bez[b],bez[b+1],1.0]) #059a + bez[b]=v[0] + bez[b+1]=v[1] + +def filter(d): + for nn in d: + if nn not in '0123456789.': #059a + d=d.replace(nn,"") + return d + +def get_BOUNDBOX(BOUNDINGBOX,SVG): + if 'viewbox' not in SVG: + h=float(filter(SVG['height'])) + #if DEBUG==1 : print 'h : ',h + w=float(filter(SVG['width'])) + #if DEBUG==1 : print 'w :',w + BOUNDINGBOX['rec']=[0.0,0.0,w,h] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=w/h + else: + viewbox=SVG['viewbox'].split() + BOUNDINGBOX['rec']=[float(viewbox[0]),float(viewbox[1]),float(viewbox[2]),float(viewbox[3])] + r=BOUNDINGBOX['rec'] + BOUNDINGBOX['coef']=(r[2]-r[0])/(r[3]-r[1]) + return BOUNDINGBOX + +#---------------------------------------------- +# 0.4.1 : attributs ex : 'id=', 'transform=', 'd=' ... +#---------------------------------------------- +def collect_ATTRIBUTS(data): + #---------------------------------------------- + # 0.4.8 : short modif for a fantasy font case + # in the OOo svg format ('viewbox' is + # written 'viewBox', for instance) + #---------------------------------------------- + data=data.replace(' ',' ').lower() + ELEM={'TYPE':data[1:data.find(' ')]} + t1=len(data) + t2=0 + ct=data.count('="') + while ct>0: + t0=data.find('="',t2) + t2=data.find(' ',t2)+1 + id=data[t2:t0] + t2=data.find('"',t0+2) + if id!='d': + ELEM[id]=data[t0+2:t2].replace('\\','/') + else: + ELEM[id]=[] + ELEM[id].append(t0+2) + ELEM[id].append(t2) + ct=data.count('="',t2) + return ELEM + +# -------------------------------------------- +# 0.4.1 : to avoid to use sax and ths xml +# tools of the complete python +# -------------------------------------------- +def build_HIERARCHY(t): + global CP, curves, SCALE, DEBUG, BOUNDINGBOX, scale_, tagTRANSFORM + global LAST_ID + TRANSFORM=0 + t=t.replace('\t',' ') + while t.find(' ')!=-1: t=t.replace(' ',' ') + n0=0 + t0=t1=0 + baliste=[] + balisetype=['?','?','/','/','!','!'] + BALISES=['D', #DECL_TEXTE', + 'D', #DECL_TEXTE', + 'F', #FERMANTE', + 'E', #ELEM_VIDE', + 'd', #DOC', + 'R', #REMARQUES', + 'C', #CONTENU', + 'O' #OUVRANTE' + ] + STACK=[] + while t1-1: + t0=t.find('<',t0) + t1=t.find('>',t0) + ouvrante=0 + #-------------------- + # 0.4.4 , add 'else:' and 'break' to the 'if' statement + #-------------------- + if t0>-1 and t1>-1: + if t[t0+1] in balisetype: + b=balisetype.index(t[t0+1]) + if t[t0+2]=='-': + b=balisetype.index(t[t0+1])+1 + #print t[t0:t1] + balise=BALISES[b] + if b==2: + parent=STACK.pop(-1) + if parent!=None and TRANSFORM>0: + TRANSFORM-=1 + elif t[t1-1] in balisetype: + balise=BALISES[balisetype.index(t[t1-1])+1] + else: + t2=t.find(' ',t0) + if t2>t1: t2=t1 + ouvrante=1 + NOM=t[t0+1:t2] + if '-1: + balise=BALISES[-1] + else: + balise=BALISES[-2] + + if balise=='E' or balise=='O': + proprietes=collect_ATTRIBUTS(t[t0:t1+ouvrante]) + + #print proprietes + if 'id' in proprietes: + LAST_ID=proprietes['id'] + #print LAST_ID + + + + if balise=='O' and 'transform' in proprietes: + STACK.append(proprietes['transform']) + TRANSFORM+=1 + elif balise=='O' : + STACK.append(None) + + proprietes['stack']=STACK[:] + D=[] + + if proprietes['TYPE'] in ['path'] and (proprietes['d'][1]-proprietes['d'][0]>1): + D=list_DATA(t[proprietes['d'][0]+t0:proprietes['d'][1]+t0]) + + elif proprietes['TYPE'] in OTHERSSHAPES: + #-------------------- + # 0.5.8, to remove exec + #-------------------- + D=OTHERSSHAPES[proprietes['TYPE']](proprietes) + + if len(D)>0: + cursor=0 + proprietes['n']=[] + for cell in D: + #if DEBUG==2 : print 'cell : ',cell ,' --' + if len(cell)>=1 and cell[0] in TAGcourbe: + #-------------------- + # 0.5.8, to remove exec + #-------------------- + if cell[0] in ['m','M']: + curves,n0,CP=Actions[cell]([cell,cursor], D, n0,CP,proprietes) + else: + curves,n0,CP=Actions[cell]([cell,cursor], D, n0,CP) + + cursor+=1 + if TRANSFORM>0 or 'transform' in proprietes : + curve_TRANSFORM(curves.ITEM,proprietes) + + if 'style' in proprietes : + curve_FILL(curves.ITEM,proprietes) + + + elif proprietes['TYPE'] == 'svg': + #print 'proprietes.keys()',proprietes.keys() + BOUNDINGBOX = get_BOUNDBOX(BOUNDINGBOX,proprietes) + else: + #-------------------- + # 0.4.4 + #-------------------- + break + t1+=1 + t0=t1 + +def scan_FILE(nom): + global CP, curves, SCALE, DEBUG, BOUNDINGBOX, scale_, tagTRANSFORM + global SEPARATE_CURVES, USE_COLORS + + dir,name=split(nom) + name=name.split('.') + result=0 + #Choise=1 + t1=Blender.sys.time() + t=filterFILE(nom) + if t!='false': + Blender.Window.EditMode(0) + if not SHARP_IMPORT: + togH = Blender.Draw.Create(1) + togW = Blender.Draw.Create(0) + togAS = Blender.Draw.Create(0) + togSP = Blender.Draw.Create(0) + togCOL = Blender.Draw.Create(0) + block=[\ + ("Clamp Width 1", togW, "Rescale the import with a Width of one unit"),\ + ("Clamp Height 1", togH, "Rescale the import with a Heightof one unit"),\ + ("No Rescaling", togAS, "No rescaling, the result can be very large"),\ + ("Separate Curves", togSP, "Create an object for each curve, Slower. May manage colors"),\ + ("Import Colors", togCOL, "try to import color if the path is set as 'fill'. Only With separate option")] + + retval = Blender.Draw.PupBlock("Import Options", block) + if togW.val: scale_=1 + elif togH.val: scale_=2 + elif togAS.val: scale_=3 + + if togSP.val: SEPARATE_CURVES=1 + + if togCOL.val and SEPARATE_CURVES : USE_COLORS=1 + + t1=Blender.sys.time() + # 0.4.1 : to avoid to use sax and the xml + # tools of the complete python + build_HIERARCHY(t) + r=BOUNDINGBOX['rec'] + curves.number_of_items=len(curves.ITEM) + for k, val in curves.ITEM.iteritems(): + val.pntsUV[0] =len(val.beziers_knot) + if curves.number_of_items>0 : #and Choise==1 : + #-------------------- + # 0.4.5 and 0.4.9 + #-------------------- + createCURVES(curves, name[0]) + else: + pass + print ' elapsed time : ',Blender.sys.time()-t1 + Blender.Redraw() + +#===================================================================== +#====================== SVG format mouvements ======================== +#===================================================================== +def functionSELECT(nom): + scan_FILE(nom) + + +if __name__=='__main__': + Blender.Window.FileSelector (functionSELECT, 'SELECT an .SVG FILE', '*.svg') diff --git a/release/scripts/bvh_import.py b/release/scripts/bvh_import.py new file mode 100644 index 00000000000..2093ac109f7 --- /dev/null +++ b/release/scripts/bvh_import.py @@ -0,0 +1,752 @@ +#!BPY + +""" +Name: 'Motion Capture (.bvh)...' +Blender: 242 +Group: 'Import' +Tip: 'Import a (.bvh) motion capture file' +""" + +__author__ = "Campbell Barton" +__url__ = ("blender.org", "blenderartists.org") +__version__ = "1.90 06/08/01" + +__bpydoc__ = """\ +This script imports BVH motion capture data to Blender. +as empties or armatures. +""" + +# -------------------------------------------------------------------------- +# BVH Import v2.0 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +import bpy +import BPyMessages +Vector= Blender.Mathutils.Vector +Euler= Blender.Mathutils.Euler +Matrix= Blender.Mathutils.Matrix +RotationMatrix = Blender.Mathutils.RotationMatrix +TranslationMatrix= Blender.Mathutils.TranslationMatrix + +DEG2RAD = 0.017453292519943295 + +class bvh_node_class(object): + __slots__=(\ + 'name',# bvh joint name + 'parent',# bvh_node_class type or None for no parent + 'children',# a list of children of this type. + 'rest_head_world',# worldspace rest location for the head of this node + 'rest_head_local',# localspace rest location for the head of this node + 'rest_tail_world',# # worldspace rest location for the tail of this node + 'rest_tail_local',# # worldspace rest location for the tail of this node + 'channels',# list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple + 'rot_order',# a triple of indicies as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation. + 'anim_data',# a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz) + 'has_loc',# Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1) + 'has_rot',# Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1) + 'temp')# use this for whatever you want + + def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order): + self.name= name + self.rest_head_world= rest_head_world + self.rest_head_local= rest_head_local + self.rest_tail_world= None + self.rest_tail_local= None + self.parent= parent + self.channels= channels + self.rot_order= rot_order + + # convenience functions + self.has_loc= channels[0] != -1 or channels[1] != -1 or channels[2] != -1 + self.has_rot= channels[3] != -1 or channels[4] != -1 or channels[5] != -1 + + + self.children= [] + + # list of 6 length tuples: (lx,ly,lz, rx,ry,rz) + # even if the channels arnt used they will just be zero + # + self.anim_data= [(0,0,0,0,0,0)] + + + def __repr__(self): + return 'BVH name:"%s", rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)' %\ + (self.name,\ + self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z,\ + self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z) + + + +# Change the order rotation is applied. +MATRIX_IDENTITY_3x3 = Matrix([1,0,0],[0,1,0],[0,0,1]) +MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) + +def eulerRotate(x,y,z, rot_order): + # Clamp all values between 0 and 360, values outside this raise an error. + mats=[RotationMatrix(x%360,3,'x'), RotationMatrix(y%360,3,'y'), RotationMatrix(z%360,3,'z')] + # print rot_order + # Standard BVH multiplication order, apply the rotation in the order Z,X,Y + return (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).toEuler() + +def read_bvh(file_path, GLOBAL_SCALE=1.0): + # File loading stuff + # Open the file for importing + file = open(file_path, 'rU') + + # Seperate into a list of lists, each line a list of words. + file_lines = file.readlines() + # Non standard carrage returns? + if len(file_lines) == 1: + file_lines = file_lines[0].split('\r') + + # Split by whitespace. + file_lines =[ll for ll in [ l.split() for l in file_lines] if ll] + + + # Create Hirachy as empties + + if file_lines[0][0].lower() == 'hierarchy': + #print 'Importing the BVH Hierarchy for:', file_path + pass + else: + raise 'ERROR: This is not a BVH file' + + bvh_nodes= {None:None} + bvh_nodes_serial = [None] + + channelIndex = -1 + + + lineIdx = 0 # An index for the file. + while lineIdx < len(file_lines) -1: + #... + if file_lines[lineIdx][0].lower() == 'root' or file_lines[lineIdx][0].lower() == 'joint': + + # Join spaces into 1 word with underscores joining it. + if len(file_lines[lineIdx]) > 2: + file_lines[lineIdx][1] = '_'.join(file_lines[lineIdx][1:]) + file_lines[lineIdx] = file_lines[lineIdx][:2] + + # MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.?? + + # Make sure the names are unique- Object names will match joint names exactly and both will be unique. + name = file_lines[lineIdx][1] + + #print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1]) + + lineIdx += 2 # Incriment to the next line (Offset) + rest_head_local = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) ) + lineIdx += 1 # Incriment to the next line (Channels) + + # newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation] + # newChannel references indecies to the motiondata, + # if not assigned then -1 refers to the last value that will be added on loading at a value of zero, this is appended + # We'll add a zero value onto the end of the MotionDATA so this is always refers to a value. + my_channel = [-1, -1, -1, -1, -1, -1] + my_rot_order= [None, None, None] + rot_count= 0 + for channel in file_lines[lineIdx][2:]: + channel= channel.lower() + channelIndex += 1 # So the index points to the right channel + if channel == 'xposition': my_channel[0] = channelIndex + elif channel == 'yposition': my_channel[1] = channelIndex + elif channel == 'zposition': my_channel[2] = channelIndex + + elif channel == 'xrotation': + my_channel[3] = channelIndex + my_rot_order[rot_count]= 0 + rot_count+=1 + elif channel == 'yrotation': + my_channel[4] = channelIndex + my_rot_order[rot_count]= 1 + rot_count+=1 + elif channel == 'zrotation': + my_channel[5] = channelIndex + my_rot_order[rot_count]= 2 + rot_count+=1 + + channels = file_lines[lineIdx][2:] + + my_parent= bvh_nodes_serial[-1] # account for none + + + # Apply the parents offset accumletivly + if my_parent==None: + rest_head_world= Vector(rest_head_local) + else: + rest_head_world= my_parent.rest_head_world + rest_head_local + + bvh_node= bvh_nodes[name]= bvh_node_class(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order) + + # If we have another child then we can call ourselves a parent, else + bvh_nodes_serial.append(bvh_node) + + # Account for an end node + if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it. + lineIdx += 2 # Incriment to the next line (Offset) + rest_tail = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3]) ) + + bvh_nodes_serial[-1].rest_tail_world= bvh_nodes_serial[-1].rest_head_world + rest_tail + bvh_nodes_serial[-1].rest_tail_local= rest_tail + + + # Just so we can remove the Parents in a uniform way- End end never has kids + # so this is a placeholder + bvh_nodes_serial.append(None) + + if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0] == '}': # == ['}'] + bvh_nodes_serial.pop() # Remove the last item + + if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0].lower() == 'motion': + #print '\nImporting motion data' + lineIdx += 3 # Set the cursor to the first frame + break + + lineIdx += 1 + + + # Remove the None value used for easy parent reference + del bvh_nodes[None] + # Dont use anymore + del bvh_nodes_serial + + bvh_nodes_list= bvh_nodes.values() + + while lineIdx < len(file_lines) -1: + line= file_lines[lineIdx] + for bvh_node in bvh_nodes_list: + #for bvh_node in bvh_nodes_serial: + lx= ly= lz= rx= ry= rz= 0.0 + channels= bvh_node.channels + anim_data= bvh_node.anim_data + if channels[0] != -1: + lx= GLOBAL_SCALE * float( line[channels[0]] ) + + if channels[1] != -1: + ly= GLOBAL_SCALE * float( line[channels[1]] ) + + if channels[2] != -1: + lz= GLOBAL_SCALE * float( line[channels[2]] ) + + if channels[3] != -1 or channels[4] != -1 or channels[5] != -1: + rx, ry, rz = eulerRotate(float( line[channels[3]] ), float( line[channels[4]] ), float( line[channels[5]] ), bvh_node.rot_order) + #x,y,z = x/10.0, y/10.0, z/10.0 # For IPO's 36 is 360d + + # Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling. + # Will go from (355d to 365d) rather then to (355d to 5d) - inbetween these 2 there will now be a correct interpolation. + + while anim_data[-1][3] - rx > 180: rx+=360 + while anim_data[-1][3] - rx < -180: rx-=360 + + while anim_data[-1][4] - ry > 180: ry+=360 + while anim_data[-1][4] - ry < -180: ry-=360 + + while anim_data[-1][5] - rz > 180: rz+=360 + while anim_data[-1][5] - rz < -180: rz-=360 + + # Done importing motion data # + anim_data.append( (lx, ly, lz, rx, ry, rz) ) + lineIdx += 1 + + # Assign children + for bvh_node in bvh_nodes.itervalues(): + bvh_node_parent= bvh_node.parent + if bvh_node_parent: + bvh_node_parent.children.append(bvh_node) + + # Now set the tip of each bvh_node + for bvh_node in bvh_nodes.itervalues(): + + if not bvh_node.rest_tail_world: + if len(bvh_node.children)==1: + bvh_node.rest_tail_world= Vector(bvh_node.children[0].rest_head_world) + bvh_node.rest_tail_local= Vector(bvh_node.children[0].rest_head_local) + else: + if not bvh_node.children: + raise 'error, bvh node has no end and no children. bad file' + + # Removed temp for now + rest_tail_world= Vector(0,0,0) + rest_tail_local= Vector(0,0,0) + for bvh_node_child in bvh_node.children: + rest_tail_world += bvh_node_child.rest_head_world + rest_tail_local += bvh_node_child.rest_head_local + + bvh_node.rest_tail_world= rest_tail_world * (1.0/len(bvh_node.children)) + bvh_node.rest_tail_local= rest_tail_local * (1.0/len(bvh_node.children)) + + # Make sure tail isnt the same location as the head. + if (bvh_node.rest_tail_local-bvh_node.rest_head_local).length <= 0.001*GLOBAL_SCALE: + + bvh_node.rest_tail_local.y= bvh_node.rest_tail_local.y + GLOBAL_SCALE/10 + bvh_node.rest_tail_world.y= bvh_node.rest_tail_world.y + GLOBAL_SCALE/10 + + + + return bvh_nodes + + + +def bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False): + + if IMPORT_START_FRAME<1: + IMPORT_START_FRAME= 1 + + scn= bpy.data.scenes.active + scn.objects.selected = [] + + objects= [] + + def add_ob(name): + ob = scn.objects.new('Empty') + objects.append(ob) + return ob + + # Add objects + for name, bvh_node in bvh_nodes.iteritems(): + bvh_node.temp= add_ob(name) + + # Parent the objects + for bvh_node in bvh_nodes.itervalues(): + bvh_node.temp.makeParent([ bvh_node_child.temp for bvh_node_child in bvh_node.children ], 1, 0) # ojbs, noninverse, 1 = not fast. + + # Offset + for bvh_node in bvh_nodes.itervalues(): + # Make relative to parents offset + bvh_node.temp.loc= bvh_node.rest_head_local + + # Add tail objects + for name, bvh_node in bvh_nodes.iteritems(): + if not bvh_node.children: + ob_end= add_ob(name + '_end') + bvh_node.temp.makeParent([ob_end], 1, 0) # ojbs, noninverse, 1 = not fast. + ob_end.loc= bvh_node.rest_tail_local + + + # Animate the data, the last used bvh_node will do since they all have the same number of frames + for current_frame in xrange(len(bvh_node.anim_data)): + Blender.Set('curframe', current_frame+IMPORT_START_FRAME) + + for bvh_node in bvh_nodes.itervalues(): + lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame] + + rest_head_local= bvh_node.rest_head_local + bvh_node.temp.loc= rest_head_local.x+lx, rest_head_local.y+ly, rest_head_local.z+lz + + bvh_node.temp.rot= rx*DEG2RAD,ry*DEG2RAD,rz*DEG2RAD + + bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT) + + scn.update(1) + return objects + + + +def bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP= False): + + if IMPORT_START_FRAME<1: + IMPORT_START_FRAME= 1 + + + # Add the new armature, + scn = bpy.data.scenes.active + scn.objects.selected = [] + + arm_data= bpy.data.armatures.new() + arm_ob = scn.objects.new(arm_data) + scn.objects.context = [arm_ob] + scn.objects.active = arm_ob + + # Put us into editmode + arm_data.makeEditable() + + # Get the average bone length for zero length bones, we may not use this. + average_bone_length= 0.0 + nonzero_count= 0 + for bvh_node in bvh_nodes.itervalues(): + l= (bvh_node.rest_head_local-bvh_node.rest_tail_local).length + if l: + average_bone_length+= l + nonzero_count+=1 + + # Very rare cases all bones couldbe zero length??? + if not average_bone_length: + average_bone_length = 0.1 + else: + # Normal operation + average_bone_length = average_bone_length/nonzero_count + + + + ZERO_AREA_BONES= [] + for name, bvh_node in bvh_nodes.iteritems(): + # New editbone + bone= bvh_node.temp= Blender.Armature.Editbone() + + bone.name= name + arm_data.bones[name]= bone + + bone.head= bvh_node.rest_head_world + bone.tail= bvh_node.rest_tail_world + + # ZERO AREA BONES. + if (bone.head-bone.tail).length < 0.001: + if bvh_node.parent: + ofs= bvh_node.parent.rest_head_local- bvh_node.parent.rest_tail_local + if ofs.length: # is our parent zero length also?? unlikely + bone.tail= bone.tail+ofs + else: + bone.tail.y= bone.tail.y+average_bone_length + else: + bone.tail.y= bone.tail.y+average_bone_length + + ZERO_AREA_BONES.append(bone.name) + + + for bvh_node in bvh_nodes.itervalues(): + if bvh_node.parent: + # bvh_node.temp is the Editbone + + # Set the bone parent + bvh_node.temp.parent= bvh_node.parent.temp + + # Set the connection state + if not bvh_node.has_loc and\ + bvh_node.parent and\ + bvh_node.parent.temp.name not in ZERO_AREA_BONES and\ + bvh_node.parent.rest_tail_local == bvh_node.rest_head_local: + bvh_node.temp.options= [Blender.Armature.CONNECTED] + + # Replace the editbone with the editbone name, + # to avoid memory errors accessing the editbone outside editmode + for bvh_node in bvh_nodes.itervalues(): + bvh_node.temp= bvh_node.temp.name + + arm_data.update() + + # Now Apply the animation to the armature + + # Get armature animation data + pose= arm_ob.getPose() + pose_bones= pose.bones + + action = Blender.Armature.NLA.NewAction("Action") + action.setActive(arm_ob) + #xformConstants= [ Blender.Object.Pose.LOC, Blender.Object.Pose.ROT ] + + # Replace the bvh_node.temp (currently an editbone) + # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) + for bvh_node in bvh_nodes.itervalues(): + bone_name= bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. + pose_bone= pose_bones[bone_name] + rest_bone= arm_data.bones[bone_name] + bone_rest_matrix = rest_bone.matrix['ARMATURESPACE'].rotationPart() + + bone_rest_matrix_inv= Matrix(bone_rest_matrix) + bone_rest_matrix_inv.invert() + + bone_rest_matrix_inv.resize4x4() + bone_rest_matrix.resize4x4() + bvh_node.temp= (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) + + + # Make a dict for fast access without rebuilding a list all the time. + xformConstants_dict={ + (True,True): [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT],\ + (False,True): [Blender.Object.Pose.ROT],\ + (True,False): [Blender.Object.Pose.LOC],\ + (False,False): [],\ + } + + + # KEYFRAME METHOD, SLOW, USE IPOS DIRECT + + # Animate the data, the last used bvh_node will do since they all have the same number of frames + for current_frame in xrange(len(bvh_node.anim_data)-1): # skip the first frame (rest frame) + # print current_frame + + #if current_frame==40: # debugging + # break + + # Dont neet to set the current frame + for bvh_node in bvh_nodes.itervalues(): + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + lx,ly,lz,rx,ry,rz= bvh_node.anim_data[current_frame+1] + + if bvh_node.has_rot: + # Set the rotation, not so simple + bone_rotation_matrix= Euler(rx,ry,rz).toMatrix() + bone_rotation_matrix.resize4x4() + pose_bone.quat= (bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat() + + if bvh_node.has_loc: + # Set the Location, simple too + pose_bone.loc= (\ + TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local ) *\ + bone_rest_matrix_inv).translationPart() # WHY * 10? - just how pose works + + # Get the transform + xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot] + + + if xformConstants: + # Insert the keyframe from the loc/quat + pose_bone.insertKey(arm_ob, current_frame+IMPORT_START_FRAME, xformConstants, True ) + + # First time, set the IPO's to linear + if current_frame==0: + for ipo in action.getAllChannelIpos().itervalues(): + if ipo: + for cur in ipo: + cur.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + if IMPORT_LOOP: + cur.extend = Blender.IpoCurve.ExtendTypes.CYCLIC + + + + + # END KEYFRAME METHOD + + + """ + # IPO KEYFRAME SETTING + # Add in the IPOs by adding keyframes, AFAIK theres no way to add IPOs to an action so I do this :/ + for bvh_node in bvh_nodes.itervalues(): + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + + # Get the transform + xformConstants= xformConstants_dict[bvh_node.has_loc, bvh_node.has_rot] + if xformConstants: + pose_bone.loc[:]= 0,0,0 + pose_bone.quat[:]= 0,0,1,0 + # Insert the keyframe from the loc/quat + pose_bone.insertKey(arm_ob, IMPORT_START_FRAME, xformConstants) + + + action_ipos= action.getAllChannelIpos() + + + for bvh_node in bvh_nodes.itervalues(): + has_loc= bvh_node.has_loc + has_rot= bvh_node.has_rot + + if not has_rot and not has_loc: + # No animation data + continue + + ipo= action_ipos[bvh_node.temp[0].name] # posebones name as key + + if has_loc: + curve_xloc= ipo[Blender.Ipo.PO_LOCX] + curve_yloc= ipo[Blender.Ipo.PO_LOCY] + curve_zloc= ipo[Blender.Ipo.PO_LOCZ] + + curve_xloc.interpolation= \ + curve_yloc.interpolation= \ + curve_zloc.interpolation= \ + Blender.IpoCurve.InterpTypes.LINEAR + + + if has_rot: + curve_wquat= ipo[Blender.Ipo.PO_QUATW] + curve_xquat= ipo[Blender.Ipo.PO_QUATX] + curve_yquat= ipo[Blender.Ipo.PO_QUATY] + curve_zquat= ipo[Blender.Ipo.PO_QUATZ] + + curve_wquat.interpolation= \ + curve_xquat.interpolation= \ + curve_yquat.interpolation= \ + curve_zquat.interpolation= \ + Blender.IpoCurve.InterpTypes.LINEAR + + # Get the bone + pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp + + + def pose_rot(anim_data): + bone_rotation_matrix= Euler(anim_data[3], anim_data[4], anim_data[5]).toMatrix() + bone_rotation_matrix.resize4x4() + return tuple((bone_rest_matrix * bone_rotation_matrix * bone_rest_matrix_inv).toQuat()) # qw,qx,qy,qz + + def pose_loc(anim_data): + return tuple((TranslationMatrix(Vector(anim_data[0], anim_data[1], anim_data[2])) * bone_rest_matrix_inv).translationPart()) + + + last_frame= len(bvh_node.anim_data)+IMPORT_START_FRAME-1 + + if has_loc: + pose_locations= [pose_loc(anim_key) for anim_key in bvh_node.anim_data] + + # Add the start at the end, we know the start is just 0,0,0 anyway + curve_xloc.append((last_frame, pose_locations[-1][0])) + curve_yloc.append((last_frame, pose_locations[-1][1])) + curve_zloc.append((last_frame, pose_locations[-1][2])) + + if len(pose_locations) > 1: + ox,oy,oz= pose_locations[0] + x,y,z= pose_locations[1] + + for i in xrange(1, len(pose_locations)-1): # from second frame to second last frame + + nx,ny,nz= pose_locations[i+1] + xset= yset= zset= True # we set all these by default + if abs((ox+nx)/2 - x) < 0.00001: xset= False + if abs((oy+ny)/2 - y) < 0.00001: yset= False + if abs((oz+nz)/2 - z) < 0.00001: zset= False + + if xset: curve_xloc.append((i+IMPORT_START_FRAME, x)) + if yset: curve_yloc.append((i+IMPORT_START_FRAME, y)) + if zset: curve_zloc.append((i+IMPORT_START_FRAME, z)) + + # Set the old and use the new + ox,oy,oz= x,y,z + x,y,z= nx,ny,nz + + + if has_rot: + pose_rotations= [pose_rot(anim_key) for anim_key in bvh_node.anim_data] + + # Add the start at the end, we know the start is just 0,0,0 anyway + curve_wquat.append((last_frame, pose_rotations[-1][0])) + curve_xquat.append((last_frame, pose_rotations[-1][1])) + curve_yquat.append((last_frame, pose_rotations[-1][2])) + curve_zquat.append((last_frame, pose_rotations[-1][3])) + + + if len(pose_rotations) > 1: + ow,ox,oy,oz= pose_rotations[0] + w,x,y,z= pose_rotations[1] + + for i in xrange(1, len(pose_rotations)-1): # from second frame to second last frame + + nw, nx,ny,nz= pose_rotations[i+1] + wset= xset= yset= zset= True # we set all these by default + if abs((ow+nw)/2 - w) < 0.00001: wset= False + if abs((ox+nx)/2 - x) < 0.00001: xset= False + if abs((oy+ny)/2 - y) < 0.00001: yset= False + if abs((oz+nz)/2 - z) < 0.00001: zset= False + + if wset: curve_wquat.append((i+IMPORT_START_FRAME, w)) + if xset: curve_xquat.append((i+IMPORT_START_FRAME, x)) + if yset: curve_yquat.append((i+IMPORT_START_FRAME, y)) + if zset: curve_zquat.append((i+IMPORT_START_FRAME, z)) + + # Set the old and use the new + ow,ox,oy,oz= w,x,y,z + w,x,y,z= nw,nx,ny,nz + + # IPO KEYFRAME SETTING + """ + pose.update() + return arm_ob + + +#=============# +# TESTING # +#=============# + +#('/metavr/mocap/bvh/boxer.bvh') +#('/d/staggered_walk.bvh') +#('/metavr/mocap/bvh/dg-306-g.bvh') # Incompleate EOF +#('/metavr/mocap/bvh/wa8lk.bvh') # duplicate joint names, \r line endings. +#('/metavr/mocap/bvh/walk4.bvh') # 0 channels + +''' +import os +DIR = '/metavr/mocap/bvh/' +for f in ('/d/staggered_walk.bvh',): + #for f in os.listdir(DIR)[5:6]: + #for f in os.listdir(DIR): + if f.endswith('.bvh'): + s = Blender.Scene.New(f) + s.makeCurrent() + #file= DIR + f + file= f + print f + bvh_nodes= read_bvh(file, 1.0) + bvh_node_dict2armature(bvh_nodes, 1) +''' + +def load_bvh_ui(file, PREF_UI= True): + + if BPyMessages.Error_NoFile(file): + return + + Draw= Blender.Draw + + IMPORT_SCALE = Draw.Create(0.1) + IMPORT_START_FRAME = Draw.Create(1) + IMPORT_AS_ARMATURE = Draw.Create(1) + IMPORT_AS_EMPTIES = Draw.Create(0) + IMPORT_LOOP = Draw.Create(0) + + # Get USER Options + if PREF_UI: + pup_block = [\ + ('As Armature', IMPORT_AS_ARMATURE, 'Imports the BVH as an armature'),\ + ('As Empties', IMPORT_AS_EMPTIES, 'Imports the BVH as empties'),\ + ('Scale: ', IMPORT_SCALE, 0.001, 100.0, 'Scale the BVH, Use 0.01 when 1.0 is 1 metre'),\ + ('Start Frame: ', IMPORT_START_FRAME, 1, 30000, 'Frame to start BVH motion'),\ + ('Loop Animation', IMPORT_LOOP, 'Enable cyclic IPOs'),\ + ] + + if not Draw.PupBlock('BVH Import...', pup_block): + return + + print 'Attempting import BVH', file + + IMPORT_SCALE = IMPORT_SCALE.val + IMPORT_START_FRAME = IMPORT_START_FRAME.val + IMPORT_AS_ARMATURE = IMPORT_AS_ARMATURE.val + IMPORT_AS_EMPTIES = IMPORT_AS_EMPTIES.val + IMPORT_LOOP = IMPORT_LOOP.val + + if not IMPORT_AS_ARMATURE and not IMPORT_AS_EMPTIES: + Blender.Draw.PupMenu('No import option selected') + return + Blender.Window.WaitCursor(1) + # Get the BVH data and act on it. + t1= Blender.sys.time() + print '\tpassing bvh...', + bvh_nodes= read_bvh(file, IMPORT_SCALE) + print '%.4f' % (Blender.sys.time()-t1) + t1= Blender.sys.time() + print '\timporting to blender...', + if IMPORT_AS_ARMATURE: bvh_node_dict2armature(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP) + if IMPORT_AS_EMPTIES: bvh_node_dict2objects(bvh_nodes, IMPORT_START_FRAME, IMPORT_LOOP) + + print 'Done in %.4f\n' % (Blender.sys.time()-t1) + Blender.Window.WaitCursor(0) + +def main(): + Blender.Window.FileSelector(load_bvh_ui, 'Import BVH', '*.bvh') + +if __name__ == '__main__': + #def foo(): + main() + ''' + scn = bpy.data.scenes.active + for ob in list(scn.objects): + if ob.name!='arm__': + scn.objects.unlink(ob) + load_bvh_ui('/test.bvh', False) + ''' \ No newline at end of file diff --git a/release/scripts/camera_changer.py b/release/scripts/camera_changer.py new file mode 100644 index 00000000000..7ae1bd64c8c --- /dev/null +++ b/release/scripts/camera_changer.py @@ -0,0 +1,121 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Camera Changer' +Blender: 234 +Group: 'Animation' +Tip: 'Create script link to change cameras (based on their names) during an animation' +""" + +__author__ = '3R - R3gis' +__version__ = '1.2' +__url__ = ["Author's site , http://cybercreator.free.fr", "French Blender support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender"] +__email__=["3R, r3gis@free.fr"] + + +__bpydoc__ = """\ +This script creates an script link to change cameras during an animation. + +The created script link (a Blender Text) is linked to Scene Frame Changed events. + +Usage: + +Run the script, then name the camera Object with the number of the frame(s) +where you want this camera to become active. + +For example:
+ - a camera called "10" will become active at frame 10.
+ - a camera called "10,25,185" will become active at frames 10, 25 and 185. + +Notes:
+ - This script creates another script named camera.py, which is linked to the current scene.
+ - If there is already a text called "camera.py", but it's from an old version or is not recognized, +you can choose if you want to rename or overwrite it. + - Script inspired by Jean-Michel (jms) Soler's:
+ http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_changerdecamera.htm +""" + + +# $Id$ +# +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004-2005: Regis Montoya +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +#Script inspired of the idea of this one : +#http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_changerdecamera.htm +# +#---------------------------------------------- +# R3gis Montoya (3R) +# +# Pout tout probleme a: +# cybercreator@free.fr +# --------------------------------------------- + +import Blender +from Blender import * +import string + +header = '# camera.py 1.3 scriptlink' + +camera_change_scriptlink = header + \ +''' +import Blender +def main(): + scn = Blender.Scene.GetCurrent() + frame = str(Blender.Get('curframe')) + + # change the camera if it has the current frame + for ob_cam in [ob for ob in scn.objects if ob.type == 'Camera']: + for number in ob_cam.name.split(','): + if number == frame: + scn.setCurrentCamera(ob_cam) + return +main() +''' + +def main(): + + # Get the text + try: cam_text = Blender.Text.Get('camera.py') + except: cam_text = None + + if cam_text: + if cam_text.asLines()[0] != header: + ret = Blender.Draw.PupMenu("WARNING: An old camera.py exists%t|Overwrite|Rename old version text") + if ret == -1: return # EXIT DO NOTHING + elif ret == 1: Text.unlink(cam_text) + elif ret == 2: cam_text.name = 'old_camera.txt' + cam_text = None + + if not cam_text: + scripting=Blender.Text.New('camera.py') + scripting.write(camera_change_scriptlink) + + scn=Scene.GetCurrent() + scriptlinks = scn.getScriptLinks('FrameChanged') + if not scriptlinks or ('camera.py' not in scriptlinks): + scn.addScriptLink('camera.py','FrameChanged') + Blender.Draw.PupMenu('FrameChange Scriptlink Added%t|Name camera objects to their activation frame numbers(s) seperated by commas|valid names are "1,10,46" or "1,10,200" or "200" (without quotation marks)') + Blender.Window.RedrawAll() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/config.py b/release/scripts/config.py new file mode 100644 index 00000000000..69f929dab97 --- /dev/null +++ b/release/scripts/config.py @@ -0,0 +1,797 @@ +#!BPY + +""" +Name: 'Scripts Config Editor' +Blender: 236 +Group: 'System' +Tooltip: 'View and edit available scripts configuration data' +""" + +__author__ = "Willian P. Germano" +__version__ = "0.1 2005/04/14" +__email__ = ('scripts', 'Author, wgermano:ig*com*br') +__url__ = ('blender', 'elysiun') + +__bpydoc__ ="""\ +This script can be used to view and edit configuration data stored +by other scripts. + +Technical: this data is saved as dictionary keys with the +Blender.Registry module functions. It is persistent while Blender is +running and, if the script's author chose to, is also saved to a file +in the scripts config data dir. + +Usage: + +- Start Screen: + +To access any available key, select it from (one of) the menu(s). + +Hotkeys:
+ ESC or Q: [Q]uit
+ H: [H]elp + +- Keys Config Screen: + +This screen exposes the configuration data for the chosen script key. If the +buttons don't fit completely on the screen, you can scroll up or down with +arrow keys or a mouse wheel. Leave the mouse pointer over any button to get +a tooltip about that option. + +Any change can be reverted -- unless you have already applied it. + +If the key is already stored in a config file, there will be a toggle button +(called 'file') that controls whether the changes will be written back to +the file or not. If you just want to change the configuration for the current +session, simply unset that button. Note, though, that data from files has +precedence over those keys already loaded in Blender, so if you re-run this +config editor, unsaved changes will not be seen. + +Hotkeys:
+ ESC: back to Start Screen
+ Q: [Q]uit
+ U: [U]ndo changes
+ ENTER: apply changes (can't be reverted, then)
+ UP, DOWN Arrows and mouse wheel: scroll text up / down + +Notes: + +a) Available keys are determined by which scripts you use. If the key you +expect isn't available (or maybe there are none or too few keys), either the +related script doesn't need or still doesn't support this feature or the key +has not been stored yet, in which case you just need to run that script once +to make its config data available. + +b) There are two places where config data files can be saved: the +bpydata/config/ dir (1) inside the default scripts dir or (2) inside the user +defined Python scripts dir +(User Preferences window -> File Paths tab -> Python path). If available, +(2) is the default and also the recommended option, because then fresh Blender +installations won't delete your config data. To use this option, simply set a +dir for Python scripts at the User Preferences window and make sure this dir +has the subdirs bpydata/ and bpydata/config/ inside it. + +c) The key called "General" in the "Other" menu has general config options. +All scripts where that data is relevant are recommended to access it and set +behaviors accordingly. +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# config.py version 0.1 2005/04/08 +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender import Draw, BGL, Registry, Window, sys as bsys +from Blender.Window import Theme +from BPyRegistry import LoadConfigData, SaveConfigData, HasConfigData,\ + BPY_KEY_IN_FILE + +MAX_STR_LEN = 300 # max length for a string +MAX_ITEMS_NUM = 100 # max number for each type of button + +# --- +# The "General" configure options key is managed from this script. +verbose = True +confirm_overwrite = True + +tooltips = { + 'verbose': 'print script messages (info, warnings, errors) to the console', + 'confirm_overwrite': 'scripts should always confirm before overwriting files' +} + +CFG_LIST = ['verbose', 'confirm_overwrite', 'tooltips'] +KEY_NAME = 'General' + +def update_registry(): + rd = {} + for var in CFG_LIST: + exec("rd['%s']=%s" % (var, var)) + Registry.SetKey(KEY_NAME, rd, True) + +rd = Registry.GetKey('General', True) +if rd: + try: + for var in CFG_LIST[:-1]: # no need to update tooltips + exec("%s=rd['%s']" % (var, var)) + except: update_registry() + +else: + update_registry() +# --- + +# script globals: +CFGKEY = '' +LABELS = [] +GD = {} # groups dict (includes "Other" for unmapped keys) +INDEX = 0 # to pass button indices to fs callbacks +FREEKEY_IDX = 0 # index of set of keys not mapped to a script name +KEYMENUS = [] +ALL_SCRIPTS = {} +ALL_GROUPS = [] +START_SCREEN = 0 +CONFIG_SCREEN = 1 +DISK_UPDATE = True # write changed data to its config file + +ACCEPTED_TYPES = [bool, int, float, str, unicode] + +SCREEN = START_SCREEN + +SCROLL_DOWN = 0 + +# events: +BEVT_START = 50 +BEVT_EXIT = 0 + BEVT_START +BEVT_BACK = 1 + BEVT_START +BEVT_DISK = 2 + BEVT_START +BEVT_CANCEL = 3 + BEVT_START +BEVT_APPLY = 4 + BEVT_START +BEVT_HELP = 5 + BEVT_START +BEVT_DEL = 6 + BEVT_START +BEVT_KEYMENU = [] +BUT_KEYMENU = [] +BEVT_BOOL = 100 +BEVT_INT = BEVT_BOOL + MAX_ITEMS_NUM +BEVT_FLOAT = BEVT_BOOL + 2*MAX_ITEMS_NUM +BEVT_STR = BEVT_BOOL + 3*MAX_ITEMS_NUM +BEVT_BROWSEDIR = BEVT_BOOL + 4*MAX_ITEMS_NUM +BEVT_BROWSEFILE = BEVT_BOOL + 5*MAX_ITEMS_NUM +BUT_TYPES = { + bool: 0, + int: 0, + float: 0, + str: 0 +} + +# Function definitions: + +def get_keys(): + LoadConfigData() # loads all data from files in (u)scripts/bpydata/config/ + return [k for k in Registry.Keys() if k[0] != "_"] + + +def show_help(script = 'config.py'): + Blender.ShowHelp(script) + + +def fs_dir_callback(pathname): + global CFGKEY, INDEX + + pathname = bsys.dirname(pathname) + datatypes = CFGKEY.sorteddata + datatypes[str][INDEX][1] = pathname + + +def fs_file_callback(pathname): + global CFGKEY, INDEX + + datatypes = CFGKEY.sorteddata + datatypes[str][INDEX][1] = pathname + + +# parse Bpymenus file to get all script filenames +# (used to show help for a given key) +def fill_scripts_dict(): + global ALL_SCRIPTS, ALL_GROUPS + + group = '' + group_len = 0 + sep = bsys.sep + home = Blender.Get('homedir') + if not home: + errmsg = """ +Can't find Blender's home dir and so can't find the +Bpymenus file automatically stored inside it, which +is needed by this script. Please run the +Help -> System -> System Information script to get +information about how to fix this. +""" + raise SystemError, errmsg + fname = bsys.join(home, 'Bpymenus') + if not bsys.exists(fname): return False + f = file(fname, 'r') + lines = f.readlines() + f.close() + for l in lines: + if l.rfind('{') > 0: + group = l.split()[0] + ALL_GROUPS.append(group) + group_len += 1 + continue + elif l[0] != "'": continue + fields = l.split("'") + if len(fields) > 2: + menuname = fields[1].replace('...','') + fields = fields[2].split() + if len(fields) > 1: + fname = fields[1].split(sep)[-1] + ALL_SCRIPTS[fname] = (menuname, group_len - 1) + return True + + +def map_to_registered_script(name): + global ALL_SCRIPTS + + if not name.endswith('.py'): + name = "%s.py" % name + if ALL_SCRIPTS.has_key(name): + return ALL_SCRIPTS[name] # == (menuname, group index) + return None + + +def reset(): + global LABELS, GD, KEYMENUS, KEYS + + # init_data is recalled when a key is deleted, so: + LABELS = [] + GD = {} + KEYMENUS = [] + KEYS = get_keys() + + +# gather all script info, fill gui menus +def init_data(): + global KEYS, GD, ALL_GROUPS, ALL_SCRIPTS, KEYMENUS, LABELS + global BUT_KEYMENU, BEVT_KEYMENU, FREEKEY_IDX + + for k in ALL_GROUPS: + GD[k] = [] + GD[None] = [] + + for k in KEYS: + res = map_to_registered_script(k) + if res: + GD[ALL_GROUPS[res[1]]].append((k, res[0])) + else: GD[None].append((k, k)) + + for k in GD.keys(): + if not GD[k]: GD.pop(k) + + if GD.has_key(None): + GD['Other'] = GD[None] + GD.pop(None) + FREEKEY_IDX = -1 + + BUT_KEYMENU = range(len(GD)) + + for k in GD.keys(): + kmenu = ['Configuration Keys: %s%%t' % k] + for j in GD[k]: + kmenu.append(j[1]) + kmenu = "|".join(kmenu) + KEYMENUS.append(kmenu) + LABELS.append(k) + + if FREEKEY_IDX < 0: + FREEKEY_IDX = LABELS.index('Other') + + length = len(KEYMENUS) + BEVT_KEYMENU = range(1, length + 1) + BUT_KEYMENU = range(length) + + +# for theme colors: +def float_colors(cols): + return map(lambda x: x / 255.0, cols) + + + +class Config: + + def __init__(self, key, has_group = True): + global DISK_UPDATE + + self.key = key + self.has_group = has_group + self.name = key + self.fromdisk = HasConfigData(key) & BPY_KEY_IN_FILE + if not self.fromdisk: DISK_UPDATE = False + else: DISK_UPDATE = True + + self.origdata = Registry.GetKey(key, True) + data = self.data = self.origdata.copy() + + if not data: + Draw.PupMenu('ERROR: couldn\'t find requested data') + self.data = None + return + + keys = data.keys() + nd = {} + for k in keys: + nd[k.lower()] = k + + if nd.has_key('tooltips'): + ndval = nd['tooltips'] + self.tips = data[ndval] + data.pop(ndval) + else: self.tips = 0 + + if nd.has_key('limits'): + ndval = nd['limits'] + self.limits = data[ndval] + data.pop(ndval) + else: self.limits = 0 + + if self.has_group: + scriptname = key + if not scriptname.endswith('.py'): + scriptname = "%s.py" % scriptname + elif nd.has_key('script'): + ndval = nd['script'] + scriptname = data[ndval] + data.pop(ndval) + if not scriptname.endswith('.py'): + scriptname = "%s.py" % scriptname + else: scriptname = None + + self.scriptname = scriptname + + self.sort() + + + def needs_update(self): # check if user changed data + data = self.data + new = self.sorteddata + + for vartype in new.keys(): + for i in new[vartype]: + if data[i[0]] != i[1]: return 1 + + return 0 # no changes + + + def update(self): # update original key + global DISK_UPDATE + + data = self.data + odata = self.origdata + new = self.sorteddata + for vartype in new.keys(): + for i in new[vartype]: + if data[i[0]] != i[1]: data[i[0]] = i[1] + if odata[i[0]] != i[1]: odata[i[0]] = i[1] + + if DISK_UPDATE: Registry.SetKey(self.key, odata, True) + + def delete(self): + global DISK_UPDATE + + delmsg = 'OK?%t|Delete key from memory' + if DISK_UPDATE: + delmsg = "%s and from disk" % delmsg + if Draw.PupMenu(delmsg) == 1: + Registry.RemoveKey(self.key, DISK_UPDATE) + return True + + return False + + + def revert(self): # revert to original key + data = self.data + new = self.sorteddata + for vartype in new.keys(): + for i in new[vartype]: + if data[i[0]] != i[1]: i[1] = data[i[0]] + + + def sort(self): # create a new dict with types as keys + global ACCEPTED_TYPES, BUT_TYPES + + data = self.data + datatypes = {} + keys = [k for k in data.keys() if k[0] != '_'] + for k in keys: + val = data[k] + tval = type(val) + if tval not in ACCEPTED_TYPES: continue + if not datatypes.has_key(tval): + datatypes[tval] = [] + datatypes[type(val)].append([k, val]) + if datatypes.has_key(unicode): + if not datatypes.has_key(str): datatypes[str] = datatypes[unicode] + else: + for i in datatypes[unicode]: datatypes[str].append(i) + datatypes.pop(unicode) + for k in datatypes.keys(): + dk = datatypes[k] + dk.sort() + dk.reverse() + BUT_TYPES[k] = range(len(dk)) + self.sorteddata = datatypes + + +# GUI: + +# gui callbacks: + +def gui(): # drawing the screen + + global SCREEN, START_SCREEN, CONFIG_SCREEN, KEYMENUS, LABELS + global BEVT_KEYMENU, BUT_KEYMENU, CFGKEY + global BUT_TYPES, SCROLL_DOWN, VARS_NUM + + WIDTH, HEIGHT = Window.GetAreaSize() + + theme = Theme.Get()[0] + tui = theme.get('ui') + ttxt = theme.get('text') + + COL_BG = float_colors(ttxt.back) + COL_TXT = ttxt.text + COL_TXTHI = ttxt.text_hi + + BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3]) + BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + + if SCREEN == START_SCREEN: + x = 10 + y = 10 + h = 20 + w = 90 + BGL.glRasterPos2i(x, y) + Draw.Text('Select a configuration key to access it. Press Q or ESC to leave.') + km_len = len(KEYMENUS) + km_columns = (WIDTH - x) / w + if km_columns == 0: km_rows = km_len + else: + km_rows = km_len / km_columns + if (km_len % km_columns): km_rows += 1 + if km_rows == 0: km_rows = 1 + ystart = y + 2*h*km_rows + if ystart > (HEIGHT - 70): ystart = HEIGHT - 70 + y = ystart + column = 1 + for i, km in enumerate(KEYMENUS): + column += 1 + BGL.glRasterPos2i(x + 2, y + h + 5) + Draw.Text(LABELS[i]) + BUT_KEYMENU[i] = Draw.Menu(km, BEVT_KEYMENU[i], + x, y, w - 10, h, 0, 'Choose a key to access its configuration data') + if column > km_columns: + column = 1 + y -= 2*h + if y < 35: break + x = 10 + else: x += w + x = 10 + y = 50 + ystart + BGL.glColor3ub(COL_TXTHI[0], COL_TXTHI[1], COL_TXTHI[2]) + BGL.glRasterPos2i(x, y) + Draw.Text('Scripts Configuration Editor') + Draw.PushButton('help', BEVT_HELP, x, 22, 45, 16, + 'View help information about this script (hotkey: H)') + + elif SCREEN == CONFIG_SCREEN: + x = y = 10 + h = 18 + data = CFGKEY.sorteddata + tips = CFGKEY.tips + fromdisk = CFGKEY.fromdisk + limits = CFGKEY.limits + VARS_NUM = 0 + for k in data.keys(): + VARS_NUM += len(data[k]) + lines = VARS_NUM + 5 # to account for header and footer + y = lines*h + if y > HEIGHT - 20: y = HEIGHT - 20 + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) + BGL.glRasterPos2i(x, y) + Draw.Text('Scripts Configuration Editor') + y -= 20 + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + txtsize = 10 + if HEIGHT < lines*h: + BGL.glRasterPos2i(10, 5) + txtsize += Draw.Text('Arrow keys or mouse wheel to scroll, ') + BGL.glRasterPos2i(txtsize, 5) + Draw.Text('Q or ESC to return.') + BGL.glRasterPos2i(x, y) + Draw.Text('Key: "%s"' % CFGKEY.name) + bh = 16 + bw = 45 + by = 16 + i = -1 + if CFGKEY.scriptname: + i = 0 + Draw.PushButton('help', BEVT_HELP, x, by, bw, bh, + 'Show documentation for the script that owns this key (hotkey: H)') + Draw.PushButton('back', BEVT_BACK, x + (1+i)*bw, by, bw, bh, + 'Back to config keys selection screen (hotkey: ESC)') + Draw.PushButton('exit', BEVT_EXIT, x + (2+i)*bw, by, bw, bh, + 'Exit from Scripts Config Editor (hotkey: Q)') + Draw.PushButton('revert', BEVT_CANCEL, x + (3+i)*bw, by, bw, bh, + 'Revert data to original values (hotkey: U)') + Draw.PushButton('apply', BEVT_APPLY, x + (4+i)*bw, by, bw, bh, + 'Apply changes, if any (hotkey: ENTER)') + delmsg = 'Delete this data key from memory' + if fromdisk: delmsg = "%s and from disk" % delmsg + Draw.PushButton('delete', BEVT_DEL, x + (5+i)*bw, by, bw, bh, + '%s (hotkey: DELETE)' % delmsg) + if fromdisk: + Draw.Toggle("file", BEVT_DISK, x + 3 + (6+i)*bw, by, bw, bh, DISK_UPDATE, + 'Update also the file where this config key is stored') + i = -1 + top = -1 + y -= 20 + yend = 30 + if data.has_key(bool) and y > 0: + lst = data[bool] + for l in lst: + top += 1 + i += 1 + if top < SCROLL_DOWN: continue + y -= h + if y < yend: break + w = 20 + tog = data[bool][i][1] + if tips and tips.has_key(l[0]): tooltip = tips[l[0]] + else: tooltip = "click to toggle" + BUT_TYPES[bool][i] = Draw.Toggle("", BEVT_BOOL + i, + x, y, w, h, tog, tooltip) + BGL.glRasterPos2i(x + w + 3, y + 5) + Draw.Text(l[0].lower().replace('_', ' ')) + i = -1 + y -= 5 + if data.has_key(int) and y > 0: + lst = data[int] + for l in lst: + w = 70 + top += 1 + i += 1 + if top < SCROLL_DOWN: continue + y -= h + if y < yend: break + val = data[int][i][1] + if limits: min, max = limits[l[0]] + else: min, max = 0, 10 + if tips and tips.has_key(l[0]): tooltip = tips[l[0]] + else: tooltip = "click / drag to change" + BUT_TYPES[int][i] = Draw.Number("", BEVT_INT + i, + x, y, w, h, val, min, max, tooltip) + BGL.glRasterPos2i(x + w + 3, y + 3) + Draw.Text(l[0].lower().replace('_', ' ')) + i = -1 + y -= 5 + if data.has_key(float) and y > 0: + lst = data[float] + for l in lst: + w = 70 + top += 1 + i += 1 + if top < SCROLL_DOWN: continue + y -= h + if y < yend: break + val = data[float][i][1] + if limits: min, max = limits[l[0]] + else: min, max = 0.0, 1.0 + if tips and tips.has_key(l[0]): tooltip = tips[l[0]] + else: tooltip = "click and drag to change" + BUT_TYPES[float][i] = Draw.Number("", BEVT_FLOAT + i, + x, y, w, h, val, min, max, tooltip) + BGL.glRasterPos2i(x + w + 3, y + 3) + Draw.Text(l[0].lower().replace('_', ' ')) + i = -1 + y -= 5 + if data.has_key(str) and y > 0: + lst = data[str] + for l in lst: + top += 1 + i += 1 + if top < SCROLL_DOWN: continue + y -= h + if y < yend: break + name = l[0].lower() + is_dir = is_file = False + if name.find('_dir', -4) > 0: is_dir = True + elif name.find('_file', -5) > 0: is_file = True + w = WIDTH - 20 + wbrowse = 50 + if is_dir and w > wbrowse: w -= wbrowse + if tips and tips.has_key(l[0]): tooltip = tips[l[0]] + else: tooltip = "click to write a new string" + name = name.replace('_',' ') + ': ' + if len(l[1]) > MAX_STR_LEN: + l[1] = l[1][:MAX_STR_LEN] + BUT_TYPES[str][i] = Draw.String(name, BEVT_STR + i, + x, y, w, h, l[1], MAX_STR_LEN, tooltip) + if is_dir: + Draw.PushButton('browse', BEVT_BROWSEDIR + i, x+w+1, y, wbrowse, h, + 'click to open a file selector (pick any file in the desired dir)') + elif is_file: + Draw.PushButton('browse', BEVT_BROWSEFILE + i, x + w + 1, y, 50, h, + 'click to open a file selector') + + +def fit_scroll(): + global SCROLL_DOWN, VARS_NUM + max = VARS_NUM - 1 # so last item is always visible + if SCROLL_DOWN > max: + SCROLL_DOWN = max + elif SCROLL_DOWN < 0: + SCROLL_DOWN = 0 + + +def event(evt, val): # input events + + global SCREEN, START_SCREEN, CONFIG_SCREEN + global SCROLL_DOWN, CFGKEY + + if not val: return + + if evt == Draw.ESCKEY: + if SCREEN == START_SCREEN: Draw.Exit() + else: + if CFGKEY.needs_update(): + if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: + CFGKEY.update() + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + Draw.Redraw() + return + elif evt == Draw.QKEY: + if SCREEN == CONFIG_SCREEN and CFGKEY.needs_update(): + if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: + CFGKEY.update() + Draw.Exit() + return + elif evt == Draw.HKEY: + if SCREEN == START_SCREEN: show_help() + elif CFGKEY.scriptname: show_help(CFGKEY.scriptname) + return + + elif SCREEN == CONFIG_SCREEN: + if evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE]: + SCROLL_DOWN += 1 + fit_scroll() + elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE]: + SCROLL_DOWN -= 1 + fit_scroll() + elif evt == Draw.UKEY: + if CFGKEY.needs_update(): + CFGKEY.revert() + elif evt == Draw.RETKEY or evt == Draw.PADENTER: + if CFGKEY.needs_update(): + CFGKEY.update() + elif evt == Draw.DELKEY: + if CFGKEY.delete(): + reset() + init_data() + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + else: return + Draw.Redraw() + + +def button_event(evt): # gui button events + + global SCREEN, START_SCREEN, CONFIG_SCREEN, CFGKEY, DISK_UPDATE + global BEVT_KEYMENU, BUT_KEYMENU, BUT_TYPES, SCROLL_DOWN, GD, INDEX + global BEVT_EXIT, BEVT_BACK, BEVT_APPLY, BEVT_CANCEL, BEVT_HELP, FREEKEY_IDX + + if SCREEN == START_SCREEN: + for e in BEVT_KEYMENU: + if evt == e: + index = e - 1 + k = BUT_KEYMENU[index].val - 1 + CFGKEY = Config(GD[LABELS[index]][k][0], index != FREEKEY_IDX) + if CFGKEY.data: + SCREEN = CONFIG_SCREEN + Draw.Redraw() + return + if evt == BEVT_EXIT: + Draw.Exit() + elif evt == BEVT_HELP: + show_help() + return + + elif SCREEN == CONFIG_SCREEN: + datatypes = CFGKEY.sorteddata + if evt >= BEVT_BROWSEFILE: + INDEX = evt - BEVT_BROWSEFILE + Window.FileSelector(fs_file_callback, 'Choose file') + elif evt >= BEVT_BROWSEDIR: + INDEX = evt - BEVT_BROWSEDIR + Window.FileSelector(fs_dir_callback, 'Choose any file') + elif evt >= BEVT_STR: + var = BUT_TYPES[str][evt - BEVT_STR].val + datatypes[str][evt - BEVT_STR][1] = var + elif evt >= BEVT_FLOAT: + var = BUT_TYPES[float][evt - BEVT_FLOAT].val + datatypes[float][evt - BEVT_FLOAT][1] = var + elif evt >= BEVT_INT: + var = BUT_TYPES[int][evt - BEVT_INT].val + datatypes[int][evt - BEVT_INT][1] = var + elif evt >= BEVT_BOOL: + var = datatypes[bool][evt - BEVT_BOOL][1] + if var == True: var = False + else: var = True + datatypes[bool][evt - BEVT_BOOL][1] = var + + elif evt == BEVT_BACK: + if SCREEN == CONFIG_SCREEN: + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + Draw.Redraw() + elif evt == BEVT_EXIT: + if CFGKEY.needs_update(): + if Draw.PupMenu('UPDATE?%t|Data was changed') == 1: + CFGKEY.update() + Draw.Exit() + return + elif evt == BEVT_APPLY: + if CFGKEY.needs_update(): + CFGKEY.update() + elif evt == BEVT_CANCEL: + if CFGKEY.needs_update(): + CFGKEY.revert() + elif evt == BEVT_DEL: + if CFGKEY.delete(): + reset() + init_data() + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + elif evt == BEVT_DISK: + if DISK_UPDATE: DISK_UPDATE = False + else: DISK_UPDATE = True + elif evt == BEVT_HELP: + show_help(CFGKEY.scriptname) + return + else: + return + Draw.Redraw() + +# End of definitions + + +KEYS = get_keys() + +if not KEYS: + Draw.PupMenu("NO DATA: please read this help screen") + Blender.ShowHelp('config.py') +else: + fill_scripts_dict() + init_data() + Draw.Register(gui, event, button_event) diff --git a/release/scripts/console.py b/release/scripts/console.py new file mode 100644 index 00000000000..7d9d8be5e9e --- /dev/null +++ b/release/scripts/console.py @@ -0,0 +1,849 @@ +#!BPY + +""" +Name: 'Interactive Console' +Blender: 237 +Group: 'System' +Tooltip: 'Interactive Python Console' +""" + +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["Author's homepage, http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun", "Official Python site, http://www.python.org"] +__bpydoc__ = """\ +This is an interactive console, similar to Python's own command line interpreter. Since it is embedded in Blender, it has access to all Blender Python modules. + +Those completely new to Python are recommended to check the link button above +that points to its official homepage, with news, downloads and documentation. + +Usage:
+ Type your code and hit "Enter" to get it executed.
+ - Right mouse click: Console Menu (Save output, etc);
+ - Mousewheel: Scroll text + - Arrow keys: command history and cursor;
+ - Shift + Backspace: Backspace whole word;
+ - Shift + Arrow keys: jump words;
+ - Ctrl + (+/- or mousewheel): Zoom text size;
+ - Ctrl + Enter: auto compleate based on variable names and modules loaded -- multiple choices popup a menu;
+ - Shift + Enter: multiline functions -- delays executing code until only Enter is pressed. +""" +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["http://members.iinet.net.au/~cpbarton/ideasman/", "blender", "elysiun"] + +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +import bpy +from Blender import * +import sys as python_sys +import StringIO + +# Constants +__DELIMETERS__ = '. ,=+-*/%<>&~][{}():\t' +__VARIABLE_DELIMETERS__ = ' ,=+-*/%<>&~{}():\t' + +__LINE_HISTORY__ = 500 + +global __FONT_SIZE__ + +__FONT_SIZES__ = ( ('tiny', 10), ('small', 12), ('normal', 14), ('large', 16) ) +__FONT_SIZE__ = 2 # index for the list above, normal default. + +global __CONSOLE_LINE_OFFSET__ +__CONSOLE_LINE_OFFSET__ = 0 + +''' +# Generic Blender functions +def getActScriptWinRect(): + area = Window.GetAreaSize() + area = (area[0]-1, area[1]-1) + for scrInfo in Window.GetScreenInfo(Window.Types['SCRIPT'], 'win', ''): + if scrInfo['vertices'][2]-scrInfo['vertices'][0] == area[0]: + if scrInfo['vertices'][3]-scrInfo['vertices'][1] == area[1]: + return scrInfo['vertices'] + return None +''' + + +# menuText, # per group +def PupMenuLess(menu, groupSize=35): + more = [' more...'] + less = [' less...'] + + menuList= menu.split('|') + + # No Less Needed, just call. + if len(menuList) < groupSize: + return Draw.PupMenu(menu) + + title = menuList[0].split('%t')[0] + + # Split the list into groups + menuGroups = [[]] + for li in menuList[1:]: + if len(menuGroups[-1]) < groupSize: + menuGroups[-1].append(li) + else: + menuGroups.append([li]) + + # Stores teh current menu group we are looking at + groupIdx = 0 + while 1: + # Give us a title with the menu number + numTitle = [ ' '.join([title, str(groupIdx + 1), 'of', str(len(menuGroups)), '%t'])] + if groupIdx == 0: + menuString = '|'.join(numTitle + menuGroups[groupIdx] + more) + elif groupIdx == len(menuGroups)-1: + menuString = '|'.join(numTitle + less + menuGroups[groupIdx]) + else: # In the middle somewhere so Show a more and less + menuString = '|'.join(numTitle + less + menuGroups[groupIdx] + more) + result = Draw.PupMenu(menuString) + # User Exit + if result == -1: + return -1 + + if groupIdx == 0: # First menu + if result-1 < groupSize: + return result + else: # must be more + groupIdx +=1 + elif groupIdx == len(menuGroups): # Last Menu + if result == 1: # Must be less + groupIdx -= 1 + else: # Must be a choice + return result + (groupIdx*groupSize) + + else: + if result == 1: # Must be less + groupIdx -= 1 + elif result-2 == groupSize: + groupIdx +=1 + else: + return result - 1 + (groupIdx*groupSize) + + + +# Use newstyle classes, Im not bothering with inheretence +# but slots are faster. +class cmdLine(object): + __slots__ = [\ + 'cmd', # is the command string, or any other message + 'type',# type: 0:user input 1:program feedback 2:error message. 3:option feedback + 'exe' # 0- not yet executed 1:executed + ] + def __init__(self, cmd, type, exe): + self.cmd = cmd + self.type = type + self.exe = exe + +# Include external file with internal namespace +def include(filename): + file = open(filename, 'r') + filedata = file.read() + file.close() + return compile(filedata, filename, 'exec') + +# Writes command line data to a blender text file. +def writeCmdData(cmdLineList, type): + if type == 3: + typeList = [0,1,2, 3, None] # all + else: + typeList = [type] # so we can use athe lists 'in' methiod + + newText = Text.New('command_output.py', 1) + for myCmd in cmdLineList: + if myCmd.type in typeList: # user input + newText.write('%s\n' % myCmd.cmd) + Draw.PupMenu('%s written' % newText.name) + +def insertCmdData(cmdBuffer): + texts = list(bpy.data.texts) + textNames = [tex.name for tex in texts] + if textNames: + choice = Draw.PupMenu('|'.join(textNames)) + if choice != -1: + text = texts[choice-1] + + # Add the text! + for l in text.asLines(): + cmdBuffer.append(cmdLine('%s ' % l, 0, 0)) + Draw.Redraw() + + +COLLECTED_VAR_NAMES = {} # a list of keys, each key has a list of absolute paths + +# Pain and simple recursice dir(), accepts a string +unused_types = str, dict, list, float, int, str, type, tuple, type(dir), type(None) +def rdir(dirString, depth=0): + #print ' ' * depth, dirString + # MAX DEPTH SET HERE + if depth > 5: + # print 'maxdepoth reached.' + return + + global COLLECTED_VAR_NAMES + dirStringSplit = dirString.split('.') + + exec('value=' + dirString) + + if type(value) in unused_types: + # print 'bad type' + return + dirList = dir(value) + + for dirItem in dirList: + if dirItem.startswith('_'): + continue + + dirData = None + try: + # Rare cases this can mess up, material.shader was a problem. + exec('dirData = %s.%s' % (dirString, dirItem)) + #print dirData + except: + # Dont bother with this data. + continue + #print 'HEY', dirData, dirItem + #if type(dirItem) != str: + # print dirItem, type(dirItem) + + if dirItem not in COLLECTED_VAR_NAMES: # .keys() + COLLECTED_VAR_NAMES[dirItem] = [] + + # Add the string + # splitD = dirString.split('"')[-2] + + # Example of dirString + # __CONSOLE_VAR_DICT__["Main"].scenes.active.render + + # Works but can be faster + # splitD = dirString.replace('__CONSOLE_VAR_DICT__["', '').replace('"]', '') + + splitD = dirString[22:].replace('"]', '') + + if splitD not in COLLECTED_VAR_NAMES[dirItem]: + # print dirItem, dirString, splitD, + COLLECTED_VAR_NAMES[dirItem].append(splitD) + + + # Stops recursice stuff, overlooping + #print type(dirItem) + #if type(dirData) == types.ClassType or \ + # type(dirData) == types.ModuleType: + type_dirData = type(dirData) + if type_dirData not in unused_types: + # print type(dirData), dirItem + # Dont loop up dirs for strings ints etc. + if dirItem not in dirStringSplit: + rdir( '%s.%s' % (dirString, dirItem), depth+1) + ''' + elif depth == 0: # Add local variables + # print type(dirData), dirItem + # Dont loop up dirs for strings ints etc. + if dirItem not in dirStringSplit: + rdir( '%s.%s' % (dirString, dirItem), depth+1) + ''' + +def recursive_dir(): + global COLLECTED_VAR_NAMES + + for name in __CONSOLE_VAR_DICT__: # .keys() + if not name.startswith('_'): # Dont pick names like __name__ + rdir('__CONSOLE_VAR_DICT__["%s"]' % name) + #print COLLECTED_VAR_NAMES + COLLECTED_VAR_NAMES[name] = [''] + return COLLECTED_VAR_NAMES + +# Runs the code line(s) the user has entered and handle errors +# As well as feeding back the output into the blender window. +def runUserCode(__USER_CODE_STRING__): + global __CONSOLE_VAR_DICT__ # We manipulate the variables here. loading and saving from localspace to this global var. + + # Open A File like object to write all output to, that would useually be printed. + python_sys.stdout.flush() # Get rid of whatever came before + __FILE_LIKE_STRING__ = StringIO.StringIO() # make a new file like string, this saves up from making a file. + __STD_OUTPUT__ = python_sys.stdout # we need to store the normal output. + python_sys.stdout=__FILE_LIKE_STRING__ # Now anything printed will be written to the file like string. + + # Try and run the user entered line(s) + try: + # Load all variabls from global dict to local space. + __TMP_VAR_NAME__ = __TMP_VAR__ = '' # so as not to raise an error when del'ing + + for __TMP_VAR_NAME__, __TMP_VAR__ in __CONSOLE_VAR_DICT__.items(): + exec('%s%s' % (__TMP_VAR_NAME__,'=__TMP_VAR__')) + del __TMP_VAR_NAME__ + del __TMP_VAR__ + + # Now all the vars are loaded, execute the code. # Newline thanks to phillip, + exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'single')) #exec(compile(__USER_CODE_STRING__, 'blender_cmd.py', 'exec')) + + # Flush global dict, allow the user to remove items. + __CONSOLE_VAR_DICT__ = {} + + __TMP_VAR_NAME__ = '' # so as not to raise an error when del'ing + # Write local veriables to global __CONSOLE_VAR_DICT__ + for __TMP_VAR_NAME__ in dir(): + if __TMP_VAR_NAME__ != '__FILE_LIKE_STRING__' and\ + __TMP_VAR_NAME__ != '__STD_OUTPUT__' and\ + __TMP_VAR_NAME__ != '__TMP_VAR_NAME__' and\ + __TMP_VAR_NAME__ != '__USER_CODE_STRING__': + + # Execute the local > global coversion. + exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__)) + del __TMP_VAR_NAME__ + + except: # Prints the REAL exception. + error = '%s: %s' % (python_sys.exc_type, python_sys.exc_value) + for errorLine in error.split('\n'): + cmdBuffer.append(cmdLine(errorLine, 2, None)) # new line to type into + + python_sys.stdout = __STD_OUTPUT__ # Go back to output to the normal blender console + + # Copy all new output to cmdBuffer + + __FILE_LIKE_STRING__.seek(0) # the readline function requires that we go back to the start of the file. + + for line in __FILE_LIKE_STRING__.readlines(): + cmdBuffer.append(cmdLine(line, 1, None)) + + cmdBuffer.append(cmdLine(' ', 0, 0)) # new line to type into + python_sys.stdout=__STD_OUTPUT__ + __FILE_LIKE_STRING__.close() + + + + + +#------------------------------------------------------------------------------# +# event handling code # +#------------------------------------------------------------------------------# +def handle_event(evt, val): + + # Insert Char into the cammand line + def insCh(ch): # Instert a char + global cmdBuffer + global cursor + # Later account for a cursor variable + cmdBuffer[-1].cmd = ('%s%s%s' % ( cmdBuffer[-1].cmd[:cursor], ch, cmdBuffer[-1].cmd[cursor:])) + + #------------------------------------------------------------------------------# + # Define Complex Key Actions # + #------------------------------------------------------------------------------# + def actionEnterKey(): + global histIndex, cursor, cmdBuffer + + def getIndent(string): + # Gather white space to add in the previous line + # Ignore the last char since its padding. + whiteSpace = '' + #for i in range(len(cmdBuffer[-1].cmd)): + for i in xrange(len(string)-1): + if cmdBuffer[-1].cmd[i] == ' ' or cmdBuffer[-1].cmd[i] == '\t': + whiteSpace += string[i] + else: + break + return whiteSpace + + # Autocomplete + if Window.GetKeyQualifiers() & Window.Qual.CTRL: + actionAutoCompleate() + return + + # Are we in the middle of a multiline part or not? + # try be smart about it + if cmdBuffer[-1].cmd.split('#')[0].rstrip().endswith(':'): + # : indicates an indent is needed + cmdBuffer.append(cmdLine('\t%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) + print ': indicates an indent is needed' + + elif cmdBuffer[-1].cmd[0] in [' ', '\t'] and len(cmdBuffer[-1].cmd) > 1 and cmdBuffer[-1].cmd.split(): + # white space at the start means he havnt finished the multiline. + cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) + print 'white space at the start means he havnt finished the multiline.' + + elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: + # Crtl forces multiline + cmdBuffer.append(cmdLine('%s ' % getIndent(cmdBuffer[-1].cmd), 0, 0)) + print 'Crtl forces multiline' + + else: # Execute multiline code block + + # Multiline code will still run with 1 line, + multiLineCode = ['if 1:'] # End of the multiline first. + + # Seek the start of the file multiline + i = 1 + while cmdBuffer[-i].exe == 0: + i+=1 + + while i > 1: + i-=1 + + if cmdBuffer[-i].cmd == ' ':# Tag as an output type so its not used in the key history + cmdBuffer[-i].type = 1 + else: # Tab added at the start for added if 1: statement + multiLineCode.append('\t%s' % cmdBuffer[-i].cmd ) + + # Mark as executed + cmdBuffer[-i].exe = 1 + + multiLineCode.append('\tpass') # reverse will make this the start. + + # Dubug, print the code that is executed. + #for m in multiLineCode: print m + + runUserCode('\n'.join(multiLineCode)) + + # Clear the output based on __LINE_HISTORY__ + if len(cmdBuffer) > __LINE_HISTORY__: + cmdBuffer = cmdBuffer[-__LINE_HISTORY__:] + + histIndex = cursor = -1 # Reset cursor and history + + def actionUpKey(): + global histIndex, cmdBuffer + if abs(histIndex)+1 >= len(cmdBuffer): + histIndex = -1 + histIndex -= 1 + while cmdBuffer[histIndex].type != 0 and abs(histIndex) < len(cmdBuffer): + histIndex -= 1 + if cmdBuffer[histIndex].type == 0: # we found one + cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd + + def actionDownKey(): + global histIndex, cmdBuffer + if histIndex >= -2: + histIndex = -len(cmdBuffer) + histIndex += 1 + while cmdBuffer[histIndex].type != 0 and histIndex != -2: + histIndex += 1 + if cmdBuffer[histIndex].type == 0: # we found one + cmdBuffer[-1].cmd = cmdBuffer[histIndex].cmd + + def actionRightMouse(): + global __FONT_SIZE__ + choice = Draw.PupMenu('Console Menu%t|Write Input Data (white)|Write Output Data (blue)|Write Error Data (red)|Write All Text|%l|Insert Blender text|%l|Font Size|%l|Quit') + + if choice == 1: + writeCmdData(cmdBuffer, 0) # type 0 user + elif choice == 2: + writeCmdData(cmdBuffer, 1) # type 1 user output + elif choice == 3: + writeCmdData(cmdBuffer, 2) # type 2 errors + elif choice == 4: + writeCmdData(cmdBuffer, 3) # All + elif choice == 6: + insertCmdData(cmdBuffer) # Insert text from Blender and run it. + elif choice == 8: + # Fontsize. + font_choice = Draw.PupMenu('Font Size%t|Large|Normal|Small|Tiny') + if font_choice != -1: + if font_choice == 1: + __FONT_SIZE__ = 3 + elif font_choice == 2: + __FONT_SIZE__ = 2 + elif font_choice == 3: + __FONT_SIZE__ = 1 + elif font_choice == 4: + __FONT_SIZE__ = 0 + Draw.Redraw() + + elif choice == 10: # Exit + Draw.Exit() + + + # Auto compleating, quite complex- use recutsice dir for the moment. + def actionAutoCompleate(): # Ctrl + Tab + if not cmdBuffer[-1].cmd[:cursor].split(): + return + + + RECURSIVE_DIR = recursive_dir() + + # get last name of user input + editVar = cmdBuffer[-1].cmd[:cursor] + # Split off spaces operators etc from the staryt of the command so we can use the startswith function. + for splitChar in __VARIABLE_DELIMETERS__: + editVar = editVar[:-1].split(splitChar)[-1] + editVar[-1] + + + # Now we should have the var by its self + if editVar: + possibilities = [] + + for __TMP_VAR_NAME__ in RECURSIVE_DIR: #.keys(): + #print '\t', __TMP_VAR_NAME__ + if __TMP_VAR_NAME__ == editVar: + # print 'ADITVAR IS A VAR' + pass + ''' + elif __TMP_VAR_NAME__.startswith( editVar ): + print __TMP_VAR_NAME__, 'aaa' + possibilities.append( __TMP_VAR_NAME__ ) + ''' + possibilities.append( __TMP_VAR_NAME__ ) + + if len(possibilities) == 1: + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], possibilities[0], cmdBuffer[-1].cmd[cursor:])) + + elif possibilities: # If its not just [] + # -1 with insert is the second last. + + # Text choice + #cmdBuffer.insert(-1, cmdLine('options: %s' % ' '.join(possibilities), 3, None)) + + menuList = [] # A lits of tuples- ABSOLUTE, RELATIVE + + for __TMP_VAR_NAME__ in possibilities: + for usage in RECURSIVE_DIR[__TMP_VAR_NAME__]: + # Account for non absolute (variables for eg.) + if usage: # not '' + absName = '%s.%s' % (usage, __TMP_VAR_NAME__) + + if __TMP_VAR_NAME__.startswith(editVar): + menuList.append( # Used for names and can be entered when pressing shift. + (absName, # Absolute name + __TMP_VAR_NAME__) # Relative name, non shift + ) + + #else: + # if absName.find(editVar) != -1: + # menuList.append((__TMP_VAR_NAME__, __TMP_VAR_NAME__)) # Used for names and can be entered when pressing shift. + + # No items to display? no menu + if not menuList: + return + + menuList.sort() + + choice = PupMenuLess( # Menu for the user to choose the autocompleate + 'Choices (Shift for local name, Ctrl for Docs)%t|' + # Title Text + '|'.join(['%s, %s' % m for m in menuList])) # Use Absolute names m[0] + + if choice != -1: + if Window.GetKeyQualifiers() & Window.Qual.CTRL: # Help + cmdBuffer[-1].cmd = ('help(%s%s) ' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0])) + elif Window.GetKeyQualifiers() & Window.Qual.SHIFT: # Put in the long name + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][1], cmdBuffer[-1].cmd[cursor:])) + else: # Only paste in the Short name + cmdBuffer[-1].cmd = ('%s%s%s' % (cmdBuffer[-1].cmd[:cursor - len(editVar)], menuList[choice-1][0], cmdBuffer[-1].cmd[cursor:])) + + + else: + # print 'NO EDITVAR' + return + + # ------------------end------------------ # + + # Quit from menu only + #if (evt == Draw.ESCKEY and not val): + # Draw.Exit() + if evt == Draw.MOUSEX or evt == Draw.MOUSEY: # AVOID TOO MANY REDRAWS. + return + + + global cursor + global histIndex + global __FONT_SIZE__ + global __CONSOLE_LINE_OFFSET__ + + ascii = Blender.event + + resetScroll = True + + #------------------------------------------------------------------------------# + # key codes and key handling # + #------------------------------------------------------------------------------# + + # UP DOWN ARROW KEYS, TO TRAVERSE HISTORY + if (evt == Draw.UPARROWKEY and val): actionUpKey() + elif (evt == Draw.DOWNARROWKEY and val): actionDownKey() + + elif (evt == Draw.RIGHTARROWKEY and val): + if Window.GetKeyQualifiers() & Window.Qual.SHIFT: + wordJump = False + newCursor = cursor+1 + while newCursor<0: + + if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__: + newCursor+=1 + else: + wordJump = True + break + if wordJump: # Did we find a new cursor pos? + cursor = newCursor + else: + cursor = -1 # end of line + else: + cursor +=1 + if cursor > -1: + cursor = -1 + + elif (evt == Draw.LEFTARROWKEY and val): + if Window.GetKeyQualifiers() & Window.Qual.SHIFT: + wordJump = False + newCursor = cursor-1 + while abs(newCursor) < len(cmdBuffer[-1].cmd): + + if cmdBuffer[-1].cmd[newCursor] not in __DELIMETERS__ or\ + newCursor == cursor: + newCursor-=1 + else: + wordJump = True + break + if wordJump: # Did we find a new cursor pos? + cursor = newCursor + else: + cursor = -len(cmdBuffer[-1].cmd) # Start of line + + else: + if len(cmdBuffer[-1].cmd) > abs(cursor): + cursor -=1 + + elif (evt == Draw.HOMEKEY and val): + cursor = -len(cmdBuffer[-1].cmd) + + elif (evt == Draw.ENDKEY and val): + cursor = -1 + + elif (evt == Draw.TABKEY and val): + insCh('\t') + + elif (evt == Draw.BACKSPACEKEY and val): + if Window.GetKeyQualifiers() & Window.Qual.SHIFT: + i = -1 + for d in __DELIMETERS__: + i = max(i, cmdBuffer[-1].cmd[:cursor-1].rfind(d)) + if i == -1: + i=0 + cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:i] , cmdBuffer[-1].cmd[cursor:])) + + else: + # Normal backspace. + cmdBuffer[-1].cmd = ('%s%s' % (cmdBuffer[-1].cmd[:cursor-1] , cmdBuffer[-1].cmd[cursor:])) + + elif (evt == Draw.DELKEY and val) and cursor < -1: + cmdBuffer[-1].cmd = cmdBuffer[-1].cmd[:cursor] + cmdBuffer[-1].cmd[cursor+1:] + cursor +=1 + + elif ((evt == Draw.RETKEY or evt == Draw.PADENTER) and val): + actionEnterKey() + + elif (evt == Draw.RIGHTMOUSE and not val): actionRightMouse(); return + + elif (evt == Draw.PADPLUSKEY or evt == Draw.EQUALKEY or evt == Draw.WHEELUPMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL: + __FONT_SIZE__ += 1 + __FONT_SIZE__ = min(len(__FONT_SIZES__)-1, __FONT_SIZE__) + elif (evt == Draw.PADMINUS or evt == Draw.MINUSKEY or evt == Draw.WHEELDOWNMOUSE) and val and Window.GetKeyQualifiers() & Window.Qual.CTRL: + __FONT_SIZE__ -=1 + __FONT_SIZE__ = max(0, __FONT_SIZE__) + + + elif evt == Draw.WHEELUPMOUSE and val: + __CONSOLE_LINE_OFFSET__ += 1 + __CONSOLE_LINE_OFFSET__ = min(len(cmdBuffer)-2, __CONSOLE_LINE_OFFSET__) + resetScroll = False + + elif evt == Draw.WHEELDOWNMOUSE and val: + __CONSOLE_LINE_OFFSET__ -= 1 + __CONSOLE_LINE_OFFSET__ = max(0, __CONSOLE_LINE_OFFSET__) + resetScroll = False + + + elif ascii: + insCh(chr(ascii)) + else: + return # dont redraw. + + # If the user types in anything then scroll to bottom. + if resetScroll: + __CONSOLE_LINE_OFFSET__ = 0 + Draw.Redraw() + + +def draw_gui(): + # Get the bounds from ObleGL directly + __CONSOLE_RECT__ = BGL.Buffer(BGL.GL_FLOAT, 4) + BGL.glGetFloatv(BGL.GL_SCISSOR_BOX, __CONSOLE_RECT__) + __CONSOLE_RECT__= __CONSOLE_RECT__.list + + # Clear the screen + BGL.glClearColor(0.0, 0.0, 0.0, 1.0) + BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) # use it to clear the color buffer + + + # Fixed margin. use a margin since 0 margin can be hard to seewhen close to a crt's edge. + margin = 4 + + # Draw cursor location colour + if __CONSOLE_LINE_OFFSET__ == 0: + cmd2curWidth = Draw.GetStringWidth(cmdBuffer[-1].cmd[:cursor], __FONT_SIZES__[__FONT_SIZE__][0]) + BGL.glColor3f(0.8, 0.2, 0.2) + if cmd2curWidth == 0: + BGL.glRecti(margin,2,margin+2, __FONT_SIZES__[__FONT_SIZE__][1]+2) + else: + BGL.glRecti(margin + cmd2curWidth-2,2, margin+cmd2curWidth, __FONT_SIZES__[__FONT_SIZE__][1]+2) + + BGL.glColor3f(1,1,1) + # Draw the set of cammands to the buffer + consoleLineIdx = __CONSOLE_LINE_OFFSET__ + 1 + wrapLineIndex = 0 + while consoleLineIdx < len(cmdBuffer) and __CONSOLE_RECT__[3] > (consoleLineIdx - __CONSOLE_LINE_OFFSET__) * __FONT_SIZES__[__FONT_SIZE__][1]: + if cmdBuffer[-consoleLineIdx].type == 0: + BGL.glColor3f(1, 1, 1) + elif cmdBuffer[-consoleLineIdx].type == 1: + BGL.glColor3f(.3, .3, 1) + elif cmdBuffer[-consoleLineIdx].type == 2: + BGL.glColor3f(1.0, 0, 0) + elif cmdBuffer[-consoleLineIdx].type == 3: + BGL.glColor3f(0, 0.8, 0) + else: + BGL.glColor3f(1, 1, 0) + + if consoleLineIdx == 1: # user input + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8) + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) + else: + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8) + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) + + # Wrapping is totally slow, can even hang blender - dont do it! + ''' + if consoleLineIdx == 1: # NEVER WRAP THE USER INPUT + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * (consoleLineIdx-__CONSOLE_LINE_OFFSET__)) - 8) + # BUG, LARGE TEXT DOSENT DISPLAY + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) + + + else: # WRAP? + # LINE WRAP + if Draw.GetStringWidth(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) > __CONSOLE_RECT__[2]: + wrapLineList = [] + copyCmd = [cmdBuffer[-consoleLineIdx].cmd, ''] + while copyCmd != ['','']: + while margin + Draw.GetStringWidth(copyCmd[0], __FONT_SIZES__[__FONT_SIZE__][0]) > __CONSOLE_RECT__[2]: + #print copyCmd + copyCmd[1] = '%s%s'% (copyCmd[0][-1], copyCmd[1]) # Add the char on the end + copyCmd[0] = copyCmd[0][:-1]# remove last chat + + # Now we have copyCmd[0] at a good length we can print it. + if copyCmd[0] != '': + wrapLineList.append(copyCmd[0]) + + copyCmd[0]='' + copyCmd = [copyCmd[1], copyCmd[0]] + + # Now we have a list of lines, draw them (OpenGLs reverse ordering requires this odd change) + wrapLineList.reverse() + for wline in wrapLineList: + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1]*((consoleLineIdx-__CONSOLE_LINE_OFFSET__) + wrapLineIndex)) - 8) + Draw.Text(wline, __FONT_SIZES__[__FONT_SIZE__][0]) + wrapLineIndex += 1 + wrapLineIndex-=1 # otherwise we get a silly extra line. + + else: # no wrapping. + + BGL.glRasterPos2i(margin, (__FONT_SIZES__[__FONT_SIZE__][1] * ((consoleLineIdx-__CONSOLE_LINE_OFFSET__)+wrapLineIndex)) - 8) + Draw.Text(cmdBuffer[-consoleLineIdx].cmd, __FONT_SIZES__[__FONT_SIZE__][0]) + ''' + consoleLineIdx += 1 + + +# This recieves the event index, call a function from here depending on the event. +def handle_button_event(evt): + pass + + +# Run the console +__CONSOLE_VAR_DICT__ = {} # Initialize var dict + + +# Print Startup lines, add __bpydoc__ to the console startup. +cmdBuffer = [] +for l in __bpydoc__.split('
'): + cmdBuffer.append( cmdLine(l, 1, None) ) + + +histIndex = cursor = -1 # How far back from the first letter are we? - in current CMD line, history if for moving up and down lines. + +# Autoexec, startup code. +scriptDir = Get('scriptsdir') +console_autoexec = None +if scriptDir: + if not scriptDir.endswith(Blender.sys.sep): + scriptDir += Blender.sys.sep + + console_autoexec = '%s%s' % (scriptDir, 'console_autoexec.py') + + if not sys.exists(console_autoexec): + # touch the file + try: + open(console_autoexec, 'w').close() + cmdBuffer.append(cmdLine('...console_autoexec.py not found, making new in scripts dir', 1, None)) + except: + cmdBuffer.append(cmdLine('...console_autoexec.py could not write, this is ok', 1, None)) + scriptDir = None # make sure we only use this for console_autoexec.py + + if not sys.exists(console_autoexec): + console_autoexec = None + + else: + cmdBuffer.append(cmdLine('...Using existing console_autoexec.py in scripts dir', 1, None)) + + + +#-Autoexec---------------------------------------------------------------------# +# Just use the function to jump into local naming mode. +# This is so we can loop through all of the autoexec functions / vars and add them to the __CONSOLE_VAR_DICT__ +def include_console(includeFile): + global __CONSOLE_VAR_DICT__ # write autoexec vars to this. + + # Execute an external py file as if local + exec(include(includeFile)) + +def standard_imports(): + # Write local to global __CONSOLE_VAR_DICT__ for reuse, + for ls in (dir(), dir(Blender)): + for __TMP_VAR_NAME__ in ls: + # Execute the local > global coversion. + exec('%s%s' % ('__CONSOLE_VAR_DICT__[__TMP_VAR_NAME__]=', __TMP_VAR_NAME__)) + + exec('%s%s' % ('__CONSOLE_VAR_DICT__["bpy"]=', 'bpy')) + +if scriptDir and console_autoexec: + include_console(console_autoexec) # pass the blender module + +standard_imports() # import Blender and bpy + +#-end autoexec-----------------------------------------------------------------# + + +# Append new line to write to +cmdBuffer.append(cmdLine(' ', 0, 0)) + +#------------------------------------------------------------------------------# +# register the event handling code, GUI # +#------------------------------------------------------------------------------# +def main(): + Draw.Register(draw_gui, handle_event, handle_button_event) + +if __name__ == '__main__': + main() diff --git a/release/scripts/discombobulator.py b/release/scripts/discombobulator.py new file mode 100644 index 00000000000..6dbb4e5382b --- /dev/null +++ b/release/scripts/discombobulator.py @@ -0,0 +1,1526 @@ +#!BPY + +""" +Name: 'Discombobulator' +Blender: 237 +Group: 'Mesh' +Tip: 'Adds random geometry to a mesh' +""" + +__author__ = "Evan J. Rosky (syrux)" +__url__ = ("Script's homepage, http://evan.nerdsofparadise.com/programs/discombobulator/index.html") +__version__ = "237" +__bpydoc__ = """\ +Discombobulator adds random geometry to a mesh. + +As an example, this script can easily give a "high-tech" +look to walls and spaceships. + +Definitions:
+ - Protrusions: extrusions of each original face on the mesh. +You may have from 1 to 4 protrusions on each face.
+ - Taper: The tips of each protrusion will be a percentage +smaller than the base.
+ - Doodads: small extruded blocks/shapes that are randomly placed +about the top of a protrusion or face. + + +Usage:
+ Input your settings, make sure the mesh you would like to modify +is selected (active) and then click on "Discombobulate".
+ See the scripts tutorial page (on the homepage) for more info. + + +New Features:
+ - Will use existing materials if there are any.
+ - Clicking "Assign materials by part" will allow assigning +of different material indices to Protrusion or Doodad Sides +and Tops in the gui element below it.
+ - Setting a material index to 0 will use whatever material +is assigned to the face that is discombobulated. + - You can now scroll using the arrow keys. + + +Notes:
+ - Modifications can be restricted to selected faces +by setting "Only selected faces" for protrusions and/or +doodads.
+ - It's possible to restrict mesh generation to add only +protrusions or only doodads instead of both.
+ - You may also choose to have Discombobulator select the +tops of created protrusions by clicking the corresponding +number of protrusion buttons under "Select Tops". You may +also do the same for doodads by choosing "Select Doodads" and +"Only Select Tops". You may choose to select the whole doodads +by leaving "Only Select Tops" off.
+ - By selecting "Deselect Selected" you can have +discombobulator deselect everything but the selections it +makes.
+ - The "Face %" option will set the percentage of faces that +will be modified either for the doodads or the protrusions.
+ - "Copy Before Modifying" will create a new object with the +modifications where leaving it off will overwrite the original +mesh.
+ +You can find more information at the Link above. +""" + + +# $Id$ +# +# Updated 2006-09-26 +# Changes since last version: +# > Works with Blender CVS and hopefully with Blender 2.40. +# > Swaps min/max values when min>max rather than complaining. +# > Will keep previously assigned materials. +# > Now allows user to assign custom material indices to +# Protrusion and Doodad Sides and Tops. +# > The initial Gui Layout will change depending on the aspect +# ratio of the window it is in. +# > Using the arrow keys will scroll the gui. +# +# -------------------------------------------------------------------------- +# Discombobulator v2.1b +# by Evan J. Rosky, 2005 +# This plugin is protected by the GPL: Gnu Public Licence +# GPL - http://www.gnu.org/copyleft/gpl.html +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2005: Evan J. Rosky +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +#Hit Alt-P to run + +import Blender +from Blender import NMesh,Object,Material,Window,Types,Scene +from Blender.NMesh import Vert,Face +from Blender.Mathutils import * + +import defaultdoodads +import BPyMathutils +from BPyMathutils import genrand +a = BPyMathutils.sgenrand(int(round(Rand(1000,99999),0))) + +#Create random numbers +def randnum(low,high): + num = genrand() + num = num*(high-low) + num = num+low + return num + +#Object Vars +newmesh = NMesh.GetRaw() +materialArray = [0] + +#Material Vars +reassignMats = 0 +protSideMat = 1 +protTopMat = 2 +doodSideMat = 3 +doodTopMat = 4 +thereAreMats = 0 +currmat = 0 + +#Global Vars +makenewobj = 1 +errortext = "Remember to select an object." +editmode = 0 + +#Protrusion Vars +makeprots = 1 +faceschangedpercent = 1.0 +minimumheight = 0.2 +maximumheight = 0.4 +subface1 = 1 +subface2 = 1 +subface3 = 1 +subface4 = 1 +subfaceArray = [1,2,3,4] +minsubfaces = 1 +minimumtaperpercent = 0.15 +maximumtaperpercent = 0.35 +useselectedfaces = 0 +selectface1 = 1 +selectface2 = 1 +selectface3 = 1 +selectface4 = 1 +deselface = 1 + +#Doodad Vars +makedoodads = 1 +doodadfacepercent = 1.0 +selectdoodad = 0 +onlyonprotrusions = 0 +doodonselectedfaces = 0 +selectdoodadtoponly = 0 +doodad1 = 1 +doodad2 = 1 +doodad3 = 1 +doodad4 = 1 +doodad5 = 1 +doodad6 = 1 +doodadminperface = 2 +doodadmaxperface = 6 +doodadminsize = 0.15 +doodadmaxsize = 0.45 +doodadminheight = 0.0 +doodadmaxheight = 0.1 +doodadArray = [1,2,3,4,5,6] + +def makeSubfaceArray(): + global subfaceArray + global subface1 + global subface2 + global subface3 + global subface4 + + subfaceArray = [] + if subface1 > 0: + subfaceArray.append(1) + if subface2 > 0: + subfaceArray.append(2) + if subface3 > 0: + subfaceArray.append(3) + if subface4 > 0: + subfaceArray.append(4) + +def makeDoodadArray(): + global doodadArray + global doodad1 + global doodad2 + global doodad3 + global doodad4 + global doodad5 + global doodad6 + + doodadArray = [] + if doodad1 > 0: + doodadArray.append(1) + if doodad2 > 0: + doodadArray.append(2) + if doodad3 > 0: + doodadArray.append(3) + if doodad4 > 0: + doodadArray.append(4) + if doodad5 > 0: + doodadArray.append(5) + if doodad6 > 0: + doodadArray.append(6) + +def extrude(mid,nor,protrusion,v1,v2,v3,v4,tosel=1,flipnor=0): + taper = 1 - randnum(minimumtaperpercent,maximumtaperpercent) + newmesh_verts = newmesh.verts + newmesh_faces = newmesh.faces + + vert = newmesh_verts[v1] + point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) + ver = Vert(point[0],point[1],point[2]) + ver.sel = tosel + newmesh_verts.append(ver) + vert = newmesh_verts[v2] + point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) + ver = Vert(point[0],point[1],point[2]) + ver.sel = tosel + newmesh_verts.append(ver) + vert = newmesh_verts[v3] + point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) + ver = Vert(point[0],point[1],point[2]) + ver.sel = tosel + newmesh_verts.append(ver) + vert = newmesh_verts[v4] + point = (vert.co - mid)*taper + mid + protrusion*Vector(nor) + ver = Vert(point[0],point[1],point[2]) + ver.sel = tosel + newmesh_verts.append(ver) + + faceindex = len(newmesh_verts) - 4 + + #side face 1 + face = Face([newmesh_verts[v1], newmesh_verts[v2], newmesh_verts[faceindex+1], newmesh_verts[faceindex]]) + if flipnor != 0: + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh_faces.append(face) + + #side face 2 + face = Face([newmesh_verts[v2], newmesh_verts[v3], newmesh_verts[faceindex+2], newmesh_verts[faceindex+1]]) + if flipnor != 0: + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh_faces.append(face) + + #side face 3 + face = Face([newmesh_verts[v3], newmesh_verts[v4], newmesh_verts[faceindex+3], newmesh_verts[faceindex+2]]) + if flipnor != 0: + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh_faces.append(face) + + #side face 4 + face = Face([newmesh_verts[v4], newmesh_verts[v1], newmesh_verts[faceindex], newmesh_verts[faceindex+3]]) + if flipnor != 0: + face.v.reverse() + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh_faces.append(face) + + #top face + face = Face(newmesh_verts[-4:]) + if flipnor != 0: + face.v.reverse() + if tosel == 1: + face.sel = 1 + if thereAreMats == 1: + if reassignMats == 0 or protTopMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protTopMat-1 + newmesh_faces.append(face) + return face + +#Sets the global protrusion values +def setProtrusionValues(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15): + + #Protrusions + global makeprots + global minimumtaperpercent + global maximumtaperpercent + global faceschangedpercent + global minimumheight + global maximumheight + global subface1 + global subface2 + global subface3 + global subface4 + global useselectedfaces + global selectface1 + global selectface2 + global selectface3 + global selectface4 + global deselface + global subfaceArray + + #Protrusions + makeprots = p0 + faceschangedpercent = p1 + minimumheight = p2 + maximumheight = p3 + subface1 = p4 + subface2 = p5 + subface3 = p6 + subface4 = p7 + minimumtaperpercent = p8 + maximumtaperpercent = p9 + useselectedfaces = p10 + selectface1 = p11 + selectface2 = p12 + selectface3 = p13 + selectface4 = p14 + deselface = p15 + makeSubfaceArray() + if len(subfaceArray) == 0: + makeprots = 0 + + if minimumheight > maximumheight: + a = maximumheight + maximimheight = minimumheight + minimumheight = a + elif minimumtaperpercent > maximumtaperpercent: + a = maximumtaperpercent + maximimtaperpercent = minimumtaperpercent + minimumtaperpercent = a + +#Sets the global Doodad values +def setDoodadValues(d0,d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17): + + #Doodads + global makedoodads + global doodadfacepercent + global selectdoodad + global onlyonprotrusions + global doodad1 + global doodad2 + global doodad3 + global doodad4 + global doodad5 + global doodad6 + global doodadminperface + global doodadmaxperface + global doodadminsize + global doodadmaxsize + global doodadminheight + global doodadmaxheight + global doodadArray + global doodonselectedfaces + global selectdoodadtoponly + + #Doodads + makedoodads = d0 + doodadfacepercent = d1 + selectdoodad = d2 + onlyonprotrusions = d3 + doodad1 = d4 + doodad2 = d5 + doodad3 = d6 + doodad4 = d7 + doodad5 = d8 + doodad6 = d9 + doodadminperface = d10 + doodadmaxperface = d11 + doodadminsize = d12 + doodadmaxsize = d13 + doodadminheight = d14 + doodadmaxheight = d15 + doodonselectedfaces = d16 + selectdoodadtoponly = d17 + makeDoodadArray() + if len(doodadArray) == 0: + makedoodads = 0 + + elif doodadminperface > doodadmaxperface: + a = doodadmaxperface + doodadmaxperface = doodadminperface + doodadminperface = a + elif doodadminsize > doodadmaxsize: + a = doodadmaxsize + doodadmaxsize = doodadminsize + doodadminsize = a + elif doodadminheight > doodadmaxheight: + a = doodadmaxheight + doodadmaxheight = doodadminheight + doodadminheight = a + +#Sets other global values +def setOtherValues(g0,m0,m1,m2,m3,m4): + + #Global + global reassignMats + global makenewobj + global protSideMat + global protTopMat + global doodSideMat + global doodTopMat + + #Get Misc Variables + makenewobj = g0 + reassignMats = m0 + protSideMat = m1 + protTopMat = m2 + doodSideMat = m3 + doodTopMat = m4 + +def discombobulate(): + + #Global + global origmesh + global newmesh + global makenewobj + global origobj + global newobj + global messagetext + global errortext + global editmode + + #Protrusions + global makeprots + global minimumtaperpercent + global maximumtaperpercent + global faceschangedpercent + global minimumheight + global maximumheight + global subface1 + global subface2 + global subface3 + global subface4 + global useselectedfaces + global selectface1 + global selectface2 + global selectface3 + global selectface4 + global deselface + global subfaceArray + + #Doodads + global makedoodads + global doodadfacepercent + global selectdoodad + global onlyonprotrusions + global doodad1 + global doodad2 + global doodad3 + global doodad4 + global doodad5 + global doodad6 + global doodadminperface + global doodadmaxperface + global doodadminsize + global doodadmaxsize + global doodadminheight + global doodadmaxheight + global doodadArray + global doodonselectedfaces + global selectdoodadtoponly + + #Global + global materialArray + global reassignMats + global protSideMat + global protTopMat + global doodSideMat + global doodTopMat + global thereAreMats + global currmat + + origobj = Scene.GetCurrent().objects.active + if not origobj: + glRasterPos2d(10,50) + errortext = "YOU MUST SELECT AN OBJECT!" + messagetext = ErrorText(errortext) + Blender.Redraw() + return + + #Leave Editmode + editmode = Window.EditMode() + if editmode: Window.EditMode(0) + + #Get Major Variables + + origmesh = origobj.getData() + + if origobj.type != 'Mesh': + glRasterPos2d(10,50) + errortext = "OBJECT MUST BE MESH!" + messagetext = ErrorText(errortext) + Blender.Redraw() + return + + newmesh = NMesh.GetRaw() + materialArray = origmesh.getMaterials() + if len(materialArray) < 1: + thereAreMats = 0 + else: + thereAreMats = 1 + + #add material indices if necessary (only up to 4) + if thereAreMats == 1 and reassignMats == 1: + if len(materialArray) < 4: + if protSideMat > 4: protSideMat = 4 + if protTopMat > 4: protTopMat = 4 + if doodSideMat > 4: doodSideMat = 4 + if doodTopMat > 4: doodTopMat = 4 + else: + if protSideMat > len(materialArray): protSideMat = len(materialArray) + if protTopMat > len(materialArray): protTopMat = len(materialArray) + if doodSideMat > len(materialArray): doodSideMat = len(materialArray) + if doodTopMat > len(materialArray): doodTopMat = len(materialArray) + + #This only does something if there are less than 4 verts + for matind in [protSideMat,protTopMat,doodSideMat,doodTopMat]: + if matind > len(materialArray) and matind <= 4: + for i in xrange(len(materialArray),matind+1): + materialArray.append(Material.New("AddedMat " + str(i))) + + #Sets the materials + newmesh.setMaterials(materialArray) + + #Set the doodad settings + defaultdoodads.settings(selectdoodadtoponly,materialArray,reassignMats,thereAreMats,doodSideMat,doodTopMat) + #defaultdoodads.settings(selectdoodadtoponly,materialArray,reassignMats,thereAreMats,currmat) + + newmesh.verts.extend(origmesh.verts) + + #Start modifying faces + for currface in origmesh.faces: + + currmat = currface.materialIndex + defaultdoodads.setCurrMat(currmat) + + #Check if it is a triangle + if len(currface.v)<4: + face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index]]) + if thereAreMats == 1: + face.materialIndex = currmat + newmesh.faces.append(face) + continue + + #Check whether or not to make protrusions + if makeprots == 0: + face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) + if thereAreMats == 1: + face.materialIndex = currmat + newmesh.faces.append(face) + if makedoodads == 1 and onlyonprotrusions == 0: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + continue + + #Check if only changing selected faces + if useselectedfaces == 1: + #check if currface is selected + if currface.sel: + a = 1 + else: + face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) + if thereAreMats == 1: + face.materialIndex = currmat + newmesh.faces.append(face) + if makedoodads == 1 and onlyonprotrusions == 0: + if doodonselectedfaces != 1: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + continue + #Check if face should be modified by random chance + if randnum(0,1)>faceschangedpercent: + face = Face([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) + if thereAreMats == 1: + face.materialIndex = currmat + newmesh.faces.append(face) + if makedoodads == 1 and onlyonprotrusions == 0: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray,face, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + continue + + center = Vector([0,0,0]) + for pt in currface.v: + center = center + pt.co + center = center / len(currface.v) + + #Determine amount of subfaces + subfaces = round(randnum(1,len(subfaceArray)),0) + subfaces = subfaceArray[(int(subfaces) - 1)] + + ######################## START DEALING WITH PROTRUSIONS ##################### + + if subfaces == 1: + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,currface.v[0].index,currface.v[1].index,currface.v[2].index,currface.v[3].index,selectface1) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + elif subfaces == 2: + orientation = int(round(randnum(0,1))) + p1 = currface.v[orientation] + p2 = currface.v[orientation + 1] + p3 = ((p2.co - p1.co)/2) + p1.co + ve1 = Vert(p3[0],p3[1],p3[2]) + ve1.sel = 0 + p1 = currface.v[2 + orientation] + if orientation < 0.5: + p2 = currface.v[3] + else: + p2 = currface.v[0] + p3 = ((p2.co - p1.co)/2) + p1.co + ve2 = Vert(p3[0],p3[1],p3[2]) + ve2.sel = 0 + if orientation < 0.5: + verti = currface.v[3] + p3 = verti.index + v1 = p3 + verti = currface.v[0] + p0 = verti.index + v2 = p0 + else: + verti = currface.v[0] + p0 = verti.index + v1 = p0 + verti = currface.v[1] + p1 = verti.index + v2 = p1 + newmesh.verts.append(ve1) + newmesh.verts.append(ve2) + index = len(newmesh.verts) - 2 + v4 = index + 1 + v3 = index + center = Vector([0, 0, 0]) + for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,v1,v2,v3,v4,selectface2) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + if orientation < 0.5: + verti = currface.v[1] + p1 = verti.index + v1 = p1 + verti = currface.v[2] + p2 = verti.index + v2 = p2 + else: + verti = currface.v[2] + p2 = verti.index + v1 = p2 + verti = currface.v[3] + p3 = verti.index + v2 = p3 + center = Vector([0]*3) + for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,v1,v2,v4,v3,selectface2) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + if orientation < 0.5: + face = Face([newmesh.verts[p0],newmesh.verts[p1],newmesh.verts[v3]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p2],newmesh.verts[p3],newmesh.verts[v4]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + else: + face = Face([newmesh.verts[p1],newmesh.verts[p2],newmesh.verts[v3]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p3],newmesh.verts[p0],newmesh.verts[v4]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + + elif subfaces == 3: + layer2inds = [] + layer2verts = [] + orientation = int(round(randnum(0,1))) + rotation = int(round(randnum(0,1))) + p1 = currface.v[orientation] + p2 = currface.v[orientation + 1] + p3 = ((p2.co - p1.co)/2) + p1.co + ve1 = Vert(p3[0],p3[1],p3[2]) + ve1.sel = 0 + p1 = currface.v[2 + orientation] + if orientation < 0.5: + p2 = currface.v[3] + else: + p2 = currface.v[0] + p3 = ((p2.co - p1.co)/2) + p1.co + ve2 = Vert(p3[0],p3[1],p3[2]) + ve2.sel = 0 + fp = [] + + #make first protrusion + if rotation < 0.5: + if orientation < 0.5: + verti = currface.v[3] + fp.append(verti.index) + v1 = verti.index + verti = currface.v[0] + fp.append(verti.index) + v2 = verti.index + layer2verts.extend([newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[2].index]]) + else: + verti = currface.v[0] + fp.append(verti.index) + v1 = verti.index + verti = currface.v[1] + fp.append(verti.index) + v2 = verti.index + layer2verts.extend([newmesh.verts[currface.v[2].index],newmesh.verts[currface.v[3].index]]) + newmesh.verts.append(ve1) + newmesh.verts.append(ve2) + index = len(newmesh.verts) - 2 + v4 = index + 1 + v3 = index + center = Vector([0]*3) + for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + layer2inds.extend([v3,v4]) + tempface = extrude(center,currface.no,prot,v1,v2,v3,v4,selectface3) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + #Still first protrusion + else: + if orientation < 0.5: + verti = currface.v[1] + fp.append(verti.index) + v1 = verti.index + verti = currface.v[2] + fp.append(verti.index) + v2 = verti.index + layer2verts.extend([newmesh.verts[currface.v[0].index],newmesh.verts[currface.v[3].index]]) + else: + verti = currface.v[2] + fp.append(verti.index) + v1 = verti.index + verti = currface.v[3] + fp.append(verti.index) + v2 = verti.index + layer2verts.extend([newmesh.verts[currface.v[1].index],newmesh.verts[currface.v[0].index]]) + newmesh.verts.append(ve2) + newmesh.verts.append(ve1) + index = len(newmesh.verts) - 2 + v4 = index + v3 = index + 1 + center = Vector([0]*3) + for pt in [newmesh.verts[v1],newmesh.verts[v2],newmesh.verts[v3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + layer2inds.extend([index, index +1]) + tempface = extrude(center,currface.no,prot,v1,v2,v4,v3,selectface3) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + #split next rect(pre-arranged, no orientation crud)--make flag in extruder for only one existing vert in mesh + p1 = newmesh.verts[layer2inds[0]] + p2 = newmesh.verts[layer2inds[1]] + p3 = ((p2.co - p1.co)/2) + p1.co + ve3 = Vert(p3[0],p3[1],p3[2]) + ve3.sel = 0 + p1 = layer2verts[0] + p2 = layer2verts[1] + p3 = ((p2.co - p1.co)/2) + p1.co + ve4 = Vert(p3[0],p3[1],p3[2]) + ve4.sel = 0 + newmesh.verts.append(ve3) + newmesh.verts.append(ve4) + tempindex = len(newmesh.verts) - 2 + v5 = tempindex + v6 = tempindex + 1 + verti = layer2verts[0] + t0 = verti.index + center = Vector([0]*3) + for pt in [newmesh.verts[v5],newmesh.verts[v6],newmesh.verts[t0],newmesh.verts[v3]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + if rotation < 0.5: flino = 1 + else: flino = 0 + tempface = extrude(center,currface.no,prot,v3,v5,v6,t0,selectface3,flino) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + if rotation < 0.5: + fpt = t0 + face = Face([newmesh.verts[fp[1]],newmesh.verts[fpt],newmesh.verts[v3]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + else: + fpt = t0 + face = Face([newmesh.verts[fp[0]],newmesh.verts[v3],newmesh.verts[fpt]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + verti = layer2verts[1] + tempindex = verti.index + center = Vector([0]*3) + for pt in [newmesh.verts[v5],newmesh.verts[v6],newmesh.verts[tempindex],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,v6,v5,v4,tempindex,selectface3,flino) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + if rotation < 0.5: + face = Face([newmesh.verts[tempindex],newmesh.verts[fp[0]],newmesh.verts[v4]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[fpt],newmesh.verts[tempindex],newmesh.verts[v6]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + else: + face = Face([newmesh.verts[tempindex],newmesh.verts[v4],newmesh.verts[fp[1]]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[tempindex],newmesh.verts[fpt],newmesh.verts[v6]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + + else: + #get all points + verti = currface.v[0] + p0 = verti.index + + verti = currface.v[1] + p1 = verti.index + + pt = ((newmesh.verts[p1].co - newmesh.verts[p0].co)/2) + newmesh.verts[p0].co + v1 = Vert(pt[0],pt[1],pt[2]) + v1.sel = 0 + + verti = currface.v[2] + p2 = verti.index + + pt = ((newmesh.verts[p2].co - newmesh.verts[p1].co)/2) + newmesh.verts[p1].co + v2 = Vert(pt[0],pt[1],pt[2]) + v2.sel = 0 + + verti = currface.v[3] + p3 = verti.index + + pt = ((newmesh.verts[p3].co - newmesh.verts[p2].co)/2) + newmesh.verts[p2].co + v3 = Vert(pt[0],pt[1],pt[2]) + v3.sel = 0 + + pt = ((newmesh.verts[p0].co - newmesh.verts[p3].co)/2) + newmesh.verts[p3].co + v4 = Vert(pt[0],pt[1],pt[2]) + v4.sel = 0 + + pt = ((v3.co - v1.co)/2) + v1.co + m = Vert(pt[0],pt[1],pt[2]) + m.sel = 0 + + #extrusion 1 + newmesh.verts.extend([v1,m,v4]) + index = len(newmesh.verts) - 3 + v1 = index + m = index + 1 + v4 = index + 2 + center = Vector([0]*3) + for pt in [newmesh.verts[p0],newmesh.verts[v1],newmesh.verts[m],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,p0,v1,m,v4,selectface4) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + #extrusion 2 + newmesh.verts.extend([v2]) + index = len(newmesh.verts) - 1 + v2 = index + center = Vector([0]*3) + for pt in [newmesh.verts[m],newmesh.verts[v1],newmesh.verts[p1],newmesh.verts[v2]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,m,v1,p1,v2,selectface4) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + #extrusion 3 + newmesh.verts.extend([v3]) + index = len(newmesh.verts) - 1 + v3 = index + center = Vector([0]*3) + for pt in [newmesh.verts[m],newmesh.verts[v2],newmesh.verts[p2],newmesh.verts[v3]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,m,v2,p2,v3,selectface4) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + #extrusion 4 + center = Vector([0]*3) + for pt in [newmesh.verts[m],newmesh.verts[v3],newmesh.verts[p3],newmesh.verts[v4]]: + center += pt.co + center = center/4 + prot = randnum(minimumheight,maximumheight) + tempface = extrude(center,currface.no,prot,v4,m,v3,p3,selectface4) + if makedoodads == 1: + if doodonselectedfaces == 1: + if currface.sel: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + else: + tempmesh = NMesh.GetRaw() + tempmesh = defaultdoodads.createDoodad(doodadArray, tempface, doodadminsize, doodadmaxsize, doodadminheight,doodadmaxheight, selectdoodad, doodadminperface, doodadmaxperface, doodadfacepercent) + newmesh.verts.extend(tempmesh.verts) + newmesh.faces.extend(tempmesh.faces) + + face = Face([newmesh.verts[p0],newmesh.verts[p1],newmesh.verts[v1]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p1],newmesh.verts[p2],newmesh.verts[v2]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p2],newmesh.verts[p3],newmesh.verts[v3]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + face = Face([newmesh.verts[p3],newmesh.verts[p0],newmesh.verts[v4]]) + if thereAreMats == 1: + if reassignMats == 0 or protSideMat == 0: + face.materialIndex = currmat + else: + face.materialIndex = protSideMat-1 + newmesh.faces.append(face) + + #NMesh.PutRaw(newmesh) + if deselface == 1: + for unvert in origmesh.verts: + newmesh.verts[unvert.index].sel = 0 + if makenewobj == 1: + newobj = origobj.__copy__() + newobj.link(newmesh) + scene = Blender.Scene.GetCurrent() + scene.objects.link(newobj) + origobj.sel = 0 + else: + origobj.link(newmesh) + + #Return to Editmode if previously in it + if editmode: Window.EditMode(1) + +####################### gui ###################### +from Blender.BGL import * +from Blender.Draw import * + +def ErrorText(errortext): + Window.WaitCursor(0) + Text(errortext) + PupMenu("ERROR: %s" % errortext.lower()) + +#Global Buttons +makenewobject = Create(makenewobj) +messagetext = Create(errortext) + +#Protrusion Buttons +doprots = Create(makeprots) +facechange = Create(faceschangedpercent*100) +minheight = Create(minimumheight) +maxheight = Create(maximumheight) +sub1 = Create(subface1) +sub2 = Create(subface2) +sub3 = Create(subface3) +sub4 = Create(subface4) +mintaper = Create(minimumtaperpercent*100) +maxtaper = Create(maximumtaperpercent*100) +useselected = Create(useselectedfaces) +selface1 = Create(selectface1) +selface2 = Create(selectface2) +selface3 = Create(selectface3) +selface4 = Create(selectface4) +deselectvertices = Create(deselface) +#selectbyverts = Create(vertselected) + +#Doodad Buttons +dodoodads = Create(makedoodads) +doodadfacechange = Create(doodadfacepercent*100) +seldoodad = Create(selectdoodad) +onprot = Create(onlyonprotrusions) +dood1 = Create(doodad1) +dood2 = Create(doodad2) +dood3 = Create(doodad3) +dood4 = Create(doodad4) +dood5 = Create(doodad5) +dood6 = Create(doodad6) +doodadminamount = Create(doodadminperface) +doodadmaxamount = Create(doodadmaxperface) +doodsizemin = Create(doodadminsize*100) +doodsizemax = Create(doodadmaxsize*100) +doodheightmin = Create(doodadminheight) +doodheightmax = Create(doodadmaxheight) +doodonselface = Create(doodonselectedfaces) +seldoodtop = Create(selectdoodadtoponly) + +#Material Buttons +assignNewMats = Create(reassignMats) +replProtSideIndex = Create(protSideMat) +replProtTopIndex = Create(protTopMat) +replDoodSideIndex = Create(doodSideMat) +replDoodTopIndex = Create(doodTopMat) + +# Events +EVENT_NONE = 1 +EVENT_DISCOMBOBULATE = 2 +EVENT_EXIT = 3 + +# Additions for moving gui +hadd = 0 +wadd = 0 +thadd = 410 +phadd = 245 +pwadd = 0 +dhadd = 55 +dwadd = 0 +ghadd = 10 +gwadd = 0 +mhadd = 55 +mwadd = 312 + +def colorbox(x,y,xright,bottom): + glColor3f(0.75, 0.75, 0.75) + glRecti(x + 1, y + 1, xright - 1, bottom - 1) + +firstDraw = 1 + +def draw(): + + #Protrusions + global doprots + global facechange + global minheight + global maxheight + global sub1 + global sub2 + global sub3 + global sub4 + global mintaper + global maxtaper + global useselected + global selface1 + global selface2 + global selface3 + global selface4 + global deselectvertices + #global selectbyverts + + #Doodads + global dodoodads + global doodadfacechange + global seldoodad + global onprot + global dood1 + global dood2 + global dood3 + global dood4 + global dood5 + global dood6 + global doodadminamount + global doodadmaxamount + global doodsizemin + global doodsizemax + global doodheightmin + global doodheightmax + global doodonselface + global seldoodtop + + #Materials + global assignNewMats + global replProtSideIndex + global replProtTopIndex + global replDoodSideIndex + global replDoodTopIndex + + #Global Settings + global makenewobject + global messagetext + global errortext + global EVENT_NONE,EVENT_DRAW,EVENT_EXIT,EVENT_UP,EVENT_DOWN,EVENT_LEFT,EVENT_RIGHT + + # Additions for moving gui + global hadd + global wadd + global thadd + global phadd + global pwadd + global dhadd + global dwadd + global ghadd + global gwadd + global mhadd + global mwadd + + #This is for creating the initial layout + global firstDraw + if(firstDraw == 1): + if(((Window.GetAreaSize()[1])*1.7) < Window.GetAreaSize()[0]): + thadd = 180 + phadd = 10 + dhadd = 10 + mhadd = 55 + ghadd = 10 + pwadd = 0 + dwadd = 305 + mwadd = 610 + gwadd = 610 + else: + thadd = 505 + phadd = 346 + dhadd = 160 + mhadd = 56 + ghadd = 10 + pwadd = 0 + dwadd = 0 + mwadd = 0 + gwadd = 0 + firstDraw = 0 + + + #Title :420high + glClearColor(0.6, 0.6, 0.6, 1.0) + glClear(GL_COLOR_BUFFER_BIT) + glColor3f(0.0,0.0,0.0) + glRasterPos2d(8+wadd, thadd+hadd) + Text("Discombobulator v2.1b") + + #Protrusion + colorbox(8+pwadd+wadd,150+phadd+hadd,312+pwadd+wadd,phadd-5+hadd) + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+pwadd+wadd, 140+phadd+hadd) + Text("Protrusions:") + doprots = Toggle("Make Protrusions",EVENT_NONE,12+pwadd+wadd,117+phadd+hadd,145,18,doprots.val,"Make Protrusions?") + facechange = Number("Face %: ",EVENT_NONE,162+pwadd+wadd,117+phadd+hadd,145,18,facechange.val,0,100,"Percentage of faces that will grow protrusions") + useselected = Toggle("Only selected faces",EVENT_NONE,12+pwadd+wadd,97+phadd+hadd,145,18,useselected.val,"If on, only selected faces will be modified") + deselectvertices = Toggle("Deselect Selected",EVENT_NONE,162+pwadd+wadd,97+phadd+hadd,145,18,deselectvertices.val,"Deselects any selected vertex except for ones selected by \"Select Tops\"") + + #Protrusion properties + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+pwadd+wadd, 80+phadd+hadd) + Text("Protrusion Properties:") + BeginAlign() + minheight = Number("Min Height: ",EVENT_NONE,12+pwadd+wadd,57+phadd+hadd,145,18,minheight.val,-100.0,100.0,"Minimum height of any protrusion") + maxheight = Number("Max Height: ",EVENT_NONE,162+pwadd+wadd,57+phadd+hadd,145,18,maxheight.val,-100.0,100.0,"Maximum height of any protrusion") + EndAlign() + BeginAlign() + mintaper = Number("Min Taper %: ",EVENT_NONE,12+pwadd+wadd,37+phadd+hadd,145,18,mintaper.val,0,100,"Minimum taper percentage of protrusion") + maxtaper = Number("Max Taper %: ",EVENT_NONE,162+pwadd+wadd,37+phadd+hadd,145,18,maxtaper.val,0,100,"Maximum taper percentage of protrusion") + EndAlign() + glRasterPos2d(19+pwadd+wadd, 22+phadd+hadd) + Text("Number of protrusions:") + BeginAlign() + sub1 = Toggle("1",EVENT_NONE,12+pwadd+wadd,phadd+hadd,34,18,sub1.val,"One Protrusion") + sub2 = Toggle("2",EVENT_NONE,48+pwadd+wadd,phadd+hadd,34,18,sub2.val,"Two Protrusions") + sub3 = Toggle("3",EVENT_NONE,84+pwadd+wadd,phadd+hadd,34,18,sub3.val,"Three Protrusions") + sub4 = Toggle("4",EVENT_NONE,120+pwadd+wadd,phadd+hadd,34,18,sub4.val,"Four Protrusions") + EndAlign() + glRasterPos2d(195+pwadd+wadd, 22+phadd+hadd) + Text("Select tops of:") + BeginAlign() + selface1 = Toggle("1",EVENT_NONE,165+pwadd+wadd,phadd+hadd,34,18,selface1.val,"Select the tip of the protrusion when it is created") + selface2 = Toggle("2",EVENT_NONE,201+pwadd+wadd,phadd+hadd,34,18,selface2.val,"Select the tips of each protrusion when they are created") + selface3 = Toggle("3",EVENT_NONE,237+pwadd+wadd,phadd+hadd,34,18,selface3.val,"Select the tips of each protrusion when they are created") + selface4 = Toggle("4",EVENT_NONE,273+pwadd+wadd,phadd+hadd,34,18,selface4.val,"Select the tips of each protrusion when they are created") + EndAlign() + #Doodads + colorbox(8+dwadd+wadd,175+dhadd+hadd,312+dwadd+wadd,dhadd-5+hadd) + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+dwadd+wadd, 165+dhadd+hadd) + Text("Doodads:") + BeginAlign() + dood1 = Toggle("1 Box",EVENT_NONE,12+dwadd+wadd,142+dhadd+hadd,45,18,dood1.val,"Creates a rectangular box") + dood2 = Toggle("2 Box",EVENT_NONE,61+dwadd+wadd,142+dhadd+hadd,45,18,dood2.val,"Creates 2 side-by-side rectangular boxes") + dood3 = Toggle("3 Box",EVENT_NONE,110+dwadd+wadd,142+dhadd+hadd,45,18,dood3.val,"Creates 3 side-by-side rectangular boxes") + EndAlign() + BeginAlign() + dood4 = Toggle("\"L\"",EVENT_NONE,164+dwadd+wadd,142+dhadd+hadd,45,18,dood4.val,"Creates a Tetris-style \"L\" shape") + dood5 = Toggle("\"T\"",EVENT_NONE,213+dwadd+wadd,142+dhadd+hadd,45,18,dood5.val,"Creates a Tetris-style \"T\" shape") + dood6 = Toggle("\"S\"",EVENT_NONE,262+dwadd+wadd,142+dhadd+hadd,45,18,dood6.val,"Creates a sort-of \"S\" or \"Z\" shape") + EndAlign() + dodoodads = Toggle("Make Doodads",EVENT_NONE,12+dwadd+wadd,120+dhadd+hadd,145,18,dodoodads.val,"Make Doodads?") + doodadfacechange = Number("Face %: ",EVENT_NONE,162+dwadd+wadd,120+dhadd+hadd,145,18,doodadfacechange.val,0,100,"Percentage of faces that will gain doodads") + seldoodad = Toggle("Select Doodads",EVENT_NONE,12+dwadd+wadd,100+dhadd+hadd,145,18,seldoodad.val,"Selects doodads when they are created") + seldoodtop = Toggle("Only Select Tops",EVENT_NONE,162+dwadd+wadd,100+dhadd+hadd,145,18,seldoodtop.val,"Only Selects tops of doodads when\"Select Doodads\" is on") + doodonselface = Toggle("Only selected faces",EVENT_NONE,12+dwadd+wadd,80+dhadd+hadd,145,18,doodonselface.val,"Only create doodads on selected faces") + onprot = Toggle("Only on Protrusions",EVENT_NONE,162+dwadd+wadd,80+dhadd+hadd,145,18,onprot.val,"Only place doodads on protrusions") + + #Doodad Properties + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+dwadd+wadd, 63+dhadd+hadd) + Text("Doodad Properties:") + BeginAlign() + doodadminamount = Number("Min Amount: ",EVENT_NONE,12+dwadd+wadd,40+dhadd+hadd,145,18,doodadminamount.val,0,100,"Minimum number of doodads per face") + doodadmaxamount = Number("Max Amount: ",EVENT_NONE,162+dwadd+wadd,40+dhadd+hadd,145,18,doodadmaxamount.val,0,100,"Maximum number of doodads per face") + EndAlign() + BeginAlign() + doodheightmin = Number("Min Height: ",EVENT_NONE,12+dwadd+wadd,20+dhadd+hadd,145,18,doodheightmin.val,0.0,100.0,"Minimum height of any doodad") + doodheightmax = Number("Max Height: ",EVENT_NONE,162+dwadd+wadd,20+dhadd+hadd,145,18,doodheightmax.val,0.0,100.0,"Maximum height of any doodad") + EndAlign() + BeginAlign() + doodsizemin = Number("Min Size %: ",EVENT_NONE,12+dwadd+wadd,dhadd+hadd,145,18,doodsizemin.val,0.0,100.0,"Minimum size of any doodad in percentage of face") + doodsizemax = Number("Max Size %: ",EVENT_NONE,162+dwadd+wadd,dhadd+hadd,145,18,doodsizemax.val,0.0,100.0,"Maximum size of any doodad in percentage of face") + EndAlign() + + #Materials + colorbox(8+mwadd+wadd,93+mhadd+hadd,312+mwadd+wadd,mhadd-5+hadd) + glColor3f(0.0,0.0,0.0) + glRasterPos2d(12+mwadd+wadd, 83+mhadd+hadd) + Text("Materials:") + glRasterPos2d(12+mwadd+wadd, 43+mhadd+hadd) + Text("Assigned Material Indices:") + assignNewMats = Toggle("Assign materials by part",EVENT_NONE,32+mwadd+wadd,60+mhadd+hadd,256,18,assignNewMats.val,"Otherwise, previous materials will be preserved") + replProtSideIndex = Number("Protrusion Sides:",EVENT_NONE,12+mwadd+wadd,20+mhadd+hadd,145,18,replProtSideIndex.val,0,16,"Material index assigned to sides of protrusions") + replProtTopIndex = Number("Protrusion Tops:",EVENT_NONE,162+mwadd+wadd,20+mhadd+hadd,145,18,replProtTopIndex.val,0,16,"Material index assigned to tops of protrusions") + replDoodSideIndex = Number("Doodad Sides:",EVENT_NONE,12+mwadd+wadd,mhadd+hadd,145,18,replDoodSideIndex.val,0,16,"Material index assigned to sides of doodads") + replDoodTopIndex = Number("Doodad Tops:",EVENT_NONE,162+mwadd+wadd,mhadd+hadd,145,18,replDoodTopIndex.val,0,16,"Material index assigned to tops and bottoms of doodads") + + #Global Parts + colorbox(8+gwadd+wadd,35+ghadd+hadd,312+gwadd+wadd,ghadd-5+hadd) + glColor3f(1.0,0.0,0.0) + glRasterPos2d(12+gwadd+wadd,25+ghadd+hadd) + messagetext = Text(errortext) + glColor3f(0.0,0.0,0.0) + makenewobject = Toggle("Copy Before Modifying",EVENT_NONE,162+gwadd+wadd,ghadd+hadd,145,18,makenewobject.val,"If selected, the original object will be copied before it is changed") + Button("Discombobulate",EVENT_DISCOMBOBULATE,12+gwadd+wadd,ghadd+hadd,100,18) + Button("Exit",EVENT_EXIT,120+gwadd+wadd,ghadd+hadd,30,18) + +def event(evt, val): + global wadd + global hadd + + if (evt == RIGHTARROWKEY and val): + wadd = wadd + 20 + Redraw(1) + if (evt == LEFTARROWKEY and val): + wadd = wadd - 20 + Redraw(1) + if (evt == UPARROWKEY and val): + hadd = hadd + 20 + Redraw(1) + if (evt == DOWNARROWKEY and val): + hadd = hadd - 20 + Redraw(1) + if (evt == QKEY and not val): + Exit() + +def bevent(evt): + + #Protrusions + global doprots + global facechange + global minheight + global maxheight + global sub1 + global sub2 + global sub3 + global sub4 + global mintaper + global maxtaper + global useselected + global selface1 + global selface2 + global selface3 + global selface4 + global deselectvertices + #global selectbyverts + + #Doodads + global dodoodads + global doodadfacechange + global seldoodad + global onprot + global dood1 + global dood2 + global dood3 + global dood4 + global dood5 + global dood6 + global doodadminamount + global doodadmaxamount + global doodsizemin + global doodsizemax + global doodheightmin + global doodheightmax + global doodonselface + global seldoodtop + + #Materials + global assignNewMats + global replProtSideIndex + global replProtTopIndex + global replDoodSideIndex + global replDoodTopIndex + + #Global Settings + global makenewobject + global messagetext + global errortext + global EVENT_NONE,EVENT_DRAW,EVENT_EXIT + + ######### Manages GUI events + if evt==EVENT_EXIT: + Exit() + elif evt==EVENT_DISCOMBOBULATE: + Window.WaitCursor(1) + setProtrusionValues(doprots.val,facechange.val/100,minheight.val,maxheight.val,sub1.val,sub2.val,sub3.val,sub4.val,mintaper.val/100,maxtaper.val/100,useselected.val,selface1.val,selface2.val,selface3.val,selface4.val,deselectvertices.val) + setDoodadValues(dodoodads.val,doodadfacechange.val/100,seldoodad.val,onprot.val,dood1.val,dood2.val,dood3.val,dood4.val,dood5.val,dood6.val,doodadminamount.val,doodadmaxamount.val,doodsizemin.val/100,doodsizemax.val/100,doodheightmin.val,doodheightmax.val,doodonselface.val,seldoodtop.val) + setOtherValues(makenewobject.val,assignNewMats.val,replProtSideIndex.val,replProtTopIndex.val,replDoodSideIndex.val,replDoodTopIndex.val) + discombobulate() + Window.WaitCursor(0) + Blender.Redraw() + +Register(draw, event, bevent) diff --git a/release/scripts/envelope_symmetry.py b/release/scripts/envelope_symmetry.py new file mode 100644 index 00000000000..935dae9aabe --- /dev/null +++ b/release/scripts/envelope_symmetry.py @@ -0,0 +1,174 @@ +#!BPY + +""" +Name: 'Envelope Symmetry' +Blender: 234 +Group: 'Animation' +Tooltip: 'Make envelope symetrical' +""" + +__author__ = "Jonas Petersen" +__url__ = ("blender", "elysiun", "Script's homepage, http://www.mindfloaters.de/blender/", "thread at blender.org, http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=4858 ") +__version__ = "0.9 2004-11-10" +__doc__ = """\ +This script creates perfectly symmetrical envelope sets. It is part of the +envelop assignment tools. + +"Envelopes" are Mesh objects with names following this naming convention: + +: + +Please check the script's homepage and the thread at blender.org (last link button above) for more info. + +For this version users need to edit the script code to change default options. +""" + +# -------------------------------------------------------------------------- +# "Envelope Symmetry" by Jonas Petersen +# Version 0.9 - 10th November 2004 - first public release +# -------------------------------------------------------------------------- +# +# A script for creating perfectly symmetrical envelope sets. It is +# part of the envelope assignment tool. +# +# It is available in Object Mode via the menu item: +# +# Object -> Scripts -> Envelope Symmetry +# +# With default settings it will: +# +# - Look for bones +# +# Find the latest version at: http://www.mindfloaters.de/blender/ +# +# -------------------------------------------------------------------------- +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Jonas Petersen, jonas at mindfloaters dot de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +# -------------------------------------------------------------------------- +# CONFIGURATION +# -------------------------------------------------------------------------- + +# Note: Theses values will later be editable via a gui interface +# within Blender. + +# The suffix for the reference and opposite envelope. +# The configuration of of the opposite envelope will be overwritten by +# the configuration of the reference envelope (shape, position, bone, weight). +# The default is REF_SUFFIX = '.L' and OPP_SUFFIX = '.R'. +REF_SUFFIX = '.R' +OPP_SUFFIX = '.L' + +# MIRROR_AXIS defines the axis in which bones are mirrored/aligned. +# Values: +# 0 for X (default) +# 1 for Y +# 2 for Z +MIRROR_AXIS = 0 + +# SEPARATOR is the character used to delimit the bone name and the weight +# in the envelope name. +SEPARATOR = ":" + +# -------------------------------------------------------------------------- +# END OF CONFIGURATION +# -------------------------------------------------------------------------- + +import Blender, math, sys +from Blender import Mathutils +from BPyNMesh import * + +def flipFace(v): + if len(v) == 3: v[0], v[1], v[2] = v[2], v[1], v[0] + elif len(v) == 4: v[0], v[1], v[2], v[3] = v[3], v[2], v[1], v[0] + +# return object with given object name (with variable parts) and mesh name +def getObjectByName(obj_name, mesh_name): + for obj in Blender.Scene.GetCurrent().objects: + if obj.type == "Mesh": +# if obj.getName()[0:len(obj_name)] == obj_name and obj.getData().name == mesh_name: + # use only mesh_name so bone name and weight (in the envelope name) + # can be changed by the user and mirrored by the script. + if obj.getData(name_only=1) == mesh_name: + return obj + return False + +SUFFIX_LEN = len(REF_SUFFIX); + +Blender.Window.EditMode(0) + +count = 0 +for obj in Blender.Scene.GetCurrent().objects: + if obj.type != 'Mesh': + continue + + count += 1 + name = obj.name + pos = name.find(SEPARATOR) + if (pos > -1): + ApplySizeAndRotation(obj) + + base_name = name[0:pos-SUFFIX_LEN] + suffix = name[pos-SUFFIX_LEN:pos] + weight = name[pos:len(name)] # the SEPARATOR following a float value + + if suffix == REF_SUFFIX: + mesh = obj.getData() + mirror_name = base_name + OPP_SUFFIX + weight + mirror_mesh_name = mesh.name + ".mirror" + + mirror_obj = getObjectByName(base_name + OPP_SUFFIX, mirror_mesh_name) + + if mirror_obj: + + # update vertices + + mirror_mesh = mirror_obj.getData() + for i in xrange(len(mesh.verts)): + org = mesh.verts[i] + mir = mirror_mesh.verts[i] + mir.co[0], mir.co[1], mir.co[2] = org.co[0], org.co[1], org.co[2] + mir.co[MIRROR_AXIS] *= -1 + + mirror_mesh.update() + else: + + # create mirror object + + mirror_mesh = obj.data + for face in mirror_mesh.faces: + flipFace(face.v) + for vert in mirror_mesh.verts: + vert.co[MIRROR_AXIS] *= -1 + + mirror_obj = Blender.NMesh.PutRaw(mirror_mesh, mirror_mesh_name) + + # update name, drawType and location + + mirror_obj.setName(mirror_name) + mirror_obj.drawType = obj.drawType + + loc = [obj.LocX, obj.LocY, obj.LocZ] + loc[MIRROR_AXIS] *= -1 + mirror_obj.setLocation(loc) + +Blender.Window.EditMode(0) diff --git a/release/scripts/export-iv-0.1.py b/release/scripts/export-iv-0.1.py new file mode 100644 index 00000000000..647dd9c5518 --- /dev/null +++ b/release/scripts/export-iv-0.1.py @@ -0,0 +1,304 @@ +#!BPY + +""" +Name: 'OpenInventor (.iv)...' +Blender: 236 +Group: 'Export' +Tip: 'Export to OpenInventor file format. (.iv)' +""" +__author__ = ("Radek Barton") +__url__ = ["http://blackhex.no-ip.org/"] +__email__ = ["scripts"] +__version__ = "0.1" + + +__bpydoc__ = """\ +This script exports to the Open Inventor format. + +Usage: + +Run this script from "File->Export" menu. + +Note: +""" +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Radek Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# + +import Blender +math_pi= 3.1415926535897931 + +def WriteHeader(file): + file.write("#Inventor V2.1 ascii\n\n") + file.write("Separator\n") + file.write("{\n") + file.write(" ShapeHints\n") + file.write(" {\n") + file.write(" vertexOrdering COUNTERCLOCKWISE\n") + file.write(" }\n") + +def WriteFooter(file): + file.write("}\n") + +def WriteMesh(file, ob): + file.write(" Separator\n") + file.write(" {\n") + file.write(" # %s\n" % ob.name) + WriteMatrix(file, ob) + mesh = ob.getData() + WriteMaterials(file, mesh) + WriteTexture(file, mesh) + WriteNormals(file, mesh) + WriteVertices(file, mesh) + WriteFaces(file, mesh) + file.write(" }\n") + +def WriteMatrix(file, ob): + matrix = ob.getMatrix() + file.write(" MatrixTransform\n") + file.write(" {\n") + file.write(" matrix\n") + for line in matrix: + file.write(" %.6f %.6f %.6f %.6f\n" % (line[0], line[1], line[2], line[3])) + file.write(" }\n") + +def WriteColors(file, mesh): + file.write(" vertexProperty VertexProperty\n") + file.write(" {\n") + file.write(" orderedRGBA\n") + file.write(" [\n") + for face in mesh.faces: + for I in xrange(len(face)): + file.write(" 0x%02x%02x%02x%02x,\n" % (face.col[I].r, + face.col[I].g, face.col[I].b, face.col[I].a)) + file.write(" ]\n") + file.write(" materialBinding PER_VERTEX\n") + file.write(" }\n") + +def WriteMaterials(file, mesh): + if mesh.materials: + file.write(" Material\n") + file.write(" {\n") + file.write(" ambientColor\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f %.6f %.6f,\n" % (mat.mirCol[0], mat.mirCol[1], + mat.mirCol[2])) + file.write(" ]\n") + file.write(" diffuseColor\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f %.6f %.6f,\n" % (mat.rgbCol[0], mat.rgbCol[1], + mat.rgbCol[2])) + file.write(" ]\n") + file.write(" specularColor\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f %.6f %.6f,\n" % (mat.specCol[0] * mat.spec / 2.0, + mat.specCol[1] * mat.spec / 2.0, mat.specCol[2] * mat.spec / 2.0)) + file.write(" ]\n") + file.write(" emissiveColor\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f %.6f %.6f,\n" % (mat.rgbCol[0] * mat.emit, + mat.rgbCol[1] * mat.emit, mat.rgbCol[0] * mat.emit)) + file.write(" ]\n") + file.write(" shininess\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f,\n" % (mat.hard / 255.0)) + file.write(" ]\n") + file.write(" transparency\n") + file.write(" [\n") + for mat in mesh.materials: + file.write(" %.6f,\n" % (1.0 - mat.alpha)) + file.write(" ]\n") + file.write(" }\n") + file.write(" MaterialBinding\n") + file.write(" {\n") + file.write(" value PER_FACE_INDEXED\n") + file.write(" }\n") + +def WriteTexture(file, mesh): + texture = mesh.faces[0].image # BAD Ju Ju + if texture: + file.write(" Texture2\n") + file.write(" {\n") + file.write(' filename "%s"\n' % texture.getName()) + file.write(" }\n") + file.write(" TextureCoordinate2\n") + file.write(" {\n") + file.write(" point\n") + file.write(" [\n") + if mesh.hasVertexUV(): + for vert in mesh.verts: + file.write(" %s %s,\n" % (vert.uvco[0], vert.uvco[1])) + file.write(" ]\n") + file.write(" }\n") + file.write(" TextureCoordinateBinding\n") + file.write(" {\n") + file.write(" value PER_VERTEX_INDEXED\n") + file.write(" }\n") + elif mesh.hasFaceUV(): + for face in mesh.faces: + for uv in face.uv: + file.write(" %.6f %.6f,\n" % (uv[0], uv[1])) + file.write(" ]\n") + file.write(" }\n") + file.write(" TextureCoordinateBinding\n") + file.write(" {\n") + file.write(" value PER_VERTEX\n") + file.write(" }\n") + +def WriteVertices(file, mesh): + file.write(" Coordinate3\n") + file.write(" {\n") + file.write(" point\n") + file.write(" [\n") + for vert in mesh.verts: + file.write(" %.6f %.6f %.6f,\n" % (vert[0], vert[1], vert[2])) + file.write(" ]\n") + file.write(" }\n") + +def WriteNormals(file, mesh): + file.write(" Normal\n") + file.write(" {\n") + file.write(" vector\n") + file.write(" [\n") + + # make copy of vertex normals + normals = [] + for face in mesh.faces: + if len(face.v) in [3, 4]: + if face.smooth: + for v in face.v: + normals.append(v.no) + else: + for v in face.v: + normals.append(face.no) + + # write normals + for no in normals: + file.write(" %.6f %.6f %.6f,\n" % (no[0], no[1], no[2])) + file.write(" ]\n") + file.write(" }\n") + + # write way how normals are binded + file.write(" NormalBinding\n") + file.write(" {\n") + file.write(" value PER_VERTEX\n") + file.write(" }\n") + +def WriteFaces(file, mesh): + file.write(" IndexedFaceSet\n") + file.write(" {\n") + + # write vertex paint + if mesh.hasVertexColours(): + WriteColors(file, mesh) + + # write material indexes + file.write(" materialIndex\n") + file.write(" [\n") + for face in mesh.faces: + file.write(" %i,\n" % face.mat); + file.write(" ]\n") + + # write faces with coordinate indexes + file.write(" coordIndex\n") + file.write(" [\n") + for face in mesh.faces: + face_v= face.v + if len(face_v) == 3: + file.write(" %i, %i, %i, -1,\n" % (face_v[0].index, + face_v[1].index, face_v[2].index)) + elif len(face_v) == 4: + file.write(" %i, %i, %i, %i, -1,\n" % (face_v[0].index, + face_v[1].index, face_v[2].index, face_v[3].index)) + file.write(" ]\n") + file.write(" }\n") + + +def WriteCamera(file, ob): + camera = ob.getData(); + # perspective camera + if camera.type == 0: + file.write(" PerspectiveCamera\n") + file.write(" {\n") + file.write(" nearDistance %s\n" % (camera.clipStart)) + file.write(" farDistance %s\n" % (camera.clipEnd)) + file.write(" }\n") + # ortho camera + else: + print camera.type + +def WriteLamp(file, ob): + lamp = ob.getData(); + # spot lamp + if lamp.type == 2: + file.write(" SpotLight\n") + file.write(" {\n") + file.write(" intensity %s\n" % (lamp.energy / 10.0)) + file.write(" color %s %s %s\n" % (lamp.col[0], lamp.col[1], lamp.col[2])) + #file.write(" location %s\n" % ()) + #file.write(" direction %s\n" % ()) + file.write(" dropOffRate %s\n" % (lamp.spotBlend)) + file.write(" cutOffAngle %s\n" % (lamp.spotSize * math_pi / 180.0)) + file.write(" }\n") + +# script main function +def ExportToIv(file_name): + scene = Blender.Scene.GetCurrent() + file = open(file_name, "w") + + # make lists of individual ob types + meshes = [] + lamps = [] + cameras = [] + for ob in scene.objects: + obtype= ob.type + if obtype == "Mesh": + meshes.append(ob); + #elif obtype == "Lamp": + # lamps.append(ob); + #elif obtype == "Camera": + # cameras.append(ob); + #else: + # print "Exporting %s objects isn't supported!" % ob.type + + # write header, footer and groups of ob types + WriteHeader(file); + #for camera in cameras: + # WriteCamera(file, camera); + #for lamp in lamps: + # WriteLamp(file, lamp) + for mesh in meshes: + WriteMesh(file, mesh) + WriteFooter(file) + + file.close() + +def FileSelectorCB(file_name): + if not file_name.lower().endswith('.iv'): + file_name += '.iv' + ExportToIv(file_name) + +if __name__ == '__main__': + Blender.Window.FileSelector(FileSelectorCB, "Export IV", Blender.sys.makename(ext='.iv')) diff --git a/release/scripts/export_cal3d.py b/release/scripts/export_cal3d.py new file mode 100644 index 00000000000..990ac480e3d --- /dev/null +++ b/release/scripts/export_cal3d.py @@ -0,0 +1,1112 @@ +#!BPY +""" +Name: 'Cal3D (.cfg .xaf .xsf .xmf .xrf)...' +Blender: 243 +Group: 'Export' +Tip: 'Export armature/bone/mesh/action data to the Cal3D format.' +""" + +# export_cal3d.py +# Copyright (C) 2003-2004 Jean-Baptiste LAMY -- jibalamy@free.fr +# Copyright (C) 2004 Matthias Braun -- matze@braunis.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +__version__ = '0.9f' +__author__ = 'Jean-Baptiste, Jiba, Lamy, Campbell Barton (Ideasman42)' +__email__ = ['Authors email, jibalamy:free*fr'] +__url__ = ['Soya3ds homepage, http://home.gna.org/oomadness/en/soya/', 'Cal3d, http://cal3d.sourceforge.net'] +__bpydoc__ =\ +'''This script is a Blender => Cal3D converter. +(See http://blender.org and http://cal3d.sourceforge.net) + +USAGE: + +To install it, place the script in your $HOME/.blender/scripts directory. + +Then open the File->Export->Cal3d v0.9 menu. And select the filename of the .cfg file. +The exporter will create a set of other files with same prefix (ie. bla.cfg, bla.xsf, +bla_Action1.xaf, bla_Action2.xaf, ...). + +You should be able to open the .cfg file in cal3d_miniviewer. + + +NOT (YET) SUPPORTED: + + - Rotation, translation, or stretching Blender objects is still quite +buggy, so AVOID MOVING / ROTATING / RESIZE OBJECTS (either mesh or armature) ! +Instead, edit the object (with tab), select all points / bones (with "a"), +and move / rotate / resize them.
+ - no support for exporting springs yet
+ - no support for exporting material colors (most games should only use images +I think...) + + +KNOWN ISSUES: + + - Cal3D versions <=0.9.1 have a bug where animations aren't played when the root bone +is not animated;
+ - Cal3D versions <=0.9.1 have a bug where objects that aren't influenced by any bones +are not drawn (fixed in Cal3D CVS). + + +NOTES: + +It requires a very recent version of Blender (>= 2.44). + +Build a model following a few rules:
+ - Use only a single armature;
+ - Use only a single rootbone (Cal3D doesn't support floating bones);
+ - Use only locrot keys (Cal3D doesn't support bone's size change);
+ - Don't try to create child/parent constructs in blender object, that gets exported +incorrectly at the moment;
+ - Objects or animations whose names start by "_" are not exported (hidden object). + +You can pass as many parameters as you want at the end, "EXPORT_FOR_SOYA=1" is just an +example. The parameters are the same as below. +''' + +# True (=1) to export for the Soya 3D engine +# (http://oomadness.tuxfamily.org/en/soya). +# (=> rotate meshes and skeletons so as X is right, Y is top and -Z is front) +# EXPORT_FOR_SOYA = 0 + +# Enables LODs computation. LODs computation is quite slow, and the algo is +# surely not optimal :-( +LODS = 0 + +# Scale the model (not supported by Soya). + +# See also BASE_MATRIX below, if you want to rotate/scale/translate the model at +# the exportation. + +######################################################################################### +# Code starts here. +# The script should be quite re-useable for writing another Blender animation exporter. +# Most of the hell of it is to deal with Blender's head-tail-roll bone's definition. + +import math +import Blender +import BPyMesh +import BPySys +import BPyArmature +import BPyObject +import bpy + +def best_armature_root(armature): + ''' + Find the armature root bone with the most children, return that bone + ''' + + bones = [bone for bone in armature.bones.values() if bone.hasChildren() == True] + if len(bones) == 1: + return bones[0] + + # Get the best root since we have more then 1 + bones = [(len(bone.getAllChildren()), bone) for bone in bones] + bones.sort() + return bones[-1][1] # bone with most children + + +Vector = Blender.Mathutils.Vector +Quaternion = Blender.Mathutils.Quaternion +Matrix = Blender.Mathutils.Matrix + +# HACK -- it seems that some Blender versions don't define sys.argv, +# which may crash Python if a warning occurs. +# if not hasattr(sys, 'argv'): sys.argv = ['???'] + +def matrix_multiply(b, a): + return [ [ + a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0], + a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1], + a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2], + 0.0, + ], [ + a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0], + a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1], + a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2], + 0.0, + ], [ + a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0], + a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1], + a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2], + 0.0, + ], [ + a[3][0] * b[0][0] + a[3][1] * b[1][0] + a[3][2] * b[2][0] + b[3][0], + a[3][0] * b[0][1] + a[3][1] * b[1][1] + a[3][2] * b[2][1] + b[3][1], + a[3][0] * b[0][2] + a[3][1] * b[1][2] + a[3][2] * b[2][2] + b[3][2], + 1.0, + ] ] + +# multiplies 2 quaternions in x,y,z,w notation +def quaternion_multiply(q1, q2): + return Quaternion(\ + q2[3] * q1[0] + q2[0] * q1[3] + q2[1] * q1[2] - q2[2] * q1[1], + q2[3] * q1[1] + q2[1] * q1[3] + q2[2] * q1[0] - q2[0] * q1[2], + q2[3] * q1[2] + q2[2] * q1[3] + q2[0] * q1[1] - q2[1] * q1[0], + q2[3] * q1[3] - q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2],\ + ) + +def matrix_translate(m, v): + m[3][0] += v[0] + m[3][1] += v[1] + m[3][2] += v[2] + return m + +def matrix2quaternion(m): + s = math.sqrt(abs(m[0][0] + m[1][1] + m[2][2] + m[3][3])) + if s == 0.0: + x = abs(m[2][1] - m[1][2]) + y = abs(m[0][2] - m[2][0]) + z = abs(m[1][0] - m[0][1]) + if (x >= y) and (x >= z): return Quaternion(1.0, 0.0, 0.0, 0.0) + elif (y >= x) and (y >= z): return Quaternion(0.0, 1.0, 0.0, 0.0) + else: return Quaternion(0.0, 0.0, 1.0, 0.0) + + q = Quaternion([ + -(m[2][1] - m[1][2]) / (2.0 * s), + -(m[0][2] - m[2][0]) / (2.0 * s), + -(m[1][0] - m[0][1]) / (2.0 * s), + 0.5 * s, + ]) + q.normalize() + #print q + return q + +def vector_by_matrix_3x3(p, m): + return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0], + p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1], + p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2]] + +def vector_add(v1, v2): + return [v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]] + +def vector_sub(v1, v2): + return [v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]] + +def quaternion2matrix(q): + xx = q[0] * q[0] + yy = q[1] * q[1] + zz = q[2] * q[2] + xy = q[0] * q[1] + xz = q[0] * q[2] + yz = q[1] * q[2] + wx = q[3] * q[0] + wy = q[3] * q[1] + wz = q[3] * q[2] + return Matrix([1.0 - 2.0 * (yy + zz), 2.0 * (xy + wz), 2.0 * (xz - wy), 0.0], + [ 2.0 * (xy - wz), 1.0 - 2.0 * (xx + zz), 2.0 * (yz + wx), 0.0], + [ 2.0 * (xz + wy), 2.0 * (yz - wx), 1.0 - 2.0 * (xx + yy), 0.0], + [0.0 , 0.0 , 0.0 , 1.0]) + +def matrix_invert(m): + det = (m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) + - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])) + if det == 0.0: return None + det = 1.0 / det + r = [ [ + det * (m[1][1] * m[2][2] - m[2][1] * m[1][2]), + - det * (m[0][1] * m[2][2] - m[2][1] * m[0][2]), + det * (m[0][1] * m[1][2] - m[1][1] * m[0][2]), + 0.0, + ], [ + - det * (m[1][0] * m[2][2] - m[2][0] * m[1][2]), + det * (m[0][0] * m[2][2] - m[2][0] * m[0][2]), + - det * (m[0][0] * m[1][2] - m[1][0] * m[0][2]), + 0.0 + ], [ + det * (m[1][0] * m[2][1] - m[2][0] * m[1][1]), + - det * (m[0][0] * m[2][1] - m[2][0] * m[0][1]), + det * (m[0][0] * m[1][1] - m[1][0] * m[0][1]), + 0.0, + ] ] + r.append([ + -(m[3][0] * r[0][0] + m[3][1] * r[1][0] + m[3][2] * r[2][0]), + -(m[3][0] * r[0][1] + m[3][1] * r[1][1] + m[3][2] * r[2][1]), + -(m[3][0] * r[0][2] + m[3][1] * r[1][2] + m[3][2] * r[2][2]), + 1.0, + ]) + return r + + +def point_by_matrix(p, m): + return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0] + m[3][0], + p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1] + m[3][1], + p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]] + +# Hack for having the model rotated right. +# Put in BASE_MATRIX your own rotation if you need some. + +BASE_MATRIX = None + + +# Cal3D data structures + +CAL3D_VERSION = 910 +MATERIALS = {} # keys are (mat.name, img.name) + +class Cal3DMaterial(object): + __slots__ = 'amb', 'diff', 'spec', 'shininess', 'maps_filenames', 'id' + def __init__(self, blend_world, blend_material, blend_images): + + # Material Settings + if blend_world: amb = [ int(c*255) for c in blend_world.amb ] + else: amb = [0,0,0] # Default value + + if blend_material: + self.amb = tuple([int(c*blend_material.amb) for c in amb] + [255]) + self.diff = tuple([int(c*255) for c in blend_material.rgbCol] + [int(blend_material.alpha*255)]) + self.spec = tuple([int(c*255) for c in blend_material.rgbCol] + [int(blend_material.alpha*255)]) + self.shininess = (float(blend_material.hard)-1)/5.10 + else: + self.amb = tuple(amb + [255]) + self.diff = (255,255,255,255) + self.spec = (255,255,255,255) + self.shininess = 1.0 + + self.maps_filenames = [] + for image in blend_images: + if image: + self.maps_filenames.append( image.filename.split('\\')[-1].split('/')[-1] ) + + self.id = len(MATERIALS) + MATERIALS[blend_material, blend_images] = self + + # new xml format + def writeCal3D(self, file): + file.write('\n') + file.write('

\n' % CAL3D_VERSION) + file.write('\n' % len(self.maps_filenames)) + file.write('\t%i %i %i %i\n' % self.amb) + file.write('\t%i %i %i %i\n' % self.diff) + file.write('\t%i %i %i %i\n' % self.spec) + file.write('\t%.6f\n' % self.shininess) + + for map_filename in self.maps_filenames: + file.write('\t%s\n' % map_filename) + + file.write('\n') + + +class Cal3DMesh(object): + __slots__ = 'name', 'submeshes', 'matrix', 'matrix_normal' + def __init__(self, ob, blend_mesh, blend_world): + self.name = ob.name + self.submeshes = [] + + BPyMesh.meshCalcNormals(blend_mesh) + + self.matrix = ob.matrixWorld + self.matrix_normal = self.matrix.copy().rotationPart() + + #if BASE_MATRIX: + # matrix = matrix_multiply(BASE_MATRIX, matrix) + + face_groups = {} + blend_materials = blend_mesh.materials + uvlayers = () + mat = None # incase we have no materials + if blend_mesh.faceUV: + uvlayers = blend_mesh.getUVLayerNames() + if len(uvlayers) == 1: + for f in blend_mesh.faces: + image = (f.image,) # bit in a tuple so we can match multi UV code + if blend_materials: mat = blend_materials[f.mat] # if no materials, mat will always be None + face_groups.setdefault( (mat,image), (mat,image,[]) )[2].append( f ) + else: + # Multi UV's + face_multi_images = [[] for i in xrange(len(blend_mesh.faces))] + face_multi_uvs = [[[] for i in xrange(len(f)) ] for f in blend_mesh.faces] + for uvlayer in uvlayers: + blend_mesh.activeUVLayer = uvlayer + for i, f in enumerate(blend_mesh.faces): + face_multi_images[i].append(f.image) + if f.image: + for j, uv in enumerate(f.uv): + face_multi_uvs[i][j].append( tuple(uv) ) + + # Convert UV's to tuples so they can be compared with eachother + # when creating new verts + for fuv in face_multi_uvs: + for i, uv in enumerate(fuv): + fuv[i] = tuple(uv) + + for i, f in enumerate(blend_mesh.faces): + image = tuple(face_multi_images[i]) + if blend_materials: mat = blend_materials[f.mat] + face_groups.setdefault( (mat,image), (mat,image,[]) )[2].append( f ) + else: + # No UV's + for f in blend_mesh.faces: + if blend_materials: mat = blend_materials[f.mat] + face_groups.setdefault( (mat,()), (mat,(),[]) )[2].append( f ) + + for blend_material, blend_images, faces in face_groups.itervalues(): + + try: material = MATERIALS[blend_material, blend_images] + except: material = MATERIALS[blend_material, blend_images] = Cal3DMaterial(blend_world, blend_material, blend_images) + + submesh = Cal3DSubMesh(self, material, len(self.submeshes)) + self.submeshes.append(submesh) + + # Check weather we need to write UVs, dont do it if theres no image + # Multilayer UV's have alredy checked that they have images when + # building face_multi_uvs + if len(uvlayers) == 1: + if blend_images == (None,): + write_single_layer_uvs = False + else: + write_single_layer_uvs = True + + + for face in faces: + + if not face.smooth: + normal = face.no + + face_vertices = [] + face_v = face.v + + + if len(uvlayers)>1: + for i, blend_vert in enumerate(face_v): + if face.smooth: normal = blend_vert.no + vertex = submesh.getVertex(blend_mesh, blend_vert, normal, face_multi_uvs[face.index][i]) + face_vertices.append(vertex) + + elif len(uvlayers)==1: + if write_single_layer_uvs: + face_uv = face.uv + + for i, blend_vert in enumerate(face_v): + if face.smooth: normal = blend_vert.no + if write_single_layer_uvs: uvs = (tuple(face_uv[i]),) + else: uvs = () + + vertex = submesh.getVertex(blend_mesh, blend_vert, normal, uvs ) + face_vertices.append(vertex) + else: + # No UVs + for i, blend_vert in enumerate(face_v): + if face.smooth: normal = blend_vert.no + vertex = submesh.getVertex(blend_mesh, blend_vert, normal, () ) + face_vertices.append(vertex) + + + # Split faces with more than 3 vertices + for i in xrange(1, len(face) - 1): + submesh.faces.append(Cal3DFace(face_vertices[0], face_vertices[i], face_vertices[i + 1])) + + def writeCal3D(self, file): + file.write('\n') + file.write('
\n' % CAL3D_VERSION) + file.write('\n' % len(self.submeshes)) + for submesh in self.submeshes: + submesh.writeCal3D(file, self.matrix, self.matrix_normal) + file.write('\n') + + +class Cal3DSubMesh(object): + __slots__ = 'material', 'vertices', 'vert_mapping', 'vert_count', 'faces', 'nb_lodsteps', 'springs', 'id' + def __init__(self, mesh, material, id): + self.material = material + self.vertices = [] + self.vert_mapping = {} # map original indicies to local + self.vert_count = 0 + self.faces = [] + self.nb_lodsteps = 0 + self.springs = [] + self.id = id + + def getVertex(self, blend_mesh, blend_vert, normal, maps): + ''' + Request a vertex, and create a new one or return a matching vertex + ''' + blend_index = blend_vert.index + index_map = self.vert_mapping.get(blend_index) + + if index_map == None: + vertex = Cal3DVertex(blend_vert.co, normal, maps, blend_mesh.getVertexInfluences(blend_index)) + self.vertices.append([vertex]) + self.vert_mapping[blend_index] = len(self.vert_mapping) + self.vert_count +=1 + return vertex + else: + vertex_list = self.vertices[index_map] + + for v in vertex_list: + if v.normal == normal and\ + v.maps == maps: + return v # reusing + + # No match, add a new vert + # Use the first verts influences + vertex = Cal3DVertex(blend_vert.co, normal, maps, vertex_list[0].influences) + vertex_list.append(vertex) + # self.vert_mapping[blend_index] = len(self.vert_mapping) + self.vert_count +=1 + return vertex + + + def compute_lods(self): + '''Computes LODs info for Cal3D (there's no Blender related stuff here).''' + + print 'Start LODs computation...' + vertex2faces = {} + for face in self.faces: + for vertex in (face.vertex1, face.vertex2, face.vertex3): + l = vertex2faces.get(vertex) + if not l: vertex2faces[vertex] = [face] + else: l.append(face) + + couple_treated = {} + couple_collapse_factor = [] + for face in self.faces: + for a, b in ((face.vertex1, face.vertex2), (face.vertex1, face.vertex3), (face.vertex2, face.vertex3)): + a = a.cloned_from or a + b = b.cloned_from or b + if a.id > b.id: a, b = b, a + if not couple_treated.has_key((a, b)): + # The collapse factor is simply the distance between the 2 points :-( + # This should be improved !! + if vector_dotproduct(a.normal, b.normal) < 0.9: continue + couple_collapse_factor.append((point_distance(a.loc, b.loc), a, b)) + couple_treated[a, b] = 1 + + couple_collapse_factor.sort() + + collapsed = {} + new_vertices = [] + new_faces = [] + for factor, v1, v2 in couple_collapse_factor: + # Determines if v1 collapses to v2 or v2 to v1. + # We choose to keep the vertex which is on the smaller number of faces, since + # this one has more chance of being in an extrimity of the body. + # Though heuristic, this rule yields very good results in practice. + if len(vertex2faces[v1]) < len(vertex2faces[v2]): v2, v1 = v1, v2 + elif len(vertex2faces[v1]) == len(vertex2faces[v2]): + if collapsed.get(v1, 0): v2, v1 = v1, v2 # v1 already collapsed, try v2 + + if (not collapsed.get(v1, 0)) and (not collapsed.get(v2, 0)): + collapsed[v1] = 1 + collapsed[v2] = 1 + + # Check if v2 is already colapsed + while v2.collapse_to: v2 = v2.collapse_to + + common_faces = filter(vertex2faces[v1].__contains__, vertex2faces[v2]) + + v1.collapse_to = v2 + v1.face_collapse_count = len(common_faces) + + for clone in v1.clones: + # Find the clone of v2 that correspond to this clone of v1 + possibles = [] + for face in vertex2faces[clone]: + possibles.append(face.vertex1) + possibles.append(face.vertex2) + possibles.append(face.vertex3) + clone.collapse_to = v2 + for vertex in v2.clones: + if vertex in possibles: + clone.collapse_to = vertex + break + + clone.face_collapse_count = 0 + new_vertices.append(clone) + + # HACK -- all faces get collapsed with v1 (and no faces are collapsed with v1's + # clones). This is why we add v1 in new_vertices after v1's clones. + # This hack has no other incidence that consuming a little few memory for the + # extra faces if some v1's clone are collapsed but v1 is not. + new_vertices.append(v1) + + self.nb_lodsteps += 1 + len(v1.clones) + + new_faces.extend(common_faces) + for face in common_faces: + face.can_collapse = 1 + + # Updates vertex2faces + vertex2faces[face.vertex1].remove(face) + vertex2faces[face.vertex2].remove(face) + vertex2faces[face.vertex3].remove(face) + vertex2faces[v2].extend(vertex2faces[v1]) + + new_vertices.extend(filter(lambda vertex: not vertex.collapse_to, self.vertices)) + new_vertices.reverse() # Cal3D want LODed vertices at the end + for i in xrange(len(new_vertices)): new_vertices[i].id = i + self.vertices = new_vertices + + new_faces.extend(filter(lambda face: not face.can_collapse, self.faces)) + new_faces.reverse() # Cal3D want LODed faces at the end + self.faces = new_faces + + print 'LODs computed : %s vertices can be removed (from a total of %s).' % (self.nb_lodsteps, len(self.vertices)) + + + def writeCal3D(self, file, matrix, matrix_normal): + + file.write('\t\n' % \ + (self.nb_lodsteps, len(self.springs), + len(self.material.maps_filenames))) + + i = 0 + for v in self.vertices: + for item in v: + item.id = i + item.writeCal3D(file, matrix, matrix_normal) + i += 1 + + for item in self.springs: + item.writeCal3D(file) + for item in self.faces: + item.writeCal3D(file) + + file.write('\t\n') + +class Cal3DVertex(object): + __slots__ = 'loc','normal','collapse_to','face_collapse_count','maps','influences','weight','cloned_from','clones','id' + def __init__(self, loc, normal, maps, blend_influences): + self.loc = loc + self.normal = normal + self.collapse_to = None + self.face_collapse_count = 0 + self.maps = maps + self.weight = None + + self.cloned_from = None + self.clones = [] + + self.id = -1 + + if len(blend_influences) == 0 or isinstance(blend_influences[0], Cal3DInfluence): + # This is a copy from another vert + self.influences = blend_influences + else: + # Pass the blender influences + + self.influences = [] + # should this really be a warning? (well currently enabled, + # because blender has some bugs where it doesn't return + # influences in python api though they are set, and because + # cal3d<=0.9.1 had bugs where objects without influences + # aren't drawn. + #if not blend_influences: + # print 'A vertex of object "%s" has no influences.\n(This occurs on objects placed in an invisible layer, you can fix it by using a single layer)' % ob.name + + # sum of influences is not always 1.0 in Blender ?!?! + sum = 0.0 + + for bone_name, weight in blend_influences: + sum += weight + + for bone_name, weight in blend_influences: + bone = BONES.get(bone_name) + if not bone: # keys + # print 'Couldnt find bone "%s" which influences object "%s"' % (bone_name, ob.name) + continue + + if weight: + self.influences.append(Cal3DInfluence(bone, weight / sum)) + + + def writeCal3D(self, file, matrix, matrix_normal): + if self.collapse_to: + collapse_id = self.collapse_to.id + else: + collapse_id = -1 + file.write('\t\t\n' % \ + (self.id, len(self.influences))) + file.write('\t\t\t%.6f %.6f %.6f\n' % tuple(self.loc*matrix)) + file.write('\t\t\t%.6f %.6f %.6f\n' % tuple( (self.normal*matrix_normal).normalize() )) + if collapse_id != -1: + file.write('\t\t\t%i\n' % collapse_id) + file.write('\t\t\t%i\n' % \ + self.face_collapse_count) + + for uv in self.maps: + # we cant have more UV's then our materials image maps + # check for this + file.write('\t\t\t%.6f %.6f\n' % uv) + + for item in self.influences: + item.writeCal3D(file) + + if self.weight != None: + file.write('\t\t\t%.6f\n' % len(self.weight)) + file.write('\t\t\n') + +class Cal3DInfluence(object): + __slots__ = 'bone', 'weight' + def __init__(self, bone, weight): + self.bone = bone + self.weight = weight + + def writeCal3D(self, file): + file.write('\t\t\t%.6f\n' % \ + (self.bone.id, self.weight)) + +class Cal3DSpring(object): + __slots__ = 'vertex1', 'vertex2', 'spring_coefficient', 'idlelength' + def __init__(self, vertex1, vertex2): + self.vertex1 = vertex1 + self.vertex2 = vertex2 + self.spring_coefficient = 0.0 + self.idlelength = 0.0 + + def writeCal3D(self, file): + file.write('\t\t\n' % \ + (self.vertex1.id, self.vertex2.id, self.spring_coefficient, self.idlelength)) + +class Cal3DFace(object): + __slots__ = 'vertex1', 'vertex2', 'vertex3', 'can_collapse', + def __init__(self, vertex1, vertex2, vertex3): + self.vertex1 = vertex1 + self.vertex2 = vertex2 + self.vertex3 = vertex3 + self.can_collapse = 0 + + def writeCal3D(self, file): + file.write('\t\t\n' % \ + (self.vertex1.id, self.vertex2.id, self.vertex3.id)) + +class Cal3DSkeleton(object): + __slots__ = 'bones' + def __init__(self): + self.bones = [] + + def writeCal3D(self, file): + file.write('\n') + file.write('
\n' % CAL3D_VERSION) + file.write('\n' % len(self.bones)) + for item in self.bones: + item.writeCal3D(file) + + file.write('\n') + +BONES = {} +POSEBONES= {} +class Cal3DBone(object): + __slots__ = 'head', 'tail', 'name', 'cal3d_parent', 'loc', 'quat', 'children', 'matrix', 'lloc', 'lquat', 'id' + def __init__(self, skeleton, blend_bone, arm_matrix, cal3d_parent=None): + + # def treat_bone(b, parent = None): + head = blend_bone.head['BONESPACE'] + tail = blend_bone.tail['BONESPACE'] + #print parent.quat + # Turns the Blender's head-tail-roll notation into a quaternion + #quat = matrix2quaternion(blender_bone2matrix(head, tail, blend_bone.roll['BONESPACE'])) + quat = matrix2quaternion(blend_bone.matrix['BONESPACE'].copy().resize4x4()) + + # Pose location + ploc = POSEBONES[blend_bone.name].loc + + if cal3d_parent: + # Compute the translation from the parent bone's head to the child + # bone's head, in the parent bone coordinate system. + # The translation is parent_tail - parent_head + child_head, + # but parent_tail and parent_head must be converted from the parent's parent + # system coordinate into the parent system coordinate. + + parent_invert_transform = matrix_invert(quaternion2matrix(cal3d_parent.quat)) + parent_head = vector_by_matrix_3x3(cal3d_parent.head, parent_invert_transform) + parent_tail = vector_by_matrix_3x3(cal3d_parent.tail, parent_invert_transform) + ploc = vector_add(ploc, blend_bone.head['BONESPACE']) + + # EDIT!!! FIX BONE OFFSET BE CAREFULL OF THIS PART!!! ?? + #diff = vector_by_matrix_3x3(head, parent_invert_transform) + parent_tail= vector_add(parent_tail, head) + # DONE!!! + + parentheadtotail = vector_sub(parent_tail, parent_head) + # hmm this should be handled by the IPos, but isn't for non-animated + # bones which are transformed in the pose mode... + loc = parentheadtotail + + else: + # Apply the armature's matrix to the root bones + head = point_by_matrix(head, arm_matrix) + tail = point_by_matrix(tail, arm_matrix) + + loc = head + quat = matrix2quaternion(matrix_multiply(arm_matrix, quaternion2matrix(quat))) # Probably not optimal + + self.head = head + self.tail = tail + + self.cal3d_parent = cal3d_parent + self.name = blend_bone.name + self.loc = loc + self.quat = quat + self.children = [] + + self.matrix = matrix_translate(quaternion2matrix(quat), loc) + if cal3d_parent: + self.matrix = matrix_multiply(cal3d_parent.matrix, self.matrix) + + # lloc and lquat are the bone => model space transformation (translation and rotation). + # They are probably specific to Cal3D. + m = matrix_invert(self.matrix) + self.lloc = m[3][0], m[3][1], m[3][2] + self.lquat = matrix2quaternion(m) + + self.id = len(skeleton.bones) + skeleton.bones.append(self) + BONES[self.name] = self + + if not blend_bone.hasChildren(): return + for blend_child in blend_bone.children: + self.children.append(Cal3DBone(skeleton, blend_child, arm_matrix, self)) + + + def writeCal3D(self, file): + file.write('\t\n' % \ + (self.id, self.name, len(self.children))) + # We need to negate quaternion W value, but why ? + file.write('\t\t%.6f %.6f %.6f\n' % \ + (self.loc[0], self.loc[1], self.loc[2])) + file.write('\t\t%.6f %.6f %.6f %.6f\n' % \ + (self.quat[0], self.quat[1], self.quat[2], -self.quat[3])) + file.write('\t\t%.6f %.6f %.6f\n' % \ + (self.lloc[0], self.lloc[1], self.lloc[2])) + file.write('\t\t%.6f %.6f %.6f %.6f\n' % \ + (self.lquat[0], self.lquat[1], self.lquat[2], -self.lquat[3])) + if self.cal3d_parent: + file.write('\t\t%i\n' % self.cal3d_parent.id) + else: + file.write('\t\t%i\n' % -1) + + for item in self.children: + file.write('\t\t%i\n' % item.id) + + file.write('\t\n') + +class Cal3DAnimation: + def __init__(self, name, duration = 0.0): + self.name = name + self.duration = duration + self.tracks = {} # Map bone names to tracks + + def writeCal3D(self, file): + file.write('\n') + file.write('
\n' % CAL3D_VERSION) + file.write('\n' % \ + (self.duration, len(self.tracks))) + + for item in self.tracks.itervalues(): + item.writeCal3D(file) + + file.write('\n') + +class Cal3DTrack(object): + __slots__ = 'bone', 'keyframes' + def __init__(self, bone): + self.bone = bone + self.keyframes = [] + + def writeCal3D(self, file): + file.write('\t\n' % + (self.bone.id, len(self.keyframes))) + for item in self.keyframes: + item.writeCal3D(file) + file.write('\t\n') + +class Cal3DKeyFrame(object): + __slots__ = 'time', 'loc', 'quat' + def __init__(self, time, loc, quat): + self.time = time + self.loc = loc + self.quat = quat + + def writeCal3D(self, file): + file.write('\t\t\n' % self.time) + file.write('\t\t\t%.6f %.6f %.6f\n' % \ + (self.loc[0], self.loc[1], self.loc[2])) + # We need to negate quaternion W value, but why ? + file.write('\t\t\t%.6f %.6f %.6f %.6f\n' % \ + (self.quat[0], self.quat[1], self.quat[2], -self.quat[3])) + file.write('\t\t\n') + +def export_cal3d(filename, PREF_SCALE=0.1, PREF_BAKE_MOTION = True, PREF_ACT_ACTION_ONLY=True, PREF_SCENE_FRAMES=False): + if not filename.endswith('.cfg'): + filename += '.cfg' + + file_only = filename.split('/')[-1].split('\\')[-1] + file_only_noext = file_only.split('.')[0] + base_only = filename[:-len(file_only)] + + def new_name(dataname, ext): + return file_only_noext + '_' + BPySys.cleanName(dataname) + ext + + #if EXPORT_FOR_SOYA: + # global BASE_MATRIX + # BASE_MATRIX = matrix_rotate_x(-math.pi / 2.0) + # Get the sce + + sce = bpy.data.scenes.active + blend_world = sce.world + # ---- Export skeleton (armature) ---------------------------------------- + + skeleton = Cal3DSkeleton() + blender_armature = [ob for ob in sce.objects.context if ob.type == 'Armature'] + if len(blender_armature) > 1: print "Found multiple armatures! using ",armatures[0].name + if blender_armature: blender_armature = blender_armature[0] + else: + # Try find a meshes armature + for ob in sce.objects.context: + blender_armature = BPyObject.getObjectArmature(ob) + if blender_armature: + break + + if not blender_armature: + Blender.Draw.PupMenu('Aborting%t|No Armature in selection') + return + + # we need pose bone locations + for pbone in blender_armature.getPose().bones.values(): + POSEBONES[pbone.name] = pbone + + Cal3DBone(skeleton, best_armature_root(blender_armature.getData()), blender_armature.matrixWorld) + + # ---- Export Mesh data --------------------------------------------------- + meshes = [] + for ob in sce.objects.context: + if ob.type != 'Mesh': continue + blend_mesh = ob.getData(mesh=1) + + if not blend_mesh.faces: continue + meshes.append( Cal3DMesh(ob, blend_mesh, blend_world) ) + + # ---- Export animations -------------------------------------------------- + backup_action = blender_armature.action + + ANIMATIONS = [] + SUPPORTED_IPOS = 'QuatW', 'QuatX', 'QuatY', 'QuatZ', 'LocX', 'LocY', 'LocZ' + + if PREF_ACT_ACTION_ONLY: action_items = [(blender_armature.action.name, blender_armature.action)] + else: action_items = Blender.Armature.NLA.GetActions().items() + + print len(action_items), 'action_items' + + for animation_name, blend_action in action_items: + + # get frame range + if PREF_SCENE_FRAMES: + action_start= Blender.Get('staframe') + action_end= Blender.Get('endframe') + else: + _frames = blend_action.getFrameNumbers() + action_start= min(_frames); + action_end= max(_frames); + del _frames + + blender_armature.action = blend_action + + if PREF_BAKE_MOTION: + # We need to set the action active if we are getting baked data + pose_data = BPyArmature.getBakedPoseData(blender_armature, action_start, action_end) + + # Fake, all we need is bone names + blend_action_ipos_items = [(pbone, True) for pbone in POSEBONES.iterkeys()] + else: + # real (bone_name, ipo) pairs + blend_action_ipos_items = blend_action.getAllChannelIpos().items() + + # Now we mau have some bones with no channels, easiest to add their names and an empty list here + # this way they are exported with dummy keyfraames at teh first used frame + action_bone_names = [name for name, ipo in blend_action_ipos_items] + for bone_name in BONES: # iterkeys + if bone_name not in action_bone_names: + blend_action_ipos_items.append( (bone_name, []) ) + + animation = Cal3DAnimation(animation_name) + # ---------------------------- + ANIMATIONS.append(animation) + animation.duration = 0.0 + + for bone_name, ipo in blend_action_ipos_items: + # Baked bones may have no IPO's width motion still + if bone_name not in BONES: + print '\tNo Bone "' + bone_name + '" in (from Animation "' + animation_name + '") ?!?' + continue + + # So we can loop without errors + if ipo==None: ipo = [] + + bone = BONES[bone_name] + track = animation.tracks[bone_name] = Cal3DTrack(bone) + + if PREF_BAKE_MOTION: + for i in xrange(action_end - action_start): + cal3dtime = i / 25.0 # assume 25FPS by default + + if cal3dtime > animation.duration: + animation.duration = cal3dtime + + #print pose_data[i][bone_name], i + loc, quat = pose_data[i][bone_name] + + loc = vector_by_matrix_3x3(loc, bone.matrix) + loc = vector_add(bone.loc, loc) + quat = quaternion_multiply(quat, bone.quat) + quat = Quaternion(quat) + + quat.normalize() + quat = tuple(quat) + + track.keyframes.append( Cal3DKeyFrame(cal3dtime, loc, quat) ) + + else: + #run 1: we need to find all time values where we need to produce keyframes + times = set() + for curve in ipo: + curve_name = curve.name + if curve_name in SUPPORTED_IPOS: + for p in curve.bezierPoints: + times.add( p.pt[0] ) + + times = list(times) + times.sort() + + # Incase we have no keys here or ipo==None + if not times: times.append(action_start) + + # run2: now create keyframes + for time in times: + cal3dtime = (time-1) / 25.0 # assume 25FPS by default + if cal3dtime > animation.duration: + animation.duration = cal3dtime + + trans = Vector() + quat = Quaternion() + + for curve in ipo: + val = curve.evaluate(time) + # val = 0.0 + curve_name= curve.name + if curve_name == 'LocX': trans[0] = val + elif curve_name == 'LocY': trans[1] = val + elif curve_name == 'LocZ': trans[2] = val + elif curve_name == 'QuatW': quat[3] = val + elif curve_name == 'QuatX': quat[0] = val + elif curve_name == 'QuatY': quat[1] = val + elif curve_name == 'QuatZ': quat[2] = val + + transt = vector_by_matrix_3x3(trans, bone.matrix) + loc = vector_add(bone.loc, transt) + quat = quaternion_multiply(quat, bone.quat) + quat = Quaternion(quat) + + quat.normalize() + quat = tuple(quat) + + track.keyframes.append( Cal3DKeyFrame(cal3dtime, loc, quat) ) + + + if animation.duration <= 0: + print 'Ignoring Animation "' + animation_name + '": duration is 0.\n' + continue + + # Restore the original armature + blender_armature.action = backup_action + # ------------------------------------- End Animation + + + + cfg = open((filename), 'wb') + cfg.write('# Cal3D model exported from Blender with export_cal3d.py\n# from %s\n' % Blender.Get('filename')) + + if PREF_SCALE != 1.0: cfg.write('scale=%.6f\n' % PREF_SCALE) + + fname = file_only_noext + '.xsf' + file = open( base_only + fname, 'wb') + skeleton.writeCal3D(file) + file.close() + + cfg.write('skeleton=%s\n' % fname) + + for animation in ANIMATIONS: + if not animation.name.startswith('_'): + if animation.duration > 0.1: # Cal3D does not support animation with only one state + fname = new_name(animation.name, '.xaf') + file = open(base_only + fname, 'wb') + animation.writeCal3D(file) + file.close() + cfg.write('animation=%s\n' % fname) + + for mesh in meshes: + if not mesh.name.startswith('_'): + fname = new_name(mesh.name, '.xmf') + file = open(base_only + fname, 'wb') + mesh.writeCal3D(file) + file.close() + + cfg.write('mesh=%s\n' % fname) + + materials = MATERIALS.values() + materials.sort(key = lambda a: a.id) + for material in materials: + # Just number materials, its less trouble + fname = new_name(str(material.id), '.xrf') + + file = open(base_only + fname, 'wb') + material.writeCal3D(file) + file.close() + + cfg.write('material=%s\n' % fname) + + print 'Cal3D Saved to "%s.cfg"' % file_only_noext + + # Warnings + if len(animation.tracks) < 2: + Blender.Draw.PupMenu('Warning, the armature has less then 2 tracks, file may not load in Cal3d') + + +def export_cal3d_ui(filename): + + PREF_SCALE= Blender.Draw.Create(1.0) + PREF_BAKE_MOTION = Blender.Draw.Create(1) + PREF_ACT_ACTION_ONLY= Blender.Draw.Create(1) + PREF_SCENE_FRAMES= Blender.Draw.Create(0) + + block = [\ + ('Scale: ', PREF_SCALE, 0.01, 100, 'The scale to set in the Cal3d .cfg file (unsupported by soya)'),\ + ('Baked Motion', PREF_BAKE_MOTION, 'use final pose position instead of ipo keyframes (IK and constraint support)'),\ + ('Active Action', PREF_ACT_ACTION_ONLY, 'Only export action applied to this armature, else export all actions.'),\ + ('Scene Frames', PREF_SCENE_FRAMES, 'Use scene frame range, else the actions start/end'),\ + ] + + if not Blender.Draw.PupBlock('Cal3D Options', block): + return + + Blender.Window.WaitCursor(1) + export_cal3d(filename, 1.0/PREF_SCALE.val, PREF_BAKE_MOTION.val, PREF_ACT_ACTION_ONLY.val, PREF_SCENE_FRAMES.val) + Blender.Window.WaitCursor(0) + + +#import os +if __name__ == '__main__': + Blender.Window.FileSelector(export_cal3d_ui, 'Cal3D Export', Blender.Get('filename').replace('.blend', '.cfg')) + #export_cal3d('/cally/data/skeleton/skeleton' + '.cfg', 1.0, True, False, False) + #export_cal3d('/test' + '.cfg') + #export_cal3d_ui('/test' + '.cfg') + #os.system('cd /; wine /cal3d_miniviewer.exe /skeleton.cfg') + #os.system('cd /cally/;wine cally') diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py new file mode 100644 index 00000000000..99d036b38bc --- /dev/null +++ b/release/scripts/export_fbx.py @@ -0,0 +1,2976 @@ +#!BPY +""" +Name: 'Autodesk FBX (.fbx)...' +Blender: 244 +Group: 'Export' +Tooltip: 'Selection to an ASCII Autodesk FBX ' +""" +__author__ = "Campbell Barton" +__url__ = ['www.blender.org', 'blenderartists.org'] +__version__ = "1.1" + +__bpydoc__ = """\ +This script is an exporter to the FBX file format. + +http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx +""" +# -------------------------------------------------------------------------- +# FBX Export v0.1 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +try: + import time + # import os # only needed for batch export, nbot used yet +except: + time = None # use this to check if they have python modules installed + +# for python 2.3 support +try: + set() +except: + try: + from sets import Set as set + except: + set = None # so it complains you dont have a ! + +# os is only needed for batch 'own dir' option +try: + import os +except: + os = None + +import Blender +import bpy +from Blender.Mathutils import Matrix, Vector, RotationMatrix + +import BPyObject +import BPyMesh +import BPySys +import BPyMessages + +import sys + +## This was used to make V, but faster not to do all that +##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' +##v = range(255) +##for c in valid: v.remove(ord(c)) +v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,42,43,47,58,59,60,61,62,63,64,92,94,96,124,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254] +invalid = ''.join([chr(i) for i in v]) +def cleanName(name): + for ch in invalid: name = name.replace(ch, '_') + return name +del v, i + + +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + + +def copy_images(dest_dir, textures): + if not dest_dir.endswith(Blender.sys.sep): + dest_dir += Blender.sys.sep + + image_paths = set() + for img in textures: + image_paths.add(Blender.sys.expandpath(img.filename)) + + # Now copy images + copyCount = 0 + for image_path in image_paths: + if Blender.sys.exists(image_path): + # Make a name for the target path. + dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] + if not Blender.sys.exists(dest_image_path): # Image isnt alredy there + print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) + try: + copy_file(image_path, dest_image_path) + copyCount+=1 + except: + print '\t\tWarning, file failed to copy, skipping.' + + print '\tCopied %d images' % copyCount + +mtx4_identity = Matrix() + +# testing +mtx_x90 = RotationMatrix( 90, 3, 'x') # used +#mtx_x90n = RotationMatrix(-90, 3, 'x') +#mtx_y90 = RotationMatrix( 90, 3, 'y') +#mtx_y90n = RotationMatrix(-90, 3, 'y') +#mtx_z90 = RotationMatrix( 90, 3, 'z') +#mtx_z90n = RotationMatrix(-90, 3, 'z') + +#mtx4_x90 = RotationMatrix( 90, 4, 'x') +mtx4_x90n = RotationMatrix(-90, 4, 'x') # used +#mtx4_y90 = RotationMatrix( 90, 4, 'y') +mtx4_y90n = RotationMatrix(-90, 4, 'y') # used +mtx4_z90 = RotationMatrix( 90, 4, 'z') # used +mtx4_z90n = RotationMatrix(-90, 4, 'z') # used + +def strip_path(p): + return p.split('\\')[-1].split('/')[-1] + +# Used to add the scene name into the filename without using odd chars +sane_name_mapping_ob = {} +sane_name_mapping_mat = {} +sane_name_mapping_tex = {} +sane_name_mapping_take = {} +sane_name_mapping_group = {} + +# Make sure reserved names are not used +sane_name_mapping_ob['Scene'] = 'Scene_' +sane_name_mapping_ob['blend_root'] = 'blend_root_' + +def increment_string(t): + name = t + num = '' + while name and name[-1].isdigit(): + num = name[-1] + num + name = name[:-1] + if num: return '%s%d' % (name, int(num)+1) + else: return name + '_0' + + + +# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up. +def sane_name(data, dct): + #if not data: return None + name = data.name + + # dont cache, only ever call once for each data type now, + # so as to avoid namespace collision between types - like with objects <-> bones + #try: return dct[name] + #except: pass + + orig_name = name + if not name: + name = 'unnamed' # blank string, ASKING FOR TROUBLE! + else: + #name = BPySys.cleanName(name) + name = cleanName(name) # use our own + + while name in dct.itervalues(): name = increment_string(name) + + dct[orig_name] = name + return name + +def sane_obname(data): return sane_name(data, sane_name_mapping_ob) +def sane_matname(data): return sane_name(data, sane_name_mapping_mat) +def sane_texname(data): return sane_name(data, sane_name_mapping_tex) +def sane_takename(data): return sane_name(data, sane_name_mapping_take) +def sane_groupname(data): return sane_name(data, sane_name_mapping_group) + + + + +def mat4x4str(mat): + return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ]) + +def meshNormalizedWeights(me): + try: # account for old bad BPyMesh + groupNames, vWeightList = BPyMesh.meshWeight2List(me) + except: + return [],[] + + if not groupNames: + return [],[] + + for i, vWeights in enumerate(vWeightList): + tot = 0.0 + for w in vWeights: + tot+=w + + if tot: + for j, w in enumerate(vWeights): + vWeights[j] = w/tot + + return groupNames, vWeightList + +header_comment = \ +'''; FBX 6.1.0 project file +; Created by Blender FBX Exporter +; for support mail: ideasman42@gmail.com +; ---------------------------------------------------- + +''' + +# This func can be called with just the filename +def write(filename, batch_objects = None, \ + EXP_OBS_SELECTED = True, + EXP_MESH = True, + EXP_MESH_APPLY_MOD = True, + EXP_MESH_HQ_NORMALS = False, + EXP_ARMATURE = True, + EXP_LAMP = True, + EXP_CAMERA = True, + EXP_EMPTY = True, + EXP_IMAGE_COPY = False, + GLOBAL_MATRIX = Matrix(), + ANIM_ENABLE = True, + ANIM_OPTIMIZE = True, + ANIM_OPTIMIZE_PRECISSION = 6, + ANIM_ACTION_ALL = False, + BATCH_ENABLE = False, + BATCH_GROUP = True, + BATCH_SCENE = False, + BATCH_FILE_PREFIX = '', + BATCH_OWN_DIR = False + ): + + # ----------------- Batch support! + if BATCH_ENABLE: + if os == None: BATCH_OWN_DIR = False + + fbxpath = filename + + # get the path component of filename + tmp_exists = Blender.sys.exists(fbxpath) + + if tmp_exists != 2: # a file, we want a path + while fbxpath and fbxpath[-1] not in ('/', '\\'): + fbxpath = fbxpath[:-1] + if not filename: + Draw.PupMenu('Error%t|Directory does not exist!') + return + + tmp_exists = Blender.sys.exists(fbxpath) + + if tmp_exists != 2: + Draw.PupMenu('Error%t|Directory does not exist!') + return + + if not fbxpath.endswith(Blender.sys.sep): + fbxpath += Blender.sys.sep + del tmp_exists + + + if BATCH_GROUP: + data_seq = bpy.data.groups + else: + data_seq = bpy.data.scenes + + # call this function within a loop with BATCH_ENABLE == False + orig_sce = bpy.data.scenes.active + + + new_fbxpath = fbxpath # own dir option modifies, we need to keep an original + for data in data_seq: # scene or group + newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name) + + + if BATCH_OWN_DIR: + new_fbxpath = fbxpath + newname + Blender.sys.sep + # path may alredy exist + # TODO - might exist but be a file. unlikely but should probably account for it. + + if Blender.sys.exists(new_fbxpath) == 0: + os.mkdir(new_fbxpath) + + + filename = new_fbxpath + newname + '.fbx' + + print '\nBatch exporting %s as...\n\t"%s"' % (data, filename) + + if BATCH_GROUP: #group + # group, so objects update properly, add a dummy scene. + sce = bpy.data.scenes.new() + sce.Layers = (1<<20) -1 + bpy.data.scenes.active = sce + for ob_base in data.objects: + sce.objects.link(ob_base) + + sce.update(1) + + # TODO - BUMMER! Armatures not in the group wont animate the mesh + + else:# scene + + + data_seq.active = data + + + # Call self with modified args + # Dont pass batch options since we alredy usedt them + write(filename, data.objects, + False, + EXP_MESH, + EXP_MESH_APPLY_MOD, + EXP_MESH_HQ_NORMALS, + EXP_ARMATURE, + EXP_LAMP, + EXP_CAMERA, + EXP_EMPTY, + EXP_IMAGE_COPY, + GLOBAL_MATRIX, + ANIM_ENABLE, + ANIM_OPTIMIZE, + ANIM_OPTIMIZE_PRECISSION, + ANIM_ACTION_ALL + ) + + if BATCH_GROUP: + # remove temp group scene + bpy.data.scenes.unlink(sce) + + bpy.data.scenes.active = orig_sce + + return # so the script wont run after we have batch exported. + + # end batch support + + + # ---------------------------------------------- + # storage classes + class my_bone_class: + __slots__ =(\ + 'blenName',\ + 'blenBone',\ + 'blenMeshes',\ + 'restMatrix',\ + 'parent',\ + 'blenName',\ + 'fbxName',\ + 'fbxArm',\ + '__pose_bone',\ + '__anim_poselist') + + def __init__(self, blenBone, fbxArm): + + # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace + self.fbxName = sane_obname(blenBone) + + self.blenName = blenBone.name + self.blenBone = blenBone + self.blenMeshes = {} # fbxMeshObName : mesh + self.fbxArm = fbxArm + self.restMatrix = blenBone.matrix['ARMATURESPACE'] + + # not used yet + # self.restMatrixInv = self.restMatrix.copy().invert() + # self.restMatrixLocal = None # set later, need parent matrix + + self.parent = None + + # not public + pose = fbxArm.blenObject.getPose() + self.__pose_bone = pose.bones[self.blenName] + + # store a list if matricies here, (poseMatrix, head, tail) + # {frame:posematrix, frame:posematrix, ...} + self.__anim_poselist = {} + + ''' + def calcRestMatrixLocal(self): + if self.parent: + self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert() + else: + self.restMatrixLocal = self.restMatrix.copy() + ''' + def setPoseFrame(self, f): + # cache pose info here, frame must be set beforehand + + # Didnt end up needing head or tail, if we do - here it is. + ''' + self.__anim_poselist[f] = (\ + self.__pose_bone.poseMatrix.copy(),\ + self.__pose_bone.head.copy(),\ + self.__pose_bone.tail.copy() ) + ''' + + self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy() + + # get pose from frame. + def getPoseMatrix(self, f):# ---------------------------------------------- + return self.__anim_poselist[f] + ''' + def getPoseHead(self, f): + #return self.__pose_bone.head.copy() + return self.__anim_poselist[f][1].copy() + def getPoseTail(self, f): + #return self.__pose_bone.tail.copy() + return self.__anim_poselist[f][2].copy() + ''' + # end + + def getAnimParRelMatrix(self, frame): + #arm_mat = self.fbxArm.matrixWorld + #arm_mat = self.fbxArm.parRelMatrix() + if not self.parent: + #return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore + return mtx4_z90 * self.getPoseMatrix(frame) + else: + #return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert() + return (mtx4_z90 * (self.getPoseMatrix(frame))) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert() + + # we need thes because cameras and lights modified rotations + def getAnimParRelMatrixRot(self, frame): + return self.getAnimParRelMatrix(frame) + + def flushAnimData(self): + self.__anim_poselist.clear() + + + class my_object_generic: + # Other settings can be applied for each type - mesh, armature etc. + def __init__(self, ob, matrixWorld = None): + self.fbxName = sane_obname(ob) + self.blenObject = ob + self.fbxGroupNames = [] + self.fbxParent = None # set later on IF the parent is in the selection. + if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX + else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX + self.__anim_poselist = {} # we should only access this + + def parRelMatrix(self): + if self.fbxParent: + return self.matrixWorld * self.fbxParent.matrixWorld.copy().invert() + else: + return self.matrixWorld + + def setPoseFrame(self, f): + self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() + + def getAnimParRelMatrix(self, frame): + if self.fbxParent: + #return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX + return (self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert() + else: + return self.__anim_poselist[frame] * GLOBAL_MATRIX + + def getAnimParRelMatrixRot(self, frame): + type = self.blenObject.type + if self.fbxParent: + matrix_rot = (((self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert())).rotationPart() + else: + matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart() + + # Lamps need to be rotated + if type =='Lamp': + matrix_rot = mtx_x90 * matrix_rot + elif ob and type =='Camera': + y = Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + + return matrix_rot + + # ---------------------------------------------- + + + + + + print '\nFBX export starting...', filename + start_time = Blender.sys.time() + try: + file = open(filename, 'w') + except: + return False + + sce = bpy.data.scenes.active + world = sce.world + + + # ---------------------------- Write the header first + file.write(header_comment) + if time: + curtime = time.localtime()[0:6] + else: + curtime = [0,0,0,0,0,0] + # + file.write(\ +'''FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 6100 + CreationTimeStamp: { + Version: 1000 + Year: %.4i + Month: %.2i + Day: %.2i + Hour: %.2i + Minute: %.2i + Second: %.2i + Millisecond: 0 + } + Creator: "FBX SDK/FBX Plugins build 20070228" + OtherFlags: { + FlagPLE: 0 + } +}''' % (curtime)) + + file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) + file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) + + pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way + + # --------------- funcs for exporting + def object_tx(ob, loc, matrix, matrix_mod = None): + ''' + Matrix mod is so armature objects can modify their bone matricies + ''' + if isinstance(ob, Blender.Types.BoneType): + + # we know we have a matrix + # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod) + matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + + parent = ob.parent + if parent: + #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod) + par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore + matrix = matrix * par_matrix.copy().invert() + + matrix_rot = matrix.rotationPart() + + loc = tuple(matrix.translationPart()) + scale = tuple(matrix.scalePart()) + rot = tuple(matrix_rot.toEuler()) + + else: + # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore + #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX + if ob and not matrix: raise "error: this should never happen!" + + matrix_rot = matrix + #if matrix: + # matrix = matrix_scale * matrix + + if matrix: + loc = tuple(matrix.translationPart()) + scale = tuple(matrix.scalePart()) + + matrix_rot = matrix.rotationPart() + # Lamps need to be rotated + if ob and ob.type =='Lamp': + matrix_rot = mtx_x90 * matrix_rot + rot = tuple(matrix_rot.toEuler()) + elif ob and ob.type =='Camera': + y = Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + rot = tuple(matrix_rot.toEuler()) + else: + rot = tuple(matrix_rot.toEuler()) + else: + if not loc: + loc = 0,0,0 + scale = 1,1,1 + rot = 0,0,0 + + return loc, rot, scale, matrix, matrix_rot + + def write_object_tx(ob, loc, matrix, matrix_mod= None): + ''' + We have loc to set the location if non blender objects that have a location + + matrix_mod is only used for bones at the moment + ''' + loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod) + + file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc) + file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot) + file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale) + return loc, rot, scale, matrix, matrix_rot + + def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None): + # if the type is 0 its an empty otherwise its a mesh + # only difference at the moment is one has a color + file.write(''' + Properties60: { + Property: "QuaternionInterpolate", "bool", "",0 + Property: "Visibility", "Visibility", "A+",1''') + + loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod) + + # Rotation order, note, for FBX files Iv loaded normal order is 1 + # setting to zero. + # eEULER_XYZ = 0 + # eEULER_XZY + # eEULER_YZX + # eEULER_YXZ + # eEULER_ZXY + # eEULER_ZYX + + file.write(''' + Property: "RotationOffset", "Vector3D", "",0,0,0 + Property: "RotationPivot", "Vector3D", "",0,0,0 + Property: "ScalingOffset", "Vector3D", "",0,0,0 + Property: "ScalingPivot", "Vector3D", "",0,0,0 + Property: "TranslationActive", "bool", "",0 + Property: "TranslationMin", "Vector3D", "",0,0,0 + Property: "TranslationMax", "Vector3D", "",0,0,0 + Property: "TranslationMinX", "bool", "",0 + Property: "TranslationMinY", "bool", "",0 + Property: "TranslationMinZ", "bool", "",0 + Property: "TranslationMaxX", "bool", "",0 + Property: "TranslationMaxY", "bool", "",0 + Property: "TranslationMaxZ", "bool", "",0 + Property: "RotationOrder", "enum", "",0 + Property: "RotationSpaceForLimitOnly", "bool", "",0 + Property: "AxisLen", "double", "",10 + Property: "PreRotation", "Vector3D", "",0,0,0 + Property: "PostRotation", "Vector3D", "",0,0,0 + Property: "RotationActive", "bool", "",0 + Property: "RotationMin", "Vector3D", "",0,0,0 + Property: "RotationMax", "Vector3D", "",0,0,0 + Property: "RotationMinX", "bool", "",0 + Property: "RotationMinY", "bool", "",0 + Property: "RotationMinZ", "bool", "",0 + Property: "RotationMaxX", "bool", "",0 + Property: "RotationMaxY", "bool", "",0 + Property: "RotationMaxZ", "bool", "",0 + Property: "RotationStiffnessX", "double", "",0 + Property: "RotationStiffnessY", "double", "",0 + Property: "RotationStiffnessZ", "double", "",0 + Property: "MinDampRangeX", "double", "",0 + Property: "MinDampRangeY", "double", "",0 + Property: "MinDampRangeZ", "double", "",0 + Property: "MaxDampRangeX", "double", "",0 + Property: "MaxDampRangeY", "double", "",0 + Property: "MaxDampRangeZ", "double", "",0 + Property: "MinDampStrengthX", "double", "",0 + Property: "MinDampStrengthY", "double", "",0 + Property: "MinDampStrengthZ", "double", "",0 + Property: "MaxDampStrengthX", "double", "",0 + Property: "MaxDampStrengthY", "double", "",0 + Property: "MaxDampStrengthZ", "double", "",0 + Property: "PreferedAngleX", "double", "",0 + Property: "PreferedAngleY", "double", "",0 + Property: "PreferedAngleZ", "double", "",0 + Property: "InheritType", "enum", "",0 + Property: "ScalingActive", "bool", "",0 + Property: "ScalingMin", "Vector3D", "",1,1,1 + Property: "ScalingMax", "Vector3D", "",1,1,1 + Property: "ScalingMinX", "bool", "",0 + Property: "ScalingMinY", "bool", "",0 + Property: "ScalingMinZ", "bool", "",0 + Property: "ScalingMaxX", "bool", "",0 + Property: "ScalingMaxY", "bool", "",0 + Property: "ScalingMaxZ", "bool", "",0 + Property: "GeometricTranslation", "Vector3D", "",0,0,0 + Property: "GeometricRotation", "Vector3D", "",0,0,0 + Property: "GeometricScaling", "Vector3D", "",1,1,1 + Property: "LookAtProperty", "object", "" + Property: "UpVectorProperty", "object", "" + Property: "Show", "bool", "",1 + Property: "NegativePercentShapeSupport", "bool", "",1 + Property: "DefaultAttributeIndex", "int", "",0''') + if ob and type(ob) != Blender.Types.BoneType: + # Only mesh objects have color + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Size", "double", "",100') + file.write('\n\t\t\tProperty: "Look", "enum", "",1') + + return loc, rot, scale, matrix, matrix_rot + + + # -------------------------------------------- Armatures + #def write_bone(bone, name, matrix_mod): + def write_bone(my_bone): + file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName) + file.write('\n\t\tVersion: 232') + + #poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3] + poseMatrix = write_object_props(my_bone.blenBone)[3] # dont apply bone matricies anymore + pose_items.append( (my_bone.fbxName, poseMatrix) ) + + + # file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) + file.write('\n\t\t\tProperty: "Size", "double", "",1') + + #((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length) + + """ + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ + ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length) + """ + + file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\ + (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length) + + #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1') + file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 1') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Skeleton"') + file.write('\n\t}') + + def write_camera_switch(): + file.write(''' + Model: "Model::Camera Switcher", "CameraSwitcher" { + Version: 232''') + + write_object_props() + file.write(''' + Property: "Color", "Color", "A",0.8,0.8,0.8 + Property: "Camera Index", "Integer", "A+",100 + } + MultiLayer: 0 + MultiTake: 1 + Hidden: "True" + Shading: W + Culling: "CullingOff" + Version: 101 + Name: "Model::Camera Switcher" + CameraId: 0 + CameraName: 100 + CameraIndexName: + }''') + + def write_camera_dummy(name, loc, near, far, proj_type, up): + file.write('\n\tModel: "Model::%s", "Camera" {' % name ) + file.write('\n\t\tVersion: 232') + write_object_props(None, loc) + + file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') + file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') + file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",40') + file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",0') + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",0') + file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0.63,0.63,0.63') + file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') + file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') + file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') + file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') + file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') + file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') + file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",21.3544940948486') + file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') + file.write('\n\t\t\tProperty: "AspectW", "double", "",320') + file.write('\n\t\t\tProperty: "AspectH", "double", "",200') + file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",1') + file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') + file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') + file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % near) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % far) + file.write('\n\t\t\tProperty: "FilmWidth", "double", "",0.816') + file.write('\n\t\t\tProperty: "FilmHeight", "double", "",0.612') + file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",1.33333333333333') + file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') + file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",4') + file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') + file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') + file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') + file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') + file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') + file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') + file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') + file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') + file.write('\n\t\t\tProperty: "Crop", "bool", "",0') + file.write('\n\t\t\tProperty: "Center", "bool", "",1') + file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') + file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') + file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') + file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') + file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') + file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') + file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",1.33333333333333') + file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') + file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') + file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') + file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') + file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",%i' % proj_type) + file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') + file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') + file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') + file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') + file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') + file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') + file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') + file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tHidden: "True"') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Camera"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) + file.write('\n\t\tUp: %i,%i,%i' % up) + file.write('\n\t\tLookAt: 0,0,0') + file.write('\n\t\tShowInfoOnMoving: 1') + file.write('\n\t\tShowAudio: 0') + file.write('\n\t\tAudioColor: 0,1,0') + file.write('\n\t\tCameraOrthoZoom: 1') + file.write('\n\t}') + + def write_camera_default(): + # This sucks but to match FBX converter its easier to + # write the cameras though they are not needed. + write_camera_dummy('Producer Perspective', (0,71.3,287.5), 10, 4000, 0, (0,1,0)) + write_camera_dummy('Producer Top', (0,4000,0), 1, 30000, 1, (0,0,-1)) + write_camera_dummy('Producer Bottom', (0,-4000,0), 1, 30000, 1, (0,0,-1)) + write_camera_dummy('Producer Front', (0,0,4000), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Back', (0,0,-4000), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0)) + write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0)) + + def write_camera(my_cam): + ''' + Write a blender camera + ''' + render = sce.render + width = render.sizeX + height = render.sizeY + aspect = float(width)/height + + data = my_cam.blenObject.data + + file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName ) + file.write('\n\t\tVersion: 232') + loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject, None, my_cam.parRelMatrix()) + + file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') + file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle) + file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1') + file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026') + file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units? + file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto + file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0') + file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0') + file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1') + file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1') + file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1') + file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2') + file.write('\n\t\t\tProperty: "GateFit", "enum", "",0') + file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0') + file.write('\n\t\t\tProperty: "AspectW", "double", "",%i' % width) + file.write('\n\t\t\tProperty: "AspectH", "double", "",%i' % height) + + '''Camera aspect ratio modes. + 0 If the ratio mode is eWINDOW_SIZE, both width and height values aren't relevant. + 1 If the ratio mode is eFIXED_RATIO, the height value is set to 1.0 and the width value is relative to the height value. + 2 If the ratio mode is eFIXED_RESOLUTION, both width and height values are in pixels. + 3 If the ratio mode is eFIXED_WIDTH, the width value is in pixels and the height value is relative to the width value. + 4 If the ratio mode is eFIXED_HEIGHT, the height value is in pixels and the width value is relative to the height value. + + Definition at line 234 of file kfbxcamera.h. ''' + + file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",2') + + file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3') + file.write('\n\t\t\tProperty: "ShowName", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0') + file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1') + file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0') + file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart) + file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0') + file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0') + file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect) + file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1') + file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1') + file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0') + file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2') + file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100') + file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0') + file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1') + file.write('\n\t\t\tProperty: "LockMode", "bool", "",0') + file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0') + file.write('\n\t\t\tProperty: "FitImage", "bool", "",0') + file.write('\n\t\t\tProperty: "Crop", "bool", "",0') + file.write('\n\t\t\tProperty: "Center", "bool", "",1') + file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1') + file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0') + file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5') + file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1') + file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0') + file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1') + file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",%.6f' % aspect) + file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0') + file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100') + file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50') + file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50') + file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",0') + file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0') + file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0') + file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0') + file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5') + file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200') + file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0') + file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777') + file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0') + file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7') + + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Camera"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc) + file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Vector(0,1,0) * matrix_rot) ) + file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Vector(0,0,-1)*matrix_rot) ) + + #file.write('\n\t\tUp: 0,0,0' ) + #file.write('\n\t\tLookAt: 0,0,0' ) + + file.write('\n\t\tShowInfoOnMoving: 1') + file.write('\n\t\tShowAudio: 0') + file.write('\n\t\tAudioColor: 0,1,0') + file.write('\n\t\tCameraOrthoZoom: 1') + file.write('\n\t}') + + def write_light(my_light): + light = my_light.blenObject.data + file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName) + file.write('\n\t\tVersion: 232') + + write_object_props(my_light.blenObject, None, my_light.parRelMatrix()) + + # Why are these values here twice?????? - oh well, follow the holy sdk's output + + # Blender light types match FBX's, funny coincidence, we just need to + # be sure that all unsupported types are made into a point light + #ePOINT, + #eDIRECTIONAL + #eSPOT + light_type = light.type + if light_type > 3: light_type = 0 + + mode = light.mode + if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows: + do_shadow = 1 + else: + do_shadow = 0 + + if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular): + do_light = 0 + else: + do_light = 1 + + scale = abs(GLOBAL_MATRIX.scalePart()[0]) # scale is always uniform in this case + + file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) + file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') + file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') + file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1') + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 + file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') + file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 + file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale)) + file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') + file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) + file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light) + file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1') + file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') + file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1') + file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') + file.write('\n\t\t\tProperty: "DecayType", "enum", "",0') + file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist) + file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0') + file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0') + file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0') + file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0') + file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0') + file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0') + file.write('\n\t\t\tProperty: "CastShadows", "bool", "",%i' % do_shadow) + file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1') + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 0') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + file.write('\n\t\tTypeFlags: "Light"') + file.write('\n\t\tGeometryVersion: 124') + file.write('\n\t}') + + # matrixOnly is not used at the moment + def write_null(my_null = None, fbxName = None, matrixOnly = None): + # ob can be null + if not fbxName: fbxName = my_null.fbxName + + file.write('\n\tModel: "Model::%s", "Null" {' % fbxName) + file.write('\n\t\tVersion: 232') + + # only use this for the root matrix at the moment + if matrixOnly: + poseMatrix = write_object_props(None, None, matrixOnly)[3] + + else: # all other Null's + if my_null: poseMatrix = write_object_props(my_null.blenObject, None, my_null.parRelMatrix())[3] + else: poseMatrix = write_object_props()[3] + + pose_items.append((fbxName, poseMatrix)) + + file.write(''' + } + MultiLayer: 0 + MultiTake: 1 + Shading: Y + Culling: "CullingOff" + TypeFlags: "Null" + }''') + + # Material Settings + if world: world_amb = world.getAmb() + else: world_amb = (0,0,0) # Default value + + def write_material(matname, mat): + file.write('\n\tMaterial: "Material::%s", "" {' % matname) + + # Todo, add more material Properties. + if mat: + mat_cold = tuple(mat.rgbCol) + mat_cols = tuple(mat.specCol) + #mat_colm = tuple(mat.mirCol) # we wont use the mirror color + mat_colamb = tuple([c for c in world_amb]) + + mat_dif = mat.ref + mat_amb = mat.amb + mat_hard = (float(mat.hard)-1)/5.10 + mat_spec = mat.spec/2.0 + mat_alpha = mat.alpha + mat_emit = mat.emit + mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS + if mat_shadeless: + mat_shader = 'Lambert' + else: + if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT: + mat_shader = 'Lambert' + else: + mat_shader = 'Phong' + else: + mat_cols = mat_cold = 0.8, 0.8, 0.8 + mat_colamb = 0.0,0.0,0.0 + # mat_colm + mat_dif = 1.0 + mat_amb = 0.5 + mat_hard = 20.0 + mat_spec = 0.2 + mat_alpha = 1.0 + mat_emit = 0.0 + mat_shadeless = False + mat_shader = 'Phong' + + file.write('\n\t\tVersion: 102') + file.write('\n\t\tShadingModel: "%s"' % mat_shader.lower()) + file.write('\n\t\tMultiLayer: 0') + + file.write('\n\t\tProperties60: {') + file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader) + file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0') + file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender + file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_dif) + + file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb) + file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb) + file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) + file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_emit) + file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0') + file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1') + file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha)) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols) + file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec) + file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0') + file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0') + file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1') + file.write('\n\t\t\tProperty: "Emissive", "ColorRGB", "",0,0,0') + file.write('\n\t\t\tProperty: "Ambient", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb) + file.write('\n\t\t\tProperty: "Diffuse", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "Specular", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols) + file.write('\n\t\t\tProperty: "Shininess", "double", "",%.1f' % mat_hard) + file.write('\n\t\t\tProperty: "Opacity", "double", "",%.1f' % mat_alpha) + if not mat_shadeless: + file.write('\n\t\t\tProperty: "Reflectivity", "double", "",0') + + file.write('\n\t\t}') + file.write('\n\t}') + + def write_video(texname, tex): + # Same as texture really! + file.write('\n\tVideo: "Video::%s", "Clip" {' % texname) + + file.write(''' + Type: "Clip" + Properties60: { + Property: "FrameRate", "double", "",0 + Property: "LastFrame", "int", "",0 + Property: "Width", "int", "",0 + Property: "Height", "int", "",0''') + if tex: + fname = tex.filename + fname_strip = strip_path(fname) + else: + fname = fname_strip = '' + + file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip) + + + file.write(''' + Property: "StartFrame", "int", "",0 + Property: "StopFrame", "int", "",0 + Property: "PlaySpeed", "double", "",1 + Property: "Offset", "KTime", "",0 + Property: "InterlaceMode", "enum", "",0 + Property: "FreeRunning", "bool", "",0 + Property: "Loop", "bool", "",0 + Property: "AccessMode", "enum", "",0 + } + UseMipMap: 0''') + + file.write('\n\t\tFilename: "%s"' % fname_strip) + if fname_strip: fname_strip = '/' + fname_strip + file.write('\n\t\tRelativeFilename: "fbx%s"' % fname_strip) # make relative + file.write('\n\t}') + + + def write_texture(texname, tex, num): + # if tex == None then this is a dummy tex + file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname) + file.write('\n\t\tType: "TextureVideoClip"') + file.write('\n\t\tVersion: 202') + # TODO, rare case _empty_ exists as a name. + file.write('\n\t\tTextureName: "Texture::%s"' % texname) + + file.write(''' + Properties60: { + Property: "Translation", "Vector", "A+",0,0,0 + Property: "Rotation", "Vector", "A+",0,0,0 + Property: "Scaling", "Vector", "A+",1,1,1''') + file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num) + + + # WrapModeU/V 0==rep, 1==clamp, TODO add support + file.write(''' + Property: "TextureTypeUse", "enum", "",0 + Property: "CurrentTextureBlendMode", "enum", "",1 + Property: "UseMaterial", "bool", "",0 + Property: "UseMipMap", "bool", "",0 + Property: "CurrentMappingType", "enum", "",0 + Property: "UVSwap", "bool", "",0''') + + file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX) + file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY) + + file.write(''' + Property: "TextureRotationPivot", "Vector3D", "",0,0,0 + Property: "TextureScalingPivot", "Vector3D", "",0,0,0 + Property: "VideoProperty", "object", "" + }''') + + file.write('\n\t\tMedia: "Video::%s"' % texname) + if tex: + fname = tex.filename + file.write('\n\t\tFileName: "%s"' % strip_path(fname)) + file.write('\n\t\tRelativeFilename: "fbx/%s"' % strip_path(fname)) # need some make relative command + else: + file.write('\n\t\tFileName: ""') + file.write('\n\t\tRelativeFilename: "fbx"') + + file.write(''' + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + }''') + + def write_deformer_skin(obname): + ''' + Each mesh has its own deformer + ''' + file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname) + file.write(''' + Version: 100 + MultiLayer: 0 + Type: "Skin" + Properties60: { + } + Link_DeformAcuracy: 50 + }''') + + # in the example was 'Bip01 L Thigh_2' + def write_sub_deformer_skin(my_mesh, my_bone, weights): + + ''' + Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers + So the SubDeformer needs the mesh-object name as a prefix to make it unique + + Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer, + a but silly but dosnt really matter + ''' + file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName)) + + file.write(''' + Version: 100 + MultiLayer: 0 + Type: "Cluster" + Properties60: { + Property: "SrcModel", "object", "" + Property: "SrcModelReference", "object", "" + } + UserData: "", ""''') + + # Support for bone parents + if my_mesh.fbxBoneParent: + if my_mesh.fbxBoneParent == my_bone: + # TODO - this is a bit lazy, we could have a simple write loop + # for this case because all weights are 1.0 but for now this is ok + # Parent Bones arent used all that much anyway. + vgroup_data = [(j, 1.0) for j in xrange(len(my_mesh.blenData.verts))] + else: + # This bone is not a parent of this mesh object, no weights + vgroup_data = [] + + else: + # Normal weight painted mesh + if my_bone.blenName in weights[0]: + # Before we used normalized wright list + #vgroup_data = me.getVertsFromGroup(bone.name, 1) + group_index = weights[0].index(my_bone.blenName) + vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]] + else: + vgroup_data = [] + + file.write('\n\t\tIndexes: ') + + i = -1 + for vg in vgroup_data: + if i == -1: + file.write('%i' % vg[0]) + i=0 + else: + if i==23: + file.write('\n\t\t') + i=0 + file.write(',%i' % vg[0]) + i+=1 + + file.write('\n\t\tWeights: ') + i = -1 + for vg in vgroup_data: + if i == -1: + file.write('%.8f' % vg[1]) + i=0 + else: + if i==38: + file.write('\n\t\t') + i=0 + file.write(',%.8f' % vg[1]) + i+=1 + + if my_mesh.fbxParent: + # TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible! + m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) + else: + # Yes! this is it... - but dosnt work when the mesh is a. + m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() ) + + #m = mtx4_z90 * my_bone.restMatrix + matstr = mat4x4str(m) + matstr_i = mat4x4str(m.invert()) + + file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/ + file.write('\n\t\tTransformLink: %s' % matstr) + file.write('\n\t}') + + def write_mesh(my_mesh): + + me = my_mesh.blenData + + # if there are non NULL materials on this mesh + if [mat for mat in my_mesh.blenMaterials if mat]: do_materials = True + else: do_materials = False + + if my_mesh.blenTextures: do_textures = True + else: do_textures = False + + + file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName) + file.write('\n\t\tVersion: 232') # newline is added in write_object_props + + write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix()) + + file.write('\n\t\t}') + file.write('\n\t\tMultiLayer: 0') + file.write('\n\t\tMultiTake: 1') + file.write('\n\t\tShading: Y') + file.write('\n\t\tCulling: "CullingOff"') + + + # Write the Real Mesh data here + file.write('\n\t\tVertices: ') + i=-1 + + for v in me.verts: + if i==-1: + file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0 + else: + if i==7: + file.write('\n\t\t'); i=0 + file.write(',%.6f,%.6f,%.6f'% tuple(v.co)) + i+=1 + + file.write('\n\t\tPolygonVertexIndex: ') + i=-1 + for f in me.faces: + fi = [v.index for v in f] + # flip the last index, odd but it looks like + # this is how fbx tells one face from another + fi[-1] = -(fi[-1]+1) + fi = tuple(fi) + if i==-1: + if len(f) == 3: file.write('%i,%i,%i' % fi ) + else: file.write('%i,%i,%i,%i' % fi ) + i=0 + else: + if i==13: + file.write('\n\t\t') + i=0 + if len(f) == 3: file.write(',%i,%i,%i' % fi ) + else: file.write(',%i,%i,%i,%i' % fi ) + i+=1 + + ed_val = [None, None] + LOOSE = Blender.Mesh.EdgeFlags.LOOSE + for ed in me.edges: + if ed.flag & LOOSE: + ed_val[0] = ed.v1.index + ed_val[1] = -(ed.v2.index+1) + if i==-1: + file.write('%i,%i' % tuple(ed_val) ) + i=0 + else: + if i==13: + file.write('\n\t\t') + i=0 + file.write(',%i,%i' % tuple(ed_val) ) + i+=1 + del LOOSE + + file.write('\n\t\tGeometryVersion: 124') + + file.write(''' + LayerElementNormal: 0 { + Version: 101 + Name: "" + MappingInformationType: "ByVertice" + ReferenceInformationType: "Direct" + Normals: ''') + + i=-1 + for v in me.verts: + if i==-1: + file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 + else: + if i==2: + file.write('\n '); i=0 + file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) + i+=1 + file.write('\n\t\t}') + + # Write VertexColor Layers + # note, no programs seem to use this info :/ + collayers = [] + if me.vertexColors: + collayers = me.getColorLayerNames() + collayer_orig = me.activeColorLayer + for colindex, collayer in enumerate(collayers): + me.activeColorLayer = collayer + file.write('\n\t\tLayerElementColor: %i {' % colindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % collayer) + + file.write(''' + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + Colors: ''') + + i = -1 + ii = 0 # Count how many Colors we write + + for f in me.faces: + for col in f.col: + if i==-1: + file.write('%i,%i,%i' % (col[0], col[1], col[2])) + i=0 + else: + if i==7: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i,%i,%i' % (col[0], col[1], col[2])) + i+=1 + ii+=1 # One more Color + + file.write('\n\t\t\tColorIndex: ') + i = -1 + for j in xrange(ii): + if i == -1: + file.write('%i' % j) + i=0 + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i' % j) + i+=1 + + file.write('\n\t\t}') + + + + # Write UV and texture layers. + uvlayers = [] + if me.faceUV: + uvlayers = me.getUVLayerNames() + uvlayer_orig = me.activeUVLayer + for uvindex, uvlayer in enumerate(uvlayers): + me.activeUVLayer = uvlayer + file.write('\n\t\tLayerElementUV: %i {' % uvindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % uvlayer) + + file.write(''' + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: ''') + + i = -1 + ii = 0 # Count how many UVs we write + + for f in me.faces: + for uv in f.uv: + if i==-1: + file.write('%.6f,%.6f' % tuple(uv)) + i=0 + else: + if i==7: + file.write('\n ') + i=0 + file.write(',%.6f,%.6f' % tuple(uv)) + i+=1 + ii+=1 # One more UV + + file.write('\n\t\t\tUVIndex: ') + i = -1 + for j in xrange(ii): + if i == -1: + file.write('%i' % j) + i=0 + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + file.write(',%i' % j) + i+=1 + + file.write('\n\t\t}') + + if do_textures: + file.write('\n\t\tLayerElementTexture: %i {' % uvindex) + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: "%s"' % uvlayer) + + if len(my_mesh.blenTextures) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tBlendMode: "Translucent"') + file.write('\n\t\t\tTextureAlpha: 1') + file.write('\n\t\t\tTextureId: ') + + if len(my_mesh.blenTextures) == 1: + file.write('0') + else: + #texture_mapping_local = {None:0} + texture_mapping_local = {None:-1} + + i = 0 # 1 for dummy + for tex in my_mesh.blenTextures: + texture_mapping_local[tex] = i + i+=1 + + i=-1 + for f in me.faces: + img_key = f.image + + if i==-1: + i=0 + file.write( '%s' % texture_mapping_local[img_key]) + else: + if i==55: + file.write('\n ') + i=0 + + file.write(',%s' % texture_mapping_local[img_key]) + i+=1 + + else: + file.write(''' + LayerElementTexture: 0 { + Version: 101 + Name: "" + MappingInformationType: "NoMappingInformation" + ReferenceInformationType: "IndexToDirect" + BlendMode: "Translucent" + TextureAlpha: 1 + TextureId: ''') + file.write('\n\t\t}') + + me.activeUVLayer = uvlayer_orig + + # Done with UV/textures. + + if do_materials: + file.write('\n\t\tLayerElementMaterial: 0 {') + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: ""') + + if len(my_mesh.blenMaterials) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tMaterials: ') + + if len(my_mesh.blenMaterials) == 1: + file.write('0') + else: + # Build a material mapping for this + #material_mapping_local = [0] * 16 # local-index : global index. + material_mapping_local = [-1] * 16 # local-index : global index. + i= 0 # 1 + for j, mat in enumerate(my_mesh.blenMaterials): + if mat: + material_mapping_local[j] = i + i+=1 + # else leave as -1 + + len_material_mapping_local = len(material_mapping_local) + + i=-1 + for f in me.faces: + f_mat = f.mat + if f_mat >= len_material_mapping_local: + f_mat = 0 + + if i==-1: + i=0 + file.write( '%s' % (material_mapping_local[f_mat])) + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + + file.write(',%s' % (material_mapping_local[f_mat])) + i+=1 + + file.write('\n\t\t}') + + file.write(''' + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + }''') + + if do_materials: + file.write(''' + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + }''') + + # Always write this + if do_textures: + file.write(''' + LayerElement: { + Type: "LayerElementTexture" + TypedIndex: 0 + }''') + + if me.vertexColors: + file.write(''' + LayerElement: { + Type: "LayerElementColor" + TypedIndex: 0 + }''') + + if me.faceUV: + file.write(''' + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + }''') + + + file.write('\n\t\t}') + + if len(uvlayers) > 1: + for i in xrange(1, len(uvlayers)): + + file.write('\n\t\tLayer: %i {' % i) + file.write('\n\t\t\tVersion: 100') + + file.write(''' + LayerElement: { + Type: "LayerElementUV"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + + if do_textures: + + file.write(''' + LayerElement: { + Type: "LayerElementTexture"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + + file.write('\n\t\t}') + + if len(collayers) > 1: + # Take into account any UV layers + layer_offset = 0 + if uvlayers: layer_offset = len(uvlayers)-1 + + for i in xrange(layer_offset, len(collayers)+layer_offset): + file.write('\n\t\tLayer: %i {' % i) + file.write('\n\t\t\tVersion: 100') + + file.write(''' + LayerElement: { + Type: "LayerElementColor"''') + + file.write('\n\t\t\t\tTypedIndex: %i' % i) + file.write('\n\t\t\t}') + file.write('\n\t\t}') + file.write('\n\t}') + + def write_group(name): + file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {' % name) + + file.write(''' + Properties60: { + Property: "MultiLayer", "bool", "",0 + Property: "Pickable", "bool", "",1 + Property: "Transformable", "bool", "",1 + Property: "Show", "bool", "",1 + } + MultiLayer: 0 + }''') + + + # add meshes here to clear because they are not used anywhere. + meshes_to_clear = [] + + ob_meshes = [] + ob_lights = [] + ob_cameras = [] + # in fbx we export bones as children of the mesh + # armatures not a part of a mesh, will be added to ob_arms + ob_bones = [] + ob_arms = [] + ob_null = [] # emptys + + # List of types that have blender objects (not bones) + ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null] + + groups = [] # blender groups, only add ones that have objects in the selections + materials = {} + textures = {} + + tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error + + # if EXP_OBS_SELECTED is false, use sceens objects + if not batch_objects: + if EXP_OBS_SELECTED: tmp_objects = sce.objects.context + else: tmp_objects = sce.objects + else: + tmp_objects = batch_objects + + if EXP_ARMATURE: + # This is needed so applying modifiers dosnt apply the armature deformation, its also needed + # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes. + # set every armature to its rest, backup the original values so we done mess up the scene + ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures] + + for arm in bpy.data.armatures: + arm.restPosition = True + + if ob_arms_orig_rest: + for ob_base in bpy.data.objects: + #if ob_base.type == 'Armature': + ob_base.makeDisplayList() + + # This causes the makeDisplayList command to effect the mesh + Blender.Set('curframe', Blender.Get('curframe')) + + + for ob_base in tmp_objects: + for ob, mtx in BPyObject.getDerivedObjects(ob_base): + #for ob in [ob_base,]: + tmp_ob_type = ob.type + if tmp_ob_type == 'Camera': + if EXP_CAMERA: + ob_cameras.append(my_object_generic(ob, mtx)) + elif tmp_ob_type == 'Lamp': + if EXP_LAMP: + ob_lights.append(my_object_generic(ob, mtx)) + elif tmp_ob_type == 'Armature': + if EXP_ARMATURE: + # TODO - armatures dont work in dupligroups! + if ob not in ob_arms: ob_arms.append(ob) + # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)" + elif tmp_ob_type == 'Empty': + if EXP_EMPTY: + ob_null.append(my_object_generic(ob, mtx)) + elif EXP_MESH: + origData = True + if tmp_ob_type != 'Mesh': + me = bpy.data.meshes.new() + try: me.getFromObject(ob) + except: me = None + if me: + meshes_to_clear.append( me ) + mats = me.materials + origData = False + else: + # Mesh Type! + if EXP_MESH_APPLY_MOD: + me = bpy.data.meshes.new() + me.getFromObject(ob) + + # so we keep the vert groups + if EXP_ARMATURE: + orig_mesh = ob.getData(mesh=1) + if orig_mesh.getVertGroupNames(): + ob.copy().link(me) + # If new mesh has no vgroups we can try add if verts are teh same + if not me.getVertGroupNames(): # vgroups were not kept by the modifier + if len(me.verts) == len(orig_mesh.verts): + groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh) + BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) + + # print ob, me, me.getVertGroupNames() + meshes_to_clear.append( me ) + origData = False + mats = me.materials + else: + me = ob.getData(mesh=1) + mats = me.materials + + # Support object colors + tmp_colbits = ob.colbits + if tmp_colbits: + tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too. + for i in xrange(16): + if tmp_colbits & (1< fbxObject mapping + # this is needed for groups as well as fbxParenting + bpy.data.objects.tag = False + tmp_obmapping = {} + for ob_generic in ob_all_typegroups: + for ob_base in ob_generic: + ob_base.blenObject.tag = True + tmp_obmapping[ob_base.blenObject] = ob_base + + # Build Groups from objects we export + for blenGroup in bpy.data.groups: + fbxGroupName = None + for ob in blenGroup.objects: + if ob.tag: + if fbxGroupName == None: + fbxGroupName = sane_groupname(blenGroup) + groups.append((fbxGroupName, blenGroup)) + + tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames + + groups.sort() # not really needed + + # Assign parents using this mapping + for ob_generic in ob_all_typegroups: + for my_ob in ob_generic: + parent = my_ob.blenObject.parent + if parent and parent.tag: # does it exist and is it in the mapping + my_ob.fbxParent = tmp_obmapping[parent] + + + del tmp_obmapping + # Finished finding groups we use + + + materials = [(sane_matname(mat), mat) for mat in materials.itervalues() if mat] + textures = [(sane_texname(img), img) for img in textures.itervalues() if img] + materials.sort() # sort by name + textures.sort() + + camera_count = 8 + file.write(''' + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: %i''' % (\ + 1+1+camera_count+\ + len(ob_meshes)+\ + len(ob_lights)+\ + len(ob_cameras)+\ + len(ob_arms)+\ + len(ob_null)+\ + len(ob_bones)+\ + bone_deformer_count+\ + len(materials)+\ + (len(textures)*2))) # add 1 for the root model 1 for global settings + + del bone_deformer_count + + file.write(''' + ObjectType: "Model" { + Count: %i + }''' % (\ + 1+camera_count+\ + len(ob_meshes)+\ + len(ob_lights)+\ + len(ob_cameras)+\ + len(ob_arms)+\ + len(ob_null)+\ + len(ob_bones))) # add 1 for the root model + + file.write(''' + ObjectType: "Geometry" { + Count: %i + }''' % len(ob_meshes)) + + if materials: + file.write(''' + ObjectType: "Material" { + Count: %i + }''' % len(materials)) + + if textures: + file.write(''' + ObjectType: "Texture" { + Count: %i + }''' % len(textures)) # add 1 for an empty tex + file.write(''' + ObjectType: "Video" { + Count: %i + }''' % len(textures)) # add 1 for an empty tex + + tmp = 0 + # Add deformer nodes + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + tmp+=1 + + # Add subdeformers + for my_bone in ob_bones: + tmp += len(my_bone.blenMeshes) + + if tmp: + file.write(''' + ObjectType: "Deformer" { + Count: %i + }''' % tmp) + del tmp + + # we could avoid writing this possibly but for now just write it + + file.write(''' + ObjectType: "Pose" { + Count: 1 + }''') + + if groups: + file.write(''' + ObjectType: "GroupSelection" { + Count: %i + }''' % len(groups)) + + file.write(''' + ObjectType: "GlobalSettings" { + Count: 1 + } +}''') + + file.write(''' + +; Object properties +;------------------------------------------------------------------ + +Objects: {''') + + # To comply with other FBX FILES + write_camera_switch() + + # Write the null object + write_null(None, 'blend_root')# , GLOBAL_MATRIX) + + for my_null in ob_null: + write_null(my_null) + + for my_arm in ob_arms: + write_null(my_arm) + + for my_cam in ob_cameras: + write_camera(my_cam) + + for my_light in ob_lights: + write_light(my_light) + + for my_mesh in ob_meshes: + write_mesh(my_mesh) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + write_bone(my_bone) + + write_camera_default() + + for matname, mat in materials: + write_material(matname, mat) + + # each texture uses a video, odd + for texname, tex in textures: + write_video(texname, tex) + i = 0 + for texname, tex in textures: + write_texture(texname, tex, i) + i+=1 + + for groupname, group in groups: + write_group(groupname) + + # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do. + + # Write armature modifiers + # TODO - add another MODEL? - because of this skin definition. + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + write_deformer_skin(my_mesh.fbxName) + + # Get normalized weights for temorary use + if my_mesh.fbxBoneParent: + weights = None + else: + weights = meshNormalizedWeights(my_mesh.blenData) + + #for bonename, bone, obname, bone_mesh, armob in ob_bones: + for my_bone in ob_bones: + if me in my_bone.blenMeshes.itervalues(): + write_sub_deformer_skin(my_mesh, my_bone, weights) + + # Write pose's really weired, only needed when an armature and mesh are used together + # each by themselves dont need pose data. for now only pose meshes and bones + + file.write(''' + Pose: "Pose::BIND_POSES", "BindPose" { + Type: "BindPose" + Version: 100 + Properties60: { + } + NbPoseNodes: ''') + file.write(str(len(pose_items))) + + + for fbxName, matrix in pose_items: + file.write('\n\t\tPoseNode: {') + file.write('\n\t\t\tNode: "Model::%s"' % fbxName ) + if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix)) + else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity)) + file.write('\n\t\t}') + + file.write('\n\t}') + + + # Finish Writing Objects + # Write global settings + file.write(''' + GlobalSettings: { + Version: 1000 + Properties60: { + Property: "UpAxis", "int", "",1 + Property: "UpAxisSign", "int", "",1 + Property: "FrontAxis", "int", "",2 + Property: "FrontAxisSign", "int", "",1 + Property: "CoordAxis", "int", "",0 + Property: "CoordAxisSign", "int", "",1 + Property: "UnitScaleFactor", "double", "",100 + } + } +''') + file.write('}') + + file.write(''' + +; Object relations +;------------------------------------------------------------------ + +Relations: {''') + + file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}') + + for my_null in ob_null: + file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName) + + for my_arm in ob_arms: + file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName) + + for my_mesh in ob_meshes: + file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName) + + # TODO - limbs can have the same name for multiple armatures, should prefix. + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName) + + for my_cam in ob_cameras: + file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName) + + for my_light in ob_lights: + file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName) + + file.write(''' + Model: "Model::Producer Perspective", "Camera" { + } + Model: "Model::Producer Top", "Camera" { + } + Model: "Model::Producer Bottom", "Camera" { + } + Model: "Model::Producer Front", "Camera" { + } + Model: "Model::Producer Back", "Camera" { + } + Model: "Model::Producer Right", "Camera" { + } + Model: "Model::Producer Left", "Camera" { + } + Model: "Model::Camera Switcher", "CameraSwitcher" { + }''') + + for matname, mat in materials: + file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname) + + if textures: + for texname, tex in textures: + file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}' % texname) + for texname, tex in textures: + file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname) + + # deformers - modifiers + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName + # is this bone effecting a mesh? + file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName)) + + # This should be at the end + # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}') + + for groupname, group in groups: + file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname) + + file.write('\n}') + file.write(''' + +; Object connections +;------------------------------------------------------------------ + +Connections: {''') + + # NOTE - The FBX SDK dosnt care about the order but some importers DO! + # for instance, defining the material->mesh connection + # before the mesh->blend_root crashes cinema4d + + + # write the fake root node + file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"') + + for ob_generic in ob_all_typegroups: # all blender 'Object's we support + for my_ob in ob_generic: + if my_ob.fbxParent: + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName)) + else: + file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_ob.fbxName) + + if materials: + for my_mesh in ob_meshes: + # Connect all materials to all objects, not good form but ok for now. + for mat in my_mesh.blenMaterials: + if mat: + file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh.fbxName)) + + if textures: + for my_mesh in ob_meshes: + if my_mesh.blenTextures: + # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName) + for tex in my_mesh.blenTextures: + if tex: + file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName)) + + for texname, tex in textures: + file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname)) + + for my_mesh in ob_meshes: + if my_mesh.fbxArm: + file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName)) + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() + file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName)) + + # limbs -> deformers + # for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + for fbxMeshObName in my_bone.blenMeshes: # .keys() + file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName)) + + + #for bonename, bone, obname, me, armob in ob_bones: + for my_bone in ob_bones: + # Always parent to armature now + if my_bone.parent: + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) ) + else: + # the armature object is written as an empty and all root level bones connect to it + file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) ) + + # groups + if groups: + for ob_generic in ob_all_typegroups: + for ob_base in ob_generic: + for fbxGroupName in ob_base.fbxGroupNames: + file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName)) + + for my_arm in ob_arms: + file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName) + + file.write('\n}') + + + # Needed for scene footer as well as animation + render = sce.render + + # from the FBX sdk + #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000)) + def fbx_time(t): + # 0.5 + val is the same as rounding. + return int(0.5 + ((t/fps) * 46186158000)) + + fps = float(render.fps) + start = render.sFrame + end = render.eFrame + if end < start: start, end = end, start + if start==end: ANIM_ENABLE = False + + # animations for these object types + ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms + + if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]: + + frame_orig = Blender.Get('curframe') + + if ANIM_OPTIMIZE: + ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION + + # default action, when no actions are avaioable + tmp_actions = [None] # None is the default action + blenActionDefault = None + action_lastcompat = None + + if ANIM_ACTION_ALL: + bpy.data.actions.tag = False + tmp_actions = list(bpy.data.actions) + + + # find which actions are compatible with the armatures + # blenActions is not yet initialized so do it now. + tmp_act_count = 0 + for my_arm in ob_arms: + + # get the default name + if not blenActionDefault: + blenActionDefault = my_arm.blenAction + + arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones]) + + for action in tmp_actions: + + action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) + + if action_chan_names: # at least one channel matches. + my_arm.blenActionList.append(action) + action.tag = True + tmp_act_count += 1 + + # incase there is no actions applied to armatures + action_lastcompat = action + + if tmp_act_count: + # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature. + if not blenActionDefault: + blenActionDefault = action_lastcompat + + del action_lastcompat + + file.write(''' +;Takes and animation section +;---------------------------------------------------- + +Takes: {''') + + if blenActionDefault: + file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault)) + else: + file.write('\n\tCurrent: "Default Take"') + + for blenAction in tmp_actions: + # we have tagged all actious that are used be selected armatures + if blenAction: + if blenAction.tag: + print '\taction: "%s" exporting...' % blenAction.name + else: + print '\taction: "%s" has no armature using it, skipping' % blenAction.name + continue + + if blenAction == None: + # Warning, this only accounts for tmp_actions being [None] + file.write('\n\tTake: "Default Take" {') + act_start = start + act_end = end + else: + # use existing name + if blenAction == blenActionDefault: # have we alredy got the name + file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name]) + else: + file.write('\n\tTake: "%s" {' % sane_takename(blenAction)) + + tmp = blenAction.getFrameNumbers() + if tmp: + act_start = min(tmp) + act_end = max(tmp) + del tmp + else: + # Fallback on this, theres not much else we can do? :/ + # when an action has no length + act_start = start + act_end = end + + # Set the action active + for my_bone in ob_arms: + if blenAction in my_bone.blenActionList: + ob.action = blenAction + # print '\t\tSetting Action!', blenAction + # sce.update(1) + + file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed + file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed + file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed + + file.write(''' + + ;Models animation + ;----------------------------------------------------''') + + + # set pose data for all bones + # do this here incase the action changes + ''' + for my_bone in ob_bones: + my_bone.flushAnimData() + ''' + i = act_start + while i <= act_end: + Blender.Set('curframe', i) + for ob_generic in ob_anim_lists: + for my_ob in ob_generic: + #Blender.Window.RedrawAll() + if ob_generic == ob_meshes and my_ob.fbxArm: + # We cant animate armature meshes! + pass + else: + my_ob.setPoseFrame(i) + + i+=1 + + + #for bonename, bone, obname, me, armob in ob_bones: + for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms): + + for my_ob in ob_generic: + + if ob_generic == ob_meshes and my_ob.fbxArm: + # do nothing, + pass + else: + + file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed + file.write('\n\t\t\tVersion: 1.1') + file.write('\n\t\t\tChannel: "Transform" {') + + context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in xrange(act_start, act_end+1) ] + + # ---------------- + # ---------------- + for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale + + if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translationPart() for mtx in context_bone_anim_mats] + elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats] + else: context_bone_anim_vecs = [mtx[0].scalePart() for mtx in context_bone_anim_mats] + + file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation + + for i in xrange(3): + # Loop on each axis of the bone + file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation + file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) + file.write('\n\t\t\t\t\t\tKeyVer: 4005') + + if not ANIM_OPTIMIZE: + # Just write all frames, simple but in-eficient + file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start)) + file.write('\n\t\t\t\t\t\tKey: ') + frame = act_start + while frame <= act_end: + if frame!=act_start: + file.write(',') + + # Curve types are + # C,n is for bezier? - linear is best for now so we can do simple keyframe removal + file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) + #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) + frame+=1 + else: + # remove unneeded keys, j is the frame, needed when some frames are removed. + context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ] + + # last frame to fisrt frame, missing 1 frame on either side. + # removeing in a backwards loop is faster + for j in xrange( (act_end-act_start)-1, 0, -1 ): + # Is this key reduenant? + if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\ + abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: + del context_bone_anim_keys[j] + + if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]: + # This axis has no moton, its okay to skip KeyCount and Keys in this case + pass + else: + # We only need to write these if there is at least one + file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys)) + file.write('\n\t\t\t\t\t\tKey: ') + for val, frame in context_bone_anim_keys: + if frame != context_bone_anim_keys[0][1]: # not the first + file.write(',') + # frame is alredy one less then blenders frame + file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame), val )) + #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val )) + + if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0') + elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0') + elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1') + + file.write('\n\t\t\t\t\t}') + file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) ) + file.write('\n\t\t\t\t}') + + # --------------- + + file.write('\n\t\t\t}') + file.write('\n\t\t}') + + # end the take + file.write('\n\t}') + + # end action loop. set original actions + # do this after every loop incase actions effect eachother. + for my_bone in ob_arms: + my_bone.blenObject.action = my_bone.blenAction + + file.write('\n}') + + Blender.Set('curframe', frame_orig) + + else: + # no animation + file.write('\n;Takes and animation section') + file.write('\n;----------------------------------------------------') + file.write('\n') + file.write('\nTakes: {') + file.write('\n\tCurrent: ""') + file.write('\n}') + + + # write meshes animation + #for obname, ob, mtx, me, mats, arm, armname in ob_meshes: + + + # Clear mesh data Only when writing with modifiers applied + for me in meshes_to_clear: + me.verts = None + + + + # --------------------------- Footer + if world: + has_mist = world.mode & 1 + mist_intense, mist_start, mist_end, mist_height = world.mist + world_hor = world.hor + else: + has_mist = mist_intense = mist_start = mist_end = mist_height = 0 + world_hor = 0,0,0 + + file.write('\n;Version 5 settings') + file.write('\n;------------------------------------------------------------------') + file.write('\n') + file.write('\nVersion5: {') + file.write('\n\tAmbientRenderSettings: {') + file.write('\n\t\tVersion: 101') + file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb)) + file.write('\n\t}') + file.write('\n\tFogOptions: {') + file.write('\n\t\tFlogEnable: %i' % has_mist) + file.write('\n\t\tFogMode: 0') + file.write('\n\t\tFogDensity: %.3f' % mist_intense) + file.write('\n\t\tFogStart: %.3f' % mist_start) + file.write('\n\t\tFogEnd: %.3f' % mist_end) + file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor)) + file.write('\n\t}') + file.write('\n\tSettings: {') + file.write('\n\t\tFrameRate: "%i"' % int(fps)) + file.write('\n\t\tTimeFormat: 1') + file.write('\n\t\tSnapOnFrames: 0') + file.write('\n\t\tReferenceTimeIndex: -1') + file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start-1)) + file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end-1)) + file.write('\n\t}') + file.write('\n\tRendererSetting: {') + file.write('\n\t\tDefaultCamera: "Producer Perspective"') + file.write('\n\t\tDefaultViewingMode: 0') + file.write('\n\t}') + file.write('\n}') + file.write('\n') + + # Incase sombody imports this, clean up by clearing global dicts + sane_name_mapping_ob.clear() + sane_name_mapping_mat.clear() + sane_name_mapping_tex.clear() + + ob_arms[:] = [] + ob_bones[:] = [] + ob_cameras[:] = [] + ob_lights[:] = [] + ob_meshes[:] = [] + ob_null[:] = [] + + + # copy images if enabled + if EXP_IMAGE_COPY: + copy_images( Blender.sys.dirname(filename), [ tex[1] for tex in textures if tex[1] != None ]) + + print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) + return True + + +# -------------------------------------------- +# UI Function - not a part of the exporter. +# this is to seperate the user interface from the rest of the exporter. +from Blender import Draw, Window +EVENT_NONE = 0 +EVENT_EXIT = 1 +EVENT_REDRAW = 2 +EVENT_FILESEL = 3 + +GLOBALS = {} + +# export opts + +def do_redraw(e,v): GLOBALS['EVENT'] = e + +# toggle between these 2, only allow one on at once +def do_obs_sel(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 0 + GLOBALS['EXP_OBS_SELECTED'].val = 1 + +def do_obs_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 1 + GLOBALS['EXP_OBS_SELECTED'].val = 0 + +def do_obs_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['EXP_OBS_SCENE'].val = 1 + GLOBALS['EXP_OBS_SELECTED'].val = 0 + +def do_batch_type_grp(e,v): + GLOBALS['EVENT'] = e + GLOBALS['BATCH_GROUP'].val = 1 + GLOBALS['BATCH_SCENE'].val = 0 + +def do_batch_type_sce(e,v): + GLOBALS['EVENT'] = e + GLOBALS['BATCH_GROUP'].val = 0 + GLOBALS['BATCH_SCENE'].val = 1 + +def do_anim_act_all(e,v): + GLOBALS['EVENT'] = e + GLOBALS['ANIM_ACTION_ALL'][0].val = 1 + GLOBALS['ANIM_ACTION_ALL'][1].val = 0 + +def do_anim_act_cur(e,v): + if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val: + Draw.PupMenu('Warning%t|Cant use this with batch export group option') + else: + GLOBALS['EVENT'] = e + GLOBALS['ANIM_ACTION_ALL'][0].val = 0 + GLOBALS['ANIM_ACTION_ALL'][1].val = 1 + +def fbx_ui_exit(e,v): + GLOBALS['EVENT'] = e + +def do_help(e,v): + url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx' + print 'Trying to open web browser with documentation at this address...' + print '\t' + url + + try: + import webbrowser + webbrowser.open(url) + except: + print '...could not open a browser window.' + + + +# run when export is pressed +#def fbx_ui_write(e,v): +def fbx_ui_write(filename): + + # Dont allow overwriting files when saving normally + if not GLOBALS['BATCH_ENABLE'].val: + if not BPyMessages.Warning_SaveOver(filename): + return + + GLOBALS['EVENT'] = EVENT_EXIT + + # Keep the order the same as above for simplicity + # the [] is a dummy arg used for objects + + Blender.Window.WaitCursor(1) + + # Make the matrix + GLOBAL_MATRIX = mtx4_identity + GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val + if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n + if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n + if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n + + ret = write(\ + filename, None,\ + GLOBALS['EXP_OBS_SELECTED'].val,\ + GLOBALS['EXP_MESH'].val,\ + GLOBALS['EXP_MESH_APPLY_MOD'].val,\ + GLOBALS['EXP_MESH_HQ_NORMALS'].val,\ + GLOBALS['EXP_ARMATURE'].val,\ + GLOBALS['EXP_LAMP'].val,\ + GLOBALS['EXP_CAMERA'].val,\ + GLOBALS['EXP_EMPTY'].val,\ + GLOBALS['EXP_IMAGE_COPY'].val,\ + GLOBAL_MATRIX,\ + GLOBALS['ANIM_ENABLE'].val,\ + GLOBALS['ANIM_OPTIMIZE'].val,\ + GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,\ + GLOBALS['ANIM_ACTION_ALL'][0].val,\ + GLOBALS['BATCH_ENABLE'].val,\ + GLOBALS['BATCH_GROUP'].val,\ + GLOBALS['BATCH_SCENE'].val,\ + GLOBALS['BATCH_FILE_PREFIX'].val,\ + GLOBALS['BATCH_OWN_DIR'].val,\ + ) + + Blender.Window.WaitCursor(0) + GLOBALS.clear() + + if ret == False: + Draw.PupMenu('Error%t|Path cannot be written to!') + + +def fbx_ui(): + # Only to center the UI + x,y = GLOBALS['MOUSE'] + x-=180; y-=0 # offset... just to get it centered + + Draw.Label('Export Objects...', x+20,y+165, 200, 20) + + if not GLOBALS['BATCH_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['EXP_OBS_SELECTED'] = Draw.Toggle('Selected Objects', EVENT_REDRAW, x+20, y+145, 160, 20, GLOBALS['EXP_OBS_SELECTED'].val, 'Export selected objects on visible layers', do_obs_sel) + GLOBALS['EXP_OBS_SCENE'] = Draw.Toggle('Scene Objects', EVENT_REDRAW, x+180, y+145, 160, 20, GLOBALS['EXP_OBS_SCENE'].val, 'Export all objects in this scene', do_obs_sce) + Draw.EndAlign() + + Draw.BeginAlign() + GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Scale all data, (Note! some imports dont support scaled armatures)') + GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Rotate all objects 90 degrese about the X axis') + GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Rotate all objects 90 degrese about the Y axis') + GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Rotate all objects 90 degrese about the Z axis') + Draw.EndAlign() + + y -= 35 + + Draw.BeginAlign() + GLOBALS['EXP_EMPTY'] = Draw.Toggle('Empty', EVENT_NONE, x+20, y+120, 60, 20, GLOBALS['EXP_EMPTY'].val, 'Export empty objects') + GLOBALS['EXP_CAMERA'] = Draw.Toggle('Camera', EVENT_NONE, x+80, y+120, 60, 20, GLOBALS['EXP_CAMERA'].val, 'Export camera objects') + GLOBALS['EXP_LAMP'] = Draw.Toggle('Lamp', EVENT_NONE, x+140, y+120, 60, 20, GLOBALS['EXP_LAMP'].val, 'Export lamp objects') + GLOBALS['EXP_ARMATURE'] = Draw.Toggle('Armature', EVENT_NONE, x+200, y+120, 60, 20, GLOBALS['EXP_ARMATURE'].val, 'Export armature objects') + GLOBALS['EXP_MESH'] = Draw.Toggle('Mesh', EVENT_REDRAW, x+260, y+120, 80, 20, GLOBALS['EXP_MESH'].val, 'Export mesh objects', do_redraw) #, do_axis_z) + Draw.EndAlign() + + if GLOBALS['EXP_MESH'].val: + # below mesh but + Draw.BeginAlign() + GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Toggle('Modifiers', EVENT_NONE, x+260, y+100, 80, 20, GLOBALS['EXP_MESH_APPLY_MOD'].val, 'Apply modifiers to mesh objects') #, do_axis_z) + GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Toggle('HQ Normals', EVENT_NONE, x+260, y+80, 80, 20, GLOBALS['EXP_MESH_HQ_NORMALS'].val, 'Generate high quality normals') #, do_axis_z) + Draw.EndAlign() + + GLOBALS['EXP_IMAGE_COPY'] = Draw.Toggle('Copy Image Files', EVENT_NONE, x+20, y+80, 160, 20, GLOBALS['EXP_IMAGE_COPY'].val, 'Copy image files to the destination path') #, do_axis_z) + + + Draw.Label('Export Armature Animation...', x+20,y+45, 300, 20) + + GLOBALS['ANIM_ENABLE'] = Draw.Toggle('Enable Animation', EVENT_REDRAW, x+20, y+25, 160, 20, GLOBALS['ANIM_ENABLE'].val, 'Export keyframe animation', do_redraw) + if GLOBALS['ANIM_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['ANIM_OPTIMIZE'] = Draw.Toggle('Optimize Keyframes', EVENT_REDRAW, x+20, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE'].val, 'Remove double keyframes', do_redraw) + if GLOBALS['ANIM_OPTIMIZE'].val: + GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Number('Precission: ', EVENT_NONE, x+180, y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val, 3, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)') + Draw.EndAlign() + + Draw.BeginAlign() + GLOBALS['ANIM_ACTION_ALL'][1] = Draw.Toggle('Current Action', EVENT_REDRAW, x+20, y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][1].val, 'Use actions currently applied to the armatures (use scene start/end frame)', do_anim_act_cur) + GLOBALS['ANIM_ACTION_ALL'][0] = Draw.Toggle('All Actions', EVENT_REDRAW, x+180,y-25, 160, 20, GLOBALS['ANIM_ACTION_ALL'][0].val, 'Use all actions for armatures', do_anim_act_all) + Draw.EndAlign() + + + Draw.Label('Export Batch...', x+20,y-60, 300, 20) + GLOBALS['BATCH_ENABLE'] = Draw.Toggle('Enable Batch', EVENT_REDRAW, x+20, y-80, 160, 20, GLOBALS['BATCH_ENABLE'].val, 'Automate exporting multiple scenes or groups to files', do_redraw) + + if GLOBALS['BATCH_ENABLE'].val: + Draw.BeginAlign() + GLOBALS['BATCH_GROUP'] = Draw.Toggle('Group > File', EVENT_REDRAW, x+20, y-105, 160, 20, GLOBALS['BATCH_GROUP'].val, 'Export each group as an FBX file', do_batch_type_grp) + GLOBALS['BATCH_SCENE'] = Draw.Toggle('Scene > File', EVENT_REDRAW, x+180, y-105, 160, 20, GLOBALS['BATCH_SCENE'].val, 'Export each scene as an FBX file', do_batch_type_sce) + + # Own dir requires OS module + if os: + GLOBALS['BATCH_OWN_DIR'] = Draw.Toggle('Own Dir', EVENT_NONE, x+20, y-125, 80, 20, GLOBALS['BATCH_OWN_DIR'].val, 'Create a dir for each exported file') + GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+100, y-125, 240, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') + else: + GLOBALS['BATCH_FILE_PREFIX'] = Draw.String('Prefix: ', EVENT_NONE, x+20, y-125, 320, 20, GLOBALS['BATCH_FILE_PREFIX'].val, 64, 'Prefix each file with this name ') + + + Draw.EndAlign() + + #y+=80 + + ''' + Draw.BeginAlign() + GLOBALS['FILENAME'] = Draw.String('path: ', EVENT_NONE, x+20, y-170, 300, 20, GLOBALS['FILENAME'].val, 64, 'Prefix each file with this name ') + Draw.PushButton('..', EVENT_FILESEL, x+320, y-170, 20, 20, 'Select the path', do_redraw) + ''' + # Until batch is added + # + + + #Draw.BeginAlign() + Draw.PushButton('Online Help', EVENT_REDRAW, x+20, y-160, 100, 20, 'Open online help in a browser window', do_help) + Draw.PushButton('Cancel', EVENT_EXIT, x+130, y-160, 100, 20, 'Exit the exporter', fbx_ui_exit) + Draw.PushButton('Export', EVENT_FILESEL, x+240, y-160, 100, 20, 'Export the fbx file', do_redraw) + + #Draw.PushButton('Export', EVENT_EXIT, x+180, y-160, 160, 20, 'Export the fbx file', fbx_ui_write) + #Draw.EndAlign() + + # exit when mouse out of the view? + # GLOBALS['EVENT'] = EVENT_EXIT + +#def write_ui(filename): +def write_ui(): + + # globals + GLOBALS['EVENT'] = 2 + #GLOBALS['MOUSE'] = Window.GetMouseCoords() + GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()] + GLOBALS['FILENAME'] = '' + ''' + # IF called from the fileselector + if filename == None: + GLOBALS['FILENAME'] = filename # Draw.Create(Blender.sys.makename(ext='.fbx')) + else: + GLOBALS['FILENAME'].val = filename + ''' + GLOBALS['EXP_OBS_SELECTED'] = Draw.Create(1) # dont need 2 variables but just do this for clarity + GLOBALS['EXP_OBS_SCENE'] = Draw.Create(0) + + GLOBALS['EXP_MESH'] = Draw.Create(1) + GLOBALS['EXP_MESH_APPLY_MOD'] = Draw.Create(1) + GLOBALS['EXP_MESH_HQ_NORMALS'] = Draw.Create(0) + GLOBALS['EXP_ARMATURE'] = Draw.Create(1) + GLOBALS['EXP_LAMP'] = Draw.Create(1) + GLOBALS['EXP_CAMERA'] = Draw.Create(1) + GLOBALS['EXP_EMPTY'] = Draw.Create(1) + GLOBALS['EXP_IMAGE_COPY'] = Draw.Create(0) + # animation opts + GLOBALS['ANIM_ENABLE'] = Draw.Create(1) + GLOBALS['ANIM_OPTIMIZE'] = Draw.Create(1) + GLOBALS['ANIM_OPTIMIZE_PRECISSION'] = Draw.Create(6) # decimal places + GLOBALS['ANIM_ACTION_ALL'] = [Draw.Create(0), Draw.Create(1)] # not just the current action + + # batch export options + GLOBALS['BATCH_ENABLE'] = Draw.Create(0) + GLOBALS['BATCH_GROUP'] = Draw.Create(1) # cant have both of these enabled at once. + GLOBALS['BATCH_SCENE'] = Draw.Create(0) # see above + GLOBALS['BATCH_FILE_PREFIX'] = Draw.Create(Blender.sys.makename(ext='_').split('\\')[-1].split('/')[-1]) + GLOBALS['BATCH_OWN_DIR'] = Draw.Create(0) + # done setting globals + + # Used by the user interface + GLOBALS['_SCALE'] = Draw.Create(1.0) + GLOBALS['_XROT90'] = Draw.Create(True) + GLOBALS['_YROT90'] = Draw.Create(False) + GLOBALS['_ZROT90'] = Draw.Create(False) + + # horrible ugly hack so tooltips draw, dosnt always work even + # Fixed in Draw.UIBlock for 2.45rc2, but keep this until 2.45 is released + Window.SetKeyQualifiers(0) + while Window.GetMouseButtons(): Blender.sys.sleep(10) + for i in xrange(100): Window.QHandle(i) + # END HORRID HACK + + # best not do move the cursor + # Window.SetMouseCoords(*[i/2 for i in Window.GetScreenSize()]) + + # hack so the toggle buttons redraw. this is not nice at all + while GLOBALS['EVENT'] != EVENT_EXIT: + + if GLOBALS['BATCH_ENABLE'].val and GLOBALS['BATCH_GROUP'].val and GLOBALS['ANIM_ACTION_ALL'][1].val: + #Draw.PupMenu("Warning%t|Cant batch export groups with 'Current Action' ") + GLOBALS['ANIM_ACTION_ALL'][0].val = 1 + GLOBALS['ANIM_ACTION_ALL'][1].val = 0 + + if GLOBALS['EVENT'] == EVENT_FILESEL: + if GLOBALS['BATCH_ENABLE'].val: + txt = 'Batch FBX Dir' + name = Blender.sys.expandpath('//') + else: + txt = 'Export FBX' + name = Blender.sys.makename(ext='.fbx') + + Blender.Window.FileSelector(fbx_ui_write, txt, name) + #fbx_ui_write('/test.fbx') + break + + Draw.UIBlock(fbx_ui) + + + # GLOBALS.clear() +#test = [write_ui] +if __name__ == '__main__': + # Cant call the file selector first because of a bug in the interface that crashes it. + # Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx')) + #write('/scratch/test.fbx') + #write_ui('/scratch/test.fbx') + + if not set: + Draw.PupMenu('Error%t|A full install of python2.3 or python 2.4+ is needed to run this script.') + else: + write_ui() diff --git a/release/scripts/export_lightwave_motion.py b/release/scripts/export_lightwave_motion.py new file mode 100644 index 00000000000..cabc4cf5fc6 --- /dev/null +++ b/release/scripts/export_lightwave_motion.py @@ -0,0 +1,156 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Lightwave Motion (.mot)...' +Blender: 241 +Group: 'Export' +Tip: 'Export Loc Rot Size chanels to a Lightwave .mot file' +""" + +__author__ = "Daniel Salazar (ZanQdo)" +__url__ = ("blender", "elysiun", +"e-mail: zanqdo@gmail.com") +__version__ = "24/03/06" + +__bpydoc__ = """\ +This script exports the selected object's motion channels to a Lightwave +motion file (.mot). + +Usage: +Run the script with one or more objects selected (any kind), frames exported +are between Start and End frames in Render buttons. + +""" + +# $Id$ +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2003, 2004: A Vanpoucke +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +import Blender as B +#------------------------------------ +#Declarados: +TotalCanales = 9 +#------------------------------------ + +def FuncionPrincipal (Dir): + B.Window.WaitCursor(1) + ObjSelect = B.Object.GetSelected() + + if not ObjSelect: + B.Draw.PupMenu('Select 1 or more objects, aborting.') + return + + if not Dir.lower().endswith('.mot'): + Dir += '.mot' + + + SC = B.Scene.GetCurrent() + SCR = SC.getRenderingContext() + + for ob in ObjSelect: + origName= NombreObjeto= ob.name + print '----\nExporting Object "%s" motion file...' % origName + + FrameA = B.Get('curframe') + FrameP = B.Get('staframe') + FrameF = B.Get('endframe') + + FrameRate = float(SCR.framesPerSec()) + + #--------------------------------------------- + + # Replace danger characters by '_' + for ch in ' /\\~!@#$%^&*()+=[];\':",./<>?\t\r\n': + NombreObjeto = NombreObjeto.replace(ch, '_') + + # Check for file path extension + if len(ObjSelect) > 1: + DirN= '%s_%s.mot' % (Dir[:-4], NombreObjeto) + else: + DirN= Dir + + # Open the file + File = open(DirN,'w') + File.write ('LWMO\n3\n\n') # 3 is the version number. + + # number of channels + File.write ('NumChannels %i\n' % TotalCanales) + + # ---------------------------- + # Main Cycle + + def CicloPrimario(NumCanal): + B.Set('curframe', FrameP) + + File.write ('Channel %i\n{ Envelope\n %i\n' % (NumCanal, (FrameF - FrameP + 1))) + + FrameA = FrameP + while FrameA < (FrameF + 1): + + B.Set('curframe', FrameA) + + mat= ob.mat # Worldspace matrix + + if NumCanal == 0: + Val = mat.translationPart().x + elif NumCanal == 1: + Val = mat.translationPart().z + elif NumCanal == 2: + Val = mat.translationPart().y + elif NumCanal == 3: + Val = -mat.toEuler().z + elif NumCanal == 4: + Val = -mat.toEuler().x + elif NumCanal == 5: + Val = -mat.toEuler().y + elif NumCanal == 6: + Val = mat.scalePart().x + elif NumCanal == 7: + Val = mat.scalePart().z + elif NumCanal == 8: + Val = mat.scalePart().y + File.write (' Key %f %f 3 0 0 0 0 0 0\n' % (Val, (FrameA/FrameRate))) + + FrameA += 1 + # Ending Stuff + File.write (' Behaviors 1 1\n}\n') + + NumObjetoActual = len(ObjSelect) + Iteraciones = 0 + ProgBarVal = 0.0 + while Iteraciones < TotalCanales: + CicloPrimario(Iteraciones) + + # Start Progress Bar + B.Window.DrawProgressBar(ProgBarVal, origName) + ProgBarVal = (float(Iteraciones) / TotalCanales) * 0.98 + Iteraciones += 1 + + B.Window.DrawProgressBar(1.0, '') # Done + print '\nDone, %s motion file location is:\n%s\n' % (origName, DirN) + B.Window.WaitCursor(0) + +# Check if there are selected objects +def main(): + B.Window.FileSelector(FuncionPrincipal, "Write .mot File", B.sys.makename(ext='.mot')) + +if __name__=='__main__': + main() \ No newline at end of file diff --git a/release/scripts/export_m3g.py b/release/scripts/export_m3g.py new file mode 100644 index 00000000000..afb019fcc1e --- /dev/null +++ b/release/scripts/export_m3g.py @@ -0,0 +1,3047 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'M3G (.m3g, .java)...' +Blender: 244 +Group: 'Export' +Tooltip: 'Export to M3G' +""" +#------------------------------------------------------------------------ +# M3G exporter for blender 2.37 or above +# +# Source: http://www.nelson-games.de/bl2m3g/source +# +# $Id: m3g_export.py,v 0.1 2005/04/19 12:25 gerhardv Exp gerhardv $ +# +# Author: Gerhard Völkl +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2005: gerhard völkl gkvoelkl@yahoo.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# ***** END GPL LICENCE BLOCK ***** +# +# To use script: +# 1.) load this file in the text window. +# (press SHIFT+F11, Open New via Datablock button) +# 2.) make sure your mouse is over the text edit window and +# run this script. (press ALT+P) +# Or: +# copy to the scripts directory and it will appear in the +# export list. (Needs 2.32 or higher) +# +# Based on informations from: +# wrl2export.py from Rick Kimball and others +# --------------------------------------------------------------------------# +# History 0.2 +# * maximal Precision in VertexArray (with algorithms from Kalle Raita) +# * IPO Animation with mesh: Rotation, Translation and Size +# History 0.3 +# * to find a 3d object in your java programm you can assign a userID +# your blender object has name 'cube#01' your 3d object will have ID 01 +# the number after '#' is taken +# * more than one material per mesh can be used +# * uv texture support (implemented by Aki Koskinen and Juha Laitinen) +# The image which is bound to the faces will be exportet within m3g-file +# Limitations by M3G-API: +# The width and height of the image must be non-negative powers of two, +# but they need not to be equal. Maximum value is 256. +# *.java export: Only PNG images can be used. +# History 0.4 +# * check limitation of texture images (credit to MASTER_ZION for Brasil) +# * Better light: The light modeles of Blender and M3G are naturally +# different. So the export script trys to translate as much as possible +# +# M3G Light type Blender Light type +# -------------------------------------------------------------- +# AMIENT Light Not available as light type in Blender +# DIRECTIONAL Light SUN +# OMNIdirectional light LAMP +# SPOT light SPOT +# not translated HEMI +# not translated AREA +# +# Attributs of M3G Lights: +# +# Attenuation (OMNI,SPOT): +# Intensity of light changes with distance +# The attenuation factor is 1 / (c + l d + q d2) +# where d is the distance between the light and the vertex being lighted +# and c, l, q are the constant, linear, and quadratic coefficients. +# In Blender exists much complex posibilies. To simplify exporter uses +# only button Dist: distance at which the light intensity is half +# the Energy +# Color (ALL) +# Color of light +# Intensity (ALL) +# The RGB color of this Light is multiplied component-wise with the +# intensity. In Blender : energy +# SpotAngle (SPOT) +# the spot cone angle for this Light +# In Blender: spotSize +# SpotExponent (SPOT) +# The spot exponent controls the distribution of the intensity of +# this Light within the spot cone, such that larger values yield +# a more concentrated cone. In Blender: SpotBl +# +# * Some GUI for options +# First prototype of GUI was created using RipSting's Blender-Python +# GUI designer. Download at Http://oregonstate.edu/~dennisa/Blender/BPG/ +# +# * Ambiente light +# Information is taken by world ambiente attribute +# +# * Parenting Part 1 +# In Blender the Empty object is used to group objects. All objects +# which have the same empty as parent are the member of the same group. +# +# empty <-- Parent of -- element 1 +# <-- Parent of -- element 2 +# +# is translated in M3G +# +# group-Node -- Member --> element 1 +# -- Member --> element 2 +# +# In Blender every object can be the parent of every other object +# In M3G that is not possible. Only a group object can be parent. +# (Or the world object which is derived from group). +# That will come later as Parenting Part 2 +# +# * Backface Culling +# you can use backface culling, if option "use backface culloing" is on. +# Culling will be set in PolygonMode object of every mesh. The correct +# winding is controlled. +# History 0.5 +#* Bone Animation - Armature (Part 1) +# +# Armature is the skeleton for skinned meshes. It stores the bones in +# rest position (more information http://www.blender.org/cms/How_Armatures_work.634.0.html) +# You can work in Blender with bones and meshes in different ways. In +# this first attempt only the use of vertex groups is assisted. +# +# Blender-Objekts translated into M3G-Objects +# +# MESH SkinnedMesh +# | | +# v v +# ARMATURE Group +# | | +# v v +# BONE_1 Group +# Group_second +# | | +# V v +# BONE_2 Group +# Group_secound +# +# Every bone is translated into two groups at the moment, because +# the second bone is needed to do the animation in an easy way. +# +# The animations in Blender for meshes are stored in action objects. +# +# Blender Objects translated into M3G-Objects +# +# ARMATURE +# | activ +# v +# ACTION ANIMATIONCONTROLLER +# | 1..n ^ +# v ANIMATIONTRACK --> Group_second +# IPOs | +# v +# KEYSEQUENZE +# +# One action is translated into one animationcontroller. One IPO is +# translated in one KEYSEQUENZE and one ANIMATIONTRACK. +# +# At the moment only the active action of the armature object is translated. +# +#* Print Info, if type of light is used that is not supported +# +# History 0.5 +# +#* New Option exportAllAction (default value: false) +# If that option is true, all actions will be exported - not only the active +# action. +# At the moment you can only assign one action to one armature. +# To know which action is used with which armature the action +# needs a special name : +# #AE# + +# Example: Name of action : walk#A10E250#02 +# Name of armature : man#10 +# End Frame: 250 +# +# History 0.6 +# Include the same image only one time into the m3g-file +# +# All the following changes of this version was made by Claus Hoefele +# +#* Until now all vertices of the faces was been written. +# Now the vertices will be used again if possible: +# normal and texture coordinates of to vertices have to be the same +# +#* Smooth/solid shading can now be defined for every single material: +# in Editing panel (F9)>Link and Materials +# +#* This script uses now correctly the TexFace and Shadless Buttons in +# Shading panel (F5)>Material buttons>Material box. +# TexFace switches on/off the Export of texture coordinates. +# Shadeless does the some with the normal coordinates +# +#* The GUI was redesigned in a PupBlock +# +#* Options: +# +#** Texturing Enabled: Switches on/off export of textures and texture +# coordinates. Attention: the TextFace button switches only +# for one mesh +#** Texturing External: the textures will be included it mg3-file or +# exported in seperate file +#** Lighting Enabled: turns on/off export of lights and normal completly +# Attention: Shadeless only for one mesh +#** Persp. Correction: turns on/off perspective correction in PolygonMode. +#** Smooth Shading: turns on/off smooth shading in PolygonMode. +# +#* Textures in external references are used again (with ImageFactory) +# +#* Blender function: Double Sided button in Editing Context +# (F9)>Mesh panel) +# turn on/off PolygonMode.CULL_BACK anzuschalten. +# +#* Script ingnores meshes that have no faces +# +# History 0.7 +# +# * Exporter can work with texture coordinates greater 1 and smaller 0 +# +# * Adler32 did not work always correct. New implementation made. +# +# * Modul shutil is not needed any longer. Exporter has its own copy_file. +# (realized and inspired by ideasman_42 and Martin Neumann) +# --------------------------------------------------------------------------# +# TODO: Export only selected mesh +# TODO: Optimize Bones <--> Vertex Group mapping +# TODO: Compressed File +# TODO: MTex - Support +# TODO: By Rotating use SQUAD instead of Beziere. It's smoother +import Blender +from Blender import Types,Lamp,Material,Texture,Window,Registry,Draw +from Blender.BGL import * +from Blender.Object import * +from Blender.Camera import * +from Blender.Mesh import * +from array import array +import sys, struct, zlib +from inspect import * +from types import * +from Blender.Mathutils import * +from os.path import * +#import rpdb2 + +# ---- Helper Functions -------------------------------------------------------# +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + +def tracer(frame, event, arg): + '''Global trace function''' + if event=='call': + tmp = getargvalues(frame) + print event, frame.f_code.co_name, frame.f_lineno, \ + formatargvalues(tmp[0],tmp[1],tmp[2],tmp[3]) + elif event=='line': + print event, frame.f_code.co_name, frame.f_lineno + #print event, frame.f_code.co_name, frame.f_lineno, \ + # getsourcelines(frame.f_code)[frame.f_lineno] + elif event=='return': + print event, frame.f_code.co_name, frame.f_lineno, "->", arg + return tracer + +def doSearchDeep(inList,outList): + '''Does deepsearch for all elements in inList''' + for element in inList: + if element != None : outList = element.searchDeep(outList) + return outList + + +def getId(aObject): + ''' returns 0 if Object is None: M3G value for null''' + if aObject == None: return 0 + return aObject.id + +def toJavaBoolean(aValue): + ''' returns java equivalent to boolean''' + if aValue: + return 'true' + else : + return 'false' + +def sign(a): + if a<0 : return -1 + elif a>0 : return 1 + else : return 0 + +def isOrderClockWise(v,normal): + ''' returns true, if order of vertices is clockwise. Important for + culling ''' + # (v2-v0)x(v2-v1)=surface_normal + # + if type(v[0]) is Types.MVertType: + mNormal = TriangleNormal(Vector(v[0].co),Vector(v[1].co),Vector(v[2].co)) + else: + mNormal = TriangleNormal(Vector(v[0]),Vectot(v[1]),Vector(v[2])) + #print "normal ",mNormal.normalize() + #print "BNormal ",normal.normalize() + + # Do not use any longer. Blender does it correct + + result = (sign(normal.x)==sign(mNormal.x) and + sign(normal.y)==sign(mNormal.y) and + sign(normal.z)==sign(mNormal.z)) + #print "Result ",result + + return True + + +# ---- M3G Types --------------------------------------------------------------# +class M3GVertexList: + def __init__(self, wrapList): + self.mlist = wrapList + + def __getitem__(self, key): + item = self.mlist[key] + if type(item) is Types.MVertType: + result =(item.co[0],item.co[1],item.co[2]) + else: + result = item + return result + +class M3GBoneReference: + def __init__(self,first,count): + self.firstVertex=first #UInt32 + self.vertexCount=count #UInt32 + + +class M3GBone: + def __init__(self): + self.verts=[] #List of influenced verts + self.transformNode=None #ObjectIndex + self.references = [] #References to Verts that are needed + self.weight=0 #Int32 + + + def setVerts(self,aVerts): + self.verts = aVerts + self.createReferences() + + def createReferences(self): + #print "createReference::len(verts) ",len(self.verts) + if len(self.verts)==0: return #No Verts available + self.verts.sort() + ref = [] + list = [] + last = self.verts[0]-1 + count = 0 + for vert in self.verts: + #print "vert ",vert + if vert==last+1: + list.append(vert) + else: + ref.append(M3GBoneReference(list[0],len(list))) + #print list[0],len(list) + list=[vert] + last=vert + #print "list ",list + if len(list)>0: + ref.append(M3GBoneReference(list[0],len(list))) + self.references = ref + + +class M3GVector3D: + def __init__(self,ax=0.0,ay=0.0,az=0.0): + self.x = ax #Float32 + self.y = ay #Float32 + self.z = az #Float32 + + def writeJava(self): + return str(self.x)+"f, "+str(self.y)+"f, "+str(self.z)+"f" + + def getData(self): + return struct.pack("<3f",self.x,self.y,self.z) + + def getDataLength(self): + return struct.calcsize("<3f") + +class M3GMatrix: + """ A 4x4 generalized matrix. The 16 elements of the + matrix are output in the same order as they are + retrieved using the API Transform.get method. In + other words, in this order: + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + 12 13 14 15 """ + def __init__(self): + self.elements=16 * [0.0] #Float32 + + def identity(self): + self.elements[ 0] = 1.0 + self.elements[ 5] = 1.0 + self.elements[10] = 1.0 + self.elements[15] = 1.0 + + def getData(self): + return struct.pack('<16f',self.elements[0],self.elements[1], + self.elements[2],self.elements[3], + self.elements[4],self.elements[5], + self.elements[6],self.elements[7], + self.elements[8],self.elements[9], + self.elements[10],self.elements[11], + self.elements[12],self.elements[13], + self.elements[14],self.elements[15]) + + def getDataLength(self): + return struct.calcsize('<16f') + + +class M3GColorRGB: + """ A color, with no alpha information. Each compo- + nent is scaled so that 0x00 is 0.0, and 0xFF is 1.0. + """ + def __init__(self,ared=0,agreen=0,ablue=0): + self.red = ared #Byte + self.green = agreen #Byte + self.blue = ablue #Byte + + def writeJava(self): + return "0x"+("%02X%02X%02X%02X" % (0.0, self.red, self.green, self.blue)) + + def getData(self): + return struct.pack('3B',self.red,self.green,self.blue) + + def getDataLength(self): + return struct.calcsize('3B') + + +class M3GColorRGBA: + """ A color, with alpha information. Each component + is scaled so that 0x00 is 0.0, and 0xFF is 1.0. The + alpha value is scaled so that 0x00 is completely + transparent, and 0xFF is completely opaque. + """ + def __init__(self,ared=0,agreen=0,ablue=0,aalpha=0): + self.red = ared #Byte + self.green = agreen #Byte + self.blue = ablue #Byte + self.alpha = aalpha #Byte + + def writeJava(self): + return "0x"+("%02X%02X%02X%02X" % (self.alpha, self.red, self.green, self.blue)) + + def getData(self): + return struct.pack('4B',self.red,self.green,self.blue,self.alpha) + + def getDataLength(self): + return struct.calcsize('4B') + + +#ObjectIndex +#The index of a previously encountered object in +#the file. Although this is serialized as a single +#unsigned integer, it is included in the compound +#type list because of the additional semantic infor- +#mation embodied in its type. A value of 0 is +#reserved to indicate a null reference; actual object indices start from 1. Object indices must refer +#only to null or to an object which has already been +#created during the input deserialization of a file - +#they must be less than or equal to the index of the +#object in which they appear. Other values are dis- +#allowed and must be treated as errors. +#UInt32 +#index; + +# ---- M3G Proxy --------------------------------------------------------------- # +class M3GProxy: + def __init__(self): + self.name = "" + self.id=0 + self.ObjectType=0 + self.binaryFormat='' + + def __repr__(self): + return "<"+str(self.__class__)[9:] + ":" + str(self.name) + ":" + str(self.id) + ">" + + +class M3GHeaderObject(M3GProxy): + def __init__(self): + M3GProxy.__init__(self) + self.M3GHeaderObject_binaryFormat = ' 0: + value += struct.calcsize('<'+str(len(self.animationTracks))+'I') + return value + + def writeJava(self,aWriter,aCreate): + if aCreate : pass #Abstract! Could not be created + if len(self.animationTracks) > 0 : + aWriter.write(2) + for iTrack in self.animationTracks: + aWriter.write(2,"BL%i.addAnimationTrack(BL%i);" % (self.id,iTrack.id)) + + +class M3GTransformable(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.hasComponentTransform=False #Boolean + #IF hasComponentTransform==TRUE, THEN + self.translation=M3GVector3D(0,0,0) #Vector3D + self.scale=M3GVector3D(1,1,1) #Vector3D + self.orientationAngle=0 #Float32 + self.orientationAxis=M3GVector3D(0,0,0) #Vector3D undefined + #END + self.hasGeneralTransform=False #Boolean + #IF hasGeneralTransform==TRUE, THEN + self.transform = M3GMatrix() #Matrix identity + self.transform.identity() + #END + #If either hasComponentTransform or hasGeneralTransform is false, the omitted fields will be + #initialized to their default values (equivalent to an identity transform in both cases). + + def writeJava(self,aWriter,aCreate): + if aCreate: pass #Abstract Base Class! Cant't be created + M3GObject3D.writeJava(self,aWriter,False) + if self.hasGeneralTransform : + aWriter.write(2,"float[] BL%i_matrix = {" % (self.id)) + aWriter.writeList(self.transform.elements,4,"f") + aWriter.write(2,"};") + aWriter.write(2) + aWriter.write(2,"Transform BL%i_transform = new Transform();" % (self.id)) + aWriter.write(2,"BL%i_transform.set(BL%i_matrix);" % (self.id,self.id)) + aWriter.write(2,"BL%i.setTransform(BL%i_transform);" % (self.id,self.id)) + aWriter.write(2) + if self.hasComponentTransform: + aWriter.write(2,("BL%i.setTranslation("+self.translation.writeJava()+");") + %(self.id)) + + def getData(self): + data = M3GObject3D.getData(self) + data += struct.pack(" 1: + aWriter.write(2,"IndexBuffer[] BL%i_indexArray = {" % (self.id)) + aWriter.write(4,",".join(["BL%i" %(i.id) for i in self.indexBuffer ])) + aWriter.write(2," };") + aWriter.write(2) + aWriter.write(2,"Appearance[] BL%i_appearanceArray = {" % (self.id)) + aWriter.write(4,",".join(["BL%i" %(i.id) for i in self.appearance ])) + aWriter.write(2," };") + aWriter.write(2) + aWriter.write(2,"%s BL%i = new %s(BL%i,BL%i_indexArray,BL%i_appearanceArray%s);" % \ + (aClassName,self.id,aClassName,self.vertexBuffer.id, self.id,self.id,aExtension)) + else: + #print "indexBuffer", len(self.indexBuffer) + #print "appearance", len(self.appearance) + aWriter.write(2,"%s BL%i = new %s(BL%i,BL%i,BL%i%s);" % \ + (aClassName, + self.id, + aClassName, + self.vertexBuffer.id, + self.indexBuffer[0].id, + self.appearance[0].id, + aExtension)) + M3GNode.writeJava(self,aWriter,False) + aWriter.write(2) + + +class M3GSkinnedMesh(M3GMesh): + def __init__(self,aVertexBuffer=None, aIndexBuffer=[], aAppearance=[]): + M3GMesh.__init__(self,aVertexBuffer, aIndexBuffer, aAppearance) + self.ObjectType=16 + self.skeleton=None #ObjectIndex + self.bones={} + #print"M3GSkinnedMesh.__init__::self.vertexBuffer:",self.vertexBuffer + ##ObjectIndex skeleton; + ##UInt32 transformReferenceCount; + ##FOR each bone reference... + ## ObjectIndex transformNode; + ## UInt32 firstVertex; + ## UInt32 vertexCount; + ## Int32 weight; + ##END + + def searchDeep(self,alist): + alist = doSearchDeep([self.skeleton],alist) + return M3GMesh.searchDeep(self,alist) + + def addSecondBone(self): + secondBones = {} + for bone in self.bones.values(): + bone2 = M3GBone() + bone2.verts=bone.verts + bone.verts=[] + mGroup = M3GGroup() + mGroup.name=bone.transformNode.name+"_second" + bone2.transformNode=mGroup + bone2.references = bone.references + bone.references = [] + bone2.weight = bone.weight + bone.weight=0 + mGroup.children = bone.transformNode.children + bone.transformNode.children = [mGroup] + mGroup.animationTracks=bone.transformNode.animationTracks + bone.transformNode.animationTracks = [] + secondBones[bone.transformNode.name+"_second"]=bone2 + for bone in secondBones.values(): + self.bones[bone.transformNode.name] = bone + + def getBlenderIndexes(self): + #print "M3GSkinnedMesh.vertexBuffer:",self.vertexBuffer + return self.vertexBuffer.positions.blenderIndexes + + def writeJava(self,aWriter,aCreate): + self.writeBaseJava(aWriter,aCreate,"SkinnedMesh", + (",BL%i" % (self.skeleton.id))) + aWriter.write(2,"//Transforms") + for bone in self.bones.values(): + #print "bone: ", bone + #print "bone.references: ", bone.references + for ref in bone.references: + aWriter.write(2,"BL%i.addTransform(BL%i,%i,%i,%i);" % + (self.id, + bone.transformNode.id,bone.weight, + ref.firstVertex, ref.vertexCount)) + aWriter.write(2) + + def getDataLength(self): + value = M3GMesh.getDataLength(self) + value += struct.calcsize(' element[i] : minimum[i] = element[i] + if maximum[i] < element[i] : maximum[i] = element[i] + #print i, maximum[i],element[i] + lrange=[0,0,0] + maxRange=0.0 + maxDimension=-1 + for i in range(3): #set bias + lrange[i] = maximum[i]-minimum[i] + self.bias[i] = minimum[i]*0.5+maximum[i]*0.5 + #print "Bias",i,self.bias[i],"min-max",minimum[i],maximum[i],"lrang",lrange[i] + if lrange[i] > maxRange: + maxRange = lrange[i] + maxDimension=i + self.scale = maxRange/65533.0 + #print "MaxRange ",maxRange + #print "scale",self.scale + + + def internalAutoScaling(self): + print "internalAutoScaling" + #Already done? + print self.components.typecode + if not self.autoscaling or self.components.typecode!="f":return + #Find bais and scale + minimum=[] + maximum=[] + for i in range(self.componentCount): + minimum.append(self.components[i]) + maximum.append(self.components[i]) + for i in range(0,len(self.components),self.componentCount): + for j in range(self.componentCount): + if minimum[j] > self.components[i+j] : minimum[j] = self.components[i+j] + if maximum[j] < self.components[i+j] : maximum[j] = self.components[i+j] + #print "i+j=",i+j,"min=",minimum[j],"max=",maximum[j],"elem=",self.components[i+j] + #print "min=", minimum + #print "max=", maximum + lrange=[0] * self.componentCount + maxRange=0.0 + maxDimension=-1 + for i in range(self.componentCount): #set bias + lrange[i] = maximum[i]-minimum[i] + self.bias[i] = minimum[i]*0.5+maximum[i]*0.5 + #print "Bias",i,self.bias[i],"min-max",minimum[i],maximum[i],"lrang",lrange[i] + if lrange[i] > maxRange: + maxRange = lrange[i] + maxDimension=i + maxValue=(2**(8*self.componentSize)*1.0)-2.0 + #print "MaxValue=",maxValue + self.scale = maxRange/maxValue + #print "MaxRange ",maxRange + #print "scale",self.scale + #Copy Components + oldArray=self.components + self.components=self.createComponentArray() + for i in range(0,len(oldArray),self.componentCount): + for j in range(self.componentCount): + element=int((oldArray[i+j]-self.bias[j])/self.scale) + #print "element",element + self.components.append(element) + # Reverse t coordinate because M3G uses a different 2D coordinate system than Blender. + if self.uvmapping: + for i in range(0,len(self.components),2): + self.components[i]= int(self.components[i]*(-1)) + for i in range(len(self.components)): + if abs(self.components[i])>maxValue:raise Exception( i+". element too great/small!") + + def writeJava(self,aWriter,aCreate): + self.internalAutoScaling() + if aCreate: + aWriter.write(2,"// VertexArray " + self.name) + if self.componentSize == 1: + aWriter.write(2,"byte[] BL%i_array = {" % (self.id)) + else: + aWriter.write(2,"short[] BL%i_array = {" % (self.id)) + aWriter.writeList(self.components) + aWriter.write(2,"};") + aWriter.write(2) + aWriter.write(2,"VertexArray BL%i = new VertexArray(BL%i_array.length/%i,%i,%i);" % + (self.id,self.id, + self.componentCount,self.componentCount,self.componentSize)) + aWriter.write(2,"BL%i.set(0,BL%i_array.length/%i,BL%i_array);" % + (self.id,self.id,self.componentCount,self.id)) + M3GObject3D.writeJava(self,aWriter,False) + aWriter.write(2) + + + def getData(self): + self.internalAutoScaling() + self.vertexCount = len(self.components)/self.componentCount + data = M3GObject3D.getData(self) + data += struct.pack('<3BH',self.componentSize, + self.componentCount, + self.encoding, + self.vertexCount) + componentType = "" + if self.componentSize == 1: + componentType = "b" + else: + componentType = "h" + for element in self.components: + data += struct.pack('<'+componentType,element) + return data + + def getDataLength(self): + self.internalAutoScaling() + value = M3GObject3D.getDataLength(self) + value += struct.calcsize('<3BH') + componentType = "" + if self.componentSize == 1: + componentType = "b" + else: + componentType = "h" + value += struct.calcsize('<'+str(len(self.components))+componentType) + return value + + def append(self,element,index=None): + #print "type(element):",type(element) + if type(element) is Types.vectorType : + for i in range(3): + value = int((element[i]-self.bias[i])/self.scale) + #print "append:",i,element[i],(element[i]-self.bias[i]),value + self.components.append(value) + elif type(element) is Types.MVertType: + for i in range(3): + value = int((element.co[i]-self.bias[i])/self.scale) + #print "append:",i,element[i],(element[i]-self.bias[i]),value + self.components.append(value) + if index!=None: + key=str(len(self.blenderIndexes)) + #print"key,index:",key,index + self.blenderIndexes[key]=index + #print"blenderIndexes",self.blenderIndexes + else: + # print "VertexArray.append: element=",element + self.components.append(element) + +class M3GVertexBuffer(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.ObjectType=21 + self.defaultColor=M3GColorRGBA(255,255,255) #ColorRGBA 0xFFFFFFFF (opaque white). + self.positions = None #ObjectIndex + self.positionBias = [0.0,0.0,0.0] #Float32[3] + self.positionScale = 1.0 #Float32 + self.normals = None #ObjectIndex + self.colors = None #ObjectIndex + self.texCoordArrays = [] + self.texcoordArrayCount = 0 #UInt32 +## #FOR each texture coordinate array... +## self.texCoords = [] #ObjectIndex +## self.texCoordBias=[] #Float32[3] +## self.texCoordScale=[] #;Float32 +## #END +## #If a texture coordinate array has only two components, the corresponding texCoordBias[2] element +## #must be 0.0. +## #Null texture coordinate arrays are never serialized, regardless of their position. A single texture +## #coordinate array will therefore always be serialized as belonging to texturing unit 0, regardless of +## #its original unit it was assigned to. +## #There are as many references in the texture coordinates array as there are active texture units for +## #this geometry. The texture coordinate references are loaded sequentially from texture unit 0. If the +## #implementation supports more texture units than are specified, these are left in their default, inactive +## #state, with a null texture coordinate reference and an undefined bias and scale. +## #If more texture coordinate references are specified than are supported by the implementation, then +## #this must be treated as an error, as it would be in the API. The application can then decide on an +## #appropriate course of action to handle this case. + + def searchDeep(self,alist): + if self.positions!=None: alist = self.positions.searchDeep(alist) + if self.normals != None: alist = self.normals.searchDeep(alist) + if self.colors!= None: alist = self.colors.searchDeep(alist) + alist = doSearchDeep(self.texCoordArrays, alist) + return M3GObject3D.searchDeep(self,alist) + + def setPositions(self,aVertexArray): + self.positions = aVertexArray + self.positionBias = aVertexArray.bias + self.positionScale = aVertexArray.scale + + def writeJava(self,aWriter,aCreate): + if aCreate: + aWriter.write(2,"//VertexBuffer"+self.name ) + aWriter.write(2,"VertexBuffer BL%i = new VertexBuffer();" % (self.id)) + aWriter.write(2,"float BL%i_Bias[] = { %ff, %ff, %ff};" % + (self.id,self.positionBias[0], + self.positionBias[1],self.positionBias[2])) + aWriter.write(2,"BL%i.setPositions(BL%i,%ff,BL%i_Bias);" % + (self.id, self.positions.id, + self.positionScale,self.id)) + aWriter.write(2,"BL%i.setNormals(BL%i);" % (self.id,self.normals.id)) + #if self.colors != None: aWriter.write(2,"BL%i.setTexCoords(0,BL%i,1.0f,null);" % + # (self.id,self.colors.id)) + lIndex = 0 + for iTexCoord in self.texCoordArrays: + aWriter.write(2,"float BL%i_%i_TexBias[] = { %ff, %ff, %ff};" % + (self.id,lIndex, iTexCoord.bias[0], + iTexCoord.bias[1],iTexCoord.bias[2])) + #int index, javax.microedition.m3g.VertexArray194 texCoords, float scale, float[] bias + aWriter.write(2,"BL%i.setTexCoords(%i,BL%i,%ff,BL%i_%i_TexBias);" % + (self.id, lIndex, iTexCoord.id, iTexCoord.scale,self.id,lIndex)) + lIndex += 1 + + M3GObject3D.writeJava(self,aWriter,False) + + + def getData(self): + self.texcoordArrayCount = len(self.texCoordArrays) + data = M3GObject3D.getData(self) + data += self.defaultColor.getData() + data += struct.pack(' 0 : + value += struct.calcsize('<' + str(len(self.indices)) + 'I') + value += struct.calcsize(' 0: + value+= struct.calcsize('<'+str(len(self.stripLengths))+'I') + return value + + +class M3GAppearance(M3GObject3D): + def __init__(self): + M3GObject3D.__init__(self) + self.ObjectType=3 + self.layer=0 #Byte + self.compositingMode=None #ObjectIndex + self.fog=None #ObjectIndex + self.polygonMode=None #ObjectIndex + self.material=None #ObjectIndex + self.textures=[] #;ObjectIndex[] + + def searchDeep(self,alist): + alist = doSearchDeep([self.compositingMode,self.fog, + self.polygonMode,self.material] + + self.textures,alist) + return M3GObject3D.searchDeep(self,alist) + + def getData(self): + data = M3GObject3D.getData(self) + data += struct.pack(" 0 : + value += struct.calcsize("<"+str(len(self.textures))+'I') + return value + + + def writeJava(self,aWriter,aCreate): + if aCreate: + aWriter.write(2,"//Appearance") + aWriter.write(2,"Appearance BL%i = new Appearance();" % (self.id)) + if self.compositingMode!= None: + aWriter.write(2,"BL%i.setPolygonMode(BL%i);" % + (self.id,self.compositingMode.id)) + if self.fog!=None: + aWriter.write(2,"BL%i.setFog(BL%i);" % + (self.id,self.fog.id)) + if self.polygonMode!=None: + aWriter.write(2,"BL%i.setPolygonMode(BL%i);" % + (self.id,self.polygonMode.id)) + if self.material!=None: + aWriter.write(2,"BL%i.setMaterial(BL%i);" % + (self.id,self.material.id)) + i=0 + for itexture in self.textures: + aWriter.write(2,"BL%i.setTexture(%i,BL%i);" % + (self.id,i,itexture.id)) + i =+ 1 + M3GObject3D.writeJava(self,aWriter,False) + aWriter.write(2) + +class M3GTexture2D(M3GTransformable): + #M3G imposes the following restrictions when assigning textures to a model: + #The dimensions must be powers of two (4, 8, 16, 32, 64, 128...). + + WRAP_REPEAT = 241 + WRAP_CLAMP = 240 + FILTER_BASE_LEVEL=208 + FILTER_LINEAR=209 + FILTER_NEAREST=210 + FUNC_ADD=224 + FUNC_BLEND=225 + FUNC_DECAL=226 + FUNC_MODULATE=227 + FUNC_REPLACE=228 + + def __init__(self,aImage): + M3GTransformable.__init__(self) + self.ObjectType=17 + self.Image = aImage #ObjectIndex + self.blendColor=M3GColorRGB(0,0,0) + self.blending=M3GTexture2D.FUNC_MODULATE #Byte + self.wrappingS=M3GTexture2D.WRAP_REPEAT #Byte + self.wrappingT=M3GTexture2D.WRAP_REPEAT #Byte + self.levelFilter=M3GTexture2D.FILTER_BASE_LEVEL #Byte + self.imageFilter=M3GTexture2D.FILTER_NEAREST #Byte + + def searchDeep(self,alist): + alist = doSearchDeep([self.Image],alist) + return M3GTransformable.searchDeep(self,alist) + + def getData(self): + data = M3GTransformable.getData(self) + data += struct.pack('#AE# + lError = "Armature name " + name + " is not ok. Perhaps you should set option 'ExportAllAction' to false." + #print "name ", name + lLetter = name.find("#") + if lLetter == -1 :raise Exception(lError) + if name[lLetter+1]!='A': raise Exception(lError) + lName = name[lLetter+2:] + #print "lName ", lName + lLetter = lName.find("E") + #print "lLetter ", lLetter + if lLetter == -1 :raise Exception(lError) + #print "lName[:]", lName[:0] + lArmatureID = int(lName[:lLetter]) + lName = lName[lLetter+1:] + lLetter = lName.find("#") + if lLetter == -1:raise Exception(lError) + lEndFrame = int(lName[:lLetter]) + lActionID = int(lName[lLetter+1:]) + return (lArmatureID,lEndFrame,lActionID) + + + def translateWorld(self,scene): + "creates world object" + world = M3GWorld() + + #Background + world.background = M3GBackground() + blWorld= scene.world + #AllWorlds = Blender.World.Get() # Set Color + #if len(AllWorlds)>=1: # world object available + if blWorld != None: + world.background.backgroundColor=self.translateRGBA(blWorld.getHor(),0) # horizon color of the first world + if mOptions.createAmbientLight & mOptions.lightingEnabled: + lLight = M3GLight() + lLight.mode = lLight.modes['AMBIENT'] + lLight.color = self.translateRGB(AllWorlds[0].getAmb()) + self.nodes.append(lLight) + + #TODO: Set background picture from world + + return world + + def translateEmpty(self,obj): + print "translate empty ..." + mGroup = M3GGroup() + self.translateToNode(obj,mGroup) + + def translateCamera(self,obj): + print "translate camera ..." + camera = obj.getData() + if camera.getType()!=0: + print "Only perscpectiv cameras will work korrekt" + return #Type=0 'perspectiv' Camera will be translated + mCamera = M3GCamera() + mCamera.projectionType=mCamera.PERSPECTIVE + mCamera.fovy=60.0 # TODO: Calculate fovy from Blender.lens + mCamera.AspectRatio=4.0/3.0 # TODO: different in every device + mCamera.near=camera.getClipStart() + mCamera.far=camera.getClipEnd() + self.translateToNode(obj,mCamera) + self.world.activeCamera = mCamera # Last one is always the active one + + + def translateMaterials(self, aMaterial, aMesh, aMatIndex, createNormals, createUvs): + print "translate materials ..." + + mAppearance = M3GAppearance() + + if createNormals: + mMaterial = M3GMaterial() + mMaterial.name = aMaterial.name + mMaterial.diffuseColor = self.translateRGBA(aMaterial.rgbCol,1.0) #ColorRGBA + #material.specularColor= self.translateRGB(mat.specCol) #ColorRGB + mAppearance.material = mMaterial + + if createUvs: + # Search file name in mesh face. + lImage = None + for iface in aMesh.faces: + if iface.mat==aMatIndex: + if iface.image != None: + lImage = iface.image + break + if lImage==None: + raise Exception("Mesh " + aMesh.name + ": No image found for uv-texture! Perhaps no uv-coordinates ?") + + # M3G requires textures to have power-of-two dimensions. + [width, height] = lImage.getSize() + powerWidth = 1 + while (powerWidth < width): + powerWidth *= 2 + powerHeight = 1 + while (powerHeight < height): + powerHeight *= 2 + if powerWidth != width or powerHeight != height: + raise Exception("Image " + lImage.filename + ": width and height must be power-of-two!") + + # ImageFactory reuses existing images. + mImage = ImageFactory.getImage(lImage, mOptions.textureExternal) + mTexture = M3GTexture2D(mImage) + mAppearance.textures.append(mTexture) + + mPolygonMode=M3GPolygonMode() + mPolygonMode.perspectiveCorrectionEnabled = mOptions.perspectiveCorrection + if not aMesh.mode & Modes.TWOSIDED: + mPolygonMode.culling=M3GPolygonMode.CULL_BACK + else: + mPolygonMode.culling=M3GPolygonMode.CULL_NONE + if mOptions.smoothShading: + mPolygonMode.shading=M3GPolygonMode.SHADE_SMOOTH + else: + mPolygonMode.shading=M3GPolygonMode.SHADE_FLAT + + mAppearance.polygonMode = mPolygonMode + + return mAppearance + + + def translateMesh(self,obj): + print "translate mesh ..." + str(obj) + + # Mesh data. + mesh = obj.getData(False, True) # get Mesh not NMesh object + if len(mesh.faces) <= 0: # no need to process empty meshes + print "Empty mesh " + str(obj) + " not processed." + return + + vertexBuffer = M3GVertexBuffer() + positions = M3GVertexArray(3, 2) # 3 coordinates - 2 bytes + if mOptions.autoscaling: positions.useMaxPrecision(mesh.verts) + indexBuffers = [] + appearances = [] + print str(len(mesh.materials)) + " material(s) found." + + # Texture coordinates. + createUvs = False + if mOptions.textureEnabled & mesh.faceUV: + for material in mesh.materials: + if material.getMode() & Material.Modes.TEXFACE: createUvs = True; + + if createUvs: + if mOptions.autoscaling: + uvCoordinates = M3GVertexArray(2,2,True,True) #2 coordinates - 2 bytes - autoscaling + else: + uvCoordinates = M3GVertexArray(2, 2) #2 coordinates - 2 bytes + uvCoordinates.bias[0] = 0.5 + uvCoordinates.bias[1] = 0.5 + uvCoordinates.bias[2] = 0.5 + uvCoordinates.scale = 1.0/65535.0 + else: + uvCoordinates = None + + # Normals. + createNormals = False + if mOptions.lightingEnabled: + for material in mesh.materials: + if not (material.getMode() & Material.Modes.SHADELESS): createNormals = True; + + if createNormals: + normals = M3GVertexArray(3, 1) # 3 coordinates - 1 byte + else: + normals = None + + # Create a submesh for each material. + for materialIndex, material in enumerate(mesh.materials): + faces = [face for face in mesh.faces if face.mat == materialIndex] + if len(faces) >= 0: + indexBuffers.append(self.translateFaces(faces, positions, normals, uvCoordinates, createNormals, createUvs)) + appearances.append(self.translateMaterials(material, mesh, materialIndex, createNormals, createUvs)) + + # If the above didn't result in any IndexBuffer (e.g. there's no material), write a single IndexBuffer + # with all faces and a default Appearance. + if len(indexBuffers) == 0: + indexBuffers.append(self.translateFaces(mesh.faces, positions, normals, uvCoordinates, createNormals, createUvs)) + appearances.append(M3GAppearance()) + + vertexBuffer.setPositions(positions) + if createNormals: vertexBuffer.normals = normals + if createUvs: vertexBuffer.texCoordArrays.append(uvCoordinates) + + parent = obj.getParent() + if parent!=None and parent.getType()=='Armature': #Armatures ? + mMesh = M3GSkinnedMesh(vertexBuffer,indexBuffers,appearances) + #print"vertexBuffer.positions:",vertexBuffer.positions + print"mMesh.vertexBuffer:",mMesh.vertexBuffer + self.translateArmature(parent,obj,mMesh) + else: + mMesh = M3GMesh(vertexBuffer,indexBuffers,appearances) + + self.translateToNode(obj,mMesh) + + #Do Animation + self.translateObjectIpo(obj,mMesh) + + def translateFaces(self, faces, positions, normals, uvCoordinates, createNormals, createUvs): + """Translates a list of faces into vertex data and triangle strips.""" + + # Create vertices and triangle strips. + indices = [0, 0, 0, 0] + triangleStrips = M3GTriangleStripArray() + + for face in faces: + for vertexIndex, vertex in enumerate(face.verts): + # Find candidates for sharing (vertices with same Blender ID). + vertexCandidateIds = [int(k) for k, v in positions.blenderIndexes.items() if v == vertex.index] + + # Check normal. + if createNormals and not face.smooth: + # For solid faces, a vertex can only be shared if the the face normal is + # the same as the normal of the shared vertex. + for candidateId in vertexCandidateIds[:]: + for j in range(3): + if face.no[j]*127 != normals.components[candidateId*3 + j]: + vertexCandidateIds.remove(candidateId) + break + + # Check texture coordinates. + if createUvs: + # If texture coordinates are required, a vertex can only be shared if the + # texture coordinates match. + for candidateId in vertexCandidateIds[:]: + s = int((face.uv[vertexIndex][0]-0.5)*65535) + t = int((0.5-face.uv[vertexIndex][1])*65535) + if (s != uvCoordinates.components[candidateId*2 + 0]) or (t != uvCoordinates.components[candidateId*2 + 1]): + vertexCandidateIds.remove(candidateId) + + if len(vertexCandidateIds) > 0: + # Share the vertex. + indices[vertexIndex] = vertexCandidateIds[0] + else: + # Create new vertex. + positions.append(vertex, vertex.index) + indices[vertexIndex] = len(positions.components)/3 - 1 + + # Normal. + if createNormals: + for j in range(3): + if face.smooth: + normals.append(int(vertex.no[j]*127)) # vertex normal + else: + normals.append(int(face.no[j]*127)) # face normal + + # Texture coordinates. + if createUvs: + lUvCoordinatesFound = True + print "face.uv[vertexIndex][0]:",face.uv[vertexIndex][0] + print "face.uv[vertexIndex][1]:",face.uv[vertexIndex][1] + if mOptions.autoscaling: + uvCoordinates.append(face.uv[vertexIndex][0]) + uvCoordinates.append(face.uv[vertexIndex][1]) + else: + uvCoordinates.append(int((face.uv[vertexIndex][0]-0.5)*65535)) + # Reverse t coordinate because M3G uses a different 2D coordinate system than Blender. + uvCoordinates.append(int((0.5-face.uv[vertexIndex][1])*65535)) + + # IndexBuffer. + triangleStrips.stripLengths.append(len(face.verts)) + if len(face.verts) > 3 : + triangleStrips.indices += [indices[1], indices[2], indices[0], indices[3]] # quad + else : + triangleStrips.indices += [indices[0], indices[1], indices[2]] # tri + + return triangleStrips + + + def translateObjectIpo(self,obj,aM3GObject): + if obj.getIpo() == None : return #No Ipo available + print "translate Ipo ..." + + lIpo = obj.getIpo() + self.translateIpo(lIpo,aM3GObject) + + + def translateIpo(self,aIpo,aM3GObject,aM3GAnimContr=None,aEndFrame=0): + #Print info about curves + #for iCurve in lIpo.getCurves(): + # print "Extrapolation",iCurve.getExtrapolation() #Constant, Extrapolation, Cyclic or Cyclic_extrapolation + # print "Interpolation",iCurve.getInterpolation() #Constant, Bezier, or Linear + # print "Name",iCurve.getName() + # for iPoint in iCurve.getPoints(): + # print "Knode points",iPoint.getPoints() + types = ['Loc','Rot','Size','Quat'] + + for type in types: + if aIpo.getCurve(type+'X'): + self.translateIpoCurve(aIpo,aM3GObject,type,aM3GAnimContr,aEndFrame) + + + def translateIpoCurve(self,aIpo,aM3GObject,aCurveType,aM3GAnimContr,aEndFrame=0): + + lContext = self.scene.getRenderingContext() + if aEndFrame==0: + lEndFrame = lContext.endFrame() + else: + lEndFrame = aEndFrame + + lTimePerFrame = 1.0 / lContext.framesPerSec() * 1000 + + lCurveX = aIpo.getCurve(aCurveType+'X') + lCurveY = aIpo.getCurve(aCurveType+'Y') + lCurveZ = aIpo.getCurve(aCurveType+'Z') + if aCurveType=='Quat': lCurveW = aIpo.getCurve(aCurveType+'W') + + lInterpolation = None + if aCurveType == 'Rot' or aCurveType == 'Quat': + lTrackType = M3GAnimationTrack.ORIENTATION + lNumComponents=4 + lCurveFactor= 10 #45 Degrees = 4,5 + if aCurveType == 'Quat': + lTrackType = M3GAnimationTrack.ORIENTATION + lNumComponents=4 + lCurveFactor= 1 + lInterpolation = M3GKeyframeSequence.SLERP + #lInterpolation = M3GKeyframeSequence.SQUAD + elif aCurveType == 'Size': + lTrackType = M3GAnimationTrack.SCALE + lNumComponents=3 + lCurveFactor=1 + else: + lTrackType = M3GAnimationTrack.TRANSLATION + lNumComponents=3 + lCurveFactor=1 + + mSequence = M3GKeyframeSequence(len(lCurveX.getPoints()), + lNumComponents, + lCurveX.getInterpolation(), + lInterpolation) + + #print 'ComponentCount',mSequence.componentCount + + mSequence.duration = lEndFrame * lTimePerFrame + mSequence.setRepeatMode(lCurveX.getExtrapolation()) + + lIndex = 0 + for iPoint in lCurveX.getPoints(): + lPoint = iPoint.getPoints() + + lPointList = [(lPoint[1]*lCurveFactor), + (lCurveY.evaluate(lPoint[0])*lCurveFactor), + (lCurveZ.evaluate(lPoint[0])*lCurveFactor)] + + #print "aCurveType ", aCurveType + + if aCurveType == 'Loc': + #print "PointList ", lPointList + #lorgTransVector = aM3GObject.blenderTransformMatrix.translationPart() + #ltrans = TranslationMatrix(Vector(lPointList)) + #ltrans2 = self.calculateChildMatrix(ltrans,aM3GObject.blenderTransformMatrix) + #lVector = ltrans2.translationPart() + lorgTransVector + #lPointList = [lVector.x, lVector.y,lVector.z] + #print "PointList ", lPointList + pass + + if aCurveType == 'Quat': + lPointList.append(lCurveW.evaluate(lPoint[0])*lCurveFactor) + #lQuat = Quaternion([lPointList[3],lPointList[0],lPointList[1],lPointList[2]]) + #print "Quat ", lQuat + #print "Quat.angel ", lQuat.angle + #print "Quat.axis ", lQuat.axis + #print "PointList ", lPointList + + #print "PointList",lPointList + + if aCurveType =='Rot': + lQuat = Euler(lPointList).toQuat() + #lPointList = [lQuat.w,lQuat.x,lQuat.y,lQuat.z] + lPointList = [lQuat.x,lQuat.y,lQuat.z,lQuat.w] + #print " Quat=", lPointList + + mSequence.setKeyframe(lIndex, + lPoint[0]*lTimePerFrame, + lPointList) + lIndex += 1 + mSequence.validRangeFirst = 0 + mSequence.validRangeLast = lIndex - 1 + + mTrack = M3GAnimationTrack(mSequence,lTrackType) + aM3GObject.animationTracks.append(mTrack) + if aM3GAnimContr==None: aM3GAnimContr = M3GAnimationController() + mTrack.animationController = aM3GAnimContr + + + def translateLamp(self,obj): + print "translate lamp ..." + lamp = obj.getData() + + #Type + lampType=lamp.getType() + if not lampType in [Lamp.Types.Lamp,Lamp.Types.Spot,Lamp.Types.Sun]: + print "INFO: Type of light is not supported. See documentation" + return #create not light; type not supported + mLight = M3GLight() + if lampType == Lamp.Types.Lamp: + mLight.mode = mLight.modes['OMNI'] + elif lampType == Lamp.Types.Spot: + mLight.mode = mLight.modes['SPOT'] + elif lampType == Lamp.Types.Sun: + mLight.mode = mLight.modes['DIRECTIONAL'] + #Attenuation (OMNI,SPOT): + if lampType in [Lamp.Types.Lamp,Lamp.Types.Spot]: + mLight.attenuationConstant = 0.0 + mLight.attenuationLinear = 2.0/lamp.dist + mLight.attenuationQuadratic = 0.0 + #Color + mLight.color = self.translateRGB(lamp.col) + #Energy + mLight.intensity = lamp.energy + #SpotAngle, SpotExponent (SPOT) + if lampType == Lamp.Types.Spot: + mLight.spotAngle = lamp.spotSize + mLight.spotExponent = lamp.spotBlend + self.translateToNode(obj,mLight) + + + def translateCore(self,obj,node): + #Name + node.name = obj.name + node.userID = self.translateUserID(obj.name) + #Location + #node.translation=self.translateLoc(obj.LocX,obj.LocY,obj.LocZ + #node.hasComponentTransform=True + #Transform + #node.transform = self.translateMatrix(obj.getMatrix('localspace')) + if type(obj) is Types.BoneType: + #print "BoneMatrix ",obj.matrix['BONESPACE'] + node.transform = self.translateMatrix(obj.matrix['ARMATURESPACE']) + #'ARMATURESPACE' - this matrix of the bone in relation to the armature + #'BONESPACE' - the matrix of the bone in relation to itself + else: + node.transform = self.translateMatrix(obj.matrixWorld) + node.hasGeneralTransform=True + + + def translateToNode(self,obj,node): + self.translateCore(obj,node) + #Nodes + self.nodes.append(node) + #Link to Blender Object + node.blenderObj = obj + node.blenderMatrixWorld = obj.matrixWorld + lparent = None + if obj.getParent()!=None: + if obj.getParent().getType()!='Armature': + lparent = obj.getParent() + else: + if obj.getParent().getParent()!=None and obj.getParent().getParent().getType()!='Armature': + lparent = obj.getParent().getParent() + node.parentBlenderObj = lparent + + + def translateUserID(self, name): + id = 0 + start = name.find('#') + + # Use digits that follow the # sign for id. + if start != -1: + start += 1 + end = start + for char in name[start:]: + if char.isdigit(): + end += 1 + else: + break + + if end > start: + id = int(name[start:end]) + + return id + + def translateLoc(self,aLocX,aLocY,aLocZ): + return M3GVector3D(aLocX,aLocY,aLocZ) + + def translateRGB(self,color): + return M3GColorRGB(int(color[0]*255), + int(color[1]*255), + int(color[2]*255)) + + def translateRGBA(self,color,alpha): + return M3GColorRGBA(int(color[0]*255), + int(color[1]*255), + int(color[2]*255), + int(alpha*255)) + + def translateMatrix(self,aPyMatrix): + """ +  0   1   2   3  + 4   5   6   7  + 8   9  10  11 + 12  13  14  15 """ + #print "Matrix:", aPyMatrix + lMatrix = M3GMatrix() + lMatrix.elements[0] = aPyMatrix[0][0] + lMatrix.elements[1] = aPyMatrix[1][0] + lMatrix.elements[2] = aPyMatrix[2][0] + lMatrix.elements[3] = aPyMatrix[3][0] + lMatrix.elements[4] = aPyMatrix[0][1] + lMatrix.elements[5] = aPyMatrix[1][1] + lMatrix.elements[6] = aPyMatrix[2][1] + lMatrix.elements[7] = aPyMatrix[3][1] + lMatrix.elements[8] = aPyMatrix[0][2] + lMatrix.elements[9] = aPyMatrix[1][2] + lMatrix.elements[10] = aPyMatrix[2][2] + lMatrix.elements[11] = aPyMatrix[3][2] + lMatrix.elements[12] = aPyMatrix[0][3] + lMatrix.elements[13] = aPyMatrix[1][3] + lMatrix.elements[14] = aPyMatrix[2][3] + lMatrix.elements[15] = aPyMatrix[3][3] + return lMatrix + + +# ---- Exporter ---------------------------------------------------------------- # + +class M3GExporter: + "Exports Blender-Scene to M3D" + def __init__(self, aWriter): + self.writer = aWriter + + + def start(self): + print "Info: starting export ..." + #rpdb2.start_embedded_debugger("t",True) + Translator = M3GTranslator() + world = Translator.start() + + #sys.settrace(tracer) + exportList = self.createDeepSearchList(world) + externalReferences = [element for element in exportList if element.__class__ is M3GExternalReference] + exportList = [element for element in exportList if element.__class__ is not M3GExternalReference] + #sys.settrace(None) + + # 1 is reservated for HeaderObject. + i=1 + + # Next are the external references. + for element in externalReferences: + i += 1 + element.id = i + print "object ",element.id, element + + # And the standard scene objects. + for element in exportList: + i += 1 + element.id = i + print "object ",element.id, element + + self.writer.writeFile(world, exportList, externalReferences) + + print("Ready!") + + + def createDeepSearchList(self,aWorld): + "creates the right order for saving m3g : leafs first" + return aWorld.searchDeep([]) + + + +# ---- Writer ---------------------------------------------------------------- # +class JavaWriter: + "writes a java class which creates m3g-Scene in a j2me programm" + def __init__(self,aFilename): + self.filename = aFilename + self.classname = Blender.sys.basename(aFilename) + self.classname = self.classname[:-5] #without extention ".java" + self.outFile = file(aFilename,"w") + + def write(self, tab, zeile=""): + "writes to file" + #print "\t" * tab + zeile + print >>self.outFile, "\t" * tab + zeile + + def writeFile(self,aWorld,aExportList,externalReferences): + self.world = aWorld + self.writeHeader() + for element in aExportList: + element.writeJava(self,True) + self.writeFooter() + self.outFile.close() + + def writeHeader(self): + "writes class header" + self.write(0,"import javax.microedition.lcdui.Image;") + self.write(0,"import javax.microedition.m3g.*;") + self.write(0,"public final class "+self.classname+" {") + self.write(1,"public static World getRoot(Canvas3D aCanvas) {") + + def writeFooter(self): + self.write(1) + self.write(1,"return BL"+str(self.world.id)+";") + self.write(0,"}}") + + def writeList(self,alist,numberOfElementsPerLine=12,aType=""): + '''Writes numberOfElementsPerLine''' + line="" + lastLine="" + counter=0 + for element in alist: + if counter!=0: + line = line + "," + str(element) + aType + else: + line = str(element) + aType + counter = counter + 1 + if counter == numberOfElementsPerLine: + if len(lastLine)>0: + self.write(3,lastLine+",") + lastLine=line + line="" + counter = 0 + if len(lastLine)>0: + if len(line)>0: + self.write(3,lastLine+",") + else: + self.write(3,lastLine) + if len(line) > 0: self.write(3,line) + + def writeClass(self,aName,aM3GObject): + self.write(2) + self.write(2,"//"+aName+":"+aM3GObject.name) + + +class M3GSectionObject: + def __init__(self,aObject): + """Object Structure + Each object in the file represents one object in the + scene graph tree, and is stored in a chunk. The + structure of an object chunk is as follows: + Byte ObjectType + UInt32 Length + Byte[] Data""" + #ObjectType + #This field describes what type of object has been serialized. + #The values 0 and 0xFF are special: 0 represents the header object, + #and 0xFF represents an external reference. + #Example: Byte ObjectType = 14 + self.ObjectType = aObject.ObjectType + self.data = aObject.getData() + self.length = aObject.getDataLength() + + def getData(self): + data = struct.pack(' 2,1,0 + for v in f.v[2::-1]: + file.write(format_vec % tuple(v.co) ) + + try: mode= f.mode + except: mode= 0 + + if mode & Mesh.FaceModes.INVISIBLE: + file.write(PREF_INVIS_TEX.val) + else: + try: image= f.image + except: image= None + + if image: file.write(sys.splitext(sys.basename(image.filename))[0]) + else: file.write(PREF_NULL_TEX.val) + + # Texture stuff ignored for now + file.write(PREF_DEF_TEX_OPTS.val) + file.write('}\n') + + +def round_vec(v): + if PREF_GRID_SNAP.val: + return round(v.x), round(v.y), round(v.z) + else: + return tuple(v) + +def write_face2brush(file, face): + ''' + takes a face and writes it as a brush + each face is a cube/brush + ''' + + if PREF_GRID_SNAP.val: format_vec= '( %d %d %d ) ' + else: format_vec= '( %.8f %.8f %.8f ) ' + + + image_text= PREF_NULL_TEX.val + + try: mode= face.mode + except: mode= 0 + + if mode & Mesh.FaceModes.INVISIBLE: + image_text= PREF_INVIS_TEX.val + else: + try: image= face.image + except: image= None + if image: image_text = sys.splitext(sys.basename(image.filename))[0] + + # original verts as tuples for writing + orig_vco= [tuple(v.co) for v in face] + + # new verts that give the face a thickness + dist= PREF_SCALE.val * PREF_FACE_THICK.val + new_vco= [round_vec(v.co - (v.no * dist)) for v in face] + #new_vco= [round_vec(v.co - (face.no * dist)) for v in face] + + file.write('// brush from face\n{\n') + # front + for co in orig_vco[2::-1]: + file.write(format_vec % co ) + file.write(image_text) + # Texture stuff ignored for now + file.write(PREF_DEF_TEX_OPTS.val) + + + for co in new_vco[:3]: + file.write(format_vec % co ) + if mode & Mesh.FaceModes.TWOSIDE: + file.write(image_text) + else: + file.write(PREF_INVIS_TEX.val) + + # Texture stuff ignored for now + file.write(PREF_DEF_TEX_OPTS.val) + + # sides. + if len(orig_vco)==3: # Tri, it seemms tri brushes are supported. + index_pairs= ((0,1), (1,2), (2,0)) + else: + index_pairs= ((0,1), (1,2), (2,3), (3,0)) + + for i1, i2 in index_pairs: + for co in orig_vco[i1], orig_vco[i2], new_vco[i2]: + file.write( format_vec % co ) + file.write(PREF_INVIS_TEX.val) + file.write(PREF_DEF_TEX_OPTS.val) + + file.write('}\n') + +def is_cube_facegroup(faces): + ''' + Returens a bool, true if the faces make up a cube + ''' + # cube must have 6 faces + if len(faces) != 6: + print '1' + return False + + # Check for quads and that there are 6 unique verts + verts= {} + for f in faces: + if len(f)!= 4: + return False + + for v in f: + verts[v.index]= 0 + + if len(verts) != 8: + return False + + # Now check that each vert has 3 face users + for f in faces: + for v in f: + verts[v.index] += 1 + + for v in verts.itervalues(): + if v != 3: # vert has 3 users? + return False + + # Could we check for 12 unique edges??, probably not needed. + return True + +def is_tricyl_facegroup(faces): + ''' + is the face group a tri cylinder + Returens a bool, true if the faces make an extruded tri solid + ''' + return False + # cube must have 5 faces + if len(faces) != 5: + print '1' + return False + + # Check for quads and that there are 6 unique verts + verts= {} + tottri= 0 + for f in faces: + if len(f)== 3: + tottri+=1 + + for v in f: + verts[v.index]= 0 + + if len(verts) != 6 or tottri != 2: + return False + + # Now check that each vert has 3 face users + for f in faces: + for v in f: + verts[v.index] += 1 + + for v in verts.itervalues(): + if v != 3: # vert has 3 users? + return False + + # Could we check for 12 unique edges??, probably not needed. + return True + +def write_node_map(file, ob): + ''' + Writes the properties of an object (empty in this case) + as a MAP node as long as it has the property name - classname + returns True/False based on weather a node was written + ''' + props= [(p.name, p.data) for p in ob.properties] + + IS_MAP_NODE= False + for name, value in props: + if name=='classname': + IS_MAP_NODE= True + break + + if not IS_MAP_NODE: + return False + + # Write a node + file.write('{\n') + for name_value in props: + file.write('"%s" "%s"\n' % name_value) + file.write('}\n') + return True + + +def export_map(filepath): + + pup_block = [\ + ('Scale:', PREF_SCALE, 1, 1000, 'Scale the blender scene by this value.'),\ + ('Face Width:', PREF_FACE_THICK, 0.01, 10, 'Thickness of faces exported as brushes.'),\ + ('Grid Snap', PREF_GRID_SNAP, 'snaps floating point values to whole numbers.'),\ + 'Null Texture',\ + ('', PREF_NULL_TEX, 1, 128, 'Export textureless faces with this texture'),\ + 'Unseen Texture',\ + ('', PREF_INVIS_TEX, 1, 128, 'Export invisible faces with this texture'),\ + ] + + if not Draw.PupBlock('map export', pup_block): + return + + Window.WaitCursor(1) + time= sys.time() + print 'Map Exporter 0.0' + file= open(filepath, 'w') + + + obs_mesh= [] + obs_lamp= [] + obs_surf= [] + obs_empty= [] + + SCALE_MAT= Mathutils.Matrix() + SCALE_MAT[0][0]= SCALE_MAT[1][1]= SCALE_MAT[2][2]= PREF_SCALE.val + + dummy_mesh= Mesh.New() + + TOTBRUSH= TOTLAMP= TOTNODE= 0 + + for ob in Object.GetSelected(): + type= ob.getType() + if type == 'Mesh': obs_mesh.append(ob) + elif type == 'Surf': obs_surf.append(ob) + elif type == 'Lamp': obs_lamp.append(ob) + elif type == 'Empty': obs_empty.append(ob) + + if obs_mesh or obs_surf: + # brushes and surf's must be under worldspan + file.write('\n// entity 0\n') + file.write('{\n') + file.write('"classname" "worldspawn"\n') + + + print '\twriting cubes from meshes' + for ob in obs_mesh: + dummy_mesh.getFromObject(ob.name) + + #print len(mesh_split2connected(dummy_mesh)) + + # Is the object 1 cube? - object-is-a-brush + dummy_mesh.transform(ob.matrixWorld*SCALE_MAT) # 1 to tx the normals also + + if PREF_GRID_SNAP.val: + for v in dummy_mesh.verts: + co= v.co + co.x= round(co.x) + co.y= round(co.y) + co.z= round(co.z) + + # High quality normals + BPyMesh.meshCalcNormals(dummy_mesh) + + # Split mesh into connected regions + for face_group in BPyMesh.mesh2linkedFaces(dummy_mesh): + if is_cube_facegroup(face_group): + write_cube2brush(file, face_group) + TOTBRUSH+=1 + elif is_tricyl_facegroup(face_group): + write_cube2brush(file, face_group) + TOTBRUSH+=1 + else: + for f in face_group: + write_face2brush(file, f) + TOTBRUSH+=1 + + #print 'warning, not exporting "%s" it is not a cube' % ob.name + + + dummy_mesh.verts= None + + + valid_dims= 3,5,7,9,11,13,15 + for ob in obs_surf: + ''' + Surf, patches + ''' + surf_name= ob.getData(name_only=1) + data= Curve.Get(surf_name) + mat = ob.matrixWorld*SCALE_MAT + + # This is what a valid patch looks like + + """ +// brush 0 +{ +patchDef2 +{ +NULL +( 3 3 0 0 0 ) +( +( ( -64 -64 0 0 0 ) ( -64 0 0 0 -2 ) ( -64 64 0 0 -4 ) ) +( ( 0 -64 0 2 0 ) ( 0 0 0 2 -2 ) ( 0 64 0 2 -4 ) ) +( ( 64 -64 0 4 0 ) ( 64 0 0 4 -2 ) ( 80 88 0 4 -4 ) ) +) +} +} + """ + for i, nurb in enumerate(data): + u= nurb.pointsU + v= nurb.pointsV + if u in valid_dims and v in valid_dims: + + file.write('// brush %d surf_name\n' % i) + file.write('{\n') + file.write('patchDef2\n') + file.write('{\n') + file.write('NULL\n') + file.write('( %d %d 0 0 0 )\n' % (u, v) ) + file.write('(\n') + + u_iter = 0 + for p in nurb: + + if u_iter == 0: + file.write('(') + + u_iter += 1 + + # add nmapping 0 0 ? + if PREF_GRID_SNAP.val: + file.write(' ( %d %d %d 0 0 )' % round_vec(Mathutils.Vector(p[0:3]) * mat)) + else: + file.write(' ( %.6f %.6f %.6f 0 0 )' % tuple(Mathutils.Vector(p[0:3]) * mat)) + + # Move to next line + if u_iter == u: + file.write(' )\n') + u_iter = 0 + + file.write(')\n') + file.write('}\n') + file.write('}\n') + + + # Debugging + # for p in nurb: print 'patch', p + + else: + print "NOT EXPORTING PATCH", surf_name, u,v, 'Unsupported' + + + file.write('}\n') # end worldspan + + + print '\twriting lamps' + for ob in obs_lamp: + print '\t\t%s' % ob.name + lamp= ob.data + file.write('{\n') + file.write('"classname" "light"\n') + file.write('"light" "%.6f"\n' % (lamp.dist* PREF_SCALE.val)) + if PREF_GRID_SNAP.val: + file.write('"origin" "%d %d %d"\n' % tuple([round(axis*PREF_SCALE.val) for axis in ob.getLocation('worldspace')]) ) + else: + file.write('"origin" "%.6f %.6f %.6f"\n' % tuple([axis*PREF_SCALE.val for axis in ob.getLocation('worldspace')]) ) + file.write('"_color" "%.6f %.6f %.6f"\n' % tuple(lamp.col)) + file.write('"style" "0"\n') + file.write('}\n') + TOTLAMP+=1 + + + print '\twriting empty objects as nodes' + for ob in obs_empty: + if write_node_map(file, ob): + print '\t\t%s' % ob.name + TOTNODE+=1 + else: + print '\t\tignoring %s' % ob.name + + Window.WaitCursor(0) + + print 'Exported Map in %.4fsec' % (sys.time()-time) + print 'Brushes: %d Nodes: %d Lamps %d\n' % (TOTBRUSH, TOTNODE, TOTLAMP) + + +def main(): + Window.FileSelector(export_map, 'EXPORT MAP', '*.map') + +if __name__ == '__main__': main() +# export_map('/foo.map') \ No newline at end of file diff --git a/release/scripts/export_mdd.py b/release/scripts/export_mdd.py new file mode 100644 index 00000000000..42a85029505 --- /dev/null +++ b/release/scripts/export_mdd.py @@ -0,0 +1,153 @@ +#!BPY + +""" + Name: 'Vertex Keyframe Animation (.mdd)...' + Blender: 242 + Group: 'Export' + Tooltip: 'Animated mesh to MDD vertex keyframe file.' +""" + +__author__ = "Bill L.Nieuwendorp" +__bpydoc__ = """\ +This script Exports Lightwaves MotionDesigner format. + +The .mdd format has become quite a popular Pipeline format
+for moving animations from package to package. + +Be sure not to use modifiers that change the number or order of verts in the mesh +""" +#Please send any fixes,updates,bugs to Slow67_at_Gmail.com or cbarton_at_metavr.com +#Bill Niewuendorp +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +import bpy +import Blender +from Blender import * +import BPyMessages +try: + from struct import pack +except: + pack = None + + +def zero_file(filepath): + ''' + If a file fails, this replaces it with 1 char, better not remove it? + ''' + file = open(filepath, 'w') + file.write('\n') # aparently macosx needs some data in a blank file? + file.close() + +def mdd_export(filepath, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS): + + Window.EditMode(0) + Blender.Window.WaitCursor(1) + mesh_orig = ob.getData(mesh=1) + + #Flip y and z + ''' + mat = Mathutils.Matrix() + mat[2][2] = -1 + rotmat = Mathutils.RotationMatrix(90, 4, 'x') + mat_flip = mat*rotmat + ''' + # Above results in this matrix + mat_flip= Mathutils.Matrix(\ + [1.0, 0.0, 0.0, 0.0],\ + [0.0, 0.0, 1.0, 0.0],\ + [0.0, 1.0, 0.0, 0.0],\ + [0.0, 0.0, 0.0, 1.0],\ + ) + + me_tmp = Mesh.New() # container mesh + + numverts = len(mesh_orig.verts) + numframes = PREF_ENDFRAME-PREF_STARTFRAME+1 + PREF_FPS= float(PREF_FPS) + f = open(filepath, 'wb') #no Errors yet:Safe to create file + + # Write the header + f.write(pack(">2i", numframes-1, numverts)) + + # Write the frame times (should we use the time IPO??) + f.write( pack(">%df" % (numframes-1), *[frame/PREF_FPS for frame in xrange(numframes-1)]) ) # seconds + + Blender.Set('curframe', PREF_STARTFRAME) + for frame in xrange(PREF_STARTFRAME,PREF_ENDFRAME+1):#in order to start at desired frame + Blender.Set('curframe', frame) + # Blender.Window.RedrawAll() # not needed + me_tmp.getFromObject(ob.name) + + if len(me_tmp.verts) != numverts: + Blender.Draw.PupMenu('Error%t|Number of verts has changed during animation|cannot export') + Blender.Window.WaitCursor(0) + f.close() # should we zero? + zero_file(filepath) + return + + me_tmp.transform(ob.matrixWorld * mat_flip) + + # Write the vertex data + f.write(pack(">%df" % (numverts*3), *[axis for v in me_tmp.verts for axis in v.co])) + + me_tmp.verts= None + f.close() + + print'MDD Exported: %s frames:%d\n'% (filepath, numframes-1) + Blender.Window.WaitCursor(0) + + +def mdd_export_ui(filepath): + # Dont overwrite + if not BPyMessages.Warning_SaveOver(filepath): + return + + scn= bpy.data.scenes.active + ob_act= scn.objects.active + if not ob_act or ob_act.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + + ctx = scn.getRenderingContext() + orig_frame = Blender.Get('curframe') + PREF_STARTFRAME= Blender.Draw.Create(int(ctx.startFrame())) + PREF_ENDFRAME= Blender.Draw.Create(int(ctx.endFrame())) + PREF_FPS= Blender.Draw.Create(ctx.fps) + + block = [\ + ("Start Frame: ", PREF_STARTFRAME, 1, 30000, "Start Bake from what frame?: Default 1"),\ + ("End Frame: ", PREF_ENDFRAME, 1, 30000, "End Bake on what Frame?"),\ + ("FPS: ", PREF_FPS, 1, 100, "Frames per second")\ + ] + + if not Blender.Draw.PupBlock("Export MDD", block): + return + + PREF_STARTFRAME, PREF_ENDFRAME=\ + min(PREF_STARTFRAME.val, PREF_ENDFRAME.val),\ + max(PREF_STARTFRAME.val, PREF_ENDFRAME.val) + + print (filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val) + mdd_export(filepath, ob_act, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS.val) + Blender.Set('curframe', orig_frame) + +if __name__=='__main__': + if not pack: + Draw.PupMenu('Error%t|This script requires a full python install') + + Blender.Window.FileSelector(mdd_export_ui, 'EXPORT MDD', sys.makename(ext='.mdd')) diff --git a/release/scripts/export_obj.py b/release/scripts/export_obj.py new file mode 100644 index 00000000000..101a1ab1e84 --- /dev/null +++ b/release/scripts/export_obj.py @@ -0,0 +1,649 @@ +#!BPY + +""" +Name: 'Wavefront (.obj)...' +Blender: 243 +Group: 'Export' +Tooltip: 'Save a Wavefront OBJ File' +""" + +__author__ = "Campbell Barton, Jiri Hnidek" +__url__ = ['www.blender.org', 'blenderartists.org'] +__version__ = "1.1" + +__bpydoc__ = """\ +This script is an exporter to OBJ file format. + +Usage: + +Select the objects you wish to export and run this script from "File->Export" menu. +Selecting the default options from the popup box will be good in most cases. +All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d) +will be exported as mesh data. +""" + + +# -------------------------------------------------------------------------- +# OBJ Export v1.1 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +import Blender +from Blender import Mesh, Scene, Window, sys, Image, Draw +import BPyMesh +import BPyObject +import BPySys +import BPyMessages + +# Returns a tuple - path,extension. +# 'hello.obj' > ('hello', '.obj') +def splitExt(path): + dotidx = path.rfind('.') + if dotidx == -1: + return path, '' + else: + return path[:dotidx], path[dotidx:] + +def fixName(name): + if name == None: + return 'None' + else: + return name.replace(' ', '_') + +# A Dict of Materials +# (material.name, image.name):matname_imagename # matname_imagename has gaps removed. +MTL_DICT = {} + +def write_mtl(filename): + + world = Blender.World.GetCurrent() + if world: + worldAmb = world.getAmb() + else: + worldAmb = (0,0,0) # Default value + + file = open(filename, "w") + file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) + file.write('# Material Count: %i\n' % len(MTL_DICT)) + # Write material/image combinations we have used. + for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems(): + + # Get the Blender data for the material and the image. + # Having an image named None will make a bug, dont do it :) + + file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname + + if mat: + file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's + file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour, + file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse + file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular + file.write('Ni %.6f\n' % mat.IOR) # Refraction index + file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve) + + # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting. + if mat.getMode() & Blender.Material.Modes['SHADELESS']: + file.write('illum 0\n') # ignore lighting + elif mat.getSpec() == 0: + file.write('illum 1\n') # no specular. + else: + file.write('illum 2\n') # light normaly + + else: + #write a dummy material here? + file.write('Ns 0\n') + file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour, + file.write('Kd 0.8 0.8 0.8\n') + file.write('Ks 0.8 0.8 0.8\n') + file.write('d 1\n') # No alpha + file.write('illum 2\n') # light normaly + + # Write images! + if img: # We have an image on the face! + file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image + + elif not mat: # No face image. if we havea material search for MTex image. + for mtex in mat.getTextures(): + if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: + try: + filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1] + file.write('map_Kd %s\n' % filename) # Diffuse mapping image + break + except: + # Texture has no image though its an image type, best ignore. + pass + + file.write('\n\n') + + file.close() + +def copy_file(source, dest): + file = open(source, 'rb') + data = file.read() + file.close() + + file = open(dest, 'wb') + file.write(data) + file.close() + + +def copy_images(dest_dir): + if dest_dir[-1] != sys.sep: + dest_dir += sys.sep + + # Get unique image names + uniqueImages = {} + for matname, mat, image in MTL_DICT.itervalues(): # Only use image name + # Get Texface images + if image: + uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default. + + # Get MTex images + if mat: + for mtex in mat.getTextures(): + if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: + image_tex = mtex.tex.image + if image_tex: + try: + uniqueImages[image_tex] = image_tex + except: + pass + + # Now copy images + copyCount = 0 + + for bImage in uniqueImages.itervalues(): + image_path = sys.expandpath(bImage.filename) + if sys.exists(image_path): + # Make a name for the target path. + dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1] + if not sys.exists(dest_image_path): # Image isnt alredy there + print '\tCopying "%s" > "%s"' % (image_path, dest_image_path) + copy_file(image_path, dest_image_path) + copyCount+=1 + print '\tCopied %d images' % copyCount + +def write(filename, objects,\ +EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_NORMALS_HQ=False,\ +EXPORT_UV=True, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\ +EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\ +EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False): + ''' + Basic write function. The context and options must be alredy set + This can be accessed externaly + eg. + write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. + ''' + + def veckey3d(v): + return round(v.x, 6), round(v.y, 6), round(v.z, 6) + + #def veckey2d(v): + # return round(v.x, 6), round(v.y, 6) + + print 'OBJ Export path: "%s"' % filename + temp_mesh_name = '~tmp-mesh' + + time1 = sys.time() + scn = Scene.GetCurrent() + + file = open(filename, "w") + + # Write Header + file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) + file.write('# www.blender3d.org\n') + + # Tell the obj file what material file to use. + if EXPORT_MTL: + mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1]) + file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] )) + + # Get the container mesh. - used for applying modifiers and non mesh objects. + containerMesh = meshName = tempMesh = None + for meshName in Blender.NMesh.GetNames(): + if meshName.startswith(temp_mesh_name): + tempMesh = Mesh.Get(meshName) + if not tempMesh.users: + containerMesh = tempMesh + if not containerMesh: + containerMesh = Mesh.New(temp_mesh_name) + + if EXPORT_ROTX90: + mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x') + + del meshName + del tempMesh + + # Initialize totals, these are updated each object + totverts = totuvco = totno = 1 + + face_vert_index = 1 # used for uvs now + + globalNormals = {} + + # Get all meshs + for ob_main in objects: + for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): + # Will work for non meshes now! :) + # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) + me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) + if not me: + continue + faceuv= me.faceUV + + # We have a valid mesh + if EXPORT_TRI and me.faces: + # Add a dummy object to it. + has_quads = False + for f in me.faces: + if len(f) == 4: + has_quads = True + break + + if has_quads: + oldmode = Mesh.Mode() + Mesh.Mode(Mesh.SelectModes['FACE']) + + me.sel = True + tempob = scn.objects.new(me) + me.quadToTriangle(0) # more=0 shortest length + oldmode = Mesh.Mode(oldmode) + scn.objects.unlink(tempob) + + Mesh.Mode(oldmode) + + # Make our own list so it can be sorted to reduce context switching + faces = [ f for f in me.faces ] + + if EXPORT_EDGES: + edges = me.edges + else: + edges = [] + + if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write + continue # dont bother with this mesh. + + if EXPORT_ROTX90: + me.transform(ob_mat*mat_xrot90) + else: + me.transform(ob_mat) + + # High Quality Normals + if EXPORT_NORMALS and faces: + if EXPORT_NORMALS_HQ: + BPyMesh.meshCalcNormals(me) + else: + # transforming normals is incorrect + # when the matrix is scaled, + # better to recalculate them + me.calcNormals() + + # # Crash Blender + #materials = me.getMaterials(1) # 1 == will return None in the list. + materials = me.materials + + materialNames = [] + materialItems = materials[:] + if materials: + for mat in materials: + if mat: # !=None + materialNames.append(mat.name) + else: + materialNames.append(None) + # Cant use LC because some materials are None. + # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. + + # Possible there null materials, will mess up indicies + # but at least it will export, wait until Blender gets fixed. + materialNames.extend((16-len(materialNames)) * [None]) + materialItems.extend((16-len(materialItems)) * [None]) + + # Sort by Material, then images + # so we dont over context switch in the obj file. + if EXPORT_MORPH_TARGET: + pass + elif faceuv and EXPORT_UV: + try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth)) + except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth))) + elif len(materials) > 1: + try: faces.sort(key = lambda a: (a.mat, a.smooth)) + except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) + else: + # no materials + try: faces.sort(key = lambda a: a.smooth) + except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth)) + + # Set the default mat to no material and no image. + contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get. + contextSmooth = None # Will either be true or false, set bad to force initialization switch. + + if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB: + name1 = ob.name + name2 = ob.getData(1) + if name1 == name2: + obnamestring = fixName(name1) + else: + obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) + + if EXPORT_BLEN_OBS: + file.write('o %s\n' % obnamestring) # Write Object name + else: # if EXPORT_GROUP_BY_OB: + file.write('g %s\n' % obnamestring) + + + # Vert + for v in me.verts: + file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) + + # UV + if faceuv and EXPORT_UV: + for f in faces: + for uv in f.uv: + file.write('vt %.6f %.6f 0.0\n' % tuple(uv)) + + # NORMAL, Smooth/Non smoothed. + if EXPORT_NORMALS: + for f in faces: + if f.smooth: + for v in f: + noKey = veckey3d(v.no) + if not globalNormals.has_key( noKey ): + globalNormals[noKey] = totno + totno +=1 + file.write('vn %.6f %.6f %.6f\n' % noKey) + else: + # Hard, 1 normal from the face. + noKey = veckey3d(f.no) + if not globalNormals.has_key( noKey ): + globalNormals[noKey] = totno + totno +=1 + file.write('vn %.6f %.6f %.6f\n' % noKey) + if not faceuv: + f_image = None + + for f in faces: + f_v= f.v + f_smooth= f.smooth + f_mat = min(f.mat, len(materialNames)-1) + if faceuv: + f_image = f.image + f_uv= f.uv + + # MAKE KEY + if EXPORT_UV and faceuv and f_image: # Object is always true. + key = materialNames[f_mat], f_image.name + else: + key = materialNames[f_mat], None # No image, use None instead. + + # CHECK FOR CONTEXT SWITCH + if key == contextMat: + pass # Context alredy switched, dont do anythoing + else: + if key[0] == None and key[1] == None: + # Write a null material, since we know the context has changed. + if EXPORT_GROUP_BY_MAT: + file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) + file.write('usemtl (null)\n') # mat, image + + else: + mat_data= MTL_DICT.get(key) + if not mat_data: + # First add to global dict so we can export to mtl + # Then write mtl + + # Make a new names from the mat and image name, + # converting any spaces to underscores with fixName. + + # If none image dont bother adding it to the name + if key[1] == None: + mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image + else: + mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image + + if EXPORT_GROUP_BY_MAT: + file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) + file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) + + contextMat = key + if f_smooth != contextSmooth: + if f_smooth: # on now off + file.write('s 1\n') + contextSmooth = f_smooth + else: # was off now on + file.write('s off\n') + contextSmooth = f_smooth + + file.write('f') + if faceuv and EXPORT_UV: + if EXPORT_NORMALS: + if f_smooth: # Smoothed, use vertex normals + for vi, v in enumerate(f_v): + file.write( ' %d/%d/%d' % (\ + v.index+totverts,\ + face_vert_index + vi,\ + globalNormals[ veckey3d(v.no) ])) # vert, uv, normal + + else: # No smoothing, face normals + no = globalNormals[ veckey3d(f.no) ] + for vi, v in enumerate(f_v): + file.write( ' %d/%d/%d' % (\ + v.index+totverts,\ + face_vert_index + vi,\ + no)) # vert, uv, normal + + else: # No Normals + for vi, v in enumerate(f_v): + file.write( ' %d/%d' % (\ + v.index+totverts,\ + face_vert_index + vi)) # vert, uv + + face_vert_index += len(f_v) + + else: # No UV's + if EXPORT_NORMALS: + if f_smooth: # Smoothed, use vertex normals + for v in f_v: + file.write( ' %d//%d' % (\ + v.index+totverts,\ + globalNormals[ veckey3d(v.no) ])) + else: # No smoothing, face normals + no = globalNormals[ veckey3d(f.no) ] + for v in f_v: + file.write( ' %d//%d' % (\ + v.index+totverts,\ + no)) + else: # No Normals + for v in f_v: + file.write( ' %d' % (\ + v.index+totverts)) + + file.write('\n') + + # Write edges. + if EXPORT_EDGES: + LOOSE= Mesh.EdgeFlags.LOOSE + for ed in edges: + if ed.flag & LOOSE: + file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) + + # Make the indicies global rather then per mesh + totverts += len(me.verts) + me.verts= None + file.close() + + + # Now we have all our materials, save them + if EXPORT_MTL: + write_mtl(mtlfilename) + if EXPORT_COPY_IMAGES: + dest_dir = filename + # Remove chars until we are just the path. + while dest_dir and dest_dir[-1] not in '\\/': + dest_dir = dest_dir[:-1] + if dest_dir: + copy_images(dest_dir) + else: + print '\tError: "%s" could not be used as a base for an image path.' % filename + + print "OBJ Export time: %.2f" % (sys.time() - time1) + + + +def write_ui(filename): + + if not filename.lower().endswith('.obj'): + filename += '.obj' + + if not BPyMessages.Warning_SaveOver(filename): + return + + EXPORT_APPLY_MODIFIERS = Draw.Create(1) + EXPORT_ROTX90 = Draw.Create(1) + EXPORT_TRI = Draw.Create(0) + EXPORT_EDGES = Draw.Create(1) + EXPORT_NORMALS = Draw.Create(0) + EXPORT_NORMALS_HQ = Draw.Create(1) + EXPORT_UV = Draw.Create(1) + EXPORT_MTL = Draw.Create(1) + EXPORT_SEL_ONLY = Draw.Create(1) + EXPORT_ALL_SCENES = Draw.Create(0) + EXPORT_ANIMATION = Draw.Create(0) + EXPORT_COPY_IMAGES = Draw.Create(0) + EXPORT_BLEN_OBS = Draw.Create(1) + EXPORT_GROUP_BY_OB = Draw.Create(0) + EXPORT_GROUP_BY_MAT = Draw.Create(0) + EXPORT_MORPH_TARGET = Draw.Create(0) + + # removed too many options are bad! + + # Get USER Options + pup_block = [\ + ('Context...'),\ + ('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\ + ('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a separate OBJ file.'),\ + ('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\ + ('Object Prefs...'),\ + ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\ + ('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders UP is translated into OBJs UP'),\ + ('Morph Target', EXPORT_MORPH_TARGET, 'Keep vert and face order, disables some other options.'),\ + ('Extra Data...'),\ + ('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\ + ('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\ + ('High Quality Normals', EXPORT_NORMALS_HQ, 'Calculate high quality normals for rendering.'),\ + ('UVs', EXPORT_UV, 'Export texface UV coords.'),\ + ('Materials', EXPORT_MTL, 'Write a separate MTL file with the OBJ.'),\ + ('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\ + ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\ + ('Grouping...'),\ + ('Objects', EXPORT_BLEN_OBS, 'Export blender objects as "OBJ objects".'),\ + ('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as "OBJ Groups".'),\ + ('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\ + ] + + if not Draw.PupBlock('Export...', pup_block): + return + + if EXPORT_MORPH_TARGET.val: + EXPORT_BLEN_OBS.val = False + EXPORT_GROUP_BY_OB.val = False + EXPORT_GROUP_BY_MAT.val = False + EXPORT_GROUP_BY_MAT.val = False + EXPORT_APPLY_MODIFIERS.val = False + + Window.EditMode(0) + Window.WaitCursor(1) + + EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val + EXPORT_ROTX90 = EXPORT_ROTX90.val + EXPORT_TRI = EXPORT_TRI.val + EXPORT_EDGES = EXPORT_EDGES.val + EXPORT_NORMALS = EXPORT_NORMALS.val + EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ.val + EXPORT_UV = EXPORT_UV.val + EXPORT_MTL = EXPORT_MTL.val + EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val + EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val + EXPORT_ANIMATION = EXPORT_ANIMATION.val + EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val + EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val + EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val + EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val + EXPORT_MORPH_TARGET = EXPORT_MORPH_TARGET.val + + + + base_name, ext = splitExt(filename) + context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension + + # Use the options to export the data using write() + # def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True): + orig_scene = Scene.GetCurrent() + if EXPORT_ALL_SCENES: + export_scenes = Scene.Get() + else: + export_scenes = [orig_scene] + + # Export all scenes. + for scn in export_scenes: + scn.makeCurrent() # If alredy current, this is not slow. + context = scn.getRenderingContext() + orig_frame = Blender.Get('curframe') + + if EXPORT_ALL_SCENES: # Add scene name into the context_name + context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied. + + # Export an animation? + if EXPORT_ANIMATION: + scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame. + else: + scene_frames = [orig_frame] # Dont export an animation. + + # Loop through all frames in the scene and export. + for frame in scene_frames: + if EXPORT_ANIMATION: # Add frame to the filename. + context_name[2] = '_%.6d' % frame + + Blender.Set('curframe', frame) + if EXPORT_SEL_ONLY: + export_objects = scn.objects.context + else: + export_objects = scn.objects + + full_path= ''.join(context_name) + + # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. + # EXPORT THE FILE. + write(full_path, export_objects,\ + EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\ + EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\ + EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\ + EXPORT_ROTX90, EXPORT_BLEN_OBS,\ + EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_MORPH_TARGET) + + Blender.Set('curframe', orig_frame) + + # Restore old active scene. + orig_scene.makeCurrent() + Window.WaitCursor(0) + + +if __name__ == '__main__': + Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj')) diff --git a/release/scripts/faceselect_same_weights.py b/release/scripts/faceselect_same_weights.py new file mode 100644 index 00000000000..b8d50cf09b6 --- /dev/null +++ b/release/scripts/faceselect_same_weights.py @@ -0,0 +1,111 @@ +#!BPY +""" +Name: 'Same Weights...' +Blender: 241 +Group: 'FaceSelect' +Tooltip: 'Select same faces with teh same weight for the active group.' +""" + +__author__ = ["Campbell Barton"] +__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__version__ = "0.1" +__bpydoc__ = """\ + +Select Same Weights + +Select same weights as the active face on the active group. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import Scene, Draw, Mesh +import BPyMesh + +def selSameWeights(me, PREF_TOLERENCE): + + # Check for missing data + if not me.faceUV: return + + act_group= me.activeGroup + if not act_group: return + + act_face = me.faces[me.activeFace] + if act_face == None: return + + + + groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) + + def get_face_weight(f): + ''' + Return the faces median weight and weight range. + ''' + wmin = 1.0 + wmax = 0.0 + w = 0.0 + for v in f: + try: + new_weight = vWeightDict[v.index][act_group] + if wmin > new_weight: wmin = new_weight + if wmax < new_weight: wmax = new_weight + w += new_weight + except: + pass + return w, wmax-wmin # weight, range + + weight_from, weight_range_from = get_face_weight(act_face) + for f in me.faces: + if (not f.sel) and f != act_face: + weight, weight_range = get_face_weight(f) + + # Compare the 2 faces weight difference and difference in their contrast. + if\ + abs(weight - weight_from) <= PREF_TOLERENCE and\ + abs(weight_range - weight_range_from) <= PREF_TOLERENCE: + f.sel = True + + +def main(): + scn= Scene.GetCurrent() + ob= scn.objects.active + + if not ob or ob.type != 'Mesh': + Draw.PupMenu('Error, no active mesh object, aborting.') + return + + me= ob.getData(mesh=1) + + PREF_TOLERENCE= Draw.Create(0.1) + + pup_block= [\ + ('Tolerence:', PREF_TOLERENCE, 0.01, 1.0, 'Tolerence for selecting faces of the same weight.'),\ + ] + + if not Draw.PupBlock('Select Same Weight...', pup_block): + return + + PREF_TOLERENCE= PREF_TOLERENCE.val + + selSameWeights(me, PREF_TOLERENCE) + +if __name__=='__main__': + main() \ No newline at end of file diff --git a/release/scripts/flt_export.py b/release/scripts/flt_export.py new file mode 100644 index 00000000000..283c24a3ad0 --- /dev/null +++ b/release/scripts/flt_export.py @@ -0,0 +1,722 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'OpenFlight (.flt)...' +Blender: 237 +Group: 'Export' +Tip: 'Export to OpenFlight v16.0 (.flt)' +""" + +__author__ = "Greg MacDonald" +__version__ = "1.2 10/20/05" +__url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") +__bpydoc__ = """\ +This script exports v16.0 OpenFlight files. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. + +Run from "File->Export" menu. + +Options are available from Blender's "Scripts Config Editor," accessible through +the "Scripts->System" menu from the scripts window. + +Features:
+* Heirarchy retained.
+* Normals retained.
+* First texture exported.
+* Diffuse material color is exported as the face color, material color, or both +depending on the option settings.
+* Double sided faces are exported as two faces.
+* Object transforms exported. + +Things To Be Aware Of:
+* Object names are exported, not mesh or data names. +* Material indices that don't have a material associated with them will confuse the +exporter. If a warning appears about this, correct it by deleting the offending +material indices in Blender. + +What's Not Handled:
+* Animations.
+* Vetex colors.
+""" + +# flt_export.py is an OpenFlight exporter for blender. +# Copyright (C) 2005 Greg MacDonald +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import Blender +from flt_filewalker import FltOut + +class ExporterOptions: + def __init__(self): + self.defaults = { 'Diffuse Color To OpenFlight Material': False, + 'Diffuse Color To OpenFlight Face': True} + + d = Blender.Registry.GetKey('flt_export', True) + + if d == None or d.keys() != self.defaults.keys(): + d = self.defaults + Blender.Registry.SetKey('flt_export', d, True) + + self.verbose = 1 + self.tolerance = 0.001 + self.use_mat_color = d['Diffuse Color To OpenFlight Material'] + self.use_face_color = d['Diffuse Color To OpenFlight Face'] + +options = ExporterOptions() + +FLOAT_TOLERANCE = options.tolerance + +identity_matrix = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] + +def is_identity(m): + for i in xrange(4): + for j in xrange(4): + if abs(m[i][j] - identity_matrix[i][j]) > FLOAT_TOLERANCE: + return False + return True + +class MaterialDesc: + def __init__(self): + self.name = 'Blender' + + # Colors, List of 3 floats. + self.diffuse = [1.0, 1.0, 1.0] + self.specular = [1.0, 1.0, 1.0] + + # Scalars + self.ambient = 0.1 # [0.0, 1.0] + self.emissive = 0.0 # [0.0, 1.0] + self.shininess = 32.0 # Range is [0.0, 128.0] + self.alpha = 1.0 # Range is [0.0, 1.0] + +class VertexDesc: + def __init__(self, co=None, no=None, uv=None): + if co: self.x, self.y, self.z = tuple(co) + else: self.x = self.y = self.z = 0.0 + if no: self.nx, self.ny, self.nz = tuple(no) + else: self.nx = self.ny = self.nz = 0.0 + if uv: self.u, self.v = tuple(uv) + else: self.u = self.v = 0.0 + +class GlobalResourceRepository: + def new_face_name(self): + self.face_name += 1 + return 'f%i' % (self.face_name-1) + + def vertex_count(self): + return len(self.vertex_lst) + + def request_vertex_desc(self, i): + return self.vertex_lst[i] + + def request_vertex_index(self, desc): + match = None + for i, v in enumerate(self.vertex_lst): + if\ + abs(v.x - desc.x) > FLOAT_TOLERANCE or\ + abs(v.y - desc.y) > FLOAT_TOLERANCE or\ + abs(v.z - desc.z) > FLOAT_TOLERANCE or\ + abs(v.nx - desc.nx) > FLOAT_TOLERANCE or\ + abs(v.ny - desc.ny) > FLOAT_TOLERANCE or\ + abs(v.nz - desc.nz) > FLOAT_TOLERANCE or\ + abs(v.u - desc.u) > FLOAT_TOLERANCE or\ + abs(v.v - desc.v) > FLOAT_TOLERANCE: + pass + else: + match = i + break + + if match != None: + return match + else: + self.vertex_lst.append(desc) + return len(self.vertex_lst) - 1 + + def request_texture_index(self, filename): + match = None + for i in xrange(len(self.texture_lst)): + if self.texture_lst[i] != filename: + continue + match = i + break + if match != None: + return match + else: + self.texture_lst.append(filename) + return len(self.texture_lst) - 1 + + def request_texture_filename(self, index): + return self.texture_lst[index] + + def texture_count(self): + return len(self.texture_lst) + + def request_material_index(self, desc): + match = None + for i in xrange(len(self.material_lst)): + if self.material_lst[i].diffuse != desc.diffuse: + continue + if self.material_lst[i].specular != desc.specular: + continue + if self.material_lst[i].ambient != desc.ambient: + continue + if self.material_lst[i].emissive != desc.emissive: + continue + if self.material_lst[i].shininess != desc.shininess: + continue + if self.material_lst[i].alpha != desc.alpha: + continue + match = i + break + + if match != None: + return i + else: + self.material_lst.append(desc) + return len(self.material_lst) - 1 + + def request_material_desc(self, index): + return self.material_lst[index] + + def material_count(self): + return len(self.material_lst) + + # Returns not actual index but one that includes intensity information. + # color_index = 127*intensity + 128*actual_index + def request_color_index(self, col): + r,g,b = tuple(col) + m = max(r, g, b) + if m > 0.0: + intensity = m / 1.0 + r = int(round(r/m * 255.0)) + g = int(round(g/m * 255.0)) + b = int(round(b/m * 255.0)) + brightest = [r, g, b] + else: + brightest = [255, 255, 255] + intensity = 0.0 + + match = None + for i in xrange(len(self.color_lst)): + if self.color_lst[i] != brightest: + continue + + match = i + break + + if match != None: + index = match + else: + length = len(self.color_lst) + if length <= 1024: + self.color_lst.append(brightest) + index = length + else: + if options.verbose >= 1: + print 'Warning: Exceeded max color limit.' + index = 0 + + color_index = int(round(127.0*intensity)) + 128*index + return color_index + + # Returns color from actual index. + def request_max_color(self, index): + return self.color_lst[index] + + def color_count(self): + return len(self.color_lst) + + def __init__(self): + self.vertex_lst = [] + self.texture_lst = [] + self.material_lst = [] + self.color_lst = [[255, 255, 255]] + self.face_name = 0 + +class Node: + # Gathers info from blender needed for export. + # The =[0] is a trick to emulate c-like static function variables + # that are persistant between calls. + def blender_export(self, level=[0]): + if self.object: + if options.verbose >= 2: + print '\t' * level[0], self.name, self.object.type + + level[0] += 1 + + for child in self.children: + child.blender_export() + + level[0] -= 1 + + # Exports this node's info to file. + def write(self): + pass + + def write_matrix(self): + if self.matrix and not is_identity(self.matrix): + self.header.fw.write_short(49) # Matrix opcode + self.header.fw.write_ushort(68) # Length of record + for i in xrange(4): + for j in xrange(4): + self.header.fw.write_float(self.matrix[i][j]) + + def write_push(self): + self.header.fw.write_short(10) + self.header.fw.write_ushort(4) + + def write_pop(self): + self.header.fw.write_short(11) + self.header.fw.write_ushort(4) + + def write_longid(self, name): + length = len(name) + if length >= 8: + self.header.fw.write_short(33) # Long ID opcode + self.header.fw.write_ushort(length+5) # Length of record + self.header.fw.write_string(name, length+1) # name + zero terminator + + # Initialization sets up basic tree structure. + def __init__(self, parent, header, object, object_lst): + self.header = header + self.object = object + if object: + self.name = self.object.name + self.matrix = self.object.getMatrix('localspace') + else: + self.name = 'no name' + self.matrix = None + + self.children = [] + self.parent = parent + if parent: + parent.children.append(self) + + left_over = object_lst[:] + self.child_objects = [] + + # Add children to child list and remove from left_over list. + + # Pop is faster then remove + i = len(object_lst) + while i: + i-=1 + if object_lst[i].parent == object: + self.child_objects.append(left_over.pop(i)) + + # Spawn children. + self.has_object_child = False # For Database class. + for child in self.child_objects: + if child.type == 'Mesh': + BlenderMesh(self, header, child, left_over) + self.has_object_child = True + else: # Treat all non meshes as emptys + BlenderEmpty(self, header, child, left_over) + +class FaceDesc: + def __init__(self): + self.vertex_index_lst = [] + self.texture_index = -1 + self.material_index = -1 + self.color_index = 127 + +class BlenderMesh(Node): + def blender_export(self): + Node.blender_export(self) + + mesh = self.object.getData() + mesh_hasuv = mesh.hasFaceUV() + # Gather materials and textures. + tex_index_lst = [] + mat_index_lst = [] + color_index_lst = [] + materials = mesh.getMaterials() + + if not materials: + materials = [Blender.Material.New()] + + for mat in materials: + # Gather Color. + if options.use_face_color: + color_index_lst.append(self.header.GRR.request_color_index(mat.getRGBCol())) + else: + color_index_lst.append(127) # white + # Gather Texture. + mtex_lst = mat.getTextures() + + index = -1 + mtex = mtex_lst[0] # Not doing multi-texturing at the moment. + if mtex != None: + tex = mtex_lst[0].tex + if tex != None: + image = tex.getImage() + if image != None: + filename = image.getFilename() + index = self.header.GRR.request_texture_index(filename) + + tex_index_lst.append(index) + + # Gather Material + mat_desc = MaterialDesc() + mat_desc.name = mat.name + mat_desc.alpha = mat.getAlpha() + mat_desc.shininess = mat.getSpec() * 64.0 # 2.0 => 128.0 + if options.use_mat_color: + mat_desc.diffuse = mat.getRGBCol() + else: + mat_desc.diffuse = [1.0, 1.0, 1.0] + + mat_desc.specular = mat.getSpecCol() + amb = mat.getAmb() + mat_desc.ambient = [amb, amb, amb] + emit = mat.getEmit() + mat_desc.emissive = [emit, emit, emit] + + mat_index_lst.append(self.header.GRR.request_material_index(mat_desc)) + + # Faces described as lists of indices into the GRR's vertex_lst. + for face in mesh.faces: + + face_v = face.v # Faster access + + # Create vertex description list for each face. + if mesh_hasuv: + vertex_lst = [VertexDesc(v.co, v.no, face.uv[i]) for i, v in enumerate(face_v)] + else: + vertex_lst = [VertexDesc(v.co, v.no) for i, v in enumerate(face_v)] + + index_lst = [] + for vert_desc in vertex_lst: + index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) + + face_desc = FaceDesc() + face_desc.vertex_index_lst = index_lst + + if face.materialIndex < len(materials): + face_desc.color_index = color_index_lst[face.materialIndex] + face_desc.texture_index = tex_index_lst[face.materialIndex] + face_desc.material_index = mat_index_lst[face.materialIndex] + else: + if options.verbose >=1: + print 'Warning: Missing material for material index. Materials will not be imported correctly. Fix by deleting abandoned material indices in Blender.' + + self.face_lst.append(face_desc) + + # Export double sided face as 2 faces with opposite orientations. + if mesh_hasuv and face.mode & Blender.NMesh.FaceModes['TWOSIDE']: + # Create vertex description list for each face. they have a face mode, so we know they have a UV too. + vertex_lst = [VertexDesc(v.co, -v.no, face.uv[i]) for i, v in enumerate(face_v)] + vertex_lst.reverse() # Reversing flips the face. + + index_lst = [] + for vert_desc in vertex_lst: + index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) + + face_desc = FaceDesc() + face_desc.vertex_index_lst = index_lst + if face.materialIndex < len(materials): + face_desc.color_index = color_index_lst[face.materialIndex] + face_desc.texture_index = tex_index_lst[face.materialIndex] + face_desc.material_index = mat_index_lst[face.materialIndex] + else: + if options.verbose >=1: + print 'Error: No material for material index. Delete abandoned material indices in Blender.' + + self.face_lst.append(face_desc) + + def write_faces(self): + for face_desc in self.face_lst: + face_name = self.header.GRR.new_face_name() + + self.header.fw.write_short(5) # Face opcode + self.header.fw.write_ushort(80) # Length of record + self.header.fw.write_string(face_name, 8) # ASCII ID + self.header.fw.write_int(-1) # IR color code + self.header.fw.write_short(0) # Relative priority + self.header.fw.write_char(0) # Draw type + self.header.fw.write_char(0) # Draw textured white. + self.header.fw.write_ushort(0) # Color name index + self.header.fw.write_ushort(0) # Alt color name index + self.header.fw.write_char(0) # Reserved + self.header.fw.write_char(1) # Template + self.header.fw.write_short(-1) # Detail tex pat index + self.header.fw.write_short(face_desc.texture_index) # Tex pattern index + self.header.fw.write_short(face_desc.material_index) # material index + self.header.fw.write_short(0) # SMC code + self.header.fw.write_short(0) # Feature code + self.header.fw.write_int(0) # IR material code + self.header.fw.write_ushort(0) # transparency 0 = opaque + self.header.fw.write_uchar(0) # LOD generation control + self.header.fw.write_uchar(0) # line style index + self.header.fw.write_int(0x00000000) # Flags + self.header.fw.write_uchar(2) # Light mode + self.header.fw.pad(7) # Reserved + self.header.fw.write_uint(-1) # Packed color + self.header.fw.write_uint(-1) # Packed alt color + self.header.fw.write_short(-1) # Tex map index + self.header.fw.write_short(0) # Reserved + self.header.fw.write_uint(face_desc.color_index) # Color index + self.header.fw.write_uint(127) # Alt color index + self.header.fw.write_short(0) # Reserved + self.header.fw.write_short(-1) # Shader index + + self.write_longid(face_name) + + self.write_push() + + # Vertex list record + self.header.fw.write_short(72) # Vertex list opcode + num_verts = len(face_desc.vertex_index_lst) + self.header.fw.write_ushort(4*num_verts+4) # Length of record + + for vert_index in face_desc.vertex_index_lst: + # Offset into vertex palette + self.header.fw.write_int(vert_index*64+8) + + self.write_pop() + + def write(self): + if self.open_flight_type == 'Object': + self.header.fw.write_short(4) # Object opcode + self.header.fw.write_ushort(28) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(16) + + self.write_longid(self.name) + + self.write_matrix() + + if self.face_lst != []: + self.write_push() + + self.write_faces() + + self.write_pop() + else: + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(32) + + self.write_longid(self.name) + + # Because a group can contain faces as well as children. + self.write_push() + + self.write_faces() + + for child in self.children: + child.write() + + self.write_pop() + + def __init__(self, parent, header, object, object_lst): + Node.__init__(self, parent, header, object, object_lst) + self.face_lst = [] + + if self.children: + self.open_flight_type= 'Group' + else: # Empty list. + self.open_flight_type = 'Object' + + +class BlenderEmpty(Node): + def write(self): + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string(self.name, 8) # ASCII ID + self.header.fw.pad(32) + + self.write_longid(self.name) + + self.write_matrix() + + if self.children: # != [] + self.write_push() + + for child in self.children: + child.write() + + self.write_pop() + +class Database(Node): + def write_header(self): + if options.verbose >= 2: + print 'Writing header.' + self.fw.write_short(1) # Header opcode + self.fw.write_ushort(324) # Length of record + self.fw.write_string('db', 8) # ASCII ID + self.fw.write_int(1600) # Revision Number + self.fw.pad(44) + self.fw.write_short(1) # Unit multiplier. + self.fw.write_char(0) # Units, 0 = meters + self.fw.write_char(0) # texwhite on new faces 0 = false + self.fw.write_uint(0x80000000) # misc flags set to saving vertex normals + self.fw.pad(24) + self.fw.write_int(0) # projection type, 0 = flat earth + self.fw.pad(30) + self.fw.write_short(1) # double precision + self.fw.pad(140) + self.fw.write_int(0) # ellipsoid model, 0 = WSG 1984 + self.fw.pad(52) + + def write_vert_pal(self): + if options.verbose >= 2: + print 'Writing vertex palette.' + # Write record for vertex palette + self.fw.write_short(67) # Vertex palette opcode. + self.fw.write_short(8) # Length of record + self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything. + + # Write records for individual vertices. + for i in xrange(self.GRR.vertex_count()): + desc = self.GRR.request_vertex_desc(i) + self.fw.write_short(70) # Vertex with color normal and uv opcode. + self.fw.write_ushort(64) # Length of record + self.fw.write_ushort(0) # Color name index + self.fw.write_short(0x2000) # Flags set to no color + self.fw.write_double(desc.x) + self.fw.write_double(desc.y) + self.fw.write_double(desc.z) + self.fw.write_float(desc.nx) + self.fw.write_float(desc.ny) + self.fw.write_float(desc.nz) + self.fw.write_float(desc.u) + self.fw.write_float(desc.v) + self.fw.pad(12) + + def write_tex_pal(self): + if options.verbose >= 2: + print 'Writing texture palette.' + # Write record for texture palette + for i in xrange(self.GRR.texture_count()): + self.fw.write_short(64) # Texture palette opcode. + self.fw.write_short(216) # Length of record + self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename + self.fw.write_int(i) # Texture index + self.fw.write_int(0) # X + self.fw.write_int(0) # Y + + def write_mat_pal(self): + if options.verbose >= 2: + print 'Writing material palette.' + for i in xrange(self.GRR.material_count()): + desc = self.GRR.request_material_desc(i) + self.fw.write_short(113) # Material palette opcode. + self.fw.write_short(84) # Length of record + self.fw.write_int(i) # Material index + self.fw.write_string(desc.name, 12) # Material name + self.fw.write_uint(0x80000000) # Flags + self.fw.write_float(desc.ambient[0]) # Ambient color. + self.fw.write_float(desc.ambient[1]) # Ambient color. + self.fw.write_float(desc.ambient[2]) # Ambient color. + self.fw.write_float(desc.diffuse[0]) # Diffuse color. + self.fw.write_float(desc.diffuse[1]) # Diffuse color. + self.fw.write_float(desc.diffuse[2]) # Diffuse color. + self.fw.write_float(desc.specular[0]) # Specular color. + self.fw.write_float(desc.specular[1]) # Specular color. + self.fw.write_float(desc.specular[2]) # Specular color. + self.fw.write_float(desc.emissive[0]) # Emissive color. + self.fw.write_float(desc.emissive[1]) # Emissive color. + self.fw.write_float(desc.emissive[2]) # Emissive color. + self.fw.write_float(desc.shininess) + self.fw.write_float(desc.alpha) + self.fw.write_int(0) # Reserved + + def write_col_pal(self): + if options.verbose >= 2: + print 'Writing color palette.' + self.fw.write_short(32) # Color palette opcode. + self.fw.write_short(4228) # Length of record + self.fw.pad(128) + count = self.GRR.color_count() + for i in xrange(count): + col = self.GRR.request_max_color(i) + self.fw.write_uchar(255) # alpha + self.fw.write_uchar(col[2]) # b + self.fw.write_uchar(col[1]) # g + self.fw.write_uchar(col[0]) # r + self.fw.pad(max(4096-count*4, 0)) + + def write(self): + self.write_header() + self.write_vert_pal() + self.write_tex_pal() + self.write_mat_pal() + self.write_col_pal() + + # Wrap everything in a group if it has an object child. + if self.has_object_child: + self.header.fw.write_short(2) # Group opcode + self.header.fw.write_ushort(44) # Length of record + self.header.fw.write_string('g1', 8) # ASCII ID + self.header.fw.pad(32) + + self.write_push() + + for child in self.children: + child.write() + + self.write_pop() + + def __init__(self, scene, fw): + self.fw = fw + self.scene = scene + self.all_objects = list(scene.objects) + self.GRR = GlobalResourceRepository() + + Node.__init__(self, None, self, None, self.all_objects) + +def fs_callback(filename): + Blender.Window.WaitCursor(True) + + if Blender.sys.exists(filename): + r = Blender.Draw.PupMenu('Overwrite ' + filename + '?%t|Yes|No') + if r != 1: + if options.verbose >= 1: + print 'Export cancelled.' + return + + time1 = Blender.sys.time() # Start timing + + fw = FltOut(filename) + + db = Database(Blender.Scene.GetCurrent(), fw) + + if options.verbose >= 1: + print 'Pass 1: Exporting from Blender.\n' + + db.blender_export() + + if options.verbose >= 1: + print 'Pass 2: Writing %s\n' % filename + + db.write() + + fw.close_file() + if options.verbose >= 1: + print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1) + + Blender.Window.WaitCursor(False) + +if options.verbose >= 1: + print '\nOpenFlight Exporter' + print 'Version:', __version__ + print 'Author: Greg MacDonald' + print __url__[2] + print + +fname = Blender.sys.makename(ext=".flt") +Blender.Window.FileSelector(fs_callback, "Export OpenFlight v16.0", fname) diff --git a/release/scripts/flt_filewalker.py b/release/scripts/flt_filewalker.py new file mode 100644 index 00000000000..442c9728e91 --- /dev/null +++ b/release/scripts/flt_filewalker.py @@ -0,0 +1,279 @@ +#!BPY + +# flt_filewalker.py is an utility module for OpenFlight IO scripts for blender. +# Copyright (C) 2005 Greg MacDonald +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import Blender +from struct import * +import re + +class FltIn: + def __init__(self, filename): + self.file = open(filename, 'rb') + self.position = 0 + self.next_position = 100000 + self.opcode = 0 + self.length = 0 + self.level = 0 + self.repeat = False # Repeat the last record. + + def begin_record(self): + if self.repeat == True: + self.repeat = False + else: + self.position += self.length + try: + self.file.seek(self.position) + input = self.file.read(4) + except: + print 'Parse Error!' + return False + + if not input: + self.close_file() + return False + + self.opcode = unpack('>h', input[:2])[0] + self.length = unpack('>H', input[-2:])[0] + + self.next_position = self.position + self.length + + return True + + def repeat_record(self): + self.repeat = True + + def get_opcode(self): + return self.opcode + + def get_level(self): + return self.level + + def up_level(self): + self.level += 1 + + def down_level(self): + self.level -= 1 + + def read_string(self, length): + s = '' + if self.file.tell() + length <= self.next_position: + start = self.file.tell() + for i in xrange(length): + char = self.file.read(1) + if char == '\x00': + break + s = s + char + + self.file.seek(start+length) +# else: +# print 'Warning: string truncated' + + return s + + def read_int(self): + if self.file.tell() + 4 <= self.next_position: + return unpack('>i', self.file.read(4))[0] + else: + #print 'Warning: int truncated' + return 0 + + def read_uint(self): + if self.file.tell() + 4 <= self.next_position: + return unpack('>I', self.file.read(4))[0] + else: + #print 'Warning: uint truncated' + return 0 + + def read_double(self): + if self.file.tell() + 8 <= self.next_position: + return unpack('>d', self.file.read(8))[0] + else: + #print 'Warning: double truncated' + return 0.0 + + def read_float(self): + if self.file.tell() + 4 <= self.next_position: + return unpack('>f', self.file.read(4))[0] + else: + #print 'Warning: float truncated' + return 0.0 + + def read_ushort(self): + if self.file.tell() + 2 <= self.next_position: + return unpack('>H', self.file.read(2))[0] + else: + #print 'Warning: ushort truncated' + return 0 + + def read_short(self): + if self.file.tell() + 2 <= self.next_position: + return unpack('>h', self.file.read(2))[0] + else: + #print 'Warning: short trunated' + return 0 + + def read_uchar(self): + if self.file.tell() + 1 <= self.next_position: + return unpack('>B', self.file.read(1))[0] + else: + #print 'Warning: uchar truncated' + return 0 + + def read_char(self): + if self.file.tell() + 1 <= self.next_position: + return unpack('>b', self.file.read(1))[0] + else: + #print 'Warning: char truncated' + return 0 + + def read_ahead(self, i): + if self.file.tell() + i <= self.next_position: + self.file.seek(i, 1) +# else: +# print 'Warning: attempt to seek past record' + + def get_length(self): + return self.length + + def close_file(self): + self.file.close() + +class FltOut: + # Length includes terminating null + def write_string(self, string, length): + if len(string) > length - 1: + str_len = length - 1 + else: + str_len = len(string) + + pad_len = length - str_len + + self.file.write(string[:str_len]) + + self.pad(pad_len) + + def write_int(self, a): + self.file.write( pack('>i', a) ) + + def write_uint(self, a): + self.file.write( pack('>I', a) ) + + def write_double(self, a): + self.file.write( pack('>d', a) ) + + def write_float(self, a): + self.file.write( pack('>f', a) ) + + def write_ushort(self, a): + self.file.write( pack('>H', a) ) + + def write_short(self, a): + self.file.write( pack('>h', a) ) + + def write_uchar(self, a): + self.file.write( pack('>B', a) ) + + def write_char(self, a): + self.file.write( pack('>b', a) ) + + def pad(self, reps): + for i in xrange(reps): + self.file.write('\x00') + + def close_file(self): + self.file.close() + + def __init__(self, filename): + self.file = open(filename, 'wb') + +class FileFinder: + def add_file_to_search_path(self, filename): + dir = Blender.sys.dirname(filename) + if dir != None and dir != '': + self.search_dirs.append(dir) + + def strip_path(self, full_path): + # One of my flt files had a windows path with unix seperation. Basename + # returned the whole path + filename, which isn't expected. So my + # attempt to fix it is to replace all / or \ with the platform specific + # dir seperator. + # + # note: \\\\ is actually just one \ indirected twice, once for python + # then again for re.sub + if Blender.sys.sep == '\\': + full_path = re.sub('/', '\\\\', full_path) + elif Blender.sys.sep == '/': + full_path = re.sub('\\\\', '/', full_path) + + filename = Blender.sys.basename(full_path) + return filename + + def find(self, full_path): + if full_path == '': + return None + + # Seperate out the path. + dirname = Blender.sys.dirname(full_path) + + # Try it first. + if Blender.sys.exists(full_path): + if not dirname in self.search_dirs: + self.search_dirs.append(dirname) + return full_path + + # Maybe it's relative. + for path in self.search_dirs: + rel_full_path = Blender.sys.join(path, full_path) + if Blender.sys.exists(rel_full_path): + return rel_full_path + + # Search previous directories that have worked. + filename = self.strip_path(full_path) + for path in self.search_dirs: + t = Blender.sys.join(path, filename) + if Blender.sys.exists(t): + return t + + # Ask user where it is. + self.user_input = Blender.Draw.PupStrInput(filename + "? ", '', 100) + #self.user_input = None + if self.user_input != None: + t = Blender.sys.join(self.user_input, filename) + if Blender.sys.exists(t): + user_dirname = Blender.sys.dirname(t) + if not user_dirname in self.search_dirs: + self.search_dirs.append(user_dirname) + return t + + # Couldn't find it. + return None + + def __init__(self): + self.user_input = '' + self.current_file = '' + self.search_dirs = [] + + dir = Blender.Get('texturesdir') + if dir != None and dir != '': + self.search_dirs.append(dir) + + dir = Blender.sys.dirname(Blender.Get('filename')) + if dir != None and dir != '': + print dir + self.search_dirs.append(dir) + \ No newline at end of file diff --git a/release/scripts/flt_import.py b/release/scripts/flt_import.py new file mode 100644 index 00000000000..ca0db650447 --- /dev/null +++ b/release/scripts/flt_import.py @@ -0,0 +1,1890 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'OpenFlight (.flt)...' +Blender: 238 +Group: 'Import' +Tip: 'Import OpenFlight (.flt)' +""" + +__author__ = "Greg MacDonald, Campbell Barton" +__version__ = "1.2 10/20/05" +__url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") +__bpydoc__ = """\ +This script imports OpenFlight files into Blender. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. + +Run from "File->Import" menu. + +Options are available from Blender's "Scripts Config Editor," accessible through +the "Scripts->System" menu from the scripts window. + +All global_prefs are toggle switches that let the user choose what is imported. Most +are straight-forward, but one option could be a source of confusion. The +"Diffuse Color From Face" option when set pulls the diffuse color from the face +colors. Otherwise the diffuse color comes from the material. What may be +confusing is that this global_prefs only works if the "Diffuse Color" option is set. + +New Features:
+* Importer is 14 times faster.
+* External triangle module is no longer required, but make sure the importer +has a 3d View screen open while its running or triangulation won't work.
+* Should be able to import all versions of flight files. + +Features:
+* Heirarchy retained.
+* First texture imported.
+* Colors imported from face or material.
+* LOD seperated out into different layers.
+* Asks for location of unfound textures or external references.
+* Searches Blender's texture directory in the user preferences panel.
+* Triangles with more than 4 verts are triangulated if the Triangle python +module is installed.
+* Matrix transforms imported.
+* External references to whole files are imported. + +Things To Be Aware Of:
+* Each new color and face attribute creates a new material and there are only a maximum of 16 +materials per object.
+* For triangulated faces, normals must be recomputed outward manually by typing +CTRL+N in edit mode.
+* You can change global_prefs only after an initial import.
+* External references are imported as geometry and will be exported that way.
+* A work around for not using the Triangle python module is to simply to +triangulate in Creator before importing. This is only necessary if your +model contains 5 or more vertices.
+* You have to manually blend the material color with the texture color. + +What's Not Handled:
+* Special texture repeating modes.
+* Replications and instancing.
+* Comment and attribute fields.
+* Light points.
+* Animations.
+* External references to a node within a file.
+* Multitexturing.
+* Vetex colors.
+""" + +# flt_import.py is an OpenFlight importer for blender. +# Copyright (C) 2005 Greg MacDonald +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import Blender +import os +import BPyMesh +import BPyImage +import flt_filewalker + +Vector= Blender.Mathutils.Vector + +def col_to_gray(c): + return 0.3*c[0] + 0.59*c[1] + 0.11*c[2] + + +global_prefs = dict() +global_prefs['verbose']= 1 +global_prefs['get_texture'] = True +global_prefs['get_diffuse'] = True +global_prefs['get_specular'] = False +global_prefs['get_emissive'] = False +global_prefs['get_alpha'] = True +global_prefs['get_ambient'] = False +global_prefs['get_shininess'] = True +global_prefs['color_from_face'] = True +global_prefs['fltfile']= '' +msg_once = False + +class MaterialDesc: + # Was going to use int(f*1000.0) instead of round(f,3), but for some reason + # round produces better results, as in less dups. + def make_key(self): + key = list() + if global_prefs['get_texture']: + if self.tex0: + key.append(self.tex0.getName()) + else: + key.append(None) + + if global_prefs['get_alpha']: + key.append(round(self.alpha, 3)) + else: + key.append(None) + + if global_prefs['get_shininess']: + key.append(round(self.shininess, 3)) + else: + key.append(None) + + if global_prefs['get_emissive']: + key.append(round(self.emissive, 3)) + else: + key.append(None) + + if global_prefs['get_ambient']: + key.append(round(self.ambient, 3)) + else: + key.append(None) + + if global_prefs['get_specular']: + for n in self.specular: + key.append(round(n, 3)) + else: + key.extend([None, None, None]) + + if global_prefs['get_diffuse']: + for n in self.diffuse: + key.append(round(n, 3)) + else: + key.extend([None, None, None]) + +# key.extend(self.face_props.values()) + + return tuple(key) + + def __init__(self): + self.name = 'Material' + # Colors, List of 3 floats. + self.diffuse = [1.0, 1.0, 1.0] + self.specular = [1.0, 1.0, 1.0] + + # Scalars + self.ambient = 0.0 # [0.0, 1.0] + self.emissive = 0.0 # [0.0, 1.0] + self.shininess = 0.5 # Range is [0.0, 2.0] + self.alpha = 1.0 # Range is [0.0, 1.0] + + self.tex0 = None + + # OpenFlight Face attributes + self.face_props = dict.fromkeys(['comment', 'ir color', 'priority', + 'draw type', 'texture white', 'template billboard', + 'smc', 'fid', 'ir material', 'lod generation control', + 'flags', 'light mode']) + +class VertexDesc: + def make_key(self): + return round(self.x, 6), round(self.y, 6), round(self.z, 6) + + def __init__(self): + + # Assign later, save memory, all verts have a loc + self.x = 0.0 + self.y = 0.0 + self.z = 0.0 + + ''' # IGNORE_NORMALS + self.nx = 0.0 + self.ny = 1.0 + self.nz = 0.0 + ''' + self.uv= Vector(0,0) + self.r = 1.0 + self.g = 1.0 + self.b = 1.0 + self.a = 1.0 + +class LightPointAppDesc: + def make_key(self): + d = dict(self.props) + del d['id'] + del d['type'] + + if d['directionality'] != 0: # not omni + d['nx'] = 0.0 + d['ny'] = 0.0 + d['nz'] = 0.0 + + return tuple(d.values()) + + def __init__(self): + self.props = dict() + self.props.update({'type': 'LPA'}) + self.props.update({'id': 'ap'}) + # Attribs not found in inline lightpoint. + self.props.update({'visibility range': 0.0}) + self.props.update({'fade range ratio': 0.0}) + self.props.update({'fade in duration': 0.0}) + self.props.update({'fade out duration': 0.0}) + self.props.update({'LOD range ratio': 0.0}) + self.props.update({'LOD scale': 0.0}) + +class GlobalResourceRepository: + def request_lightpoint_app(self, desc): + match = self.light_point_app.get(desc.make_key()) + + if match: + return match.getName() + else: + # Create empty and fill with properties. + name = desc.props['type'] + ': ' + desc.props['id'] + object = Blender.Object.New('Empty', name) + scene.link(object) + object.Layers= current_layer + object.sel= 1 + + # Attach properties + for name, value in desc.props.iteritems(): + object.addProperty(name, value) + + self.light_point_app.update({desc.make_key(): object}) + + return object.getName() + + # Dont use request_vert - faster to make it from the vector direct. + """ + def request_vert(self, desc): + match = self.vert_dict.get(desc.make_key()) + + if match: + return match + else: + vert = Blender.Mathutils.Vector(desc.x, desc.y, desc.z) + ''' IGNORE_NORMALS + vert.no[0] = desc.nx + vert.no[1] = desc.ny + vert.no[2] = desc.nz + ''' + self.vert_dict.update({desc.make_key(): vert}) + return vert + """ + def request_mat(self, mat_desc): + match = self.mat_dict.get(mat_desc.make_key()) + if match: return match + + mat = Blender.Material.New(mat_desc.name) + + if mat_desc.tex0 != None: + mat.setTexture(0, mat_desc.tex0, Blender.Texture.TexCo.UV) + + mat.setAlpha(mat_desc.alpha) + mat.setSpec(mat_desc.shininess) + mat.setHardness(255) + mat.setEmit(mat_desc.emissive) + mat.setAmb(mat_desc.ambient) + mat.setSpecCol(mat_desc.specular) + mat.setRGBCol(mat_desc.diffuse) + + # Create a text object to store openflight face attribs until + # user properties can be set on materials. +# t = Blender.Text.New('FACE: ' + mat.getName()) +# +# for name, value in mat_desc.face_props.items(): +# t.write(name + '\n' + str(value) + '\n\n') + + self.mat_dict.update({mat_desc.make_key(): mat}) + + return mat + + def request_image(self, filename_with_path): + if not global_prefs['get_texture']: return None + return BPyImage.comprehensiveImageLoad(filename_with_path, global_prefs['fltfile']) # Use join in case of spaces + + def request_texture(self, image): + if not global_prefs['get_texture']: + return None + + tex = self.tex_dict.get(image.filename) + if tex: return tex + + tex = Blender.Texture.New(Blender.sys.basename(image.filename)) + tex.setImage(image) + tex.setType('Image') + self.tex_dict.update({image.filename: tex}) + return tex + + def __init__(self): + # material + self.mat_dict = dict() + mat_lst = Blender.Material.Get() + for mat in mat_lst: + mat_desc = MaterialDesc() + mapto_lst = mat.getTextures() + if mapto_lst[0]: + mat_desc.tex0 = mapto_lst[0].tex + else: + mat_desc.tex0 = None + mat_desc.alpha = mat.getAlpha() + mat_desc.shininess = mat.getSpec() + mat_desc.emissive = mat.getEmit() + mat_desc.ambient = mat.getAmb() + mat_desc.specular = mat.getSpecCol() + mat_desc.diffuse = mat.getRGBCol() + + self.mat_dict.update({mat_desc.make_key(): mat}) + + # texture + self.tex_dict = dict() + tex_lst = Blender.Texture.Get() + + for tex in tex_lst: + img = tex.getImage() + # Only interested in textures with images. + if img: + self.tex_dict.update({img.filename: tex}) + + # vertex + # self.vert_dict = dict() + + # light point + self.light_point_app = dict() + +# Globals +GRR = GlobalResourceRepository() +FF = flt_filewalker.FileFinder() +scene = Blender.Scene.GetCurrent() # just hope they dont chenge scenes once the file selector pops up. +current_layer = 0x01 + + +# Opcodes that indicate its time to return control to parent. +throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63] +do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125] + +opcode_name = { 0: 'db', + 1: 'head', + 2: 'grp', + 4: 'obj', + 5: 'face', + 10: 'push', + 11: 'pop', + 14: 'dof', + 19: 'push sub', + 20: 'pop sub', + 21: 'push ext', + 22: 'pop ext', + 23: 'cont', + 31: 'comment', + 32: 'color pal', + 33: 'long id', + 49: 'matrix', + 50: 'vector', + 52: 'multi-tex', + 53: 'uv lst', + 55: 'bsp', + 60: 'rep', + 61: 'inst ref', + 62: 'inst def', + 63: 'ext ref', + 64: 'tex pal', + 67: 'vert pal', + 68: 'vert w col', + 69: 'vert w col & norm', + 70: 'vert w col, norm & uv', + 71: 'vert w col & uv', + 72: 'vert lst', + 73: 'lod', + 74: 'bndin box', + 76: 'rot edge', + 78: 'trans', + 79: 'scl', + 80: 'rot pnt', + 81: 'rot and/or scale pnt', + 82: 'put', + 83: 'eyepoint & trackplane pal', + 84: 'mesh', + 85: 'local vert pool', + 86: 'mesh prim', + 87: 'road seg', + 88: 'road zone', + 89: 'morph vert lst', + 90: 'link pal', + 91: 'snd', + 92: 'rd path', + 93: 'snd pal', + 94: 'gen matrix', + 95: 'txt', + 96: 'sw', + 97: 'line styl pal', + 98: 'clip reg', + 100: 'ext', + 101: 'light src', + 102: 'light src pal', + 103: 'reserved', + 104: 'reserved', + 105: 'bndin sph', + 106: 'bndin cyl', + 107: 'bndin hull', + 108: 'bndin vol cntr', + 109: 'bndin vol orient', + 110: 'rsrvd', + 111: 'light pnt', + 112: 'tex map pal', + 113: 'mat pal', + 114: 'name tab', + 115: 'cat', + 116: 'cat dat', + 117: 'rsrvd', + 118: 'rsrvd', + 119: 'bounding hist', + 120: 'rsrvd', + 121: 'rsrvd', + 122: 'push attrib', + 123: 'pop attrib', + 124: 'rsrvd', + 125: 'rsrvd', + 126: 'curv', + 127: 'road const', + 128: 'light pnt appear pal', + 129: 'light pnt anim pal', + 130: 'indexed lp', + 131: 'lp sys', + 132: 'indx str', + 133: 'shdr pal'} + +class Handler: + def in_throw_back_lst(self, opcode): + return opcode in self.throw_back_lst + + def handle(self, opcode): + return self.handler[opcode]() + + def handles(self, opcode): + return opcode in self.handler.iterkeys() + + def throws_back_all_unhandled(self): + return self.throw_back_unhandled + + def set_throw_back_lst(self, a): + self.throw_back_lst = a + + def set_throw_back_all_unhandled(self): + self.throw_back_unhandled = True + + def set_only_throw_back_specified(self): + self.throw_back_unhandled = False + + def set_handler(self, d): + self.handler = d + + def __init__(self): + # Dictionary of opcodes to handler methods. + self.handler = dict() + # Send all opcodes not handled to the parent node. + self.throw_back_unhandled = False + # If throw_back_unhandled is False then only throw back + # if the opcodes in throw_back are encountered. + self.throw_back_lst = list() + +class Node: + def blender_import(self): + if self.opcode in opcode_name and global_prefs['verbose'] >= 2: + for i in xrange(self.get_level()): + print ' ', + print opcode_name[self.opcode], + print '-', self.props['id'], + print '-', self.props['comment'], + + print + + for child in self.children: + child.blender_import() + + # Import comment. +# if self.props['comment'] != '': +# name = 'COMMENT: ' + self.props['id'] +# t = Blender.Text.New(name) +# t.write(self.props['comment']) +# self.props['comment'] = name + + # Always ignore extensions and anything in between them. + def parse_push_extension(self): + self.saved_handler = self.active_handler + self.active_handler = self.extension_handler + return True + + def parse_pop_extension(self): + self.active_handler = self.saved_handler + return True + + def parse_push(self): + self.header.fw.up_level() + # Ignore unknown children. + self.ignore_unhandled = True + # Don't do child records that might overwrite parent info. ex: longid + self.active_handler = self.child_handler + return True + + def parse_pop(self): + self.header.fw.down_level() + + if self.header.fw.get_level() == self.level: + return False + + return True + + def parse(self): + while self.header.fw.begin_record(): + opcode = self.header.fw.get_opcode() + + # Print out info on opcode and tree level. + if global_prefs['verbose'] >= 3: + p = '' + for i in xrange(self.header.fw.get_level()): + p = p + ' ' + if opcode in opcode_name: + p = p + opcode_name[opcode] + else: + if global_prefs['verbose'] >= 1: + print 'undocumented opcode', opcode + continue + + if self.global_handler.handles(opcode): + if global_prefs['verbose'] >= 3: + print p + ' handled globally' + if self.global_handler.handle(opcode) == False: + break + + elif self.active_handler.handles(opcode): + if global_prefs['verbose'] >= 4: + print p + ' handled' + if self.active_handler.handle(opcode) == False: + break + + else: + if self.active_handler.throws_back_all_unhandled(): + if global_prefs['verbose'] >= 3: + print p + ' handled elsewhere' + self.header.fw.repeat_record() + break + + elif self.active_handler.in_throw_back_lst(opcode): + if global_prefs['verbose'] >= 3: + print p + ' handled elsewhere' + self.header.fw.repeat_record() + break + + else: + if global_prefs['verbose'] >= 3: + print p + ' ignored' + elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name: + print opcode_name[opcode], 'not handled' + + def get_level(self): + return self.level + + def parse_long_id(self): + self.props['id'] = self.header.fw.read_string(self.header.fw.get_length()-4) + return True + + def parse_comment(self): + self.props['comment'] = self.header.fw.read_string(self.header.fw.get_length()-4) + return True + + def __init__(self, parent, header): + self.root_handler = Handler() + self.child_handler = Handler() + self.extension_handler = Handler() + self.global_handler = Handler() + + self.global_handler.set_handler({21: self.parse_push_extension}) + self.active_handler = self.root_handler + + # used by parse_*_extension + self.extension_handler.set_handler({22: self.parse_pop_extension}) + self.saved_handler = None + + self.header = header + self.children = list() + + self.parent = parent + + if parent: + parent.children.append(self) + + self.level = self.header.fw.get_level() + self.opcode = self.header.fw.get_opcode() + + self.props = {'id': 'unnamed', 'comment': '', 'type': 'untyped'} + +class VertexPalette(Node): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + self.root_handler.set_handler({68: self.parse_vertex_c, + 69: self.parse_vertex_cn, + 70: self.parse_vertex_cnuv, + 71: self.parse_vertex_cuv}) + self.root_handler.set_throw_back_all_unhandled() + + self.vert_desc_lst = list() + self.blender_verts = list() + self.offset = 8 + # Used to create a map from byte offset to vertex index. + self.index = dict() + + + def blender_import(self): + self.blender_verts.extend([Vector(vert_desc.x, vert_desc.y, vert_desc.z) for vert_desc in self.vert_desc_lst ]) + + def parse_vertex_common(self): + # Add this vertex to an offset to index dictionary. + #self.index_lst.append( (self.offset, self.next_index) ) + self.index[self.offset]= len(self.index) + + # Get ready for next record. + self.offset += self.header.fw.get_length() + + v = VertexDesc() + + self.header.fw.read_ahead(2) + v.flags = self.header.fw.read_short() + + v.x = self.header.fw.read_double() + v.y = self.header.fw.read_double() + v.z = self.header.fw.read_double() + + return v + + def parse_vertex_post_common(self, v): + if not v.flags & 0x2000: # 0x2000 = no color + if v.flags & 0x1000: # 0x1000 = packed color + v.a = self.header.fw.read_uchar() + v.b = self.header.fw.read_uchar() + v.g = self.header.fw.read_uchar() + v.r = self.header.fw.read_uchar() + else: + self.header.fw.read_ahead(4) + + color_index = self.header.fw.read_uint() + v.r, v.g, v.b, v.a= self.header.get_color(color_index) + + self.vert_desc_lst.append(v) + + return True + + def parse_vertex_c(self): + v = self.parse_vertex_common() + + self.parse_vertex_post_common(v) + + return True + + def parse_vertex_cn(self): + v = self.parse_vertex_common() + + ''' + v.nx = self.header.fw.read_float() + v.ny = self.header.fw.read_float() + v.nz = self.header.fw.read_float() + ''' + # Just to advance + self.header.fw.read_float() + self.header.fw.read_float() + self.header.fw.read_float() + + self.parse_vertex_post_common(v) + + return True + + def parse_vertex_cuv(self): + v = self.parse_vertex_common() + + v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float() + + self.parse_vertex_post_common(v) + + return True + + def parse_vertex_cnuv(self): + v = self.parse_vertex_common() + ''' + v.nx = self.header.fw.read_float() + v.ny = self.header.fw.read_float() + v.nz = self.header.fw.read_float() + ''' + # Just to advance + self.header.fw.read_float() + self.header.fw.read_float() + self.header.fw.read_float() + + v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float() + + self.parse_vertex_post_common(v) + + return True + + def parse(self): # Run once per import + Node.parse(self) + +class InterNode(Node): + def __init__(self): + self.object = None + self.mesh = None + self.isMesh = False + self.faceLs= [] + self.matrix = None + + def blender_import_my_faces(self): + + # Add the verts onto the mesh + mesh = self.mesh + blender_verts= self.header.vert_pal.blender_verts + vert_desc_lst= self.header.vert_pal.vert_desc_lst + + vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] + + mesh.verts.extend([blender_verts[i] for i in vert_list]) + + + new_faces= [] + new_faces_props= [] + ngon= BPyMesh.ngon + vert_index= 1 + for flt_face in self.faceLs: + material_index= flt_face.blen_mat_idx + image= flt_face.blen_image + + face_len= len(flt_face.indices) + + # Get the indicies in reference to the mesh. + + uvs= [vert_desc_lst[j].uv for j in flt_face.indices] + if face_len <=4: # tri or quad + new_faces.append( [i+vert_index for i in xrange(face_len)] ) + new_faces_props.append((material_index, image, uvs)) + + else: # fgon + mesh_face_indicies = [i+vert_index for i in xrange(face_len)] + tri_ngons= ngon(mesh, mesh_face_indicies) + new_faces.extend([ [mesh_face_indicies[t] for t in tri] for tri in tri_ngons]) + new_faces_props.extend( [ (material_index, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]) ) for tri in tri_ngons ] ) + + vert_index+= face_len + + mesh.faces.extend(new_faces) + + try: mesh.faceUV= True + except: pass + + for i, f in enumerate(mesh.faces): + f.mat, f.image, f.uv= new_faces_props[i] + + def blender_import(self): +# name = self.props['type'] + ': ' + self.props['id'] + name = self.props['id'] + if self.isMesh: + self.object = Blender.Object.New('Mesh', name) + #self.mesh = self.object.getData() + self.mesh = Blender.Mesh.New() + self.mesh.verts.extend( Vector() ) # DUMMYVERT + self.object.link(self.mesh) + else: + self.object = Blender.Object.New('Empty', name) + + if self.parent: + self.parent.object.makeParent([self.object]) + + scene.link(self.object) + self.object.Layer = current_layer + self.object.sel = 1 + + Node.blender_import(self) # Attach faces to self.faceLs + + if self.isMesh: + # Add all my faces into the mesh at once + self.blender_import_my_faces() + + if self.matrix: + self.object.setMatrix(self.matrix) + + # Attach properties + #for name, value in self.props.items(): + # self.object.addProperty(name, value) + + def parse_face(self): + child = Face(self) + child.parse() + return True + + def parse_group(self): + child = Group(self) + child.parse() + return True + + def move_to_next_layer(self): + global current_layer + current_layer = current_layer << 1 + if current_layer > 0x80000: + current_layer = 1 + + def parse_lod(self): + child = LOD(self) + child.parse() + return True + + def parse_unhandled(self): + child = Unhandled(self) + child.parse() + return True + + def parse_object(self): + child = Object(self) + child.parse() + return True + + def parse_xref(self): + child = XRef(self) + child.parse() + return True + + def parse_indexed_light_point(self): + child = IndexedLightPoint(self) + child.parse() + return True + + def parse_inline_light_point(self): + child = InlineLightPoint(self) + child.parse() + return True + + def parse_matrix(self): + m = list() + for i in xrange(4): + m.append([]) + for j in xrange(4): + f = self.header.fw.read_float() + m[i].append(f) + self.matrix = Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3]) + +EDGE_FGON= Blender.Mesh.EdgeFlags['FGON'] +FACE_TEX= Blender.Mesh.FaceModes['TEX'] + +class Face(Node): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + self.root_handler.set_handler({31: self.parse_comment, + 10: self.parse_push}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({72: self.parse_vertex_list, + 10: self.parse_push, + 11: self.parse_pop}) + + if parent: + parent.isMesh = True + + self.indices = list() # face verts here + + self.comment = '' + self.props = dict.fromkeys(['ir color', 'priority', + 'draw type', 'texture white', 'template billboard', + 'smc', 'fid', 'ir material', 'lod generation control', + 'flags', 'light mode']) + + self.header.fw.read_ahead(8) # face id + # Load face. + self.props['ir color'] = self.header.fw.read_int() + self.props['priority'] = self.header.fw.read_short() + self.props['draw type'] = self.header.fw.read_char() + self.props['texture white'] = self.header.fw.read_char() + self.header.fw.read_ahead(4) # color name indices + self.header.fw.read_ahead(1) # reserved + self.props['template billboard'] = self.header.fw.read_uchar() + self.detail_tex_index = self.header.fw.read_short() + self.tex_index = self.header.fw.read_short() + self.mat_index = self.header.fw.read_short() + self.props['smc'] = self.header.fw.read_short() + self.props['fid'] = self.header.fw.read_short() + self.props['ir material'] = self.header.fw.read_int() + self.alpha = 1.0 - float(self.header.fw.read_ushort()) / 65535.0 + self.props['lod generation control'] = self.header.fw.read_uchar() + self.header.fw.read_ahead(1) # line style index + self.props['flags'] = self.header.fw.read_int() + self.props['light mode'] = self.header.fw.read_uchar() + self.header.fw.read_ahead(7) + a = self.header.fw.read_uchar() + b = self.header.fw.read_uchar() + g = self.header.fw.read_uchar() + r = self.header.fw.read_uchar() + self.packed_color = [r, g, b, a] + a = self.header.fw.read_uchar() + b = self.header.fw.read_uchar() + g = self.header.fw.read_uchar() + r = self.header.fw.read_uchar() + self.alt_packed_color = [r, g, b, a] + self.tex_map_index = self.header.fw.read_short() + self.header.fw.read_ahead(2) + self.color_index = self.header.fw.read_uint() + self.alt_color_index = self.header.fw.read_uint() + #self.header.fw.read_ahead(2) + #self.shader_index = self.header.fw.read_short() + + + """ + def blender_import_face(self, material_index, image): + + + mesh = self.parent.mesh + face_len= len(self.indices) + + mesh_vert_len_orig= len(mesh.verts) + mesh.verts.extend([ self.header.vert_pal.blender_verts[i] for i in self.indices]) + + # Exception for an edge + if face_len==2: + mesh.edges.extend((mesh.verts[-1], mesh.verts[-2])) + return + + + mesh_face_indicies = range(mesh_vert_len_orig, mesh_vert_len_orig+face_len) + + #print mesh_face_indicies , 'mesh_face_indicies ' + + # First we need to triangulate NGONS + if face_len>4: + tri_indicies = [[i+mesh_vert_len_orig for i in t] for t in BPyMesh.ngon(mesh, mesh_face_indicies) ] # use range because the verts are in order. + else: + tri_indicies= [mesh_face_indicies] # can be a quad but thats ok + + # Extend face or ngon + + mesh.faces.extend(tri_indicies) + #print mesh.faces, 'mesh.faces' + mesh.faceUV= True + + # Now set UVs + for i in xrange(len(mesh.faces)-len(tri_indicies), len(mesh.faces)): + f= mesh.faces[i] + f_v= f.v + for j, uv in enumerate(f.uv): + vertex_index_flt= self.indices[f_v[j].index - mesh_vert_len_orig] + + vert_desc = self.header.vert_pal.vert_desc_lst[vertex_index_flt] + uv.x, uv.y= vert_desc.u, vert_desc.v + + # Only a bug in 2.42, fixed in cvs + for c in f.col: + c.r=c.g=c.b= 255 + + f.mat = material_index + if image: + f.image = image + else: + f.mode &= ~FACE_TEX + + # FGon + + if face_len>4: + # Add edges we know are not fgon + end_index= len(mesh.verts) + start_index= end_index - len(self.indices) + edge_dict= dict([ ((i, i+1), None) for i in xrange(start_index, end_index-1)]) + edge_dict[(start_index, end_index)]= None # wish this was a set + + fgon_edges= {} + for tri in tri_indicies: + for i in (0,1,2): + i1= tri[i] + i2= tri[i-1] + + # Sort + if i1>i2: + i1,i2= i2,i1 + + if not edge_dict.has_key( (i1,i2) ): # if this works its an edge vert + fgon_edges[i1,i2]= None + + + # Now set fgon flags + for ed in mesh.edges: + i1= ed.v1.index + i2= ed.v2.index + if i1>i2: + i1,i2= i2,i1 + + if fgon_edges.has_key( (i1,i2) ): + # This is an edge tagged for fgonning? + fgon_edges[i1, i2] + ed.flag |= EDGE_FGON + del fgon_edges[i1, i2] # make later searches faster? + + if not fgon_edges: + break + """ + + def parse_comment(self): + self.comment = self.header.fw.read_string(self.header.fw.get_length()-4) + return True + + # returns a tuple (material, image) where material is the blender material and + # image is the blender image or None. + def create_blender_material(self): + # Create face material. + mat_desc = MaterialDesc() + + if self.mat_index != -1: + if not self.mat_index in self.header.mat_desc_pal: + if global_prefs['verbose'] >= 1: + #print 'Warning: Material index', self.mat_index, 'not in material palette.' + pass + else: + mat_pal_desc = self.header.mat_desc_pal[self.mat_index] + mat_desc.alpha = mat_pal_desc.alpha * self.alpha # combine face and mat alphas + mat_desc.ambient = mat_pal_desc.ambient + mat_desc.diffuse = mat_pal_desc.diffuse + mat_desc.specular = mat_pal_desc.specular + mat_desc.emissive = mat_pal_desc.emissive + mat_desc.shininess = mat_pal_desc.shininess + else: + # if no material get alpha from just face. + mat_desc.alpha = self.alpha + + # Color. + if global_prefs['color_from_face']: + color = None + if not self.props['flags'] & 0x40000000: + if self.props['flags'] & 0x10000000: # packed color + color = self.packed_color + else: + color = self.header.get_color(self.color_index) + + if color: + r = float(color[0])/255.0 + g = float(color[1])/255.0 + b = float(color[2])/255.0 + mat_desc.diffuse = [r, g, b] + + # Texture + image = None + if self.tex_index != -1 and self.tex_index in self.header.bl_tex_pal: + mat_desc.tex0 = self.header.bl_tex_pal[self.tex_index] + if mat_desc.tex0: + mat_desc.name = FF.strip_path(self.header.tex_pal[self.tex_index]) + image = mat_desc.tex0.image + + # OpenFlight Face Attributes + mat_desc.face_props = self.props + + # Get material. + mat = GRR.request_mat(mat_desc) + + # Add material to mesh. + mesh = self.parent.mesh + + # Return where it is in the mesh for faces. + mesh_materials= mesh.materials + + material_index= -1 + for i,m in enumerate(mesh_materials): + if m.name==mat.name: + material_index= i + break + + if material_index==-1: + material_index= len(mesh_materials) + if material_index==16: + material_index= 15 + if global_prefs['verbose'] >= 1: + print 'Warning: Too many materials per mesh object. Only a maximum of 16 ' + \ + 'allowed. Using 16th material instead.' + + else: + mesh_materials.append(mat) + mesh.materials= mesh_materials + + return (material_index, image) + + + def blender_import(self): + vert_count = len(self.indices) + if vert_count < 3: + if global_prefs['verbose'] >= 2: + print 'Warning: Ignoring face with no vertices.' + return + + # Assign material and image + + self.parent.faceLs.append(self) + self.blen_mat_idx, self.blen_image= self.create_blender_material() + + + + + # Store comment info in parent. + if self.comment != '': + if self.parent.props['comment'] != '': + self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment + else: + self.parent.props['comment'] = self.comment + + def parse_vertex_list(self): + length = self.header.fw.get_length() + fw = self.header.fw + vert_pal = self.header.vert_pal + + count = (length-4)/4 + + # If this ever fails the chunk below does error checking + self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] + ''' + for i in xrange(count): + byte_offset = fw.read_int() + if byte_offset in vert_pal.index: + index = vert_pal.index[byte_offset] + self.indices.append(index) + elif global_prefs['verbose'] >= 1: + print 'Warning: Unable to map byte offset %s' + \ + ' to vertex index.' % byte_offset + ''' + return True + + +class Object(InterNode): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({5: self.parse_face, + #130: self.parse_indexed_light_point, + #111: self.parse_inline_light_point, + 10: self.parse_push, + 11: self.parse_pop}) + + self.props['type'] = 'Object' + self.props['id'] = self.header.fw.read_string(8) + + + +class Group(InterNode): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({5: self.parse_face, + #130: self.parse_indexed_light_point, + #111: self.parse_inline_light_point, + 2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, + 14: self.parse_unhandled, + 91: self.parse_unhandled, + 98: self.parse_unhandled, + 63: self.parse_xref}) + self.props = dict.fromkeys(['type', 'id', 'comment', 'priority', 'flags', 'special1', + 'special2', 'significance', 'layer code', 'loop count', + 'loop duration', 'last frame duration']) + + self.props['type'] = 'Group' + self.props['comment'] = '' + self.props['id'] = self.header.fw.read_string(8) + self.props['priority'] = self.header.fw.read_short() + self.header.fw.read_ahead(2) + self.props['flags'] = self.header.fw.read_int() + self.props['special1'] = self.header.fw.read_short() + self.props['special2'] = self.header.fw.read_short() + self.props['significance'] = self.header.fw.read_short() + self.props['layer code'] = self.header.fw.read_char() + self.header.fw.read_ahead(5) + self.props['loop count'] = self.header.fw.read_int() + self.props['loop duration'] = self.header.fw.read_float() + self.props['last frame duration'] = self.header.fw.read_float() + +class XRef(InterNode): + def parse(self): + if self.xref: + self.xref.parse() + Node.parse(self) + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + xref_filename = self.header.fw.read_string(200) + filename = FF.find(xref_filename) + + self.props['type'] = 'XRef' + + if filename != None: + self.xref = Database(filename, self) + self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(filename))[0] + else: + self.xref = None + self.props['id'] = 'X: broken' + +class LOD(InterNode): + def blender_import(self): + self.move_to_next_layer() + InterNode.blender_import(self) + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, # switch + 14: self.parse_unhandled, # DOF + 91: self.parse_unhandled, # sound + 98: self.parse_unhandled, # clip + 63: self.parse_xref}) + + self.props['type'] = 'LOD' + self.props['id'] = self.header.fw.read_string(8) + +class InlineLightPoint(InterNode): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({72: self.parse_vertex_list, + 10: self.parse_push, + 11: self.parse_pop}) + + self.indices = list() + + self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance']) + self.app_props = dict() + + self.props['comment'] = '' + self.props['type'] = 'Light Point' + self.props['id'] = self.header.fw.read_string(8) + + self.app_props.update({'smc': self.header.fw.read_short()}) + self.app_props.update({'fid': self.header.fw.read_short()}) + self.app_props.update({'back color: a': self.header.fw.read_uchar()}) + self.app_props.update({'back color: b': self.header.fw.read_uchar()}) + self.app_props.update({'back color: g': self.header.fw.read_uchar()}) + self.app_props.update({'back color: r': self.header.fw.read_uchar()}) + self.app_props.update({'display mode': self.header.fw.read_int()}) + self.app_props.update({'intensity': self.header.fw.read_float()}) + self.app_props.update({'back intensity': self.header.fw.read_float()}) + self.app_props.update({'minimum defocus': self.header.fw.read_float()}) + self.app_props.update({'maximum defocus': self.header.fw.read_float()}) + self.app_props.update({'fading mode': self.header.fw.read_int()}) + self.app_props.update({'fog punch mode': self.header.fw.read_int()}) + self.app_props.update({'directional mode': self.header.fw.read_int()}) + self.app_props.update({'range mode': self.header.fw.read_int()}) + self.app_props.update({'min pixel size': self.header.fw.read_float()}) + self.app_props.update({'max pixel size': self.header.fw.read_float()}) + self.app_props.update({'actual size': self.header.fw.read_float()}) + self.app_props.update({'trans falloff pixel size': self.header.fw.read_float()}) + self.app_props.update({'trans falloff exponent': self.header.fw.read_float()}) + self.app_props.update({'trans falloff scalar': self.header.fw.read_float()}) + self.app_props.update({'trans falloff clamp': self.header.fw.read_float()}) + self.app_props.update({'fog scalar': self.header.fw.read_float()}) + self.app_props.update({'fog intensity': self.header.fw.read_float()}) + self.app_props.update({'size threshold': self.header.fw.read_float()}) + self.app_props.update({'directionality': self.header.fw.read_int()}) + self.app_props.update({'horizontal lobe angle': self.header.fw.read_float()}) + self.app_props.update({'vertical lobe angle': self.header.fw.read_float()}) + self.app_props.update({'lobe roll angle': self.header.fw.read_float()}) + self.app_props.update({'dir falloff exponent': self.header.fw.read_float()}) + self.app_props.update({'dir ambient intensity': self.header.fw.read_float()}) + self.header.fw.read_ahead(12) # Animation settings. + self.app_props.update({'significance': self.header.fw.read_float()}) + self.props['draw order'] = self.header.fw.read_int() + self.app_props.update({'flags': self.header.fw.read_int()}) + #self.fw.read_ahead(12) # More animation settings. + + # return dictionary: lp_app name => index list + def group_points(self, props): + + name_to_indices = {} + + for i in self.indices: + vert_desc = self.header.vert_pal.vert_desc_lst[i] + app_desc = LightPointAppDesc() + app_desc.props.update(props) + # add vertex normal and color + app_desc.props.update({'nx': vert_desc.nx}) + app_desc.props.update({'ny': vert_desc.ny}) + app_desc.props.update({'nz': vert_desc.nz}) + + app_desc.props.update({'r': vert_desc.r}) + app_desc.props.update({'g': vert_desc.g}) + app_desc.props.update({'b': vert_desc.b}) + app_desc.props.update({'a': vert_desc.a}) + + app_name = GRR.request_lightpoint_app(app_desc) + + if name_to_indices.get(app_name): + name_to_indices[app_name].append(i) + else: + name_to_indices.update({app_name: [i]}) + + return name_to_indices + + def blender_import(self): + name = '%s: %s' % (self.props['type'], self.props['id']) + + name_to_indices = self.group_points(self.app_props) + + for app_name, indices in name_to_indices.iteritems(): + self.object = Blender.Object.New('Mesh', name) + #self.mesh = self.object.getData() + self.mesh= Blender.Mesh.New() + self.mesh.verts.extend( Vector() ) # DUMMYVERT + self.object.link(self.mesh) + + if self.parent: + self.parent.object.makeParent([self.object]) + + for i in indices: + vert = self.header.vert_pal.blender_verts[i] + self.mesh.verts.append(vert) + + scene.link(self.object) + self.object.Layer = current_layer + self.object.sel= 1 + + if self.matrix: + self.object.setMatrix(self.matrix) + + # Import comment. + if self.props['comment'] != '': + name = 'COMMENT: ' + self.props['id'] + t = Blender.Text.New(name) + t.write(self.props['comment']) + self.props['comment'] = name + + # Attach properties. + self.props.update({'appearance': app_name}) + for name, value in self.props.iteritems(): + self.object.addProperty(name, value) + + self.mesh.update() + + def parse_vertex_list(self): + length = self.header.fw.get_length() + fw = self.header.fw + vert_pal = self.header.vert_pal + + count = (length-4)/4 + + # If this ever fails the chunk below does error checking + self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] + + ''' + for i in xrange(count): + byte_offset = fw.read_int() + if byte_offset in vert_pal.index: + index = vert_pal.index[byte_offset] + self.indices.append(index) + elif global_prefs['verbose'] >= 1: + print 'Warning: Unable to map byte offset %s' + \ + ' to vertex index.' % byte_offset + ''' + + return True + + + +class IndexedLightPoint(InterNode): + # return dictionary: lp_app name => index list + def group_points(self, props): + + name_to_indices = {} + + for i in self.indices: + vert_desc = self.header.vert_pal.vert_desc_lst[i] + app_desc = LightPointAppDesc() + app_desc.props.update(props) + # add vertex normal and color + app_desc.props.update({'nx': vert_desc.nx}) + app_desc.props.update({'ny': vert_desc.ny}) + app_desc.props.update({'nz': vert_desc.nz}) + + app_desc.props.update({'r': vert_desc.r}) + app_desc.props.update({'g': vert_desc.g}) + app_desc.props.update({'b': vert_desc.b}) + app_desc.props.update({'a': vert_desc.a}) + + app_name = GRR.request_lightpoint_app(app_desc) + + if name_to_indices.get(app_name): + name_to_indices[app_name].append(i) + else: + name_to_indices.update({app_name: [i]}) + + return name_to_indices + + def blender_import(self): + name = self.props['type'] + ': ' + self.props['id'] + + name_to_indices = self.group_points(self.header.lightpoint_appearance_pal[self.index]) + + for app_name, indices in name_to_indices.iteritems(): + self.object = Blender.Object.New('Mesh', name) + #self.mesh = self.object.getData() + self.mesh= Blender.Mesh.New() + self.mesh.verts.extend( Vector() ) # DUMMYVERT + self.object.link(self.mesh) + + if self.parent: + self.parent.object.makeParent([self.object]) + + for i in indices: + vert = self.header.vert_pal.blender_verts[i] + self.mesh.verts.append(vert) + + scene.link(self.object) + + self.object.Layer = current_layer + + if self.matrix: + self.object.setMatrix(self.matrix) + + # Import comment. + if self.props['comment'] != '': + name = 'COMMENT: ' + self.props['id'] + t = Blender.Text.New(name) + t.write(self.props['comment']) + self.props['comment'] = name + + # Attach properties. + self.props.update({'appearance': app_name}) + for name, value in self.props.iteritems(): + self.object.addProperty(name, value) + + self.mesh.update() + + def parse_vertex_list(self): + length = self.header.fw.get_length() + fw = self.header.fw + vert_pal = self.header.vert_pal + + count = (length-4)/4 + + # If this ever fails the chunk below does error checking + self.indices= [vert_pal.index[fw.read_int()] for i in xrange(count)] + + ''' + for i in xrange(count): + byte_offset = fw.read_int() + if byte_offset in vert_pal.index: + index = vert_pal.index[byte_offset] + self.indices.append(index) + elif global_prefs['verbose'] >= 1: + print 'Warning: Unable to map byte offset %s' + \ + ' to vertex index.' % byte_offset + ''' + return True + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({72: self.parse_vertex_list, + 10: self.parse_push, + 11: self.parse_pop}) + + self.indices = list() + + self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance']) + self.props['comment'] = '' + self.props['type'] = 'Light Point' + self.props['id'] = self.header.fw.read_string(8) + self.index = self.header.fw.read_int() + self.header.fw.read_ahead(4) # animation index + self.props['draw order'] = self.header.fw.read_int() + +class Unhandled(InterNode): + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, # switch + 14: self.parse_unhandled, # DOF + 91: self.parse_unhandled, # sound + 98: self.parse_unhandled, # clip + 63: self.parse_xref}) + + self.props['id'] = self.header.fw.read_string(8) + +class Database(InterNode): + def blender_import(self): + self.tex_pal = dict(self.tex_pal_lst) + del self.tex_pal_lst + + # Setup Textures + bl_tex_pal_lst = list() + for i in self.tex_pal.iterkeys(): + path_filename = FF.find(self.tex_pal[i]) + if path_filename != None: + img = GRR.request_image(path_filename) + if img: + tex = GRR.request_texture(img) + tex.setName(FF.strip_path(self.tex_pal[i])) + bl_tex_pal_lst.append( (i, tex) ) + else: + bl_tex_pal_lst.append( (i, None) ) + elif global_prefs['verbose'] >= 1: + print 'Warning: Unable to find', self.tex_pal[i] + + self.bl_tex_pal = dict(bl_tex_pal_lst) + + # Setup Materials + self.mat_desc_pal = dict(self.mat_desc_pal_lst) + + InterNode.blender_import(self) + + def parse_appearance_palette(self): + props = dict() + self.fw.read_ahead(4) # reserved + props.update({'id': self.fw.read_string(256)}) + index = self.fw.read_int() + props.update({'smc': self.fw.read_short()}) + props.update({'fid': self.fw.read_short()}) + props.update({'back color: a': self.fw.read_uchar()}) + props.update({'back color: b': self.fw.read_uchar()}) + props.update({'back color: g': self.fw.read_uchar()}) + props.update({'back color: r': self.fw.read_uchar()}) + props.update({'display mode': self.fw.read_int()}) + props.update({'intensity': self.fw.read_float()}) + props.update({'back intensity': self.fw.read_float()}) + props.update({'minimum defocus': self.fw.read_float()}) + props.update({'maximum defocus': self.fw.read_float()}) + props.update({'fading mode': self.fw.read_int()}) + props.update({'fog punch mode': self.fw.read_int()}) + props.update({'directional mode': self.fw.read_int()}) + props.update({'range mode': self.fw.read_int()}) + props.update({'min pixel size': self.fw.read_float()}) + props.update({'max pixel size': self.fw.read_float()}) + props.update({'actual size': self.fw.read_float()}) + props.update({'trans falloff pixel size': self.fw.read_float()}) + props.update({'trans falloff exponent': self.fw.read_float()}) + props.update({'trans falloff scalar': self.fw.read_float()}) + props.update({'trans falloff clamp': self.fw.read_float()}) + props.update({'fog scalar': self.fw.read_float()}) + props.update({'fog intensity': self.fw.read_float()}) + props.update({'size threshold': self.fw.read_float()}) + props.update({'directionality': self.fw.read_int()}) + props.update({'horizontal lobe angle': self.fw.read_float()}) + props.update({'vertical lobe angle': self.fw.read_float()}) + props.update({'lobe roll angle': self.fw.read_float()}) + props.update({'dir falloff exponent': self.fw.read_float()}) + props.update({'dir ambient intensity': self.fw.read_float()}) + props.update({'significance': self.fw.read_float()}) + props.update({'flags': self.fw.read_int()}) + props.update({'visibility range': self.fw.read_float()}) + props.update({'fade range ratio': self.fw.read_float()}) + props.update({'fade in duration': self.fw.read_float()}) + props.update({'fade out duration': self.fw.read_float()}) + props.update({'LOD range ratio': self.fw.read_float()}) + props.update({'LOD scale': self.fw.read_float()}) + + self.lightpoint_appearance_pal.update({index: props}) + + def parse_header(self): + self.props['type'] = 'Header' + self.props['comment'] = '' + self.props['id'] = self.fw.read_string(8) + self.props['version'] = self.fw.read_int() + self.fw.read_ahead(46) + self.props['units'] = self.fw.read_char() + self.props['set white'] = bool(self.fw.read_char()) + self.props['flags'] = self.fw.read_int() + self.fw.read_ahead(24) + self.props['projection type'] = self.fw.read_int() + self.fw.read_ahead(36) + self.props['sw x'] = self.fw.read_double() + self.props['sw y'] = self.fw.read_double() + self.props['dx'] = self.fw.read_double() + self.props['dy'] = self.fw.read_double() + self.fw.read_ahead(24) + self.props['sw lat'] = self.fw.read_double() + self.props['sw lon'] = self.fw.read_double() + self.props['ne lat'] = self.fw.read_double() + self.props['ne lon'] = self.fw.read_double() + self.props['origin lat'] = self.fw.read_double() + self.props['origin lon'] = self.fw.read_double() + self.props['lambert lat1'] = self.fw.read_double() + self.props['lambert lat2'] = self.fw.read_double() + self.fw.read_ahead(16) + self.props['ellipsoid model'] = self.fw.read_int() + self.fw.read_ahead(4) + self.props['utm zone'] = self.fw.read_short() + self.fw.read_ahead(6) + self.props['dz'] = self.fw.read_double() + self.props['radius'] = self.fw.read_double() + self.fw.read_ahead(8) + self.props['major axis'] = self.fw.read_double() + self.props['minor axis'] = self.fw.read_double() + + if global_prefs['verbose'] >= 1: + print 'OpenFlight Version:', float(self.props['version']) / 100.0 + print + + return True + + def parse_mat_palette(self): + mat_desc = MaterialDesc() + index = self.fw.read_int() + + name = self.fw.read_string(12) + if len(mat_desc.name) > 0: + mat_desc.name = name + + flag = self.fw.read_int() + # skip material if not used + if not flag & 0x80000000: + return True + + ambient_col = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] + mat_desc.diffuse = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] + mat_desc.specular = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] + emissive_col = [self.fw.read_float(), self.fw.read_float(), self.fw.read_float()] + + mat_desc.shininess = self.fw.read_float() / 64.0 # [0.0, 128.0] => [0.0, 2.0] + mat_desc.alpha = self.fw.read_float() + + # Convert ambient and emissive colors into intensitities. + mat_desc.ambient = col_to_gray(ambient_col) + mat_desc.emissive = col_to_gray(emissive_col) + + self.mat_desc_pal_lst.append( (index, mat_desc) ) + + return True + + def get_color(self, color_index): + index = color_index / 128 + intensity = float(color_index - 128.0 * index) / 127.0 + + if index >= 0 and index <= 1023: + brightest = self.col_pal[index] + r = int(brightest[0] * intensity) + g = int(brightest[1] * intensity) + b = int(brightest[2] * intensity) + a = int(brightest[3]) + + color = [r, g, b, a] + + return color + + def parse_color_palette(self): + self.header.fw.read_ahead(128) + for i in xrange(1024): + a = self.header.fw.read_uchar() + b = self.header.fw.read_uchar() + g = self.header.fw.read_uchar() + r = self.header.fw.read_uchar() + self.col_pal.append((r, g, b, a)) + return True + + def parse_vertex_palette(self): + self.vert_pal = VertexPalette(self) + self.vert_pal.parse() + return True + + def parse_texture_palette(self): + name = self.fw.read_string(200) + index = self.fw.read_int() + self.tex_pal_lst.append( (index, name) ) + return True + + def __init__(self, filename, parent=None): + if global_prefs['verbose'] >= 1: + print 'Parsing:', filename + print + + self.fw = flt_filewalker.FltIn(filename) + Node.__init__(self, parent, self) + InterNode.__init__(self) + + self.root_handler.set_handler({1: self.parse_header, + 67: self.parse_vertex_palette, + 33: self.parse_long_id, + 31: self.parse_comment, + 64: self.parse_texture_palette, + 32: self.parse_color_palette, + 113: self.parse_mat_palette, + 128: self.parse_appearance_palette, + 10: self.parse_push}) + if parent: + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({#130: self.parse_indexed_light_point, + #111: self.parse_inline_light_point, + 2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, + 14: self.parse_unhandled, + 91: self.parse_unhandled, + 98: self.parse_unhandled, + 63: self.parse_xref}) + + self.vert_pal = None + self.lightpoint_appearance_pal = dict() + self.tex_pal = dict() + self.tex_pal_lst = list() + self.bl_tex_pal = dict() + self.col_pal = list() + self.mat_desc_pal_lst = list() + self.mat_desc_pal = dict() + self.props = dict.fromkeys(['id', 'type', 'comment', 'version', 'units', 'set white', + 'flags', 'projection type', 'sw x', 'sw y', 'dx', 'dy', 'dz', 'sw lat', + 'sw lon', 'ne lat', 'ne lon', 'origin lat', 'origin lon', 'lambert lat1', + 'lambert lat2', 'ellipsoid model', 'utm zone', 'radius', 'major axis', 'minor axis']) + +def select_file(filename): + if not Blender.sys.exists(filename): + msg = 'Error: File ' + filename + ' does not exist.' + Blender.Draw.PupMenu(msg) + return + + if not filename.lower().endswith('.flt'): + msg = 'Error: Not a flight file.' + Blender.Draw.PupMenu(msg) + print msg + print + return + + global_prefs['fltfile']= filename + global_prefs['verbose']= 1 + global_prefs['get_texture'] = True + global_prefs['get_diffuse'] = True + global_prefs['get_specular'] = False + global_prefs['get_emissive'] = False + global_prefs['get_alpha'] = True + global_prefs['get_ambient'] = False + global_prefs['get_shininess'] = True + global_prefs['color_from_face'] = True + + # Start loading the file, + # first set the context + Blender.Window.WaitCursor(True) + Blender.Window.EditMode(0) + for ob in scene.objects: + ob.sel=0 + + + FF.add_file_to_search_path(filename) + + if global_prefs['verbose'] >= 1: + print 'Pass 1: Loading.' + print + + load_time = Blender.sys.time() + db = Database(filename) + db.parse() + load_time = Blender.sys.time() - load_time + + if global_prefs['verbose'] >= 1: + print + print 'Pass 2: Importing to Blender.' + print + + import_time = Blender.sys.time() + db.blender_import() + import_time = Blender.sys.time() - import_time + + Blender.Window.ViewLayer(range(1,21)) + + # FIX UP AFTER DUMMY VERT AND REMOVE DOUBLES + Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) + for ob in scene.objects.context: + if ob.type=='Mesh': + me=ob.getData(mesh=1) + me.verts.delete(0) # remove the dummy vert + me.sel= 1 + me.remDoubles(0.0001) + + + + Blender.Window.RedrawAll() + + if global_prefs['verbose'] >= 1: + print 'Done.' + print + print 'Time to parse file: %.3f seconds' % load_time + print 'Time to import to blender: %.3f seconds' % import_time + print 'Total time: %.3f seconds' % (load_time + import_time) + + Blender.Window.WaitCursor(False) + + +if global_prefs['verbose'] >= 1: + print + print 'OpenFlight Importer' + print 'Version:', __version__ + print 'Author: Greg MacDonald' + print __url__[2] + print + + +if __name__ == '__main__': + Blender.Window.FileSelector(select_file, "Import OpenFlight", "*.flt") + #select_file('/fe/flt/helnwsflt/helnws.flt') + #select_file('/fe/flt/Container_006.flt') + #select_file('/fe/flt/NaplesORIGINALmesh.flt') + #select_file('/Anti_tank_D30.flt') + #select_file('/metavr/file_examples/flt/cherrypoint/CherryPoint_liter_runway.flt') + + +""" +TIME= Blender.sys.time() +import os +PATH= 'c:\\flt_test' +for FNAME in os.listdir(PATH): + if FNAME.lower().endswith('.flt'): + FPATH= os.path.join(PATH, FNAME) + newScn= Blender.Scene.New(FNAME) + newScn.makeCurrent() + scene= newScn + select_file(FPATH) + +print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) +""" + \ No newline at end of file diff --git a/release/scripts/help_bpy_api.py b/release/scripts/help_bpy_api.py new file mode 100644 index 00000000000..484663b32b3 --- /dev/null +++ b/release/scripts/help_bpy_api.py @@ -0,0 +1,41 @@ +#!BPY +""" +Name: 'Blender/Python Scripting API' +Blender: 244 +Group: 'Help' +Tooltip: 'The Blender Python API reference manual' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "blenderartist") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at http://www.blender.org's +"Blenders Python API" page. +""" + +# -------------------------------------------------------------------------- +# Blender/Python Scripting Reference Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(int(Blender.Get('version'))) +webbrowser.open('http://www.blender.org/documentation/'+ version +'PythonDoc/index.html') diff --git a/release/scripts/help_browser.py b/release/scripts/help_browser.py new file mode 100644 index 00000000000..d321ffa6256 --- /dev/null +++ b/release/scripts/help_browser.py @@ -0,0 +1,789 @@ +#!BPY + +""" +Name: 'Scripts Help Browser' +Blender: 234 +Group: 'Help' +Tooltip: 'Show help information about a chosen installed script.' +""" + +__author__ = "Willian P. Germano" +__version__ = "0.1 11/02/04" +__email__ = ('scripts', 'Author, wgermano:ig*com*br') +__url__ = ('blender', 'elysiun') + +__bpydoc__ ="""\ +This script shows help information for scripts registered in the menus. + +Usage: + +- Start Screen: + +To read any script's "user manual" select a script from one of the +available category menus. If the script has help information in the format +expected by this Help Browser, it will be displayed in the Script Help +Screen. Otherwise you'll be offered the possibility of loading the chosen +script's source file in Blender's Text Editor. The programmer(s) may have +written useful comments there for users. + +Hotkeys:
+ ESC or Q: [Q]uit + +- Script Help Screen: + +This screen shows the user manual page for the chosen script. If the text +doesn't fit completely on the screen, you can scroll it up or down with +arrow keys or a mouse wheel. There may be link and email buttons that if +clicked should open your default web browser and email client programs for +further information or support. + +Hotkeys:
+ ESC: back to Start Screen
+ Q: [Q]uit
+ S: view script's [S]ource code in Text Editor
+ UP, DOWN Arrows and mouse wheel: scroll text up / down +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# sysinfo.py version 0.1 Jun 09, 2004 +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender import sys as bsys, Draw, Window, Registry + +WEBBROWSER = True +try: + import webbrowser +except: + WEBBROWSER = False + +DEFAULT_EMAILS = { + 'scripts': ['Bf-scripts-dev', 'bf-scripts-dev@blender.org'] +} + +DEFAULT_LINKS = { + 'blender': ["blender.org\'s Python forum", "http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewforum&f=9"], + 'elysiun': ["elYsiun\'s Python and Plugins forum", "http://www.elysiun.com/forum/viewforum.php?f=5"] +} + +PADDING = 15 +COLUMNS = 1 +TEXT_WRAP = 100 +WIN_W = WIN_H = 200 +SCROLL_DOWN = 0 + +def screen_was_resized(): + global WIN_W, WIN_H + + w, h = Window.GetAreaSize() + if WIN_W != w or WIN_H != h: + WIN_W = w + WIN_H = h + return True + return False + +def fit_on_screen(): + global TEXT_WRAP, PADDING, WIN_W, WIN_H, COLUMNS + + COLUMNS = 1 + WIN_W, WIN_H = Window.GetAreaSize() + TEXT_WRAP = int((WIN_W - PADDING) / 6) + if TEXT_WRAP < 40: + TEXT_WRAP = 40 + elif TEXT_WRAP > 100: + if TEXT_WRAP > 110: + COLUMNS = 2 + TEXT_WRAP /= 2 + else: TEXT_WRAP = 100 + +def cut_point(text, length): + "Returns position of the last space found before 'length' chars" + l = length + c = text[l] + while c != ' ': + l -= 1 + if l == 0: return length # no space found + c = text[l] + return l + +def text_wrap(text, length = None): + global TEXT_WRAP + + wrapped = [] + lines = text.split('
') + llen = len(lines) + if llen > 1: + if lines[-1] == '': llen -= 1 + for i in range(llen - 1): + lines[i] = lines[i].rstrip() + '
' + lines[llen-1] = lines[llen-1].rstrip() + + if not length: length = TEXT_WRAP + + for l in lines: + while len(l) > length: + cpt = cut_point(l, length) + line, l = l[:cpt], l[cpt + 1:] + wrapped.append(line) + wrapped.append(l) + return wrapped + +def load_script_text(script): + global PATHS, SCRIPT_INFO + + if script.userdir: + path = PATHS['uscripts'] + else: + path = PATHS['scripts'] + + fname = bsys.join(path, script.fname) + + source = Blender.Text.Load(fname) + if source: + Draw.PupMenu("File loaded%%t|Please check the file \"%s\" in the Text Editor window" % source.name) + + +# for theme colors: +def float_colors(cols): + return map(lambda x: x / 255.0, cols) + +# globals + +SCRIPT_INFO = None + +PATHS = { + 'home': Blender.Get('homedir'), + 'scripts': Blender.Get('scriptsdir'), + 'uscripts': Blender.Get('uscriptsdir') +} + +if not PATHS['home']: + errmsg = """ +Can't find Blender's home dir and so can't find the +Bpymenus file automatically stored inside it, which +is needed by this script. Please run the +Help -> System -> System Information script to get +information about how to fix this. +""" + raise SystemError, errmsg + +BPYMENUS_FILE = bsys.join(PATHS['home'], 'Bpymenus') + +f = file(BPYMENUS_FILE, 'r') +lines = f.readlines() +f.close() + +AllGroups = [] + +class Script: + + def __init__(self, data): + self.name = data[0] + self.version = data[1] + self.fname = data[2] + self.userdir = data[3] + self.tip = data[4] + +# End of class Script + + +class Group: + + def __init__(self, name): + self.name = name + self.scripts = [] + + def add_script(self, script): + self.scripts.append(script) + + def get_name(self): + return self.name + + def get_scripts(self): + return self.scripts + +# End of class Group + + +class BPy_Info: + + def __init__(self, script, dict): + + self.script = script + + self.d = dict + + self.header = [] + self.len_header = 0 + self.content = [] + self.len_content = 0 + self.spaces = 0 + self.fix_urls() + self.make_header() + self.wrap_lines() + + def make_header(self): + + sc = self.script + d = self.d + + header = self.header + + title = "Script: %s" % sc.name + version = "Version: %s for Blender %1.2f or newer" % (d['__version__'], + sc.version / 100.0) + + if len(d['__author__']) == 1: + asuffix = ':' + else: asuffix = 's:' + + authors = "%s%s %s" % ("Author", asuffix, ", ".join(d['__author__'])) + + header.append(title) + header.append(version) + header.append(authors) + self.len_header = len(header) + + + def fix_urls(self): + + emails = self.d['__email__'] + fixed = [] + for a in emails: + if a in DEFAULT_EMAILS.keys(): + fixed.append(DEFAULT_EMAILS[a]) + else: + a = a.replace('*','.').replace(':','@') + ltmp = a.split(',') + if len(ltmp) != 2: + ltmp = [ltmp[0], ltmp[0]] + fixed.append(ltmp) + + self.d['__email__'] = fixed + + links = self.d['__url__'] + fixed = [] + for a in links: + if a in DEFAULT_LINKS.keys(): + fixed.append(DEFAULT_LINKS[a]) + else: + ltmp = a.split(',') + if len(ltmp) != 2: + ltmp = [ltmp[0], ltmp[0]] + fixed.append([ltmp[0].strip(), ltmp[1].strip()]) + + self.d['__url__'] = fixed + + + def wrap_lines(self, reset = 0): + + lines = self.d['__bpydoc__'].split('\n') + self.content = [] + newlines = [] + newline = [] + + if reset: + self.len_content = 0 + self.spaces = 0 + + for l in lines: + if l == '' and newline: + newlines.append(newline) + newline = [] + newlines.append('') + else: newline.append(l) + if newline: newlines.append(newline) + + for lst in newlines: + wrapped = text_wrap(" ".join(lst)) + for l in wrapped: + self.content.append(l) + if l: self.len_content += 1 + else: self.spaces += 1 + + if not self.content[-1]: + self.len_content -= 1 + + +# End of class BPy_Info + +def parse_pyobj_close(closetag, lines, i): + i += 1 + l = lines[i] + while l.find(closetag) < 0: + i += 1 + l = "%s%s" % (l, lines[i]) + return [l, i] + +def parse_pyobj(var, lines, i): + "Bad code, was in a hurry for release" + + l = lines[i].replace(var, '').replace('=','',1).strip() + + i0 = i - 1 + + if l[0] == '"': + if l[1:3] == '""': # """ + if l.find('"""', 3) < 0: # multiline + l2, i = parse_pyobj_close('"""', lines, i) + if l[-1] == '\\': l = l[:-1] + l = "%s%s" % (l, l2) + elif l[-1] == '"' and l[-2] != '\\': # single line: "..." + pass + else: + l = "ERROR" + + elif l[0] == "'": + if l[-1] == '\\': + l2, i = parse_pyobj_close("'", lines, i) + l = "%s%s" % (l, l2) + elif l[-1] == "'" and l[-2] != '\\': # single line: '...' + pass + else: + l = "ERROR" + + elif l[0] == '(': + if l[-1] != ')': + l2, i = parse_pyobj_close(')', lines, i) + l = "%s%s" % (l, l2) + + elif l[0] == '[': + if l[-1] != ']': + l2, i = parse_pyobj_close(']', lines, i) + l = "%s%s" % (l, l2) + + return [l, i - i0] + +# helper functions: + +def parse_help_info(script): + + global PATHS, SCRIPT_INFO + + if script.userdir: + path = PATHS['uscripts'] + else: + path = PATHS['scripts'] + + fname = bsys.join(path, script.fname) + + if not bsys.exists(fname): + Draw.PupMenu('IO Error: couldn\'t find script %s' % fname) + return None + + f = file(fname, 'r') + lines = f.readlines() + f.close() + + # fix line endings: + if lines[0].find('\r'): + unixlines = [] + for l in lines: + unixlines.append(l.replace('\r','')) + lines = unixlines + + llen = len(lines) + has_doc = 0 + + doc_data = { + '__author__': '', + '__version__': '', + '__url__': '', + '__email__': '', + '__bpydoc__': '', + '__doc__': '' + } + + i = 0 + while i < llen: + l = lines[i] + incr = 1 + for k in doc_data.keys(): + if l.find(k, 0, 20) == 0: + value, incr = parse_pyobj(k, lines, i) + exec("doc_data['%s'] = %s" % (k, value)) + has_doc = 1 + break + i += incr + + # fix these to seqs, simplifies coding elsewhere + for w in ['__author__', '__url__', '__email__']: + val = doc_data[w] + if val and type(val) == str: + doc_data[w] = [doc_data[w]] + + if not doc_data['__bpydoc__']: + if doc_data['__doc__']: + doc_data['__bpydoc__'] = doc_data['__doc__'] + + if has_doc: # any data, maybe should confirm at least doc/bpydoc + info = BPy_Info(script, doc_data) + SCRIPT_INFO = info + return True + + else: + return False + + +def parse_script_line(l): + + try: + pieces = l.split("'") + name = pieces[1].replace('...','') + version, fname, userdir = pieces[2].strip().split() + tip = pieces[3] + except: + return None + + return [name, int(version), fname, int(userdir), tip] + + +def parse_bpymenus(lines): + + global AllGroups + + llen = len(lines) + + for i in range(llen): + l = lines[i].strip() + if not l: continue + if l[-1] == '{': + group = Group(l[:-2]) + AllGroups.append(group) + i += 1 + l = lines[i].strip() + while l != '}': + if l[0] != '|': + data = parse_script_line(l) + if data: + script = Script(data) + group.add_script(script) + i += 1 + l = lines[i].strip() + +# AllGroups.reverse() + + +def create_group_menus(): + + global AllGroups + menus = [] + + for group in AllGroups: + + name = group.get_name() + menu = [] + scripts = group.get_scripts() + for s in scripts: menu.append(s.name) + menu = "|".join(menu) + menu = "%s%%t|%s" % (name, menu) + menus.append([name, menu]) + + return menus + + +# Collecting data: +fit_on_screen() +parse_bpymenus(lines) +GROUP_MENUS = create_group_menus() + + +# GUI: + +from Blender import BGL +from Blender.Window import Theme + +# globals: + +START_SCREEN = 0 +SCRIPT_SCREEN = 1 + +SCREEN = START_SCREEN + +# gui buttons: +len_gmenus = len(GROUP_MENUS) + +BUT_GMENU = range(len_gmenus) +for i in range(len_gmenus): + BUT_GMENU[i] = Draw.Create(0) + +# events: +BEVT_LINK = None # range(len(SCRIPT_INFO.links)) +BEVT_EMAIL = None # range(len(SCRIPT_INFO.emails)) +BEVT_GMENU = range(100, len_gmenus + 100) +BEVT_VIEWSOURCE = 1 +BEVT_EXIT = 2 +BEVT_BACK = 3 + +# gui callbacks: + +def gui(): # drawing the screen + + global SCREEN, START_SCREEN, SCRIPT_SCREEN + global SCRIPT_INFO, AllGroups, GROUP_MENUS + global BEVT_EMAIL, BEVT_LINK + global BEVT_VIEWSOURCE, BEVT_EXIT, BEVT_BACK, BEVT_GMENU, BUT_GMENU + global PADDING, WIN_W, WIN_H, SCROLL_DOWN, COLUMNS, FMODE + + theme = Theme.Get()[0] + tui = theme.get('ui') + ttxt = theme.get('text') + + COL_BG = float_colors(ttxt.back) + COL_TXT = ttxt.text + COL_TXTHI = ttxt.text_hi + + BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3]) + BGL.glClear(BGL.GL_COLOR_BUFFER_BIT) + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + + resize = screen_was_resized() + if resize: fit_on_screen() + + if SCREEN == START_SCREEN: + x = PADDING + bw = 85 + bh = 25 + hincr = 50 + + butcolumns = (WIN_W - 2*x)/ bw + if butcolumns < 2: butcolumns = 2 + elif butcolumns > 7: butcolumns = 7 + + len_gm = len(GROUP_MENUS) + butlines = len_gm / butcolumns + if len_gm % butcolumns: butlines += 1 + + h = hincr * butlines + 20 + y = h + bh + + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) + BGL.glRasterPos2i(x, y) + Draw.Text('Scripts Help Browser') + + y -= bh + + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + + i = 0 + j = 0 + for group_menu in GROUP_MENUS: + BGL.glRasterPos2i(x, y) + Draw.Text(group_menu[0]+':') + BUT_GMENU[j] = Draw.Menu(group_menu[1], BEVT_GMENU[j], + x, y-bh-5, bw, bh, 0, + 'Choose a script to read its help information') + if i == butcolumns - 1: + x = PADDING + i = 0 + y -= hincr + else: + i += 1 + x += bw + 3 + j += 1 + + x = PADDING + y = 10 + BGL.glRasterPos2i(x, y) + Draw.Text('Select script for its help. Press Q or ESC to leave.') + + elif SCREEN == SCRIPT_SCREEN: + if SCRIPT_INFO: + + if resize: + SCRIPT_INFO.wrap_lines(1) + SCROLL_DOWN = 0 + + h = 18 * SCRIPT_INFO.len_content + 12 * SCRIPT_INFO.spaces + x = PADDING + y = WIN_H + bw = 38 + bh = 16 + + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) + for line in SCRIPT_INFO.header: + y -= 18 + BGL.glRasterPos2i(x, y) + size = Draw.Text(line) + + for line in text_wrap('Tooltip: %s' % SCRIPT_INFO.script.tip): + y -= 18 + BGL.glRasterPos2i(x, y) + size = Draw.Text(line) + + i = 0 + y -= 28 + for data in SCRIPT_INFO.d['__url__']: + Draw.PushButton('link %d' % (i + 1), BEVT_LINK[i], + x + i*bw, y, bw, bh, data[0]) + i += 1 + y -= bh + 1 + + i = 0 + for data in SCRIPT_INFO.d['__email__']: + Draw.PushButton('email', BEVT_EMAIL[i], x + i*bw, y, bw, bh, data[0]) + i += 1 + y -= 18 + + y0 = y + BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2]) + for line in SCRIPT_INFO.content[SCROLL_DOWN:]: + if line: + line = line.replace('
', '') + BGL.glRasterPos2i(x, y) + Draw.Text(line) + y -= 18 + else: y -= 12 + if y < PADDING + 20: # reached end, either stop or go to 2nd column + if COLUMNS == 1: break + elif x == PADDING: # make sure we're still in column 1 + x = 6*TEXT_WRAP + PADDING / 2 + y = y0 + + x = PADDING + Draw.PushButton('source', BEVT_VIEWSOURCE, x, 17, 45, bh, + 'View this script\'s source code in the Text Editor (hotkey: S)') + Draw.PushButton('exit', BEVT_EXIT, x + 45, 17, 45, bh, + 'Exit from Scripts Help Browser (hotkey: Q)') + if not FMODE: Draw.PushButton('back', BEVT_BACK, x + 2*45, 17, 45, bh, + 'Back to scripts selection screen (hotkey: ESC)') + BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2]) + BGL.glRasterPos2i(x, 5) + Draw.Text('use the arrow keys or the mouse wheel to scroll text', 'small') + +def fit_scroll(): + global SCROLL_DOWN + if not SCRIPT_INFO: + SCROLL_DOWN = 0 + return + max = SCRIPT_INFO.len_content + SCRIPT_INFO.spaces - 1 + if SCROLL_DOWN > max: SCROLL_DOWN = max + if SCROLL_DOWN < 0: SCROLL_DOWN = 0 + + +def event(evt, val): # input events + + global SCREEN, START_SCREEN, SCRIPT_SCREEN + global SCROLL_DOWN, FMODE + + if not val: return + + if evt == Draw.ESCKEY: + if SCREEN == START_SCREEN or FMODE: Draw.Exit() + else: + SCREEN = START_SCREEN + SCROLL_DOWN = 0 + Draw.Redraw() + return + elif evt == Draw.QKEY: + Draw.Exit() + return + elif evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE] and SCREEN == SCRIPT_SCREEN: + SCROLL_DOWN += 1 + fit_scroll() + Draw.Redraw() + return + elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE] and SCREEN == SCRIPT_SCREEN: + SCROLL_DOWN -= 1 + fit_scroll() + Draw.Redraw() + return + elif evt == Draw.SKEY: + if SCREEN == SCRIPT_SCREEN and SCRIPT_INFO: + load_script_text(SCRIPT_INFO.script) + return + +def button_event(evt): # gui button events + + global SCREEN, START_SCREEN, SCRIPT_SCREEN + global BEVT_LINK, BEVT_EMAIL, BEVT_GMENU, BUT_GMENU, SCRIPT_INFO + global SCROLL_DOWN, FMODE + + if evt >= 100: # group menus + for i in range(len(BUT_GMENU)): + if evt == BEVT_GMENU[i]: + group = AllGroups[i] + index = BUT_GMENU[i].val - 1 + if index < 0: return # user didn't pick a menu entry + script = group.get_scripts()[BUT_GMENU[i].val - 1] + if parse_help_info(script): + SCREEN = SCRIPT_SCREEN + BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20) + BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50) + Draw.Redraw() + else: + res = Draw.PupMenu("No help available%t|View Source|Cancel") + if res == 1: + load_script_text(script) + elif evt >= 20: + if not WEBBROWSER: + Draw.PupMenu('Missing standard Python module%t|You need module "webbrowser" to access the web') + return + + if evt >= 50: # script screen email buttons + email = SCRIPT_INFO.d['__email__'][evt - 50][1] + webbrowser.open("mailto:%s" % email) + else: # >= 20: script screen link buttons + link = SCRIPT_INFO.d['__url__'][evt - 20][1] + webbrowser.open(link) + elif evt == BEVT_VIEWSOURCE: + if SCREEN == SCRIPT_SCREEN: load_script_text(SCRIPT_INFO.script) + elif evt == BEVT_EXIT: + Draw.Exit() + return + elif evt == BEVT_BACK: + if SCREEN == SCRIPT_SCREEN and not FMODE: + SCREEN = START_SCREEN + SCRIPT_INFO = None + SCROLL_DOWN = 0 + Draw.Redraw() + +keepon = True +FMODE = False # called by Blender.ShowHelp(name) API function ? + +KEYNAME = '__help_browser' +rd = Registry.GetKey(KEYNAME) +if rd: + rdscript = rd['script'] + keepon = False + Registry.RemoveKey(KEYNAME) + for group in AllGroups: + for script in group.get_scripts(): + if rdscript == script.fname: + parseit = parse_help_info(script) + if parseit == True: + keepon = True + SCREEN = SCRIPT_SCREEN + BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20) + BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50) + FMODE = True + elif parseit == False: + Draw.PupMenu("ERROR: script doesn't have proper help data") + break + +if not keepon: + Draw.PupMenu("ERROR: couldn't find script") +else: + Draw.Register(gui, event, button_event) diff --git a/release/scripts/help_getting_started.py b/release/scripts/help_getting_started.py new file mode 100644 index 00000000000..19eac9e2e20 --- /dev/null +++ b/release/scripts/help_getting_started.py @@ -0,0 +1,43 @@ +#!BPY +""" +Name: 'Getting Started' +Blender: 234 +Group: 'Help' +Tooltip: 'Help for new users' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"Getting Started" page. +""" + +# $Id$ +# +# -------------------------------------------------------------------------- +# Getting Started Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(Blender.Get('version')) +webbrowser.open('http://www.blender3d.org/Help/?pg=GettingStarted&ver=' + version) diff --git a/release/scripts/help_manual.py b/release/scripts/help_manual.py new file mode 100644 index 00000000000..75d93522c31 --- /dev/null +++ b/release/scripts/help_manual.py @@ -0,0 +1,41 @@ +#!BPY +""" +Name: 'Manual' +Blender: 234 +Group: 'Help' +Tooltip: 'The Blender reference manual' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"Blender Manual" page. +""" + +# -------------------------------------------------------------------------- +# Manual Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(Blender.Get('version')) +webbrowser.open('http://www.blender3d.org/Help/?pg=Manual&ver=' + version) diff --git a/release/scripts/help_release_notes.py b/release/scripts/help_release_notes.py new file mode 100644 index 00000000000..49382755163 --- /dev/null +++ b/release/scripts/help_release_notes.py @@ -0,0 +1,41 @@ +#!BPY +""" +Name: 'Release Notes' +Blender: 234 +Group: 'Help' +Tooltip: 'Information about the changes in this version of Blender' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"Release Notes" page. +""" + +# -------------------------------------------------------------------------- +# Release Notes Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(Blender.Get('version')) +webbrowser.open('http://www.blender3d.org/Help/?pg=ReleaseNotes&ver=' + version) diff --git a/release/scripts/help_tutorials.py b/release/scripts/help_tutorials.py new file mode 100644 index 00000000000..1fbabc43eb6 --- /dev/null +++ b/release/scripts/help_tutorials.py @@ -0,0 +1,42 @@ +#!BPY + +""" +Name: 'Tutorials' +Blender: 234 +Group: 'Help' +Tooltip: 'Tutorials for learning to use Blender' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"Blender Tutorials" page. +""" + +# -------------------------------------------------------------------------- +# Tutorials Help Menu Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +version = str(Blender.Get('version')) +webbrowser.open('http://www.blender3d.org/Help/?pg=Tutorials&ver=' + version) diff --git a/release/scripts/help_web_blender.py b/release/scripts/help_web_blender.py new file mode 100644 index 00000000000..999746c1f9c --- /dev/null +++ b/release/scripts/help_web_blender.py @@ -0,0 +1,42 @@ +#!BPY + +""" +Name: 'Blender Website' +Blender: 234 +Group: 'HelpWebsites' +Tooltip: 'The official Blender website' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at Blender's main site, +www.blender3d.org. +""" + + +# -------------------------------------------------------------------------- +# Blender Website Help Menu -> Websites Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +webbrowser.open('http://www.blender3d.org/') diff --git a/release/scripts/help_web_devcomm.py b/release/scripts/help_web_devcomm.py new file mode 100644 index 00000000000..afe9ef064d9 --- /dev/null +++ b/release/scripts/help_web_devcomm.py @@ -0,0 +1,41 @@ +#!BPY + +""" +Name: 'Developer Community' +Blender: 234 +Group: 'HelpWebsites' +Tooltip: 'Get involved with Blender development' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender.org, the +Blender development portal. +""" + +# -------------------------------------------------------------------------- +# Blender Website Help Menu -> Websites Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import webbrowser +webbrowser.open('http://www.blender.org') diff --git a/release/scripts/help_web_eshop.py b/release/scripts/help_web_eshop.py new file mode 100644 index 00000000000..997d07ca255 --- /dev/null +++ b/release/scripts/help_web_eshop.py @@ -0,0 +1,41 @@ +#!BPY + +""" +Name: 'Blender E-Shop' +Blender: 234 +Group: 'HelpWebsites' +Tooltip: 'Buy official Blender resources and merchandise online' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"E-Shop" section. +""" + +# -------------------------------------------------------------------------- +# Blender Website Help Menu -> Websites Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender, webbrowser +webbrowser.open('http://www.blender3d.org/e-shop') diff --git a/release/scripts/help_web_usercomm.py b/release/scripts/help_web_usercomm.py new file mode 100644 index 00000000000..56f64764ac7 --- /dev/null +++ b/release/scripts/help_web_usercomm.py @@ -0,0 +1,41 @@ +#!BPY + +""" +Name: 'User Community' +Blender: 234 +Group: 'HelpWebsites' +Tooltip: 'Get involved with other Blender users' +""" + +__author__ = "Matt Ebb" +__url__ = ("blender", "elysiun") +__version__ = "1.0" +__bpydoc__ = """\ +This script opens the user's default web browser at www.blender3d.org's +"User Community" page. +""" + +# -------------------------------------------------------------------------- +# Blender Website Help Menu -> Websites Item +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import webbrowser +webbrowser.open('http://www.blender3d.org/Community') diff --git a/release/scripts/hotkeys.py b/release/scripts/hotkeys.py new file mode 100644 index 00000000000..bfaac252b21 --- /dev/null +++ b/release/scripts/hotkeys.py @@ -0,0 +1,921 @@ +#!BPY + +""" Registration info for Blender menus: +Name: 'HotKey and MouseAction Reference' +Blender: 242 +Group: 'Help' +Tip: 'All the hotkeys/short keys' +""" + +__author__ = "Jean-Michel Soler (jms)" +__url__ = ("blender", "blenderartist", +"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm", +"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") +__version__ = "21/01/2007" + +__bpydoc__ = """\ +This script is a reference about all hotkeys and mouse actions in Blender. + +Usage: + +Open the script from the Help menu and select group of keys to browse. + +Notes:
+ Additional entries in the database (c) 2004 by Bart. + Additional entries in the database for blender 2.37 --> 2.43 (c) 2003-2007/01 by jms. + +""" + +#------------------------ +# Hotkeys script +# (c) jm soler (2003-->01/2007) +# ----------------------- +# Page officielle : +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_hotkeyscript.htm +# Communiquer les problemes et les erreurs sur: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------- +# ce script est proposé sous licence GPL pour etre associe +# a la distribution de Blender 2.33 et suivant +# -------------------------------------------------------------------------- +# this script is released under GPL licence +# for the Blender 2.33 scripts package +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) 2003, 2004: Jean-Michel Soler +# Additionnal entries in the original data base (c) 2004 by Bart (bart@neeneenee.de) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender.Draw import * +from Blender.BGL import * + +# INTERNATIONAL={0:'English','1':'French'} +# LANGUAGE=0 + +hotkeys={ +'Search ':[['', '']], +'Specials 1 ':[ +[',', 'Set Bounding Box rotation scaling pivot'], +['Ctrl-,', 'Set Median Point rotation scaling pivot'], +['.', 'Set 3D cursor as rotation scaling pivot'], +['.', 'Outliner : to get the current active data in center of view'], +['Ctrl-.', 'Set Individual Object Centers as rotation scaling pivot'], +['~', 'Display all layers (German keys: ö,french keyboard: ù)'], +['Shift-~', 'Display all/previous layers (German keys: Shift-ö, french keyboard: shift-ù)'], +['ENTER', 'Outliner : to open a subtree, works on entire item line. '], +['HOME', 'Outliner : to show the entire Object hierarchy. '], +['SHIFT+BACKSPACE',' Text edit mode: Clear text '], +['SPACE', 'Popup menu'], +['SPACE', '3D View: camera selected'], +['Ctrl-SPACE', 'Manipulator (transform widget) Menu'], +['TAB', 'Enter/exit Edit Mode'], +['TAB', 'Edit Mode and Numerical Edit (see N key) : move to next input value'], +['TAB', 'Sequencer: Edit meta strip'], +['TAB', 'IPO: Edit selected'], +['TAB', 'Text Editor : indent'], +['TAB', 'NODE window : Edit group'], #243 +['Shift-TAB', 'Text Editor : unindent'], +['Shift-TAB', 'Edit Mode: Toggle snaping'], +['Ctrl-TAB', 'ARMATURE : Enter/exit Pose Mode'], +['Ctrl-TAB','MESH : all views, enter exit weight paint mode.'], +['Shift-TAB', 'Edit Mode : Enter Object Mode'], +['Ctrl-Open menu /', ''], +['Ctrl-Load Image', 'Opens a thumbnail browser instead of file browser for images'], +['.', '...'] +], + +'Mouse ':[ +['Actions:', ''], +['LMB', '3D View: Set 3D Cursor'], +['LMB', '3D View: camera selected'], +['LMB drag', 'Border select circle: add to selection'], +['LMB hold down', 'Popup menu'], +['LMB hold down drag', 'Gesture'], +['Ctrl-LMB', 'IPO: Add key'], +['Ctrl-LMB', '3D View: OBJECT or EDIT mode, select with the Lasso tool'], +['Ctrl-LMB', '3D View: ARMATURE EDIT mode, add a new bone to the selected end '], +['Shift-LMB','MANIPULATOR (transform widget): select the axe to remove in the current'], +['Shift-LMB','MANIPULATOR transformation ( if there is a problem with small step adjustment'], +['Shift-LMB','MANIPULATOR first select the axe or axes with LBM alone)'], +['Shift-LMB', 'Outliner : Hold Shift while clicking on a triangle arrow to open/close the subtree below'], +['MMB', 'Rotate'], +['Ctrl-MMB', 'Zoom view'], +['Ctrl-LMB', 'Outliner : Hold CTRL while clicking on a name allows you to edit a name.'], +['Ctrl-LMB', 'Outliner : This works for all visualized data, including bones or vertex groups,'], +['Ctrl-LMB', 'Outliner : but not for \'nameless\' items that draw the links to Hooks, Deform '], +['Ctrl-LMB', 'Outliner : Groups or Constraints.'], +['Shift-MMB', 'Move view'], +['RMB', 'Select'], +['RMB drag', 'Border select circle: subtract from selection'], +['RMB hold down', 'Popup menu'], +['Alt-RMB', 'Object Mode :Select but in a displayed list of objects located under the mouse cursor'], +['Alt-RMB', 'Edit Mode: Select EDGES LOOP '], +['Alt+Ctrl-RMB', 'Edit Mode: Select FACES LOOP'], +['Alt+Ctrl-RMB', 'UV Image Editor: Select face'], +['Shift-RMB', 'Add/subtract to/from selection'], +['Wheel', 'Zoom view'], +['Transformations:', ''], +['Drag+Ctrl', 'Step adjustment'], +['Drag+Ctrl+Shift', 'Small step adjustment (Transform Widget : first select the axe or axes with LBM alone)'], +['Drag+Shift', 'Fine adjustment (Transform Widget : first select the axe or axes with LBM alone)'], +['LMB', 'Confirm transformation'], +['MMB', 'Toggle optional transform feature'], +['RMB', 'Abort transformation'], +['.', '...'] +], + +'F-Keys ':[ +['F1', 'Open File'], +['Shift-F1', 'Library Data Select'], +['F2', 'Save File'], +['Shift-F2', 'Export DXF'], +['Ctrl-F2', 'Save/export in vrml 1.0 format' ], +['F3', 'Save image'], +['Ctrl-F3', 'Save image : dump 3d view'], +['Ctrl-Shift-F3', 'Save image : dump screen'], +['F4', 'Logic Window (may change)'], +['Shift-F4', 'Object manager Data Select '], +['F5', 'Material Window'], +['Shift-F5', '3D Window'], +['F6', 'Texture Window'], +['Shift-F6', 'IPO Window'], +['F7', 'Object Window'], +['Shift-F7', 'Buttons Window'], +['F8', 'World Window'], +['Shift-F8', 'Video Sequencer Window'], +['F9', 'Edit Mode Window'], +['Shift-F9', 'OOP Window'], +['Alt-Shift-F9', 'OutLiner Window'], +['F10', 'Render Window'], +['Shift-F10', 'UV Image Editor'], +['F11', 'Recall the last rendered image'], +['Shift-F11', 'Text Editor'], +['ctrl-F11', 'replay the last rendered animation'], +['F12', 'Render current Scene'], +['Ctrl-F12', 'Render animation'], +['Ctrl-Shift-F12', 'NLA Editor'], +['Shift-F12', 'Action Editor'], +['Shift-F12', 'Action Editor'], +['.', '...'] +], + +'Numbers ':[ +['1..2..0-=', 'Show layer 1..2..12'], +['1..2..0-=', 'Edit Mode with Size, Grab, rotate tools : enter value'], +['Alt-1..2..0', 'Show layer 11..12..20'], +['Shift-1..2..0', 'Toggle layer 1..2..12'], +['Ctrl-1..4', 'Object/Edit Mode : change subsurf level to the selected value'], +['Shift-ALT-...', 'Toggle layer 11..12..20'], +['Crtl-Shift-ALT-3', 'Edit Mode & Face Mode : Triangle faces'], +['Crtl-Shift-ALT-4', 'Edit Mode & Face Mode : Quad faces'], +['Crtl-Shift-ALT-5', 'Edit Mode & Face Mode : Non quad or triangle faces'], +['.', '...'] +], + +'Numpad ':[ +['Numpad DEL', 'Zoom on object'], +['Numpad /', 'Local view on object (hide others)'], +['Numpad *', 'Rotate view to objects local axes'], +['Numpad +', 'Zoom in (works everywhere)'], +['Numpad -', 'OutLiner window, Collapse one level of the hierarchy'], +['Alt-Numpad +', 'Proportional vertex Edit Mode: Increase range of influence'], +['Ctrl-Numpad +', 'Edit Mode: Select More vertices'], +['Numpad -', 'Zoom out (works everywhere)'], +['Numpad +', 'OutLiner window, Expand one level of the hierarchy'], +['Alt-Numpad -', 'Proportional vertex Edit Mode: Decrease range of influence'], +['Ctrl-Numpad +', 'Edit Mode: Select Less vertices'], +['Numpad 0', 'Set Camera view'], +['Ctrl-Numpad 0', 'Set active object as camera'], +['Alt-Numbad 0', 'Restore old camera'], +['Ctrl-Alt-Numpad 0', 'Align active camera to view'], +['Numpad 1', 'Front view'], +['Ctrl-Numpad 1', 'Back view'], +['Numpad 3', 'Right view'], +['Ctrl-Numpad 3', 'Left view'], +['Numpad 7', 'Top view'], +['Ctrl-Numpad 7', 'Bottom view '], +['Numpad 5', 'Toggle orthogonal/perspective view'], +['Numpad 9', 'Redraw view'], +['Numpad 4', 'Rotate view left'], +['ctrl-Shift-Numpad 4', 'Previous Screen'], +['Numpad 6', 'Rotate view right'], +['ctrl-Shift-Numpad 6', 'Next Screen'], +['Numpad 8', 'Rotate view up'], +['Numpad 2', 'Rotate view down'], +['.', '...'] +], + +'Arrows ':[ +['Home/Pos1', 'View all',''], +['Home', 'OutLiner Windows, Show hierarchy'], +['PgUp', 'Edit Mode and Proportionnal Editing Tools, increase influence'], +['PgUp', 'Strip Editor, Move Down'], +['PgUn', 'TimeLine: Jump to next marker'], +['PgUp', 'IPO: Select next keyframe'], +['Ctrl-PgUp', 'IPO: Select and jump to next keyframe'], +['Ctrl-PgUn', 'TimeLine: Jump to next key'], +['PgDn', 'Edit Mode and Proportionnal Editing Tools, decrease influence'], +['PgDn', 'Strip Editor, Move Up'], +['PgDn', 'TimeLine: Jump to prev marker'], +['PgDn', 'IPO: Select previous keyframe'], +['Ctrl-PgDn', 'IPO: Select and jump to previous keyframe'], +['Ctrl-PgDn', 'TimeLine: Jump to prev key'], +['Left', 'One frame backwards'], +['Right', 'One frame forwards'], +['Down', '10 frames backwards'], +['Up', '10 frames forwards'], +['Alt-Down', 'Blender in Window mode'], +['Alt-Up', 'Blender in Fullscreen mode'], +['Ctrl-Left', 'Previous screen'], +['Ctrl-Right', 'Next screen'], +['Ctrl-Alt-C', 'Object Mode : Add Constraint'], +['Ctrl-Down', 'Maximize window toggle'], +['Ctrl-Up', 'Maximize window toggle'], +['Shift-Arrow', 'Toggle first frame/ last frame'], +['.', '...'] +], + +'Letters ':[ +{ +"A":[ +['A', 'Select all/Deselect all'], +['A', 'Outliner : Select all/Deselect all'], +['A', 'Ipo Editor : Object mode, Select all/Deselect all displayed Curves'], #243 +['A', 'Ipo Editor : Edit mode, Select all/Deselect all vertices'], #243 +['A', 'Render window (F12) : Display alpha plane'], +['Alt-A', 'Play animation in current window'], +['Ctrl-A', 'Apply objects size/rotation to object data'], +['Ctrl-A', 'Text Editor: Select all'], +['Shift-A', 'Sequencer: Add menu'], +['Shift-A', '3D-View: Add menu'], +['Shift-ALT-A', 'Play animation in all windows'], +['Shift-CTRL-A', 'Apply lattice / Make dupliverts real'], +['Shift-CTRL-A', 'Apply Deform '], +['.', '...'] +], + +"B":[ +['B', 'Border select'], +['BB', 'Circle select'], +['Alt+B', 'Object Mode: Select visible view section in 3D space'], +['Shift-B', 'Set render border (in active camera view)'], +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake (on an image in the uv editor window) the selected Meshes'], #243 +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake Full render of selected Meshes'], #243 +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake Ambient Occlusion of selected Meshes'], #243 +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake Normals of the selected Meshes'], #243 +['Ctrl-Alt+B', 'Object Mode: in 3D view, Bake Texture Only of selected Meshes'], #243 +['.', '...'] +], + +"C":[ +['C', 'Center view on cursor'], +['C', 'UV Image Editor: Active Face Select toggle'], +['C', 'Sequencer: Change content of the strip '], #243 +['C', 'IPO: Snap current frame to selected key'], +['C', 'TimeLine: Center View'], +['C', 'File Selector : Copy file'], +['C', 'NODE window : Show cyclic referencies'], #243 +['Alt-C', 'Object Mode: Convert menu'], +['Alt-C', 'Text Editor: Copy '], +['Ctrl-Shift-C', 'Text Editor: Copy selection to clipboard'], +['Ctrl-C', 'Copy menu (Copy properties of active to selected objects)'], +['Ctrl-C', 'UV Image Editor: Stick UVs to mesh vertex'], +['Ctrl-C','ARMATURE : posemode, Copy pose attributes'], +['Ctrl+Alt-C',' ARMATURE : posemode, add constraint to new empty object.'], +['Shift-C', 'Center and zoom view on selected objects'], +['Shift-C', 'UV Image Editor: Stick local UVs to mesh vertex'], +['.', '...'] +], + +"D":[ +['D', 'Set 3d draw mode'], +['Alt-D', 'Object Mode: Create new instance of object'], +['Ctrl-D', 'Display alpha of image texture as wire'], +['Ctrl-D', 'Text Editor : uncomment'], +['Shift-D', 'Create full copy of object'], +['Shift-D', 'NODE window : duplicate'], #243 +['CTRL-SHIFT-D', 'NLA editor : Duplicate markers'], +['CTRL-SHIFT-D', 'Action editor : Duplicate markers'], +['CTRL-SHIFT-D', 'IPO editor : Duplicate markers'], +['.', '...'] +], + +"E":[ +['E', 'Edit Mode: Extrude'], +['E', 'UV Image Editor: LSCM Unwrap'], +['E', 'TimeLine: Set current frame as End '], +['E', 'NODE window : Execute composite'], #243 +['ER', 'Edit Mode: Extrude Rotate'], +['ES', 'Edit Mode: Extrude Scale'], +['ESX', 'Edit Mode: Extrude Scale X axis'], +['ESY', 'Edit Mode: Extrude Scale Y axis'], +['ESZ', 'Edit Mode: Extrude Scale Z axis'], +['EX', 'Edit Mode: Extrude along X axis'], +['EY', 'Edit Mode: Extrude along Y axis'], +['EZ', 'Edit Mode: Extrude along Z axis'], +['Alt-E', 'Edit Mode: exit Edit Mode'], +['Ctrl-E', 'Edit Mode: Edge Specials menu'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Mark seams'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Clear seams'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CW'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Rotate Edge CCW'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Loop Cut'], +['Ctrl-E', 'Edit Mode: Edge Specials menu, Edge Slide'], +['Shift-E', 'Edit Mode: SubSurf Edge Sharpness'], +['.', '...'] +], + +"F":[ +['F', 'Edit mode: Make edge/face'], +['F', 'Sequencer: Set Filter Y'], +['F', 'Object Mode: UV/Face Select mode'], +['Alt-F', 'Edit Mode: Beautify fill'], +['Alt-F,','Text editor : find again '], +['Alt-Ctrl-F,','Text editor : find '], +['Ctrl-F', 'Object Mode: Sort faces in Z direction'], +['Ctrl-F', 'Edit Mode: Flip triangle edges'], +['Shift-F', 'Edit Mode: Fill with triangles'], +['Shift-F', 'Object Mode: fly mode (see header for fly mode keys)'], +['.', '...'] +], + +"G":[ +['G', 'Grab (move)'], +['G', 'Timeline : Grab (move) Marker'], +['Alt-G', 'Clear location (this does only make sense in Object mode)'], +['Alt-G', 'NODE window : ungroup'], #243 +['Shift-ALT-G', 'Object mode: Remove selected objects from group'], +['Ctrl-G', 'NODE window : group'], #243 +['Ctrl-G', 'Add selected objects to group'], +['Ctrl-G', 'IPO editor, Grab/move marker'], +['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Grab Mode'], +['Shift-G', 'Object mode: Selected Group menu'], +['Shift-G', 'Object mode: Selected Group menu 1, Children'], +['Shift-G', 'Object mode: Selected Group menu 2, Immediate Children'], +['Shift-G', 'Object mode: Selected Group menu 3, Parent'], +['Shift-G', 'Object mode: Selected Group menu 4, Sibling'], +['Shift-G', 'Object mode: Selected Group menu 5, Object of same type'], +['Shift-G', 'Object mode: Selected Group menu 6, Object in same shared layers'], +['Shift-G', 'Object mode: Selected Group menu 7, Objects in same group'], +['.', '...'] +], + +"H":[ +['H', 'Hide selected vertices/faces'], +['H', 'Curves: Set handle type'], +['H', 'Action editor: Handle type aligned'], +['H', 'Action editor: Handle type free'], +['H', 'NODE window : hide/unhide'], #243 +['Alt-H', 'Edit Mode : Show Hidden vertices/faces'], +['Shift-H', 'Curves: Automatic handle calculation'], +['Shift-H', 'Action editor: Handle type auto'], +['Shift-H', 'Edit Mode : Hide deselected vertices/faces'], +['Ctrl-H', 'Edit Mode : Add a hook on selected points or show the hook menu .'], +['.', '...'] +], + +"I":[ +['I', 'Keyframe menu'], +['Alt-I','ARMATURE : posemode, remove IK constraints.'], +['Ctrl-I','ARMATURE : add IK constraint'], +['.', '...'] +], + +"J":[ +['J', 'IPO: Join menu'], +['J', 'Mesh: Join all adjacent triangles to quads'], +['J', 'Render Window: Swap render buffer'], +['Alt-J,','Text editor : Jump '], +['Ctrl-J', 'Join selected objects'], +['Ctrl-J', 'Nurbs: Add segment'], +['Ctrl-J', 'IPO: Join keyframes menu'], +['.', '...'] +], + +"K":[ +['K', '3d Window: Show keyframe positions'], +['K', 'Edit Mode: Loop/Cut menu'], +['K', 'IPO: Show keyframe positions'], +['K', 'Nurbs: Print knots'], +['K', 'VIDEO editor : cut at current frame'], #243 +['Ctrl-K', 'Make skeleton from armature'], +['Shift-K', 'Show and select all keyframes for object'], +['Shift-K', 'Edit Mode: Knife Mode select'], +['Shift-K', 'UV Face Select: Clear vertex colours'], +['Shift-K', 'Vertex Paint: All vertex colours are erased; they are changed to the current drawing colour.'], +['.', '...'] +], + +"L":[ +['L', 'Make local menu'], +['L', 'Edit Mode: Select linked vertices (near mouse pointer)'], +['L', 'NODE window: Select linked from '], #243 +['L', 'OOPS window: Select linked objects'], +['L', 'UV Face Select: Select linked faces'], +['Ctrl-L', 'Make links menu (for instance : to scene...)'], +['Shift-L', 'Select links menu'], +['Shift-L', 'NODE window: Select linked to '], #243 +['.', '...'] +], + +"M":[ +['M', 'Object mode : Move object to different layer'], +['M', 'Sequencer: Make meta strip (group) from selected strips'], +['M', 'Edit Mode: Mirros Axis menu'], +['M', 'File Selector: rename file'], +['M', 'Video Sequence Editor : Make Meta strip...'], +['M', 'NLA editor: Add marker'], +['M', 'Action editor: Add marker'], +['M', 'IPO editor: Add marker'], +['M', 'TimeLine: Add marker'], +['Alt-M', 'Edit Mode: Merge vertices menu'], +['Alt-M', 'Video Sequence Editor : Separate Meta strip...'], +['Ctrl-M', 'Object Mode: Mirros Axis menu'], +['Shift-M', 'TimeLine: Name marker'], +['Shift-M', 'IPO editor : Name marker'], +['Shift-M', 'NLA editor : Name marker'], +['Shift-M', 'Actions editor : Name marker'], +['.', '...'] +], + +"N":[ +['N', 'Transform Properties panel'] , +['N', 'OOPS window: Rename object'], +['N', 'VIDEO SEQUENCE editor : display strip properties '], #243 +['Alt-N', 'Text Editor : New text '], +['Ctrl-N', 'Armature: Recalculate bone roll angles'] , +['Ctrl-N', 'Edit Mode: Recalculate normals to outside'] , +['Ctrl-Shift-N', 'Edit Mode: Recalculate normals to inside'], +['.', '...'] +], + +"O":[ +['O', 'Edit Mode/UV Image Editor: Toggle proportional vertex editing'], +['O', 'IPO editor: Clean ipo curves (beware to the thresold needed value)'], #243 +['Alt-O', 'Clear object origin'], +['Alt-O', 'Edit mode, 3dview with prop-edit-mode, enables/disables connected'], +['Alt-O', 'Text Editor : Open file '], +['Ctrl-O', 'Open a panel with the ten most recent projets files'], #243 +['Shift-O', 'Proportional vertex Edit Mode: Toggle smooth/steep falloff'], +['Shift-O', 'Object Mode: Add a subsurf modifier to the selected mesh'], +['Shift-O', 'IPO editor: Smooth ipo curves'], #243 +['.', '...'] +], + +"P":[ +['P', 'Object Mode: Start realtime engine'], +['P', 'Edit mode: Seperate vertices to new object'], +['shift-P', 'Edit mode: Push-Pull'], +['shift-P', 'Object mode: Add a preview window in the D window'], +['P', 'UV Image Editor: Pin selected vertices. Pinned vertices will stay in place on the UV editor when executing an LSCM unwrap.'], +['Alt-P', 'Clear parent relationship'], +['Alt-P', 'UV Image Editor: Unpin UVs'], +['Alt-P', 'Text Editor : Run current script '], +['Ctrl-P', 'Make active object parent of selected object'], +['Ctrl-Shift-P', 'Make active object parent of selected object without inverse'], +['Ctrl-P', 'Edit mode: Make active vertex parent of selected object'], +['Ctrl-P', 'ARMATURE : editmode, make bone parent.'], +['.', '...'] +], + +"Q":[['Ctrl-Q', 'Quit'], + ['.', '...'] + ], + +"R":[ +['R', 'FileSelector : remove file'], +['R', 'Rotate'], +['R', 'IPO: Record mouse movement as IPO curve'], +['R', 'UV Face Select: Rotate menu uv coords or vertex colour'], +['R', 'NODE window : read saved render result'], #243 +['R', 'SEQUENCER window : re-assign entries to another strip '], #243 +['RX', 'Rotate around X axis'], +['RXX', "Rotate around object's local X axis"], +['RY', 'Rotate around Y axis'], +['RYY', "Rotate around object's local Y axis"], +['RZ', 'Rotate around Z axis'], +['RZZ', "Rotate around object's local Z axis"], +['Alt-R', 'Clear object rotation'], +['Alt-R', 'Text editor : reopen text.'], +['Ctrl-R', 'Edit Mode: Knife, cut selected edges, accept left mouse/ cancel right mouse'], +['Ctrl-Alt-R', 'MANIPULATOR (transform widget): set in Rotate Mode'], +['Shift-R', 'Edit Mode: select Face Loop'], +['Shift-R', 'Nurbs: Select row'], +['.', '...'] +], + +"S":[ +['S', 'Scale'] , +['S', 'TimeLine: Set Start'], +['SX', 'Flip around X axis'] , +['SY', 'Flip around Y axis'] , +['SZ', 'Flip around Z axis'] , +['SXX', 'Flip around X axis and show axis'] , +['SYY', 'Flip around Y axis and show axis'] , +['SZZ', 'Flip around Z axis and show axis'] , +['Alt-S', 'Edit mode: Shrink/fatten (Scale along vertex normals)'] , +['Alt-S', 'Text Editor : Save the current text to file '], +['Alt-S',' ARMATURE : posemode editmode: Scale envalope.'], +['Ctrl-Shift-S', 'Edit mode: To Sphere'] , +['Ctrl-Alt-Shift-S', 'Edit mode: Shear'] , +['Alt-S', 'Clear object size'] , +['Ctrl-S', 'Edit mode: Shear'] , +['Alt-Shift-S,','Text editor : Select the line '], +['Ctrl-Alt-G', 'MANIPULATOR (transform widget): set in Size Mode'], +['Shift-S', 'Cursor/Grid snap menu'], +['Shift-S+1', 'VIDEO SEQUENCE editor : jump to the current frame '], +['.', '...'] +], + +"T":[ +['T', 'Adjust texture space'], +['T', 'Edit mode: Flip 3d curve'], +['T', 'IPO: Menu Change IPO type, 1 Constant'], +['T', 'IPO: Menu Change IPO type, 2 Linear'], +['T', 'IPO: Menu Change IPO type, 3 Bezier'], +['T', 'TimeLine: Show second'], +['T', 'VIDEO SEQUENCE editor : toggle between show second andd show frame'], #243 +['Alt-T', 'Clear tracking of object'], +['Ctrl-T', 'Make selected object track active object'], +['Ctrl-T', 'Edit Mode: Convert to triangles'], +['Ctrl-ALT-T', 'Benchmark'], +['.', '...'] +], + +"U":[ +['U', 'Make single user menu (for import completly linked object to another scene for instance) '] , +['U', '3D View: Make Single user Menu'] , +['U', 'UV Face Select: Automatic UV calculation menu'] , +['U', 'Vertex-/Weightpaint mode: Undo'] , +['Ctrl-U', 'Save current state as user default'], +['Shift-U', 'Edit Mode: Redo Menu'], +['Alt-U', 'Edit Mode & Object Mode: Undo Menu'], +['.', '...'] +], + +"V":[ +['V', 'Curves/Nurbs: Vector handle'], +['V', 'Edit Mode : Rip selected vertices'], +['V', 'Vertexpaint mode'], +['V', 'UV Image Editor: Stitch UVs'], +['Ctrl-V',' UV Image Editor: maximize stretch.'], +['V', 'Action editor: Vector'], +['Alt-V', "Scale object to match image texture's aspect ratio"], +['Alt-V', 'Text Editor : Paste '], +['Alt-Shift-V', 'Text Editor : View menu'], +['Alt-Shift-V', 'Text Editor : View menu 1, Top of the file '], +['Alt-Shift-V', 'Text Editor : View menu 2, Bottom of the file '], +['Alt-Shift-V', 'Text Editor : View menu 3, PageUp'], +['Alt-Shift-V', 'Text Editor : View menu 4, PageDown'], +['Ctrl-Shift-V', 'Text Editor: Paste from clipboard'], +['Shift-V', 'Edit mode: Align view to selected vertices'], +['Shift-V', 'UV Image Editor: Limited Stitch UVs popup'], +['.', '...'] +], + +"W":[ +['W', 'Edit Mode: Specials menu'], +['W', 'Edit Mode: Specials menu, ARMATURE 1 Subdivide'], +['W', 'Edit Mode: Specials menu, ARMATURE 2 Flip Left-Right Name'], +['W', 'Edit Mode: Specials menu, CURVE 1 Subdivide'], +['W', 'Edit Mode: Specials menu, CURVE 2 Swich Direction'], +['W', 'Edit Mode: Specials menu, MESH 1 Subdivide'], +['W', 'Edit Mode: Specials menu, MESH 2 Subdivide Multi'], +['W', 'Edit Mode: Specials menu, MESH 3 Subdivide Multi Fractal'], +['W', 'Edit Mode: Specials menu, MESH 4 Subdivide Smooth'], +['W', 'Edit Mode: Specials menu, MESH 5 Merge'], +['W', 'Edit Mode: Specials menu, MESH 6 Remove Double'], +['W', 'Edit Mode: Specials menu, MESH 7 Hide'], +['W', 'Edit Mode: Specials menu, MESH 8 Reveal'], +['W', 'Edit Mode: Specials menu, MESH 9 Select Swap'], +['W', 'Edit Mode: Specials menu, MESH 10 Flip Normal'], +['W', 'Edit Mode: Specials menu, MESH 11 Smooth'], +['W', 'Edit Mode: Specials menu, MESH 12 Bevel'], +['W', 'Edit Mode: Specials menu, MESH 13 Set Smooth'], +['W', 'Edit Mode : Specials menu, MESH 14 Set Solid'], +['W', 'Object Mode : on MESH objects, Boolean Tools menu'], +['W', 'Object Mode : on MESH objects, Boolean Tools 1 Intersect'], +['W', 'Object Mode : on MESH objects, Boolean Tools 2 union'], +['W', 'Object Mode : on MESH objects, Boolean Tools 3 difference'], +['W', 'Object Mode : on MESH objects, Boolean Tools 4 Add an intersect Modifier'], +['W', 'Object Mode : on MESH objects, Boolean Tools 5 Add an union Modifier'], +['W', 'Object Mode : on MESH objects, Boolean Tools 6 Add a difference Modifier'], +['W', 'Object mode : on TEXT object, Split characters, a new TEXT object by character in the selected string '], +['W', 'UV Image Editor: Weld/Align'], +['WX', 'UV Image Editor: Weld/Align X axis'], +['WY', 'UV Image Editor: Weld/Align Y axis'], +['Ctrl-W', 'Save current file'] , +['Shift-W', 'Warp/bend selected vertices around cursor'], +['alt-W', 'Export in videoscape format'], +['.', '...'] + ], + +"X":[ +['X', 'Delete menu'] , +['X', 'TimeLine : Remove marker'], +['X', 'NLA : Remove marker'], +['X', 'IPO : Remove marker'], +['X', 'NODE window : delete'], #243 +['Alt-X', 'Text Editor : Cut '], +['Ctrl-X', 'Restore default state (Erase all)'], +['.', '...'] + ], + +"Y":[ +['Y', 'Edit Mode & Mesh : Split selected vertices/faces from the rest'], +['Ctrl-Y', 'Object Mode : Redo'], +['.', '...'] +], + +"Z":[ +['Z', 'Render Window: 200% zoom from mouse position'], +['Z', 'Switch 3d draw type : solide/ wireframe (see also D)'], +['Alt-Z', 'Switch 3d draw type : solid / textured (see also D)'], +['Alt-Z,','Text editor : undo '], +['Ctrl-Z', 'Object Mode : Undo'], +['Ctrl-Z,','Text editor : undo '], +['Ctrl-Shift-Z,','Text editor : Redo '], +['Shift-Z', 'Switch 3d draw type : shaded / wireframe (see also D)'], +['.', '...'] +]}]} + +up=128 +down=129 +UP=0 +SEARCH=131 +OLDSEARCHLINE='' +SEARCHLINE=Create('') +LINE=130 +FINDED=[] +LEN=0 + +for k in hotkeys.keys(): + hotkeys[k].append(Create(0)) + +for k in hotkeys['Letters '][0]: + hotkeys['Letters '][0][k].append(Create(0)) + +hotL=hotkeys['Letters '][0].keys() +hotL.sort() + +hot=hotkeys.keys() +hot.sort() + +def searchfor(SEARCHLINE): + global hotkeys, hot + FINDLIST=[] + for k in hot: + if k not in ['Letters ', 'Search '] : + for l in hotkeys[k][:-1]: + #print 'k, l : ', k, l, l[1] + if l[1].upper().find(SEARCHLINE.upper())!=-1: + FINDLIST.append(l) + + elif k == 'Letters ': + for l in hotL : + for l0 in hotkeys['Letters '][0][l][:-1]: + #print 'k, l : ',l, k, l0 + if l0[1].upper().find(SEARCHLINE.upper())!=-1: + FINDLIST.append(l0) + #print 'FINDLIST',FINDLIST + FINDLIST.append(['Find list','Entry']) + return FINDLIST + + +glCr=glRasterPos2d +glCl3=glColor3f +glCl4=glColor4f +glRct=glRectf + +cf=[0.95,0.95,0.9,0.0] +c1=[0.95,0.95,0.9,0.0] +c=cf +r=[0,0,0,0] + +def trace_rectangle4(r,c): + glCl4(c[0],c[1],c[2],c[3]) + glRct(r[0],r[1],r[2],r[3]) + +def trace_rectangle3(r,c,c1): + glCl3(c[0],c[1],c[2]) + glRct(r[0],r[1],r[2],r[3]) + glCl3(c1[0],c1[1],c1[2]) + +def draw(): + global r,c,c1,hotkeys, hot, hotL, up, down, UP, SEARCH, SEARCHLINE,LINE + global OLDSEARCHLINE, FINDED, SCROLL, LEN + size=Buffer(GL_FLOAT, 4) + glGetFloatv(GL_SCISSOR_BOX, size) + size= size.list + + for s in [0,1,2,3]: size[s]=int(size[s]) + + c=[0.75,0.75,0.75,0] + c1=[0.6,0.6,0.6,0] + + r=[0,size[3],size[2],0] + trace_rectangle4(r,c) + + c=[0.64,0.64,0.64,0] + c1=[0.95,0.95,0.9,0.0] + + r=[0,size[3],size[2],size[3]-40] + trace_rectangle4(r,c) + + c1=[0.7,0.7,0.9,0.0] + c=[0.2,0.2,0.4,0.0] + c2=[0.71,0.71,0.71,0.0] + + glColor3f(1, 1, 1) + glRasterPos2f(42, size[3]-25) + + Text("HotKey and MouseAction Reference") + + l=0 + listed=0 + Llisted=0 + size[3]=size[3]-18 + + BeginAlign() + for i, k in enumerate(hot): + hotkeys[k][-1]=Toggle(k, i+10, 78*i, size[3]-(47), 78, 24, hotkeys[k][-1].val ) + l+=len(k) + if hotkeys[k][-1].val==1.0: + listed= i + EndAlign() + l=0 + size[3]=size[3]-4 + + if hot[listed]!='Letters ' and hot[listed]!='Search ' : + size[3]=size[3]-8 + SCROLL=size[3]/21 + END=-1 + if SCROLL < len(hotkeys[hot[listed]][:-1]): + BeginAlign() + Button('/\\',up,4,size[3]+8,20,14,'Scroll up') + Button('\\/',down,4,size[3]-8,20,14,'Scroll down') + EndAlign() + if (SCROLL+UP)0: + LEN=len(FINDED) + size[3]=size[3]-8 + SCROLL=size[3]/21 + END=-1 + + if SCROLL < len(FINDED): + BeginAlign() + Button('/\\',up,4,size[3]+8,20,14,'Scroll up') + Button('\\/',down,4,size[3]-8,20,14,'Scroll down') + EndAlign() + if (SCROLL+UP)4: + UP-=5 + elif (evt== UPARROWKEY): + if (UP+SCROLL)0: + UP-=1 + Redraw() + +def bevent(evt): + global hotkeysmhot, hotL, up,down,UP, FINDED + global SEARCH, SEARCHLINE,LINE, OLDSEARCHLINE + + if (evt== 1): + Exit() + + elif 9 < evt < 20: + for i, k in enumerate(hot): + if i+10!=evt: + hotkeys[k][-1].val=0 + UP=0 + Blender.Window.Redraw() + + elif 19 < evt < 46: + for i, k in enumerate(hotL): + if i+20!=evt: + hotkeys['Letters '][0][k][-1].val=0 + UP=0 + Blender.Window.Redraw() + + elif (evt==up): + UP+=1 + Blender.Window.Redraw() + + elif (evt==down): + if UP>0: UP-=1 + Blender.Window.Redraw() + + elif (evt==LINE): + if SEARCHLINE.val!='' and SEARCHLINE.val!=OLDSEARCHLINE: + OLDSEARCHLINE=SEARCHLINE.val + FINDED=searchfor(OLDSEARCHLINE) + Blender.Window.Redraw() + +if __name__ == '__main__': + Register(draw, event, bevent) \ No newline at end of file diff --git a/release/scripts/image_auto_layout.py b/release/scripts/image_auto_layout.py new file mode 100644 index 00000000000..19ee396c3b1 --- /dev/null +++ b/release/scripts/image_auto_layout.py @@ -0,0 +1,451 @@ +#!BPY + +""" +Name: 'Consolidate into one image' +Blender: 243 +Group: 'Image' +Tooltip: 'Pack all texture images into 1 image and remap faces.' +""" + +__author__ = "Campbell Barton" +__url__ = ("blender", "blenderartists.org") +__version__ = "1.1 2007/02/15" + +__bpydoc__ = """\ +This script makes a new image from the used areas of all the images mapped to the selected mesh objects. +Image are packed into 1 new image that is assigned to the original faces. +This is usefull for game models where 1 image is faster then many, and saves the labour of manual texture layout in an image editor. + +""" +# -------------------------------------------------------------------------- +# Auto Texture Layout v1.0 by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +# Function to find all the images we use +import Blender as B +from Blender.Mathutils import Vector, RotationMatrix +from Blender.Scene import Render +import BPyMathutils +BIGNUM= 1<<30 +TEXMODE= B.Mesh.FaceModes.TEX + +def pointBounds(points): + ''' + Takes a list of points and returns the + area, center, bounds + ''' + ymax= xmax= -BIGNUM + ymin= xmin= BIGNUM + + for p in points: + x= p.x + y= p.y + + if x>xmax: xmax=x + if y>ymax: ymax=y + + if x 0.1: + mat_pos= RotationMatrix( rot_angle, 2) + mat_neg= RotationMatrix( -rot_angle, 2) + + new_points_pos= [v*mat_pos for v in current_points] + area_pos, cent_pos, bounds_pos= pointBounds(new_points_pos) + + # 45d rotations only need to be tested in 1 direction. + if rot_angle == 45: + area_neg= area_pos + else: + new_points_neg= [v*mat_neg for v in current_points] + area_neg, cent_neg, bounds_neg= pointBounds(new_points_neg) + + + # Works! + #print 'Testing angle', rot_angle, current_area, area_pos, area_neg + + best_area= min(area_pos, area_neg, current_area) + if area_pos == best_area: + current_area= area_pos + cent= cent_pos + bounds= bounds_pos + current_points= new_points_pos + total_rot_angle+= rot_angle + elif rot_angle != 45 and area_neg == best_area: + current_area= area_neg + cent= cent_neg + bounds= bounds_neg + current_points= new_points_neg + total_rot_angle-= rot_angle + + rot_angle *= 0.5 + + # Return the optimal rotation. + return total_rot_angle + + +class faceGroup(object): + ''' + A Group of faces that all use the same image, each group has its UVs packed into a square. + ''' + __slots__= 'xmax', 'ymax', 'xmin', 'ymin',\ + 'image', 'faces', 'box_pack', 'size', 'ang', 'rot_mat', 'cent'\ + + def __init__(self, mesh_list, image, size, PREF_IMAGE_MARGIN): + self.image= image + self.size= size + self.faces= [f for me in mesh_list for f in me.faces if f.mode & TEXMODE and f.image == image] + + # Find the best rotation. + all_points= [uv for f in self.faces for uv in f.uv] + bountry_indicies= BPyMathutils.convexHull(all_points) + bountry_points= [all_points[i] for i in bountry_indicies] + + # Pre Rotation bounds + self.cent= pointBounds(bountry_points)[1] + + # Get the optimal rotation angle + self.ang= bestBoundsRotation(bountry_points) + self.rot_mat= RotationMatrix(self.ang, 2), RotationMatrix(-self.ang, 2) + + # Post rotation bounds + bounds= pointBounds([\ + ((uv-self.cent) * self.rot_mat[0]) + self.cent\ + for uv in bountry_points])[2] + + # Break the bounds into useable values. + xmin, ymin, xmax, ymax= bounds + + # Store the bounds, include the margin. + # The bounds rect will need to be rotated to the rotation angle. + self.xmax= xmax + (PREF_IMAGE_MARGIN/size[0]) + self.xmin= xmin - (PREF_IMAGE_MARGIN/size[0]) + self.ymax= ymax + (PREF_IMAGE_MARGIN/size[1]) + self.ymin= ymin - (PREF_IMAGE_MARGIN/size[1]) + + self.box_pack=[\ + 0.0, 0.0,\ + size[0]*(self.xmax - self.xmin),\ + size[1]*(self.ymax - self.ymin),\ + image.name] + + ''' + # default. + self.scale= 1.0 + + def set_worldspace_scale(self): + scale_uv= 0.0 + scale_3d= 0.0 + for f in self.faces: + for i in xrange(len(f.v)): + scale_uv+= (f.uv[i]-f.uv[i-1]).length * 0.1 + scale_3d+= (f.v[i].co-f.v[i-1].co).length * 0.1 + self.scale= scale_3d/scale_uv + ''' + + + + def move2packed(self, width, height): + ''' + Moves the UV coords to their packed location + using self.box_pack as the offset, scaler. + box_pack must be set to its packed location. + width and weight are the w/h of the overall packed area's bounds. + ''' + # packedLs is a list of [(anyUniqueID, left, bottom, width, height)...] + # Width and height in float pixel space. + + # X Is flipped :/ + #offset_x= (1-(self.box_pack[1]/d)) - (((self.xmax-self.xmin) * self.image.size[0])/d) + offset_x= self.box_pack[0]/width + offset_y= self.box_pack[1]/height + + for f in self.faces: + for uv in f.uv: + uv_rot= ((uv-self.cent) * self.rot_mat[0]) + self.cent + uv.x= offset_x+ (((uv_rot.x-self.xmin) * self.size[0])/width) + uv.y= offset_y+ (((uv_rot.y-self.ymin) * self.size[1])/height) + +def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN): #, PREF_SIZE_FROM_UV=True): + ''' + Main packing function + + All meshes from mesh_list must have faceUV else this function will fail. + ''' + face_groups= {} + + for me in mesh_list: + for f in me.faces: + if f.mode & TEXMODE: + image= f.image + if image: + try: + face_groups[image.name] # will fail if teh groups not added. + except: + try: + size= image.size + except: + B.Draw.PupMenu('Aborting: Image cold not be loaded|' + image.name) + return + + face_groups[image.name]= faceGroup(mesh_list, image, size, PREF_IMAGE_MARGIN) + + if not face_groups: + B.Draw.PupMenu('No Images found in mesh(es). Aborting!') + return + + if len(face_groups)<2: + B.Draw.PupMenu('Only 1 image found|Select a mesh(es) using 2 or more images.') + return + + ''' + if PREF_SIZE_FROM_UV: + for fg in face_groups.itervalues(): + fg.set_worldspace_scale() + ''' + + # RENDER THE FACES. + render_scn= B.Scene.New() + render_scn.makeCurrent() + render_context= render_scn.getRenderingContext() + render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path. + + PREF_IMAGE_PATH_EXPAND= B.sys.expandpath(PREF_IMAGE_PATH) + '.png' + + # TEST THE FILE WRITING. + try: + # Can we write to this file??? + f= open(PREF_IMAGE_PATH_EXPAND, 'w') + f.close() + except: + B.Draw.PupMenu('Error%t|Could not write to path|' + PREF_IMAGE_PATH_EXPAND) + return + + render_context.imageSizeX(PREF_IMAGE_SIZE) + render_context.imageSizeY(PREF_IMAGE_SIZE) + render_context.enableOversampling(True) + render_context.setOversamplingLevel(16) + render_context.setRenderWinSize(100) + render_context.setImageType(Render.PNG) + render_context.enableExtensions(True) + render_context.enableSky() # No alpha needed. + render_context.enableRGBColor() + render_context.threads = 2 + + #Render.EnableDispView() # Broken?? + + # New Mesh and Object + render_mat= B.Material.New() + render_mat.mode |= B.Material.Modes.SHADELESS + render_mat.mode |= B.Material.Modes.TEXFACE + + + render_me= B.Mesh.New() + render_me.verts.extend([Vector(0,0,0)]) # Stupid, dummy vert, preverts errors. when assigning UV's/ + render_ob= B.Object.New('Mesh') + render_ob.link(render_me) + render_scn.link(render_ob) + render_me.materials= [render_mat] + + + # New camera and object + render_cam_data= B.Camera.New('ortho') + render_cam_ob= B.Object.New('Camera') + render_cam_ob.link(render_cam_data) + render_scn.link(render_cam_ob) + render_scn.objects.camera = render_cam_ob + + render_cam_data.type= 'ortho' + render_cam_data.scale= 1.0 + + + # Position the camera + render_cam_ob.LocZ= 1.0 + render_cam_ob.LocX= 0.5 + render_cam_ob.LocY= 0.5 + + # List to send to to boxpack function. + boxes2Pack= [ fg.box_pack for fg in face_groups.itervalues()] + packWidth, packHeight = B.Geometry.BoxPack2D(boxes2Pack) + + if PREF_KEEP_ASPECT: + packWidth= packHeight= max(packWidth, packHeight) + + + # packedLs is a list of [(anyUniqueID, left, bottom, width, height)...] + # Re assign the face groups boxes to the face_group. + for box in boxes2Pack: + face_groups[ box[4] ].box_pack= box # box[4] is the ID (image name) + + + # Add geometry to the mesh + for fg in face_groups.itervalues(): + # Add verts clockwise from the bottom left. + _x= fg.box_pack[0] / packWidth + _y= fg.box_pack[1] / packHeight + _w= fg.box_pack[2] / packWidth + _h= fg.box_pack[3] / packHeight + + render_me.verts.extend([\ + Vector(_x, _y, 0),\ + Vector(_x, _y +_h, 0),\ + Vector(_x + _w, _y +_h, 0),\ + Vector(_x + _w, _y, 0),\ + ]) + + render_me.faces.extend([\ + render_me.verts[-1],\ + render_me.verts[-2],\ + render_me.verts[-3],\ + render_me.verts[-4],\ + ]) + + target_face= render_me.faces[-1] + target_face.image= fg.image + target_face.mode |= TEXMODE + + # Set the UV's, we need to flip them HOZ? + target_face.uv[0].x= target_face.uv[1].x= fg.xmax + target_face.uv[2].x= target_face.uv[3].x= fg.xmin + + target_face.uv[0].y= target_face.uv[3].y= fg.ymin + target_face.uv[1].y= target_face.uv[2].y= fg.ymax + + for uv in target_face.uv: + uv_rot= ((uv-fg.cent) * fg.rot_mat[1]) + fg.cent + uv.x= uv_rot.x + uv.y= uv_rot.y + + render_context.render() + Render.CloseRenderWindow() + render_context.saveRenderedImage(PREF_IMAGE_PATH_EXPAND) + + #if not B.sys.exists(PREF_IMAGE_PATH_EXPAND): + # raise 'Error!!!' + + + # NOW APPLY THE SAVED IMAGE TO THE FACES! + #print PREF_IMAGE_PATH_EXPAND + try: + target_image= B.Image.Load(PREF_IMAGE_PATH_EXPAND) + except: + B.Draw.PupMenu('Error: Could not render or load the image at path|' + PREF_IMAGE_PATH_EXPAND) + return + + # Set to the 1 image. + for me in mesh_list: + for f in me.faces: + if f.mode & TEXMODE and f.image: + f.image= target_image + + for fg in face_groups.itervalues(): + fg.move2packed(packWidth, packHeight) + + scn.makeCurrent() + render_me.verts= None # free a tiny amount of memory. + B.Scene.Unlink(render_scn) + target_image.makeCurrent() + + +def main(): + scn= B.Scene.GetCurrent() + scn_objects = scn.objects + ob= scn_objects.active + + if not ob or ob.type != 'Mesh': + B.Draw.PupMenu('Error, no active mesh object, aborting.') + return + + # Create the variables. + # Filename without path or extension. + newpath= B.Get('filename').split('/')[-1].split('\\')[-1].replace('.blend', '') + + PREF_IMAGE_PATH = B.Draw.Create('//%s_grp' % newpath) + PREF_IMAGE_SIZE = B.Draw.Create(1024) + PREF_IMAGE_MARGIN = B.Draw.Create(6) + PREF_KEEP_ASPECT = B.Draw.Create(0) + PREF_ALL_SEL_OBS = B.Draw.Create(0) + + pup_block = [\ + 'Image Path: (no ext)',\ + ('', PREF_IMAGE_PATH, 3, 100, 'Path to new Image. "//" for curent blend dir.'),\ + 'Image Options', + ('Pixel Size:', PREF_IMAGE_SIZE, 64, 4096, 'Image Width and Height.'),\ + ('Pixel Margin:', PREF_IMAGE_MARGIN, 0, 64, 'Use a margin to stop mipmapping artifacts.'),\ + ('Keep Aspect', PREF_KEEP_ASPECT, 'If disabled, will stretch the images to the bounds of the texture'),\ + 'Texture Source',\ + ('All Sel Objects', PREF_ALL_SEL_OBS, 'Combine all selected objects into 1 texture, otherwise active object only.'),\ + ] + + if not B.Draw.PupBlock('Consolidate images...', pup_block): + return + + PREF_IMAGE_PATH= PREF_IMAGE_PATH.val + PREF_IMAGE_SIZE= PREF_IMAGE_SIZE.val + PREF_IMAGE_MARGIN= PREF_IMAGE_MARGIN.val + PREF_KEEP_ASPECT= PREF_KEEP_ASPECT.val + PREF_ALL_SEL_OBS= PREF_ALL_SEL_OBS.val + + if PREF_ALL_SEL_OBS: + mesh_list= [ob.getData(mesh=1) for ob in scn_objects.context if ob.type=='Mesh'] + # Make sure we have no doubles- dict by name, then get the values back. + + for me in mesh_list: me.tag = False + + mesh_list_new = [] + for me in mesh_list: + if me.faceUV and me.tag==False: + me.tag = True + mesh_list_new.append(me) + + # replace list with possible doubles + mesh_list = mesh_list_new + + else: + mesh_list= [ob.getData(mesh=1)] + if not mesh_list[0].faceUV: + B.Draw.PupMenu('Error, active mesh has no images, Aborting!') + return + + consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN) + B.Window.RedrawAll() + +if __name__=='__main__': + main() diff --git a/release/scripts/image_billboard.py b/release/scripts/image_billboard.py new file mode 100644 index 00000000000..b1cd9d38891 --- /dev/null +++ b/release/scripts/image_billboard.py @@ -0,0 +1,280 @@ +#!BPY +""" +Name: 'Billboard Render on Active' +Blender: 242 +Group: 'Image' +Tooltip: 'Selected objects and lamps to rendered faces on the act mesh' +""" +__author__= "Campbell Barton" +__url__= ["blender", "blenderartist"] +__version__= "1.0" + +__bpydoc__= """\ +Render Billboard Script +This can texture a simple billboard mesh from any number of selected objects. + +Renders objects in the selection to quad faces on the active mesh. + +Usage +* Light your model or enable the shadless flag so it is visible +* Make a low poly mesh out of quads with 90d corners. (this will be you billboard mesh) +* Select the model and any lamps that light it +* Select the billboard mesh so that it is active +* Run this script, Adjust settings such as image size or oversampling. +* Select a place to save the PNG image. +* Once the script has finished running return to the 3d view by pressing Shift+F5 +* To see the newly applied textures change the drawtype to 'Textured Solid' +""" +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton 2006 +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender as B +import BPyMathutils +import bpy +import BPyRender +from Blender.Scene import Render + +import os +Vector= B.Mathutils.Vector + +def alpha_mat(image): + # returns a material useable for + mtl= bpy.data.materials.new() + mtl.mode |= (B.Material.Modes.SHADELESS | B.Material.Modes.ZTRANSP | B.Material.Modes.FULLOSA ) + mtl.alpha= 0.0 # so image sets the alpha + + tex= bpy.data.textures.new() + tex.type= B.Texture.Types.IMAGE + image.antialias = True + tex.setImageFlags('InterPol', 'UseAlpha') + tex.setExtend('Clip') + tex.image= image + + mtl.setTexture(0, tex, B.Texture.TexCo.UV, B.Texture.MapTo.COL | B.Texture.MapTo.ALPHA) + + return mtl + +# PupBlock Settings +GLOBALS= {} +PREF_RES= B.Draw.Create(512) +PREF_TILE_RES= B.Draw.Create(256) +PREF_AA = B.Draw.Create(1) +PREF_ALPHA= B.Draw.Create(1) +PREF_Z_OFFSET = B.Draw.Create(10.0) +PREF_IMG_PACK= B.Draw.Create(1) + + +def save_billboard(PREF_IMAGE_PATH): + B.Window.WaitCursor(1) + # remove png, add it later + PREF_IMAGE_PATH= PREF_IMAGE_PATH.replace('.png', '') + + ob_sel= GLOBALS['ob_sel'] + me_ob = GLOBALS['me_ob'] + me_data = GLOBALS['me_data'] + + time= B.sys.time() + + me_mat= me_ob.matrixWorld + + # Render images for all faces + face_data= [] # Store faces, images etc + boxes2Pack= [] + me_data.faceUV= True + + for i, f in enumerate(me_data.faces): + no= f.no + # Offset the plane by the zoffset on the faces normal + plane= [v.co * me_mat for v in f] + + # Horizontal stacking, make sure 0,1 and 2,3 are the longest + if\ + (plane[0]-plane[1]).length + (plane[2]-plane[3]).length < \ + (plane[1]-plane[2]).length + (plane[3]-plane[0]).length: + plane.append(plane.pop(0)) + rot90= True + else: + rot90= False + + + #plane.reverse() + no= B.Mathutils.QuadNormal(*plane) + plane= [v + no*PREF_Z_OFFSET.val for v in plane] + + cent= (plane[0]+plane[1]+plane[2]+plane[3] ) /4.0 + camera_matrix= BPyMathutils.plane2mat(plane) + tmp_path= '%s_%d' % (PREF_IMAGE_PATH, i) + img= BPyRender.imageFromObjectsOrtho(ob_sel, tmp_path, PREF_TILE_RES.val, PREF_TILE_RES.val, PREF_AA.val, PREF_ALPHA.val, camera_matrix) + img.reload() + #img.pack() # se we can keep overwriting the path + #img.filename= "" + + + if not PREF_IMG_PACK.val: + f.mode |= B.Mesh.FaceModes.TEX + f.image = img + f.uv=Vector(0,1), Vector(0,0), Vector(1,0), Vector(1,1) + + if PREF_ALPHA.val: + f.transp |= B.Mesh.FaceTranspModes.ALPHA + else: + w= ((plane[0]-plane[1]).length + (plane[2]-plane[3]).length)/2 + h= ((plane[1]-plane[2]).length + (plane[3]-plane[0]).length)/2 + + face_data.append( (f, img, rot90) ) + boxes2Pack.append( [0.0,0.0,h, w, i] ) + + if PREF_IMG_PACK.val: + # pack the quads into a square + packWidth, packHeight = B.Geometry.BoxPack2D(boxes2Pack) + + render_obs= [] + + # Add geometry to the mesh + for box in boxes2Pack: + i= box[4] + + orig_f, img, rot90= face_data[i] + + # New Mesh and Object + render_mat= alpha_mat(img) + + render_me= bpy.data.meshes.new() + + render_ob= B.Object.New('Mesh') + render_me.materials= [render_mat] + render_ob.link(render_me) + + render_obs.append(render_ob) + + # Add verts clockwise from the bottom left. + _x= box[0] / packWidth + _y= box[1] / packHeight + _w= box[2] / packWidth + _h= box[3] / packHeight + + + render_me.verts.extend([\ + Vector(_x, _y, 0),\ + Vector(_x, _y +_h, 0),\ + Vector(_x + _w, _y +_h, 0),\ + Vector(_x + _w, _y, 0),\ + ]) + + render_me.faces.extend(list(render_me.verts)) + render_me.faceUV= True + + # target_face= render_me.faces[-1] + # TEXFACE isnt used because of the renderign engine cant to alpha's for texdface. + #target_face.image= img + #target_face.mode |= B.Mesh.FaceModes.TEX + + # Set the UV's, we need to flip them HOZ? + uv1, uv2, uv3, uv4= orig_f.uv + uv3.x= uv4.x= _x+_w + uv1.x= uv2.x= _x + + uv2.y= uv3.y= _y+_h + uv1.y= uv4.y= _y + + if rot90: + orig_f.uv= Vector(uv4), Vector(uv1), Vector(uv2), Vector(uv3) + + target_image= BPyRender.imageFromObjectsOrtho(render_obs, PREF_IMAGE_PATH, PREF_RES.val, PREF_RES.val, PREF_AA.val, PREF_ALPHA.val, None) + + # Set to the 1 image. + for f in me_data.faces: + f.image= target_image + if PREF_ALPHA.val: + f.transp |= B.Mesh.FaceTranspModes.ALPHA + + # Free the images data and remove + for data in face_data: + img= data[1] + os.remove(img.filename) + img.reload() + # Finish pack + + me_data.update() + me_ob.makeDisplayList() + B.Window.WaitCursor(0) + print '%.2f secs taken' % (B.sys.time()-time) + + + + +def main(): + scn= bpy.data.scenes.active + ob_sel= list(scn.objects.context) + + PREF_KEEP_ASPECT= False + + # Error Checking + if len(ob_sel) < 2: + B.Draw.PupMenu("Error%t|Select 2 mesh objects") + return + + me_ob= scn.objects.active + + if not me_ob: + B.Draw.PupMenu("Error%t|No active mesh selected.") + + try: + ob_sel.remove(me_ob) + except: + pass + + if me_ob.type != 'Mesh': + B.Draw.PupMenu("Error%t|Active Object must be a mesh to write billboard images too") + return + + me_data= me_ob.getData(mesh=1) + + for f in me_data.faces: + if len(f) != 4: + B.Draw.PupMenu("Error%t|Active mesh must have only quads") + return + + + # Get user input + block = [\ + 'Image Pixel Size',\ + ("Packed Size: ", PREF_RES, 128, 2048, "Pixel width and height to render the billboard to"),\ + ("Tile Size: ", PREF_TILE_RES, 64, 1024, "Pixel width and height for each tile to render to"),\ + 'Render Settings',\ + ("Pack Final", PREF_IMG_PACK , "Pack all images into 1 image"),\ + ("Oversampling", PREF_AA , "Higher quality woth extra sampling"),\ + ("Alpha Clipping", PREF_ALPHA , "Render empty areas as transparent"),\ + ("Cam ZOffset: ", PREF_Z_OFFSET, 0.1, 100, "Distance to place the camera away from the quad when rendering")\ + ] + + if not B.Draw.PupBlock("Billboard Render", block): + return + + # Set globals + GLOBALS['ob_sel'] = ob_sel + GLOBALS['me_ob'] = me_ob + GLOBALS['me_data'] = me_data + + B.Window.FileSelector(save_billboard, 'SAVE BILLBOARD', B.sys.makename(ext='.png')) + +if __name__=='__main__': + main() diff --git a/release/scripts/image_edit.py b/release/scripts/image_edit.py new file mode 100644 index 00000000000..14ab57515ba --- /dev/null +++ b/release/scripts/image_edit.py @@ -0,0 +1,136 @@ +#!BPY +""" +Name: 'Edit Externaly' +Blender: 242a +Group: 'Image' +Tooltip: 'Open in an application for editing. (hold Shift to configure)' +""" + +__author__ = "Campbell Barton" +__url__ = ["blender", "elysiun"] +__version__ = "1.0" + +__bpydoc__ = """\ +This script opens the current image in an external application for editing. + +Useage: +Choose an image for editing in the UV/Image view. + +To configure the application to open the image with, hold Shift as you click on +this menu item. + +For first time users try running the default application for your operating system. +If the application does not open you can type in the full path. +You can choose that the last entered application will be saved as a default. + +* Note, default commants for opening an image are "start" for win32 and "open" for macos. +This will use the system default assosiated application. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton 2006 +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +try: + import os + import sys as py_sys + platform = py_sys.platform +except: + Draw.PupMenu('Error, python not installed') + os=None + +import Blender +from Blender import Image, sys, Draw, Registry + +def edit_extern(image=None): + + if not image: + image = Image.GetCurrent() + + if not image: # Image is None + Draw.PupMenu('ERROR: You must select an active Image.') + return + if image.packed: + Draw.PupMenu('ERROR: Image is packed, unpack before editing.') + return + + imageFileName = sys.expandpath( image.filename ) + + if not sys.exists(imageFileName): + Draw.PupMenu('ERROR: Image path does not exist.') + return + + pupblock = [imageFileName.split('/')[-1].split('\\')[-1]] + + new_text= False + try: + appstring = Registry.GetKey('ExternalImageEditor', True) + appstring = appstring['path'] + + # for ZanQdo if he removed the path from the textbox totaly. ;) - Cam + if not appstring or appstring.find('%f')==-1: + new_text= True + except: + new_text= True + + if new_text: + pupblock.append('first time, set path.') + if platform == 'win32': + appstring = 'start "" /B "%f"' + elif platform == 'darwin': + appstring = 'open "%f"' + else: + appstring = 'gimp-remote "%f"' + + appstring_but = Draw.Create(appstring) + save_default_but = Draw.Create(0) + + pupblock.append(('editor: ', appstring_but, 0, 48, 'Path to application, %f will be replaced with the image path.')) + pupblock.append(('Set Default', save_default_but, 'Store this path in the blender registry.')) + + # Only configure if Shift is held, + if Blender.Window.GetKeyQualifiers() & Blender.Window.Qual.SHIFT: + if not Draw.PupBlock('External Image Editor...', pupblock): + return + + appstring = appstring_but.val + save_default= save_default_but.val + + if save_default: + Registry.SetKey('ExternalImageEditor', {'path':appstring}, True) + + if appstring.find('%f') == -1: + Draw.PupMenu('ERROR: The comment you entered did not contain the filename ("%f")') + return + + # ------------------------------- + + appstring = appstring.replace('%f', imageFileName) + print '\tediting image with command "%s"' % appstring + os.system(appstring) + + +def main(): + edit_extern() + + +if __name__ == '__main__' and os != None: + main() \ No newline at end of file diff --git a/release/scripts/image_find_paths.py b/release/scripts/image_find_paths.py new file mode 100644 index 00000000000..266ecee9435 --- /dev/null +++ b/release/scripts/image_find_paths.py @@ -0,0 +1,167 @@ +#!BPY + +""" +Name: 'Fix Broken Paths' +Blender: 242 +Group: 'Image' +Tooltip: 'Search for new image paths to make relative links to' +""" + +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["blenderartist.org"] + +__bpydoc__ = """\ +Find image target paths + +This script searches for images whos +file paths do not point to an existing image file, +all image paths are made relative where possible. +usefull when moving projects between computers, when absolute paths links are broken. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +from Blender import * + +try: + import os +except: + Draw.PupMenu('You need a full python install to use this script') + os= None + + +#==============================================# +# Strips the slashes from the back of a string # +#==============================================# +def stripPath(path): + return path.split('/')[-1].split('\\')[-1] + +# finds the file starting at the root. +def findImage(findRoot, imagePath): + newImageFile = None + + imageFile = imagePath.split('/')[-1].split('\\')[-1] + + # ROOT, DIRS, FILES + pathWalk = os.walk(findRoot) + pathList = [True] + + matchList = [] # Store a list of (match, size), choose the biggest. + while True: + try: + pathList = pathWalk.next() + except: + break + + for file in pathList[2]: + # FOUND A MATCH + if file.lower() == imageFile.lower(): + name = pathList[0] + sys.sep + file + try: + size = os.path.getsize(name) + except: + size = 0 + + if size: + print ' found:', name + matchList.append( (name, size) ) + + if matchList == []: + print 'no match for:', imageFile + return None + else: + # Sort by file size + matchList.sort(lambda A, B: cmp(B[1], A[1]) ) + + print 'using:', matchList[0][0] + # First item is the largest + return matchList[0][0] # 0 - first, 0 - pathname + + +# Makes the pathe relative to the blend file path. +def makeRelative(path, blendBasePath): + if path.startswith(blendBasePath): + path = path.replace(blendBasePath, '//') + path = path.replace('//\\', '//') + return path + +def find_images(findRoot): + print findRoot + + # findRoot = Draw.PupStrInput ('find in: ', '', 100) + + if findRoot == '': + Draw.PupMenu('No Directory Selected') + return + + # Account for // + findRoot = sys.expandpath(findRoot) + + # Strip filename + while findRoot[-1] != '/' and findRoot[-1] != '\\': + findRoot = findRoot[:-1] + + + if not findRoot.endswith(sys.sep): + findRoot += sys.sep + + + if findRoot != '/' and not sys.exists(findRoot[:-1]): + Draw.PupMenu('Directory Dosent Exist') + + blendBasePath = sys.expandpath('//') + + + Window.WaitCursor(1) + # ============ DIR DONE\ + images = Image.Get() + len_images = float(len(images)) + for idx, i in enumerate(images): + + progress = idx / len_images + Window.DrawProgressBar(progress, 'searching for images') + + # If files not there? + if not sys.exists(sys.expandpath(i.filename )): + newImageFile = findImage(findRoot, i.filename) + if newImageFile != None: + newImageFile= makeRelative(newImageFile, blendBasePath) + print 'newpath relink:', newImageFile + i.filename = newImageFile + i.reload() + else: + # Exists + newImageFile= makeRelative(i.filename, blendBasePath) + if newImageFile!=i.filename: + print 'newpath relative:', newImageFile + i.filename = newImageFile + + + Window.RedrawAll() + Window.DrawProgressBar(1.0, '') + Window.WaitCursor(0) + +if __name__ == '__main__' and os: + Window.FileSelector(find_images, 'SEARCH ROOT DIR', sys.expandpath('//')) + + diff --git a/release/scripts/import_dxf.py b/release/scripts/import_dxf.py new file mode 100644 index 00000000000..3f2fef72aa2 --- /dev/null +++ b/release/scripts/import_dxf.py @@ -0,0 +1,4139 @@ +#!BPY + +""" +Name: 'Autodesk DXF (.dxf)' +Blender: 244 +Group: 'Import' +Tooltip: 'Import for DXF geometry data (Drawing eXchange Format).' +""" +__author__ = 'Kitsu(Ed Blake) & migius(Remigiusz Fiedler)' +__version__ = '1.0.beta10 - 2007.09.09 by migius' +__url__ = ["http://blenderartists.org/forum/showthread.php?t=84319", + "http://wiki.blender.org/index.php/Scripts/Manual/Import/DXF-3D"] +__email__ = ["Kitsune_e(at)yahoo.com", "migius(at)4d-vectors.de"] +__bpydoc__ = """\ +This script imports DXF objects (2d/3d) into Blender. + +This script imports 2d and 3d Geometery from DXFr12 format files. +This version is focused on import of 3d-objects. + +Supported DXF Objects: +LINE +POINT +SOLID +TRACE +TEXT +INSERT (=block) +MINSERT (=array) +CIRCLE +ARC +3DFACE +2d-POLYLINE (=plane, incl. arc, variable-width, curve, spline) +3d-POLYLINE (=no-plane) +3d-POLYMESH +3d-POLYFACE +under construction, partly supported DXF>r12: +LWPOLYLINE (LightWeight), MLINE, MTEXT, ELLIPSE + +Unsupported DXF Objects: +DXF r12: DIMENSION, XREF (External Reference) +DXF>r12: SPLINE, GROUP, RAY/XLINE, LEADER, 3DSOLID, BODY, REGION, dynamic BLOCK + +Supported Properties: +Hierarchy: Entire DXF BLOCKs hierarchy is preserved after import into Blender +visibility, frozen +COLOR +LAYER +thickness +width +(todo: grouped, XDATA) +It is recommended to use DXF-object properties for coding Blender materials. + +Notes: +- Recommend that you run 'RemoveDoubles' on each imported mesh after using this script +- Blocks are created on layer 19 then referenced at each insert point. +* Big DXF-files (over 1500 objects) decrease import performance. The problem is not the inefficiency of python-scripting but Blenders performance in creating new objects in his database - probably a database management problem. +* The Blender curves of imported ARCs and POLYLINE-arc-segments have light malformed ends.(to fix in beta10) + +TODO: +- the new style object visibility +- support for Spline-curves, Besier-curves +- support for real 3d-solids (ACIS) +- (to see more, search for "-todo-" in script) + + +History: + v1.0 - 2007.09 by migius: "full 3d"-release + planned tasks: + -- filtering of unused/not-inserted BLOCKs + -- human-formating of data in INI-File + -- suport for MLine + -- suport for Ellipse + -- suport for Mtext + -- blender_object.ID.properties[dxf_layer_name] + -- Configuration files(.ini) should/can handle various material setups + -- added f_layerFilter + -- to-check: obj/mat/group/_mapping-idea from ideasman42: + -- better support for long dxf-layer-names + -- support width_force for LINEs/ARCs/CIRCLEs/ELLIPSEs = "solidify" + -- curves: added fill/non-fill option for closed curves: CIRCLEs,ELLIPSEs,POLYLINEs + -- bug:? object = Object.Get(obname) -> = SCENE.getChildren(obname) + -- command-line-mode/batch-mode + -- fixed malformed endpoints of Blender curves of imported ARCs and POLYLINE-arc segments. + beta10: 2007.09.09 by migius + a1 added "fill_on" option to draw top and bottom sides of CIRCLEs and ELLIPSEs + a1 rewrite f_CIRCLE.Draw: from Mesh.Primitive to Mesh + a1 bugfix "newScene"-mode: Cylinders/Arcs were drawn at <0,0,0>location + beta09: 2007.09.02 by migius + g5 redesign UI: grouping of buttons + g3 update multi-import-mode: <*.*> button + g- added multi-import-mode: (path/*) for importing many dxf-files at once + g- added import into newScene + g- redesign UI: user presets, into newScene-import + f- cleanup code + f- bugfix: thickness for Bezier/Bsplines into Blender-curves + f- BlenderWiki documentation, on-line Manual + f- added import POLYLINE-Bsplines into Blender-NURBSCurves + f- added import POLYLINE-arc-segments into Blender-BezierCurves + f- added import POLYLINE-Bezier-curves into Blender-Curves + d5 rewrite: Optimization Levels, added 'directDrawing' + d4 added: f_set_thick(cntrolled by ini-parameters) + d4 bugfix: face-normals in objects with minus thickness + d4 added: placeholder'Empty'-size in f_Insert.draw + d3 rewrite f_Text.Draw: added suport for all Text's parameters + d2 redesign: progressbar + e- tuning by ideasman42: better use of the Py API. + c- tuning by ideasman42 + b- rewrite f_Text.Draw rotation/transform + b- bugfix: POLYLINE-segment-intersection more reliable now + b- bugfix: circle:_thic, 'Empties':no material_assignement + b- added material assignment (from layer and/or color) + a- added empty, cylinder and UVsphere for POINTs + a- added support for 2d-POLYLINE: splines, fitted curves, fitted surfaces + a- redesign f_Drawer for block_definitions + a- rewrite import into Blender-Curve-Object + beta08: 2007.07.27 by migius + l- bugfix: solid_vgroups, clean:scene.objects.new() + l- redesign UI to standard Draw.Register+FileSelector, advanced_config_option + k- bugfix UI:fileSelect() for MacOSX os.listdir() + k- added reset/save/load for config-data + k- redesign keywords/drawTypes/Draw.Create_Buttons + j- new interface using UIBlock() with own FileSelector, cause Window.FileSelector() too buggy + i- rewritten Class:Settings for better config-parameter management + h- bugfix: face-normals in objects with minus thickness + h- added Vertex-Groups in polylines and solids generated Meshes, for easier material assignment + h- beautify code, whitespace->tabs + h- added settings.thic_force switch for forcing thickness + h- added one Object/Mesh for all simple-entities from the same Layer, + sorted in Vertex-Groups(color_name) (fewer objects = better import performance) + g- rewrote: insert-point-handle-object is a small tetrahedron + e- bugfix: closed-polymesh3d + - rewrote: startUI, type_map.keys, f_drawer, for all class_f_draw(added "settings" as attribut) + - added 2d/3d-support for Polyline_Width incl. angleintersection + beta07: 2007.06.19 by migius + - added 3d-support for LWPolylines + - added 2d/3d-support for Points + beta06: 2007.06.15 by migius + - cleanup code + - added 2d/3d-support for MINSERT=BlockArray in f_drawer, added f_rotXY_Vec + beta05: 2007.06.14 by migius + - added 2d/3d-support for 3d-PolyLine, PolyMesh and PolyFace + - added Global-Scale for size control of imported scenes + beta04: 2007.06.12 by migius + - rewrote the f_drawBulge for correct import the arc-segments of Polylines + beta03: 2007.06.10 by migius + - rewrote interface + beta02: 2007.06.09 by migius + - added 3d-support for Arcs and Circles + - added support for Object_Thickness(=height) + beta01: 2007.06.08 by migius + - added 3d-support for Blocks/Inserts within nested-structures + - rewrote f_transform for correct 3d-location/3d-rotation + - added 3d-support Lines, 3dFaces + - added 2d+3d-support for Solids and Traces + + v0.9 - 2007.01 by kitsu: (for 2.43) + - + + v0.8 - 2006.12 by kitsu: + - + + v0.5b - 2006.10 by kitsu: (for 2.42a) + - + +""" + +# -------------------------------------------------------------------------- +# DXF Import v1.0 by Ed Blake (AKA kitsu) and Remigiusz Fiedler (AKA migius) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +import bpy +from Blender import * +#from Blender.Mathutils import Vector, Matrix +#import BPyMessages + + +from dxfReader import readDXF # get_name, get_layer +from dxfReader import Object as dxfObject +from dxfColorMap import color_map +from math import * + +try: + import os + if os.name:# != 'mac': + import psyco + psyco.log() + psyco.full(memory=100) + psyco.profile(0.05, memory=100) + psyco.profile(0.2) +except ImportError: + pass + +print '\n\n\n\n' +print 'Import DXF to Blender *** START ***' #--------------------- + +SCENE = None +WORLDX = Mathutils.Vector((1,0,0)) +WORLDY = Mathutils.Vector((1,1,0)) +WORLDZ = Mathutils.Vector((0,0,1)) + +G_SCALE = 1.0 #(0.0001-1000) global scaling factor for all dxf data +MIN_DIST = 0.001 #cut-off value for sort out short-distance polyline-"duoble_vertex" +ARC_RESOLUTION = 64 #(4-500) arc/circle resolution - number of segments +ARC_RADIUS = 1.0 #(0.01-100) arc/circle radius for number of segments algorithm +THIN_RESOLUTION = 8 #(4-500) thin_cylinder arc_resolution - number of segments +MIN_THICK = MIN_DIST * 10.0 #minimal thickness by forced thickness +MIN_WIDTH = MIN_DIST * 10.0 #minimal width by forced width +ANGLECUT_LIMIT = 3.0 #limit for anglecut of polylines-wide-segments (values:1.0 - 5.0) +TARGET_LAYER = 3 #target blender_layer +GROUP_BYLAYER = 0 #(0/1) all entities from same layer import into one blender-group + +FILENAME_MAX = 180 #max length of path+file_name string (FILE_MAXDIR + FILE_MAXFILE) +MAX_NAMELENGTH = 17 #max_effective_obnamelength in blender =21=17+(.001) +INIFILE_DEFAULT_NAME = 'importDXF' +INIFILE_EXTENSION = '.ini' +INIFILE_HEADER = 'ImportDXF.py ver.1.0 config data' + +AUTO = BezTriple.HandleTypes.AUTO +FREE = BezTriple.HandleTypes.FREE +VECT = BezTriple.HandleTypes.VECT +ALIGN = BezTriple.HandleTypes.ALIGN +cur_COUNTER = 0 #counter for progress_bar + + +"""This module provides wrapper objects for dxf entities. + + The wrappers expect a "dxf object" as input. The dxf object is + an object with a type and a data attribute. Type is a lowercase + string matching the 0 code of a dxf entity. Data is a list containing + dxf objects or lists of [code, data] pairs. + + This module is not general, and is only for dxf import. +""" + +# from Stani's dxf writer v1.1 (c)www.stani.be (GPL) +#---color values +BYBLOCK=0 +BYLAYER=256 + +#---block-type flags (bit coded values, may be combined): +ANONYMOUS =1 # This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application +NON_CONSTANT_ATTRIBUTES =2 # This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) +XREF =4 # This block is an external reference (xref) +XREF_OVERLAY =8 # This block is an xref overlay +EXTERNAL =16 # This block is externally dependent +RESOLVED =32 # This is a resolved external reference, or dependent of an external reference (ignored on input) +REFERENCED =64 # This definition is a referenced external reference (ignored on input) + +#---polyline flags +CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) +CURVE_FIT =2 # Curve-fit vertices have been added +SPLINE_FIT =4 # Spline-fit vertices have been added +POLYLINE_3D =8 # This is a 3D polyline +POLYGON_MESH =16 # This is a 3D polygon mesh +CLOSED_N =32 # The polygon mesh is closed in the N direction +POLYFACE_MESH =64 # The polyline is a polyface mesh +CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline + +#---text flags +#horizontal +LEFT = 0 +CENTER = 1 +RIGHT = 2 +ALIGNED = 3 #if vertical alignment = 0 +MIDDLE = 4 #if vertical alignment = 0 +FIT = 5 #if vertical alignment = 0 +#vertical +BASELINE = 0 +BOTTOM = 1 +MIDDLE = 2 +TOP = 3 + +#---mtext flags +#attachment point +TOP_LEFT = 1 +TOP_CENTER = 2 +TOP_RIGHT = 3 +MIDDLE_LEFT = 4 +MIDDLE_CENTER = 5 +MIDDLE_RIGHT = 6 +BOTTOM_LEFT = 7 +BOTTOM_CENTER = 8 +BOTTOM_RIGHT = 9 +#drawing direction +LEFT_RIGHT = 1 +TOP_BOTTOM = 3 +BY_STYLE = 5 #the flow direction is inherited from the associated text style +#line spacing style (optional): +AT_LEAST = 1 #taller characters will override +EXACT = 2 #taller characters will not override + + + +class Layer: #----------------------------------------------------------------- + """Class for objects representing dxf layers. + """ + def __init__(self, obj, name=None, color=None, frozen=None): + """Expects an object of type layer as input. + """ + self.type = obj.type + self.data = obj.data[:] + + if name: + self.name = name + #self.bfname = name #remi--todo----------- + else: + self.name = obj.get_type(2)[0] #layer name of object + + if color: + self.color = color + else: + self.color = obj.get_type(62)[0] #color of object + + if frozen: + self.frozen = frozen + else: + self.flags = obj.get_type(70)[0] + self.frozen = self.flags&1 + + + def __repr__(self): + return "%s: name - %s, color - %s" %(self.__class__.__name__, self.name, self.color) + + + +def getit(obj, typ, default=None): #------------------------------------------ + """Universal procedure for geting data from list/objects. + """ + it = default + if type(obj) == list: #if obj is a list, then searching in a list + for item in obj: + #print 'deb:getit item, type(item)', item, type(item) + try: + if item[0] == typ: + it = item[1] + break #as soon as the first found + except: + # TODO - I found one case where item was a text instance + # that failed with no __getitem__ + pass + else: #else searching in Object with get_type-Methode + item = obj.get_type(typ) + if item: + it = item[0] + #print 'deb:getit:typ, it', typ, it #---------- + return it + + + +def get_extrusion(data): #------------------------------------------------- + """Find the axis of extrusion. + + Used to get from object_data the objects Object Coordinate System (ocs). + """ + #print 'deb:get_extrusion: data: \n', data #--------------- + vec = [0,0,1] + vec[0] = getit(data, 210, 0) # 210 = x + vec[1] = getit(data, 220, 0) # 220 = y + vec[2] = getit(data, 230, 1) # 230 = z + #print 'deb:get_extrusion: vec: ', vec #--------------- + return vec + + + + + +class Solid: #----------------------------------------------------------------- + """Class for objects representing dxf solid or trace. + """ + def __init__(self, obj): + """Expects an entity object of type solid or trace as input. + """ + if obj.type == 'trace': + obj.type = 'solid' + if not obj.type == 'solid': + raise TypeError, "Wrong type \'%s\' for solid/trace object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.extrusion = get_extrusion(obj.data) + self.points = self.get_points(obj.data) + + + + def get_points(self, data): + """Gets start and end points for a solid type object. + + Solids have 3 or 4 points and fixed codes for each value. + """ + + # start x, y, z and end x, y, z = 0 + a = [0, 0, 0] + b = [0, 0, 0] + c = [0, 0, 0] + d = [0, 0, 0] + a[0] = getit(data, 10, None) # 10 = x + a[1] = getit(data, 20, None) # 20 = y + a[2] = getit(data, 30, 0) # 30 = z + b[0] = getit(data, 11, None) + b[1] = getit(data, 21, None) + b[2] = getit(data, 31, 0) + c[0] = getit(data, 12, None) + c[1] = getit(data, 22, None) + c[2] = getit(data, 32, 0) + out = [a,b,c] + + d[0] = getit(data, 13, None) + if d[0] != None: + d[1] = getit(data, 23, None) + d[2] = getit(data, 33, 0) + out.append(d) + #print 'deb:solid.vertices:---------\n', out #----------------------- + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for SOLID: generate Blender_geometry. + """ + points = self.points + if not points: return + edges, faces = [], [] + l = len(self.points) + + obname = 'so_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + + vg_left, vg_right, vg_top, vg_bottom, vg_start, vg_end = [], [], [], [], [], [] + thic = set_thick(self.thic, settings) + if thic != 0: + thic_points = [[v[0], v[1], v[2] + thic] for v in points[:]] + if thic < 0.0: + thic_points.extend(points) + points = thic_points + else: + points.extend(thic_points) + + if l == 4: + faces = [[0,1,3,2], [4,6,7,5], [0,4,5,1], + [1,5,7,3], [3,7,6,2], [2,6,4,0]] + vg_left = [2,6,4,0] + vg_right = [1,5,7,3] + vg_top = [4,6,7,5] + vg_bottom = [0,1,3,2] + vg_start = [0,4,5,1] + vg_end = [3,7,6,2] + elif l == 3: + faces = [[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]] + vg_top = [3,4,5] + vg_bottom = [0,1,2] + vg_left = [2,5,3,0] + vg_right = [1,4,5,2] + vg_start = [0,3,4,1] + elif l == 2: faces = [[0,1,3,2]] + else: + if l == 4: faces = [[0,1,3,2]] + elif l == 3: faces = [[0,1,2]] + elif l == 2: edges = [[0,1]] + + + + me = Mesh.New(obname) # create a new mesh + me.verts.extend(points) # add vertices to mesh + if faces: me.faces.extend(faces) # add faces to the mesh + if edges: me.edges.extend(edges) # add faces to the mesh + + ob = SCENE.objects.new(me) # create a new mesh_object + if settings.var['vGroup_on']: + # each MeshSite becomes vertexGroup for easier material assignment --------------------- + replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.ADD/REPLACE + if vg_left: me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', vg_left, 1.0, replace) + if vg_right:me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', vg_right, 1.0, replace) + if vg_top: me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', vg_top, 1.0, replace) + if vg_bottom:me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',vg_bottom, 1.0, replace) + if vg_start:me.addVertGroup('side.start') ; me.assignVertsToGroup('side.start', vg_start, 1.0, replace) + if vg_end: me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', vg_end, 1.0, replace) + + transform(self.extrusion, 0, ob) + + return ob + + + + +class Line: #----------------------------------------------------------------- + """Class for objects representing dxf lines. + """ + def __init__(self, obj): + """Expects an entity object of type line as input. + """ + if not obj.type == 'line': + raise TypeError, "Wrong type \'%s\' for line object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + #print 'deb:self.thic: ', self.thic #--------------------- + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.extrusion = get_extrusion(obj.data) + self.points = self.get_points(obj.data) + + + def get_points(self, data): + """Gets start and end points for a line type object. + + Lines have a fixed number of points (two) and fixed codes for each value. + """ + # start x,y,z and end x,y,z = 0 + a = [0, 0, 0] + b = [0, 0, 0] + a[0] = getit(data, 10, None) # 10 = x + a[1] = getit(data, 20, None) # 20 = y + a[2] = getit(data, 30, 0) # 30 = z + b[0] = getit(data, 11, None) + b[1] = getit(data, 21, None) + b[2] = getit(data, 31, 0) + out = [a,b] + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for LINE: generate Blender_geometry. + """ + # Generate the geometery + #settings.var['curves_on']=False + + points = self.points + + global activObjectLayer + global activObjectName + #print 'deb:draw:line.ob IN activObjectName: ', activObjectName #--------------------- + + if activObjectLayer == self.layer and settings.var['one_mesh_on']: + obname = activObjectName + #print 'deb:line.draw obname from activObjectName: ', obname #--------------------- + ob = Object.Get(obname) # open an existing mesh_object + #ob = SCENE.getChildren(obname) # open an existing mesh_object + me = Mesh.Get(ob.name) # open objects mesh data + else: + obname = 'li_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + activObjectName = ob.name + activObjectLayer = self.layer + #print ('deb:line.draw new line.ob+mesh:"%s" created!' %ob.name) #--------------------- + + #if settings.var['width_force']: # -todo----------- + + faces, edges = [], [] + n = len(me.verts) + thic = set_thick(self.thic, settings) + if thic != 0: + t, e = thic, self.extrusion + #print 'deb:thic, extr: ', t, e #--------------------- + points.extend([[v[0]+t*e[0], v[1]+t*e[1], v[2]+t*e[2]] for v in points[:]]) + faces = [[0+n, 1+n, 3+n, 2+n]] + else: + me.verts.extend(points) # add vertices to mesh + edges = [[0+n, 1+n]] + + me.verts.extend(points) # add vertices to mesh + if faces: me.faces.extend(faces) # add faces to the mesh + if edges: me.edges.extend(edges) # add faces to the mesh + + if settings.var['vGroup_on']: + # entities with the same color build one vertexGroup for easier material assignment --------------------- + ob.link(me) # link mesh to that object + vG_name = 'color_%s' %self.color_index + if edges: faces = edges + replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD + try: + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: existed vGroup:', vG_name #--------------------- + except: + me.addVertGroup(vG_name) + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: create new vGroup:', vG_name #--------------------- + + + #print 'deb:draw:line.ob OUT activObjectName: ', activObjectName #--------------------- + return ob + + + +class Point: #----------------------------------------------------------------- + """Class for objects representing dxf points. + """ + def __init__(self, obj): + """Expects an entity object of type point as input. + """ + if not obj.type == 'point': + raise TypeError, "Wrong type %s for point object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + #print 'deb:self.thic: ', self.thic #--------------------- + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.extrusion = get_extrusion(obj.data) + self.points = self.get_points(obj.data) + + + def get_points(self, data): + """Gets coordinates for a point type object. + + Points have fixed codes for each value. + """ + a = [0, 0, 0] + a[0] = getit(data, 10, None) # 10 = x + a[1] = getit(data, 20, None) # 20 = y + a[2] = getit(data, 30, 0) # 30 = z + out = [a] + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for POINT: generate Blender_geometry. + """ + points = self.points + obname = 'po_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + points_as = settings.var['points_as'] + thic = settings.var['thick_min'] + if thic < settings.var['dist_min']: thic = settings.var['dist_min'] + + if points_as in [1,3,4]: + if points_as == 1: # as 'empty' + c = 'Empty' + if points_as == 3: # as 'thin sphere' + res = settings.var['thin_res'] + c = Mesh.Primitives.UVsphere(res,res,thic) + if points_as == 4: # as 'thin box' + c = Mesh.Primitives.Cube(thic) + ob = SCENE.objects.new(c, obname) # create a new object + transform(self.extrusion, 0, ob) + ob.loc = tuple(points[0]) + + elif points_as == 2: # as 'vertex' + global activObjectLayer + global activObjectName + #print 'deb:draw:point.ob IN activObjectName: ', activObjectName #--------------------- + if activObjectLayer == self.layer and settings.var['one_mesh_on']: + obname = activObjectName + #print 'deb:draw:point.ob obname from activObjectName: ', obname #--------------------- + ob = Object.Get(obname) # open an existing mesh_object + #ob = SCENE.getChildren(obname) # open an existing mesh_object + me = Mesh.Get(ob.name) # open objects mesh data + else: + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + activObjectName = ob.name + activObjectLayer = self.layer + #print ('deb:draw:point new point.ob+mesh:"%s" created!' %ob.name) #--------------------- + me.verts.extend(points) # add vertices to mesh + + return ob + + + + +class LWpolyline: #----------------------------------------------------------------- + """Class for objects representing dxf LWpolylines. + """ + def __init__(self, obj): + """Expects an entity object of type lwpolyline as input. + """ + #print 'deb:LWpolyline.START:----------------' #------------------------ + if not obj.type == 'lwpolyline': + raise TypeError, "Wrong type %s for polyline object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.num_points = obj.get_type(90)[0] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + + self.color_index = getit(obj, 62, BYLAYER) + + self.elevation = getit(obj, 30, 0) + self.thic = getit(obj, 39, 0) + self.flags = getit(obj, 70, 0) + + self.closed = self.flags&1 # byte coded, 1 = closed, 128 = plinegen + + self.layer = getit(obj.data, 8, None) + self.points = self.get_points(obj.data) + self.extrusion = get_extrusion(obj.data) + + #print 'deb:LWpolyline.obj.data:\n', obj.data #------------------------ + #print 'deb:LWpolyline.ENDinit:----------------' #------------------------ + + + def get_points(self, data): + """Gets points for a polyline type object. + + LW-Polylines have no fixed number of verts, and + each vert can have a number of properties. + Verts should be coded as + 10:xvalue + 20:yvalue + 40:startwidth or 0 + 41:endwidth or 0 + 42:bulge or 0 + for each vert + """ + num = self.num_points + point = None + points = [] + for item in data: + if item[0] == 10: # 10 = x + if point: + points.append(point) + point = Vertex() + point.x = item[1] + elif item[0] == 20: # 20 = y + point.y = item[1] + elif item[0] == 40: # 40 = start width + point.swidth = item[1] + elif item[0] == 41: # 41 = end width + point.ewidth = item[1] + elif item[0] == 42: # 42 = bulge + point.bulge = item[1] + points.append(point) + return points + + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for LWPOLYLINE: generate Blender_geometry. + """ + #print 'deb:LWpolyline.draw.START:----------------' #------------------------ + points = [] + obname = 'lw_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + #settings.var['curves_on'] == True + #print 'deb:index_len: ', len(self.points) #------------------ + for i, point in enumerate(self.points): + #print 'deb:index: ', i #------------------ + if not point.bulge: + points.append(point.loc) + elif point.bulge and not self.closed and i == len(self.points)-1: + points.append(point.loc) + elif point.bulge: # + if i == len(self.points)-1: + point2 = self.points[0] + else: + point2 = self.points[i+1] + arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) + verts = drawBulge(point, point2, arc_res) +# if i == len(self.points)-1: +# if self.closed: +# verts.pop() #remove last(=first) vertex +# else: +# verts.pop() #remove last vertex, because this point will be writen as the next vertex + points.extend(verts) + + thic = self.thic + if settings.var['thick_force'] and thic == 0: thic = settings.var['thick_min'] + if settings.var['thick_on'] and thic != 0: + len1 = len(points) + points.extend([[point[0], point[1], point[2]+thic] for point in points]) + faces = [] + #print 'deb:len1:', len1 #----------------------- + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + if self.closed: + faces.append([len1-1, 0, len1, 2*len1-1]) + #print 'deb:faces_list:\n', faces #----------------------- + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + else: + edges = [[num, num+1] for num in xrange(len(points)-1)] + if self.closed: + edges.append([len(points)-1, 0]) + #print 'deb:edges_list:\n', edges #----------------------- + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.edges.extend(edges) # add edges to the mesh + + ob.LocZ = self.elevation + transform(self.extrusion, 0, ob) + + #print 'deb:LWpolyline.draw.END:----------------' #------------------------ + return ob + + + +class Polyline: #----------------------------------------------------------------- + """Class for objects representing dxf Polylines. + """ + def __init__(self, obj): + """Expects an entity object of type polyline as input. + """ + #print 'deb:polyline.init.START:----------------' #------------------------ + if not obj.type == 'polyline': + raise TypeError, "Wrong type %s for polyline object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + #print 'deb:polyline.obj.data[:]:\n', obj.data[:] #------------------------ + self.points = [] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.elevation = getit(obj, 30, 0) + #print 'deb:elevation: ', self.elevation #--------------- + self.thic = getit(obj, 39, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.flags = getit(obj, 70, 0) + self.closed = self.flags & 1 # closed in the M direction + self.curved = self.flags & 2 # Bezier-curve-fit vertices have been added + self.spline = self.flags & 4 # Bspline-fit vertices have been added + self.poly3d = self.flags & 8 # 3D-polyline + self.plmesh = self.flags & 16 # 3D-polygon mesh + self.closeN = self.flags & 32 # closed in the N direction + self.plface = self.flags & 64 # 3D-polyface mesh + self.contin = self.flags & 128 # the linetype pattern is generated continuously + + if self.poly3d or self.plface or self.plmesh: + self.poly2d = False # its not a 2D-polyline + else: + self.poly2d = True # it is a 2D-polyline + + self.swidth = getit(obj, 40, 0) # default start width + self.ewidth = getit(obj, 41, 0) # default end width + #self.bulge = getit(obj, 42, None) # bulge of the segment + self.vectorsM = getit(obj, 71, None) # PolyMesh: expansion in M-direction / PolyFace: number of the vertices + self.vectorsN = getit(obj, 72, None) # PolyMesh: expansion in M-direction / PolyFace: number of faces + #self.resolM = getit(obj, 73, None) # resolution of surface in M direction + #self.resolN = getit(obj, 74, None) # resolution of surface in N direction + self.curvetyp = getit(obj, 75, 0) # type of curve/surface: 0=None/5=Quadric/6=Cubic/8=Bezier + self.curvNormal = False + self.curvQBspline = False + self.curvCBspline = False + self.curvBezier = False + if self.curvetyp == 0: self.curvNormal = True + elif self.curvetyp == 5: self.curvQBspline = True + elif self.curvetyp == 6: self.curvCBspline = True + elif self.curvetyp == 8: self.curvBezier = True + + self.layer = getit(obj.data, 8, None) + self.extrusion = get_extrusion(obj.data) + + self.points = [] #list with vertices coordinats + self.faces = [] #list with vertices assigment to faces + #print 'deb:polyline.init.ENDinit:----------------' #------------ + + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + + def draw(self, settings): #-------------%%%% DRAW POLYLINE %%%--------------- + """for POLYLINE: generate Blender_geometry. + """ + ob = [] + if self.plface: #---- 3dPolyFace - mesh with free topology + ob = self.drawPlFace(settings) + elif self.plmesh: #---- 3dPolyMesh - mesh with ortogonal topology + ob = self.drawPlMesh(settings) + #---- 2dPolyline - plane polyline with arc/wide/thic segments + #---- 3dPolyline - noplane polyline (thin segments = without arc/wide/thic) + elif self.poly2d or self.poly3d: + if settings.var['curves_on']: # and self.spline: + ob = self.drawPolyCurve(settings) + else: + ob = self.drawPoly2d(settings) + return ob + + + + def drawPlFace(self, settings): #---- 3dPolyFace - mesh with free topology + """Generate the geometery of polyface. + """ + #print 'deb:polyface.draw.START:----------------' #------------------------ + points = [] + faces = [] + #print 'deb:len of pointsList ====== ', len(self.points) #------------------------ + for point in self.points: + if point.face: + faces.append(point.face) + else: + points.append(point.loc) + + + #print 'deb:len of points_list:\n', len(points) #----------------------- + #print 'deb:points_list:\n', points #----------------------- + #print 'deb:faces_list:\n', faces #----------------------- + obname = 'pf_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + transform(self.extrusion, 0, ob) + #print 'deb:polyface.draw.END:----------------' #------------------------ + + return ob + + + + def drawPlMesh(self, settings): #---- 3dPolyMesh - mesh with orthogonal topology + """Generate the geometery of polymesh. + """ + #print 'deb:polymesh.draw.START:----------------' #------------------------ + #points = [] + #print 'deb:len of pointsList ====== ', len(self.points) #------------------------ + faces = [] + m = self.vectorsM + n = self.vectorsN + for j in xrange(m - 1): + for i in xrange(n - 1): + nn = j * n + faces.append([nn+i, nn+i+1, nn+n+i+1, nn+n+i]) + + if self.closed: #mesh closed in N-direction + nn = (m-1)*n + for i in xrange(n - 1): + faces.append([nn+i, nn+i+1, i+1, i]) + + if self.closeN: #mesh closed in M-direction + for j in xrange(m-1): + nn = j * n + faces.append([nn+n-1, nn, nn+n, nn+n-1+n]) + + if self.closed and self.closeN: #mesh closed in M/N-direction + faces.append([ (n*m)-1, (m-1)*n, 0, n-1]) + + #print 'deb:len of points_list:\n', len(points) #----------------------- + #print 'deb:faces_list:\n', faces #----------------------- + obname = 'pm_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend([point.loc for point in self.points]) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + transform(self.extrusion, 0, ob) + #print 'deb:polymesh.draw.END:----------------' #------------------------ + return ob + + + def drawPolyCurve(self, settings): #---- Polyline - draw as Blender-curve + """Generate the geometery of polyline as Blender-curve. + """ + #print 'deb:polyline2dCurve.draw.START:----------------' #--- + if len(self.points) < 2: + #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #--------- + return + + if self.spline: pline_typ = 'ps' # Polyline-nurbSpline + elif self.curved: pline_typ = 'pc' # Polyline-bezierCurve + else: pline_typ = 'pl' # Polyline + obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name + obname = obname[:MAX_NAMELENGTH] + d_points = [] + #for DXFr10-format: update all points[].loc[2] == None -> 0.0 + for point in self.points: + if point.loc[2] == None: + point.loc[2] = self.elevation + d_points.append(point) + + thic = set_thick(self.thic, settings) + + if thic != 0.0: #hack: Blender<2.45 curve-extrusion + LocZ = d_points[0].loc[2] + temp_points = [] + for point in d_points: + point.loc[2] = 0.0 + temp_points.append(point) + d_points = temp_points + + #print 'deb:polyline2dCurve.draw d_points=', d_points #--------------- + pline = Curve.New(obname) # create new curve data + + if False: #self.spline: # NURBSplines-----FAKE(with Bezier)----- + #print 'deb:polyline2dCurve.draw self.spline!' #--------------- + curve = pline.appendNurb(BezTriple.New(d_points[0])) + for p in d_points[1:]: + curve.append(BezTriple.New(p)) + for point in curve: + point.handleTypes = [AUTO, AUTO] + if self.closed: + curve.flagU = 1 # Set curve cyclic=close + else: + curve.flagU = 0 # Set curve not cyclic=open + curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- + curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- + + elif self.spline: # NURBSplines-----TODO--:if curvQBspline: generate middlepoints--- + #print 'deb:polyline2dCurve.draw self.spline!' #--------------- + weight1 = 0.5 + weight2 = 1.0 + # generate middlepoints except start/end-segments --- + if self.curvQBspline: + temp_points = [] + point = d_points[0].loc + point.append(weight1) + temp_points.append(point) + for i in xrange(1,len(d_points)-2): + point1 = d_points[i].loc + point2 = d_points[i+1].loc + mpoint = list((Mathutils.Vector(point1) + Mathutils.Vector(point2)) * 0.5) + mpoint.append(weight2) + point1.append(weight1) + temp_points.append(point1) + temp_points.append(mpoint) + point2.append(weight1) + temp_points.append(point2) + point = d_points[-1].loc + point.append(weight1) + temp_points.append(point) + d_points = temp_points + else: + temp_points = [] + for d in d_points: + d = d.loc + d.append(weight1) + temp_points.append(d) + d_points = temp_points + + if not self.closed: + # generate extended startpoint and endpoint------ + point1 = Mathutils.Vector(d_points[0][:3]) + point2 = Mathutils.Vector(d_points[1][:3]) + startpoint = list(point1 - point2 + point1) + startpoint.append(weight1) + point1 = Mathutils.Vector(d_points[-1][:3]) + point2 = Mathutils.Vector(d_points[-2][:3]) + endpoint = list(point1 - point2 + point1) + endpoint.append(weight1) + temp_points = [] + temp_points.append(startpoint) + temp_points.extend(d_points) + d_points = temp_points + d_points.append(endpoint) + + point = d_points[0] + curve = pline.appendNurb(point) + curve.setType(4) #NURBS curve + for point in d_points[1:]: + curve.append(point) + if self.closed: + curve.flagU = 1 # Set curve cyclic=close + else: + curve.flagU = 0 # Set curve not cyclic=open + + elif self.curved: #--Bezier-curves---OK------- + #print 'deb:polyline2dCurve.draw self.curved!' #--------------- + curve = pline.appendNurb(BezTriple.New(d_points[0])) + for p in d_points[1:]: + curve.append(BezTriple.New(p)) + for point in curve: + point.handleTypes = [AUTO, AUTO] + if self.closed: + curve.flagU = 1 # Set curve cyclic=close + else: + curve.flagU = 0 # Set curve not cyclic=open + curve[0].handleTypes = [FREE, ALIGN] #remi--todo----- + curve[-1].handleTypes = [ALIGN, FREE] #remi--todo----- + + else: #--straight line/arc-segments----OK------ + points = [] + d_points.append(d_points[0]) #------ first vertex added ------------- + #curve.setType(0) #polygon_type of Blender_curve + for i in xrange(len(d_points)-1): + point1 = d_points[i] + point2 = d_points[i+1] + if point1.bulge and (i < len(d_points)-2 or self.closed): + verts = drawBulge(point1, point2, arc_res=8, curve_on=True) #calculate additional points for bulge + if i == 0: curve = pline.appendNurb(BezTriple.New(verts[0])) + else: curve.append(BezTriple.New(verts[0])) + curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + for p in verts[1:]: + curve.append(BezTriple.New(p)) + curve[-1].handleTypes = [AUTO, AUTO] #--todo--calculate bezier-tangents +# curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + else: + if i == 0: curve = pline.appendNurb(BezTriple.New(point1.loc)) + else: curve.append(BezTriple.New(point1.loc)) + curve[-1].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + if self.closed: + curve.flagU = 1 # Set curve cyclic=close +# curve[0].handleTypes = [VECT, VECT] #--todo--calculate bezier-tangents + else: + curve.flagU = 0 # Set curve not cyclic=open + curve[0].handleTypes = [FREE, VECT] #--todo--calculate bezier-tangents + curve[-1].handleTypes = [VECT, FREE] #--todo--calculate bezier-tangents + + pline.update() + ob = SCENE.objects.new(pline) # create a new curve_object + + if thic != 0.0: #hack: Blender<2.45 curve-extrusion + thic = thic * 0.5 + pline.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) + ob.LocZ = thic + LocZ + + transform(self.extrusion, 0, ob) + if thic != 0.0: + ob.SizeZ *= abs(thic) + + #print 'deb:polyline2dCurve.draw.END:----------------' #----- + return ob + + + def drawPoly2d(self, settings): #---- 2dPolyline - plane wide/thic lines + """Generate the geometery of regular polyline. + """ + #print 'deb:polyline2d.draw.START:----------------' #------------------------ + points = [] + d_points = [] + swidths = [] + ewidths = [] + swidth_default = self.swidth #default start width of POLYLINEs segments + ewidth_default = self.ewidth #default end width of POLYLINEs segments + thic = set_thick(self.thic, settings) + if self.spline: pline_typ = 'ps' + elif self.curved: pline_typ = 'pc' + else: pline_typ = 'pl' + obname = '%s_%s' %(pline_typ, self.layer) # create object_name from layer name +# obname = 'pl_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + + if len(self.points) < 2: + #print 'deb:drawPoly2d exit, cause POLYLINE has less than 2 vertices' #--------- + return + #d_points = self.points[:] + #for DXFr10-format: update all points[].loc[2] == None -> 0.0 + for point in self.points: + if point.loc[2] == None: + point.loc[2] = self.elevation + d_points.append(point) + #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ + + #add duplic of the first vertex at the end of pointslist + d_points.append(d_points[0]) + + #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ + #print 'deb:d_pointsList ======:\n ', d_points #------------------------ + + + #routine to sort out of "double.vertices" -------- + minimal_dist = settings.var['dist_min'] * 0.1 + temp_points = [] + for i in xrange(len(d_points)-1): + point = d_points[i] + point2 = d_points[i+1] + #print 'deb:double.vertex p1,p2', point, point2 #------------------------ + delta = Mathutils.Vector(point2.loc) - Mathutils.Vector(point.loc) + if delta.length > minimal_dist: + temp_points.append(point) + #else: print 'deb:double.vertex sort out!' #------------------------ + temp_points.append(d_points[-1]) #------ last vertex added ------------- + d_points = temp_points #-----vertex.list without "double.vertices" + #print 'deb:d_pointsList =after DV-outsorting=====:\n ', d_points #------------------------ + + #print 'deb:len of d_pointsList ====== ', len(d_points) #------------------------ + if len(d_points) < 2: + #print 'deb:drawPoly2d corrupted Vertices' #--------- + return + + #analyse of straight- and bulge-segments (generation of additional points for bulge) + exist_wide_segment = False + for i in xrange(len(d_points)-1): + point1 = d_points[i] + point2 = d_points[i+1] + #print 'deb:pline.tocalc.point1:', point1 #------------------------ + #print 'deb:pline.tocalc.point2:', point2 #------------------------ + + swidth = point1.swidth + ewidth = point1.ewidth + if swidth == None: swidth = swidth_default + if ewidth == None: ewidth = ewidth_default + + if swidth != 0.0 or ewidth != 0.0: exist_wide_segment = True + + if settings.var['width_force']: # force minimal width for thin segments + if swidth < settings.var['width_min']: swidth = settings.var['width_min'] + if ewidth < settings.var['width_min']: ewidth = settings.var['width_min'] + if not settings.var['width_on']: # then force minimal width for all segments + swidth = settings.var['width_min'] + ewidth = settings.var['width_min'] + + if point1.bulge and (i < (len(d_points)-2) or self.closed): + arc_res = settings.var['arc_res']/sqrt(settings.var['arc_rad']) + verts = drawBulge(point1, point2, arc_res) #calculate additional points for bulge + points.extend(verts) + delta_width = (ewidth - swidth) / len(verts) + width_list = [swidth + (delta_width * ii) for ii in xrange(len(verts)+1)] + swidths.extend(width_list[0:-1]) + ewidths.extend(width_list[1:]) + else: + points.append(point1.loc) + swidths.append(swidth) + ewidths.append(ewidth) + + + #--calculate width_vectors: left-side- and right-side-points ---------------- + # 1.level:IF width --------------------------------------- + if (settings.var['width_on'] and exist_wide_segment) or settings.var['width_force']: + points.append(d_points[0].loc) #temporarly add first vertex at the end (for better loop) + + pointsLs = [] # list of left-start-points + pointsLe = [] # list of left-end-points + pointsRs = [] # list of right-start-points + pointsRe = [] # list of right-end-points + pointsW = [] # list of entire-border-points + #rotMatr90 = Mathutils.Matrix(rotate 90 degree around Z-axis) = normalvectorXY + rotMatr90 = Mathutils.Matrix([0, -1, 0], [1, 0, 0], [0, 0, 1]) + for i in xrange(len(points)-1): + point1 = points[i] + point2 = points[i+1] + point1vec = Mathutils.Vector(point1) + point2vec = Mathutils.Vector(point2) + swidth05 = swidths[i] * 0.5 + ewidth05 = ewidths[i] * 0.5 + if swidth05 == 0: swidth05 = 0.5 * settings.var['dist_min'] #minimal width + if ewidth05 == 0: ewidth05 = 0.5 * settings.var['dist_min'] #minimal width + + normal_vector = rotMatr90 * (point2vec-point1vec).normalize() + swidth05vec = swidth05 * normal_vector + ewidth05vec = ewidth05 * normal_vector + pointsLs.append(point1vec + swidth05vec) #vertex left start + pointsRs.append(point1vec - swidth05vec) #vertex right start + pointsLe.append(point2vec + ewidth05vec) #vertex left end + pointsRe.append(point2vec - ewidth05vec) #vertex right end + + pointsLc, pointsRc = [], [] + + # 2.level:IF width and corner-intersection activated + if settings.var['pl_section_on']: #optional clean corner-intersections + if not self.closed: + pointsLc.append(pointsLs[0]) + pointsRc.append(pointsRs[0]) + lenL = len(pointsLs)-2 #without the last point at the end of the list + else: + pointsLs.append(pointsLs[0]) + pointsRs.append(pointsRs[0]) + pointsLe.append(pointsLe[0]) + pointsRe.append(pointsRe[0]) + points.append(points[0]) + lenL = len(pointsLs)-1 #without the duplic of the first point at the end of the list + #print 'deb:pointsLs():\n', pointsLs #---------------- + #print 'deb:lenL, len.pointsLs():', lenL,',', len(pointsLs) #---------------- + for i in xrange(lenL): + pointVec = Mathutils.Vector(points[i+1]) + #print 'deb:pointVec: ', pointVec #------------- + #compute left-corner-points + vecL1 = pointsLs[i] + vecL2 = pointsLe[i] + vecL3 = pointsLs[i+1] + vecL4 = pointsLe[i+1] + #print 'deb:vectorsL:---------\n', vecL1,'\n',vecL2,'\n',vecL3,'\n',vecL4 #------------- + #cornerpointL = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4) + cornerpointL = Mathutils.LineIntersect(vecL1, vecL2, vecL3, vecL4) + #print 'deb:cornerpointL: ', cornerpointL #------------- + + #compute right-corner-points + vecR1 = pointsRs[i] + vecR2 = pointsRe[i] + vecR3 = pointsRs[i+1] + vecR4 = pointsRe[i+1] + #print 'deb:vectorsR:---------\n', vecR1,'\n',vecR2,'\n',vecR3,'\n',vecR4 #------------- + #cornerpointR = Geometry.LineIntersect2D(vec1, vec2, vec3, vec4) + cornerpointR = Mathutils.LineIntersect(vecR1, vecR2, vecR3, vecR4) + #print 'deb:cornerpointR: ', cornerpointR #------------- + + #if diststance(cornerL-center-cornerR) < limiter * (seg1_endWidth + seg2_startWidth) + if cornerpointL != None and cornerpointR != None: + cornerpointL = cornerpointL[0] + cornerpointR = cornerpointR[0] + max_cornerDist = (vecL2 - vecR2).length + (vecL3 - vecR3).length + is_cornerDist = (cornerpointL - pointVec).length + (cornerpointR - pointVec).length + # anglecut --------- limited by ANGLECUT_LIMIT (1.0 - 5.0) + if is_cornerDist < max_cornerDist * settings.var['angle_cut']: + pointsLc.append(cornerpointL) + pointsRc.append(cornerpointR) + else: + pointsLc.extend((pointsLe[i],pointsLs[i+1])) + pointsRc.extend((pointsRe[i],pointsRs[i+1])) + else: + pointsLc.extend((pointsLe[i],pointsLs[i+1])) + pointsRc.extend((pointsRe[i],pointsRs[i+1])) + if not self.closed: + pointsLc.append(pointsLe[-2]) + pointsRc.append(pointsRe[-2]) + else: + """ """ + + # 2.level:IF width but not corner-intersection activated + else: + # points_multiplexer of start-points and end-points + lenL = len(pointsLs) - 1 #without the duplic of the first point at the end of list + if self.closed: lenL += 1 #inclusive the duplic of the first point at the end of list + for i in xrange(lenL): + pointsLc.extend((pointsLs[i], pointsLe[i])) + pointsRc.extend((pointsRs[i], pointsRe[i])) + + pointsW = pointsLc + pointsRc # all_points_List = left_side + right_side + #print 'deb:pointsW():\n', pointsW #---------------- + len1 = int(len(pointsW) * 0.5) + #print 'deb:len1:', len1 #----------------------- + + # 2.level:IF width and thickness --------------------- + if thic != 0: + thic_pointsW = [] + thic_pointsW.extend([[point[0], point[1], point[2]+thic] for point in pointsW]) + if thic < 0.0: + thic_pointsW.extend(pointsW) + pointsW = thic_pointsW + else: + pointsW.extend(thic_pointsW) + faces = [] + f_start, f_end = [], [] + f_bottom = [[num, num+1, len1+num+1, len1+num] for num in xrange(len1-1)] + f_top = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1+len1, len1+len1+len1-1)] + f_left = [[num, len1+len1+num, len1+len1+num+1, num+1] for num in xrange(len1-1)] + f_right = [[num, num+1, len1+len1+num+1, len1+len1+num] for num in xrange(len1, len1+len1-1)] + + if self.closed: + f_bottom.append([len1-1, 0, len1, len1+len1-1]) #bottom face + f_top.append( [len1+len1+len1-1, len1+len1+len1+len1-1, len1+len1+len1, len1+len1+0]) #top face + f_left.append( [0, len1-1, len1+len1+len1-1, len1+len1]) #left face + f_right.append( [len1, len1+len1+len1, len1+len1+len1+len1-1, len1+len1-1]) #right face + else: + f_start = [[0, len1, len1+len1+len1, len1+len1]] + f_end = [[len1+len1-1, 0+len1-1, len1+len1+len1-1, len1+len1+len1+len1-1]] + + faces = f_bottom + f_top + f_left + f_right + f_start + f_end + #faces = f_bottom + f_top + #faces = f_left + f_right + f_start + f_end + #print 'deb:faces_list:\n', faces #----------------------- + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(pointsW) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + # each MeshSite becomes vertexGroup for easier material assignment --------------------- + # The mesh must first be linked to an object so the method knows which object to update. + # This is because vertex groups in Blender are stored in the object -- not in the mesh, + # which may be linked to more than one object. + if settings.var['vGroup_on']: + # each MeshSite becomes vertexGroup for easier material assignment --------------------- + replace = Blender.Mesh.AssignModes.REPLACE #or .AssignModes.ADD + vg_left, vg_right, vg_top, vg_bottom = [], [], [], [] + for v in f_left: vg_left.extend(v) + for v in f_right: vg_right.extend(v) + for v in f_top: vg_top.extend(v) + for v in f_bottom: vg_bottom.extend(v) + me.addVertGroup('side.left') ; me.assignVertsToGroup('side.left', list(set(vg_left)), 1.0, replace) + me.addVertGroup('side.right') ; me.assignVertsToGroup('side.right', list(set(vg_right)), 1.0, replace) + me.addVertGroup('side.top') ; me.assignVertsToGroup('side.top', list(set(vg_top)), 1.0, replace) + me.addVertGroup('side.bottom'); me.assignVertsToGroup('side.bottom',list(set(vg_bottom)), 1.0, replace) + if not self.closed: + me.addVertGroup('side.start'); me.assignVertsToGroup('side.start', f_start[0], 1.0, replace) + me.addVertGroup('side.end') ; me.assignVertsToGroup('side.end', f_end[0], 1.0, replace) + + + # 2.level:IF width, but no-thickness --------------------- + else: + faces = [] + faces = [[num, len1+num, len1+num+1, num+1] for num in xrange(len1 - 1)] + if self.closed: + faces.append([len1, 0, len1-1, len1+len1-1]) + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(pointsW) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + + # 1.level:IF no-width, but thickness --------------------- + elif thic != 0: + len1 = len(points) + thic_points = [] + thic_points.extend([[point[0], point[1], point[2]+thic] for point in points]) + if thic < 0.0: + thic_points.extend(points) + points = thic_points + else: + points.extend(thic_points) + faces = [] + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + if self.closed: + faces.append([len1-1, 0, len1, 2*len1-1]) + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + + # 1.level:IF no-width and no-thickness --------------------- + else: + edges = [[num, num+1] for num in xrange(len(points)-1)] + if self.closed: + edges.append([len(points)-1, 0]) + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + me.verts.extend(points) # add vertices to mesh + me.edges.extend(edges) # add edges to the mesh + + transform(self.extrusion, 0, ob) + #print 'deb:polyline.draw.END:----------------' #----------------------- + return ob + + + + +class Vertex(object): #----------------------------------------------------------------- + """Generic vertex object used by polylines (and maybe others). + """ + + def __init__(self, obj=None): + """Initializes vertex data. + + The optional obj arg is an entity object of type vertex. + """ + #print 'deb:Vertex.init.START:----------------' #----------------------- + self.loc = [0,0,0] + self.face = [] + self.swidth = 0 + self.ewidth = 0 + self.bulge = 0 + if obj is not None: + if not obj.type == 'vertex': + raise TypeError, "Wrong type %s for vertex object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + self.get_props(obj.data) + #print 'deb:Vertex.init.END:----------------' #------------------------ + + + def get_props(self, data): + """Gets coords for a VERTEX type object. + + Each vert can have a number of properties. + Verts should be coded as + 10:xvalue + 20:yvalue + 40:startwidth or 0 + 41:endwidth or 0 + 42:bulge or 0 + """ + self.x = getit(data, 10, None) + self.y = getit(data, 20, None) + self.z = getit(data, 30, None) + + self.flags = getit(data, 70, 0) # flags + self.curved = self.flags&1 # Bezier-curve-fit:additional-vertex + self.curv_t = self.flags&2 # Bezier-curve-fit:tangent exists + self.spline = self.flags&8 # Bspline-fit:additional-vertex + self.splin2 = self.flags&16 # Bspline-fit:control-vertex + self.poly3d = self.flags&32 # polyline3d:control-vertex + self.plmesh = self.flags&64 # polymesh3d:control-vertex + self.plface = self.flags&128 # polyface + + # if PolyFace.Vertex with Face_definition + if self.curv_t: + self.curv_tangent = getit(data, 50, None) # curve_tangent + + if self.plface and not self.plmesh: + v1 = getit(data, 71, 0) # polyface:Face.vertex 1. + v2 = getit(data, 72, 0) # polyface:Face.vertex 2. + v3 = getit(data, 73, 0) # polyface:Face.vertex 3. + v4 = getit(data, 74, None) # polyface:Face.vertex 4. + self.face = [abs(v1)-1,abs(v2)-1,abs(v3)-1] + if v4 != None: + self.face.append(abs(v4)-1) + else: #--parameter for polyline2d + self.swidth = getit(data, 40, None) # start width + self.ewidth = getit(data, 41, None) # end width + self.bulge = getit(data, 42, 0) # bulge of segment + + + def __len__(self): + return 3 + + + def __getitem__(self, key): + return self.loc[key] + + + def __setitem__(self, key, value): + if key in [0,1,2]: + self.loc[key] + + + def __iter__(self): + return self.loc.__iter__() + + + def __str__(self): + return str(self.loc) + + + def __repr__(self): + return "Vertex %s, swidth=%s, ewidth=%s, bulge=%s, face=%s" %(self.loc, self.swidth, self.ewidth, self.bulge, self.face) + + + def getx(self): + return self.loc[0] + def setx(self, value): + self.loc[0] = value + x = property(getx, setx) + + + def gety(self): + return self.loc[1] + def sety(self, value): + self.loc[1] = value + y = property(gety, sety) + + + def getz(self): + return self.loc[2] + def setz(self, value): + self.loc[2] = value + z = property(getz, setz) + + + +class Text: #----------------------------------------------------------------- + """Class for objects representing dxf Text. + """ + def __init__(self, obj): + """Expects an entity object of type text as input. + """ + if not obj.type == 'text': + raise TypeError, "Wrong type %s for text object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.height = 1.7 * obj.get_type(40)[0] #text.height + self.value = obj.get_type(1)[0] #The text string value + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.color_index = getit(obj, 62, BYLAYER) + self.thic = getit(obj, 39, 0) + + self.rotation = getit(obj, 50, 0) # radians + self.width_factor = getit(obj, 41, 1) # Scaling factor along local x axis + self.oblique = getit(obj, 51, 0) # oblique angle: skew in degrees -90 <= oblique <= 90 + + #self.style = getit(obj, 7, 'STANDARD') # --todo---- Text style name (optional, default = STANDARD) + + #Text generation flags (optional, default = 0): + #2 = backward (mirrored in X), + #4 = upside down (mirrored in Y) + self.flags = getit(obj, 71, 0) + self.mirrorX, self.mirrorY = 1.0, 1.0 + if self.flags&2: self.mirrorX = - 1.0 + if self.flags&4: self.mirrorY = - 1.0 + + # vertical.alignment: 0=baseline, 1=bottom, 2=middle, 3=top + self.valignment = getit(obj, 73, 0) + #Horizontal text justification type (optional, default = 0) integer codes (not bit-coded) + #0=left, 1=center, 2=right + #3=aligned, 4=middle, 5=fit + self.halignment = getit(obj, 72, 0) + + self.layer = getit(obj.data, 8, None) + self.loc1, self.loc2 = self.get_loc(obj.data) + if self.loc2[0] != None and self.halignment != 5: + self.loc = self.loc2 + else: + self.loc = self.loc1 + self.extrusion = get_extrusion(obj.data) + + + + def get_loc(self, data): + """Gets adjusted location for text type objects. + + If group 72 and/or 73 values are nonzero then the first alignment point values + are ignored and AutoCAD calculates new values based on the second alignment + point and the length and height of the text string itself (after applying the + text style). If the 72 and 73 values are zero or missing, then the second + alignment point is meaningless. + I don't know how to calc text size... + """ + # bottom left x, y, z and justification x, y, z = 0 + #x, y, z, jx, jy, jz = 0, 0, 0, 0, 0, 0 + x = getit(data, 10, None) #First alignment point (in OCS). + y = getit(data, 20, None) + z = getit(data, 30, 0.0) + jx = getit(data, 11, None) #Second alignment point (in OCS). + jy = getit(data, 21, None) + jz = getit(data, 31, 0.0) + return [x, y, z],[jx, jy, jz] + + + def __repr__(self): + return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) + + + def draw(self, settings): + """for TEXTs: generate Blender_geometry. + """ + obname = 'tx_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + txt = Text3d.New(obname) + ob = SCENE.objects.new(txt) # create a new text_object + + txt.setText(self.value) + txt.setSize(1.0) #Blender<2.45 accepts only (0.0 - 5.0) + #txt.setSize(self.height) + #txt.setWidth(self.bold) + #setLineSeparation(sep) + txt.setShear(self.oblique/90) + + thic = set_thick(self.thic, settings) + if thic != 0.0: + thic = self.thic * 0.5 + self.loc[2] += thic + txt.setExtrudeDepth(1.0) #Blender<2.45 accepts only (0.1 - 10.0) + if self.halignment == 0: + align = Text3d.LEFT + elif self.halignment == 1: + align = Text3d.MIDDLE + elif self.halignment == 2: + align = Text3d.RIGHT + else: + align = Text3d.LEFT + txt.setAlignment(align) + + if self.valignment == 1: + txt.setYoffset(0.0) + elif self.valignment == 2: + txt.setYoffset(- self.height * 0.5) + elif self.valignment == 3: + txt.setYoffset(- self.height) + + # move the object center to the text location + ob.loc = tuple(self.loc) + transform(self.extrusion, self.rotation, ob) + + # flip it and scale it to the text width + ob.SizeX *= self.height * self.width_factor * self.mirrorX + ob.SizeY *= self.height * self.mirrorY + if thic != 0.0: ob.SizeZ *= abs(thic) + return ob + + + +def set_thick(thickness, settings): + """Set thickness relative to settings variables. + + Set thickness relative to settings variables: + 'thick_on','thick_force','thick_min'. + Accepted also minus values of thickness + python trick: sign(x)=cmp(x,0) + """ + if settings.var['thick_force']: + if settings.var['thick_on']: + if abs(thickness) < settings.var['thick_min']: + thic = settings.var['thick_min'] * cmp(self.thic,0) + else: thic = thickness + else: thic = settings.var['thick_min'] + else: + if settings.var['thick_on']: thic = thickness + else: thic = 0.0 + return thic + + + + +class Mtext: #----------------------------------------------------------------- + """Class for objects representing dxf Mtext. + """ + + def __init__(self, obj): + """Expects an entity object of type mtext as input. + """ + if not obj.type == 'mtext': + raise TypeError, "Wrong type %s for mtext object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.height = obj.get_type(40)[0] + self.width = obj.get_type(41)[0] + self.alignment = obj.get_type(71)[0] # alignment 1=TL, 2=TC, 3=TR, 4=ML, 5=MC, 6=MR, 7=BL, 8=BC, 9=BR + self.value = self.get_text(obj.data) # The text string value + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.color_index = getit(obj, 62, BYLAYER) + self.rotation = getit(obj, 50, 0) # radians + + self.width_factor = getit(obj, 42, 1) # Scaling factor along local x axis + self.line_space = getit(obj, 44, 1) # percentage of default + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.extrusion = get_extrusion(obj.data) + + + def get_text(self, data): + """Reconstructs mtext data from dxf codes. + """ + primary = '' + secondary = [] + for item in data: + if item[0] == 1: # There should be only one primary... + primary = item[1] + elif item[0] == 3: # There may be any number of extra strings (in order) + secondary.append(item[1]) + if not primary: + #raise ValueError, "Empty Mtext Object!" + string = "Empty Mtext Object!" + if not secondary: + string = primary.replace(r'\P', '\n') + else: + string = ''.join(secondary)+primary + string = string.replace(r'\P', '\n') + return string + + + def get_loc(self, data): + """Gets location for a mtext type objects. + + Mtext objects have only one point indicating + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, None) + loc[1] = getit(data, 20, None) + loc[2] = getit(data, 30, 0.0) + return loc + + + def __repr__(self): + return "%s: layer - %s, value - %s" %(self.__class__.__name__, self.layer, self.value) + + + def draw(self, settings): + """for MTEXTs: generate Blender_geometry. + """ + # Now Create an object + obname = 'tm_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + txt = Text3d.New(obname) + ob = SCENE.objects.new(txt) # create a new text_object + + txt.setSize(1) + # Blender doesn't give access to its text object width currently + # only to the text3d's curve width... + #txt.setWidth(text.width/10) + txt.setLineSeparation(self.line_space) + txt.setExtrudeDepth(0.5) + txt.setText(self.value) + + # scale it to the text size + ob.SizeX = self.height * self.width_factor + ob.SizeY = self.height + ob.SizeZ = self.height + + # move the object center to the text location + ob.loc = tuple(self.loc) + transform(self.extrusion, self.rotation, ob) + + return ob + + + + +class Circle: #----------------------------------------------------------------- + """Class for objects representing dxf Circles. + """ + + def __init__(self, obj): + """Expects an entity object of type circle as input. + """ + if not obj.type == 'circle': + raise TypeError, "Wrong type %s for circle object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.radius = obj.get_type(40)[0] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.extrusion = get_extrusion(obj.data) + + + + def get_loc(self, data): + """Gets the center location for circle type objects. + + Circles have a single coord location. + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, None) + loc[1] = getit(data, 20, None) + loc[2] = getit(data, 30, 0.0) + return loc + + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + def draw(self, settings): + """for CIRCLE: generate Blender_geometry. + """ + obname = 'ci_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + radius = self.radius + + thic = set_thick(self.thic, settings) + if settings.var['curves_on']: + c = Curve.New(obname) # create new curve data + p1 = (0, -radius, 0) + p2 = (radius, 0, 0) + p3 = (0, radius, 0) + p4 = (-radius, 0, 0) + + p1 = BezTriple.New(p1) + p2 = BezTriple.New(p2) + p3 = BezTriple.New(p3) + p4 = BezTriple.New(p4) + + curve = c.appendNurb(p1) + curve.append(p2) + curve.append(p3) + curve.append(p4) + for point in curve: + point.handleTypes = [AUTO, AUTO] + curve.flagU = 1 # Set curve cyclic=closed + c.update() + + #remi --todo-----to check--------------------------- + ob = SCENE.objects.new(c) # create a new circle_mesh_object + ob.loc = tuple(self.loc) + if thic != 0.0: #hack: Blender<2.45 curve-extrusion + thic = thic * 0.5 + c.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) + ob.LocZ = thic + self.loc[2] + transform(self.extrusion, 0, ob) + if thic != 0.0: + ob.SizeZ *= abs(thic) + return ob + + elif False: + verts_num = settings.var['arc_res'] * sqrt(radius / settings.var['arc_rad']) + if verts_num > 100: verts_num = 100 # Blender accepts only values [3:500] + if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500] + if thic != 0: + loc2 = thic * 0.5 #-----blenderAPI draw Cylinder with 2*thickness + self.loc[2] += loc2 #---new location for the basis of cylinder + #print 'deb:circleDraw:self.loc2:', self.loc #----------------------- + c = Mesh.Primitives.Cylinder(int(verts_num), radius*2, abs(thic)) + else: + c = Mesh.Primitives.Circle(int(verts_num), radius*2) + + #c.update() + ob = SCENE.objects.new(c, obname) # create a new circle_mesh_object + ob.loc = tuple(self.loc) + transform(self.extrusion, 0, ob) + return ob + + else: + cir = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(cir) # create a new arc_object + # set a number of segments in entire circle + arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) + start, end = 0.0 , 360.0 + verts, edges = drawArc(None, radius, start, end, arc_res) + verts = verts[:-2] #list without last point (cause first piont equal) + edges = edges[:-1] + edges[-1][1] = 0 + print 'deb:edges:', edges #remi-todo----- why is this List inhomogene ? ---------- + if thic != 0: + len1 = len(verts) + thic_verts = [] + thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) + if thic < 0.0: + thic_verts.extend(verts) + verts = thic_verts + else: + verts.extend(thic_verts) + faces = [] + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + faces.append([len1 - 1, 0, len1, len1 + len1 -1]) + if settings.var['fill_on']: + if thic < 0.0: + verts.append([0,0,thic]) #center of top side + verts.append([0,0,0]) #center of bottom side + else: + verts.append([0,0,0]) #center of bottom side + verts.append([0,0,thic]) #center of top side + center1 = len(verts)-2 + center2 = len(verts)-1 + faces.extend([num+1, num, center1] for num in xrange(len1 - 1)) + faces.append([0, len1 - 1, center1]) + faces.extend([num+len1, num+1+len1, center2] for num in xrange(len1 - 1)) + faces.append([len1-1+len1, 0+len1, center2]) + #print 'deb:verts:', verts #--------------- + #print 'deb:faces:', faces #--------------- + cir.verts.extend(verts) # add vertices to mesh + cir.faces.extend(faces) # add faces to the mesh + else: + cir.verts.extend(verts) # add vertices to mesh + cir.edges.extend(edges) # add edges to the mesh + + ob.loc = tuple(self.loc) + transform(self.extrusion, 0, ob) + return ob + + + + +class Arc: #----------------------------------------------------------------- + """Class for objects representing dxf arcs. + """ + + def __init__(self, obj): + """Expects an entity object of type arc as input. + """ + if not obj.type == 'arc': + raise TypeError, "Wrong type %s for arc object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.radius = obj.get_type(40)[0] + self.start_angle = obj.get_type(50)[0] + self.end_angle = obj.get_type(51)[0] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.extrusion = get_extrusion(obj.data) + + + + def get_loc(self, data): + """Gets the center location for arc type objects. + + Arcs have a single coord location. + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, None) + loc[1] = getit(data, 20, None) + loc[2] = getit(data, 30, 0.0) + return loc + + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + def draw(self, settings): + """for ARC: generate Blender_geometry. + """ + obname = 'ar_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + + center = self.loc + radius = self.radius + start = self.start_angle + end = self.end_angle + #print 'deb:drawArc: center, radius, start, end:\n', center, radius, start, end #--------- + thic = set_thick(self.thic, settings) + + if settings.var['curves_on']: + arc_res = 8 + verts, edges = drawArc(None, radius, start, end, arc_res) + arc = Curve.New(obname) # create new curve data + curve = arc.appendNurb(BezTriple.New(verts[0])) + for p in verts[1:]: + curve.append(BezTriple.New(p)) + for point in curve: + point.handleTypes = [AUTO, AUTO] + #print 'deb:arc.draw point=', point #--------------- + curve[0].handleTypes = [FREE, VECT] #remi--todo----- + curve[-1].handleTypes = [VECT, FREE] #remi--todo----- + curve.flagU = 0 # Set curve not cyclic=open + arc.update() + + #remi --todo-----to check--------------------------- + ob = SCENE.objects.new(arc) # create a new circle_mesh_object + ob.loc = tuple(self.loc) + if thic != 0.0: #hack: Blender<2.45 curve-extrusion + thic = thic * 0.5 + arc.setExt1(1.0) # curve-extrusion accepts only (0.0 - 2.0) + ob.LocZ = thic + self.loc[2] + transform(self.extrusion, 0, ob) + if thic != 0.0: + ob.SizeZ *= abs(thic) + return ob + + else: + arc = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(arc) # create a new arc_object + # set a number of segments in entire circle + arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) + verts, edges = drawArc(None, radius, start, end, arc_res) + if thic != 0: + len1 = len(verts) + thic_verts = [] + thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) + if thic < 0.0: + thic_verts.extend(verts) + verts = thic_verts + else: + verts.extend(thic_verts) + faces = [] + #print 'deb:len1:', len1 #----------------------- + #print 'deb:verts:', verts #remi-todo----- why is this List inhomogene ---------- + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + + arc.verts.extend(verts) # add vertices to mesh + arc.faces.extend(faces) # add faces to the mesh + else: + arc.verts.extend(verts) # add vertices to mesh + arc.edges.extend(edges) # add edges to the mesh + + #arc.update() + #ob = SCENE.objects.new(arc) # create a new arc_object + #ob.link(arc) + ob.loc = tuple(center) + #ob.loc = Mathutils.Vector(ob.loc) + transform(self.extrusion, 0, ob) + #ob.size = (1,1,1) + return ob + + +class BlockRecord: #----------------------------------------------------------------- + """Class for objects representing dxf block_records. + """ + + def __init__(self, obj): + """Expects an entity object of type block_record as input. + """ + if not obj.type == 'block_record': + raise TypeError, "Wrong type %s for block_record object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.name = getit(obj, 2, None) + + # optional data (with defaults) + self.insertion_units = getit(obj, 70, None) + self.insert_units = getit(obj, 1070, None) + """code 1070 Einfügeeinheiten: + 0 = Keine Einheiten; 1 = Zoll; 2 = Fuß; 3 = Meilen; 4 = Millimeter; + 5 = Zentimeter; 6 = Meter; 7 = Kilometer; 8 = Mikrozoll; + 9 = Mils; 10 = Yard; 11 = Angstrom; 12 = Nanometer; + 13 = Mikrons; 14 = Dezimeter; 15 = Dekameter; + 16 = Hektometer; 17 = Gigameter; 18 = Astronomische Einheiten; + 19 = Lichtjahre; 20 = Parsecs + """ + + + def __repr__(self): + return "%s: name - %s, insert units - %s" %(self.__class__.__name__, self.name, self.insertion_units) + + + + +class Block: #----------------------------------------------------------------- + """Class for objects representing dxf blocks. + """ + + def __init__(self, obj): + """Expects an entity object of type block as input. + """ + if not obj.type == 'block': + raise TypeError, "Wrong type %s for block object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + self.name = obj.name + + # required data + self.flags = obj.get_type(70)[0] + self.entities = dxfObject('block_contents') #creates empty entities_container for this block + self.entities.data = objectify([ent for ent in obj.data if type(ent) != list]) + + # optional data (with defaults) + self.path = getit(obj, 1, '') + self.discription = getit(obj, 4, '') + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + + + def get_loc(self, data): + """Gets the insert point of the block. + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, None) # 10 = x + loc[1] = getit(data, 20, None) # 20 = y + loc[2] = getit(data, 30, 0.0) # 30 = z + return loc + + + def __repr__(self): + return "%s: name - %s, description - %s, xref-path - %s" %(self.__class__.__name__, self.name, self.discription, self.path) + + + + +class Insert: #----------------------------------------------------------------- + """Class for objects representing dxf inserts. + """ + + def __init__(self, obj): + """Expects an entity object of type insert as input. + """ + if not obj.type == 'insert': + raise TypeError, "Wrong type %s for insert object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.blockname = obj.get_type(2)[0] + + # optional data (with defaults) + self.rotation = getit(obj, 50, 0) + self.space = getit(obj, 67, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.scale = self.get_scale(obj.data) + self.rows, self.columns = self.get_array(obj.data) + self.extrusion = get_extrusion(obj.data) + + + + def get_loc(self, data): + """Gets the center location for block type objects. + """ + loc = [0, 0, 0] + loc[0] = getit(data, 10, 0.0) + loc[1] = getit(data, 20, 0.0) + loc[2] = getit(data, 30, 0.0) + return loc + + + + def get_scale(self, data): + """Gets the x/y/z scale factor for the block. + """ + scale = [1, 1, 1] + scale[0] = getit(data, 41, 1.0) + scale[1] = getit(data, 42, 1.0) + scale[2] = getit(data, 43, 1.0) + return scale + + + + def get_array(self, data): + """Returns the pair (row number, row spacing), (column number, column spacing). + """ + columns = getit(data, 70, 1) + rows = getit(data, 71, 1) + cspace = getit(data, 44, 0.0) + rspace = getit(data, 45, 0.0) + return (rows, rspace), (columns, cspace) + + + + def __repr__(self): + return "%s: layer - %s, blockname - %s" %(self.__class__.__name__, self.layer, self.blockname) + + + def draw(self, settings, deltaloc): + """for INSERT(block): draw empty-marker for duplicated Blender_Group. + + Blocks are made of three objects: + the block_record in the tables section + the block in the blocks section + the insert object in the entities section + + block_records give the insert units, blocks provide the objects drawn in the + block, and the insert object gives the location/scale/rotation of the block + instances. To draw a block you must first get a group with all the + blocks entities drawn in it, then scale the entities to match the world + units, then dupligroup that data to an object matching each insert object. + """ + + obname = 'in_%s' %self.blockname # create object name from block name + obname = obname[:MAX_NAMELENGTH] + + if settings.drawTypes['insert']: #if insert_drawType activated + ob = SCENE.objects.new('Empty', obname) # create a new empty_object + empty_size = 1.0 * settings.var['g_scale'] + if empty_size < 0.01: empty_size = 0.01 + elif empty_size > 10.0: empty_size = 10.0 + ob.drawSize = empty_size + + # get our block_def-group + block = settings.blocks(self.blockname) + ob.DupGroup = block + ob.enableDupGroup = True + + #print 'deb:draw.block.deltaloc:', deltaloc #-------------------- + ob.loc = tuple(self.loc) + if deltaloc: + deltaloc = rotXY_Vec(self.rotation, deltaloc) + #print 'deb:draw.block.loc:', deltaloc #-------------------- + ob.loc = [ob.loc[0]+deltaloc[0], ob.loc[1]+deltaloc[1], ob.loc[2]+deltaloc[2]] + transform(self.extrusion, self.rotation, ob) + ob.size = tuple(self.scale) + return ob + + + + +class Ellipse: #----------------------------------------------------------------- + """Class for objects representing dxf ellipses. + """ + + def __init__(self, obj): + """Expects an entity object of type ellipse as input. + """ + if not obj.type == 'ellipse': + raise TypeError, "Wrong type %s for ellipse object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # required data + self.ratio = obj.get_type(40)[0] + self.start_angle = obj.get_type(41)[0] + self.end_angle = obj.get_type(42)[0] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.thic = getit(obj, 39, 0.0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.loc = self.get_loc(obj.data) + self.major = self.get_major(obj.data) + self.extrusion = get_extrusion(obj.data) + self.radius = sqrt(self.major[0]**2 + self.major[0]**2 + self.major[0]**2) + + + def get_loc(self, data): + """Gets the center location for arc type objects. + + Arcs have a single coord location. + """ + loc = [0.0, 0.0, 0.0] + loc[0] = getit(data, 10, 0.0) + loc[1] = getit(data, 20, 0.0) + loc[2] = getit(data, 30, 0.0) + return loc + + + def get_major(self, data): + """Gets the major axis for ellipse type objects. + + The ellipse major axis defines the rotation of the ellipse and its radius. + """ + loc = [0.0, 0.0, 0.0] + loc[0] = getit(data, 11, 0.0) + loc[1] = getit(data, 21, 0.0) + loc[2] = getit(data, 31, 0.0) + return loc + + + def __repr__(self): + return "%s: layer - %s, radius - %s" %(self.__class__.__name__, self.layer, self.radius) + + + def draw(self, settings): + """for ELLIPSE: generate Blender_geometry. + """ + # Generate the geometery + center = self.loc + thic = set_thick(self.thic, settings) + + if settings.var['curves_on']: + ob = drawCurveArc(self) + else: + obname = 'el_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + + major = Mathutils.Vector(self.major) + #remi--todo----AngleBetweenVecs makes abs(value)!----- + delta = Mathutils.AngleBetweenVecs(major, WORLDX) + radius = major.length + start = degrees(self.start_angle) + end = degrees(self.end_angle) + + # set a number of segments in entire circle + arc_res = settings.var['arc_res'] * sqrt(radius) / sqrt(settings.var['arc_rad']) + verts, edges = drawArc(None, radius, start, end, arc_res) + + if thic != 0: + len1 = len(verts) + thic_verts = [] + thic_verts.extend([[point[0], point[1], point[2]+thic] for point in verts]) + if thic < 0.0: + thic_verts.extend(verts) + verts = thic_verts + else: + verts.extend(thic_verts) + faces = [] + #print 'deb:len1:', len1 #----------------------- + #print 'deb:verts:', verts #remi--todo----- why is this List inhomogene? ---------- + faces = [[num, num+1, num+len1+1, num+len1] for num in xrange(len1 - 1)] + + me.verts.extend(verts) # add vertices to mesh + me.faces.extend(faces) # add faces to the mesh + else: + me.verts.extend(verts) # add vertices to mesh + me.edges.extend(edges) # add edges to the mesh + + ob.loc = tuple(center) + ob.SizeY = self.ratio + transform(self.extrusion, 0, ob) + + return ob + + + +class Face: #----------------------------------------------------------------- + """Class for objects representing dxf 3d faces. + """ + + def __init__(self, obj): + """Expects an entity object of type 3dfaceplot as input. + """ + if not obj.type == '3dface': + raise TypeError, "Wrong type %s for 3dface object!" %obj.type + self.type = obj.type + self.data = obj.data[:] + + # optional data (with defaults) + self.space = getit(obj, 67, 0) + self.color_index = getit(obj, 62, BYLAYER) + + self.layer = getit(obj.data, 8, None) + self.points = self.get_points(obj.data) + + + def get_points(self, data): + """Gets 3-4 points for a 3d face type object. + + Faces have three or optionally four verts. + """ + a = [0, 0, 0] + b = [0, 0, 0] + c = [0, 0, 0] + d = [0, 0, 0] + a[0] = getit(data, 10, None) # 10 = x + a[1] = getit(data, 20, None) # 20 = y + a[2] = getit(data, 30, 0.0) # 30 = z + b[0] = getit(data, 11, None) + b[1] = getit(data, 21, None) + b[2] = getit(data, 31, 0.0) + c[0] = getit(data, 12, None) + c[1] = getit(data, 22, None) + c[2] = getit(data, 32, 0.0) + out = [a,b,c] + + d[0] = getit(data, 13, None) + if d[0] != None: + d[1] = getit(data, 23, None) + d[2] = getit(data, 33, 0.0) + out.append(d) + + #if len(out) < 4: print '3dface with only 3 vertices:\n',a,b,c,d #----------------- + return out + + + def __repr__(self): + return "%s: layer - %s, points - %s" %(self.__class__.__name__, self.layer, self.points) + + + def draw(self, settings): + """for 3DFACE: generate Blender_geometry. + """ + # Generate the geometery + points = self.points + + global activObjectLayer + global activObjectName + #print 'deb:draw:face.ob IN activObjectName: ', activObjectName #--------------------- + + if activObjectLayer == self.layer and settings.var['one_mesh_on']: + obname = activObjectName + #print 'deb:face.draw obname from activObjectName: ', obname #--------------------- + ob = Object.Get(obname) # open an existing mesh_object + #ob = SCENE.getChildren(obname) # open an existing mesh_object + else: + obname = 'fa_%s' %self.layer # create object name from layer name + obname = obname[:MAX_NAMELENGTH] + me = Mesh.New(obname) # create a new mesh + ob = SCENE.objects.new(me) # create a new mesh_object + activObjectName = ob.name + activObjectLayer = self.layer + #print ('deb:except. new face.ob+mesh:"%s" created!' %ob.name) #--------------------- + + me = Mesh.Get(ob.name) # open objects mesh data + faces, edges = [], [] + n = len(me.verts) + if len(self.points) == 4: + faces = [[0+n,1+n,2+n,3+n]] + elif len(self.points) == 3: + faces = [[0+n,1+n,2+n]] + elif len(self.points) == 2: + edges = [[0+n,1+n]] + + me.verts.extend(points) # add vertices to mesh + if faces: me.faces.extend(faces) # add faces to the mesh + if edges: me.edges.extend(edges) # add faces to the mesh + if settings.var['vGroup_on']: + # entities with the same color build one vertexGroup for easier material assignment --------------------- + ob.link(me) # link mesh to that object + vG_name = 'color_%s' %self.color_index + if edges: faces = edges + replace = Blender.Mesh.AssignModes.ADD #or .AssignModes.REPLACE or ADD + try: + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: existed vGroup:', vG_name #--------------------- + except: + me.addVertGroup(vG_name) + me.assignVertsToGroup(vG_name, faces[0], 1.0, replace) + #print 'deb: create new vGroup:', vG_name #-------------------- + + #print 'deb:draw:face.ob OUT activObjectName: ', activObjectName #--------------------- + return ob + + +#--------------------------------------------------------------------------------------- +# type to object maping (sorted-dictionary for f_obiectify ONLY!, format={'key':Class} ) +type_map = { + 'layer':Layer, + 'block_record':BlockRecord, + 'block':Block, + 'insert':Insert, + 'point':Point, + '3dface':Face, + 'line':Line, +# 'mline':MLine, + 'polyline':Polyline, + 'lwpolyline':LWpolyline, +# 'region':Region, + 'trace':Solid, + 'solid':Solid, + 'text':Text, + 'mtext':Mtext, + 'circle':Circle, + 'ellipse':Ellipse, + 'arc':Arc +} + + + +def objectify(data): #----------------------------------------------------------------- + """Expects a section type object's data as input. + + Maps object data to the correct object type. + """ + #print 'deb:objectify start %%%%%%%%%%%' #--------------- + objects = [] # colector for finished objects + known_types = type_map.keys() # so we don't have to call foo.keys() every iteration + curves_on = GUI_A['curves_on'].val + index = 0 + while index < len(data): + item = data[index] + #print 'deb:objectify item: \n', item #------------ + if type(item) != list and item.type == 'table': + item.data = objectify(item.data) # tables have sub-objects + objects.append(item) + elif type(item) != list and item.type == 'polyline': #remi --todo----------- + #print 'deb:gosub Polyline\n' #------------- + pline = Polyline(item) + while 1: + index += 1 + item = data[index] + if item.type == 'vertex': + #print 'deb:objectify gosub Vertex--------' #------------- + v = Vertex(item) + if pline.spline: # Bspline-curve + # then for Blender-mesh filter only additional_vertices + # OR + # then for Blender-curve filter only spline_control_vertices + if (v.spline and not curves_on) or (curves_on and v.splin2): #correct for real NURBS-import + #if (v.spline and not curves_on) or (curves_on and not v.splin2): #fake for Bezier-emulation of NURBS-import + pline.points.append(v) + elif pline.curved: # Bezier-curve + # then for Blender-mesh filter only curve_additional_vertices + # OR + # then for Blender-curve filter curve_control_vertices + if not curves_on or (curves_on and not v.curved): + pline.points.append(v) + else: + pline.points.append(v) + elif item.type == 'seqend': + #print 'deb:objectify it is seqEND ---------\n' #------------- + break + else: + print "Error: non-vertex found before seqend!" + index -= 1 #so go back one step + break + objects.append(pline) + elif type(item) != list and item.type in known_types: + # proccess the object and append the resulting object + objects.append(type_map[item.type](item)) + else: + # we will just let the data pass un-harrased + objects.append(item) + index += 1 + #print 'deb:objectify objects:\n', objects #------------ + #print 'deb:objectify END %%%%%%%%' #------------ + return objects + + + +class MatColors: #----------------------------------------------------------------- + """A smart container for dxf-color based materials. + + This class is a wrapper around a dictionary mapping dxf-color indicies to materials. + When called with a color index it returns a material corrisponding to that index. + Behind the scenes it checks if that index is in its keys, and if not it creates + a new material. It then adds the new index:material pair to its dict and returns + the material. + """ + + def __init__(self, map): + """Expects a map - a dictionary mapping layer names to layers. + """ + self.map = map # a dictionary of layername:layer + self.colMaterials = {} # a dictionary of color_index:blender_material + #print 'deb:init_MatColors argument.map: ', map #------------------ + + + def __call__(self, color=None): + """Return the material associated with color. + + If a layer name is provided, the color of that layer is used. + """ + if not color: + color = 0 + if type(color) == str: + #print 'deb:color is string:--------------: ', color #--todo---bug with ARC from ARC-T0.DXF layer="T-3DARC-1"----- + try: + color = self.map[color].color + #print 'deb:color=self.map[color].color:', color #------------------ + except KeyError: + layer = Layer(name=color, color=0, frozen=False) + self.map[color] = layer + color = 0 + color = abs(color) + if color not in self.colMaterials.keys(): + self.add(color) + return self.colMaterials[color] + + + def add(self, color): + """Create a new material 'ColorNr-N' using the provided color index-N. + """ + global color_map + mat = Material.New('ColorNr-%s' %color) + mat.setRGBCol(color_map[color]) + mat.mode |= Material.Modes.SHADELESS + mat.mode |= Material.Modes.WIRE +# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug +# except: pass + self.colMaterials[color] = mat + + + +class MatLayers: #----------------------------------------------------------------- + """A smart container for dxf-layer based materials. + + This class is a wrapper around a dictionary mapping dxf-layer names to materials. + When called with a layer name it returns a material corrisponding to that. + Behind the scenes it checks if that layername is in its keys, and if not it creates + a new material. It then adds the new layername:material pair to its dict and returns + the material. + """ + + def __init__(self, map): + """Expects a map - a dictionary mapping layer names to layers. + """ + self.map = map # a dictionary of layername:layer + self.layMaterials = {} # a dictionary of layer_name:blender_material + #print 'deb:init_MatLayers argument.map: ', map #------------------ + + + def __call__(self, layername=None): + """Return the material associated with dxf-layer. + + If a dxf-layername is not provided, create a new material + """ + if layername not in self.layMaterials.keys(): + self.add(layername) + return self.layMaterials[layername] + + + def add(self, layername): + """Create a new material 'layername'. + """ + try: mat = Material.Get('Lay-%s' %layername) + except: mat = Material.New('Lay-%s' %layername) + #print 'deb:MatLayers material: ', mat #---------- + #print 'deb:MatLayers getMode: ', mat.getMode() #---------- + global layersmap + color = layersmap[layername].color + #print 'deb:MatLayers layer_color: ', color #----------- + global color_map + mat.setRGBCol(color_map[color]) + mat.mode |= Material.Modes.SHADELESS + mat.mode |= Material.Modes.WIRE +# try: mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc-bug +# except: pass + self.layMaterials[layername] = mat + + + + +class Blocks: #----------------------------------------------------------------- + """A smart container for blocks. + + This class is a wrapper around a dictionary mapping block names to Blender data blocks. + When called with a name string it returns a block corresponding to that name. + Behind the scenes it checks if that name is in its keys, and if not it creates + a new data block. It then adds the new name:block_data pair to its dict and returns + the block. + """ + + def __init__(self, blocksmap, settings): + """Expects a dictionary mapping block_name:block_data. + """ + self.blocksmap = blocksmap #a dictionary mapping block_name:block_data + self.settings = settings + self.blocks = {} #container for blocks + + + def __call__(self, name=None): + """Return the data block associated with that block_name. + + If that name is not in its keys, it creates a new data block. + If no name is provided return entire self.blocks container. + """ + if not name: + return self.blocks + if name not in self.blocks.keys(): + self.addBlock(name) + return self.blocks[name] + + + def addBlock(self, name): + """Create a new 'block group' for the block name. + """ + block_def = Group.New('bl_%s' %name) # groupObject contains definition of BLOCK + block = self.blocksmap[name] + self.settings.write("\nDrawing block:\'%s\' ..." % name) + drawEntities(block.entities, self.settings, block_def) + self.settings.write("Drawing block:\'%s\' done!" %name) + self.blocks[name] = block_def + + + + + +class Settings: #----------------------------------------------------------------- + """A container for all the import settings and objects used by the draw functions. + + This is like a collection of globally accessable persistant properties and functions. + """ + # Optimization constants + MIN = 0 + MID = 1 + PRO = 2 + MAX = 3 + + def __init__(self, keywords, drawTypes): + """initialize all the important settings used by the draw functions. + """ + self.obj_number = 1 #global object_number for progress_bar + + self.var = dict(keywords) #a dictionary of (key_variable:Value) control parameter + self.drawTypes = dict(drawTypes) #a dictionary of (entity_type:True/False) = import on/off for this entity_type + + self.var['colorFilter_on'] = False #deb:remi------------ + self.acceptedColors = [0,2,3,4,5,6,7,8,9, + 10 ] + + self.var['layerFilter_on'] = False #deb:remi------------ + self.acceptedLayers = ['3', + '0' + ] + + self.var['blockFilter_on'] = False #deb:remi------------ + self.acceptedBlocks = ['BOX01', + 'BOX02' + ] + + + def update(self, keywords, drawTypes): + """update all the important settings used by the draw functions. + """ + + for k, v in keywords.iteritems(): + self.var[k] = v + #print 'deb:settings_update var %s= %s' %(k, self.var[k]) #-------------- + for t, v in drawTypes.iteritems(): + self.drawTypes[t] = v + #print 'deb:settings_update drawType %s= %s' %(t, self.drawTypes[t]) #-------------- + + #print 'deb:self.drawTypes', self.drawTypes #--------------- + + + def validate(self, drawing): + """Given the drawing, build dictionaries of Layers, Colors and Blocks. + """ + + #de: paßt die distance parameter an globalScale + if self.var['g_scale'] != 1: + self.var['dist_min'] = self.var['dist_min'] / self.var['g_scale'] + self.var['thick_min'] = self.var['thick_min'] / self.var['g_scale'] + self.var['width_min'] = self.var['width_min'] / self.var['g_scale'] + + # First sort out all the section_items + sections = dict([(item.name, item) for item in drawing.data]) + + # The section:header may be omited + if 'header' in sections.keys(): + self.write("Found section:header!") + else: + self.write("File contains no section:header!") + + # The section:tables may be partialy or completely missing. + self.layersTable = False + self.colMaterials = MatColors({}) + self.layMaterials = MatLayers({}) + if 'tables' in sections.keys(): + self.write("Found section:tables!") + # First sort out all the tables + tables = dict([(item.name, item) for item in sections["tables"].data]) + if 'layer' in tables.keys(): + self.write("Found table:layers!") + self.layersTable = True + # Read the layers table and get the layer colors + global layersmap + layersmap = getLayersmap(drawing) + self.colMaterials = MatColors(layersmap) + self.layMaterials = MatLayers(layersmap) + else: + self.write("File contains no table:layers!") + else: + self.write("File contains no section:tables!") + self.write("File contains no table:layers!") + + # The section:blocks may be omited + if 'blocks' in sections.keys(): + self.write("Found section:blocks!") + # Read the block definitions and build our block object + if self.drawTypes['insert']: #if drawing of type 'Insert' activated + blocksmap, self.obj_number = getBlocksmap(drawing) #Build a dictionary of blockname:block_data pairs + self.blocks = Blocks(blocksmap, self) # initiates container for blocks_data + + #print 'deb: self.obj_number', self.obj_number #---------- + else: + self.write("File contains no section:blocks!") + self.drawTypes['insert'] = False + + # The section:entities + if 'entities' in sections.keys(): + self.write("Found section:entities!") + + self.obj_number += len(drawing.entities.data) + #print 'deb: self.obj_number', self.obj_number #---------- + self.obj_number = 1.0 / self.obj_number + + + def write(self, text, newline=True): + """Wraps the built-in print command in a optimization check. + """ + if self.var['optimization'] <= self.MID: + if newline: + print text + else: + print text, + + + def redraw(self): + """Update Blender if optimization level is low enough. + """ + if self.var['optimization'] <= self.MIN: + Blender.Redraw() + + + def progress(self, done, text): + """Wrapper for Blender.Window.DrawProgressBar. + """ + if self.var['optimization'] <= self.PRO: + progressbar = done * self.obj_number + Window.DrawProgressBar(progressbar, text) + #print 'deb:drawer done, progressbar: ', done, progressbar #----------------------- + + + def layer_isOff(self, name): + """Given a layer name, and return its visible status. + """ + # colors are negative if layer is off + try: + #print 'deb:layer_isOff self.colMaterials.map:\n', self.colMaterials.map #-------------- + layer = self.colMaterials.map[name] + except KeyError: return False + if layer.color < 0: return True + #print 'deb:layer_isOff: layer is ON' #--------------- + return False + + + def layer_isFrozen(self, name): + """Given a layer name, and return its frozen status. + """ + # colors are negative if layer is off + try: + #print 'deb:layer_isFrozen self.colMaterials.map:\n', self.colMaterials.map #--------------- + layer = self.colMaterials.map[name] + except KeyError: return False + if layer.frozen: return True + #print 'deb:layer_isFrozen: layer is not FROZEN' #--------------- + return False + + + + +def main(dxfFile): #---------------#############################----------- + #print 'deb:filename:', filename #-------------- + global SCENE + editmode = Window.EditMode() # are we in edit mode? If so ... + if editmode: + Window.EditMode(0) # leave edit mode before + + #SCENE = bpy.data.scenes.active + #SCENE.objects.selected = [] # deselect all + + global cur_COUNTER #counter for progress_bar + cur_COUNTER = 0 + + try: + print "Getting settings..." + global GUI_A, GUI_B + if GUI_A['g_scale_on'].val: + GUI_A['g_scale'].val = 10.0 ** int(GUI_A['g_scale_as'].val) + else: + GUI_A['g_scale'].val = 1.0 + + keywords = {} + drawTypes = {} + for k, v in GUI_A.iteritems(): + keywords[k] = v.val + for k, v in GUI_B.iteritems(): + drawTypes[k] = v.val + #print 'deb:startUInew keywords: ', keywords #-------------- + #print 'deb:startUInew drawTypes: ', drawTypes #-------------- + + # The settings object controls how dxf entities are drawn + settings.update(keywords, drawTypes) + #print 'deb:settings.var:\n', settings.var #----------------------- + + if not settings: + #Draw.PupMenu('DXF importer: EXIT!%t') + print '\nDXF Import: terminated by user!' + Window.WaitCursor(False) + if editmode: Window.EditMode(1) # and put things back how we fond them + return None + + #no more used dxfFile = dxfFileName.val + #print 'deb: dxfFile file: ', dxfFile #---------------------- + if dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): + Window.WaitCursor(True) # Let the user know we are thinking + print 'start reading DXF file: %s.' % dxfFile + time1 = Blender.sys.time() #time marker1 + drawing = readDXF(dxfFile, objectify) + print 'finished reading DXF file in %.4f sec.' % (Blender.sys.time()-time1) + Window.WaitCursor(False) + else: + if UI_MODE: Draw.PupMenu('DXF importer: EXIT----------!%t| no valid DXF-file selected!') + print "DXF importer: error, no DXF-file selected. Abort!" + Window.WaitCursor(False) + if editmode: Window.EditMode(1) # and put things back how we fond them + return None + + settings.validate(drawing) + + Window.WaitCursor(True) # Let the user know we are thinking + settings.write("\n\nDrawing entities...") + + # Draw all the know entity types in the current scene + global oblist + oblist = [] # a list of all created AND linked objects for final f_globalScale + time2 = Blender.sys.time() #time marker2 + + drawEntities(drawing.entities, settings) + + #print 'deb:drawEntities after: oblist:', oblist #----------------------- + if oblist: # and settings.var['g_scale'] != 1: + globalScale(oblist, settings.var['g_scale']) + + # Set the visable layers + SCENE.setLayers([i+1 for i in range(18)]) + SCENE.update(1) + #Blender.Redraw(-1) + SCENE.objects.selected = [i[0] for i in oblist] #select only the imported objects + #SCENE.objects.selected = SCENE.objects #select all objects in current scene + Blender.Redraw() + + time_text = Blender.sys.time() - time2 + Window.WaitCursor(False) + message = 'DXF Import to Blender: done in %.4f sec. --------------------' % time_text + settings.progress(1.0/settings.obj_number, 'DXF import done!') + print message + #settings.write(message) + if UI_MODE: Draw.PupMenu('DXF importer: Done!|finished in %.4f sec.' % time_text) + + finally: + # restore state even if things didn't work + #print 'deb:drawEntities finally!' #----------------------- + Window.WaitCursor(False) + if editmode: Window.EditMode(1) # and put things back how we fond them + + + +def getOCS(az): #----------------------------------------------------------------- + """An implimentation of the Arbitrary Axis Algorithm. + """ + #decide if we need to transform our coords + if az[0] == 0 and az[1] == 0: + return False + #elif abs(az[0]) < 0.0001 and abs(az[1]) < 0.0001: + # return False + + az = Mathutils.Vector(az) + + cap = 0.015625 # square polar cap value (1/64.0) + if abs(az.x) < cap and abs(az.y) < cap: + ax = Mathutils.CrossVecs(WORLDY, az) + else: + ax = Mathutils.CrossVecs(WORLDZ, az) + ax = ax.normalize() + ay = Mathutils.CrossVecs(az, ax) + ay = ay.normalize() + return ax, ay, az + + + +def transform(normal, rotation, obj): #-------------------------------------------- + """Use the calculated ocs to determine the objects location/orientation in space. + + Quote from dxf docs: + The elevation value stored with an entity and output in DXF files is a sum + of the Z-coordinate difference between the UCS XY plane and the OCS XY + plane, and the elevation value that the user specified at the time the entity + was drawn. + """ + ma = Mathutils.Matrix([1,0,0],[0,1,0],[0,0,1]) + o = Mathutils.Vector(obj.loc) + ocs = getOCS(normal) + if ocs: + ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2]) + o = ma.invert() * o + ma = Mathutils.Matrix(ocs[0], ocs[1], ocs[2]) + + if rotation != 0: + g = radians(-rotation) + rmat = Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1]) + ma = rmat * ma + + obj.setMatrix(ma) + obj.loc = o + #print 'deb:new obj.matrix:\n', obj.getMatrix() #-------------------- + + + +def rotXY_Vec(rotation, vec): #---------------------------------------------------- + """Rotate vector vec in XY-plane. vec must be in radians + """ + if rotation != 0: + o = Mathutils.Vector(vec) + g = radians(-rotation) + vec = o * Mathutils.Matrix([cos(g), -sin(g), 0], [sin(g), cos(g), 0], [0, 0, 1]) + return vec + + + +def getLayersmap(drawing): #------------------------------------------------------ + """Build a dictionary of layername:layer pairs for the given drawing. + """ + tables = drawing.tables + for table in tables.data: + if table.name == 'layer': + layers = table + break + layersmap = {} + for item in layers.data: + if type(item) != list and item.type == 'layer': + layersmap[item.name] = item + return layersmap + + + +def getBlocksmap(drawing): #-------------------------------------------------------- + """Build a dictionary of blockname:block_data pairs for the given drawing. + """ + blocksmap = {} + obj_number = 0 + for item in drawing.blocks.data: + #print 'deb:getBlocksmap item=' ,item #-------- + #print 'deb:getBlocksmap item.entities=' ,item.entities #-------- + #print 'deb:getBlocksmap item.entities.data=' ,item.entities.data #-------- + if type(item) != list and item.type == 'block': + obj_number += len(item.entities.data) + try: + blocksmap[item.name] = item + except KeyError: + # annon block + print 'Cannot map "%s" - "%s" as Block!' %(item.name, item) + return blocksmap, obj_number + + + + + +def drawEntities(entities, settings, block_def=None): #---------------------------------------- + """Draw every kind of thing in the entity list. + + If provided 'block_def': the entities are to be added to the Blender 'group'. + """ + for _type in type_map.keys(): + #print 'deb:drawEntities_type:', _type #------------------ + # for each known type get a list of that type and call the associated draw function + drawer(_type, entities.get_type(_type), settings, block_def) + + +def drawer(_type, entities, settings, block_def): #------------------------------------------ + """Call with a list of entities and a settings object to generate Blender geometry. + + If 'block_def': the entities are to be added to the Blender 'group'. + """ + if entities: + # Break out early if settings says we aren't drawing the current dxf-type + global cur_COUNTER #counter for progress_bar + group = None + #print 'deb:drawer.check:_type: ', _type #-------------------- + if _type == '3dface':_type = 'face' # hack, while python_variable_name can not beginn with a nummber + if not settings.drawTypes[_type] or _type == 'block_record': + message = 'Skipping dxf\'%ss\' entities' %_type + settings.write(message, True) + cur_COUNTER += len(entities) + settings.progress(cur_COUNTER, message) + return + #print 'deb:drawer.todo:_type:', _type #----------------------- + + len_temp = len(entities) + # filtering only model-space enitities (no paper-space enitities) + entities = [entity for entity in entities if entity.space == 0] + + # filtering only objects with color from acceptedColorsList + if settings.var['colorFilter_on']: + entities = [entity for entity in entities if entity.color in settings.acceptedColors] + + # filtering only objects on layers from acceptedLayersList + if settings.var['layerFilter_on']: +# entities = [entity for entity in entities if entity.layer[0] in ['M','3','0'] and not entity.layer.endswith('H')] + entities = [entity for entity in entities if entity.layer in settings.acceptedLayers] + + # filtering only objects on not-frozen layers + entities = [entity for entity in entities if not settings.layer_isFrozen(entity.layer)] + + global activObjectLayer, activObjectName + activObjectLayer = '' + activObjectName = '' + + message = "Drawing dxf\'%ss\'..." %_type + cur_COUNTER += len_temp - len(entities) + settings.write(message, False) + settings.progress(cur_COUNTER, message) + if len(entities) > 0.1 / settings.obj_number: + show_progress = int(0.03 / settings.obj_number) + else: show_progress = 0 + cur_temp = 0 + + #print 'deb:drawer cur_COUNTER: ', cur_COUNTER #----------------------- + + for entity in entities: #----loop------------------------------------- + settings.write('\b.', False) + cur_COUNTER += 1 + if show_progress: + cur_temp += 1 + if cur_temp == show_progress: + settings.progress(cur_COUNTER, message) + cur_temp = 0 + #print 'deb:drawer show_progress=',show_progress #----------------------- + + # get the layer group (just to make things a little cleaner) + if settings.var['group_bylayer_on'] and not block_def: + group = getGroup('l:%s' % entity.layer[:MAX_NAMELENGTH-2]) + + if _type == 'insert': #---- INSERT and MINSERT=array ------------------------ + #print 'deb:insert entity.loc:', entity.loc #---------------- + columns = entity.columns[0] + coldist = entity.columns[1] + rows = entity.rows[0] + rowdist = entity.rows[1] + deltaloc = [0,0,0] + #print 'deb:insert columns, rows:', columns, rows #----------- + for col in xrange(columns): + deltaloc[0] = col * coldist + for row in xrange(rows): + deltaloc[1] = row * rowdist + #print 'deb:insert col=%s, row=%s,deltaloc=%s' %(col, row, deltaloc) #------ + ob = entity.draw(settings, deltaloc) #-----draw BLOCK---------- + setObjectProperties(ob, group, entity, settings, block_def) + if ob: + if settings.var['optimization'] <= settings.MIN: + if settings.var['g_scale'] != 1: globalScaleOne(ob, True, settings.var['g_scale']) + settings.redraw() + else: oblist.append((ob, True)) + + else: #---draw entities except BLOCKs/INSERTs--------------------- + alt_obname = activObjectName + ob = entity.draw(settings) + if ob and ob.name != alt_obname: + setObjectProperties(ob, group, entity, settings, block_def) + if settings.var['optimization'] <= settings.MIN: + if settings.var['g_scale'] != 1: globalScaleOne(ob, False, settings.var['g_scale']) + settings.redraw() + else: oblist.append((ob, False)) + + #print 'deb:Finished drawing:', entities[0].type #------------------------ + message = "\nDrawing dxf\'%ss\' done!" % _type + settings.write(message, True) + + + +def globalScale(oblist, SCALE): #--------------------------------------------------------- + """Global_scale for list of all imported objects. + + oblist is a list of pairs (ob, insertFlag), where insertFlag=True/False + """ + #print 'deb:globalScale.oblist: ---------%\n', oblist #--------------------- + for l in oblist: + ob, insertFlag = l[0], l[1] + globalScaleOne(ob, insertFlag, SCALE) + + +def globalScaleOne(ob, insertFlag, SCALE): #--------------------------------------------------------- + """Global_scale imported object. + """ + #print 'deb:globalScaleOne ob: ', ob #--------------------- + SCALE_MAT= Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1]) + if insertFlag: # by BLOCKs/INSERTs only insert-point must be scaled------------ + ob.loc = Mathutils.Vector(ob.loc) * SCALE_MAT + else: # entire scaling for all other imported objects ------------ + ob.setMatrix(ob.matrixWorld*SCALE_MAT) + + + +def setObjectProperties(ob, group, entity, settings, block_def): #----------------------- + """Link object to scene. + """ + + if not ob: #remi--todo----------------------- + message = "\nObject \'%s\' not found!" %entity + settings.write(message) + return + + if group: + setGroup(group, ob) # if object belongs to group + + if block_def: # if object belongs to BLOCK_def - Move it to layer nr19 + setGroup(block_def, ob) + #print 'deb:setObjectProperties \'%s\' set to block_def_group!' %ob.name #--------- + ob.layers = [19] + else: + #ob.layers = [i+1 for i in xrange(20)] #remi--todo------------ + ob.layers = [settings.var['target_layer']] + + # Set material for any objects except empties + if ob.type != 'Empty': + setMaterial_from(entity, ob, settings, block_def) + + # Set the visibility + if settings.layer_isOff(entity.layer): + #ob.layers = [20] #remi--todo------------- + ob.restrictDisplay = True + ob.restrictRender = True + + #print 'deb:\n---------linking Object %s!' %ob.name #---------- + + + +def getGroup(name): #----------------------------------------------------------------- + """Returns a Blender group-object. + """ + try: + group = Group.Get(name) + except: # What is the exception? + group = Group.New(name) + return group + + +def setGroup(group, ob): #------------------------------------------------------------ + """Assigns object to Blender group. + """ + try: + group.objects.link(ob) + except: + group.objects.append(ob) #remi?--------------- + + + +def setMaterial_from(entity, ob, settings, block_def): #------------------------------------------------ + """ Set Blender-material for the object controled by item. + + Set Blender-material for the object + - controlled by settings.var['material_from'] + """ + if settings.var['material_from'] == 1: # 1= material from color + if entity.color_index == BYLAYER: + mat = settings.colMaterials(entity.layer) + else: + mat = settings.colMaterials(entity.color_index) + elif settings.var['material_from'] == 2: # 2= material from layer + mat = settings.layMaterials(entity.layer) +# elif settings.var['material_from'] == 3: # 3= material from layer+color +# mat = settings.layMaterials(entity.layer) +# color = entity.color_index +# if type(color) == int: +# mat.setRGBCol(color_map[abs(color)]) +# elif settings.var['material_from'] == 4: # 4= material from block +# elif settings.var['material_from'] == 5: # 5= material from INI-file + else: # set neutral material + try: + mat = Material.Get('dxf-neutral') + except: + mat = Material.New('dxf-neutral') + mat.mode |= Material.Modes.SHADELESS + mat.mode |= Material.Modes.WIRE +# try:mat.setMode('Shadeless', 'Wire') #work-around for 2.45rc1-bug +# except: pass + try: + #print 'deb:material mat:', mat #----------- + ob.setMaterials([mat]) #assigns Blender-material to object + except ValueError: + settings.write("material error - \'%s\'!" %mat) + ob.colbits = 0x01 # Set OB materials. + + + +def drawBulge(p1, p2, arc_res, curve_on=False): #------------------------------------------------- + """return the center, radius, start angle, and end angle given two points. + + Needs to take into account bulge sign. + negative = clockwise + positive = counter-clockwise + + to find center given two points, and arc angle + calculate radius + Cord = sqrt(start^2 + end^2) + S = (bulge*Cord)/2 + radius = ((Cord/2)^2+S^2)/2*S + angle of arc = 4*atan( bulge ) + angle from p1 to center is (180-angle)/2 + get vector pointing from p1 to p2 (p2 - p1) + normalize it and multiply by radius + rotate around p1 by angle to center, point to center. + start angle = angle between (center - p1) and worldX + end angle = angle between (center - p2) and worldX + """ + + bulge = p1.bulge + p2 = Mathutils.Vector(p2.loc) + p1 = Mathutils.Vector(p1.loc) + cord = p2 - p1 # vector from p1 to p2 + clength = cord.length + s = (bulge * clength)/2.0 # sagitta (height) + radius = abs(((clength/2.0)**2.0 + s**2.0)/(2.0*s)) # magic formula + angle = (degrees(4.0*atan(bulge))) # theta (included angle) + if curve_on: + verts_num = 8 + else: + verts_num = arc_res * sqrt(radius) # set a number of segments in entire circle + if verts_num > 1024: verts_num = 1024 # Blender accepts only values [3:500] + if verts_num < 4: verts_num = 4 # Blender accepts only values [3:500] + pieces = int(abs(angle)/(360.0/verts_num)) + if pieces < 3: pieces = 3 #bulge under arc_resolution + #if pieces < 3: points = [p1, p2] ;return points + step = angle/pieces # set step so pieces * step = degrees in arc + delta = (180.0 - abs(angle))/2.0 # the angle from cord to center + if bulge < 0: delta = -delta + radial = cord.normalize() * radius # a radius length vector aligned with cord + rmat = Mathutils.RotationMatrix(-delta, 3, 'Z') + center = p1 + (rmat * radial) # rotate radial by delta degrees, then add to p1 to find center + #length = radians(abs(angle)) * radius + #print 'deb:drawBulge:\n angle, delta: ', angle, delta #---------------- + #print 'deb:center, radius: ', center, radius #---------------------- + + startpoint = p1 - center + #endpoint = p2 - center + stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") + points = [startpoint] + point = Mathutils.Vector(startpoint) + for i in xrange(int(pieces)-1): #fast (but not so acurate as: vector * RotMatrix(step * i) + point = stepmatrix * point + points.append(point) + points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points] + return points + + + +def drawArc(center, radius, start, end, arc_res): #----------------------------------------- + """Draw a mesh arc with the given parameters. + """ + # center is currently set by object + # if start > end: start = start - 360 + if end > 360: end = end%360.0 + + startmatrix = Mathutils.RotationMatrix(-start, 3, "Z") + startpoint = startmatrix * Mathutils.Vector(radius, 0, 0) + endmatrix = Mathutils.RotationMatrix(-end, 3, "Z") + endpoint = endmatrix * Mathutils.Vector(radius, 0, 0) + + if end < start: end +=360.0 + angle = end - start + #length = radians(angle) * radius + + #if radius < MIN_DIST * 10: # if circumfence is too small + if arc_res > 1024: arc_res = 1024 + if arc_res < 4: arc_res = 4 + pieces = int(abs(angle)/(360.0/arc_res)) # set a fixed step of ARC_RESOLUTION + if pieces < 3: pieces = 3 #cambo----- + step = angle/pieces # set step so pieces * step = degrees in arc + + stepmatrix = Mathutils.RotationMatrix(-step, 3, "Z") + points = [startpoint] + point = Mathutils.Vector(startpoint) + for i in xrange(int(pieces)): + point = stepmatrix * point + points.append(point) + points.append(endpoint) + + if center: + points = [[point[0]+center[0], point[1]+center[1], point[2]+center[2]] for point in points] + edges = [[num, num+1] for num in xrange(len(points)-1)] + + return points, edges + + + +def drawCurveCircle(circle): #--- no more used -------------------------------------------- + """Given a dxf circle object return a blender circle object using curves. + """ + c = Curve.New('circle') # create new curve data + center = circle.loc + radius = circle.radius + + p1 = (0, -radius, 0) + p2 = (radius, 0, 0) + p3 = (0, radius, 0) + p4 = (-radius, 0, 0) + + p1 = BezTriple.New(p1) + p2 = BezTriple.New(p2) + p3 = BezTriple.New(p3) + p4 = BezTriple.New(p4) + + curve = c.appendNurb(p1) + curve.append(p2) + curve.append(p3) + curve.append(p4) + for point in curve: + point.handleTypes = [AUTO, AUTO] + curve.flagU = 1 # Set curve cyclic + c.update() + + ob = Object.New('Curve', 'circle') # make curve object + return ob + + +def drawCurveArc(self): #---- only for ELLIPSE ------------------------------------------------------------- + """Given a dxf ELLIPSE object return a blender_curve. + """ + center = self.loc + radius = self.radius + start = self.start_angle + end = self.end_angle + + if start > end: + start = start - 360.0 + startmatrix = Mathutils.RotationMatrix(start, 3, "Z") + startpoint = startmatrix * Mathutils.Vector((radius, 0, 0)) + endmatrix = Mathutils.RotationMatrix(end, 3, "Z") + endpoint = endmatrix * Mathutils.Vector((radius, 0, 0)) + # Note: handles must be tangent to arc and of correct length... + + a = Curve.New('arc') # create new curve data + + p1 = (0, -radius, 0) + p2 = (radius, 0, 0) + p3 = (0, radius, 0) + p4 = (-radius, 0, 0) + + p1 = BezTriple.New(p1) + p2 = BezTriple.New(p2) + p3 = BezTriple.New(p3) + p4 = BezTriple.New(p4) + + curve = a.appendNurb(p1) + curve.append(p2) + curve.append(p3) + curve.append(p4) + for point in curve: + point.handleTypes = [AUTO, AUTO] + curve.flagU = 1 # Set curve cyclic + a.update() + + ob = Object.New('Curve', 'arc') # make curve object + return ob + + + + +# GUI STUFF -----#################################################----------------- +from Blender.BGL import * + +EVENT_NONE = 1 +EVENT_START = 2 +EVENT_REDRAW = 3 +EVENT_LOAD_INI = 4 +EVENT_SAVE_INI = 5 +EVENT_PRESET = 6 +EVENT_CHOOSE_INI = 7 +EVENT_CHOOSE_DXF = 8 +EVENT_HELP = 9 +EVENT_CONFIG = 10 +EVENT_PRESETS = 11 +EVENT_DXF_DIR = 12 +EVENT_PRESET2D = 20 +EVENT_EXIT = 100 +GUI_EVENT = EVENT_NONE + +GUI_A = {} # GUI-buttons dictionary for parameter +GUI_B = {} # GUI-buttons dictionary for drawingTypes + +# settings default, initialize ------------------------ + +points_as_menu = "convert to: %t|empty %x1|mesh.vertex %x2|thin sphere %x3|thin box %x4" +lines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" +mlines_as_menu = "convert to: %t|*edge %x1|*mesh %x2|*thin cylinder %x3|*thin box %x4" +plines_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" +plines3_as_menu = "convert to: %t|*edge %x1|mesh %x2|*thin cylinder %x3|*thin box %x4" +plmesh_as_menu = "convert to: %t|mesh %x1" +solids_as_menu = "convert to: %t|mesh %x1" +blocks_as_menu = "convert to: %t|dupl.group %x1|*real.group %x2|*exploded %x3" +texts_as_menu = "convert to: %t|text %x1|*mesh %x2" +material_from_menu= "material from: %t|COLOR %x1|LAYER %x2|*LAYER+COLOR %x3|*BLOCK %x4|*XDATA %x5|*INI-File %x6" +g_scale_list = "scale factor: %t|x 1000 %x3|x 100 %x2|x 10 %x1|x 1 %x0|x 0.1 %x-1|x 0.01 %x-2|x 0.001 %x-3|x 0.0001 %x-4|x 0.00001 %x-5" + +dxfFileName = Draw.Create("") +iniFileName = Draw.Create(INIFILE_DEFAULT_NAME + INIFILE_EXTENSION) +user_preset = 0 +config_UI = Draw.Create(0) #switch_on/off extended config_UI + +keywords_org = { + 'curves_on' : 0, + 'optimization': 2, + 'one_mesh_on': 1, + 'vGroup_on' : 1, + 'dummy_on' : 0, + 'newScene_on' : 1, + 'target_layer' : TARGET_LAYER, + 'group_bylayer_on' : GROUP_BYLAYER, + 'g_scale' : float(G_SCALE), + 'g_scale_as': int(log10(G_SCALE)), # 0, + 'g_scale_on': 1, + 'thick_on' : 1, + 'thick_min' : float(MIN_THICK), + 'thick_force': 0, + 'width_on' : 1, + 'width_min' : float(MIN_WIDTH), + 'width_force': 0, + 'dist_on' : 1, + 'dist_min' : float(MIN_DIST), + 'dist_force': 0, + 'material_on': 1, + 'material_from': 2, + 'pl_3d' : 1, + 'fill_on' : 1, + 'arc_res' : ARC_RESOLUTION, + 'arc_rad' : ARC_RADIUS, + 'thin_res' : THIN_RESOLUTION, + 'angle_cut' : ANGLECUT_LIMIT, + 'pl_section_on': 1, + 'points_as' : 2, + 'lines_as' : 2, + 'mlines_as' : 2, + 'plines_as' : 2, + 'plines3_as': 2, + 'plmesh_as' : 1, + 'solids_as' : 1, + 'blocks_as' : 1, + 'texts_as' : 1 + } + +drawTypes_org = { + 'point' : 1, + 'line' : 1, + 'arc' : 1, + 'circle': 1, + 'ellipse': 0, + 'mline' : 0, + 'polyline': 1, + 'plmesh': 1, + 'pline3': 1, + 'lwpolyline': 1, + 'text' : 1, + 'mtext' : 0, + 'block' : 1, + 'insert': 1, + 'face' : 1, + 'solid' : 1, + 'trace' : 1 + } + +# creating of GUI-buttons +# GUI_A - GUI-buttons dictionary for parameter +# GUI_B - GUI-buttons dictionary for drawingTypes +for k, v in keywords_org.iteritems(): + GUI_A[k] = Draw.Create(v) +for k, v in drawTypes_org.iteritems(): + GUI_B[k] = Draw.Create(v) +#print 'deb:init GUI_A: ', GUI_A #--------------- +#print 'deb:init GUI_B: ', GUI_B #--------------- +# initialize settings-object controls how dxf entities are drawn +settings = Settings(keywords_org, drawTypes_org) + + + +def saveConfig(): #remi--todo----------------------------------------------- + """Save settings/config/materials from GUI to INI-file. + + Write all config data to INI-file. + """ + global iniFileName + + iniFile = iniFileName.val + #print 'deb:saveConfig inifFile: ', inifFile #---------------------- + if iniFile.lower().endswith(INIFILE_EXTENSION): + output = '[%s,%s]' %(GUI_A, GUI_B) + if output =='None': + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no config-data present to save!') + else: + #if BPyMessages.Warning_SaveOver(iniFile): #<- remi find it too abstarct + if sys.exists(iniFile): + f = file(iniFile, 'r'); header_str = f.readline(); f.close() + if header_str.startswith(INIFILE_HEADER[0:12]): + if Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile) == 1: + save_ok = True + elif Draw.PupMenu(' OK ? %t|SAVE OVER: ' + '\'%s\'' %iniFile + + '|Alert: this file has no valid ImportDXF-format| ! it may belong to another aplication !') == 1: + save_ok = True + else: save_ok = False + else: save_ok = True + + if save_ok: + try: + f = file(iniFile, 'w') + f.write(INIFILE_HEADER + '\n') + f.write(output) + f.close() + Draw.PupMenu('DXF importer: INI-file: Done!%t|config-data saved in ' + '\'%s\'' %iniFile) + except: + Draw.PupMenu('DXF importer: INI-file: Error!%t|failure by writing to ' + '\'%s\'|no config-data saved!' %iniFile) + + else: + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid name/extension for INI-file selected!') + print "DXF importer: Alert!: no valid INI-file selected." + if not iniFile: + if dxfFileName.val.lower().endswith('.dxf'): + iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION + + +def loadConfig(): #remi--todo----------------------------------------------- + """Load settings/config/materials from INI-file. + + Read material-assignements from config-file. + """ + #070724 buggy Window.FileSelector(loadConfigFile, 'Load config data from INI-file', inifilename) + global iniFileName, GUI_A, GUI_B + + iniFile = iniFileName.val + #print 'deb:loadConfig iniFile: ', iniFile #---------------------- + if iniFile.lower().endswith(INIFILE_EXTENSION) and sys.exists(iniFile): + f = file(iniFile, 'r') + header_str = f.readline() + if not header_str.startswith(INIFILE_HEADER): + f.close() + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid header in INI-file: ' + '\'%s\'' %iniFile) + else: + data_str = f.read() + f.close() + #print 'deb:loadConfig data_str from %s: \n' %iniFile , data_str #-------------------------- + data = eval(data_str) + for k, v in data[0].iteritems(): + try: + GUI_A[k].val = v + except: + GUI_A[k] = Draw.Create(v) + for k, v in data[1].iteritems(): + try: + GUI_B[k].val = v + except: + GUI_B[k] = Draw.Create(v) + else: + Draw.PupMenu('DXF importer: INI-file: Alert!%t|no valid INI-file selected!') + print "DXF importer: Alert!: no valid INI-file selected." + if not iniFileName: + if dxfFileName.val.lower().endswith('.dxf'): + iniFileName.val = dxfFileName.val[0:-4] + INIFILE_EXTENSION + + + +def resetDefaultConfig(): #----------------------------------------------- + """Resets settings/config/materials to defaults. + + """ + global GUI_A, GUI_B + #print 'deb:lresetDefaultConfig keywords_org: \n', keywords_org #--------- + for k, v in keywords_org.iteritems(): + GUI_A[k].val = v + for k, v in drawTypes_org.iteritems(): + GUI_B[k].val = v + + +def resetDefaultConfig_2D(): #----------------------------------------------- + """Sets settings/config/materials to defaults 2D. + + """ + resetDefaultConfig() + global GUI_A, GUI_B + keywords2d = { + 'curves_on' : 0, + 'one_mesh_on': 1, + 'vGroup_on' : 1, + 'thick_on' : 0, + 'thick_force': 0, + 'width_on' : 1, + 'width_force': 0, + 'dist_on' : 1, + 'dist_force': 0, + 'pl_3d' : 0, + 'fill_on' : 0, + 'pl_section_on': 1, + 'points_as' : 2, + 'lines_as' : 2, + 'mlines_as' : 2, + 'plines_as' : 2, + 'solids_as' : 1, + 'blocks_as' : 1, + 'texts_as' : 1 + } + + drawTypes2d = { + 'point' : 1, + 'line' : 1, + 'arc' : 1, + 'circle': 1, + 'ellipse': 0, + 'mline' : 0, + 'polyline': 1, + 'plmesh': 0, + 'pline3': 0, + 'lwpolyline': 1, + 'text' : 1, + 'mtext' : 0, + 'block' : 1, + 'insert': 1, + 'face' : 0, + 'solid' : 1, + 'trace' : 1 + } + + for k, v in keywords2d.iteritems(): + GUI_A[k].val = v + for k, v in drawTypes2d.iteritems(): + GUI_B[k].val = v + + + +def draw_UI(): #----------------------------------------------------------------- + """ Draw startUI and setup Settings. + """ + global GUI_A, GUI_B #__version__ + global user_preset, iniFileName, dxfFileName, config_UI + + # This is for easy layout changes + but_0c = 70 #button 1.column width + but_1c = 70 #button 1.column width + but_2c = 70 #button 2.column + but_3c = 70 #button 3.column + menu_margin = 10 + butt_margin = 10 + menu_w = (3 * butt_margin) + but_0c + but_1c + but_2c + but_3c #menu width + + simple_menu_h = 110 + extend_menu_h = 380 + y = simple_menu_h # y is menu upper.y + if config_UI.val: y += extend_menu_h + x = 20 #menu left.x + but0c = x + menu_margin #buttons 0.column position.x + but1c = but0c + but_0c + butt_margin + but2c = but1c + but_1c + butt_margin + but3c = but2c + but_2c + butt_margin + + # Here starts menu ----------------------------------------------------- + #glClear(GL_COLOR_BUFFER_BIT) + #glRasterPos2d(8, 125) + + colorbox(x, y+20, x+menu_w+menu_margin*2, menu_margin) + Draw.Label("DXF Importer ver." + __version__, but0c, y, menu_w, 20) + + if config_UI.val: + y -= 30 + Draw.BeginAlign() + GUI_B['point'] = Draw.Toggle('POINT', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['point'].val, "support dxf-POINT on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['points_as'] = Draw.Menu(points_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['points_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['line'] = Draw.Toggle('LINE.ARC.CIRCLE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['line'].val, "support dxf-LINE,ARC,CIRCLE,ELLIPSE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['lines_as'] = Draw.Menu(lines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['lines_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['mline'] = Draw.Toggle('*MLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['mline'].val, "(*wip)support dxf-MLINE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['mlines_as'] = Draw.Menu(mlines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['mlines_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['polyline'] = Draw.Toggle('2D-POLYLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['polyline'].val, "support dxf-2D-POLYLINE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['plines_as'] = Draw.Menu(plines_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plines_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['pline3'] = Draw.Toggle('3D-POLYLINE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['pline3'].val, "support dxf-3D-POLYLINE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['plines3_as'] = Draw.Menu(plines3_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plines3_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['plmesh'] = Draw.Toggle('POLYMESH/-FACE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['plmesh'].val, "support dxf-POLYMESH/POLYFACE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['plmesh_as'] = Draw.Menu(plmesh_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['plmesh_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['solid'] = Draw.Toggle('3DFACE.SOLID.TRACE', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['solid'].val, "support dxf-3DFACE, SOLID and TRACE on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['solids_as'] = Draw.Menu(solids_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['solids_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['text'] = Draw.Toggle('TEXT', EVENT_NONE, but0c, y, but_0c, 20, GUI_B['text'].val, "support dxf-TEXT on/off") + GUI_B['mtext'] = Draw.Toggle('*MTEXT', EVENT_NONE, but1c, y, but_1c-butt_margin, 20, GUI_B['mtext'].val, "(*wip)support dxf-MTEXT on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['texts_as'] = Draw.Menu(texts_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['texts_as'].val, "select target Blender-object") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_B['block'] = Draw.Toggle('BLOCK / ARRAY', EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_B['block'].val, "support dxf-BLOCK and ARRAY on/off") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['blocks_as'] = Draw.Menu(blocks_as_menu, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['blocks_as'].val, "select target Blender-object") + Draw.EndAlign() + + + y -= 20 + Draw.BeginAlign() + GUI_A['material_from'] = Draw.Menu(material_from_menu, EVENT_NONE, but0c, y, but_0c+but_1c, 20, GUI_A['material_from'].val, "material assignment from?") + Draw.Label('-->', but2c, y, but_2c, 20) + GUI_A['material_on'] = Draw.Toggle('material', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['material_on'].val, "support for material assignment on/off") + Draw.EndAlign() + + + y -= 30 + GUI_A['group_bylayer_on'] = Draw.Toggle('oneGroup', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['group_bylayer_on'].val, "grouping entities from the same layer on/off") + GUI_A['curves_on'] = Draw.Toggle('to Curves', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['curves_on'].val, "drawing LINE/ARC/POLYLINE into Blender-Curves instead of Meshes on/off") + Draw.BeginAlign() + GUI_A['g_scale_on'] = Draw.Toggle('glob.Scale', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['g_scale_on'].val, "scaling all DXF objects on/off") + GUI_A['g_scale_as'] = Draw.Menu(g_scale_list, EVENT_NONE, but3c, y, but_3c, 20, GUI_A['g_scale_as'].val, "10^ factor for scaling the DXFdata") + Draw.EndAlign() + + + y -= 20 + #Draw.Label('', but1c+but_1c/2, y, but_1c/2, 20) + GUI_A['one_mesh_on'] = Draw.Toggle('oneMesh', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['one_mesh_on'].val, "drawing DXF-entities into one mesh-object. Recommended for big DXF-files. on/off") + GUI_A['vGroup_on'] = Draw.Toggle('vGroups', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['vGroup_on'].val, "support Blender-VertexGroups on/off") + Draw.BeginAlign() + GUI_A['dist_on'] = Draw.Toggle('dist.:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['dist_on'].val, "support distance on/off") + GUI_A['dist_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['dist_force'].val, "force minimal distance on/off") + GUI_A['dist_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['dist_min'].val, 0, 10, "minimal lenght/distance (double.vertex removing)") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + GUI_A['pl_section_on'] = Draw.Toggle('int.section', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['pl_section_on'].val, "support POLYLINE-wide-segment-intersection on/off") + GUI_A['angle_cut'] = Draw.Number('', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['angle_cut'].val, 1, 5, "it limits POLYLINE-wide-segment-intersection: 1.0-5.0") + Draw.EndAlign() + Draw.BeginAlign() + GUI_A['thick_on'] = Draw.Toggle('thick:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['thick_on'].val, "support thickness on/off") + GUI_A['thick_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['thick_force'].val, "force minimal thickness on/off") + GUI_A['thick_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['thick_min'].val, 0, 10, "minimal thickness") + Draw.EndAlign() + + + y -= 20 + Draw.BeginAlign() +# GUI_A['thin_res'] = Draw.Number('thin:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['thin_res'].val, 4, 500, "thin cylinder resolution - number of segments") + GUI_A['arc_rad'] = Draw.Number('radi:', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['arc_rad'].val, 0.01, 100, "basis radius for arc/circle resolution") + GUI_A['arc_res'] = Draw.Number('res:', EVENT_NONE, but1c, y, but_1c-25, 20, GUI_A['arc_res'].val, 4, 500, "arc/circle resolution - number of segments") + GUI_A['fill_on'] = Draw.Toggle('cap', EVENT_NONE, but1c+but_1c-25, y, 25, 20, GUI_A['fill_on'].val, "draws top and bottom caps of CYLINDERs on/off") + Draw.EndAlign() + Draw.BeginAlign() + GUI_A['width_on'] = Draw.Toggle('width:', EVENT_NONE, but2c, y, but_2c-20, 20, GUI_A['width_on'].val, "support width on/off") + GUI_A['width_force'] = Draw.Toggle('F', EVENT_NONE, but2c+but_2c-20, y, 20, 20, GUI_A['width_force'].val, "force minimal width on/off") + GUI_A['width_min'] = Draw.Number('', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['width_min'].val, 0, 10, "minimal width") + Draw.EndAlign() + + y -= 30 + #GUI_A['dummy_on'] = Draw.Toggle(' - ', EVENT_NONE, but0c, y, but_0c, 20, GUI_A['dummy_on'].val, "reserved") + GUI_A['newScene_on'] = Draw.Toggle('newScene', EVENT_NONE, but1c, y, but_1c, 20, GUI_A['newScene_on'].val, "creates new Blender-Scene for each import on/off") + GUI_A['target_layer'] = Draw.Number('layer', EVENT_NONE, but2c, y, but_2c, 20, GUI_A['target_layer'].val, 1, 18, "imports into this Blender-layer (<19> reserved for block_definitions)") + GUI_A['optimization'] = Draw.Number('optim:', EVENT_NONE, but3c, y, but_3c, 20, GUI_A['optimization'].val, 0, 3, "Optimization Level: 0=Debug/directDrawing, 1=Verbose, 2=ProgressBar, 3=silentMode/fastest") + + y -= 30 + Draw.BeginAlign() + Draw.PushButton('INI file >', EVENT_CHOOSE_INI, but0c, y, but_0c, 20, 'Select INI-file from project directory') + iniFileName = Draw.String(' :', EVENT_NONE, but1c, y, menu_w-but_0c-butt_margin, 20, iniFileName.val, FILENAME_MAX, "write here the name of the INI-file") + Draw.EndAlign() + + y -= 20 + Draw.BeginAlign() + Draw.PushButton('Presets', EVENT_PRESETS, but0c, y, but_0c, 20, "tipist for Preset-INI-files") + Draw.PushButton('Load', EVENT_LOAD_INI, but1c, y, but_1c, 20, ' Loads configuration from ini-file: %s' % iniFileName.val) + Draw.PushButton('Save', EVENT_SAVE_INI, but2c, y, but_2c, 20, 'Saves configuration to ini-file: %s' % iniFileName.val) +# user_preset = Draw.Number('preset:', EVENT_PRESETS, but2c, y, but_2c, 20, user_preset.val, 0, 5, "call user Preset-INI-files") + Draw.PushButton('2D', EVENT_PRESET2D, but3c, y, but_3c/2, 20, 'resets configuration to 2D-defaults') + Draw.PushButton('3D', EVENT_PRESET, but3c+but_3c/2, y, but_3c/2, 20, 'resets configuration to 3D-defaults') + Draw.EndAlign() + + + y -= 30 + Draw.BeginAlign() + Draw.PushButton('DXFfile >', EVENT_CHOOSE_DXF, but0c, y, but_0c, 20, 'Select DXF-file from project directory') + dxfFileName = Draw.String(' :', EVENT_NONE, but1c, y, but_1c+but_2c+but_3c-20, 20, dxfFileName.val, FILENAME_MAX, "type the name of DXF-file or * for multi-import") + Draw.PushButton('*.*', EVENT_DXF_DIR, but3c+but_3c-20, y, 20, 20, 'Set asterisk * as filter') + Draw.EndAlign() + + + y -= 50 + Draw.BeginAlign() + Draw.PushButton('EXIT', EVENT_EXIT, but0c, y, but_0c, 40, '' ) + Draw.PushButton('HELP', EVENT_HELP, but1c, y, but_1c, 20, 'calls BlenderWiki for Manual, Updates and Support.') + Draw.PushButton('START IMPORT', EVENT_START, but2c, y, but_2c+but_3c+butt_margin, 40, 'Start the import procedure') + Draw.EndAlign() + + config_UI = Draw.Toggle('CONFIG', EVENT_CONFIG, but1c-butt_margin/2, y+20, but_1c+butt_margin, 20, config_UI.val, 'Advanced configuration on/off' ) + + y -= 20 + Draw.BeginAlign() + Draw.Label(' ', but0c-menu_margin, y, menu_margin, 20) + Draw.Label("*) parts under construction", but0c, y, menu_w, 20) + Draw.Label(' ', but0c+menu_w, y, menu_margin, 20) + Draw.EndAlign() + +#-- END GUI Stuf----------------------------------------------------- + +def colorbox(x,y,xright,bottom): + glColor3f(0.75, 0.75, 0.75) + glRecti(x + 1, y + 1, xright - 1, bottom - 1) + +def dxf_callback(input_filename): + global dxfFileName + dxfFileName.val=input_filename + +def ini_callback(input_texture): + global iniFileName + iniFileName.val=input_texture + +def event(evt, val): + if evt in (Draw.QKEY, Draw.ESCKEY) and not val: + Blender.Draw.Exit() + +def bevent(evt): +# global EVENT_NONE,EVENT_LOAD_DXF,EVENT_LOAD_INI,EVENT_SAVE_INI,EVENT_EXIT + global config_UI, user_preset + + ######### Manages GUI events + if (evt==EVENT_EXIT): + Blender.Draw.Exit() + elif (evt==EVENT_CHOOSE_INI): + Window.FileSelector(ini_callback, "INI-file Selection", '*.ini') + elif (evt==EVENT_CONFIG): + Draw.Redraw() + elif (evt==EVENT_PRESET): + resetDefaultConfig() + Draw.Redraw() + elif (evt==EVENT_PRESET2D): + resetDefaultConfig_2D() + Draw.Redraw() + elif (evt==EVENT_PRESETS): + user_preset += 1 + if user_preset > 5: user_preset = 1 + iniFileName.val = INIFILE_DEFAULT_NAME + str(user_preset) + INIFILE_EXTENSION + Draw.Redraw() + elif (evt==EVENT_HELP): + try: + import webbrowser + webbrowser.open('http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') + except: + Draw.PupMenu('DXF importer: HELP Alert!%t|no connection to manual-page on Blender-Wiki! try:|\ +http://wiki.blender.org/index.php?title=Scripts/Manual/Import/DXF-3D') + Draw.Redraw() + elif (evt==EVENT_LOAD_INI): + loadConfig() + Draw.Redraw() + elif (evt==EVENT_SAVE_INI): + saveConfig() + Draw.Redraw() + elif (evt==EVENT_DXF_DIR): + dxfFile = dxfFileName.val + dxfPathName = '' + if '/' in dxfFile: + dxfPathName = '/'.join(dxfFile.split('/')[:-1]) + '/' + elif '\\' in dxfFile: + dxfPathName = '\\'.join(dxfFile.split('\\')[:-1]) + '\\' + dxfFileName.val = dxfPathName + '*.dxf' + global GUI_A + GUI_A['newScene_on'].val = 1 + Draw.Redraw() + elif (evt==EVENT_CHOOSE_DXF): + Window.FileSelector(dxf_callback, "DXF-file Selection", '*.dxf') + elif (evt==EVENT_START): + dxfFile = dxfFileName.val + #print 'deb: dxfFile file: ', dxfFile #---------------------- + if dxfFile.lower().endswith('*.dxf'): + if Draw.PupMenu('DXF importer: OK?|will import all DXF-files from:|%s' % dxfFile) == 1: + global UI_MODE + UI_MODE = False + multi_import(dxfFile[:-5]) # cut last char:'*.dxf' + Draw.Exit() + else: + Draw.Redraw() + elif dxfFile.lower().endswith('.dxf') and sys.exists(dxfFile): + if GUI_A['newScene_on'].val: + _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] + _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' + _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) + global SCENE + SCENE = Blender.Scene.New(_dxf_file) + SCENE.makeCurrent() + #or so? Blender.Scene.makeCurrent(_dxf_file) + #sce = bpy.data.scenes.new(_dxf_file) + #bpy.data.scenes.active = sce + else: + SCENE = Blender.Scene.GetCurrent() + SCENE.objects.selected = [] # deselect all + main(dxfFile) + #SCENE.objects.selected = SCENE.objects + #Window.RedrawAll() + #Blender.Redraw() + #Draw.Redraw() + else: + Draw.PupMenu('DXF importer: Alert!%t|no valid DXF-file selected!') + print "DXF importer: error, no valid DXF-file selected! try again" + Draw.Redraw() + + + + +def multi_import(DIR): + """Imports all DXF-files from directory DIR. + + """ + global SCENE + batchTIME = Blender.sys.time() + #if #DIR == "": DIR = os.path.curdir + if DIR == "": DIR = Blender.sys.dirname(Blender.Get('filename')) + print 'Searching for DXF-files in %s' %DIR + files = \ + [sys.join(DIR, f) for f in os.listdir(DIR) if f.lower().endswith('.dxf')] + if not files: + print '...None DXF-files found. Abort!' + return + + i = 0 + for dxfFile in files: + i += 1 + print 'Importing', dxfFile, ' NUMBER', i, 'of', len(files) + if GUI_A['newScene_on'].val: + _dxf_file = dxfFile.split('/')[-1].split('\\')[-1] + _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' + _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) + SCENE = Blender.Scene.New(_dxf_file) + SCENE.makeCurrent() + #or so? Blender.Scene.makeCurrent(_dxf_file) + #sce = bpy.data.scenes.new(_dxf_file) + #bpy.data.scenes.active = sce + else: + SCENE = Blender.Scene.GetCurrent() + SCENE.objects.selected = [] # deselect all + main(dxfFile) + #Blender.Redraw() + + print 'TOTAL TIME: %.6f' % (Blender.sys.time() - batchTIME) + + + + +if __name__ == "__main__": + UI_MODE = True + Draw.Register(draw_UI, event, bevent) + + +""" +if 1: + # DEBUG ONLY + UI_MODE = False + TIME= Blender.sys.time() + #DIR = '/dxf_r12_testfiles/' + DIR = '/metavr/' + import os + print 'Searching for files' + os.system('find %s -iname "*.dxf" > /tmp/tempdxf_list' % DIR) + # os.system('find /storage/ -iname "*.dxf" > /tmp/tempdxf_list') + print '...Done' + file= open('/tmp/tempdxf_list', 'r') + lines= file.readlines() + file.close() + # sort by filesize for faster testing + lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] + lines_size.sort() + lines = [f[1] for f in lines_size] + + for i, _dxf in enumerate(lines): + if i >= 70: + #if 1: + print 'Importing', _dxf, '\nNUMBER', i, 'of', len(lines) + if True: + _dxf_file= _dxf.split('/')[-1].split('\\')[-1] + _dxf_file = _dxf_file[:-4] # cut last char:'.dxf' + _dxf_file = _dxf_file[:MAX_NAMELENGTH] #? [-MAX_NAMELENGTH:]) + sce = bpy.data.scenes.new(_dxf_file) + bpy.data.scenes.active = sce + dxfFileName.val = _dxf + main(_dxf) + + print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) +""" \ No newline at end of file diff --git a/release/scripts/import_mdd.py b/release/scripts/import_mdd.py new file mode 100644 index 00000000000..8e7b9985d3d --- /dev/null +++ b/release/scripts/import_mdd.py @@ -0,0 +1,158 @@ +#!BPY + + #""" + #Name: 'Load MDD to Mesh RVKs' + #Blender: 242 + #Group: 'Import' + #Tooltip: 'baked vertex animation to active mesh object.' + #""" +__author__ = "Bill L.Nieuwendorp" +__bpydoc__ = """\ +This script Imports Lightwaves MotionDesigner format. + +The .mdd format has become quite a popular Pipeline format
+for moving animations from package to package. +""" +# mdd importer +# +# Warning if the vertex order or vertex count differs from the +# origonal model the mdd was Baked out from their will be Strange +# behavior +# +# +#vertex animation to ShapeKeys with ipo and gives the frame a value of 1.0 +#A modifier to read mdd files would be Ideal but thats for another day :) +# +#Please send any fixes,updates,bugs to Slow67_at_Gmail.com +#Bill Niewuendorp + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + + + + +try: + from struct import unpack +except: + unpack = None + +import Blender +from Blender import Mesh, Object, Scene +import BPyMessages + +def mdd_import(filepath, ob, PREF_IPONAME, PREF_START_FRAME, PREF_JUMP): + + print '\n\nimporting mdd "%s"' % filepath + + Blender.Window.DrawProgressBar (0.0, "Importing mdd ...") + Blender.Window.EditMode(0) + Blender.Window.WaitCursor(1) + + file = open(filepath, 'rb') + frames, points = unpack(">2i", file.read(8)) + time = unpack((">%df" % frames), file.read(frames * 4)) + + print '\tpoints:%d frames:%d' % (points,frames) + + scn = Scene.GetCurrent() + ctx = scn.getRenderingContext() + Blender.Set("curframe", PREF_START_FRAME) + me = ob.getData(mesh=1) + + def UpdateMesh(me,fr): + for v in me.verts: + # 12 is the size of 3 floats + x,y,z= unpack('>3f', file.read(12)) + v.co[:] = x,z,y + me.update() + + Blender.Window.DrawProgressBar (0.4, "4 Importing mdd ...") + + + curfr = ctx.currentFrame() + print'\twriting mdd data...' + for i in xrange(frames): + Blender.Set("curframe", i+PREF_START_FRAME) + if len(me.verts) > 1 and (curfr >= PREF_START_FRAME) and (curfr <= PREF_START_FRAME+frames): + UpdateMesh(me, i) + ob.insertShapeKey() + + Blender.Window.DrawProgressBar (0.5, "5 Importing mdd ...") + + key= me.key + + # Add the key of its not there + if not key: + me.insertKey(1, 'relative') + key= me.key + + key.ipo = Blender.Ipo.New('Key', PREF_IPONAME) + ipo = key.ipo + # block = key.getBlocks() # not used. + all_keys = ipo.curveConsts + + for i in xrange(PREF_JUMP+1, len(all_keys), PREF_JUMP): + curve = ipo.getCurve(i) + if curve == None: + curve = ipo.addCurve(all_keys[i]) + + curve.append((PREF_START_FRAME+i-1,1)) + curve.append((PREF_START_FRAME+i- PREF_JUMP -1,0)) + curve.append((PREF_START_FRAME+i+ PREF_JUMP-1,0)) + curve.setInterpolation('Linear') + curve.recalc() + + print 'done' + Blender.Window.WaitCursor(0) + Blender.Window.DrawProgressBar (1.0, '') + + +def mdd_import_ui(filepath): + + if BPyMessages.Error_NoFile(filepath): + return + + scn= Scene.GetCurrent() + ob_act= scn.objects.active + + if ob_act == None or ob_act.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + PREF_IPONAME = Blender.Draw.Create(filepath.split('/')[-1].split('\\')[-1].split('.')[0]) + PREF_START_FRAME = Blender.Draw.Create(1) + PREF_JUMP = Blender.Draw.Create(1) + + block = [\ + ("Ipo Name: ", PREF_IPONAME, 0, 30, "Ipo name for the new shape key"),\ + ("Start Frame: ", PREF_START_FRAME, 1, 3000, "Start frame for the animation"),\ + ("Key Skip: ", PREF_JUMP, 1, 100, "KeyReduction, Skip every Nth Frame")\ + ] + + if not Blender.Draw.PupBlock("Import MDD", block): + return + orig_frame = Blender.Get('curframe') + mdd_import(filepath, ob_act, PREF_IPONAME.val, PREF_START_FRAME.val, PREF_JUMP.val) + Blender.Set('curframe', orig_frame) + +if __name__ == '__main__': + if not unpack: + Draw.PupMenu('Error%t|This script requires a full python install') + + Blender.Window.FileSelector(mdd_import_ui, 'IMPORT MDD', '*.mdd') diff --git a/release/scripts/import_obj.py b/release/scripts/import_obj.py new file mode 100644 index 00000000000..30c4c410434 --- /dev/null +++ b/release/scripts/import_obj.py @@ -0,0 +1,880 @@ +#!BPY + +""" +Name: 'Wavefront (.obj)...' +Blender: 242 +Group: 'Import' +Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.' +""" + +__author__= "Campbell Barton", "Jiri Hnidek" +__url__= ["blender.org", "blenderartists.org"] +__version__= "2.0" + +__bpydoc__= """\ +This script imports a Wavefront OBJ files to Blender. + +Usage: +Run this script from "File->Import" menu and then load the desired OBJ file. +Note, This loads mesh objects and materials only, nurbs and curves are not supported. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton 2007 +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * +import bpy +import BPyMesh +import BPyImage +import BPyMessages + +try: import os +except: os= False + + +# Generic path functions +def stripFile(path): + '''Return directory, where the file is''' + lastSlash= max(path.rfind('\\'), path.rfind('/')) + if lastSlash != -1: + path= path[:lastSlash] + return '%s%s' % (path, sys.sep) + +def stripPath(path): + '''Strips the slashes from the back of a string''' + return path.split('/')[-1].split('\\')[-1] + +def stripExt(name): # name is a string + '''Strips the prefix off the name before writing''' + index= name.rfind('.') + if index != -1: + return name[ : index ] + else: + return name +# end path funcs + + + +def line_value(line_split): + ''' + Returns 1 string represneting the value for this line + None will be returned if theres only 1 word + ''' + length= len(line_split) + if length == 1: + return None + + elif length == 2: + return line_split[1] + + elif length > 2: + return ' '.join( line_split[1:] ) + +def obj_image_load(imagepath, DIR, IMAGE_SEARCH): + ''' + Mainly uses comprehensiveImageLoad + but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores. + ''' + + if '_' in imagepath: + image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) + if image: return image + # Did the exporter rename the image? + image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH) + if image: return image + + # Return an image, placeholder if it dosnt exist + image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH) + return image + + +def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH): + ''' + Create all the used materials in this obj, + assign colors and images to the materials from all referenced material libs + ''' + DIR= stripFile(filepath) + + #==================================================================================# + # This function sets textures defined in .mtl file # + #==================================================================================# + def load_material_image(blender_material, context_material_name, imagepath, type): + + texture= bpy.data.textures.new(type) + texture.setType('Image') + + # Absolute path - c:\.. etc would work here + image= obj_image_load(imagepath, DIR, IMAGE_SEARCH) + has_data = image.has_data + texture.image = image + + # Adds textures for materials (rendering) + if type == 'Kd': + if has_data and image.depth == 32: + # Image has alpha + blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA) + texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha') + blender_material.mode |= Material.Modes.ZTRANSP + blender_material.alpha = 0.0 + else: + blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL) + + # adds textures to faces (Textured/Alt-Z mode) + # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. + unique_material_images[context_material_name]= image, has_data # set the texface image + + elif type == 'Ka': + blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API + + elif type == 'Ks': + blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC) + + elif type == 'Bump': + blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR) + elif type == 'D': + blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA) + blender_material.mode |= Material.Modes.ZTRANSP + blender_material.alpha = 0.0 + # Todo, unset deffuse material alpha if it has an alpha channel + + elif type == 'refl': + blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF) + + + # Add an MTL with the same name as the obj if no MTLs are spesified. + temp_mtl= stripExt(stripPath(filepath))+ '.mtl' + + if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs: + material_libs.append( temp_mtl ) + del temp_mtl + + #Create new materials + for name in unique_materials.iterkeys(): + unique_materials[name]= bpy.data.materials.new(name) + + unique_material_images[name]= None, False # assign None to all material images to start with, add to later. + + unique_materials[None]= None + + for libname in material_libs: + mtlpath= DIR + libname + if not sys.exists(mtlpath): + #print '\tError Missing MTL: "%s"' % mtlpath + pass + else: + #print '\t\tloading mtl: "%s"' % mtlpath + context_material= None + mtl= open(mtlpath) + for line in mtl: #.xreadlines(): + if line.startswith('newmtl'): + context_material_name= line_value(line.split()) + if unique_materials.has_key(context_material_name): + context_material = unique_materials[ context_material_name ] + else: + context_material = None + + elif context_material: + # we need to make a material to assign properties to it. + line_split= line.split() + line_lower= line.lower() + if line_lower.startswith('ka'): + context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('kd'): + context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('ks'): + context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3]))) + elif line_lower.startswith('ns'): + context_material.setHardness( int((float(line_split[1])*0.51)) ) + elif line_lower.startswith('ni'): # Refraction index + context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3 + elif line_lower.startswith('d') or line_lower.startswith('tr'): + context_material.setAlpha(float(line_split[1])) + elif line_lower.startswith('map_ka'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Ka') + elif line_lower.startswith('map_ks'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Ks') + elif line_lower.startswith('map_kd'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Kd') + elif line_lower.startswith('map_bump'): + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'Bump') + elif line_lower.startswith('map_d') or line_lower.startswith('map_tr'): # Alpha map - Dissolve + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'D') + + elif line_lower.startswith('refl'): # Reflectionmap + img_filepath= line_value(line.split()) + if img_filepath: + load_material_image(context_material, context_material_name, img_filepath, 'refl') + mtl.close() + + + + +def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): + ''' + Takes vert_loc and faces, and seperates into multiple sets of + (verts_loc, faces, unique_materials, dataname) + This is done so objects do not overload the 16 material limit. + ''' + + filename = stripExt(stripPath(filepath)) + + if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: + # use the filename for the object name since we arnt chopping up the mesh. + return [(verts_loc, faces, unique_materials, filename)] + + + def key_to_name(key): + # if the key is a tuple, join it to make a string + if type(key) == tuple: + return '%s_%s' % key + elif not key: + return filename # assume its a string. make sure this is true if the splitting code is changed + else: + return key + + # Return a key that makes the faces unique. + if SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS: + def face_key(face): + return face[4] # object + + elif not SPLIT_OB_OR_GROUP and SPLIT_MATERIALS: + def face_key(face): + return face[2] # material + + else: # Both + def face_key(face): + return face[4], face[2] # object,material + + + face_split_dict= {} + + oldkey= -1 # initialize to a value that will never match the key + + for face in faces: + + key= face_key(face) + + if oldkey != key: + # Check the key has changed. + try: + verts_split, faces_split, unique_materials_split, vert_remap= face_split_dict[key] + except KeyError: + faces_split= [] + verts_split= [] + unique_materials_split= {} + vert_remap= [-1]*len(verts_loc) + + face_split_dict[key]= (verts_split, faces_split, unique_materials_split, vert_remap) + + oldkey= key + + face_vert_loc_indicies= face[0] + + # Remap verts to new vert list and add where needed + for enum, i in enumerate(face_vert_loc_indicies): + if vert_remap[i] == -1: + new_index= len(verts_split) + vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time. + face_vert_loc_indicies[enum] = new_index # remap to the local index + verts_split.append( verts_loc[i] ) # add the vert to the local verts + + else: + face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index + + matname= face[2] + if matname and not unique_materials_split.has_key(matname): + unique_materials_split[matname] = unique_materials[matname] + + faces_split.append(face) + + + # remove one of the itemas and reorder + return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.iteritems()] + + +def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, dataname): + ''' + Takes all the data gathered and generates a mesh, adding the new object to new_objects + deals with fgons, sharp edges and assigning materials + ''' + if not has_ngons: + CREATE_FGONS= False + + if unique_smooth_groups: + sharp_edges= {} + smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.iterkeys() ]) + context_smooth_group_old= -1 + + # Split fgons into tri's + fgon_edges= {} # Used for storing fgon keys + if CREATE_EDGES: + edges= [] + + context_object= None + + # reverse loop through face indicies + for f_idx in xrange(len(faces)-1, -1, -1): + + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object= faces[f_idx] + + len_face_vert_loc_indicies = len(face_vert_loc_indicies) + + if len_face_vert_loc_indicies==1: + faces.pop(f_idx)# cant add single vert faces + + elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2: # faces that have no texture coords are lines + if CREATE_EDGES: + # generators are better in python 2.4+ but can't be used in 2.3 + # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) ) + edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1)] ) + + faces.pop(f_idx) + else: + + # Smooth Group + if unique_smooth_groups and context_smooth_group: + # Is a part of of a smooth group and is a face + if context_smooth_group_old is not context_smooth_group: + edge_dict= smooth_group_users[context_smooth_group] + context_smooth_group_old= context_smooth_group + + for i in xrange(len_face_vert_loc_indicies): + i1= face_vert_loc_indicies[i] + i2= face_vert_loc_indicies[i-1] + if i1>i2: i1,i2= i2,i1 + + try: + edge_dict[i1,i2]+= 1 + except KeyError: + edge_dict[i1,i2]= 1 + + # FGons into triangles + if has_ngons and len_face_vert_loc_indicies > 4: + + ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies) + faces.extend(\ + [(\ + [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\ + [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],\ + context_material,\ + context_smooth_group,\ + context_object)\ + for ngon in ngon_face_indices]\ + ) + + # edges to make fgons + if CREATE_FGONS: + edge_users= {} + for ngon in ngon_face_indices: + for i in (0,1,2): + i1= face_vert_loc_indicies[ngon[i ]] + i2= face_vert_loc_indicies[ngon[i-1]] + if i1>i2: i1,i2= i2,i1 + + try: + edge_users[i1,i2]+=1 + except KeyError: + edge_users[i1,i2]= 1 + + for key, users in edge_users.iteritems(): + if users>1: + fgon_edges[key]= None + + # remove all after 3, means we dont have to pop this one. + faces.pop(f_idx) + + + # Build sharp edges + if unique_smooth_groups: + for edge_dict in smooth_group_users.itervalues(): + for key, users in edge_dict.iteritems(): + if users==1: # This edge is on the boundry of a group + sharp_edges[key]= None + + + # mat the material names to an index + material_mapping= dict([(name, i) for i, name in enumerate(unique_materials.keys())]) + + materials= [None] * len(unique_materials) + + for name, index in material_mapping.iteritems(): + materials[index]= unique_materials[name] + + me= bpy.data.meshes.new(dataname) + + me.materials= materials[0:16] # make sure the list isnt too big. + #me.verts.extend([(0,0,0)]) # dummy vert + me.verts.extend(verts_loc) + + face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) + + if verts_tex and me.faces: + me.faceUV= 1 + # TEXMODE= Mesh.FaceModes['TEX'] + + context_material_old= -1 # avoid a dict lookup + mat= 0 # rare case it may be un-initialized. + me_faces= me.faces + ALPHA= Mesh.FaceTranspModes.ALPHA + + for i, face in enumerate(faces): + if len(face[0]) < 2: + pass #raise "bad face" + elif len(face[0])==2: + if CREATE_EDGES: + edges.append(face[0]) + else: + face_index_map= face_mapping[i] + if face_index_map!=None: # None means the face wasnt added + blender_face= me_faces[face_index_map] + + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object= face + + + + if context_smooth_group: + blender_face.smooth= True + + if context_material: + if context_material_old is not context_material: + mat= material_mapping[context_material] + if mat>15: + mat= 15 + context_material_old= context_material + + blender_face.mat= mat + + + if verts_tex: + if context_material: + image, has_data= unique_material_images[context_material] + if image: # Can be none if the material dosnt have an image. + blender_face.image= image + if has_data and image.depth == 32: + blender_face.transp |= ALPHA + + # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled. + if len(face_vert_loc_indicies)==4: + if face_vert_loc_indicies[2]==0 or face_vert_loc_indicies[3]==0: + face_vert_tex_indicies= face_vert_tex_indicies[2], face_vert_tex_indicies[3], face_vert_tex_indicies[0], face_vert_tex_indicies[1] + else: # length of 3 + if face_vert_loc_indicies[2]==0: + face_vert_tex_indicies= face_vert_tex_indicies[1], face_vert_tex_indicies[2], face_vert_tex_indicies[0] + # END EEEKADOODLE FIX + + # assign material, uv's and image + for ii, uv in enumerate(blender_face.uv): + uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]] + del me_faces + del ALPHA + + # Add edge faces. + me_edges= me.edges + if CREATE_FGONS and fgon_edges: + FGON= Mesh.EdgeFlags.FGON + for ed in me.findEdges( fgon_edges.keys() ): + if ed!=None: + me_edges[ed].flag |= FGON + del FGON + + if unique_smooth_groups and sharp_edges: + SHARP= Mesh.EdgeFlags.SHARP + for ed in me.findEdges( sharp_edges.keys() ): + if ed!=None: + me_edges[ed].flag |= SHARP + del SHARP + + if CREATE_EDGES: + me_edges.extend( edges ) + + del me_edges + + me.calcNormals() + + ob= scn.objects.new(me) + new_objects.append(ob) + +def get_float_func(filepath): + ''' + find the float function for this obj file + - weather to replace commas or not + ''' + file= open(filepath, 'rU') + for line in file: #.xreadlines(): + if line.startswith('v'): # vn vt v + if ',' in line: + return lambda f: float(f.replace(',', '.')) + elif '.' in line: + return float + +def load_obj(filepath, CLAMP_SIZE= 0.0, CREATE_FGONS= True, CREATE_SMOOTH_GROUPS= True, CREATE_EDGES= True, SPLIT_OBJECTS= True, SPLIT_GROUPS= True, SPLIT_MATERIALS= True, IMAGE_SEARCH=True): + ''' + Called by the user interface or another script. + load_obj(path) - should give acceptable results. + This function passes the file and sends the data off + to be split into objects and then converted into mesh objects + ''' + print '\nimporting obj "%s"' % filepath + + time_main= sys.time() + + verts_loc= [] + verts_tex= [] + faces= [] # tuples of the faces + material_libs= [] # filanems to material libs this uses + + + # Get the string to float conversion func for this file- is 'float' for almost all files. + float_func= get_float_func(filepath) + + # Context variables + context_material= None + context_smooth_group= None + context_object= None + + has_ngons= False + # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0 + + # Until we can use sets + unique_materials= {} + unique_material_images= {} + unique_smooth_groups= {} + # unique_obects= {} - no use for this variable since the objects are stored in the face. + + # when there are faces that end with \ + # it means they are multiline- + # since we use xreadline we cant skip to the next line + # so we need to know weather + multi_line_face= False + + print '\tpassing obj file "%s"...' % filepath, + time_sub= sys.time() + file= open(filepath, 'r') + for line in file: #.xreadlines(): + + if line.startswith('v '): + line_split= line.split() + # rotate X90: (x,-z,y) + verts_loc.append( (float_func(line_split[1]), -float_func(line_split[3]), float_func(line_split[2])) ) + + elif line.startswith('vn '): + pass + + elif line.startswith('vt '): + line_split= line.split() + verts_tex.append( (float_func(line_split[1]), float_func(line_split[2])) ) + + # Handel faces lines (as faces) and the second+ lines of fa multiline face here + # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces) + elif line.startswith('f') or (line.startswith('l ') and CREATE_EDGES) or multi_line_face: + + if multi_line_face: + # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face + line_split= line.split() + multi_line_face= False + + else: + line_split= line[2:].split() + face_vert_loc_indicies= [] + face_vert_tex_indicies= [] + + # Instance a face + faces.append((\ + face_vert_loc_indicies,\ + face_vert_tex_indicies,\ + context_material,\ + context_smooth_group,\ + context_object\ + )) + + if line_split[-1][-1]== '\\': + multi_line_face= True + if len(line_split[-1])==1: + line_split.pop() # remove the \ item + else: + line_split[-1]= line_split[-1][:-1] # remove the \ from the end last number + + isline= line.startswith('l') + + for v in line_split: + obj_vert= v.split('/') + + vert_loc_index= int(obj_vert[0])-1 + + # Make relative negative vert indicies absolute + if vert_loc_index < 0: + vert_loc_index= len(verts_loc) + vert_loc_index + 1 + + face_vert_loc_indicies.append(vert_loc_index) + + if not isline: + if len(obj_vert)>1 and obj_vert[1]: + # formatting for faces with normals and textures us + # loc_index/tex_index/nor_index + + vert_tex_index= int(obj_vert[1])-1 + # Make relative negative vert indicies absolute + if vert_tex_index < 0: + vert_tex_index= len(verts_tex) + vert_tex_index + 1 + + face_vert_tex_indicies.append(vert_tex_index) + else: + # dummy + face_vert_tex_indicies.append(0) + + if len(face_vert_loc_indicies) > 4: + has_ngons= True + + elif line.startswith('s'): + if CREATE_SMOOTH_GROUPS: + context_smooth_group= line_value(line.split()) + if context_smooth_group=='off': + context_smooth_group= None + elif context_smooth_group: # is not None + unique_smooth_groups[context_smooth_group]= None + + elif line.startswith('o'): + if SPLIT_OBJECTS: + context_object= line_value(line.split()) + # unique_obects[context_object]= None + + elif line.startswith('g'): + if SPLIT_GROUPS: + context_object= line_value(line.split()) + # print 'context_object', context_object + # unique_obects[context_object]= None + + elif line.startswith('usemtl'): + context_material= line_value(line.split()) + unique_materials[context_material]= None + elif line.startswith('mtllib'): # usemap or usemat + material_libs.extend( line.split()[1:] ) # can have multiple mtllib filenames per line + + ''' # How to use usemap? depricated? + elif line.startswith('usema'): # usemap or usemat + context_image= line_value(line.split()) + ''' + + file.close() + time_new= sys.time() + print '%.4f sec' % (time_new-time_sub) + time_sub= time_new + + + print '\tloading materials and images...', + create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH) + + time_new= sys.time() + print '%.4f sec' % (time_new-time_sub) + time_sub= time_new + + + # deselect all + scn = bpy.data.scenes.active + scn.objects.selected = [] + new_objects= [] # put new objects here + + print '\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ), + # Split the mesh by objects/materials, may + if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True + else: SPLIT_OB_OR_GROUP = False + + for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS): + # Create meshes from the data + create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, dataname) + + axis_min= [ 1000000000]*3 + axis_max= [-1000000000]*3 + + if CLAMP_SIZE: + # Get all object bounds + for ob in new_objects: + for v in ob.getBoundBox(): + for axis, value in enumerate(v): + if axis_min[axis] > value: axis_min[axis]= value + if axis_max[axis] < value: axis_max[axis]= value + + # Scale objects + max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2]) + scale= 1.0 + + while CLAMP_SIZE < max_axis * scale: + scale= scale/10.0 + + for ob in new_objects: + ob.setSize(scale, scale, scale) + + time_new= sys.time() + + print '%.4f sec' % (time_new-time_sub) + print 'finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main)) + + +DEBUG= True + + +def load_obj_ui(filepath, BATCH_LOAD= False): + if BPyMessages.Error_NoFile(filepath): + return + + + CREATE_SMOOTH_GROUPS= Draw.Create(0) + CREATE_FGONS= Draw.Create(1) + CREATE_EDGES= Draw.Create(1) + SPLIT_OBJECTS= Draw.Create(1) + SPLIT_GROUPS= Draw.Create(1) + SPLIT_MATERIALS= Draw.Create(1) + MORPH_TARGET= Draw.Create(0) + CLAMP_SIZE= Draw.Create(10.0) + IMAGE_SEARCH= Draw.Create(1) + + + # Get USER Options + pup_block= [\ + 'Import...',\ + ('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\ + ('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\ + ('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\ + 'Separate objects from obj...',\ + ('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\ + ('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\ + ('Material', SPLIT_MATERIALS, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)'),\ + 'Options...',\ + ('Morph Target', MORPH_TARGET, 'Keep vert and face order, disables some other options.'),\ + ('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\ + ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\ + ] + + if not Draw.PupBlock('Import OBJ...', pup_block): + return + + if MORPH_TARGET.val: + SPLIT_OBJECTS.val = False + SPLIT_GROUPS.val = False + SPLIT_MATERIALS.val = False + + Window.WaitCursor(1) + + if BATCH_LOAD: # load the dir + try: + files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ] + except: + Window.WaitCursor(0) + Draw.PupMenu('Error%t|Could not open path ' + filepath) + return + + if not files: + Window.WaitCursor(0) + Draw.PupMenu('Error%t|No files at path ' + filepath) + return + + for f in files: + scn= bpy.data.scenes.new( stripExt(f) ) + scn.makeCurrent() + + load_obj(sys.join(filepath, f),\ + CLAMP_SIZE.val,\ + CREATE_FGONS.val,\ + CREATE_SMOOTH_GROUPS.val,\ + CREATE_EDGES.val,\ + SPLIT_OBJECTS.val,\ + SPLIT_GROUPS.val,\ + SPLIT_MATERIALS.val,\ + IMAGE_SEARCH.val,\ + ) + + else: # Normal load + load_obj(filepath,\ + CLAMP_SIZE.val,\ + CREATE_FGONS.val,\ + CREATE_SMOOTH_GROUPS.val,\ + CREATE_EDGES.val,\ + SPLIT_OBJECTS.val,\ + SPLIT_GROUPS.val,\ + SPLIT_MATERIALS.val,\ + IMAGE_SEARCH.val,\ + ) + + Window.WaitCursor(0) + + +def load_obj_ui_batch(file): + load_obj_ui(file, True) + +DEBUG= False + +if __name__=='__main__' and not DEBUG: + if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: + Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') + else: + Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') + + +''' +# For testing compatibility +else: + # DEBUG ONLY + TIME= sys.time() + import os + print 'Searching for files' + os.system('find /fe/obj -iname "*.obj" > /tmp/temp3ds_list') + + print '...Done' + file= open('/tmp/temp3ds_list', 'r') + lines= file.readlines() + file.close() + + def between(v,a,b): + if v <= max(a,b) and v >= min(a,b): + return True + return False + + for i, _obj in enumerate(lines): + if between(i, 0,20): + _obj= _obj[:-1] + print 'Importing', _obj, '\nNUMBER', i, 'of', len(lines) + _obj_file= _obj.split('/')[-1].split('\\')[-1] + newScn= bpy.data.scenes.new(_obj_file) + newScn.makeCurrent() + load_obj(_obj, False) + + print 'TOTAL TIME: %.6f' % (sys.time() - TIME) +''' +#load_obj('/test.obj') +#load_obj('/fe/obj/mba1.obj') diff --git a/release/scripts/lightwave_export.py b/release/scripts/lightwave_export.py new file mode 100644 index 00000000000..b0fc1cc7faf --- /dev/null +++ b/release/scripts/lightwave_export.py @@ -0,0 +1,688 @@ +#!BPY + +""" +Name: 'LightWave (.lwo)...' +Blender: 243 +Group: 'Export' +Tooltip: 'Export selected meshes to LightWave File Format (.lwo)' +""" + +__author__ = "Anthony D'Agostino (Scorpius)" +__url__ = ("blender", "elysiun", +"Author's homepage, http://www.redrival.com/scorpius") +__version__ = "Part of IOSuite 0.5" + +__bpydoc__ = """\ +This script exports meshes to LightWave file format. + +LightWave is a full-featured commercial modeling and rendering +application. The lwo file format is composed of 'chunks,' is well +defined, and easy to read and write. It is similar in structure to the +trueSpace cob format. + +Usage:
+ Select meshes to be exported and run this script from "File->Export" menu. + +Supported:
+ UV Coordinates, Meshes, Materials, Material Indices, Specular +Highlights, and Vertex Colors. For added functionality, each object is +placed on its own layer. Someone added the CLIP chunk and imagename support. + +Missing:
+ Not too much, I hope! :). + +Known issues:
+ Empty objects crash has been fixed. + +Notes:
+ For compatibility reasons, it also reads lwo files in the old LW +v5.5 format. +""" + +# $Id$ +# +# +---------------------------------------------------------+ +# | Copyright (c) 2002 Anthony D'Agostino | +# | http://www.redrival.com/scorpius | +# | scorpius@netzero.com | +# | April 21, 2002 | +# | Read and write LightWave Object File Format (*.lwo) | +# +---------------------------------------------------------+ + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +import Blender +import struct, cStringIO, operator +import BPyMesh + +VCOL_NAME = "\251 Per-Face Vertex Colors" +DEFAULT_NAME = "\251 Blender Default" +# ============================== +# === Write LightWave Format === +# ============================== +def write(filename): + start = Blender.sys.time() + file = open(filename, "wb") + + scn = Blender.Scene.GetCurrent() + objects = list(scn.objects.context) + + if not objects: + Blender.Draw.PupMenu('Error%t|No Objects selected') + return + + try: objects.sort( key = lambda a: a.name ) + except: objects.sort(lambda a,b: cmp(a.name, b.name)) + + text = generate_text() + desc = generate_desc() + icon = "" #generate_icon() + + meshes = [] + for obj in objects: + mesh = BPyMesh.getMeshFromObject(obj, None, True, False, scn) + if mesh: + mesh.transform(obj.matrixWorld) + meshes.append(mesh) + + material_names = get_used_material_names(meshes) + tags = generate_tags(material_names) + surfs = generate_surfs(material_names) + chunks = [text, desc, icon, tags] + + meshdata = cStringIO.StringIO() + + layer_index = 0 + + for mesh in meshes: + layr = generate_layr(obj.name, layer_index) + pnts = generate_pnts(mesh) + bbox = generate_bbox(mesh) + pols = generate_pols(mesh) + ptag = generate_ptag(mesh, material_names) + clip = generate_clip(mesh, material_names) + + if mesh.faceUV: + vmad_uv = generate_vmad_uv(mesh) # per face + + if mesh.vertexColors: + #if meshtools.average_vcols: + # vmap_vc = generate_vmap_vc(mesh) # per vert + #else: + vmad_vc = generate_vmad_vc(mesh) # per face + + write_chunk(meshdata, "LAYR", layr); chunks.append(layr) + write_chunk(meshdata, "PNTS", pnts); chunks.append(pnts) + write_chunk(meshdata, "BBOX", bbox); chunks.append(bbox) + write_chunk(meshdata, "POLS", pols); chunks.append(pols) + write_chunk(meshdata, "PTAG", ptag); chunks.append(ptag) + + if mesh.vertexColors: + #if meshtools.average_vcols: + # write_chunk(meshdata, "VMAP", vmap_vc) + # chunks.append(vmap_vc) + #else: + write_chunk(meshdata, "VMAD", vmad_vc) + chunks.append(vmad_vc) + + if mesh.faceUV: + write_chunk(meshdata, "VMAD", vmad_uv) + chunks.append(vmad_uv) + write_chunk(meshdata, "CLIP", clip) + chunks.append(clip) + + layer_index += 1 + mesh.verts = None # save some ram + + for surf in surfs: + chunks.append(surf) + + write_header(file, chunks) + write_chunk(file, "ICON", icon) + write_chunk(file, "TEXT", text) + write_chunk(file, "DESC", desc) + write_chunk(file, "TAGS", tags) + file.write(meshdata.getvalue()); meshdata.close() + for surf in surfs: + write_chunk(file, "SURF", surf) + write_chunk(file, "DATE", "August 19, 2005") + + Blender.Window.DrawProgressBar(1.0, "") # clear progressbar + file.close() + print '\a\r', + print "Successfully exported %s in %.3f seconds" % (filename.split('\\')[-1].split('/')[-1], Blender.sys.time() - start) + + +# ======================================= +# === Generate Null-Terminated String === +# ======================================= +def generate_nstring(string): + if len(string)%2 == 0: # even + string += "\0\0" + else: # odd + string += "\0" + return string + +# =============================== +# === Get Used Material Names === +# =============================== +def get_used_material_names(meshes): + matnames = {} + for mesh in meshes: + if (not mesh.materials) and mesh.vertexColors: + # vcols only + matnames[VCOL_NAME] = None + + elif mesh.materials and (not mesh.vertexColors): + # materials only + for material in mesh.materials: + if material: + matnames[material.name] = None + elif (not mesh.materials) and (not mesh.vertexColors): + # neither + matnames[DEFAULT_NAME] = None + else: + # both + for material in mesh.materials: + if material: + matnames[material.name] = None + return matnames.keys() + +# ========================================= +# === Generate Tag Strings (TAGS Chunk) === +# ========================================= +def generate_tags(material_names): + if material_names: + material_names = map(generate_nstring, material_names) + tags_data = reduce(operator.add, material_names) + else: + tags_data = generate_nstring(''); + return tags_data + +# ======================== +# === Generate Surface === +# ======================== +def generate_surface(name): + #if name.find("\251 Per-") == 0: + # return generate_vcol_surf(mesh) + if name == DEFAULT_NAME: + return generate_default_surf() + else: + return generate_surf(name) + +# ====================== +# === Generate Surfs === +# ====================== +def generate_surfs(material_names): + return map(generate_surface, material_names) + +# =================================== +# === Generate Layer (LAYR Chunk) === +# =================================== +def generate_layr(name, idx): + data = cStringIO.StringIO() + data.write(struct.pack(">h", idx)) # layer number + data.write(struct.pack(">h", 0)) # flags + data.write(struct.pack(">fff", 0, 0, 0)) # pivot + data.write(generate_nstring(name)) # name + return data.getvalue() + +# =================================== +# === Generate Verts (PNTS Chunk) === +# =================================== +def generate_pnts(mesh): + data = cStringIO.StringIO() + for i, v in enumerate(mesh.verts): + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Writing Verts") + x, y, z = v.co + data.write(struct.pack(">fff", x, z, y)) + return data.getvalue() + +# ========================================== +# === Generate Bounding Box (BBOX Chunk) === +# ========================================== +def generate_bbox(mesh): + data = cStringIO.StringIO() + # need to transform verts here + if mesh.verts: + nv = [v.co for v in mesh.verts] + xx = [ co[0] for co in nv ] + yy = [ co[1] for co in nv ] + zz = [ co[2] for co in nv ] + else: + xx = yy = zz = [0.0,] + + data.write(struct.pack(">6f", min(xx), min(zz), min(yy), max(xx), max(zz), max(yy))) + return data.getvalue() + +# ======================================== +# === Average All Vertex Colors (Fast) === +# ======================================== +''' +def average_vertexcolors(mesh): + vertexcolors = {} + vcolor_add = lambda u, v: [u[0]+v[0], u[1]+v[1], u[2]+v[2], u[3]+v[3]] + vcolor_div = lambda u, s: [u[0]/s, u[1]/s, u[2]/s, u[3]/s] + for i, f in enumerate(mesh.faces): # get all vcolors that share this vertex + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Finding Shared VColors") + col = f.col + for j in xrange(len(f)): + index = f[j].index + color = col[j] + r,g,b = color.r, color.g, color.b + vertexcolors.setdefault(index, []).append([r,g,b,255]) + i = 0 + for index, value in vertexcolors.iteritems(): # average them + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.verts), "Averaging Vertex Colors") + vcolor = [0,0,0,0] # rgba + for v in value: + vcolor = vcolor_add(vcolor, v) + shared = len(value) + value[:] = vcolor_div(vcolor, shared) + i+=1 + return vertexcolors +''' + +# ==================================================== +# === Generate Per-Vert Vertex Colors (VMAP Chunk) === +# ==================================================== +# Blender now has all vcols per face +""" +def generate_vmap_vc(mesh): + data = cStringIO.StringIO() + data.write("RGB ") # type + data.write(struct.pack(">H", 3)) # dimension + data.write(generate_nstring("Blender's Vertex Colors")) # name + vertexcolors = average_vertexcolors(mesh) + for i in xrange(len(vertexcolors)): + try: r, g, b, a = vertexcolors[i] # has a face user + except: r, g, b, a = 255,255,255,255 + data.write(struct.pack(">H", i)) # vertex index + data.write(struct.pack(">fff", r/255.0, g/255.0, b/255.0)) + return data.getvalue() +""" + +# ==================================================== +# === Generate Per-Face Vertex Colors (VMAD Chunk) === +# ==================================================== +def generate_vmad_vc(mesh): + data = cStringIO.StringIO() + data.write("RGB ") # type + data.write(struct.pack(">H", 3)) # dimension + data.write(generate_nstring("Blender's Vertex Colors")) # name + for i, f in enumerate(mesh.faces): + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Vertex Colors") + col = f.col + f_v = f.v + for j in xrange(len(f)-1, -1, -1): # Reverse order + r,g,b, dummy = tuple(col[j]) + data.write(struct.pack(">H", f_v[j].index)) # vertex index + data.write(struct.pack(">H", i)) # face index + data.write(struct.pack(">fff", r/255.0, g/255.0, b/255.0)) + return data.getvalue() + +# ================================================ +# === Generate Per-Face UV Coords (VMAD Chunk) === +# ================================================ +def generate_vmad_uv(mesh): + data = cStringIO.StringIO() + data.write("TXUV") # type + data.write(struct.pack(">H", 2)) # dimension + data.write(generate_nstring("Blender's UV Coordinates")) # name + + for i, f in enumerate(mesh.faces): + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing UV Coordinates") + + uv = f.uv + f_v = f.v + for j in xrange(len(f)-1, -1, -1): # Reverse order + U,V = uv[j] + v = f_v[j].index + data.write(struct.pack(">H", v)) # vertex index + data.write(struct.pack(">H", i)) # face index + data.write(struct.pack(">ff", U, V)) + return data.getvalue() + +# ====================================== +# === Generate Variable-Length Index === +# ====================================== +def generate_vx(index): + if index < 0xFF00: + value = struct.pack(">H", index) # 2-byte index + else: + value = struct.pack(">L", index | 0xFF000000) # 4-byte index + return value + +# =================================== +# === Generate Faces (POLS Chunk) === +# =================================== +def generate_pols(mesh): + data = cStringIO.StringIO() + data.write("FACE") # polygon type + for i,f in enumerate(mesh.faces): + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Faces") + data.write(struct.pack(">H", len(f))) # numfaceverts + numfaceverts = len(f) + f_v = f.v + for j in xrange(numfaceverts-1, -1, -1): # Reverse order + data.write(generate_vx(f_v[j].index)) + return data.getvalue() + +# ================================================= +# === Generate Polygon Tag Mapping (PTAG Chunk) === +# ================================================= +def generate_ptag(mesh, material_names): + + def surf_indicies(mat): + try: + if mat: + return material_names.index(mat.name) + except: + pass + + return 0 + + + data = cStringIO.StringIO() + data.write("SURF") # polygon tag type + mesh_materials = mesh.materials + mesh_surfindicies = [surf_indicies(mat) for mat in mesh_materials] + + try: VCOL_NAME_SURF_INDEX = material_names.index(VCOL_NAME) + except: VCOL_NAME_SURF_INDEX = 0 + + try: DEFAULT_NAME_SURF_INDEX = material_names.index(DEFAULT_NAME) + except: DEFAULT_NAME_SURF_INDEX = 0 + len_mat = len(mesh_materials) + for i, f in enumerate(mesh.faces): # numfaces + f_mat = f.mat + if f_mat >= len_mat: f_mat = 0 # Rare annoying eror + + + if not i%100: + Blender.Window.DrawProgressBar(float(i)/len(mesh.faces), "Writing Surface Indices") + + data.write(generate_vx(i)) + if (not mesh_materials) and mesh.vertexColors: # vcols only + surfidx = VCOL_NAME_SURF_INDEX + elif mesh_materials and not mesh.vertexColors: # materials only + surfidx = mesh_surfindicies[f_mat] + elif (not mesh_materials) and (not mesh.vertexColors): # neither + surfidx = DEFAULT_NAME_SURF_INDEX + else: # both + surfidx = mesh_surfindicies[f_mat] + + data.write(struct.pack(">H", surfidx)) # surface index + return data.getvalue() + +# =================================================== +# === Generate VC Surface Definition (SURF Chunk) === +# =================================================== +def generate_vcol_surf(mesh): + data = cStringIO.StringIO() + if mesh.vertexColors: + surface_name = generate_nstring(VCOL_NAME) + data.write(surface_name) + data.write("\0\0") + + data.write("COLR") + data.write(struct.pack(">H", 14)) + data.write(struct.pack(">fffH", 1, 1, 1, 0)) + + data.write("DIFF") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 0.0, 0)) + + data.write("LUMI") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 1.0, 0)) + + data.write("VCOL") + data.write(struct.pack(">H", 34)) + data.write(struct.pack(">fH4s", 1.0, 0, "RGB ")) # intensity, envelope, type + data.write(generate_nstring("Blender's Vertex Colors")) # name + + data.write("CMNT") # material comment + comment = "Vertex Colors: Exported from Blender\256 243" + comment = generate_nstring(comment) + data.write(struct.pack(">H", len(comment))) + data.write(comment) + return data.getvalue() + +# ================================================ +# === Generate Surface Definition (SURF Chunk) === +# ================================================ +def generate_surf(material_name): + data = cStringIO.StringIO() + data.write(generate_nstring(material_name)) + data.write("\0\0") + + try: + material = Blender.Material.Get(material_name) + R,G,B = material.R, material.G, material.B + ref = material.ref + emit = material.emit + spec = material.spec + hard = material.hard + + except: + material = None + + R=G=B = 1.0 + ref = 1.0 + emit = 0.0 + spec = 0.2 + hard = 0.0 + + + data.write("COLR") + data.write(struct.pack(">H", 14)) + data.write(struct.pack(">fffH", R, G, B, 0)) + + data.write("DIFF") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", ref, 0)) + + data.write("LUMI") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", emit, 0)) + + data.write("SPEC") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", spec, 0)) + + data.write("GLOS") + data.write(struct.pack(">H", 6)) + gloss = hard / (255/2.0) + gloss = round(gloss, 1) + data.write(struct.pack(">fH", gloss, 0)) + + data.write("CMNT") # material comment + comment = material_name + ": Exported from Blender\256 243" + comment = generate_nstring(comment) + data.write(struct.pack(">H", len(comment))) + data.write(comment) + + # Check if the material contains any image maps + if material: + mtextures = material.getTextures() # Get a list of textures linked to the material + for mtex in mtextures: + if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE): # Check if the texture is of type "IMAGE" + data.write("BLOK") # Surface BLOK header + data.write(struct.pack(">H", 104)) # Hardcoded and ugly! Will only handle 1 image per material + + # IMAP subchunk (image map sub header) + data.write("IMAP") + data_tmp = cStringIO.StringIO() + data_tmp.write(struct.pack(">H", 0)) # Hardcoded - not sure what it represents + data_tmp.write("CHAN") + data_tmp.write(struct.pack(">H", 4)) + data_tmp.write("COLR") + data_tmp.write("OPAC") # Hardcoded texture layer opacity + data_tmp.write(struct.pack(">H", 8)) + data_tmp.write(struct.pack(">H", 0)) + data_tmp.write(struct.pack(">f", 1.0)) + data_tmp.write(struct.pack(">H", 0)) + data_tmp.write("ENAB") + data_tmp.write(struct.pack(">HH", 2, 1)) # 1 = texture layer enabled + data_tmp.write("NEGA") + data_tmp.write(struct.pack(">HH", 2, 0)) # Disable negative image (1 = invert RGB values) + data_tmp.write("AXIS") + data_tmp.write(struct.pack(">HH", 2, 1)) + data.write(struct.pack(">H", len(data_tmp.getvalue()))) + data.write(data_tmp.getvalue()) + + # IMAG subchunk + data.write("IMAG") + data.write(struct.pack(">HH", 2, 1)) + data.write("PROJ") + data.write(struct.pack(">HH", 2, 5)) # UV projection + + data.write("VMAP") + uvname = generate_nstring("Blender's UV Coordinates") + data.write(struct.pack(">H", len(uvname))) + data.write(uvname) + + return data.getvalue() + +# ============================================= +# === Generate Default Surface (SURF Chunk) === +# ============================================= +def generate_default_surf(): + data = cStringIO.StringIO() + material_name = DEFAULT_NAME + data.write(generate_nstring(material_name)) + data.write("\0\0") + + data.write("COLR") + data.write(struct.pack(">H", 14)) + data.write(struct.pack(">fffH", 1, 1, 1, 0)) + + data.write("DIFF") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 0.8, 0)) + + data.write("LUMI") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 0, 0)) + + data.write("SPEC") + data.write(struct.pack(">H", 6)) + data.write(struct.pack(">fH", 0.5, 0)) + + data.write("GLOS") + data.write(struct.pack(">H", 6)) + gloss = 50 / (255/2.0) + gloss = round(gloss, 1) + data.write(struct.pack(">fH", gloss, 0)) + + data.write("CMNT") # material comment + comment = material_name + ": Exported from Blender\256 243" + + # vals = map(chr, xrange(164,255,1)) + # keys = xrange(164,255,1) + # keys = map(lambda x: `x`, keys) + # comment = map(None, keys, vals) + # comment = reduce(operator.add, comment) + # comment = reduce(operator.add, comment) + + comment = generate_nstring(comment) + data.write(struct.pack(">H", len(comment))) + data.write(comment) + return data.getvalue() + +# ============================================ +# === Generate Object Comment (TEXT Chunk) === +# ============================================ +def generate_text(): + comment = "Lightwave Export Script for Blender by Anthony D'Agostino" + return generate_nstring(comment) + +# ============================================== +# === Generate Description Line (DESC Chunk) === +# ============================================== +def generate_desc(): + comment = "Copyright 2002 Scorpius Entertainment" + return generate_nstring(comment) + +# ================================================== +# === Generate Thumbnail Icon Image (ICON Chunk) === +# ================================================== +def generate_icon(): + data = cStringIO.StringIO() + file = open("f:/obj/radiosity/lwo2_icon.tga", "rb") # 60x60 uncompressed TGA + file.read(18) + icon_data = file.read(3600) # ? + file.close() + data.write(struct.pack(">HH", 0, 60)) + data.write(icon_data) + #print len(icon_data) + return data.getvalue() + +# =============================================== +# === Generate CLIP chunk with STIL subchunks === +# =============================================== +def generate_clip(mesh, material_names): + data = cStringIO.StringIO() + clipid = 1 + for i, material in enumerate(mesh.materials): # Run through list of materials used by mesh + if material: + mtextures = material.getTextures() # Get a list of textures linked to the material + for mtex in mtextures: + if (mtex) and (mtex.tex.type == Blender.Texture.Types.IMAGE): # Check if the texture is of type "IMAGE" + pathname = mtex.tex.image.filename # If full path is needed use filename in place of name + pathname = pathname[0:2] + pathname.replace("\\", "/")[3:] # Convert to Modo standard path + imagename = generate_nstring(pathname) + data.write(struct.pack(">L", clipid)) # CLIP sequence/id + data.write("STIL") # STIL image + data.write(struct.pack(">H", len(imagename))) # Size of image name + data.write(imagename) + clipid += 1 + return data.getvalue() + +# =================== +# === Write Chunk === +# =================== +def write_chunk(file, name, data): + file.write(name) + file.write(struct.pack(">L", len(data))) + file.write(data) + +# ============================= +# === Write LWO File Header === +# ============================= +def write_header(file, chunks): + chunk_sizes = map(len, chunks) + chunk_sizes = reduce(operator.add, chunk_sizes) + form_size = chunk_sizes + len(chunks)*8 + len("FORM") + file.write("FORM") + file.write(struct.pack(">L", form_size)) + file.write("LWO2") + +def fs_callback(filename): + if not filename.lower().endswith('.lwo'): filename += '.lwo' + write(filename) + +Blender.Window.FileSelector(fs_callback, "Export LWO", Blender.sys.makename(ext='.lwo')) diff --git a/release/scripts/lightwave_import.py b/release/scripts/lightwave_import.py new file mode 100644 index 00000000000..24e072f018a --- /dev/null +++ b/release/scripts/lightwave_import.py @@ -0,0 +1,1694 @@ +#!BPY +""" +Name: 'LightWave (.lwo)...' +Blender: 239 +Group: 'Import' +Tooltip: 'Import LightWave Object File Format' +""" + +__author__ = ["Alessandro Pirovano, Anthony D'Agostino (Scorpius)", "Campbell Barton (ideasman42)", "ZanQdo"] +__url__ = ("www.blender.org", "blenderartist.org", +"Anthony's homepage, http://www.redrival.com/scorpius", "Alessandro's homepage, http://uaraus.altervista.org") + +importername = "lwo_import 0.4.0" + +# +---------------------------------------------------------+ +# | Save your work before and after use. | +# | Please report any useful comment to: | +# | uaraus-dem@yahoo.it | +# | Thanks | +# +---------------------------------------------------------+ +# +---------------------------------------------------------+ +# | Copyright (c) 2002 Anthony D'Agostino | +# | http://www.redrival.com/scorpius | +# | scorpius@netzero.com | +# | April 21, 2002 | +# | Import Export Suite v0.5 | +# +---------------------------------------------------------+ +# | Read and write LightWave Object File Format (*.lwo) | +# +---------------------------------------------------------+ +# +---------------------------------------------------------+ +# | Alessandro Pirovano tweaked starting on March 2005 | +# | http://uaraus.altervista.org | +# +---------------------------------------------------------+ +# +---------------------------------------------------------- +# | GPL license block +# | +# | This program is free software; you can redistribute it and/or modify +# | it under the terms of the GNU General Public License as published by +# | the Free Software Foundation; either version 2 of the License, or +# | (at your option) any later version. +# | +# | This program is distributed in the hope that it will be useful, +# | but WITHOUT ANY WARRANTY; without even the implied warranty of +# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# | GNU General Public License for more details. +# | +# | You should have received a copy of the GNU General Public License +# | along with this program; if not, write to the Free Software +# | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +---------------------------------------------------------- +# +---------------------------------------------------------+ +# | Release log: | +# | 0.4.0 : Updated for blender 2.44 | +# | ZanQdo - made the mesh import the right way up | +# | Ideasman42 - Updated functions for the bew API | +# | as well as removing the text object class | +# | 0.2.2 : This code works with Blender 2.42 RC3 | +# | Added a new PolyFill function for BPYMesh's | +# | ngon() to use, checked compatibility | +# | lightwaves ngons are imported as fgons | +# | Checked compatibility against 1711 lwo files | +# | 0.2.1 : This code works with Blender 2.40 RC1 | +# | modified material mode assignment to deal with | +# | Python API modification | +# | Changed script license to GNU GPL | +# | 0.2.0: This code works with Blender 2.40a2 or up | +# | Major rewrite to deal with large meshes | +# | - 2 pass file parsing | +# | - lower memory foot###if DEBUG: print | +# | (as long as python gc allows) | +# | 2.40a2 - Removed subsurf settings patches=poly | +# | 2.40a2 - Edge generation instead of 2vert faces | +# | 0.1.16: fixed (try 2) texture offset calculations | +# | added hint on axis mapping | +# | added hint on texture blending mode | +# | added hint on texture transparency setting | +# | search images in original directory first | +# | fixed texture order application | +# | 0.1.15: added release log | +# | fixed texture offset calculations (non-UV) | +# | fixed reverting vertex order in face generation | +# | associate texture on game-engine settings | +# | vector math definitely based on mathutils | +# | search images in "Images" and "../Images" dir | +# | revised logging facility | +# | fixed subsurf texture and material mappings | +# | 0.1.14: patched missing mod_vector (not definitive) | +# | 0.1.13: first public release | +# +---------------------------------------------------------+ + +#blender related import +import Blender +import bpy + +# use for comprehensiveImageLoad +import BPyImage + +# Use this ngon function +import BPyMesh + +import BPyMessages + +#python specific modules import +try: + import struct, chunk, cStringIO +except: + struct= chunk= cStringIO= None + +### # Debuggin disabled in release. +### # do a search replace to enabe debug prints +### DEBUG = False + +# =========================================================== +# === Utility Preamble ====================================== +# =========================================================== + +textname = None +#uncomment the following line to enable logging facility to the named text object +#textname = "lwo_log" + +TXMTX = Blender.Mathutils.Matrix(\ +[1, 0, 0, 0],\ +[0, 0, 1, 0],\ +[0, 1, 0, 0],\ +[0, 0, 0, 1]) + +# =========================================================== +# === Make sure it is a string ... deal with strange chars == +# =========================================================== +def safestring(st): + myst = "" + for ll in xrange(len(st)): + if st[ll] < " ": + myst += "#" + else: + myst += st[ll] + return myst + +# =========================================================== +# === Main read functions =================================== +# =========================================================== + +# ============================= +# === Read LightWave Format === +# ============================= +def read(filename): + if BPyMessages.Error_NoFile(filename): + return + + print "This is: %s" % importername + print "Importing file:", filename + bpy.data.scenes.active.objects.selected = [] + + start = Blender.sys.time() + file = open(filename, "rb") + + editmode = Blender.Window.EditMode() # are we in edit mode? If so ... + if editmode: Blender.Window.EditMode(0) # leave edit mode before getting the mesh # === LWO header === + + try: + form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) + except: + Blender.Draw.PupMenu('Error%t|This is not a lightwave file') + return + + if (form_type == "LWOB"): + read_lwob(file, filename) + elif (form_type == "LWO2"): + read_lwo2(file, filename) + else: + print "Can't read a file with the form_type: %s" % form_type + return + + Blender.Window.DrawProgressBar(1.0, "") # clear progressbar + file.close() + end = Blender.sys.time() + seconds = " in %.2f %s" % (end-start, "seconds") + if form_type == "LWO2": fmt = " (v6.0 Format)" + if form_type == "LWOB": fmt = " (v5.5 Format)" + print "Successfully imported " + filename.split('\\')[-1].split('/')[-1] + fmt + seconds + + if editmode: Blender.Window.EditMode(1) # optional, just being nice + Blender.Redraw() + +# enddef read + + +# ================================= +# === Read LightWave 5.5 format === +# ================================= +def read_lwob(file, filename): + #This function is directly derived from the LWO2 import routine + #dropping all the material analysis parts + + ###if DEBUG: print "LightWave 5.5 format" + + dir_part = Blender.sys.dirname(filename) + fname_part = Blender.sys.basename(filename) + #ask_weird = 1 + + #first initialization of data structures + defaultname = Blender.sys.splitext(fname_part)[0] + tag_list = [] #tag list: global for the whole file? + surf_list = [] #surf list: global for the whole file? + clip_list = [] #clip list: global for the whole file? + object_index = 0 + object_list = None + objspec_list = None + + #add default material for orphaned faces, if any + surf_list.append({'NAME': "_Orphans", 'g_MAT': bpy.data.materials.new("_Orphans")}) + + #pass 2: effectively generate objects + ###if DEBUG: print "Pass 1: dry import" + file.seek(0) + objspec_list = ["imported", {}, [], [], {}, {}, 0, {}, {}] + # === LWO header === + form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) + if (form_type != "LWOB"): + ###if DEBUG: print "??? Inconsistent file type: %s" % form_type + return + while 1: + try: + lwochunk = chunk.Chunk(file) + except EOFError: + break + ###if DEBUG: print ' ', + if lwochunk.chunkname == "LAYR": + ###if DEBUG: print "---- LAYR", + objname = read_layr(lwochunk) + ###if DEBUG: print objname + if objspec_list != None: #create the object + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + objspec_list = [objname, {}, [], [], {}, {}, 0, {}, {}] + object_index += 1 + elif lwochunk.chunkname == "PNTS": # Verts + ###if DEBUG: print "---- PNTS", + verts = read_verts(lwochunk) + objspec_list[2] = verts + elif lwochunk.chunkname == "POLS": # Faces v5.5 + ###if DEBUG: print "-------- POLS(5.5)" + faces = read_faces_5(lwochunk) + flag = 0 + #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored + if flag<2: + if objspec_list[3] != []: + #create immediately the object + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + #update with new data + objspec_list = [objspec_list[0], #update name + {}, #init + objspec_list[2], #same vertexes + faces, #give it the new faces + {}, #no need to copy - filled at runtime + {}, #polygon tagging will follow + flag, #patch flag + objspec_list[7], #same uvcoords + {}] #no vmad mapping + object_index += 1 + #end if already has a face list + objspec_list[3] = faces + objname = objspec_list[0] + if objname == None: + objname = defaultname + #end if processing a valid poly type + else: # Misc Chunks + ###if DEBUG: print "---- %s: skipping (definitely!)" % lwochunk.chunkname + lwochunk.skip() + #uncomment here to log data structure as it is built + # ###if DEBUG: print object_list + #last object read + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + objspec_list = None + surf_list = None + clip_list = None + + + ###if DEBUG: print "\nFound %d objects:" % object_index + +# enddef read_lwob + + +# ============================= +# === Read LightWave Format === +# ============================= +def read_lwo2(file, filename, typ="LWO2"): + + ###if DEBUG: print "LightWave 6 (and above) format" + + dir_part = Blender.sys.dirname(filename) + fname_part = Blender.sys.basename(filename) + ask_weird = 1 + + #first initialization of data structures + defaultname = Blender.sys.splitext(fname_part)[0] + tag_list = [] #tag list: global for the whole file? + surf_list = [] #surf list: global for the whole file? + clip_list = [] #clip list: global for the whole file? + object_index = 0 + object_list = None + objspec_list = None + # init value is: object_list = [[None, {}, [], [], {}, {}, 0, {}, {}]] + #0 - objname #original name + #1 - obj_dict = {TAG} #objects created + #2 - verts = [] #object vertexes + #3 - faces = [] #object faces (associations poly -> vertexes) + #4 - obj_dim_dict = {TAG} #tuples size and pos in local object coords - used for NON-UV mappings + #5 - polytag_dict = {TAG} #tag to polygons mapping + #6 - patch_flag #0 = surf; 1 = patch (subdivision surface) - it was the image list + #7 - uvcoords_dict = {name} #uvmap coordinates (mixed mode per vertex/per face) + #8 - facesuv_dict = {name} #vmad only coordinates associations poly & vertex -> uv tuples + + #pass 1: look in advance for materials + ###if DEBUG: print "Starting Pass 1: hold on tight" + while 1: + try: + lwochunk = chunk.Chunk(file) + except EOFError: + break + ###if DEBUG: print ' ', + if lwochunk.chunkname == "TAGS": # Tags + ###if DEBUG: print "---- TAGS" + tag_list.extend(read_tags(lwochunk)) + elif lwochunk.chunkname == "SURF": # surfaces + ###if DEBUG: print "---- SURF" + surf_list.append(read_surfs(lwochunk, surf_list, tag_list)) + elif lwochunk.chunkname == "CLIP": # texture images + ###if DEBUG: print "---- CLIP" + clip_list.append(read_clip(lwochunk, dir_part)) + ###if DEBUG: print "read total %s clips up to now" % len(clip_list) + else: # Misc Chunks + if ask_weird: + ckname = safestring(lwochunk.chunkname) + if "#" in ckname: + choice = Blender.Draw.PupMenu("WARNING: file could be corrupted.%t|Import anyway|Give up") + if choice != 1: + ###if DEBUG: print "---- %s: Maybe file corrupted. Terminated by user" % lwochunk.chunkname + return + ask_weird = 0 + ###if DEBUG: print "---- %s: skipping (maybe later)" % lwochunk.chunkname + lwochunk.skip() + + #add default material for orphaned faces, if any + surf_list.append({'NAME': "_Orphans", 'g_MAT': bpy.data.materials.new("_Orphans")}) + + #pass 2: effectively generate objects + ###if DEBUG: print "Pass 2: now for the hard part" + file.seek(0) + # === LWO header === + form_id, form_size, form_type = struct.unpack(">4s1L4s", file.read(12)) + if (form_type != "LWO2"): + ###if DEBUG: print "??? Inconsistent file type: %s" % form_type + return + while 1: + try: + lwochunk = chunk.Chunk(file) + except EOFError: + break + ###if DEBUG: print ' ', + if lwochunk.chunkname == "LAYR": + ###if DEBUG: print "---- LAYR" + objname = read_layr(lwochunk) + ###if DEBUG: print objname + if objspec_list != None: #create the object + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + objspec_list = [objname, {}, [], [], {}, {}, 0, {}, {}] + object_index += 1 + elif lwochunk.chunkname == "PNTS": # Verts + ###if DEBUG: print "---- PNTS" + verts = read_verts(lwochunk) + objspec_list[2] = verts + elif lwochunk.chunkname == "VMAP": # MAPS (UV) + ###if DEBUG: print "---- VMAP" + #objspec_list[7] = read_vmap(objspec_list[7], len(objspec_list[2]), lwochunk) + read_vmap(objspec_list[7], len(objspec_list[2]), lwochunk) + elif lwochunk.chunkname == "VMAD": # MAPS (UV) per-face + ###if DEBUG: print "---- VMAD" + #objspec_list[7], objspec_list[8] = read_vmad(objspec_list[7], objspec_list[8], len(objspec_list[3]), len(objspec_list[2]), lwochunk) + read_vmad(objspec_list[7], objspec_list[8], len(objspec_list[3]), len(objspec_list[2]), lwochunk) + elif lwochunk.chunkname == "POLS": # Faces v6.0 + ###if DEBUG: print "-------- POLS(6)" + faces, flag = read_faces_6(lwochunk) + #flag is 0 for regular polygon, 1 for patches (= subsurf), 2 for anything else to be ignored + if flag<2: + if objspec_list[3] != []: + #create immediately the object + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + #update with new data + objspec_list = [objspec_list[0], #update name + {}, #init + objspec_list[2], #same vertexes + faces, #give it the new faces + {}, #no need to copy - filled at runtime + {}, #polygon tagging will follow + flag, #patch flag + objspec_list[7], #same uvcoords + {}] #no vmad mapping + object_index += 1 + #end if already has a face list + objspec_list[3] = faces + objname = objspec_list[0] + if objname == None: + objname = defaultname + #end if processing a valid poly type + elif lwochunk.chunkname == "PTAG": # PTags + ###if DEBUG: print "---- PTAG" + polytag_dict = read_ptags(lwochunk, tag_list) + for kk, polytag_dict_val in polytag_dict.iteritems(): objspec_list[5][kk] = polytag_dict_val + else: # Misc Chunks + ###if DEBUG: print "---- %s: skipping (definitely!)" % lwochunk.chunkname + lwochunk.skip() + #uncomment here to log data structure as it is built + + #last object read + create_objects(clip_list, objspec_list, surf_list) + update_material(clip_list, objspec_list, surf_list) #give it all the object + objspec_list = None + surf_list = None + clip_list = None + + ###if DEBUG: print "\nFound %d objects:" % object_index +# enddef read_lwo2 + + + + + + +# =========================================================== +# === File reading routines ================================= +# =========================================================== +# ================== +# === Read Verts === +# ================== +def read_verts(lwochunk): + #data = cStringIO.StringIO(lwochunk.read()) + numverts = lwochunk.chunksize/12 + return [struct.unpack(">fff", lwochunk.read(12)) for i in xrange(numverts)] +# enddef read_verts + + +# ================= +# === Read Name === +# ================= +# modified to deal with odd lenght strings +def read_name(file): + name = "" + while 1: + char = file.read(1) + if char == "\0": break + else: name += char + len_name = len(name) + 1 #count the trailing zero + if len_name%2==1: + char = file.read(1) #remove zero padding to even lenght + len_name += 1 + return name, len_name + + +# ================== +# === Read Layer === +# ================== +def read_layr(lwochunk): + data = cStringIO.StringIO(lwochunk.read()) + idx, flags = struct.unpack(">hh", data.read(4)) + pivot = struct.unpack(">fff", data.read(12)) + layer_name, discard = read_name(data) + if not layer_name: layer_name = "NoName" + return layer_name +# enddef read_layr + + +# ====================== +# === Read Faces 5.5 === +# ====================== +def read_faces_5(lwochunk): + data = cStringIO.StringIO(lwochunk.read()) + faces = [] + i = 0 + while i < lwochunk.chunksize: + #if not i%1000 and my_meshtools.show_progress: + # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces") + + numfaceverts, = struct.unpack(">H", data.read(2)) + facev = [struct.unpack(">H", data.read(2))[0] for j in xrange(numfaceverts)] + facev.reverse() + faces.append(facev) + surfaceindex, = struct.unpack(">H", data.read(2)) + if surfaceindex < 0: + ###if DEBUG: print "***Error. Referencing uncorrect surface index" + return + i += (4+numfaceverts*2) + return faces + + +# ================================== +# === Read Variable-Length Index === +# ================================== +def read_vx(data): + byte1, = struct.unpack(">B", data.read(1)) + if byte1 != 0xFF: # 2-byte index + byte2, = struct.unpack(">B", data.read(1)) + index = byte1*256 + byte2 + index_size = 2 + else: # 4-byte index + byte2, byte3, byte4 = struct.unpack(">3B", data.read(3)) + index = byte2*65536 + byte3*256 + byte4 + index_size = 4 + return index, index_size + + +# ====================== +# === Read uvmapping === +# ====================== +def read_vmap(uvcoords_dict, maxvertnum, lwochunk): + + if maxvertnum == 0: + ###if DEBUG: print "Found VMAP but no vertexes to map!" + return uvcoords_dict + data = cStringIO.StringIO(lwochunk.read()) + map_type = data.read(4) + if map_type != "TXUV": + ###if DEBUG: print "Reading VMAP: No Texture UV map Were Found. Map Type: %s" % map_type + return uvcoords_dict + dimension, = struct.unpack(">H", data.read(2)) + name, i = read_name(data) #i initialized with string lenght + zeros + ###if DEBUG: print "TXUV %d %s" % (dimension, name) + #note if there is already a VMAD it will be lost + #it is assumed that VMAD will follow the corresponding VMAP + Vector = Blender.Mathutils.Vector + try: #if uvcoords_dict.has_key(name): + my_uv_dict = uvcoords_dict[name] #update existing + except: #else: + my_uv_dict = {} #start a brand new: this could be made more smart + while (i < lwochunk.chunksize - 6): #4+2 header bytes already read + vertnum, vnum_size = read_vx(data) + uv = struct.unpack(">ff", data.read(8)) + if vertnum >= maxvertnum: + ###if DEBUG: print "Hem: more uvmap than vertexes? ignoring uv data for vertex %d" % vertnum + pass + else: + my_uv_dict[vertnum] = Vector(uv) + i += 8 + vnum_size + #end loop on uv pairs + uvcoords_dict[name] = my_uv_dict + #this is a per-vertex mapping AND the uv tuple is vertex-ordered, so faces_uv is the same as faces + #return uvcoords_dict + return + +# ======================== +# === Read uvmapping 2 === +# ======================== +def read_vmad(uvcoords_dict, facesuv_dict, maxfacenum, maxvertnum, lwochunk): + if maxvertnum == 0 or maxfacenum == 0: + ###if DEBUG: print "Found VMAD but no vertexes to map!" + return uvcoords_dict, facesuv_dict + data = cStringIO.StringIO(lwochunk.read()) + map_type = data.read(4) + if map_type != "TXUV": + ###if DEBUG: print "Reading VMAD: No Texture UV map Were Found. Map Type: %s" % map_type + return uvcoords_dict, facesuv_dict + dimension, = struct.unpack(">H", data.read(2)) + name, i = read_name(data) #i initialized with string lenght + zeros + ###if DEBUG: print "TXUV %d %s" % (dimension, name) + try: #if uvcoords_dict.has_key(name): + my_uv_dict = uvcoords_dict[name] #update existing + except: #else: + my_uv_dict = {} #start a brand new: this could be made more smart + my_facesuv_list = [] + newindex = maxvertnum + 10 #why +10? Why not? + #end variable initialization + Vector = Blender.Mathutils.Vector + while (i < lwochunk.chunksize - 6): #4+2 header bytes already read + vertnum, vnum_size = read_vx(data) + i += vnum_size + polynum, vnum_size = read_vx(data) + i += vnum_size + uv = struct.unpack(">ff", data.read(8)) + if polynum >= maxfacenum or vertnum >= maxvertnum: + ###if DEBUG: print "Hem: more uvmap than vertexes? ignorig uv data for vertex %d" % vertnum + pass + else: + my_uv_dict[newindex] = Vector(uv) + my_facesuv_list.append([polynum, vertnum, newindex]) + newindex += 1 + i += 8 + #end loop on uv pairs + uvcoords_dict[name] = my_uv_dict + facesuv_dict[name] = my_facesuv_list + ###if DEBUG: print "updated %d vertexes data" % (newindex-maxvertnum-10) + return + + +# ================= +# === Read tags === +# ================= +def read_tags(lwochunk): + data = cStringIO.StringIO(lwochunk.read()) + tag_list = [] + current_tag = "" + i = 0 + while i < lwochunk.chunksize: + char = data.read(1) + if char == "\0": + tag_list.append(current_tag) + if (len(current_tag) % 2 == 0): char = data.read(1) + current_tag = "" + else: + current_tag += char + i += 1 + ###if DEBUG: print "read %d tags, list follows: %s" % (len(tag_list), tag_list) + return tag_list + + +# ================== +# === Read Ptags === +# ================== +def read_ptags(lwochunk, tag_list): + data = cStringIO.StringIO(lwochunk.read()) + polygon_type = data.read(4) + if polygon_type != "SURF": + ###if DEBUG: print "No Surf Were Found. Polygon Type: %s" % polygon_type + return {} + ptag_dict = {} + i = 0 + while(i < lwochunk.chunksize-4): #4 bytes polygon type already read + #if not i%1000 and my_meshtools.show_progress: + # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading PTAGS") + poln, poln_size = read_vx(data) + i += poln_size + tag_index, = struct.unpack(">H", data.read(2)) + if tag_index > (len(tag_list)): + ###if DEBUG: print "Reading PTAG: Surf belonging to undefined TAG: %d. Skipping" % tag_index + return {} + i += 2 + tag_key = tag_list[tag_index] + try: + ptag_dict[tag_list[tag_index]].append(poln) + except: #if not(ptag_dict.has_key(tag_key)): + ptag_dict[tag_list[tag_index]] = [poln] + + ###if DEBUG: for i, ptag_dict_val in ptag_dict.iteritems(): print "read %d polygons belonging to TAG %s" % (len(ptag_dict_val ), i) + return ptag_dict + + + +# ================== +# === Read Clips === +# ================== +def read_clip(lwochunk, dir_part): +# img, IMG, g_IMG refers to blender image objects +# ima, IMAG, g_IMAG refers to clip dictionary 'ID' entries: refer to blok and surf + clip_dict = {} + data = cStringIO.StringIO(lwochunk.read()) + image_index, = struct.unpack(">L", data.read(4)) + clip_dict['ID'] = image_index + i = 4 + while(i < lwochunk.chunksize): + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">H", data.read(2)) + if subchunkname == "STIL": + ###if DEBUG: print "-------- STIL" + clip_name, k = read_name(data) + #now split text independently from platform + #depend on the system where image was saved. NOT the one where the script is run + no_sep = "\\" + if Blender.sys.sep == no_sep: no_sep ="/" + if (no_sep in clip_name): + clip_name = clip_name.replace(no_sep, Blender.sys.sep) + short_name = Blender.sys.basename(clip_name) + if clip_name == "" or short_name == "": + ###if DEBUG: print "Reading CLIP: Empty clip name not allowed. Skipping" + discard = data.read(subchunklen-k) + clip_dict['NAME'] = clip_name + clip_dict['BASENAME'] = short_name + elif subchunkname == "XREF": #cross reference another image + ###if DEBUG: print "-------- XREF" + image_index, = struct.unpack(">L", data.read(4)) + clip_name, k = read_name(data) + clip_dict['NAME'] = clip_name + clip_dict['XREF'] = image_index + elif subchunkname == "NEGA": #negate texture effect + ###if DEBUG: print "-------- NEGA" + n, = struct.unpack(">H", data.read(2)) + clip_dict['NEGA'] = n + else: # Misc Chunks + ###if DEBUG: print "-------- CLIP:%s: skipping" % subchunkname + discard = data.read(subchunklen) + i = i + 6 + subchunklen + #end loop on surf chunks + ###if DEBUG: print "read image:%s" % clip_dict + if 'XREF' in clip_dict: # has_key + ###if DEBUG: print "Cross-reference: no image pre-allocated." + return clip_dict + #look for images + #img = load_image("",clip_dict['NAME']) + NAME= BASENAME= None + + try: + NAME= clip_dict['NAME'] + BASENAME= clip_dict['BASENAME'] + except: + clip_dict['g_IMG'] = None + return + # ###if DEBUG: print 'test', NAME, BASENAME + img = BPyImage.comprehensiveImageLoad(NAME, dir_part, PLACE_HOLDER= False, RECURSIVE=False) + if not img: + ###if DEBUG: print "***No image %s found: trying LWO file subdir" % NAME + img = BPyImage.comprehensiveImageLoad(BASENAME, dir_part, PLACE_HOLDER= False, RECURSIVE=False) + + ###if DEBUG: if not img: print "***No image %s found: giving up" % BASENAME + #lucky we are: we have an image + ###if DEBUG: print "Image pre-allocated." + clip_dict['g_IMG'] = img + + return clip_dict + + +# =========================== +# === Read Surfaces Block === +# =========================== +def read_surfblok(subchunkdata): + lenght = len(subchunkdata) + my_dict = {} + my_uvname = "" + data = cStringIO.StringIO(subchunkdata) + ############################################################## + # blok header sub-chunk + ############################################################## + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">h", data.read(2)) + accumulate_i = subchunklen + 6 + if subchunkname != 'IMAP': + ###if DEBUG: print "---------- SURF: BLOK: %s: block aborting" % subchunkname + return {}, "" + ###if DEBUG: print "---------- IMAP" + ordinal, i = read_name(data) + my_dict['ORD'] = ordinal + #my_dict['g_ORD'] = -1 + my_dict['ENAB'] = True + while(i < subchunklen): # ---------left 6------------------------- loop on header parameters + sub2chunkname, = struct.unpack("4s", data.read(4)) + sub2chunklen, = struct.unpack(">h", data.read(2)) + i = i + 6 + sub2chunklen + if sub2chunkname == "CHAN": + ###if DEBUG: print "------------ CHAN" + sub2chunkname, = struct.unpack("4s", data.read(4)) + my_dict['CHAN'] = sub2chunkname + sub2chunklen -= 4 + elif sub2chunkname == "ENAB": #only present if is to be disabled + ###if DEBUG: print "------------ ENAB" + ena, = struct.unpack(">h", data.read(2)) + my_dict['ENAB'] = ena + sub2chunklen -= 2 + elif sub2chunkname == "NEGA": #only present if is to be enabled + ###if DEBUG: print "------------ NEGA" + ena, = struct.unpack(">h", data.read(2)) + if ena == 1: + my_dict['NEGA'] = ena + sub2chunklen -= 2 + elif sub2chunkname == "OPAC": #only present if is to be disabled + ###if DEBUG: print "------------ OPAC" + opa, = struct.unpack(">h", data.read(2)) + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['OPAC'] = opa + my_dict['OPACVAL'] = s + sub2chunklen -= 6 + elif sub2chunkname == "AXIS": + ###if DEBUG: print "------------ AXIS" + ena, = struct.unpack(">h", data.read(2)) + my_dict['DISPLAXIS'] = ena + sub2chunklen -= 2 + else: # Misc Chunks + ###if DEBUG: print "------------ SURF: BLOK: IMAP: %s: skipping" % sub2chunkname + discard = data.read(sub2chunklen) + #end loop on blok header subchunks + ############################################################## + # blok attributes sub-chunk + ############################################################## + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">h", data.read(2)) + accumulate_i += subchunklen + 6 + if subchunkname != 'TMAP': + ###if DEBUG: print "---------- SURF: BLOK: %s: block aborting" % subchunkname + return {}, "" + ###if DEBUG: print "---------- TMAP" + i = 0 + while(i < subchunklen): # -----------left 6----------------------- loop on header parameters + sub2chunkname, = struct.unpack("4s", data.read(4)) + sub2chunklen, = struct.unpack(">h", data.read(2)) + i = i + 6 + sub2chunklen + if sub2chunkname == "CNTR": + ###if DEBUG: print "------------ CNTR" + x, y, z = struct.unpack(">fff", data.read(12)) + envelope, env_size = read_vx(data) + my_dict['CNTR'] = [x, y, z] + sub2chunklen -= (12+env_size) + elif sub2chunkname == "SIZE": + ###if DEBUG: print "------------ SIZE" + x, y, z = struct.unpack(">fff", data.read(12)) + envelope, env_size = read_vx(data) + my_dict['SIZE'] = [x, y, z] + sub2chunklen -= (12+env_size) + elif sub2chunkname == "ROTA": + ###if DEBUG: print "------------ ROTA" + x, y, z = struct.unpack(">fff", data.read(12)) + envelope, env_size = read_vx(data) + my_dict['ROTA'] = [x, y, z] + sub2chunklen -= (12+env_size) + elif sub2chunkname == "CSYS": + ###if DEBUG: print "------------ CSYS" + ena, = struct.unpack(">h", data.read(2)) + my_dict['CSYS'] = ena + sub2chunklen -= 2 + else: # Misc Chunks + ###if DEBUG: print "------------ SURF: BLOK: TMAP: %s: skipping" % sub2chunkname + pass + if sub2chunklen > 0: + discard = data.read(sub2chunklen) + #end loop on blok attributes subchunks + ############################################################## + # ok, now other attributes without sub_chunks + ############################################################## + while(accumulate_i < lenght): # ---------------------------------- loop on header parameters: lenght has already stripped the 6 bypes header + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">H", data.read(2)) + accumulate_i = accumulate_i + 6 + subchunklen + if subchunkname == "PROJ": + ###if DEBUG: print "---------- PROJ" + p, = struct.unpack(">h", data.read(2)) + my_dict['PROJ'] = p + subchunklen -= 2 + elif subchunkname == "AXIS": + ###if DEBUG: print "---------- AXIS" + a, = struct.unpack(">h", data.read(2)) + my_dict['MAJAXIS'] = a + subchunklen -= 2 + elif subchunkname == "IMAG": + ###if DEBUG: print "---------- IMAG" + i, i_size = read_vx(data) + my_dict['IMAG'] = i + subchunklen -= i_size + elif subchunkname == "WRAP": + ###if DEBUG: print "---------- WRAP" + ww, wh = struct.unpack(">hh", data.read(4)) + #reduce width and height to just 1 parameter for both + my_dict['WRAP'] = max([ww,wh]) + #my_dict['WRAPWIDTH'] = ww + #my_dict['WRAPHEIGHT'] = wh + subchunklen -= 4 + elif subchunkname == "WRPW": + ###if DEBUG: print "---------- WRPW" + w, = struct.unpack(">f", data.read(4)) + my_dict['WRPW'] = w + envelope, env_size = read_vx(data) + subchunklen -= (env_size+4) + elif subchunkname == "WRPH": + ###if DEBUG: print "---------- WRPH" + w, = struct.unpack(">f", data.read(4)) + my_dict['WRPH'] = w + envelope, env_size = read_vx(data) + subchunklen -= (env_size+4) + elif subchunkname == "VMAP": + ###if DEBUG: print "---------- VMAP" + vmp, i = read_name(data) + my_dict['VMAP'] = vmp + my_uvname = vmp + subchunklen -= i + else: # Misc Chunks + ###if DEBUG: print "---------- SURF: BLOK: %s: skipping" % subchunkname + pass + if subchunklen > 0: + discard = data.read(subchunklen) + #end loop on blok subchunks + return my_dict, my_uvname + + +# ===================== +# === Read Surfaces === +# ===================== +def read_surfs(lwochunk, surf_list, tag_list): + my_dict = {} + data = cStringIO.StringIO(lwochunk.read()) + surf_name, i = read_name(data) + parent_name, j = read_name(data) + i += j + if (surf_name == "") or not(surf_name in tag_list): + ###if DEBUG: print "Reading SURF: Actually empty surf name not allowed. Skipping" + return {} + if (parent_name != ""): + parent_index = [x['NAME'] for x in surf_list].count(parent_name) + if parent_index >0: + my_dict = surf_list[parent_index-1] + my_dict['NAME'] = surf_name + ###if DEBUG: print "Surface data for TAG %s" % surf_name + while(i < lwochunk.chunksize): + subchunkname, = struct.unpack("4s", data.read(4)) + subchunklen, = struct.unpack(">H", data.read(2)) + i = i + 6 + subchunklen #6 bytes subchunk header + if subchunkname == "COLR": #color: mapped on color + ###if DEBUG: print "-------- COLR" + r, g, b = struct.unpack(">fff", data.read(12)) + envelope, env_size = read_vx(data) + my_dict['COLR'] = [r, g, b] + subchunklen -= (12+env_size) + elif subchunkname == "DIFF": #diffusion: mapped on reflection (diffuse shader) + ###if DEBUG: print "-------- DIFF" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['DIFF'] = s + subchunklen -= (4+env_size) + elif subchunkname == "SPEC": #specularity: mapped to specularity (spec shader) + ###if DEBUG: print "-------- SPEC" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['SPEC'] = s + subchunklen -= (4+env_size) + elif subchunkname == "REFL": #reflection: mapped on raymirror + ###if DEBUG: print "-------- REFL" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['REFL'] = s + subchunklen -= (4+env_size) + elif subchunkname == "TRNL": #translucency: mapped on same param + ###if DEBUG: print "-------- TRNL" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['TRNL'] = s + subchunklen -= (4+env_size) + elif subchunkname == "GLOS": #glossiness: mapped on specularity hardness (spec shader) + ###if DEBUG: print "-------- GLOS" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['GLOS'] = s + subchunklen -= (4+env_size) + elif subchunkname == "TRAN": #transparency: inverted and mapped on alpha channel + ###if DEBUG: print "-------- TRAN" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['TRAN'] = s + subchunklen -= (4+env_size) + elif subchunkname == "LUMI": #luminosity: mapped on emit channel + ###if DEBUG: print "-------- LUMI" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['LUMI'] = s + subchunklen -= (4+env_size) + elif subchunkname == "GVAL": #glow: mapped on add channel + ###if DEBUG: print "-------- GVAL" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['GVAL'] = s + subchunklen -= (4+env_size) + elif subchunkname == "SMAN": #smoothing angle + ###if DEBUG: print "-------- SMAN" + s, = struct.unpack(">f", data.read(4)) + my_dict['SMAN'] = s + subchunklen -= 4 + elif subchunkname == "SIDE": #double sided? + ###if DEBUG: print "-------- SIDE" #if 1 side do not define key + s, = struct.unpack(">H", data.read(2)) + if s == 3: + my_dict['SIDE'] = s + subchunklen -= 2 + elif subchunkname == "RIND": #Refraction: mapped on IOR + ###if DEBUG: print "-------- RIND" + s, = struct.unpack(">f", data.read(4)) + envelope, env_size = read_vx(data) + my_dict['RIND'] = s + subchunklen -= (4+env_size) + elif subchunkname == "BLOK": #blocks + ###if DEBUG: print "-------- BLOK" + rr, uvname = read_surfblok(data.read(subchunklen)) + #paranoia setting: preventing adding an empty dict + if rr: # != {} + try: + my_dict['BLOK'].append(rr) + except: + my_dict['BLOK'] = [rr] + + if uvname: # != "": + my_dict['UVNAME'] = uvname #theoretically there could be a number of them: only one used per surf + # all are dictionaries - so testing keys + if not('g_IMAG' in my_dict) and ('CHAN' in rr) and ('OPAC' in rr) and ('IMAG' in rr): + if (rr['CHAN'] == 'COLR') and (rr['OPAC'] == 0): + my_dict['g_IMAG'] = rr['IMAG'] #do not set anything, just save image object for later assignment + subchunklen = 0 #force ending + else: # Misc Chunks + pass + ###if DEBUG: print "-------- SURF:%s: skipping" % subchunkname + if subchunklen > 0: + discard = data.read(subchunklen) + #end loop on surf chunks + try:#if my_dict.has_key('BLOK'): + my_dict['BLOK'].reverse() #texture applied in reverse order with respect to reading from lwo + except: + pass + + #uncomment this if material pre-allocated by read_surf + my_dict['g_MAT'] = bpy.data.materials.new(my_dict['NAME']) + ###if DEBUG: print "-> Material pre-allocated." + return my_dict + +# ========================= +# === Recalculate Faces === +# ========================= + +def get_uvface(complete_list, facenum): + # extract from the complete list only vertexes of the desired polygon + ''' + my_facelist = [] + for elem in complete_list: + if elem[0] == facenum: + my_facelist.append(elem) + return my_facelist + ''' + return [elem for elem in complete_list if elem[0] == facenum] + +def get_newindex(polygon_list, vertnum): + # extract from the polygon list the new index associated to a vertex + if not polygon_list: # == [] + return -1 + for elem in polygon_list: + if elem[1] == vertnum: + return elem[2] + # ###if DEBUG: print "WARNING: expected vertex %s for polygon %s. Polygon_list dump follows" % (vertnum, polygon_list[0][0]) + # ###if DEBUG: print polygon_list + return -1 + +def get_surf(surf_list, cur_tag): + for elem in surf_list: # elem can be None + if elem and elem['NAME'] == cur_tag: + return elem + return {} + + + +# ==================================== +# === Modified Create Blender Mesh === +# ==================================== +def my_create_mesh(clip_list, surf, objspec_list, current_facelist, objname, not_used_faces): + #take the needed faces and update the not-used face list + complete_vertlist = objspec_list[2] + complete_facelist = objspec_list[3] + uvcoords_dict = objspec_list[7] + facesuv_dict = objspec_list[8] + vertex_map = {} #implementation as dict + cur_ptag_faces = [] + cur_ptag_faces_indexes = [] + maxface = len(complete_facelist) + for ff in current_facelist: + if ff >= maxface: + ###if DEBUG: print "Non existent face addressed: Giving up with this object" + return None, not_used_faces #return the created object + cur_face = complete_facelist[ff] + cur_ptag_faces_indexes.append(ff) + if not_used_faces: # != [] + not_used_faces[ff] = -1 + for vv in cur_face: vertex_map[vv] = 1 + #end loop on faces + store_edge = 0 + + scn= bpy.data.scenes.active + msh = bpy.data.meshes.new() + obj = scn.objects.new(msh) + + mat = None + try: + msh.materials = [surf['g_MAT']] + except: + pass + + msh.mode |= Blender.Mesh.Modes.AUTOSMOOTH #smooth it anyway + if 'SMAN' in surf: # has_key + #not allowed mixed mode mesh (all the mesh is smoothed and all with the same angle) + #only one smoothing angle will be active! => take the max one + msh.degr = min(80, int(surf['SMAN']/3.1415926535897932384626433832795*180.0)) #lwo in radians - blender in degrees + + try: + img= lookup_imag(clip_list, surf['g_IMAG'])['g_IMG'] + except: + img= None + + #uv_flag = ((surf.has_key('UVNAME')) and (uvcoords_dict.has_key(surf['UVNAME'])) and (img != None)) + uv_flag = (('UVNAME' in surf) and (surf['UVNAME'] in uvcoords_dict)) + + ###if DEBUG: print "\n#===================================================================#" + ###if DEBUG: print "Processing Object: %s" % objname + ###if DEBUG: print "#===================================================================#" + + if uv_flag: + msh.verts.extend([(0.0,0.0,0.0),]) + j = 1 + else: + j = 0 + + def tmp_get_vert(k, i): + vertex_map[k] = i+j # j is the dummy vert + # ###if DEBUG: print complete_vertlist[i] + return complete_vertlist[k] + + + + msh.verts.extend([tmp_get_vert(k, i) for i, k in enumerate(vertex_map.iterkeys())]) + msh.transform(TXMTX) # faster then applying while reading. + #end sweep over vertexes + + #append faces + FACE_TEX= Blender.Mesh.FaceModes.TEX + FACE_ALPHA= Blender.Mesh.FaceTranspModes.ALPHA + EDGE_DRAW_FLAG= Blender.Mesh.EdgeFlags.EDGEDRAW | Blender.Mesh.EdgeFlags.EDGERENDER + + + edges = [] + face_data = [] # [(indicies, material, uvs, image), ] + face_uvs = [] + edges_fgon = [] + + if uv_flag: + uvcoords_dict_context = uvcoords_dict[surf['UVNAME']] + try: current_uvdict = facesuv_dict[surf['UVNAME']] + except: current_uvdict = None + + default_uv = Blender.Mathutils.Vector(0,0) + def tmp_get_face_uvs(cur_face, i): + uvs = [] + if current_uvdict: + uvface = get_uvface(current_uvdict,i) + for vi in cur_face: + ni = get_newindex(uvface, vi) + if ni == -1: ni = vi + + try: + uvs.append(uvcoords_dict_context[ ni ]) + except: + ###if DEBUG: print '\tWarning, Corrupt UVs' + uvs.append(default_uv) + else: + for vi in cur_face: + try: + uvs.append(uvcoords_dict_context[ vi ]) + except: + ###if DEBUG: print '\tWarning, Corrupt UVs' + uvs.append(default_uv) + + return uvs + cur_face + for i in cur_ptag_faces_indexes: + cur_face = complete_facelist[i] + numfaceverts = len(cur_face) + + if numfaceverts == 2: edges.append((vertex_map[cur_face[0]], vertex_map[cur_face[1]])) + elif numfaceverts == 3 or numfaceverts == 4: + rev_face = [__i for __i in reversed(cur_face)] + face_data.append( [vertex_map[j] for j in rev_face] ) + if uv_flag: face_uvs.append(tmp_get_face_uvs(rev_face, i)) + elif numfaceverts > 4: + meta_faces= BPyMesh.ngon(complete_vertlist, cur_face, PREF_FIX_LOOPS= True) + edge_face_count = {} + for mf in meta_faces: + # These will always be tri's since they are scanfill faces + mf = cur_face[mf[2]], cur_face[mf[1]], cur_face[mf[0]] + face_data.append( [vertex_map[j] for j in mf] ) + + if uv_flag: face_uvs.append(tmp_get_face_uvs(mf, i)) + + #if USE_FGON: + if len(meta_faces) > 1: + mf = face_data[-1] # reuse mf + for j in xrange(3): + v1= mf[j] + v2= mf[j-1] + if v1!=v2: + if v1>v2: + v2,v1= v1,v2 + try: + edge_face_count[v1,v2]+= 1 + except: + edge_face_count[v1,v2]= 0 + + + + if edge_face_count: + edges_fgon.extend( [vert_key for vert_key, count in edge_face_count.iteritems() if count] ) + + if edges: + msh.edges.extend(edges) + + face_mapping_removed = msh.faces.extend(face_data, indexList=True) + if 'TRAN' in surf or (mat and mat.alpha<1.0): # incase mat is null + transp_flag = True + else: + transp_flag = False + + if uv_flag: + msh.faceUV = True + msh_faces= msh.faces + for i, uvs in enumerate(face_uvs): + i_mapped = face_mapping_removed[i] + if i_mapped != None: + f = msh_faces[i_mapped] + f.uv = uvs + if img: + f.image = img + + if transp_flag: f.transp |= FACE_ALPHA + + if edges_fgon: + msh_edges = msh.edges + FGON= Blender.Mesh.EdgeFlags.FGON + edges_fgon = msh.findEdges( edges_fgon ) + if type(edges_fgon) != list: edges_fgon = [edges_fgon] + for ed in edges_fgon: + if ed!=None: + msh_edges[ed].flag |= FGON + + if not(uv_flag): #clear eventual UV data + msh.faceUV = False + + if uv_flag: + msh.verts.delete([0,]) + + return obj, not_used_faces #return the created object + + +# ============================================ +# === Set Subsurf attributes on given mesh === +# ============================================ +def set_subsurf(obj): + mods = obj.modifiers # get the object's modifiers + mod = mods.append(Blender.Modifier.Type.SUBSURF) # add a new subsurf modifier + mod[Blender.Modifier.Settings.LEVELS] = 2 # set subsurf subdivision levels to 2 + mod[Blender.Modifier.Settings.RENDLEVELS] = 2 # set subsurf rendertime subdivision levels to 2 + obj.makeDisplayList() + + +# ================================= +# === object size and dimension === +# ================================= +def obj_size_pos(obj): + bbox = obj.getBoundBox() + bbox_min = map(lambda *row: min(row), *bbox) #transpose & get min + bbox_max = map(lambda *row: max(row), *bbox) #transpose & get max + obj_size = (bbox_max[0]-bbox_min[0], bbox_max[1]-bbox_min[1], bbox_max[2]-bbox_min[2]) + obj_pos = ( (bbox_max[0]+bbox_min[0]) / 2, (bbox_max[1]+bbox_min[1]) / 2, (bbox_max[2]+bbox_min[2]) / 2) + return (obj_size, obj_pos) + + +# ========================= +# === Create the object === +# ========================= +def create_objects(clip_list, objspec_list, surf_list): + nf = len(objspec_list[3]) + not_used_faces = range(nf) + ptag_dict = objspec_list[5] + obj_dict = {} #links tag names to object, used for material assignments + obj_dim_dict = {} + obj_list = [] #have it handy for parent association + middlechar = "+" + endchar = "" + if (objspec_list[6] == 1): + middlechar = endchar = "#" + for cur_tag, ptag_dict_val in ptag_dict.iteritems(): + if ptag_dict_val != []: + cur_surf = get_surf(surf_list, cur_tag) + cur_obj, not_used_faces= my_create_mesh(clip_list, cur_surf, objspec_list, ptag_dict_val, objspec_list[0][:9]+middlechar+cur_tag[:9], not_used_faces) + # Works now with new modifiers + if objspec_list[6] == 1: + set_subsurf(cur_obj) + if cur_obj: # != None + obj_dict[cur_tag] = cur_obj + obj_dim_dict[cur_tag] = obj_size_pos(cur_obj) + obj_list.append(cur_obj) + #end loop on current group + #and what if some faces not used in any named PTAG? get rid of unused faces + orphans = [] + for tt in not_used_faces: + if tt > -1: orphans.append(tt) + #end sweep on unused face list + not_used_faces = None + if orphans: # != [] + cur_surf = get_surf(surf_list, "_Orphans") + cur_obj, not_used_faces = my_create_mesh(clip_list, cur_surf, objspec_list, orphans, objspec_list[0][:9]+middlechar+"Orphans", []) + if cur_obj: # != None + if objspec_list[6] == 1: + set_subsurf(cur_obj) + obj_dict["_Orphans"] = cur_obj + obj_dim_dict["_Orphans"] = obj_size_pos(cur_obj) + obj_list.append(cur_obj) + objspec_list[1]= obj_dict + objspec_list[4]= obj_dim_dict + + return + + + +# =========================================== +# === Lookup for image index in clip_list === +# =========================================== +def lookup_imag(clip_list, ima_id): + for ii in clip_list: + if ii and ii['ID'] == ima_id: + if 'XREF' in ii: # has_key + #cross reference - recursively look for images + return lookup_imag(clip_list, ii['XREF']) + else: + return ii + return None + + +# =================================================== +# === Create and assign image mapping to material === +# =================================================== +def create_blok(surf, mat, clip_list, obj_size, obj_pos): + + def output_size_ofs(size, pos, blok): + #just automate repetitive task + # 0 == X, 1 == Y, 2 == Z + size_default = [1.0] * 3 + size2 = [1.0] * 3 + ofs_default = [0.0] * 3 + offset = [1.0] * 3 + axis_default = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z] + axis = [1.0] * 3 + c_map_txt = [" X--", " -Y-", " --Z"] + c_map = [0,1,2] # standard, good for Z axis projection + if blok['MAJAXIS'] == 0: + c_map = [1,2,0] # X axis projection + if blok['MAJAXIS'] == 2: + c_map = [0,2,1] # Y axis projection + + ###if DEBUG: print "!!!axis mapping:" + #this is the smart way + ###if DEBUG: for mp in c_map: print c_map_txt[mp] + + if blok['SIZE'][0] != 0.0: #paranoia controls + size_default[0] = (size[0]/blok['SIZE'][0]) + ofs_default[0] = ((blok['CNTR'][0]-pos[0])/blok['SIZE'][0]) + if blok['SIZE'][1] != 0.0: + size_default[2] = (size[2]/blok['SIZE'][1]) + ofs_default[2] = ((blok['CNTR'][1]-pos[2])/blok['SIZE'][1]) + if blok['SIZE'][2] != 0.0: + size_default[1] = (size[1]/blok['SIZE'][2]) + ofs_default[1] = ((blok['CNTR'][2]-pos[1])/blok['SIZE'][2]) + + for mp in xrange(3): + axis[mp] = axis_default[c_map[mp]] + size2[mp] = size_default[c_map[mp]] + offset[mp] = ofs_default[c_map[mp]] + if offset[mp]>10.0: offset[mp]-10.0 + if offset[mp]<-10.0: offset[mp]+10.0 +# size = [size_default[mp] for mp in c_map] + + ###if DEBUG: print "!!!texture size and offsets:" + ###if DEBUG: print " sizeX = %.5f; sizeY = %.5f; sizeZ = %.5f" % (size[0],size[1],size[2]) + ###if DEBUG: print " ofsX = %.5f; ofsY = %.5f; ofsZ = %.5f" % (offset[0],offset[1],offset[2]) + return axis, size2, offset + + ti = 0 + alphaflag = 0 #switched to 1 if some tex in this block is using alpha + lastimag = 0 #experimental .... + for blok in surf['BLOK']: + ###if DEBUG: print "#...................................................................#" + ###if DEBUG: print "# Processing texture block no.%s for surf %s" % (ti,surf['NAME']) + ###if DEBUG: print "#...................................................................#" + # tobj.pdict (blok) + if ti > 9: break #only 8 channels 0..7 allowed for texture mapping + #if not blok['ENAB']: + # ###if DEBUG: print "***Image is not ENABled! Quitting this block" + # break + if not('IMAG' in blok): # has_key + ###if DEBUG: print "***No IMAGE for this block? Quitting" + break #extract out the image index within the clip_list + if blok['IMAG'] == 0: blok['IMAG'] = lastimag #experimental .... + ###if DEBUG: print "looking for image number %d" % blok['IMAG'] + ima = lookup_imag(clip_list, blok['IMAG']) + if ima == None: + ###if DEBUG: print "***Block index image not within CLIP list? Quitting Block" + break #safety check (paranoia setting) + img = ima['g_IMG'] + lastimag = blok['IMAG'] #experimental .... + if img == None: + ###if DEBUG: print "***Failed to pre-allocate image %s found: giving up" % ima['BASENAME'] + break + tname = str(ima['ID']) + if blok['ENAB']: + tname += "+" + else: + tname += "x" #let's signal when should not be enabled + if 'CHAN' in blok: # has_key + tname += blok['CHAN'] + newtex = bpy.data.textures.new(tname) + newtex.setType('Image') # make it anu image texture + newtex.image = img + #how does it extends beyond borders + if 'WRAP' in blok: # has_key + if (blok['WRAP'] == 3) or (blok['WRAP'] == 2): + newtex.setExtend('Extend') + elif (blok['WRAP'] == 1): + newtex.setExtend('Repeat') + elif (blok['WRAP'] == 0): + newtex.setExtend('Clip') + ###if DEBUG: print "generated texture %s" % tname + + #MapTo is determined by CHAN parameter + #assign some defaults + colfac = 1.0 + dvar = 1.0 + norfac = 0.5 + nega = False + mapflag = Blender.Texture.MapTo.COL #default to color + maptype = Blender.Texture.Mappings.FLAT + if 'CHAN' in blok: # has_key + if blok['CHAN'] == 'COLR' and 'OPACVAL' in blok: # has_key + colfac = blok['OPACVAL'] + # Blender needs this to be clamped + colfac = max(0.0, min(1.0, colfac)) + ###if DEBUG: print "!!!Set Texture -> MapTo -> Col = %.3f" % colfac + if blok['CHAN'] == 'BUMP': + mapflag = Blender.Texture.MapTo.NOR + if 'OPACVAL' in blok: norfac = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> Nor = %.3f" % norfac + if blok['CHAN'] == 'LUMI': + mapflag = Blender.Texture.MapTo.EMIT + if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar + if blok['CHAN'] == 'DIFF': + mapflag = Blender.Texture.MapTo.REF + if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar + if blok['CHAN'] == 'SPEC': + mapflag = Blender.Texture.MapTo.SPEC + if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar + if blok['CHAN'] == 'TRAN': + mapflag = Blender.Texture.MapTo.ALPHA + if 'OPACVAL' in blok: dvar = blok['OPACVAL'] # has_key + ###if DEBUG: print "!!!Set Texture -> MapTo -> DVar = %.3f" % dvar + alphaflag = 1 + nega = True + if 'NEGA' in blok: # has_key + ###if DEBUG: print "!!!Watch-out: effect of this texture channel must be INVERTED!" + nega = not nega + + blendmode_list = ['Mix', + 'Subtractive', + 'Difference', + 'Multiply', + 'Divide', + 'Mix with calculated alpha layer and stencil flag', + 'Texture Displacement', + 'Additive'] + set_blendmode = 7 #default additive + if 'OPAC' in blok: # has_key + set_blendmode = blok['OPAC'] + if set_blendmode == 5: #transparency + newtex.imageFlags |= Blender.Texture.ImageFlags.CALCALPHA + if nega: newtex.flags |= Blender.Texture.Flags.NEGALPHA + ###if DEBUG: print "!!!Set Texture -> MapTo -> Blending Mode = %s" % blendmode_list[set_blendmode] + + #the TexCo flag is determined by PROJ parameter + axis = [Blender.Texture.Proj.X, Blender.Texture.Proj.Y, Blender.Texture.Proj.Z] + size = [1.0] * 3 + ofs = [0.0] * 3 + if 'PROJ' in blok: # has_key + if blok['PROJ'] == 0: #0 - Planar + ###if DEBUG: print "!!!Flat projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.FLAT + elif blok['PROJ'] == 1: #1 - Cylindrical + ###if DEBUG: print "!!!Cylindrical projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.TUBE + elif blok['PROJ'] == 2: #2 - Spherical + ###if DEBUG: print "!!!Spherical projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.SPHERE + elif blok['PROJ'] == 3: #3 - Cubic + ###if DEBUG: print "!!!Cubic projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.CUBE + elif blok['PROJ'] == 4: #4 - Front Projection + ###if DEBUG: print "!!!Front projection" + coordflag = Blender.Texture.TexCo.ORCO + maptype = Blender.Texture.Mappings.FLAT # ??? could it be a FLAT with some other TexCo type? + elif blok['PROJ'] == 5: #5 - UV + ###if DEBUG: print "UVMapped" + coordflag = Blender.Texture.TexCo.UV + maptype = Blender.Texture.Mappings.FLAT #in case of UV default to FLAT mapping => effectively not used + if blok['PROJ'] != 5: #This holds for any projection map except UV + axis, size, ofs = output_size_ofs(obj_size, obj_pos, blok) + + # Clamp ofs and size else blender will raise an error + for ii in xrange(3): + ofs[ii]= min(10.0, max(-10, ofs[ii])) + size[ii]= min(100, max(-100, size[ii])) + + mat.setTexture(ti, newtex, coordflag, mapflag) + current_mtex = mat.getTextures()[ti] + current_mtex.mapping = maptype + current_mtex.colfac = colfac + current_mtex.dvar = dvar + current_mtex.norfac = norfac + current_mtex.neg = nega + current_mtex.xproj = axis[0] + current_mtex.yproj = axis[1] + current_mtex.zproj = axis[2] + current_mtex.size = tuple(size) + current_mtex.ofs = tuple(ofs) + if (set_blendmode == 5): #transparency + current_mtex.stencil = not (nega) + + ti += 1 + #end loop over bloks + return alphaflag + + +# ======================================== +# === Create and assign a new material === +# ======================================== +#def update_material(surf_list, ptag_dict, obj, clip_list, uv_dict, dir_part): +def update_material(clip_list, objspec, surf_list): + if (surf_list == []) or (objspec[5] == {}) or (objspec[1] == {}): + ###if DEBUG: print "something getting wrong in update_material: dump follows ..." + ###if DEBUG: print surf_list + ###if DEBUG: print objspec[5] + ###if DEBUG: print objspec[1] + return + obj_dict = objspec[1] + all_faces = objspec[3] + obj_dim_dict = objspec[4] + ptag_dict = objspec[5] + uvcoords_dict = objspec[7] + facesuv_dict = objspec[8] + for surf in surf_list: + if surf and surf['NAME'] in ptag_dict: # in ptag_dict.keys() + ###if DEBUG: print "#-------------------------------------------------------------------#" + ###if DEBUG: print "Processing surface (material): %s" % surf['NAME'] + ###if DEBUG: print "#-------------------------------------------------------------------#" + #material set up + facelist = ptag_dict[surf['NAME']] + #bounding box and position + cur_obj = obj_dict[surf['NAME']] + obj_size = obj_dim_dict[surf['NAME']][0] + obj_pos = obj_dim_dict[surf['NAME']][1] + ###if DEBUG: print surf + #uncomment this if material pre-allocated by read_surf + mat = surf['g_MAT'] + if mat == None: + ###if DEBUG: print "Sorry, no pre-allocated material to update. Giving up for %s." % surf['NAME'] + break + #mat = Blender.Material.New(surf['NAME']) + #surf['g_MAT'] = mat + if 'COLR' in surf: # has_key + mat.rgbCol = surf['COLR'] + if 'LUMI' in surf: + mat.setEmit(surf['LUMI']) + if 'GVAL' in surf: # has_key + mat.setAdd(surf['GVAL']) + if 'SPEC' in surf: # has_key + mat.setSpec(surf['SPEC']) #it should be * 2 but seems to be a bit higher lwo [0.0, 1.0] - blender [0.0, 2.0] + if 'DIFF' in surf: # has_key + mat.setRef(surf['DIFF']) #lwo [0.0, 1.0] - blender [0.0, 1.0] + if 'GLOS' in surf: # has_key #lwo [0.0, 1.0] - blender [0, 255] + glo = int(371.67 * surf['GLOS'] - 42.334) #linear mapping - seems to work better than exp mapping + if glo <32: glo = 32 #clamped to 32-255 + if glo >255: glo = 255 + mat.setHardness(glo) + if 'TRNL' in surf: # has_key + mat.setTranslucency(surf['TRNL']) #NOT SURE ABOUT THIS lwo [0.0, 1.0] - blender [0.0, 1.0] + + mm = mat.mode + mm |= Blender.Material.Modes.TRANSPSHADOW + if 'REFL' in surf: # has_key + mat.setRayMirr(surf['REFL']) #lwo [0.0, 1.0] - blender [0.0, 1.0] + mm |= Blender.Material.Modes.RAYMIRROR + if 'TRAN' in surf: # has_key + mat.setAlpha(1.0-surf['TRAN']) #lwo [0.0, 1.0] - blender [1.0, 0.0] + mm |= Blender.Material.Modes.RAYTRANSP + if 'RIND' in surf: # has_key + s = surf['RIND'] + if s < 1.0: s = 1.0 + if s > 3.0: s = 3.0 + mat.setIOR(s) #clipped to blender [1.0, 3.0] + mm |= Blender.Material.Modes.RAYTRANSP + if 'BLOK' in surf and surf['BLOK'] != []: + #update the material according to texture. + alphaflag = create_blok(surf, mat, clip_list, obj_size, obj_pos) + if alphaflag: + mm |= Blender.Material.Modes.RAYTRANSP + mat.mode = mm + #finished setting up the material + #end if exist SURF + #end loop on materials (SURFs) + return + + +# ====================== +# === Read Faces 6.0 === +# ====================== +def read_faces_6(lwochunk): + data = cStringIO.StringIO(lwochunk.read()) + faces = [] + polygon_type = data.read(4) + subsurf = 0 + if polygon_type != "FACE" and polygon_type != "PTCH": + ###if DEBUG: print "No FACE/PATCH Were Found. Polygon Type: %s" % polygon_type + return "", 2 + if polygon_type == 'PTCH': subsurf = 1 + i = 0 + while(i < lwochunk.chunksize-4): + #if not i%1000 and my_meshtools.show_progress: + # Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces") + facev = [] + numfaceverts, = struct.unpack(">H", data.read(2)) + i += 2 + + for j in xrange(numfaceverts): + index, index_size = read_vx(data) + i += index_size + facev.append(index) + faces.append(facev) + ###if DEBUG: print "read %s faces; type of block %d (0=FACE; 1=PATCH)" % (len(faces), subsurf) + return faces, subsurf + +def main(): + if not struct: + Blender.Draw.PupMenu('This importer requires a full python install') + return + + Blender.Window.FileSelector(read, "Import LWO", '*.lwo') + + +if __name__=='__main__': + main() + +# Cams debugging lwo loader +""" +TIME= Blender.sys.time() +import os +print 'Searching for files' +os.system('find /fe/lwo/Objects/ -follow -iname "*.lwo" > /tmp/templwo_list') +# os.system('find /storage/ -iname "*.lwo" > /tmp/templwo_list') +print '...Done' +file= open('/tmp/templwo_list', 'r') +lines= file.readlines() + +# sort by filesize for faster testing +lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines] +lines_size.sort() +lines = [f[1] for f in lines_size] + +file.close() + +def between(v,a,b): + if v <= max(a,b) and v >= min(a,b): + return True + + return False +size= 0.0 +for i, _lwo in enumerate(lines): + #if i==425: # SCANFILL + #if 1: + #if i==520: # SCANFILL CRASH + #if i==47: # SCANFILL CRASH + #if between(i, 525, 550): + #if i > 1635: + #if i != 1519: # 730 + if i>141: + #if 1: + # _lwo= _lwo[:-1] + print 'Importing', _lwo, '\nNUMBER', i, 'of', len(lines) + _lwo_file= _lwo.split('/')[-1].split('\\')[-1] + newScn= bpy.data.scenes.new(_lwo_file) + bpy.data.scenes.active = newScn + size += ((os.path.getsize(_lwo)/1024.0))/ 1024.0 + read(_lwo) + # Remove objects to save memory? + ''' + for ob in newScn.objects: + if ob.type=='Mesh': + me= ob.getData(mesh=1) + me.verts= None + newScn.unlink(ob) + ''' + print 'mb size so far', size + +print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) +""" \ No newline at end of file diff --git a/release/scripts/md2_export.py b/release/scripts/md2_export.py new file mode 100644 index 00000000000..71e056a5f53 --- /dev/null +++ b/release/scripts/md2_export.py @@ -0,0 +1,1247 @@ +#!BPY + +""" +Name: 'MD2 (.md2)' +Blender: 243 +Group: 'Export' +Tooltip: 'Export to Quake file format (.md2).' +""" + +__author__ = 'Bob Holcomb' +__version__ = '0.18.1' +__url__ = ["Bob's site, http://bane.servebeer.com", + "Support forum, http://bane.servebeer.com", "blender", "elysiun"] +__email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"] +__bpydoc__ = """\ +This script Exports a Quake 2 file (MD2). + + Additional help from: Shadwolf, Skandal, Rojo, Cambo
+ Thanks Guys! +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C): Bob Holcomb +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +import Blender +from Blender import * +from Blender.Draw import * +from Blender.BGL import * +from Blender.Window import * + +import struct, string +from types import * + + + +###################################################### +# GUI Loader +###################################################### + +# Export globals +g_filename=Create("tris.md2") +g_frame_filename=Create("default") + +g_filename_search=Create("") +g_frame_search=Create("default") + +g_texture_path=Create("") + +user_frame_list=[] + +#Globals +g_scale=Create(1.0) + +# Events +EVENT_NOEVENT=1 +EVENT_SAVE_MD2=2 +EVENT_CHOOSE_FILENAME=3 +EVENT_CHOOSE_FRAME=4 +EVENT_EXIT=100 + +###################################################### +# Callbacks for Window functions +###################################################### +def filename_callback(input_filename): + global g_filename + g_filename.val=input_filename + +def frame_callback(input_frame): + global g_frame_filename + g_frame_filename.val=input_frame + +def draw_gui(): + global g_scale + global g_filename + global g_frame_filename + global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_FRAME,EVENT_EXIT + global g_texture_path + + ########## Titles + glClear(GL_COLOR_BUFFER_BIT) + glRasterPos2d(10, 120) + Text("MD2 Export") + + ######### Parameters GUI Buttons + ######### MD2 Filename text entry + g_filename = String("MD2 file to save: ", EVENT_NOEVENT, 10, 75, 210, 18, + g_filename.val, 255, "MD2 file to save") + ########## MD2 File Search Button + Button("Search",EVENT_CHOOSE_FILENAME,220,75,80,18) + + ########## MD2 Frame List Text entry + g_frame_filename = String("Frame List file to load: ", EVENT_NOEVENT, 10, 55, 210, 18, + g_frame_filename.val, 255, "Frame List to load-overrides MD2 defaults") + ########## Frame List Search Button + Button("Search",EVENT_CHOOSE_FRAME,220,55,80,18) + + ########## Texture path to append + g_texture_path=String("Texture Path: ", EVENT_NOEVENT, 10,35,210,18, + g_texture_path.val,255, "Texture path to prepend") + + + ########## Scale slider-default is 1/8 which is a good scale for md2->blender + g_scale= Slider("Scale Factor: ", EVENT_NOEVENT, 10, 95, 210, 18, + 1.0, 0.001, 10.0, 1, "Scale factor for object Model"); + + ######### Draw and Exit Buttons + Button("Export",EVENT_SAVE_MD2 , 10, 10, 80, 18) + Button("Exit",EVENT_EXIT , 170, 10, 80, 18) + +def event(evt, val): + if (evt == QKEY and not val): + Exit() + +def bevent(evt): + global g_filename + global g_frame_filename + global EVENT_NOEVENT,EVENT_SAVE_MD2,EVENT_EXIT + + ######### Manages GUI events + if (evt==EVENT_EXIT): + Blender.Draw.Exit() + elif (evt==EVENT_CHOOSE_FILENAME): + FileSelector(filename_callback, "MD2 File Selection") + elif (evt==EVENT_CHOOSE_FRAME): + FileSelector(frame_callback, "Frame Selection") + elif (evt==EVENT_SAVE_MD2): + if (g_filename.val == "model"): + save_md2("blender.md2") + Blender.Draw.Exit() + return + else: + save_md2(g_filename.val) + Blender.Draw.Exit() + return + +Register(draw_gui, event, bevent) + +###################################################### +# MD2 Model Constants +###################################################### +MD2_MAX_TRIANGLES=4096 +MD2_MAX_VERTICES=2048 +MD2_MAX_TEXCOORDS=2048 +MD2_MAX_FRAMES=512 +MD2_MAX_SKINS=32 +MD2_MAX_FRAMESIZE=(MD2_MAX_VERTICES * 4 + 128) + +MD2_FRAME_NAME_LIST=(("stand",1,40), + ("run",41,46), + ("attack",47,54), + ("pain1",55,58), + ("pain2",59,62), + ("pain3",63,66), + ("jump",67,72), + ("flip",73,84), + ("salute", 85,95), + ("taunt",96,112), + ("wave",113,123), + ("point",124,135), + ("crstnd",136,154), + ("crwalk",155,160), + ("crattack",161,169), + ("crpain",170,173), + ("crdeath",174,178), + ("death1",179,184), + ("death2",185,190), + ("death3",191,198)) + #198 frames + +MD2_NORMALS=((-0.525731, 0.000000, 0.850651), + (-0.442863, 0.238856, 0.864188), + (-0.295242, 0.000000, 0.955423), + (-0.309017, 0.500000, 0.809017), + (-0.162460, 0.262866, 0.951056), + (0.000000, 0.000000, 1.000000), + (0.000000, 0.850651, 0.525731), + (-0.147621, 0.716567, 0.681718), + (0.147621, 0.716567, 0.681718), + (0.000000, 0.525731, 0.850651), + (0.309017, 0.500000, 0.809017), + (0.525731, 0.000000, 0.850651), + (0.295242, 0.000000, 0.955423), + (0.442863, 0.238856, 0.864188), + (0.162460, 0.262866, 0.951056), + (-0.681718, 0.147621, 0.716567), + (-0.809017, 0.309017, 0.500000), + (-0.587785, 0.425325, 0.688191), + (-0.850651, 0.525731, 0.000000), + (-0.864188, 0.442863, 0.238856), + (-0.716567, 0.681718, 0.147621), + (-0.688191, 0.587785, 0.425325), + (-0.500000, 0.809017, 0.309017), + (-0.238856, 0.864188, 0.442863), + (-0.425325, 0.688191, 0.587785), + (-0.716567, 0.681718, -0.147621), + (-0.500000, 0.809017, -0.309017), + (-0.525731, 0.850651, 0.000000), + (0.000000, 0.850651, -0.525731), + (-0.238856, 0.864188, -0.442863), + (0.000000, 0.955423, -0.295242), + (-0.262866, 0.951056, -0.162460), + (0.000000, 1.000000, 0.000000), + (0.000000, 0.955423, 0.295242), + (-0.262866, 0.951056, 0.162460), + (0.238856, 0.864188, 0.442863), + (0.262866, 0.951056, 0.162460), + (0.500000, 0.809017, 0.309017), + (0.238856, 0.864188, -0.442863), + (0.262866, 0.951056, -0.162460), + (0.500000, 0.809017, -0.309017), + (0.850651, 0.525731, 0.000000), + (0.716567, 0.681718, 0.147621), + (0.716567, 0.681718, -0.147621), + (0.525731, 0.850651, 0.000000), + (0.425325, 0.688191, 0.587785), + (0.864188, 0.442863, 0.238856), + (0.688191, 0.587785, 0.425325), + (0.809017, 0.309017, 0.500000), + (0.681718, 0.147621, 0.716567), + (0.587785, 0.425325, 0.688191), + (0.955423, 0.295242, 0.000000), + (1.000000, 0.000000, 0.000000), + (0.951056, 0.162460, 0.262866), + (0.850651, -0.525731, 0.000000), + (0.955423, -0.295242, 0.000000), + (0.864188, -0.442863, 0.238856), + (0.951056, -0.162460, 0.262866), + (0.809017, -0.309017, 0.500000), + (0.681718, -0.147621, 0.716567), + (0.850651, 0.000000, 0.525731), + (0.864188, 0.442863, -0.238856), + (0.809017, 0.309017, -0.500000), + (0.951056, 0.162460, -0.262866), + (0.525731, 0.000000, -0.850651), + (0.681718, 0.147621, -0.716567), + (0.681718, -0.147621, -0.716567), + (0.850651, 0.000000, -0.525731), + (0.809017, -0.309017, -0.500000), + (0.864188, -0.442863, -0.238856), + (0.951056, -0.162460, -0.262866), + (0.147621, 0.716567, -0.681718), + (0.309017, 0.500000, -0.809017), + (0.425325, 0.688191, -0.587785), + (0.442863, 0.238856, -0.864188), + (0.587785, 0.425325, -0.688191), + (0.688191, 0.587785, -0.425325), + (-0.147621, 0.716567, -0.681718), + (-0.309017, 0.500000, -0.809017), + (0.000000, 0.525731, -0.850651), + (-0.525731, 0.000000, -0.850651), + (-0.442863, 0.238856, -0.864188), + (-0.295242, 0.000000, -0.955423), + (-0.162460, 0.262866, -0.951056), + (0.000000, 0.000000, -1.000000), + (0.295242, 0.000000, -0.955423), + (0.162460, 0.262866, -0.951056), + (-0.442863, -0.238856, -0.864188), + (-0.309017, -0.500000, -0.809017), + (-0.162460, -0.262866, -0.951056), + (0.000000, -0.850651, -0.525731), + (-0.147621, -0.716567, -0.681718), + (0.147621, -0.716567, -0.681718), + (0.000000, -0.525731, -0.850651), + (0.309017, -0.500000, -0.809017), + (0.442863, -0.238856, -0.864188), + (0.162460, -0.262866, -0.951056), + (0.238856, -0.864188, -0.442863), + (0.500000, -0.809017, -0.309017), + (0.425325, -0.688191, -0.587785), + (0.716567, -0.681718, -0.147621), + (0.688191, -0.587785, -0.425325), + (0.587785, -0.425325, -0.688191), + (0.000000, -0.955423, -0.295242), + (0.000000, -1.000000, 0.000000), + (0.262866, -0.951056, -0.162460), + (0.000000, -0.850651, 0.525731), + (0.000000, -0.955423, 0.295242), + (0.238856, -0.864188, 0.442863), + (0.262866, -0.951056, 0.162460), + (0.500000, -0.809017, 0.309017), + (0.716567, -0.681718, 0.147621), + (0.525731, -0.850651, 0.000000), + (-0.238856, -0.864188, -0.442863), + (-0.500000, -0.809017, -0.309017), + (-0.262866, -0.951056, -0.162460), + (-0.850651, -0.525731, 0.000000), + (-0.716567, -0.681718, -0.147621), + (-0.716567, -0.681718, 0.147621), + (-0.525731, -0.850651, 0.000000), + (-0.500000, -0.809017, 0.309017), + (-0.238856, -0.864188, 0.442863), + (-0.262866, -0.951056, 0.162460), + (-0.864188, -0.442863, 0.238856), + (-0.809017, -0.309017, 0.500000), + (-0.688191, -0.587785, 0.425325), + (-0.681718, -0.147621, 0.716567), + (-0.442863, -0.238856, 0.864188), + (-0.587785, -0.425325, 0.688191), + (-0.309017, -0.500000, 0.809017), + (-0.147621, -0.716567, 0.681718), + (-0.425325, -0.688191, 0.587785), + (-0.162460, -0.262866, 0.951056), + (0.442863, -0.238856, 0.864188), + (0.162460, -0.262866, 0.951056), + (0.309017, -0.500000, 0.809017), + (0.147621, -0.716567, 0.681718), + (0.000000, -0.525731, 0.850651), + (0.425325, -0.688191, 0.587785), + (0.587785, -0.425325, 0.688191), + (0.688191, -0.587785, 0.425325), + (-0.955423, 0.295242, 0.000000), + (-0.951056, 0.162460, 0.262866), + (-1.000000, 0.000000, 0.000000), + (-0.850651, 0.000000, 0.525731), + (-0.955423, -0.295242, 0.000000), + (-0.951056, -0.162460, 0.262866), + (-0.864188, 0.442863, -0.238856), + (-0.951056, 0.162460, -0.262866), + (-0.809017, 0.309017, -0.500000), + (-0.864188, -0.442863, -0.238856), + (-0.951056, -0.162460, -0.262866), + (-0.809017, -0.309017, -0.500000), + (-0.681718, 0.147621, -0.716567), + (-0.681718, -0.147621, -0.716567), + (-0.850651, 0.000000, -0.525731), + (-0.688191, 0.587785, -0.425325), + (-0.587785, 0.425325, -0.688191), + (-0.425325, 0.688191, -0.587785), + (-0.425325, -0.688191, -0.587785), + (-0.587785, -0.425325, -0.688191), + (-0.688191, -0.587785, -0.425325)) + + +###################################################### +# MD2 data structures +###################################################### +class md2_point: + vertices=[] + lightnormalindex=0 + binary_format="<3BB" + def __init__(self): + self.vertices=[0]*3 + self.lightnormalindex=0 + def save(self, file): + temp_data=[0]*4 + temp_data[0]=self.vertices[0] + temp_data[1]=self.vertices[1] + temp_data[2]=self.vertices[2] + temp_data[3]=self.lightnormalindex + data=struct.pack(self.binary_format, temp_data[0], temp_data[1], temp_data[2], temp_data[3]) + file.write(data) + def dump(self): + print "MD2 Point Structure" + print "vertex X: ", self.vertices[0] + print "vertex Y: ", self.vertices[1] + print "vertex Z: ", self.vertices[2] + print "lightnormalindex: ",self.lightnormalindex + print "" + +class md2_face: + vertex_index=[] + texture_index=[] + binary_format="<3h3h" + def __init__(self): + self.vertex_index = [ 0, 0, 0 ] + self.texture_index = [ 0, 0, 0] + def save(self, file): + temp_data=[0]*6 + #swap vertices around so they draw right + temp_data[0]=self.vertex_index[0] + temp_data[1]=self.vertex_index[2] + temp_data[2]=self.vertex_index[1] + #swap texture vertices around so they draw right + temp_data[3]=self.texture_index[0] + temp_data[4]=self.texture_index[2] + temp_data[5]=self.texture_index[1] + data=struct.pack(self.binary_format,temp_data[0],temp_data[1],temp_data[2],temp_data[3],temp_data[4],temp_data[5]) + file.write(data) + def dump (self): + print "MD2 Face Structure" + print "vertex 1 index: ", self.vertex_index[0] + print "vertex 2 index: ", self.vertex_index[1] + print "vertex 3 index: ", self.vertex_index[2] + print "texture 1 index: ", self.texture_index[0] + print "texture 2 index: ", self.texture_index[1] + print "texture 3 index: ", self.texture_index[2] + print "" + +class md2_tex_coord: + u=0 + v=0 + binary_format="<2h" + def __init__(self): + self.u=0 + self.v=0 + def save(self, file): + temp_data=[0]*2 + temp_data[0]=self.u + temp_data[1]=self.v + data=struct.pack(self.binary_format, temp_data[0], temp_data[1]) + file.write(data) + def dump (self): + print "MD2 Texture Coordinate Structure" + print "texture coordinate u: ",self.u + print "texture coordinate v: ",self.v + print "" + +class md2_GL_command: + s=0.0 + t=0.0 + vert_index=0 + binary_format="<2fi" + + def __init__(self): + self.s=0.0 + self.t=0.0 + vert_index=0 + def save(self,file): + temp_data=[0]*3 + temp_data[0]=float(self.s) + temp_data[1]=float(self.t) + temp_data[2]=self.vert_index + data=struct.pack(self.binary_format, temp_data[0],temp_data[1],temp_data[2]) + file.write(data) + def dump (self): + print "MD2 OpenGL Command" + print "s: ", self.s + print "t: ", self.t + print "Vertex Index: ", self.vert_index + print "" + +class md2_GL_cmd_list: + num=0 + cmd_list=[] + binary_format="MD2_MAX_TRIANGLES: + print "Number of triangles exceeds MD2 standard: ", face_count,">",MD2_MAX_TRIANGLES + result=Blender.Draw.PupMenu("Number of triangles exceeds MD2 standard: Continue?%t|YES|NO") + if(result==2): + return False + if vert_count>MD2_MAX_VERTICES: + print "Number of verticies exceeds MD2 standard",vert_count,">",MD2_MAX_VERTICES + result=Blender.Draw.PupMenu("Number of verticies exceeds MD2 standard: Continue?%t|YES|NO") + if(result==2): + return False + if frame_count>MD2_MAX_FRAMES: + print "Number of frames exceeds MD2 standard of",frame_count,">",MD2_MAX_FRAMES + result=Blender.Draw.PupMenu("Number of frames exceeds MD2 standard: Continue?%t|YES|NO") + if(result==2): + return False + #model is OK + return True + +###################################################### +# Fill MD2 data structure +###################################################### +def fill_md2(md2, object): + #global defines + global user_frame_list + global g_texture_path + + Blender.Window.DrawProgressBar(0.25,"Filling MD2 Data") + + #get a Mesh, not NMesh + mesh=object.getData(False, True) + + #load up some intermediate data structures + tex_list={} + tex_count=0 + #create the vertex list from the first frame + Blender.Set("curframe", 1) + + #header information + md2.ident=844121161 + md2.version=8 + md2.num_vertices=len(mesh.verts) + md2.num_faces=len(mesh.faces) + + #get the skin information + #use the first faces' image for the texture information + mesh_image=mesh.faces[0].image + size=mesh_image.getSize() + md2.skin_width=size[0] + md2.skin_height=size[1] + md2.num_skins=1 + #add a skin node to the md2 data structure + md2.skins.append(md2_skin()) + md2.skins[0].name=g_texture_path.val+Blender.sys.basename(mesh_image.getFilename()) + if len(md2.skins[0].name)>64: + print "Texture Path and name is more than 64 characters" + result=Blender.Draw.PupMenu("Texture path and name is more than 64 characters-Quitting") + return False + + #put texture information in the md2 structure + #build UV coord dictionary (prevents double entries-saves space) + for face in mesh.faces: + for i in range(0,3): + t=(face.uv[i]) + tex_key=(t[0],t[1]) + if not tex_list.has_key(tex_key): + tex_list[tex_key]=tex_count + tex_count+=1 + md2.num_tex_coords=tex_count #each vert has its own UV coord + + for this_tex in range (0, md2.num_tex_coords): + md2.tex_coords.append(md2_tex_coord()) + for coord, index in tex_list.iteritems(): + #md2.tex_coords.append(md2_tex_coord()) + md2.tex_coords[index].u=int(coord[0]*md2.skin_width) + md2.tex_coords[index].v=int((1-coord[1])*md2.skin_height) + + #put faces in the md2 structure + #for each face in the model + for this_face in range(0, md2.num_faces): + md2.faces.append(md2_face()) + for i in range(0,3): + #blender uses indexed vertexes so this works very well + md2.faces[this_face].vertex_index[i]=mesh.faces[this_face].verts[i].index + #lookup texture index in dictionary + uv_coord=(mesh.faces[this_face].uv[i]) + tex_key=(uv_coord[0],uv_coord[1]) + tex_index=tex_list[tex_key] + md2.faces[this_face].texture_index[i]=tex_index + + Blender.Window.DrawProgressBar(0.5, "Computing GL Commands") + + #compute GL commands + md2.num_GL_commands=build_GL_commands(md2, mesh) + + #get the frame data + #calculate 1 frame size + (1 vert size*num_verts) + md2.frame_size=40+(md2.num_vertices*4) #in bytes + + #get the frame list + user_frame_list=get_frame_list() + if user_frame_list=="default": + md2.num_frames=198 + else: + temp=user_frame_list[len(user_frame_list)-1] #last item + md2.num_frames=temp[2] #last frame number + + + progress=0.5 + progressIncrement=0.25/md2.num_frames + + #fill in each frame with frame info and all the vertex data for that frame + for frame_counter in range(0,md2.num_frames): + + progress+=progressIncrement + Blender.Window.DrawProgressBar(progress, "Calculating Frame: "+str(frame_counter)) + + #add a frame + md2.frames.append(md2_frame()) + #update the mesh objects vertex positions for the animation + Blender.Set("curframe", frame_counter) #set blender to the correct frame + mesh.getFromObject(object.name) #update the mesh to make verts current + +#each frame has a scale and transform value that gets the vertex value between 0-255 +#since the scale and transform are the same for the all the verts in the frame, we only need +#to figure this out once per frame + + #we need to start with the bounding box + #bounding_box=object.getBoundBox() #uses the object, not the mesh data + #initialize with the first vertex for both min and max. X and Y are swapped for MD2 format + + #initialize + frame_min_x=100000.0 + frame_max_x=-100000.0 + frame_min_y=100000.0 + frame_max_y=-100000.0 + frame_min_z=100000.0 + frame_max_z=-100000.0 + + for face in mesh.faces: + for vert in face.verts: + if frame_min_x>vert.co[1]: frame_min_x=vert.co[1] + if frame_max_xvert.co[0]: frame_min_y=vert.co[0] + if frame_max_yvert.co[2]: frame_min_z=vert.co[2] + if frame_max_z maxdot): + maxdot = dot; + maxdotindex = j; + + md2.frames[frame_counter].vertices[vert_counter].lightnormalindex=maxdotindex+2 + + del maxdot, maxdotindex + del new_x, new_y, new_z + del frame_max_x, frame_max_y, frame_max_z, frame_min_x, frame_min_y, frame_min_z + del frame_scale_x, frame_scale_y, frame_scale_z, frame_trans_x, frame_trans_y, frame_trans_z + + + #output all the frame names-user_frame_list is loaded during the validation + for frame_set in user_frame_list: + for counter in range(frame_set[1]-1, frame_set[2]): + md2.frames[counter].name=frame_set[0]+"_"+str(counter-frame_set[1]+2) + + #compute these after everthing is loaded into a md2 structure + header_size=17*4 #17 integers, and each integer is 4 bytes + skin_size=64*md2.num_skins #64 char per skin * number of skins + tex_coord_size=4*md2.num_tex_coords #2 short * number of texture coords + face_size=12*md2.num_faces #3 shorts for vertex index, 3 shorts for tex index + frames_size=(((12+12+16)+(4*md2.num_vertices)) * md2.num_frames) #frame info+verts per frame*num frames + GL_command_size=md2.num_GL_commands*4 #each is an int or float, so 4 bytes per + + #fill in the info about offsets + md2.offset_skins=0+header_size + md2.offset_tex_coords=md2.offset_skins+skin_size + md2.offset_faces=md2.offset_tex_coords+tex_coord_size + md2.offset_frames=md2.offset_faces+face_size + md2.offset_GL_commands=md2.offset_frames+frames_size + md2.offset_end=md2.offset_GL_commands+GL_command_size + +###################################################### +# Get Frame List +###################################################### +def get_frame_list(): + global g_frame_filename + frame_list=[] + + if g_frame_filename.val=="default": + return MD2_FRAME_NAME_LIST + + else: + #check for file + if (Blender.sys.exists(g_frame_filename.val)==1): + #open file and read it in + file=open(g_frame_filename.val,"r") + lines=file.readlines() + file.close() + + #check header (first line) + if lines[0].stip()<>"# MD2 Frame Name List": + print "its not a valid file" + result=Blender.Draw.PupMenu("This is not a valid frame definition file-using default%t|OK") + return MD2_FRAME_NAME_LIST + else: + #read in the data + num_frames=0 + for counter in range(1, len(lines)): + current_line=lines[counter].strip() + if current_line[0]=="#": + #found a comment + pass + else: + data=current_line.split() + frame_list.append([data[0],num_frames+1, num_frames+int(data[1])]) + num_frames+=int(data[1]) + return frame_list + else: + print "Cannot find file" + result=Blender.Draw.PupMenu("Cannot find frame definion file-using default%t|OK") + return MD2_FRAME_NAME_LIST + +###################################################### +# Globals for GL command list calculations +###################################################### +used_tris=[] +edge_dict={} +strip_verts=[] +strip_st=[] +strip_tris=[] +strip_first_run=True +odd=False + +###################################################### +# Find Strip length function +###################################################### +def find_strip_length(mesh, start_tri, edge_key): + #print "Finding strip length" + + global used_tris + global edge_dict + global strip_tris + global strip_st + global strip_verts + global strip_first_run + global odd + + used_tris[start_tri]=2 + + strip_tris.append(start_tri) #add this tri to the potential list of tri-strip + + #print "I am face: ", start_tri + #print "Using edge Key: ", edge_key + + faces=edge_dict[edge_key] #get list of face indexes that share this edge + if (len(faces)==0): + #print "Cant find edge with key: ", edge_key + pass + + #print "Faces sharing this edge: ", faces + for face_index in faces: + face=mesh.faces[face_index] + if face_index==start_tri: #don't want to check myself + #print "I found myself, continuing" + pass + else: + if used_tris[face_index]!=0: #found a used tri-move along + #print "Found a used tri: ", face_index + pass + else: + #find non-shared vert + for vert_counter in range(0,3): + if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]): + next_vert=vert_counter + + if(odd==False): + #print "Found a suitable even connecting tri: ", face_index + used_tris[face_index]=2 #mark as dirty for this rum + odd=True + + #find the new edge + if(face.verts[next_vert].index < face.verts[(next_vert+2)%3].index): + temp_key=(face.verts[next_vert].index,face.verts[(next_vert+2)%3].index) + else: + temp_key=(face.verts[(next_vert+2)%3].index, face.verts[next_vert].index) + + #print "temp key: ", temp_key + temp_faces=edge_dict[temp_key] + + if(len(temp_faces)==0): + print "Can't find any other faces with key: ", temp_key + else: + #search the new edge + #print "found other faces, searching them" + find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best + break; + else: + #print "Found a suitable odd connecting tri: ", face_index + used_tris[face_index]=2 #mark as dirty for this rum + odd=False + + #find the new edge + if(face.verts[next_vert].index < face.verts[(next_vert+1)%3].index): + temp_key=(face.verts[next_vert].index,face.verts[(next_vert+1)%3].index) + else: + temp_key=(face.verts[(next_vert+1)%3].index, face.verts[next_vert].index) + #print "temp key: ", temp_key + temp_faces=edge_dict[temp_key] + if(len(temp_faces)==0): + print "Can't find any other faces with key: ", temp_key + else: + #search the new edge + #print "found other faces, searching them" + find_strip_length(mesh, face_index, temp_key) #recursive greedy-takes first tri it finds as best + break; + + return len(strip_tris) + + +###################################################### +# Tri-Stripify function +###################################################### +def stripify_tri_list(mesh, edge_key): + global edge_dict + global strip_tris + global strip_st + global strip_verts + + shared_edge=[] + key=[] + + #print "*****Stripify the triangle list*******" + #print "strip tris: ", strip_tris + #print "strip_tri length: ", len(strip_tris) + + for tri_counter in range(0, len(strip_tris)): + face=mesh.faces[strip_tris[tri_counter]] + if (tri_counter==0): #first one only + #find non-edge vert + for vert_counter in range(0,3): + if (face.verts[vert_counter].index!=edge_key[0] and face.verts[vert_counter].index!=edge_key[1]): + start_vert=vert_counter + strip_verts.append(face.verts[start_vert].index) + strip_st.append(face.uv[start_vert]) + + strip_verts.append(face.verts[(start_vert+2)%3].index) + strip_st.append(face.uv[(start_vert+2)%3]) + + strip_verts.append(face.verts[(start_vert+1)%3].index) + strip_st.append(face.uv[(start_vert+1)%3]) + else: + for vert_counter in range(0,3): + if(face.verts[vert_counter].index!=strip_verts[-1] and face.verts[vert_counter].index!=strip_verts[-2]): + strip_verts.append(face.verts[vert_counter].index) + strip_st.append(face.uv[vert_counter]) + break + + + +###################################################### +# Build GL command List +###################################################### +def build_GL_commands(md2, mesh): + print "Building GL Commands" + + global used_tris + global edge_dict + global strip_verts + global strip_tris + global strip_st + + #globals initialization + used_tris=[0]*len(mesh.faces) + #print "Used: ", used_tris + num_commands=0 + + #edge dictionary generation + edge_dict=dict([(ed.key,[]) for ed in mesh.edges]) + for face in (mesh.faces): + for key in face.edge_keys: + edge_dict[key].append(face.index) + + #print "edge Dict: ", edge_dict + + for tri_counter in range(0,len(mesh.faces)): + if used_tris[tri_counter]!=0: + #print "Found a used triangle: ", tri_counter + pass + else: + #print "Found an unused triangle: ", tri_counter + + #intialization + strip_tris=[0]*0 + strip_verts=[0]*0 + strip_st=[0]*0 + strip_first_run=True + odd=True + + #find the strip length + strip_length=find_strip_length(mesh, tri_counter, mesh.faces[tri_counter].edge_keys[0]) + + #mark tris as used + for used_counter in range(0,strip_length): + used_tris[strip_tris[used_counter]]=1 + + stripify_tri_list(mesh, mesh.faces[tri_counter].edge_keys[0]) + + #create command list + cmd_list=md2_GL_cmd_list() + #number of commands in this list + print "strip length: ", strip_length + cmd_list.num=(len(strip_tris)+2) #positive for strips, fans would be negative, but not supported yet + num_commands+=1 + + #add s,t,vert for this command list + for command_counter in range(0, len(strip_tris)+2): + cmd=md2_GL_command() + cmd.s=strip_st[command_counter][0] + cmd.t=1.0-strip_st[command_counter][1] #flip upside down + cmd.vert_index=strip_verts[command_counter] + num_commands+=3 + cmd_list.cmd_list.append(cmd) + print "Cmd List length: ", len(cmd_list.cmd_list) + print "Cmd list num: ", cmd_list.num + print "Cmd List: ", cmd_list.dump() + md2.GL_commands.append(cmd_list) + + #add the null command at the end + temp_cmdlist=md2_GL_cmd_list() + temp_cmdlist.num=0 + md2.GL_commands.append(temp_cmdlist) + num_commands+=1 + + #cleanup and return + used=strip_vert=strip_st=strip_tris=0 + return num_commands + + + + +###################################################### +# Save MD2 Format +###################################################### +def save_md2(filename): + print "" + print "***********************************" + print "MD2 Export" + print "***********************************" + print "" + + Blender.Window.DrawProgressBar(0.0,"Begining MD2 Export") + + md2=md2_obj() #blank md2 object to save + + #get the object + mesh_objs = Blender.Object.GetSelected() + + #check there is a blender object selected + if len(mesh_objs)==0: + print "Fatal Error: Must select a mesh to output as MD2" + print "Found nothing" + result=Blender.Draw.PupMenu("Must select an object to export%t|OK") + return + + mesh_obj=mesh_objs[0] #this gets the first object (should be only one) + + #check if it's a mesh object + if mesh_obj.getType()!="Mesh": + print "Fatal Error: Must select a mesh to output as MD2" + print "Found: ", mesh_obj.getType() + result=Blender.Draw.PupMenu("Selected Object must be a mesh to output as MD2%t|OK") + return + + ok=validation(mesh_obj) + if ok==False: + return + + fill_md2(md2, mesh_obj) + md2.dump() + + Blender.Window.DrawProgressBar(1.0, "Writing to Disk") + + #actually write it to disk + file=open(filename,"wb") + md2.save(file) + file.close() + + #cleanup + md2=0 + + print "Closed the file" diff --git a/release/scripts/md2_import.py b/release/scripts/md2_import.py new file mode 100644 index 00000000000..e39b2ca85ec --- /dev/null +++ b/release/scripts/md2_import.py @@ -0,0 +1,598 @@ +#!BPY + +""" +Name: 'MD2 (.md2)' +Blender: 239 +Group: 'Import' +Tooltip: 'Import from Quake file format (.md2).' +""" + +__author__ = 'Bob Holcomb' +__version__ = '0.16' +__url__ = ["Bob's site, http://bane.servebeer.com", + "Support forum, http://scourage.servebeer.com/phpbb/", "blender", "elysiun"] +__email__ = ["Bob Holcomb, bob_holcomb:hotmail*com", "scripts"] +__bpydoc__ = """\ +This script imports a Quake 2 file (MD2), textures, +and animations into blender for editing. Loader is based on MD2 loader from www.gametutorials.com-Thanks DigiBen! and the md3 blender loader by PhaethonH
+ + Additional help from: Shadwolf, Skandal, Rojo and Campbell Barton
+ Thanks Guys! +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Bob Holcomb +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +import Blender +from Blender import Mesh, Object, sys +from Blender.BGL import * +from Blender.Draw import * +from Blender.Window import * +from Blender.Mathutils import Vector +import struct +from types import * + + +###################################################### +# Main Body +###################################################### + +#returns the string from a null terminated string +def asciiz (s): + n = 0 + while (ord(s[n]) != 0): + n = n + 1 + return s[0:n] + + +###################################################### +# MD2 Model Constants +###################################################### +MD2_MAX_TRIANGLES=4096 +MD2_MAX_VERTICES=2048 +MD2_MAX_TEXCOORDS=2048 +MD2_MAX_FRAMES=512 +MD2_MAX_SKINS=32 +MD2_MAX_FRAMESIZE=(MD2_MAX_VERTICES * 4 + 128) + +###################################################### +# MD2 data structures +###################################################### +class md2_alias_triangle(object): + __slots__ = 'vertices', 'lightnormalindex' + binary_format="<3BB" #little-endian (<), 3 Unsigned char + + def __init__(self): + self.vertices=[0]*3 + self.lightnormalindex=0 + + def load(self, file): + temp_data = file.read(struct.calcsize(self.binary_format)) + data = struct.unpack(self.binary_format, temp_data) + self.vertices[0]=data[0] + self.vertices[1]=data[1] + self.vertices[2]=data[2] + self.lightnormalindex=data[3] + return self + + def dump(self): + print "MD2 Alias_Triangle Structure" + print "vertex: ", self.vertices[0] + print "vertex: ", self.vertices[1] + print "vertex: ", self.vertices[2] + print "lightnormalindex: ",self.lightnormalindex + print "" + +class md2_face(object): + + binary_format="<3h3h" #little-endian (<), 3 short, 3 short + + __slots__ = 'vertex_index', 'texture_index' + + def __init__(self): + self.vertex_index = [ 0, 0, 0 ] + self.texture_index = [ 0, 0, 0] + + def load (self, file): + temp_data=file.read(struct.calcsize(self.binary_format)) + data=struct.unpack(self.binary_format, temp_data) + self.vertex_index[0]=data[0] + self.vertex_index[1]=data[1] + self.vertex_index[2]=data[2] + self.texture_index[0]=data[3] + self.texture_index[1]=data[4] + self.texture_index[2]=data[5] + return self + + def dump (self): + print "MD2 Face Structure" + print "vertex index: ", self.vertex_index[0] + print "vertex index: ", self.vertex_index[1] + print "vertex index: ", self.vertex_index[2] + print "texture index: ", self.texture_index[0] + print "texture index: ", self.texture_index[1] + print "texture index: ", self.texture_index[2] + print "" + +class md2_tex_coord(object): + __slots__ = 'u', 'v' + binary_format="<2h" #little-endian (<), 2 unsigned short + + def __init__(self): + self.u=0 + self.v=0 + + def load (self, file): + temp_data=file.read(struct.calcsize(self.binary_format)) + data=struct.unpack(self.binary_format, temp_data) + self.u=data[0] + self.v=data[1] + return self + + def dump (self): + print "MD2 Texture Coordinate Structure" + print "texture coordinate u: ",self.u + print "texture coordinate v: ",self.v + print "" + + +class md2_skin(object): + __slots__ = 'name' + binary_format="<64s" #little-endian (<), char[64] + + def __init__(self): + self.name="" + + def load (self, file): + temp_data=file.read(struct.calcsize(self.binary_format)) + data=struct.unpack(self.binary_format, temp_data) + self.name=asciiz(data[0]) + return self + + def dump (self): + print "MD2 Skin" + print "skin name: ",self.name + print "" + +class md2_alias_frame(object): + __slots__ = 'scale', 'translate', 'name', 'vertices' + binary_format="<3f3f16s" #little-endian (<), 3 float, 3 float char[16] + #did not add the "3bb" to the end of the binary format + #because the alias_vertices will be read in through + #thier own loader + + def __init__(self): + self.scale=[0.0]*3 + self.translate=[0.0]*3 + self.name="" + self.vertices=[] + + + def load (self, file): + temp_data=file.read(struct.calcsize(self.binary_format)) + data=struct.unpack(self.binary_format, temp_data) + self.scale[0]=data[0] + self.scale[1]=data[1] + self.scale[2]=data[2] + self.translate[0]=data[3] + self.translate[1]=data[4] + self.translate[2]=data[5] + self.name=asciiz(data[6]) + return self + + def dump (self): + print "MD2 Alias Frame" + print "scale x: ",self.scale[0] + print "scale y: ",self.scale[1] + print "scale z: ",self.scale[2] + print "translate x: ",self.translate[0] + print "translate y: ",self.translate[1] + print "translate z: ",self.translate[2] + print "name: ",self.name + print "" + +class md2_obj(object): + __slots__ =\ + 'tex_coords', 'faces', 'frames',\ + 'skins', 'ident', 'version',\ + 'skin_width', 'skin_height',\ + 'frame_size', 'num_skins', 'num_vertices',\ + 'num_tex_coords', 'num_faces', 'num_GL_commands',\ + 'num_frames', 'offset_skins', 'offset_tex_coords',\ + 'offset_faces', 'offset_frames', 'offset_GL_commands' + + ''' + #Header Structure + ident=0 #int 0 This is used to identify the file + version=0 #int 1 The version number of the file (Must be 8) + skin_width=0 #int 2 The skin width in pixels + skin_height=0 #int 3 The skin height in pixels + frame_size=0 #int 4 The size in bytes the frames are + num_skins=0 #int 5 The number of skins associated with the model + num_vertices=0 #int 6 The number of vertices (constant for each frame) + num_tex_coords=0 #int 7 The number of texture coordinates + num_faces=0 #int 8 The number of faces (polygons) + num_GL_commands=0 #int 9 The number of gl commands + num_frames=0 #int 10 The number of animation frames + offset_skins=0 #int 11 The offset in the file for the skin data + offset_tex_coords=0 #int 12 The offset in the file for the texture data + offset_faces=0 #int 13 The offset in the file for the face data + offset_frames=0 #int 14 The offset in the file for the frames data + offset_GL_commands=0#int 15 The offset in the file for the gl commands data + offset_end=0 #int 16 The end of the file offset + ''' + binary_format="<17i" #little-endian (<), 17 integers (17i) + + #md2 data objects + + def __init__ (self): + self.tex_coords=[] + self.faces=[] + self.frames=[] + self.skins=[] + + + def load (self, file): + temp_data = file.read(struct.calcsize(self.binary_format)) + data = struct.unpack(self.binary_format, temp_data) + + self.ident=data[0] + self.version=data[1] + + if (self.ident!=844121161 or self.version!=8): + print "Not a valid MD2 file" + Exit() + + self.skin_width=data[2] + self.skin_height=data[3] + self.frame_size=data[4] + + #make the # of skin objects for model + self.num_skins=data[5] + for i in xrange(0,self.num_skins): + self.skins.append(md2_skin()) + + self.num_vertices=data[6] + + #make the # of texture coordinates for model + self.num_tex_coords=data[7] + for i in xrange(0,self.num_tex_coords): + self.tex_coords.append(md2_tex_coord()) + + #make the # of triangle faces for model + self.num_faces=data[8] + for i in xrange(0,self.num_faces): + self.faces.append(md2_face()) + + self.num_GL_commands=data[9] + + #make the # of frames for the model + self.num_frames=data[10] + for i in xrange(0,self.num_frames): + self.frames.append(md2_alias_frame()) + #make the # of vertices for each frame + for j in xrange(0,self.num_vertices): + self.frames[i].vertices.append(md2_alias_triangle()) + + self.offset_skins=data[11] + self.offset_tex_coords=data[12] + self.offset_faces=data[13] + self.offset_frames=data[14] + self.offset_GL_commands=data[15] + + #load the skin info + file.seek(self.offset_skins,0) + for i in xrange(0, self.num_skins): + self.skins[i].load(file) + #self.skins[i].dump() + + #load the texture coordinates + file.seek(self.offset_tex_coords,0) + for i in xrange(0, self.num_tex_coords): + self.tex_coords[i].load(file) + #self.tex_coords[i].dump() + + #load the face info + file.seek(self.offset_faces,0) + for i in xrange(0, self.num_faces): + self.faces[i].load(file) + #self.faces[i].dump() + + #load the frames + file.seek(self.offset_frames,0) + for i in xrange(0, self.num_frames): + self.frames[i].load(file) + #self.frames[i].dump() + for j in xrange(0,self.num_vertices): + self.frames[i].vertices[j].load(file) + #self.frames[i].vertices[j].dump() + return self + + def dump (self): + print "Header Information" + print "ident: ", self.ident + print "version: ", self.version + print "skin width: ", self.skin_width + print "skin height: ", self.skin_height + print "frame size: ", self.frame_size + print "number of skins: ", self.num_skins + print "number of texture coordinates: ", self.num_tex_coords + print "number of faces: ", self.num_faces + print "number of frames: ", self.num_frames + print "number of vertices: ", self.num_vertices + print "offset skins: ", self.offset_skins + print "offset texture coordinates: ", self.offset_tex_coords + print "offset faces: ", self.offset_faces + print "offset frames: ",self.offset_frames + print "" + +###################################################### +# Import functions +###################################################### +def load_textures(md2, texture_filename): + #did the user specify a texture they wanted to use? + if texture_filename: + if (Blender.sys.exists(texture_filename)): + try: return Blender.Image.Load(texture_filename) + except: return -1 # could not load? + + #does the model have textures specified with it? + if int(md2.num_skins) > 0: + for i in xrange(0,md2.num_skins): + #md2.skins[i].dump() + if (Blender.sys.exists(md2.skins[i].name)): + try: return Blender.Image.Load(md2.skins[i].name) + except: return -1 + + +def animate_md2(md2, mesh): + ######### Animate the verts through keyframe animation + + # Fast access to the meshes vertex coords + verts = [v.co for v in mesh.verts] + scale = g_scale.val + + for i in xrange(1, md2.num_frames): + frame = md2.frames[i] + #update the vertices + for j in xrange(md2.num_vertices): + x=(frame.scale[0] * frame.vertices[j].vertices[0] + frame.translate[0]) * scale + y=(frame.scale[1] * frame.vertices[j].vertices[1] + frame.translate[1]) * scale + z=(frame.scale[2] * frame.vertices[j].vertices[2] + frame.translate[2]) * scale + + #put the vertex in the right spot + verts[j][:] = y,-x,z + + mesh.insertKey(i,"absolute") + # mesh.insertKey(i) + + #not really necissary, but I like playing with the frame counter + Blender.Set("curframe", i) + + + # Make the keys animate in the 3d view. + key = mesh.key + key.relative = False + + # Add an IPO to teh Key + ipo = Blender.Ipo.New('Key', 'md2') + key.ipo = ipo + # Add a curve to the IPO + curve = ipo.addCurve('Basis') + + # Add 2 points to cycle through the frames. + curve.append((1, 0)) + curve.append((md2.num_frames, (md2.num_frames-1)/10.0)) + curve.interpolation = Blender.IpoCurve.InterpTypes.LINEAR + + + +def load_md2(md2_filename, texture_filename): + #read the file in + file=open(md2_filename,"rb") + WaitCursor(1) + DrawProgressBar(0.0, 'Loading MD2') + md2=md2_obj() + md2.load(file) + #md2.dump() + file.close() + + ######### Creates a new mesh + mesh = Mesh.New() + + uv_coord=[] + #uv_list=[] + verts_extend = [] + #load the textures to use later + #-1 if there is no texture to load + mesh_image=load_textures(md2, texture_filename) + if mesh_image == -1 and texture_filename: + print 'MD2 Import, Warning, texture "%s" could not load' + + ######### Make the verts + DrawProgressBar(0.25,"Loading Vertex Data") + frame = md2.frames[0] + scale = g_scale.val + + def tmp_get_vertex(i): + #use the first frame for the mesh vertices + x=(frame.scale[0]*frame.vertices[i].vertices[0]+frame.translate[0])*scale + y=(frame.scale[1]*frame.vertices[i].vertices[1]+frame.translate[1])*scale + z=(frame.scale[2]*frame.vertices[i].vertices[2]+frame.translate[2])*scale + return y,-x,z + + mesh.verts.extend( [tmp_get_vertex(i) for i in xrange(0,md2.num_vertices)] ) + del tmp_get_vertex + + ######## Make the UV list + DrawProgressBar(0.50,"Loading UV Data") + + w = float(md2.skin_width) + h = float(md2.skin_height) + #for some reason quake2 texture maps are upside down, flip that + uv_list = [Vector(co.u/w, 1-(co.v/h)) for co in md2.tex_coords] + del w, h + + ######### Make the faces + DrawProgressBar(0.75,"Loading Face Data") + faces = [] + face_uvs = [] + for md2_face in md2.faces: + f = md2_face.vertex_index[0], md2_face.vertex_index[2], md2_face.vertex_index[1] + uv = uv_list[md2_face.texture_index[0]], uv_list[md2_face.texture_index[2]], uv_list[md2_face.texture_index[1]] + + if f[2] == 0: + # EEKADOODLE :/ + f= f[1], f[2], f[0] + uv= uv[1], uv[2], uv[0] + + #ditto in reverse order with the texture verts + faces.append(f) + face_uvs.append(uv) + + + face_mapping = mesh.faces.extend(faces, indexList=True) + print len(faces) + print len(mesh.faces) + mesh.faceUV= True #turn on face UV coordinates for this mesh + mesh_faces = mesh.faces + for i, uv in enumerate(face_uvs): + if face_mapping[i] != None: + f = mesh_faces[face_mapping[i]] + f.uv = uv + if (mesh_image!=-1): + f.image=mesh_image + + scn= Blender.Scene.GetCurrent() + mesh_obj= scn.objects.new(mesh) + animate_md2(md2, mesh) + DrawProgressBar(0.98,"Loading Animation Data") + + #locate the Object containing the mesh at the cursor location + cursor_pos=Blender.Window.GetCursorPos() + mesh_obj.setLocation(float(cursor_pos[0]),float(cursor_pos[1]),float(cursor_pos[2])) + DrawProgressBar (1.0, "") + WaitCursor(0) + +#*********************************************** +# MAIN +#*********************************************** + +# Import globals +g_md2_filename=Create("*.md2") +#g_md2_filename=Create("/d/warvet/tris.md2") +g_texture_filename=Create('') +# g_texture_filename=Create("/d/warvet/warvet.jpg") + +g_filename_search=Create("*.md2") +g_texture_search=Create('') +# g_texture_search=Create("/d/warvet/warvet.jpg") + +#Globals +g_scale=Create(1.0) + +# Events +EVENT_NOEVENT=1 +EVENT_LOAD_MD2=2 +EVENT_CHOOSE_FILENAME=3 +EVENT_CHOOSE_TEXTURE=4 +EVENT_SAVE_MD2=5 +EVENT_EXIT=100 + +###################################################### +# Callbacks for Window functions +###################################################### +def filename_callback(input_filename): + global g_md2_filename + g_md2_filename.val=input_filename + +def texture_callback(input_texture): + global g_texture_filename + g_texture_filename.val=input_texture + +###################################################### +# GUI Loader +###################################################### + + +def draw_gui(): + global g_scale + global g_md2_filename + global g_texture_filename + global EVENT_NOEVENT,EVENT_LOAD_MD2,EVENT_CHOOSE_FILENAME,EVENT_CHOOSE_TEXTURE,EVENT_EXIT + + ########## Titles + glClear(GL_COLOR_BUFFER_BIT) + glRasterPos2d(8, 125) + Text("MD2 loader") + + ######### Parameters GUI Buttons + BeginAlign() + g_md2_filename = String("MD2 file to load: ", EVENT_NOEVENT, 10, 55, 210, 18, + g_md2_filename.val, 255, "MD2 file to load") + ########## MD2 File Search Button + Button("Browse",EVENT_CHOOSE_FILENAME,220,55,80,18) + EndAlign() + + BeginAlign() + g_texture_filename = String("Texture file to load: ", EVENT_NOEVENT, 10, 35, 210, 18, + g_texture_filename.val, 255, "Texture file to load-overrides MD2 file") + ########## Texture Search Button + Button("Browse",EVENT_CHOOSE_TEXTURE,220,35,80,18) + EndAlign() + + ########## Scale slider-default is 1/8 which is a good scale for md2->blender + g_scale= Slider("Scale Factor: ", EVENT_NOEVENT, 10, 75, 210, 18, + 1.0, 0.001, 10.0, 1, "Scale factor for obj Model"); + + ######### Draw and Exit Buttons + Button("Load",EVENT_LOAD_MD2 , 10, 10, 80, 18) + Button("Exit",EVENT_EXIT , 170, 10, 80, 18) + +def event(evt, val): + if (evt == QKEY and not val): + Blender.Draw.Exit() + +def bevent(evt): + global g_md2_filename + global g_texture_filename + global EVENT_NOEVENT,EVENT_LOAD_MD2,EVENT_SAVE_MD2,EVENT_EXIT + + ######### Manages GUI events + if (evt==EVENT_EXIT): + Blender.Draw.Exit() + elif (evt==EVENT_CHOOSE_FILENAME): + FileSelector(filename_callback, "MD2 File Selection") + elif (evt==EVENT_CHOOSE_TEXTURE): + FileSelector(texture_callback, "Texture Selection") + elif (evt==EVENT_LOAD_MD2): + if not Blender.sys.exists(g_md2_filename.val): + PupMenu('Model file does not exist') + return + else: + load_md2(g_md2_filename.val, g_texture_filename.val) + Blender.Redraw() + Blender.Draw.Exit() + return + +if __name__ == '__main__': + Register(draw_gui, event, bevent) diff --git a/release/scripts/mesh_boneweight_copy.py b/release/scripts/mesh_boneweight_copy.py new file mode 100644 index 00000000000..8aa9a1e3213 --- /dev/null +++ b/release/scripts/mesh_boneweight_copy.py @@ -0,0 +1,287 @@ +#!BPY +""" +Name: 'Bone Weight Copy' +Blender: 243 +Group: 'Object' +Tooltip: 'Copy Bone Weights from 1 mesh, to all other selected meshes.' +""" + +__author__ = ["Campbell Barton"] +__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__version__ = "0.1" +__bpydoc__ = """\ + +Bone Weight Copy + +This script is used to copy bone weights from 1 mesh with weights (the source mesh) to many (the target meshes). +Weights are copied from 1 mesh to another based on how close they are together. + +For normal operation, select 1 source mesh with vertex weights and any number of unweighted meshes that overlap the source mesh. +Then run this script using default options and check the new weigh. + + +A differnt way to use this script is to update the weights an an alredy weighted mesh. +this is done using the "Copy to Selected" option enabled and works a bit differently, +With the target mesh, select the verts you want to update. +since all meshes have weights we cant just use the weighted mesh as the source, +so the Active Object is used for the source mesh. +Run the script and the selected verts on all non active meshes will be updated. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from Blender import Armature, Object, Mathutils, Window, Mesh +Vector= Mathutils.Vector +SMALL_NUM= 0.000001 +def copy_bone_influences(_from, _to, PREF_SEL_ONLY, PREF_NO_XCROSS): + ob_from, me_from, world_verts_from, from_groups= _from + ob_to, me_to, world_verts_to, dummy= _to + del dummy + + def getSnapIdx(seek_vec, vecs): + ''' + Returns the closest vec to snap_points + ''' + + # First seek the closest Z axis vert idx/v + seek_vec_x,seek_vec_y,seek_vec_z= seek_vec + + from_vec_idx= 0 + + len_vecs= len(vecs) + + upidx= len_vecs-1 + loidx= 0 + + while from_vec_idx < len_vecs and vecs[from_vec_idx][1].z < seek_vec_z: + from_vec_idx+=1 + + # Clamp if we overstepped. + if from_vec_idx >= len_vecs: + from_vec_idx-=1 + + close_dist= (vecs[from_vec_idx][1]-seek_vec).length + close_idx= vecs[from_vec_idx][0] + + upidx= from_vec_idx+1 + loidx= from_vec_idx-1 + + # Set uselo/useup. This means we can keep seeking up/down. + if upidx >= len_vecs: useup= False + else: useup= True + + if loidx < 0: uselo= False + else: uselo= True + + # Seek up/down to find the closest v to seek vec. + while uselo or useup: + if useup: + if upidx >= len_vecs: + useup= False + else: + i,v= vecs[upidx] + if (not PREF_NO_XCROSS) or ((v.x >= -SMALL_NUM and seek_vec_x >= -SMALL_NUM) or (v.x <= SMALL_NUM and seek_vec_x <= SMALL_NUM)): # enfoce xcrossing + if v.z-seek_vec_z > close_dist: + # the verticle distance is greater then the best distance sofar. we can stop looking up. + useup= False + elif abs(seek_vec_y-v.y) < close_dist and abs(seek_vec_x-v.x) < close_dist: + # This is in the limit measure it. + l= (seek_vec-v).length + if l= -SMALL_NUM and seek_vec_x >= -SMALL_NUM) or (v.x <= SMALL_NUM and seek_vec_x <= SMALL_NUM)): # enfoce xcrossing + if seek_vec_z-v.z > close_dist: + # the verticle distance is greater then the best distance sofar. we can stop looking up. + uselo= False + elif abs(seek_vec_y-v.y) < close_dist and abs(seek_vec_x-v.x) < close_dist: + # This is in the limit measure it. + l= (seek_vec-v).length + if l "%s" ' % (ob_from.name, ob_to.name)) + + from_idx= getSnapIdx(co, world_verts_from) + from_infs= me_from.getVertexInfluences(from_idx) + + for group, weight in from_infs: + + # Add where needed. + if PREF_SEL_ONLY and group not in to_groups: + me_to.addVertGroup(group) + to_groups.append(group) + + me_to.assignVertsToGroup(group, [i], weight, add_) + + me_to.update() + +# ZSORT return (i/co) tuples, used for fast seeking of the snapvert. +def worldspace_verts_idx(me, ob): + mat= ob.matrixWorld + verts_zsort= [ (i, v.co*mat) for i, v in enumerate(me.verts) ] + + # Sorts along the Z Axis so we can optimize the getsnap. + try: verts_zsort.sort(key = lambda a: a[1].z) + except: verts_zsort.sort(lambda a,b: cmp(a[1].z, b[1].z,)) + + return verts_zsort + + +def worldspace_verts(me, ob): + mat= ob.matrixWorld + return [ v.co*mat for v in me.verts ] + +def subdivMesh(me, subdivs): + oldmode = Mesh.Mode() + Mesh.Mode(Mesh.SelectModes['FACE']) + me.sel= 1 + for i in xrange(subdivs): + me.subdivide(0) + Mesh.Mode(oldmode) + + +def main(): + print '\nStarting BoneWeight Copy...' + scn= Blender.Scene.GetCurrent() + contextSel= Object.GetSelected() + if not contextSel: + Blender.Draw.PupMenu('Error%t|2 or more mesh objects need to be selected.|aborting.') + return + + PREF_QUALITY= Blender.Draw.Create(0) + PREF_NO_XCROSS= Blender.Draw.Create(0) + PREF_SEL_ONLY= Blender.Draw.Create(0) + + pup_block = [\ + ('Quality:', PREF_QUALITY, 0, 4, 'Generate interpolated verts for a higher quality result.'),\ + ('No X Crossing', PREF_NO_XCROSS, 'Do not snap across the zero X axis'),\ + '',\ + '"Update Selected" copies',\ + 'active object weights to',\ + 'selected verts on the other',\ + 'selected mesh objects.',\ + ('Update Selected', PREF_SEL_ONLY, 'Only copy new weights to selected verts on the target mesh. (use active object as source)'),\ + ] + + + if not Blender.Draw.PupBlock("Copy Weights for %i Meshs" % len(contextSel), pup_block): + return + + PREF_SEL_ONLY= PREF_SEL_ONLY.val + PREF_NO_XCROSS= PREF_NO_XCROSS.val + quality= PREF_QUALITY.val + + act_ob= scn.objects.active + if PREF_SEL_ONLY and act_ob==None: + Blender.Draw.PupMenu('Error%t|When dealing with 2 or more meshes with vgroups|There must be an active object|to be used as a source|aborting.') + return + + sel=[] + from_data= None + + for ob in contextSel: + if ob.type=='Mesh': + me= ob.getData(mesh=1) + groups= me.getVertGroupNames() + + # If this is the only mesh with a group OR if its one of many, but its active. + if groups and ((ob==act_ob and PREF_SEL_ONLY) or (not PREF_SEL_ONLY)): + if from_data: + Blender.Draw.PupMenu('More then 1 mesh has vertex weights, only select 1 mesh with weights. aborting.') + return + else: + # This uses worldspace_verts_idx which gets (idx,co) pairs, then zsorts. + if quality: + for _ob in contextSel: + _ob.sel=0 + ob.sel=1 + Object.Duplicate(mesh=1) + ob= scn.objects.active + me= ob.getData(mesh=1) + # groups will be the same + print '\tGenerating higher %ix quality weights.' % quality + subdivMesh(me, quality) + scn.unlink(ob) + from_data= (ob, me, worldspace_verts_idx(me, ob), groups) + + else: + data= (ob, me, worldspace_verts(me, ob), groups) + sel.append(data) + + if not from_data: + Blender.Draw.PupMenu('Error%t|No mesh with vertex groups found.') + return + + if not sel: + Blender.Draw.PupMenu('Error%t|Select 2 or more mesh objects, aborting.') + if quality: from_data[1].verts= None + return + + t= Blender.sys.time() + Window.WaitCursor(1) + + # Now do the copy. + print '\tCopying from "%s" to %i other mesh(es).' % (from_data[0].name, len(sel)) + for data in sel: + copy_bone_influences(from_data, data, PREF_SEL_ONLY, PREF_NO_XCROSS) + + # We cant unlink the mesh, but at least remove its data. + if quality: + from_data[1].verts= None + + print 'Copy Complete in %.6f sec' % (Blender.sys.time()-t) + Window.DrawProgressBar(1.0, '') + Window.WaitCursor(0) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/mesh_cleanup.py b/release/scripts/mesh_cleanup.py new file mode 100644 index 00000000000..1eb3e3968b2 --- /dev/null +++ b/release/scripts/mesh_cleanup.py @@ -0,0 +1,452 @@ +#!BPY +""" +Name: 'Clean Meshes' +Blender: 242 +Group: 'Mesh' +Tooltip: 'Clean unused data from all selected mesh objects.' +""" + +__author__ = ["Campbell Barton"] +__url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") +__version__ = "0.1" +__bpydoc__ = """\ +Clean Meshes + +Cleans unused data from selected meshes +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +from Blender import * +import bpy +from Blender.Mathutils import TriangleArea + +import Blender +import BPyMesh +dict2MeshWeight= BPyMesh.dict2MeshWeight +meshWeight2Dict= BPyMesh.meshWeight2Dict + +def rem_free_verts(me): + vert_users= [0] * len(me.verts) + for f in me.faces: + for v in f: + vert_users[v.index]+=1 + + for e in me.edges: + for v in e: # loop on edge verts + vert_users[v.index]+=1 + + verts_free= [i for i, users in enumerate(vert_users) if not users] + + if verts_free: + pass + me.verts.delete(verts_free) + return len(verts_free) + +def rem_free_edges(me, limit=None): + ''' Only remove based on limit if a limit is set, else remove all ''' + + edgeDict= {} # will use a set when python 2.4 is standard. + + for f in me.faces: + for edkey in f.edge_keys: + edgeDict[edkey] = None + + edges_free= [] + for e in me.edges: + if not edgeDict.has_key(e.key): + edges_free.append(e) + + if limit != None: + edges_free= [e for e in edges_free if e.length <= limit] + + me.edges.delete(edges_free) + return len(edges_free) + +def rem_area_faces(me, limit=0.001): + ''' Faces that have an area below the limit ''' + rem_faces= [f for f in me.faces if f.area <= limit] + if rem_faces: + me.faces.delete( 0, rem_faces ) + return len(rem_faces) + +def rem_perimeter_faces(me, limit=0.001): + ''' Faces whos combine edge length is below the limit ''' + def faceEdLen(f): + v= f.v + if len(v) == 3: + return\ + (v[0].co-v[1].co).length +\ + (v[1].co-v[2].co).length +\ + (v[2].co-v[0].co).length + else: # 4 + return\ + (v[0].co-v[1].co).length +\ + (v[1].co-v[2].co).length +\ + (v[2].co-v[3].co).length +\ + (v[3].co-v[0].co).length + rem_faces= [f for f in me.faces if faceEdLen(f) <= limit] + if rem_faces: + me.faces.delete( 0, rem_faces ) + return len(rem_faces) + +def rem_unused_materials(me): + materials= me.materials + len_materials= len(materials) + if len_materials < 2: + return 0 + + rem_materials= 0 + + material_users= dict( [(i,0) for i in xrange(len_materials)] ) + + for f in me.faces: + # Make sure the face index isnt too big. this happens sometimes. + if f.mat >= len_materials: + f.mat=0 + material_users[f.mat] += 1 + + mat_idx_subtract= 0 + reindex_mapping= dict( [(i,0) for i in xrange(len_materials)] ) + i= len_materials + while i: + i-=1 + + if material_users[i] == 0: + mat_idx_subtract+=1 + reindex_mapping[i]= mat_idx_subtract + materials.pop(i) + rem_materials+=1 + + for f in me.faces: + f.mat= f.mat - reindex_mapping[f.mat] + + me.materials= materials + return rem_materials + + +def rem_free_groups(me, groupNames, vWeightDict): + ''' cound how many vert users a group has and remove unused groups ''' + rem_groups = 0 + groupUserDict= dict([(group,0) for group in groupNames]) + + for vertexWeight in vWeightDict: + for group, weight in vertexWeight.iteritems(): + groupUserDict[group] += 1 + + i=len(groupNames) + while i: + i-=1 + group= groupNames[i] + if groupUserDict[group] == 0: + del groupNames[i] + print '\tremoving, vgroup', group + rem_groups+=1 + return rem_groups + +def rem_zero_weights(me, limit, groupNames, vWeightDict): + ''' remove verts from a group when their weight is zero.''' + rem_vweight_count= 0 + for vertexWeight in vWeightDict: + items= vertexWeight.items() + for group, weight in items: + if weight < limit: + del vertexWeight[group] + rem_vweight_count+= 1 + + return rem_vweight_count + + +def normalize_vweight(me, groupNames, vWeightDict): + for vertexWeight in vWeightDict: + unit= 0.0 + for group, weight in vertexWeight.iteritems(): + unit+= weight + + if unit != 1.0 and unit != 0.0: + for group, weight in vertexWeight.iteritems(): + vertexWeight[group]= weight/unit + +def isnan(f): + fstring = str(f).lower() + if 'nan' in fstring: + return True + if 'inf' in fstring: + return True + + return False + +def fix_nan_verts__internal(me): + rem_nan = 0 + for v in me.verts: + co = v.co + for i in (0,1,2): + if isnan(co[i]): + co[i] = 0.0 + rem_nan += 1 + return rem_nan + +def fix_nan_verts(me): + rem_nan = 0 + key = me.key + if key: + # Find the object, and get a mesh thats thinked to the oblink. + # this is a bit crap but needed to set the active key. + me_oblink = None + for ob in bpy.data.objects: + me_oblink = ob.getData(mesh=1) + if me_oblink == me: + me = me_oblink + break + if not me_oblink: + ob = None + + if key and ob: + blocks = key.blocks + # print blocks + orig_pin = ob.pinShape + orig_shape = ob.activeShape + orig_relative = key.relative + ob.pinShape = True + for i, block in enumerate(blocks): + ob.activeShape = i+1 + ob.makeDisplayList() + rem_nan += fix_nan_verts__internal(me) + me.update(block.name) # get the new verts + ob.pinShape = orig_pin + ob.activeShape = orig_shape + key.relative = orig_relative + + else: # No keys, simple operation + rem_nan = fix_nan_verts__internal(me) + + return rem_nan + +def fix_nan_uvs(me): + rem_nan = 0 + if me.faceUV: + orig_uvlayer = me.activeUVLayer + for uvlayer in me.getUVLayerNames(): + me.activeUVLayer = uvlayer + for f in me.faces: + for uv in f.uv: + for i in (0,1): + if isnan(uv[i]): + uv[i] = 0.0 + rem_nan += 1 + me.activeUVLayer = orig_uvlayer + return rem_nan + + +def has_vcol(me): + for f in me.faces: + for col in f.col: + if not (255 == col.r == col.g == col.b): + return True + return False + +def rem_white_vcol_layers(me): + vcols_removed = 0 + if me.vertexColors: + for col in me.getColorLayerNames(): + me.activeColorLayer = col + if not has_vcol(me): + me.removeColorLayer(col) + vcols_removed += 1 + + return vcols_removed + + +def main(): + sce= bpy.data.scenes.active + obsel= list(sce.objects.context) + actob= sce.objects.active + + is_editmode= Window.EditMode() + + # Edit mode object is not active, add it to the list. + if is_editmode and (not actob.sel): + obsel.append(actob) + + + #====================================# + # Popup menu to select the functions # + #====================================# + + CLEAN_ALL_DATA= Draw.Create(0) + CLEAN_VERTS_FREE= Draw.Create(1) + CLEAN_EDGE_NOFACE= Draw.Create(0) + CLEAN_EDGE_SMALL= Draw.Create(0) + CLEAN_FACE_PERIMETER= Draw.Create(0) + CLEAN_FACE_SMALL= Draw.Create(0) + + CLEAN_MATERIALS= Draw.Create(0) + CLEAN_WHITE_VCOL_LAYERS= Draw.Create(0) + CLEAN_GROUP= Draw.Create(0) + CLEAN_VWEIGHT= Draw.Create(0) + CLEAN_WEIGHT_NORMALIZE= Draw.Create(0) + limit= Draw.Create(0.01) + + CLEAN_NAN_VERTS= Draw.Create(0) + CLEAN_NAN_UVS= Draw.Create(0) + + # Get USER Options + + pup_block= [\ + ('Verts: free', CLEAN_VERTS_FREE, 'Remove verts that are not used by an edge or a face.'),\ + ('Edges: free', CLEAN_EDGE_NOFACE, 'Remove edges that are not in a face.'),\ + ('Edges: short', CLEAN_EDGE_SMALL, 'Remove edges that are below the length limit.'),\ + ('Faces: small perimeter', CLEAN_FACE_PERIMETER, 'Remove faces below the perimeter limit.'),\ + ('Faces: small area', CLEAN_FACE_SMALL, 'Remove faces below the area limit (may remove faces stopping T-face artifacts).'),\ + ('limit: ', limit, 0.001, 1.0, 'Limit for the area and length tests above (a higher limit will remove more data).'),\ + ('Material Clean', CLEAN_MATERIALS, 'Remove unused materials.'),\ + ('Color Layers', CLEAN_WHITE_VCOL_LAYERS, 'Remove vertex color layers that are totaly white'),\ + ('VGroup Clean', CLEAN_GROUP, 'Remove vertex groups that have no verts using them.'),\ + ('Weight Clean', CLEAN_VWEIGHT, 'Remove zero weighted verts from groups (limit is zero threshold).'),\ + ('WeightNormalize', CLEAN_WEIGHT_NORMALIZE, 'Make the sum total of vertex weights accross vgroups 1.0 for each vertex.'),\ + 'Clean NAN values',\ + ('NAN Verts', CLEAN_NAN_VERTS, 'Make NAN or INF verts (0,0,0)'),\ + ('NAN UVs', CLEAN_NAN_UVS, 'Make NAN or INF UVs (0,0)'),\ + '',\ + ('All Mesh Data', CLEAN_ALL_DATA, 'Warning! Operate on ALL mesh objects in your Blend file. Use with care'),\ + ] + + if not Draw.PupBlock('Clean Selected Meshes...', pup_block): + return + + CLEAN_VERTS_FREE= CLEAN_VERTS_FREE.val + CLEAN_EDGE_NOFACE= CLEAN_EDGE_NOFACE.val + CLEAN_EDGE_SMALL= CLEAN_EDGE_SMALL.val + CLEAN_FACE_PERIMETER= CLEAN_FACE_PERIMETER.val + CLEAN_FACE_SMALL= CLEAN_FACE_SMALL.val + CLEAN_MATERIALS= CLEAN_MATERIALS.val + CLEAN_WHITE_VCOL_LAYERS= CLEAN_WHITE_VCOL_LAYERS.val + CLEAN_GROUP= CLEAN_GROUP.val + CLEAN_VWEIGHT= CLEAN_VWEIGHT.val + CLEAN_WEIGHT_NORMALIZE= CLEAN_WEIGHT_NORMALIZE.val + limit= limit.val + CLEAN_ALL_DATA= CLEAN_ALL_DATA.val + CLEAN_NAN_VERTS= CLEAN_NAN_VERTS.val + CLEAN_NAN_UVS= CLEAN_NAN_UVS.val + + if is_editmode: Window.EditMode(0) + + if CLEAN_ALL_DATA: + if CLEAN_GROUP or CLEAN_VWEIGHT or CLEAN_WEIGHT_NORMALIZE: + # For groups we need the objects linked to the mesh + meshes= [ob.getData(mesh=1) for ob in bpy.data.objects if ob.type == 'Mesh' if not ob.lib] + else: + meshes= bpy.data.meshes + else: + meshes= [ob.getData(mesh=1) for ob in obsel if ob.type == 'Mesh'] + + tot_meshes = len(meshes) # so we can decrement libdata + rem_face_count= rem_edge_count= rem_vert_count= rem_material_count= rem_vcol_layer_count= rem_group_count= rem_vweight_count= fix_nan_vcount= fix_nan_uvcount= 0 + if not meshes: + if is_editmode: Window.EditMode(1) + Draw.PupMenu('No meshes to clean') + + Blender.Window.WaitCursor(1) + bpy.data.meshes.tag = False + for me in meshes: + + # Dont touch the same data twice + if me.tag: + tot_meshes -= 1 + continue + me.tag = True + + if me.lib: + tot_meshes -= 1 + continue + + if me.multires: + multires_level_orig = me.multiresDrawLevel + me.multiresDrawLevel = 1 + print 'Warning, cannot perform destructive operations on multires mesh:', me.name + else: + if CLEAN_FACE_SMALL: + rem_face_count += rem_area_faces(me, limit) + + if CLEAN_FACE_PERIMETER: + rem_face_count += rem_perimeter_faces(me, limit) + + if CLEAN_EDGE_SMALL: # for all use 2- remove all edges. + rem_edge_count += rem_free_edges(me, limit) + + if CLEAN_EDGE_NOFACE: + rem_edge_count += rem_free_edges(me) + + if CLEAN_VERTS_FREE: + rem_vert_count += rem_free_verts(me) + + if CLEAN_MATERIALS: + rem_material_count += rem_unused_materials(me) + + if CLEAN_WHITE_VCOL_LAYERS: + rem_vcol_layer_count += rem_white_vcol_layers(me) + + if CLEAN_VWEIGHT or CLEAN_GROUP or CLEAN_WEIGHT_NORMALIZE: + groupNames, vWeightDict= meshWeight2Dict(me) + + if CLEAN_VWEIGHT: + rem_vweight_count += rem_zero_weights(me, limit, groupNames, vWeightDict) + + if CLEAN_GROUP: + rem_group_count += rem_free_groups(me, groupNames, vWeightDict) + pass + + if CLEAN_WEIGHT_NORMALIZE: + normalize_vweight(me, groupNames, vWeightDict) + + # Copy back to mesh vertex groups. + dict2MeshWeight(me, groupNames, vWeightDict) + + if CLEAN_NAN_VERTS: + fix_nan_vcount = fix_nan_verts(me) + + if CLEAN_NAN_UVS: + fix_nan_uvcount = fix_nan_uvs(me) + + # restore multires. + if me.multires: + me.multiresDrawLevel = multires_level_orig + + Blender.Window.WaitCursor(0) + if is_editmode: Window.EditMode(0) + stat_string= 'Removed from ' + str(tot_meshes) + ' Mesh(es)%t|' + + if CLEAN_VERTS_FREE: stat_string+= 'Verts: %i|' % rem_vert_count + if CLEAN_EDGE_SMALL or CLEAN_EDGE_NOFACE: stat_string+= 'Edges: %i|' % rem_edge_count + if CLEAN_FACE_SMALL or CLEAN_FACE_PERIMETER: stat_string+= 'Faces: %i|' % rem_face_count + if CLEAN_MATERIALS: stat_string+= 'Materials: %i|' % rem_material_count + if CLEAN_WHITE_VCOL_LAYERS: stat_string+= 'Color Layers: %i|' % rem_vcol_layer_count + if CLEAN_VWEIGHT: stat_string+= 'VWeights: %i|' % rem_vweight_count + if CLEAN_GROUP: stat_string+= 'VGroups: %i|' % rem_group_count + if CLEAN_NAN_VERTS: stat_string+= 'Vert Nan Fix: %i|' % fix_nan_vcount + if CLEAN_NAN_UVS: stat_string+= 'UV Nan Fix: %i|' % fix_nan_uvcount + Draw.PupMenu(stat_string) + + +if __name__ == '__main__': + main() diff --git a/release/scripts/mesh_edges2curves.py b/release/scripts/mesh_edges2curves.py new file mode 100644 index 00000000000..fdf61298ebc --- /dev/null +++ b/release/scripts/mesh_edges2curves.py @@ -0,0 +1,174 @@ +#!BPY +""" Registration info for Blender menus: +Name: 'Edges to Curve' +Blender: 241 +Group: 'Mesh' +Tip: 'Edges not used by a face are converted into polyline(s)' +""" +__author__ = ("Campbell Barton") +__url__ = ("blender", "elysiun") +__version__ = "1.0 2006/02/08" + +__bpydoc__ = """\ +Edges to Curves + +This script converts open and closed edge loops into polylines + +Supported:
+ Polylines where each vert has no more then 2 edges attached to it. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +from Blender import * + +def edkey(ed): + i1 = ed.v1.index + i2 = ed.v2.index + if i1>i2: + return (i2,i1), ed + else: + return (i1,i2), ed + +def polysFromMesh(me): + # a polyline is 2 + #polylines are a list + polyLines = [] + + # Get edges not used by a face + edgeDict= dict([ (ed.key, ed) for ed in me.edges ]) + for f in me.faces: + for key in f.edge_keys: + try: + del edgeDict[key] + except: + pass + + edges= edgeDict.values() + + + while edges: + currentEdge= edges.pop() + startVert= currentEdge.v2 + endVert= currentEdge.v1 + polyLine= [startVert, endVert] + ok= 1 + while ok: + ok= 0 + #for i, ed in enumerate(edges): + i=len(edges) + while i: + i-=1 + ed= edges[i] + if ed.v1 == endVert: + polyLine.append(ed.v2) + endVert= polyLine[-1] + ok=1 + del edges[i] + #break + elif ed.v2 == endVert: + polyLine.append(ed.v1) + endVert= polyLine[-1] + ok=1 + del edges[i] + #break + elif ed.v1 == startVert: + polyLine.insert(0, ed.v2) + startVert= polyLine[0] + ok=1 + del edges[i] + #break + elif ed.v2 == startVert: + polyLine.insert(0, ed.v1) + startVert= polyLine[0] + ok=1 + del edges[i] + #break + polyLines.append((polyLine, polyLine[0]==polyLine[-1])) + # print len(edges), len(polyLines) + return polyLines + + +def mesh2polys(): + scn= Scene.GetCurrent() + scn.objects.selected = [] + + meshOb= scn.objects.active + if meshOb==None or meshOb.type != 'Mesh': + Draw.PupMenu( 'ERROR: No Active Mesh Selected, Aborting' ) + return + Window.WaitCursor(1) + Window.EditMode(0) + me = meshOb.getData(mesh=1) + polygons= polysFromMesh(me) + w=t=1 + cu= Curve.New() + cu.name = me.name + cu.setFlag(1) + + ob = scn.objects.active = scn.objects.new(cu) + ob.setMatrix(meshOb.matrixWorld) + + i=0 + for poly, closed in polygons: + if closed: + vIdx= 1 + else: + vIdx= 0 + + v= poly[vIdx] + cu.appendNurb([v.co.x, v.co.y, v.co.z, w, t]) + cu[i].type= 0 # Poly Line + + # Close the polyline if its closed. + if closed: + cu[i].setFlagU(1) + + # Add all the points in the polyline. + while vIdx 0] + + else: + # Use a small margin verts must be outside before we mirror them. + neg_vts = [v for v in me.verts if v.sel if v.co.x < -PREF_XZERO_THRESH] + pos_vts = [v for v in me.verts if v.sel if v.co.x > PREF_XZERO_THRESH] + + + + #*Mirror Location*********************************************************# + if PREF_MIRROR_LOCATION: + mirror_pairs= [] + # allign the negative with the positive. + flipvec= Mathutils.Vector() + len_neg_vts= float(len(neg_vts)) + for i1, nv in enumerate(neg_vts): + if nv.sel: # we may alredy be mirrored, if so well be deselected + nv_co= nv.co + for i2, pv in enumerate(pos_vts): + if pv.sel: + # Enforce edge users. + if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]: + flipvec[:]= pv.co + flipvec.x= -flipvec.x + l= (nv_co-flipvec).length + + if l==0.0: # Both are alredy mirrored so we dont need to think about them. + # De-Select so we dont use again/ + pv.sel= nv.sel= 0 + + # Record a match. + elif l<=PREF_MAX_DIST: + + # We can adjust the length by the normal, now we know the length is under the limit. + # DISABLED, WASNT VERY USEFULL + ''' + if PREF_NOR_WEIGHT>0: + # Get the normal and flipm reuse flipvec + flipvec[:]= pv.no + flipvec.x= -flipvec.x + try: + ang= Mathutils.AngleBetweenVecs(nv.no, flipvec)/180.0 + except: # on rare occasions angle between vecs will fail.- zero length vec. + ang= 0 + + l=l*(1+(ang*PREF_NOR_WEIGHT)) + ''' + # Record the pairs for sorting to see who will get joined + mirror_pairs.append((l, nv, pv)) + + # Update every 20 loops + if i1 % 10 == 0: + Window.DrawProgressBar(0.8 * (i1/len_neg_vts), 'Mirror verts %i of %i' % (i1, len_neg_vts)) + + Window.DrawProgressBar(0.9, 'Mirror verts: Updating locations') + + # Now we have a list of the pairs we might use, lets find the best and do them first. + # de-selecting as we go. so we can makke sure not to mess it up. + try: mirror_pairs.sort(key = lambda a: a[0]) + except: mirror_pairs.sort(lambda a,b: cmp(a[0], b[0])) + + for dist, v1,v2 in mirror_pairs: # dist, neg, pos + if v1.sel and v2.sel: + if PREF_MODE==0: # Middle + flipvec[:]= v2.co # positive + flipvec.x= -flipvec.x # negatve + v2.co= v1.co= (flipvec+v1.co)*0.5 # midway + v2.co.x= -v2.co.x + elif PREF_MODE==2: # Left + v2.co= v1.co + v2.co.x= -v2.co.x + elif PREF_MODE==1: # Right + v1.co= v2.co + v1.co.x= -v1.co.x + v1.sel= v2.sel= 0 + + + #*Mirror Weights**********************************************************# + if PREF_MIRROR_WEIGHTS: + + groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) + mirror_pairs_l2r= [] # Stor a list of matches for these verts. + mirror_pairs_r2l= [] # Stor a list of matches for these verts. + + # allign the negative with the positive. + flipvec= Mathutils.Vector() + len_neg_vts= float(len(neg_vts)) + + # Here we make a tuple to look through, if were middle well need to look through both. + if PREF_MODE==0: # Middle + find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), (pos_vts, neg_vts, mirror_pairs_r2l)) + elif PREF_MODE==1: # Left + find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), ) + elif PREF_MODE==2: # Right + find_set= ((pos_vts, neg_vts, mirror_pairs_r2l), ) + + + # Do a locational lookup again :/ - This isnt that good form but if we havnt mirrored weights well need to do it anyway. + # The Difference with this is that we dont need to have 1:1 match for each vert- just get each vert to find another mirrored vert + # and use its weight. + # Use "find_set" so we can do a flipped search L>R and R>L without duplicate code. + for vtls_A, vtls_B, pair_ls in find_set: + for i1, vA in enumerate(vtls_A): + best_len=1<<30 # BIGNUM + best_idx=-1 + + # Find the BEST match + vA_co= vA.co + for i2, vB in enumerate(vtls_B): + # Enforce edge users. + if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]: + flipvec[:]= vB.co + flipvec.x= -flipvec.x + l= (vA_co-flipvec).length + + if l Right', PREF_MODE_L2R, 'Copy from the Left to Right of the mesh. Enable Both for a mid loc/weight.'),\ + ('Right > Left', PREF_MODE_R2L, 'Copy from the Right to Left of the mesh. Enable Both for a mid loc/weight.'),\ + '',\ + ('MaxDist:', PREF_MAX_DIST, 0.0, 1.0, 'Generate interpolated verts so closer vert weights can be copied.'),\ + ('XZero limit:', PREF_XZERO_THRESH, 0.0, 1.0, 'Mirror verts above this distance from the middle, else lock to X/zero.'),\ + ('Sel Verts Only', PREF_SEL_ONLY, 'Only mirror selected verts. Else try and mirror all'),\ + ('Edge Users', PREF_EDGE_USERS, 'Only match up verts that have the same number of edge users.'),\ + 'Location Prefs',\ + ('Mirror Location', PREF_MIRROR_LOCATION, 'Mirror vertex locations.'),\ + ('XMidSnap Verts', PREF_XMID_SNAP, 'Snap middle verts to X Zero (uses XZero limit)'),\ + 'Weight Prefs',\ + ('Mirror Weights', PREF_MIRROR_WEIGHTS, 'Mirror vertex locations.'),\ + ('Flip Groups', PREF_FLIP_NAMES, 'Mirror flip names.'),\ + ('New Flip Groups', PREF_CREATE_FLIP_NAMES, 'Make new groups for flipped names.'),\ + ] + + if not Draw.PupBlock("X Mirror mesh tool", pup_block): + return + + # WORK OUT THE MODE 0 + # PREF_MODE, 0:middle, 1: Left. 2:Right. + PREF_MODE_R2L= PREF_MODE_R2L.val + PREF_MODE_L2R= PREF_MODE_L2R.val + + if PREF_MODE_R2L and PREF_MODE_L2R: + PREF_MODE= 0 # Middle + elif not PREF_MODE_R2L and PREF_MODE_L2R: + PREF_MODE= 1 # Left to Right + elif PREF_MODE_R2L and not PREF_MODE_L2R: + PREF_MODE= 2 # Right to Left + else: # Neither Selected. Do middle anyway + PREF_MODE= 0 + + + PREF_EDITMESH_ONLY= PREF_EDITMESH_ONLY.val + PREF_MIRROR_LOCATION= PREF_MIRROR_LOCATION.val + PREF_XMID_SNAP= PREF_XMID_SNAP.val + PREF_MAX_DIST= PREF_MAX_DIST.val + PREF_XZERO_THRESH= PREF_XZERO_THRESH.val + PREF_SEL_ONLY= PREF_SEL_ONLY.val + PREF_EDGE_USERS= PREF_EDGE_USERS.val + # weights + PREF_MIRROR_WEIGHTS= PREF_MIRROR_WEIGHTS.val + PREF_FLIP_NAMES= PREF_FLIP_NAMES.val + PREF_CREATE_FLIP_NAMES= PREF_CREATE_FLIP_NAMES.val + + t= sys.time() + + is_editmode = Window.EditMode() # Exit Editmode. + if is_editmode: Window.EditMode(0) + Mesh.Mode(Mesh.SelectModes['VERTEX']) + Window.WaitCursor(1) + + if act_ob: + mesh_mirror(act_ob.getData(mesh=1), PREF_MIRROR_LOCATION, PREF_XMID_SNAP, PREF_MAX_DIST, PREF_XZERO_THRESH, PREF_MODE, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES) + if (not PREF_EDITMESH_ONLY) and sel: + for ob in sel: + mesh_mirror(ob.getData(mesh=1), PREF_MIRROR_LOCATION, PREF_XMID_SNAP, PREF_MAX_DIST, PREF_XZERO_THRESH, PREF_MODE, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES) + + if is_editmode: Window.EditMode(1) + Window.WaitCursor(0) + Window.DrawProgressBar(1.0, '') + Window.RedrawAll() + + print 'Mirror done in %.6f sec.' % (sys.time()-t) + +if __name__ == '__main__': + main() diff --git a/release/scripts/mesh_poly_reduce.py b/release/scripts/mesh_poly_reduce.py new file mode 100644 index 00000000000..9d8bb61f652 --- /dev/null +++ b/release/scripts/mesh_poly_reduce.py @@ -0,0 +1,143 @@ +#!BPY +""" +Name: 'Poly Reducer' +Blender: 243 +Group: 'Mesh' +Tooltip: 'Removed polygons from a mesh while maintaining the shape, textures and weights.' +""" + +__author__ = "Campbell Barton" +__url__ = ("blender", "elysiun") +__version__ = "1.0 2006/02/07" + +__bpydoc__ = """\ +This script simplifies the mesh by removing faces, keeping the overall shape of the mesh. +""" + +from Blender import Draw, Window, Scene, Mesh, Mathutils, sys, Object +import BPyMesh +# reload(BPyMesh) +import BPyMessages + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell J Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + + +def main(): + scn = Scene.GetCurrent() + act_ob= scn.objects.active + if not act_ob or act_ob.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + act_me= act_ob.getData(mesh=1) + + if act_me.multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + act_group= act_me.activeGroup + if not act_group: act_group= '' + + + # Defaults + PREF_REDUX= Draw.Create(0.5) + PREF_BOUNDRY_WEIGHT= Draw.Create(5.0) + PREF_REM_DOUBLES= Draw.Create(1) + PREF_FACE_AREA_WEIGHT= Draw.Create(1.0) + PREF_FACE_TRIANGULATE= Draw.Create(1) + + VGROUP_INF_ENABLE= Draw.Create(0) + VGROUP_INF_REDUX= Draw.Create(act_group) + VGROUP_INF_WEIGHT= Draw.Create(10.0) + + PREF_DO_UV= Draw.Create(1) + PREF_DO_VCOL= Draw.Create(1) + PREF_DO_WEIGHTS= Draw.Create(1) + PREF_OTHER_SEL_OBS= Draw.Create(0) + + pup_block = [\ + ('Poly Reduce:', PREF_REDUX, 0.05, 0.95, 'Scale the meshes poly count by this value.'),\ + ('Boundry Weight:', PREF_BOUNDRY_WEIGHT, 0.0, 20.0, 'Weight boundry verts by this scale, 0.0 for no boundry weighting.'),\ + ('Area Weight:', PREF_FACE_AREA_WEIGHT, 0.0, 20.0, 'Collapse edges effecting lower area faces first.'),\ + ('Triangulate', PREF_FACE_TRIANGULATE, 'Convert quads to tris before reduction, for more choices of edges to collapse.'),\ + '',\ + ('VGroup Weighting', VGROUP_INF_ENABLE, 'Use a vertex group to influence the reduction, higher weights for higher quality '),\ + ('vgroup name: ', VGROUP_INF_REDUX, 0, 32, 'The name of the vertex group to use for the weight map'),\ + ('vgroup mult: ', VGROUP_INF_WEIGHT, 0.0, 100.0, 'How much to make the weight effect the reduction'),\ + ('Other Selected Obs', PREF_OTHER_SEL_OBS, 'reduce other selected objects.'),\ + '',\ + '',\ + '',\ + ('UV Coords', PREF_DO_UV, 'Interpolate UV Coords.'),\ + ('Vert Colors', PREF_DO_VCOL, 'Interpolate Vertex Colors'),\ + ('Vert Weights', PREF_DO_WEIGHTS, 'Interpolate Vertex Weights'),\ + ('Remove Doubles', PREF_REM_DOUBLES, 'Remove doubles before reducing to avoid boundry tearing.'),\ + ] + + if not Draw.PupBlock("Poly Reducer", pup_block): + return + + PREF_REDUX= PREF_REDUX.val + PREF_BOUNDRY_WEIGHT= PREF_BOUNDRY_WEIGHT.val + PREF_REM_DOUBLES= PREF_REM_DOUBLES.val + PREF_FACE_AREA_WEIGHT= PREF_FACE_AREA_WEIGHT.val + PREF_FACE_TRIANGULATE= PREF_FACE_TRIANGULATE.val + + VGROUP_INF_ENABLE= VGROUP_INF_ENABLE.val + VGROUP_INF_WEIGHT= VGROUP_INF_WEIGHT.val + + if VGROUP_INF_ENABLE and VGROUP_INF_WEIGHT: + VGROUP_INF_REDUX= VGROUP_INF_REDUX.val + else: + VGROUP_INF_WEIGHT= 0.0 + VGROUP_INF_REDUX= None + + + PREF_DO_UV= PREF_DO_UV.val + PREF_DO_VCOL= PREF_DO_VCOL.val + PREF_DO_WEIGHTS= PREF_DO_WEIGHTS.val + PREF_OTHER_SEL_OBS= PREF_OTHER_SEL_OBS.val + + + t= sys.time() + + is_editmode = Window.EditMode() # Exit Editmode. + if is_editmode: Window.EditMode(0) + Window.WaitCursor(1) + print 'reducing:', act_ob.name, act_ob.getData(1) + BPyMesh.redux(act_ob, PREF_REDUX, PREF_BOUNDRY_WEIGHT, PREF_REM_DOUBLES, PREF_FACE_AREA_WEIGHT, PREF_FACE_TRIANGULATE, PREF_DO_UV, PREF_DO_VCOL, PREF_DO_WEIGHTS, VGROUP_INF_REDUX, VGROUP_INF_WEIGHT) + + if PREF_OTHER_SEL_OBS: + for ob in scn.objects.context: + if ob.type == 'Mesh' and ob != act_ob: + print 'reducing:', ob.name, ob.getData(1) + BPyMesh.redux(ob, PREF_REDUX, PREF_BOUNDRY_WEIGHT, PREF_REM_DOUBLES, PREF_FACE_AREA_WEIGHT, PREF_FACE_TRIANGULATE, PREF_DO_UV, PREF_DO_VCOL, PREF_DO_WEIGHTS, VGROUP_INF_REDUX, VGROUP_INF_WEIGHT) + Window.RedrawAll() + + if is_editmode: Window.EditMode(1) + Window.WaitCursor(0) + Window.RedrawAll() + + print 'Reduction done in %.6f sec.' % (sys.time()-t) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/mesh_skin.py b/release/scripts/mesh_skin.py new file mode 100644 index 00000000000..fdb721bc9f3 --- /dev/null +++ b/release/scripts/mesh_skin.py @@ -0,0 +1,639 @@ +#!BPY + +""" +Name: 'Skin Faces/Edge-Loops' +Blender: 243 +Group: 'MeshFaceKey' +Tooltip: 'Select 2 vert loops, then run this script.' +""" + +__author__ = "Campbell Barton AKA Ideasman" +__url__ = ["blenderartists.org", "www.blender.org"] +__version__ = "1.1 2006/12/26" + +__bpydoc__ = """\ +With this script vertex loops can be skinned: faces are created to connect the +selected loops of vertices. + +Usage: + +In mesh Edit mode select the vertices of the loops (closed paths / curves of +vertices: circles, for example) that should be skinned, then run this script. +A pop-up will provide further options, if the results of a method are not adequate try one of the others. +""" + + +# $Id$ +# +# -------------------------------------------------------------------------- +# Skin Selected edges 1.0 By Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +# Made by Ideasman/Campbell 2005/06/15 - cbarton@metavr.com + +import Blender +import bpy +from Blender import Window +from Blender.Mathutils import MidpointVecs, Vector, CrossVecs +from Blender.Mathutils import AngleBetweenVecs as _AngleBetweenVecs_ +import BPyMessages + +from Blender.Draw import PupMenu + +BIG_NUM = 1<<30 + +global CULL_METHOD +CULL_METHOD = 0 + +def AngleBetweenVecs(a1,a2): + try: + return _AngleBetweenVecs_(a1,a2) + except: + return 180.0 + +class edge(object): + __slots__ = 'v1', 'v2', 'co1', 'co2', 'length', 'removed', 'match', 'cent', 'angle', 'next', 'prev', 'normal', 'fake' + def __init__(self, v1,v2): + self.v1 = v1 + self.v2 = v2 + co1, co2= v1.co, v2.co + self.co1= co1 + self.co2= co2 + + # uv1 uv2 vcol1 vcol2 # Add later + self.length = (co1 - co2).length + self.removed = 0 # Have we been culled from the eloop + self.match = None # The other edge were making a face with + + self.cent= MidpointVecs(co1, co2) + self.angle= 0.0 + self.fake= False + +class edgeLoop(object): + __slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges' + def __init__(self, loop, me, closed): # Vert loop + # Use next and prev, nextDist, prevDist + + # Get Loops centre. + fac= len(loop) + verts = me.verts + self.centre= reduce(lambda a,b: a+verts[b].co/fac, loop, Vector()) + + # Convert Vert loop to Edges. + self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop))] + + if not closed: + self.edges[0].fake = True # fake edge option + + self.closed = closed + + + # Assign linked list + for eIdx in xrange(len(self.edges)-1): + self.edges[eIdx].next = self.edges[eIdx+1] + self.edges[eIdx].prev = self.edges[eIdx-1] + # Now last + self.edges[-1].next = self.edges[0] + self.edges[-1].prev = self.edges[-2] + + + + # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP. + self.normal = Vector() + for e in self.edges: + n = CrossVecs(self.centre-e.co1, self.centre-e.co2) + # Do we realy need tot normalize? + n.normalize() + self.normal += n + + # Generate the angle + va= e.cent - e.prev.cent + vb= e.next.cent - e.cent + + e.angle= AngleBetweenVecs(va, vb) + + # Blur the angles + #for e in self.edges: + # e.angle= (e.angle+e.next.angle)/2 + + # Blur the angles + #for e in self.edges: + # e.angle= (e.angle+e.prev.angle)/2 + + self.normal.normalize() + + # Generate a normal for each edge. + for e in self.edges: + + n1 = e.co1 + n2 = e.co2 + n3 = e.prev.co1 + + a = n1-n2 + b = n1-n3 + normal1 = CrossVecs(a,b) + normal1.normalize() + + n1 = e.co2 + n3 = e.next.co2 + n2 = e.co1 + + a = n1-n2 + b = n1-n3 + + normal2 = CrossVecs(a,b) + normal2.normalize() + + # Reuse normal1 var + normal1 += normal1 + normal2 + normal1.normalize() + + e.normal = normal1 + #print e.normal + + + + def backup(self): + # Keep a backup of the edges + self.backup_edges = self.edges[:] + + def restore(self): + self.edges = self.backup_edges[:] + for e in self.edges: + e.removed = 0 + + def reverse(self): + self.edges.reverse() + self.normal.negate() + + for e in self.edges: + e.normal.negate() + e.v1, e.v2 = e.v2, e.v1 + e.co1, e.co2 = e.co2, e.co1 + e.next, e.prev = e.prev, e.next + + + def removeSmallest(self, cullNum, otherLoopLen): + ''' + Removes N Smallest edges and backs up the loop, + this is so we can loop between 2 loops as if they are the same length, + backing up and restoring incase the loop needs to be skinned with another loop of a different length. + ''' + global CULL_METHOD + if CULL_METHOD == 1: # Shortest edge + eloopCopy = self.edges[:] + + # Length sort, smallest first + try: eloopCopy.sort(key = lambda e1: e1.length) + except: eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length )) + + # Dont use atm + #eloopCopy.sort(lambda e1, e2: cmp(e1.angle*e1.length, e2.angle*e2.length)) # Length sort, smallest first + #eloopCopy.sort(lambda e1, e2: cmp(e1.angle, e2.angle)) # Length sort, smallest first + + remNum = 0 + for i, e in enumerate(eloopCopy): + if not e.fake: + e.removed = 1 + self.edges.remove( e ) # Remove from own list, still in linked list. + remNum += 1 + + if not remNum < cullNum: + break + + else: # CULL METHOD is even + + culled = 0 + + step = int(otherLoopLen / float(cullNum)) * 2 + + currentEdge = self.edges[0] + while culled < cullNum: + + # Get the shortest face in the next STEP + step_count= 0 + bestAng= 360.0 + smallestEdge= None + while step_count<=step or smallestEdge==None: + step_count+=1 + if not currentEdge.removed: # 0 or -1 will not be accepted + if currentEdge.angle 2: + return None + + vert_used[i] = True + + # do an edgeloop seek + if len(sbl) == 2: + contextVertLoop= [sbl[0], i, sbl[1]] # start the vert loop + vert_used[contextVertLoop[ 0]] = True + vert_used[contextVertLoop[-1]] = True + else: + contextVertLoop= [i, sbl[0]] + vert_used[contextVertLoop[ 1]] = True + + # Always seek up + ok = True + while ok: + ok = False + closed = False + sbl = vert_siblings[contextVertLoop[-1]] + if len(sbl) == 2: + next = sbl[not sbl.index( contextVertLoop[-2] )] + if vert_used[next]: + closed = True + # break + else: + contextVertLoop.append( next ) # get the vert that isnt the second last + vert_used[next] = True + ok = True + + # Seek down as long as the starting vert was not at the edge. + if not closed and len(vert_siblings[i]) == 2: + + ok = True + while ok: + ok = False + sbl = vert_siblings[contextVertLoop[0]] + if len(sbl) == 2: + next = sbl[not sbl.index( contextVertLoop[1] )] + if vert_used[next]: + closed = True + else: + contextVertLoop.insert(0, next) # get the vert that isnt the second last + vert_used[next] = True + ok = True + + mainVertLoops.append((contextVertLoop, closed)) + + + verts = me.verts + # convert from indicies to verts + # mainVertLoops = [([verts[i] for i in contextVertLoop], closed) for contextVertLoop, closed in mainVertLoops] + # print len(mainVertLoops) + return mainVertLoops + + + +def skin2EdgeLoops(eloop1, eloop2, me, ob, MODE): + + new_faces= [] # + + # Make sure e1 loops is bigger then e2 + if len(eloop1.edges) != len(eloop2.edges): + if len(eloop1.edges) < len(eloop2.edges): + eloop1, eloop2 = eloop2, eloop1 + + eloop1.backup() # were about to cull faces + CULL_FACES = len(eloop1.edges) - len(eloop2.edges) + eloop1.removeSmallest(CULL_FACES, len(eloop1.edges)) + else: + CULL_FACES = 0 + # First make sure poly vert loops are in sync with eachother. + + # The vector allong which we are skinning. + skinVector = eloop1.centre - eloop2.centre + + loopDist = skinVector.length + + # IS THE LOOP FLIPPED, IF SO FLIP BACK. we keep it flipped, its ok, + if eloop1.closed or eloop2.closed: + angleBetweenLoopNormals = AngleBetweenVecs(eloop1.normal, eloop2.normal) + if angleBetweenLoopNormals > 90: + eloop2.reverse() + + + DIR= eloop1.centre - eloop2.centre + + # if eloop2.closed: + bestEloopDist = BIG_NUM + bestOffset = 0 + # Loop rotation offset to test.1 + eLoopIdxs = range(len(eloop1.edges)) + for offset in xrange(len(eloop1.edges)): + totEloopDist = 0 # Measure this total distance for thsi loop. + + offsetIndexLs = eLoopIdxs[offset:] + eLoopIdxs[:offset] # Make offset index list + + + # e1Idx is always from 0uu to N, e2Idx is offset. + for e1Idx, e2Idx in enumerate(offsetIndexLs): + e1= eloop1.edges[e1Idx] + e2= eloop2.edges[e2Idx] + + + # Include fan connections in the measurement. + OK= True + while OK or e1.removed: + OK= False + + # Measure the vloop distance =============== + diff= ((e1.cent - e2.cent).length) #/ nangle1 + + ed_dir= e1.cent-e2.cent + a_diff= AngleBetweenVecs(DIR, ed_dir)/18 # 0 t0 18 + + totEloopDist += (diff * (1+a_diff)) / (1+loopDist) + + # Premeture break if where no better off + if totEloopDist > bestEloopDist: + break + + e1=e1.next + + if totEloopDist < bestEloopDist: + bestOffset = offset + bestEloopDist = totEloopDist + + # Modify V2 LS for Best offset + eloop2.edges = eloop2.edges[bestOffset:] + eloop2.edges[:bestOffset] + + else: + # Both are open loops, easier to calculate. + + + # Make sure the fake edges are at the start. + for i, edloop in enumerate((eloop1, eloop2)): + # print "LOOPO" + if edloop.edges[0].fake: + # alredy at the start + #print "A" + pass + elif edloop.edges[-1].fake: + # put the end at the start + edloop.edges.insert(0, edloop.edges.pop()) + #print "B" + + else: + for j, ed in enumerate(edloop.edges): + if ed.fake: + #print "C" + edloop.edges = edloop.edges = edloop.edges[j:] + edloop.edges[:j] + break + # print "DONE" + ed1, ed2 = eloop1.edges[0], eloop2.edges[0] + + if not ed1.fake or not ed2.fake: + raise "Error" + + # Find the join that isnt flipped (juts like detecting a bow-tie face) + a1 = (ed1.co1 - ed2.co1).length + (ed1.co2 - ed2.co2).length + a2 = (ed1.co1 - ed2.co2).length + (ed1.co2 - ed2.co1).length + + if a1 > a2: + eloop2.reverse() + # make the first edge the start edge still + eloop2.edges.insert(0, eloop2.edges.pop()) + + + + + for loopIdx in xrange(len(eloop2.edges)): + e1 = eloop1.edges[loopIdx] + e2 = eloop2.edges[loopIdx] + + # Remember the pairs for fan filling culled edges. + e1.match = e2; e2.match = e1 + + if not (e1.fake or e2.fake): + new_faces.append([e1.v1, e1.v2, e2.v2, e2.v1]) + + # FAN FILL MISSING FACES. + if CULL_FACES: + # Culled edges will be in eloop1. + FAN_FILLED_FACES = 0 + + contextEdge = eloop1.edges[0] # The larger of teh 2 + while FAN_FILLED_FACES < CULL_FACES: + while contextEdge.next.removed == 0: + contextEdge = contextEdge.next + + vertFanPivot = contextEdge.match.v2 + + while contextEdge.next.removed == 1: + #if not contextEdge.next.fake: + new_faces.append([contextEdge.next.v1, contextEdge.next.v2, vertFanPivot]) + + # Should we use another var?, this will work for now. + contextEdge.next.removed = 1 + + contextEdge = contextEdge.next + FAN_FILLED_FACES += 1 + + # may need to fan fill backwards 1 for non closed loops. + + eloop1.restore() # Add culled back into the list. + + return new_faces + +def main(): + global CULL_METHOD + + is_editmode = Window.EditMode() + if is_editmode: Window.EditMode(0) + ob = bpy.data.scenes.active.objects.active + if ob == None or ob.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + me = ob.getData(mesh=1) + + if me.multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + time1 = Blender.sys.time() + selEdges = getSelectedEdges(me, ob) + vertLoops = getVertLoops(selEdges, me) # list of lists of edges. + if vertLoops == None: + PupMenu('Error%t|Selection includes verts that are a part of more then 1 loop') + if is_editmode: Window.EditMode(1) + return + # print len(vertLoops) + + + if len(vertLoops) > 2: + choice = PupMenu('Loft '+str(len(vertLoops))+' edge loops%t|loop|segment') + if choice == -1: + if is_editmode: Window.EditMode(1) + return + elif len(vertLoops) < 2: + PupMenu('Error%t|No Vertloops found!') + if is_editmode: Window.EditMode(1) + return + else: + choice = 2 + + + # The line below checks if any of the vert loops are differenyt in length. + if False in [len(v[0]) == len(vertLoops[0][0]) for v in vertLoops]: + CULL_METHOD = PupMenu('Small to large edge loop distrobution method%t|remove edges evenly|remove smallest edges') + if CULL_METHOD == -1: + if is_editmode: Window.EditMode(1) + return + + if CULL_METHOD ==1: # RESET CULL_METHOD + CULL_METHOD = 0 # shortest + else: + CULL_METHOD = 1 # even + + + time1 = Blender.sys.time() + # Convert to special edge data. + edgeLoops = [] + for vloop, closed in vertLoops: + edgeLoops.append(edgeLoop(vloop, me, closed)) + + + # VERT LOOP ORDERING CODE + # "Build a worm" list - grow from Both ends + edgeOrderedList = [edgeLoops.pop()] + + # Find the closest. + bestSoFar = BIG_NUM + bestIdxSoFar = None + for edLoopIdx, edLoop in enumerate(edgeLoops): + l =(edgeOrderedList[-1].centre - edLoop.centre).length + if l < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l + + edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) + + # Now we have the 2 closest, append to either end- + # Find the closest. + while edgeLoops: + bestSoFar = BIG_NUM + bestIdxSoFar = None + first_or_last = 0 # Zero is first + for edLoopIdx, edLoop in enumerate(edgeLoops): + l1 =(edgeOrderedList[-1].centre - edLoop.centre).length + + if l1 < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l1 + first_or_last = 1 # last + + l2 =(edgeOrderedList[0].centre - edLoop.centre).length + if l2 < bestSoFar: + bestIdxSoFar = edLoopIdx + bestSoFar = l2 + first_or_last = 0 # last + + if first_or_last: # add closest Last + edgeOrderedList.append( edgeLoops.pop(bestIdxSoFar) ) + else: # Add closest First + edgeOrderedList.insert(0, edgeLoops.pop(bestIdxSoFar) ) # First + + faces = [] + + for i in xrange(len(edgeOrderedList)-1): + faces.extend( skin2EdgeLoops(edgeOrderedList[i], edgeOrderedList[i+1], me, ob, 0) ) + if choice == 1 and len(edgeOrderedList) > 2: # Loop + faces.extend( skin2EdgeLoops(edgeOrderedList[0], edgeOrderedList[-1], me, ob, 0) ) + + # REMOVE SELECTED FACES. + MESH_MODE= Blender.Mesh.Mode() + if MESH_MODE & Blender.Mesh.SelectModes.EDGE or MESH_MODE & Blender.Mesh.SelectModes.VERTEX: pass + elif MESH_MODE & Blender.Mesh.SelectModes.FACE: + try: me.faces.delete(1, [ f for f in me.faces if f.sel ]) + except: pass + + me.faces.extend(faces) + + print '\nSkin done in %.4f sec.' % (Blender.sys.time()-time1) + + + if is_editmode: Window.EditMode(1) + +if __name__ == '__main__': + main() diff --git a/release/scripts/mesh_solidify.py b/release/scripts/mesh_solidify.py new file mode 100644 index 00000000000..9e11ed68c63 --- /dev/null +++ b/release/scripts/mesh_solidify.py @@ -0,0 +1,345 @@ +#!BPY +""" +Name: 'Solidify Selection' +Blender: 243 +Group: 'Mesh' +Tooltip: 'Makes the mesh solid by creating a second skin.' +""" + +__author__ = "Campbell Barton" +__url__ = ("www.blender.org", "blenderartists.org") +__version__ = "1.1" + +__bpydoc__ = """\ +This script makes a skin from the selected faces. +Optionaly you can skin between the original and new faces to make a watertight solid object +""" + +# -------------------------------------------------------------------------- +# Solidify Selection 1.0 by Campbell Barton (AKA Ideasman42) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +from Blender import * +import bpy +import BPyMesh +# reload(BPyMesh) +import BPyMessages +# reload(BPyMessages) + +from BPyMathutils import angleToLength + +# python 2.3 has no reversed() iterator. this will only work on lists and tuples +try: + reversed +except: + def reversed(l): return l[::-1] + +def copy_facedata_multilayer(me, from_faces, to_faces): + ''' + Tkes 2 lists of faces and copies multilayer data from 1 to another + make sure they are aligned, cant copy from a quad to a tri, used for solidify selection. + ''' + + def copy_default_face(data): + face_from, face_to = data + face_to.mat = face_from.mat + face_to.smooth = face_from.smooth + face_to.sel = True + face_from.sel = False + + def copy_tex_face(data): + face_from, face_to = data + face_to.uv = [c for c in reversed(face_from.uv)] + face_to.mode = face_from.mode + face_to.flag = face_from.flag + face_to.image = face_from.image + + def copy_col_face(data): + face_from, face_to = data + face_to.col = [c for c in reversed(face_from.col)] + + # make a list of face_from, face_to pairs + #face_pairs = zip(faces_sel, [me_faces[len_faces + i] for i in xrange(len(faces_sel))]) + face_pairs = zip(from_faces, to_faces) + + # Copy properties from 1 set of faces to another. + map(copy_default_face, face_pairs) + + for uvlayer in me.getUVLayerNames(): + me.activeUVLayer = uvlayer + map(copy_tex_face, face_pairs) + + for collayer in me.getColorLayerNames(): + me.activeColorLayer = collayer + map(copy_col_face, face_pairs) + + # Now add quads between if we wants + + +Ang= Mathutils.AngleBetweenVecs +SMALL_NUM=0.00001 + +def solidify(me, PREF_THICK, PREF_SKIN_SIDES=True, PREF_REM_ORIG=False, PREF_COLLAPSE_SIDES=False): + + # Main code function + me_faces = me.faces + faces_sel= [f for f in me_faces if f.sel] + + BPyMesh.meshCalcNormals(me) + normals= [v.no for v in me.verts] + vertFaces= [[] for i in xrange(len(me.verts))] + for f in me_faces: + no=f.no + for v in f: + vertFaces[v.index].append(no) + + # Scale the normals by the face angles from the vertex Normals. + for i in xrange(len(me.verts)): + length=0.0 + if vertFaces[i]: + for fno in vertFaces[i]: + try: + a= Ang(fno, normals[i]) + except: + a= 0 + if a>=90: + length+=1 + elif a < SMALL_NUM: + length+= 1 + else: + length+= angleToLength(a) + + length= length/len(vertFaces[i]) + #print 'LENGTH %.6f' % length + # normals[i]= (normals[i] * length) * PREF_THICK + normals[i] *= length * PREF_THICK + + + + len_verts = len( me.verts ) + len_faces = len( me_faces ) + + vert_mapping= [-1] * len(me.verts) + verts= [] + for f in faces_sel: + for v in f: + i= v.index + if vert_mapping[i]==-1: + vert_mapping[i]= len_verts + len(verts) + verts.append(v.co + normals[i]) + + #verts= [v.co + normals[v.index] for v in me.verts] + + me.verts.extend( verts ) + #faces= [tuple([ me.verts[v.index+len_verts] for v in reversed(f.v)]) for f in me_faces ] + faces= [ tuple([vert_mapping[v.index] for v in reversed(f.v)]) for f in faces_sel ] + me_faces.extend( faces ) + + + + + # Old method before multi UVs + """ + has_uv = me.faceUV + has_vcol = me.vertexColors + for i, orig_f in enumerate(faces_sel): + new_f= me_faces[len_faces + i] + new_f.mat = orig_f.mat + new_f.smooth = orig_f.smooth + orig_f.sel=False + new_f.sel= True + new_f = me_faces[i+len_faces] + if has_uv: + new_f.uv = [c for c in reversed(orig_f.uv)] + new_f.mode = orig_f.mode + new_f.flag = orig_f.flag + if orig_f.image: + new_f.image = orig_f.image + if has_vcol: + new_f.col = [c for c in reversed(orig_f.col)] + """ + copy_facedata_multilayer(me, faces_sel, [me_faces[len_faces + i] for i in xrange(len(faces_sel))]) + + if PREF_SKIN_SIDES or PREF_COLLAPSE_SIDES: + skin_side_faces= [] + skin_side_faces_orig= [] + # Get edges of faces that only have 1 user - so we can make walls + edges = {} + + # So we can reference indicies that wrap back to the start. + ROT_TRI_INDEX = 0,1,2,0 + ROT_QUAD_INDEX = 0,1,2,3,0 + + for f in faces_sel: + f_v= f.v + for i, edgekey in enumerate(f.edge_keys): + if edges.has_key(edgekey): + edges[edgekey]= None + else: + if len(f_v) == 3: + edges[edgekey] = f, f_v, i, ROT_TRI_INDEX[i+1] + else: + edges[edgekey] = f, f_v, i, ROT_QUAD_INDEX[i+1] + del ROT_QUAD_INDEX, ROT_TRI_INDEX + + # So we can remove doubles with edges only. + if PREF_COLLAPSE_SIDES: + me.sel = False + + # Edges are done. extrude the single user edges. + for edge_face_data in edges.itervalues(): + if edge_face_data: # != None + f, f_v, i1, i2 = edge_face_data + v1i,v2i= f_v[i1].index, f_v[i2].index + + if PREF_COLLAPSE_SIDES: + # Collapse + cv1 = me.verts[v1i] + cv2 = me.verts[vert_mapping[v1i]] + + cv3 = me.verts[v2i] + cv4 = me.verts[vert_mapping[v2i]] + + cv1.co = cv2.co = (cv1.co+cv2.co)/2 + cv3.co = cv4.co = (cv3.co+cv4.co)/2 + + cv1.sel=cv2.sel=cv3.sel=cv4.sel=True + + + + else: + # Now make a new Face + # skin_side_faces.append( (v1i, v2i, vert_mapping[v2i], vert_mapping[v1i]) ) + skin_side_faces.append( (v2i, v1i, vert_mapping[v1i], vert_mapping[v2i]) ) + skin_side_faces_orig.append((f, len(me_faces) + len(skin_side_faces_orig), i1, i2)) + + if PREF_COLLAPSE_SIDES: + me.remDoubles(0.0001) + else: + me_faces.extend(skin_side_faces) + # Now assign properties. + """ + # Before MultiUVs + for i, origfData in enumerate(skin_side_faces_orig): + orig_f, new_f_idx, i1, i2 = origfData + new_f= me_faces[new_f_idx] + + new_f.mat= orig_f.mat + new_f.smooth= orig_f.smooth + if has_uv: + new_f.mode= orig_f.mode + new_f.flag= orig_f.flag + if orig_f.image: + new_f.image= orig_f.image + + uv1= orig_f.uv[i1] + uv2= orig_f.uv[i2] + new_f.uv= (uv1, uv2, uv2, uv1) + + if has_vcol: + col1= orig_f.col[i1] + col2= orig_f.col[i2] + new_f.col= (col1, col2, col2, col1) + """ + + for i, origfData in enumerate(skin_side_faces_orig): + orig_f, new_f_idx, i2, i1 = origfData + new_f= me_faces[new_f_idx] + + new_f.mat= orig_f.mat + new_f.smooth= orig_f.smooth + + for uvlayer in me.getUVLayerNames(): + me.activeUVLayer = uvlayer + for i, origfData in enumerate(skin_side_faces_orig): + orig_f, new_f_idx, i2, i1 = origfData + new_f= me_faces[new_f_idx] + + new_f.mode= orig_f.mode + new_f.flag= orig_f.flag + new_f.image= orig_f.image + + uv1= orig_f.uv[i1] + uv2= orig_f.uv[i2] + new_f.uv= (uv1, uv2, uv2, uv1) + + for collayer in me.getColorLayerNames(): + me.activeColorLayer = collayer + for i, origfData in enumerate(skin_side_faces_orig): + orig_f, new_f_idx, i2, i1 = origfData + new_f= me_faces[new_f_idx] + + col1= orig_f.col[i1] + col2= orig_f.col[i2] + new_f.col= (col1, col2, col2, col1) + + + if PREF_REM_ORIG: + me_faces.delete(0, faces_sel) + + + + +def main(): + scn = bpy.data.scenes.active + ob = scn.objects.active + + if not ob or ob.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + me = ob.getData(mesh=1) + if me.multires: + BPyMessages.Error_NoMeshMultiresEdit() + return + + # Create the variables. + PREF_THICK = Draw.Create(-0.1) + PREF_SKIN_SIDES= Draw.Create(1) + PREF_COLLAPSE_SIDES= Draw.Create(0) + PREF_REM_ORIG= Draw.Create(0) + + pup_block = [\ + ('Thick:', PREF_THICK, -10, 10, 'Skin thickness in mesh space.'),\ + ('Skin Sides', PREF_SKIN_SIDES, 'Skin between the original and new faces.'),\ + ('Collapse Sides', PREF_COLLAPSE_SIDES, 'Skin between the original and new faces.'),\ + ('Remove Original', PREF_REM_ORIG, 'Remove the selected faces after skinning.'),\ + ] + + if not Draw.PupBlock('Solid Skin Selection', pup_block): + return + + is_editmode = Window.EditMode() + if is_editmode: Window.EditMode(0) + + Window.WaitCursor(1) + + me = ob.getData(mesh=1) + solidify(me, PREF_THICK.val, PREF_SKIN_SIDES.val, PREF_REM_ORIG.val, PREF_COLLAPSE_SIDES.val) + + + Window.WaitCursor(0) + if is_editmode: Window.EditMode(1) + + Window.RedrawAll() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/mesh_unfolder.py b/release/scripts/mesh_unfolder.py new file mode 100644 index 00000000000..906e0f0a300 --- /dev/null +++ b/release/scripts/mesh_unfolder.py @@ -0,0 +1,1582 @@ +#!BPY +""" +Name: 'Unfold' +Blender: 245 +Group: 'Mesh' +Tip: 'Unfold meshes to create nets' +Version: v2.5 +Author: Matthew Chadwick +""" +import Blender +from Blender import * +from Blender.Mathutils import * +try: + import sys + import traceback + import math + import re + from math import * + import sys + import random + import xml.sax, xml.sax.handler, xml.sax.saxutils + + # annoying but need so classes dont raise errors + xml_sax_handler_ContentHandler = xml.sax.handler.ContentHandler + +except: + Draw.PupMenu('Error%t|A full python installation is required to run this script.') + xml = None + xml_sax_handler_ContentHandler = type(0) + +__author__ = 'Matthew Chadwick' +__version__ = '2.5 06102007' +__url__ = ["http://celeriac.net/unfolder/", "blender", "blenderartist"] +__email__ = ["post at cele[remove this text]riac.net", "scripts"] +__bpydoc__ = """\ + +Mesh Unfolder + +Unfolds the selected mesh onto a plane to form a net + +Not all meshes can be unfolded + +Meshes must be free of holes, +isolated edges (not part of a face), twisted quads and other rubbish. +Nice clean triangulated meshes unfold best + +This program is free software; you can distribute it and/or modify it under the terms +of the GNU General Public License as published by the Free Software Foundation; version 2 +or later, currently at http://www.gnu.org/copyleft/gpl.html + +The idea came while I was riding a bike. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +# Face lookup +class FacesAndEdges: + def __init__(self, mesh): + self.nfaces = 0 + # straight from the documentation + self.edgeFaces = dict([(edge.key, []) for edge in mesh.edges]) + for face in mesh.faces: + face.sel = False + for key in face.edge_keys: + self.edgeFaces[key].append(face) + def findTakenAdjacentFace(self, bface, edge): + return self.findAdjacentFace(bface, edge) + # find the first untaken (non-selected) adjacent face in the list of adjacent faces for the given edge (allows for manifold meshes too) + def findAdjacentFace(self, bface, edge): + faces = self.edgeFaces[edge.key()] + for i in xrange(len(faces)): + if faces[i] == bface: + j = (i+1) % len(faces) + while(faces[j]!=bface): + if faces[j].sel == False: + return faces[j] + j = (j+1) % len(faces) + return None + def returnFace(self, face): + face.sel = False + self.nfaces-=1 + def facesTaken(self): + return self.nfaces + def takeAdjacentFace(self, bface, edge): + if (edge==None): + return None + face = self.findAdjacentFace(bface, edge) + if(face!=None): + face.sel = True + self.nfaces+=1 + return face + def takeFace(self, bface): + if(bface!=None): + bface.sel= True + self.nfaces+=1 + + +# A fold between two faces with a common edge +class Fold: + ids = -1 + def __init__(self, parent, refPoly, poly, edge, angle=None): + Fold.ids+=1 + self.id = Fold.ids + self.refPoly = refPoly + self.poly = poly + self.srcFace = None + self.desFace = None + self.edge = edge + self.foldedEdge = edge + self.rm = None + self.parent = parent + self.tree = None + if(refPoly!=None): + self.refPolyNormal = refPoly.normal() + self.polyNormal = poly.normal() + if(angle==None): + self.angle = self.calculateAngle() + self.foldingPoly = poly.rotated(edge, self.angle) + else: + self.angle = angle + self.foldingPoly = poly + self.unfoldedEdge = self.edge + self.unfoldedNormal = None + self.animAngle = self.angle + self.cr = None + self.nancestors = None + def reset(self): + self.foldingPoly = self.poly.rotated(self.edge, self.dihedralAngle()) + def getID(self): + return self.id + def getParent(self): + return self.parent + def ancestors(self): + if(self.nancestors==None): + self.nancestors = self.computeAncestors() + return self.nancestors + def computeAncestors(self): + if(self.parent==None): + return 0 + else: + return self.parent.ancestors()+1 + def dihedralAngle(self): + return self.angle + def unfoldTo(self, f): + self.animAngle = self.angle*f + self.foldingPoly = self.poly.rotated(self.edge, self.animAngle) + def calculateAngle(self): + sangle = Mathutils.AngleBetweenVecs(self.refPolyNormal, self.polyNormal) + if(sangle!=sangle): + sangle=0.0 + ncp = Mathutils.CrossVecs(self.refPolyNormal, self.polyNormal) + dp = Mathutils.DotVecs(ncp, self.edge.vector) + if(dp>0.0): + return +sangle + else: + return -sangle + def alignWithParent(self): + pass + def unfoldedNormal(self): + return self.unfoldedNormal + def getEdge(self): + return self.edge + def getFace(self): + return self.poly + def testFace(self): + return Poly.fromVectors([self.edge.v1, self.edge.v2, Vector([0,0,0])]) + def unfoldedFace(self): + return self.foldingPoly + def unfold(self): + if(self.parent!=None): + self.parent.foldFace(self) + def foldFace(self, child): + child.foldingPoly.rotate(self.edge, self.animAngle) + if(self.parent!=None): + self.parent.foldFace(child) + +class Cut(Fold): + pass + +# Trees build folds by traversing the mesh according to a local measure +class Tree: + def __init__(self, net, parent,fold,otherConstructor=None): + self.net = net + self.fold = fold + self.face = fold.srcFace + self.poly = Poly.fromBlenderFace(self.face) + self.generations = net.generations + self.growing = True + self.tooLong = False + self.parent = parent + self.grown = False + if not(otherConstructor): + self.edges = net.edgeIteratorClass(self) + def goodness(self): + return self.edges.goodness() + def compare(self, other): + if(self.goodness() > other.goodness()): + return +1 + else: + return -1 + def isGrowing(self): + return self.growing + def beGrowing(self): + self.growing = True + def grow(self): + self.tooLong = self.fold.ancestors()>self.generations + if(self.edges.hasNext() and self.growing): + edge = self.edges.next() + tface = self.net.facesAndEdges.takeAdjacentFace(self.face, edge) + if(tface!=None): + self.branch(tface, edge) + if(self.parent==None): + self.grow() + else: + self.grown = True + def isGrown(self): + return self.grown + def canGrow(self): + return (self.parent!=None and self.parent.grown) + def getNet(self): + return self.net + def getFold(self): + return self.fold + def getFace(self): + return self.face + def branch(self, tface, edge): + fold = Fold(self.fold, self.poly, Poly.fromBlenderFace(tface), edge) + fold.srcFace = tface + self.net.myFacesVisited+=1 + tree = Tree(self.net, self, fold) + fold.tree = tree + fold.unfold() + overlaps = self.net.checkOverlaps(fold) + nc = len(overlaps) + self.net.overlaps+=nc + if(nc>0 and self.net.avoidsOverlaps): + self.handleOverlap(fold, overlaps) + else: + self.addFace(fold) + def handleOverlap(self, fold, overlaps): + self.net.facesAndEdges.returnFace(fold.srcFace) + self.net.myFacesVisited-=1 + for cfold in overlaps: + ttree = cfold.tree + ttree.growing = True + ttree.grow() + def addFace(self, fold): + ff = fold.unfoldedFace() + fold.desFace = self.net.addFace(ff, fold.srcFace) + self.net.folds.append(fold) + self.net.addBranch(fold.tree) + fold.tree.growing = not(self.tooLong) + if(self.net.diffuse==False): + fold.tree.grow() + +# A Net is the result of the traversal of the mesh by Trees +class Net: + def __init__(self, src, des): + self.src = src + self.des = des + self.firstFace = None + self.firstPoly = None + self.refFold = None + self.edgeIteratorClass = RandomEdgeIterator + if(src!=None): + self.srcFaces = src.faces + self.facesAndEdges = FacesAndEdges(self.src) + self.myFacesVisited = 0 + self.facesAdded = 0 + self.folds = [] + self.cuts = [] + self.branches = [] + self.overlaps = 0 + self.avoidsOverlaps = True + self.frame = 1 + self.ff = 180.0 + self.firstFaceIndex = None + self.trees = 0 + self.foldIPO = None + self.perFoldIPO = None + self.IPOCurves = {} + self.generations = 128 + self.diffuse = True + self.noise = 0.0 + self.grownBranches = 0 + self.assignsUV = True + self.animates = False + self.showProgress = False + self.feedback = None + def setSelectedFaces(self, faces): + self.srcFaces = faces + self.facesAndEdges = FacesAndEdges(self.srcFaces) + def setShowProgress(self, show): + self.showProgress = show + # this method really needs work + def unfold(self): + selectedFaces = [face for face in self.src.faces if (self.src.faceUV and face.sel)] + if(self.avoidsOverlaps): + print "unfolding with overlap detection" + if(self.firstFaceIndex==None): + self.firstFaceIndex = random.randint(0, len(self.src.faces)-1) + else: + print "Using user-selected seed face ", self.firstFaceIndex + self.firstFace = self.src.faces[self.firstFaceIndex] + z = min([v.co.z for v in self.src.verts])-0.1 + ff = Poly.fromBlenderFace(self.firstFace) + if(len(ff.v)<3): + raise Exception("This mesh contains an isolated edge - it must consist only of faces") + testFace = Poly.fromVectors( [ Vector([0.0,0.0,0.0]), Vector([0.0,1.0,0.0]), Vector([1.0,1.0,0.0]) ] ) + # hmmm. I honestly can't remember why this needs to be done, but it does. + u=0 + v=1 + w=2 + if ff.v[u].x==ff.v[u+1].x and ff.v[u].y==ff.v[u+1].y: + u=1 + v=2 + w=0 + # here we make a couple of folds, not part of the net, which serve to get the net into the xy plane + xyFace = Poly.fromList( [ [ff.v[u].x,ff.v[u].y, z] , [ff.v[v].x,ff.v[v].y, z] , [ff.v[w].x+0.1,ff.v[w].y+0.1, z] ] ) + refFace = Poly.fromVectors([ ff.v[u], ff.v[v], xyFace.v[1], xyFace.v[0] ] ) + xyFold = Fold(None, xyFace, refFace, Edge(xyFace.v[0], xyFace.v[1] )) + self.refFold = Fold(xyFold, refFace, ff, Edge(refFace.v[0], refFace.v[1] )) + self.refFold.srcFace = self.firstFace + # prepare to grow the trees + trunk = Tree(self, None, self.refFold) + trunk.generations = self.generations + self.firstPoly = ff + self.facesAndEdges.takeFace(self.firstFace) + self.myFacesVisited+=1 + self.refFold.unfold() + self.refFold.tree = trunk + self.refFold.desFace = self.addFace(self.refFold.unfoldedFace(), self.refFold.srcFace) + self.folds.append(self.refFold) + trunk.grow() + i = 0 + # keep the trees growing while they can + while(self.myFacesVisited 0): + if self.edgeIteratorClass==RandomEdgeIterator: + i = random.randint(0,len(self.branches)-1) + tree = self.branches[i] + if(tree.isGrown()): + self.branches.pop(i) + else: + tree.beGrowing() + if(tree.canGrow()): + tree.grow() + i = 0 + else: + i = (i + 1) % len(self.branches) + if self.src.faceUV: + for face in self.src.faces: + face.sel = False + for face in selectedFaces: + face.sel = True + self.src.update() + Window.RedrawAll() + def assignUVs(self): + for fold in self.folds: + self.assignUV(fold.srcFace, fold.unfoldedFace()) + print " assigned uv to ", len(self.folds), len(self.src.faces) + self.src.update() + def checkOverlaps(self, fold): + #return self.getOverlapsBetween(fold, self.folds) + return self.getOverlapsBetweenGL(fold, self.folds) + def getOverlapsBetween(self, fold, folds): + if(fold.parent==None): + return [] + mf = fold.unfoldedFace() + c = [] + for afold in folds: + mdf = afold.unfoldedFace() + if(afold!=fold): + # currently need to get agreement from both polys because + # a touch by a vertex of one the other's edge is acceptable & + # they disagree on that + intersects = mf.intersects2D(mdf) and mdf.intersects2D(mf) + inside = ( mdf.containsAnyOf(mf) or mf.containsAnyOf(mdf) ) + if( intersects or inside or mdf.overlays(mf)): + c.append(afold) + return c + def getOverlapsBetweenGL(self, fold, folds): + b = fold.unfoldedFace().bounds() + polys = len(folds)*4+16 # the buffer is nhits, mindepth, maxdepth, name + buffer = BGL.Buffer(BGL.GL_INT, polys) + BGL.glSelectBuffer(polys, buffer) + BGL.glRenderMode(BGL.GL_SELECT) + BGL.glInitNames() + BGL.glPushName(0) + BGL.glPushMatrix() + BGL.glMatrixMode(BGL.GL_PROJECTION) + BGL.glLoadIdentity() + BGL.glOrtho(b[0].x, b[1].x, b[1].y, b[0].y, 0.0, 10.0) + #clip = BGL.Buffer(BGL.GL_FLOAT, 4) + #clip.list = [0,0,0,0] + #BGL.glClipPlane(BGL.GL_CLIP_PLANE1, clip) + # could use clipping planes here too + BGL.glMatrixMode(BGL.GL_MODELVIEW) + BGL.glLoadIdentity() + bx = (b[1].x - b[0].x) + by = (b[1].y - b[0].y) + cx = bx / 2.0 + cy = by / 2.0 + for f in xrange(len(folds)): + afold = folds[f] + if(fold!=afold): + BGL.glLoadName(f) + BGL.glBegin(BGL.GL_LINE_LOOP) + for v in afold.unfoldedFace().v: + BGL.glVertex2f(v.x, v.y) + BGL.glEnd() + BGL.glPopMatrix() + BGL.glFlush() + hits = BGL.glRenderMode(BGL.GL_RENDER) + buffer = [buffer[i] for i in xrange(3, 4*hits, 4)] + o = [folds[buffer[i]] for i in xrange(len(buffer))] + return self.getOverlapsBetween(fold, o) + def colourFace(self, face, cr): + for c in face.col: + c.r = int(cr[0]) + c.g = int(cr[1]) + c.b = int(cr[2]) + c.a = int(cr[3]) + self.src.update() + def setAvoidsOverlaps(self, avoids): + self.avoidsOverlaps = avoids + def addBranch(self, branch): + self.branches.append(branch) + if self.edgeIteratorClass!=RandomEdgeIterator: + self.branches.sort(lambda b1, b2: b1.compare(b2)) + def srcSize(self): + return len(self.src.faces) + def nBranches(self): + return len(self.branches) + def facesCreated(self): + return len(self.des.faces) + def facesVisited(self): + return self.myFacesVisited + def getOverlaps(self): + return self.overlaps + def sortOutIPOSource(self): + print "Sorting out IPO" + if self.foldIPO!=None: + return + o = None + try: + o = Blender.Object.Get("FoldRate") + except: + o = Blender.Object.New("Empty", "FoldRate") + Blender.Scene.GetCurrent().objects.link(o) + if(o.getIpo()==None): + ipo = Blender.Ipo.New("Object", "FoldRateIPO") + z = ipo.addCurve("RotZ") + print " added RotZ IPO curve" + z.addBezier((1,0)) + # again, why is this 10x out ? + z.addBezier((180, self.ff/10.0)) + z.addBezier((361, 0.0)) + o.setIpo(ipo) + z.recalc() + z.setInterpolation("Bezier") + z.setExtrapolation("Cyclic") + self.setIPOSource(o) + print " added IPO source" + def setIPOSource(self, object): + try: + self.foldIPO = object + for i in xrange(self.foldIPO.getIpo().getNcurves()): + self.IPOCurves[self.foldIPO.getIpo().getCurves()[i].getName()] = i + print " added ", self.foldIPO.getIpo().getCurves()[i].getName() + except: + print "Problem setting IPO object" + print sys.exc_info()[1] + traceback.print_exc(file=sys.stdout) + def setFoldFactor(self, ff): + self.ff = ff + def sayTree(self): + for fold in self.folds: + if(fold.getParent()!=None): + print fold.getID(), fold.dihedralAngle(), fold.getParent().getID() + def report(self): + p = int(float(self.myFacesVisited)/float(len(self.src.faces)) * 100) + print str(p) + "% unfolded" + print "faces created:", self.facesCreated() + print "faces visited:", self.facesVisited() + print "originalfaces:", len(self.src.faces) + n=0 + if(self.avoidsOverlaps): + print "net avoided at least ", self.getOverlaps(), " overlaps ", + n = len(self.src.faces) - self.facesCreated() + if(n>0): + print "but was unable to avoid ", n, " overlaps. Incomplete net." + else: + print "- A complete net." + else: + print "net has at least ", self.getOverlaps(), " collision(s)" + return n + # fold all my folds to a fraction of their total fold angle + def unfoldToCurrentFrame(self): + self.unfoldTo(Blender.Scene.GetCurrent().getRenderingContext().currentFrame()) + def unfoldTo(self, frame): + frames = Blender.Scene.GetCurrent().getRenderingContext().endFrame() + if(self.foldIPO!=None and self.foldIPO.getIpo()!=None): + f = self.foldIPO.getIpo().EvaluateCurveOn(self.IPOCurves["RotZ"],frame) + # err, this number seems to be 10x less than it ought to be + fff = 1.0 - (f*10.0 / self.ff) + else: + fff = 1.0-((frame)/(frames*1.0)) + for fold in self.folds: + fold.unfoldTo(fff) + for fold in self.folds: + fold.unfold() + tface = fold.unfoldedFace() + bface = fold.desFace + i = 0 + for v in bface.verts: + v.co.x = tface.v[i].x + v.co.y = tface.v[i].y + v.co.z = tface.v[i].z + i+=1 + Window.Redraw(Window.Types.VIEW3D) + return None + def addFace(self, poly, originalFace=None): + originalLength = len(self.des.verts) + self.des.verts.extend([Vector(vv.x, vv.y, vv.z) for vv in poly.v]) + self.des.faces.extend([ range(originalLength, originalLength + poly.size()) ]) + newFace = self.des.faces[len(self.des.faces)-1] + newFace.uv = [vv for vv in poly.v] + if(originalFace!=None and self.src.vertexColors): + newFace.col = [c for c in originalFace.col] + if(self.feedback!=None): + pu = str(int(self.fractionUnfolded() * 100))+"% unfolded" + howMuchDone = str(self.myFacesVisited)+" of "+str(len(self.src.faces))+" "+pu + self.feedback.say(howMuchDone) + #Window.DrawProgressBar (p, pu) + if(self.showProgress): + Window.Redraw(Window.Types.VIEW3D) + return newFace + def fractionUnfolded(self): + return float(self.myFacesVisited)/float(len(self.src.faces)) + def assignUV(self, face, uv): + face.uv = [Vector(v.x, v.y) for v in uv.v] + def unfoldAll(feedback=None): + objects = Blender.Object.Get() + for object in objects: + if(object.getType()=='Mesh' and not(object.getName().endswith("_net")) and len(object.getData(False, True).faces)>1): + net = Net.createNet(object, feedback) + net.searchForUnfolding() + svg = SVGExporter(net, object.getName()+".svg") + svg.export() + unfoldAll = staticmethod(unfoldAll) + def searchForUnfolding(self, limit=-1): + overlaps = 1 + attempts = 0 + while(overlaps > 0 or attempts=0 and (mesh.faces[mesh.activeFace].sel): + net.firstFaceIndex = mesh.activeFace + net.object = ob + net.feedback = feedback + return net + createNet = staticmethod(createNet) + def importNet(filename): + netName = filename.rstrip(".svg").replace("\\","/") + netName = netName[netName.rfind("/")+1:] + try: + netObject = Blender.Object.Get(netName) + except: + netObject = Blender.Object.New("Mesh", netName) + netObject.getData(mesh=1).name = netName + try: + Blender.Scene.GetCurrent().objects.link(netObject) + except: + pass + net = Net(None, netObject.getData(mesh=1)) + handler = NetHandler(net) + xml.sax.parse(filename, handler) + Window.Redraw(Window.Types.VIEW3D) + return net + importNet = staticmethod(importNet) + def getSourceMesh(self): + return self.src + +# determines the order in which to visit faces according to a local measure +class EdgeIterator: + def __init__(self, branch, otherConstructor=None): + self.branch = branch + self.bface = branch.getFace() + self.edge = branch.getFold().getEdge() + self.net = branch.getNet() + self.n = len(self.bface) + self.edges = [] + self.i = 0 + self.gooodness = 0 + self.createEdges() + self.computeGoodness() + if(otherConstructor==None): + self.sequenceEdges() + def createEdges(self): + edge = None + e = Edge.edgesOfBlenderFace(self.net.getSourceMesh(), self.bface) + for edge in e: + if not(edge.isBlenderSeam() and edge!=self.edge): + self.edges.append(edge) + def sequenceEdges(self): + pass + def next(self): + edge = self.edges[self.i] + self.i+=1 + return edge + def size(self): + return len(self.edges) + def reset(self): + self.i = 0 + def hasNext(self): + return (self.ilen(bface)-1): + return None + if(i==len(bface)-1): + j = 0 + else: + j = i+1 + edge = Edge( bface.v[i].co.copy(), bface.v[j].co.copy() ) + edge.bEdge = mesh.findEdge(bface.v[i], bface.v[j]) + edge.idx = i + return edge + fromBlenderFace=staticmethod(fromBlenderFace) + def edgesOfBlenderFace(mesh, bmFace): + edges = [mesh.edges[mesh.findEdges(edge[0], edge[1])] for edge in bmFace.edge_keys] + v = bmFace.verts + e = [] + vi = v[0] + i=0 + for j in xrange(1, len(bmFace)+1): + vj = v[j%len(bmFace)] + for ee in edges: + if((ee.v1.index==vi.index and ee.v2.index==vj.index) or (ee.v2.index==vi.index and ee.v1.index==vj.index)): + e.append(Edge(vi.co, vj.co, ee, i)) + i+=1 + vi = vj + return e + edgesOfBlenderFace=staticmethod(edgesOfBlenderFace) + def isBlenderSeam(self): + return (self.bmEdge.flag & Mesh.EdgeFlags.SEAM) + def isInFGon(self): + return (self.bmEdge.flag & Mesh.EdgeFlags.FGON) + def mapTo(self, poly): + if(self.idx==len(poly.v)-1): + j = 0 + else: + j = self.idx+1 + return Edge(poly.v[self.idx], poly.v[j]) + def isDegenerate(self): + return self.vector.length==0 + def vertices(s): + return [ [s.v1.x, s.v1.y, s.v1.z], [s.v2.x, s.v2.y,s.v2.z] ] + def key(self): + return self.bmEdge.key + def goodness(self): + return self.gooodness + def setGoodness(self, g): + self.gooodness = g + def compare(self, other): + if(self.goodness() > other.goodness()): + return +1 + else: + return -1 + # Does the given segment intersect this, for overlap detection. + # endpoints are allowed to touch the line segment + def intersects2D(self, s): + if(self.matches(s)): + return False + else: + i = Geometry.LineIntersect2D(self.v1, self.v2, s.v1, s.v2) + if(i!=None): + i.resize4D() + i.z = self.v1.z # hack to put the point on the same plane as this edge for comparison + return(i!=None and not(self.endsWith(i))) + def matches(self, s): + return ( (self.v1==s.v1 and self.v2==s.v2) or (self.v2==s.v1 and self.v1==s.v2) ) + # Is the given point on the end of this segment ? 10-5 seems to an acceptable limit for closeness in Blender + def endsWith(self, aPoint, e=0.0001): + return ( (self.v1-aPoint).length < e or (self.v2-aPoint).length < e ) + + +class Poly: + ids = -1 + def __init__(self): + Poly.ids+=1 + self.v = [] + self.id = Poly.ids + self.boundz = None + self.edges = None + def getID(self): + return self.id + def normal(self): + a =self.v[0] + b=self.v[1] + c=self.v[2] + p = b-a + p.resize3D() + q = a-c + q.resize3D() + return CrossVecs(p,q) + def makeEdges(self): + self.edges = [] + for i in xrange(self.nPoints()): + self.edges.append(Edge( self.v[i % self.nPoints()], self.v[ (i+1) % self.nPoints()] )) + def edgeAt(self, i): + if(self.edges==None): + self.makeEdges() + return self.edges[i] + def intersects2D(self, poly): + for i in xrange(self.nPoints()): + edge = self.edgeAt(i) + for j in xrange(poly.nPoints()): + if edge.intersects2D(poly.edgeAt(j)): + return True + return False + def isBad(self): + badness = 0 + for vv in self.v: + if(vv.x!=vv.x or vv.y!=vv.y or vv.z!=vv.z): # Nan check + badness+=1 + return (badness>0) + def midpoint(self): + x=y=z = 0.0 + n = 0 + for vv in self.v: + x+=vv.x + y+=vv.y + z+=vv.z + n+=1 + return [ x/n, y/n, z/n ] + def centerAtOrigin(self): + mp = self.midpoint() + mp = -mp + toOrigin = TranslationMatrix(mp) + self.v = [(vv * toOrigin) for vv in self.v] + def move(self, tv): + mv = TranslationMatrix(tv) + self.v = [(vv * mv) for vv in self.v] + def scale(self, s): + mp = Vector(self.midpoint()) + fromOrigin = TranslationMatrix(mp) + mp = -mp + toOrigin = TranslationMatrix(mp) + sm = ScaleMatrix(s, 4) + # Todo, the 3 lines below in 1 LC + self.v = [(vv * toOrigin) for vv in self.v] + self.v = [(sm * vv) for vv in self.v] + self.v = [(vv * fromOrigin) for vv in self.v] + def nPoints(self): + return len(self.v) + def size(self): + return len(self.v) + def rotated(self, axis, angle): + p = self.clone() + p.rotate(axis, angle) + return p + def rotate(self, axis, angle): + rotation = RotationMatrix(angle, 4, "r", axis.vector) + toOrigin = TranslationMatrix(axis.v1n) + fromOrigin = TranslationMatrix(axis.v1) + # Todo, the 3 lines below in 1 LC + self.v = [(vv * toOrigin) for vv in self.v] + self.v = [(rotation * vv) for vv in self.v] + self.v = [(vv * fromOrigin) for vv in self.v] + def moveAlong(self, vector, distance): + t = TranslationMatrix(vector) + s = ScaleMatrix(distance, 4) + ts = t*s + self.v = [(vv * ts) for vv in self.v] + def bounds(self): + if(self.boundz == None): + vv = [vv for vv in self.v] + vv.sort(key=lambda v: v.x) + minx = vv[0].x + maxx = vv[len(vv)-1].x + vv.sort(key=lambda v: v.y) + miny = vv[0].y + maxy = vv[len(vv)-1].y + self.boundz = [Vector(minx, miny, 0), Vector(maxx, maxy, 0)] + return self.boundz + def fromBlenderFace(bface): + p = Poly() + for vv in bface.v: + vec = Vector([vv.co[0], vv.co[1], vv.co[2] , 1.0]) + p.v.append(vec) + return p + fromBlenderFace = staticmethod(fromBlenderFace) + def fromList(list): + p = Poly() + for vv in list: + vec = Vector( [vvv for vvv in vv] ) + vec.resize4D() + p.v.append(vec) + return p + fromList = staticmethod(fromList) + def fromVectors(vectors): + p = Poly() + p.v.extend([v.copy().resize4D() for v in vectors]) + return p + fromVectors = staticmethod(fromVectors) + def clone(self): + p = Poly() + p.v.extend(self.v) + return p + def hasVertex(self, ttv): + v = Mathutils.Vector(ttv) + v.normalize() + for tv in self.v: + vv = Mathutils.Vector(tv) + vv.normalize() + t = 0.00001 + if abs(vv.x-v.x)0): j=i-1 + cv = self.v[i] + nv = self.v[j] + if ((((cv.y<=tp.y) and (tp.y") + self.e.endElement("style") + self.e.endElement("defs") + #self.addClipPath() + self.addMeta() + def addMeta(self): + self.e.startElement("metadata", xml.sax.xmlreader.AttributesImpl({})) + self.e.startElement("nets:net", xml.sax.xmlreader.AttributesImpl({})) + for i in xrange(1, len(self.net.folds)): + fold = self.net.folds[i] + # AttributesNSImpl - documentation is rubbish. using this hack. + atts = {} + atts["nets:id"] = "fold"+str(fold.getID()) + if(fold.parent!=None): + atts["nets:parent"] = "fold"+str(fold.parent.getID()) + else: + atts["nets:parent"] = "null" + atts["nets:da"] = str(fold.dihedralAngle()) + if(fold.parent!=None): + atts["nets:ofPoly"] = "poly"+str(fold.parent.foldingPoly.getID()) + else: + atts["nets:ofPoly"] = "" + atts["nets:toPoly"] = "poly"+str(fold.foldingPoly.getID()) + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("nets:fold", a) + self.e.endElement("nets:fold") + self.e.endElement("nets:net") + self.e.endElement("metadata") + def end(self): + self.e.endElement("svg") + self.e.endDocument() + print "grown." + def export(self): + self.net.unfoldTo(1) + bb = self.object.getBoundBox() + print bb + self.vxmin = bb[0][0] + self.vymin = bb[0][1] + self.vxmax = bb[7][0] + self.vymax = bb[7][1] + self.start() + atts = {} + atts["id"] = self.object.getName() + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("g", a) + #self.addUVImage() + self.addPolys() + self.addFoldLines() + #self.addCutLines() + self.e.endElement("g") + self.end() + def addClipPath(self): + atts = {} + atts["id"] = "netClip" + atts["clipPathUnits"] = "userSpaceOnUse" + atts["x"] = str(self.vxmin) + atts["y"] = str(self.vymin) + atts["width"] = "100%" + atts["height"] = "100%" + self.e.startElement("clipPath", atts) + self.addPolys() + self.e.endElement("clipPath") + def addUVImage(self): + image = Blender.Image.GetCurrent() #hmm - how to determine the desired image ? + if image==None: + return + ifn = image.getFilename() + ifn = self.filename.replace(".svg", ".jpg") + image.setFilename(ifn) + ifn = ifn[ifn.rfind("/")+1:] + image.save() + atts = {} + atts["clip-path"] = "url(#netClip)" + atts["xlink:href"] = ifn + self.e.startElement("image", atts) + self.e.endElement("image") + def addPolys(self): + atts = {} + atts["id"] = "polys" + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("g", a) + for i in xrange(len(self.net.folds)): + self.addPoly(self.net.folds[i]) + self.e.endElement("g") + def addFoldLines(self): + atts = {} + atts["id"] = "foldLines" + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("g", a) + for i in xrange( 1, len(self.net.folds)): + self.addFoldLine(self.net.folds[i]) + self.e.endElement("g") + def addFoldLine(self, fold): + edge = fold.edge.mapTo(fold.parent.foldingPoly) + if fold.dihedralAngle()>0: + foldType="valley" + else: + foldType="mountain" + atts={} + atts["x1"] = str(edge.v1.x) + atts["y1"] = str(edge.v1.y) + atts["x2"] = str(edge.v2.x) + atts["y2"] = str(edge.v2.y) + atts["id"] = "fold"+str(fold.getID()) + atts["class"] = foldType + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("line", a) + self.e.endElement("line") + def addCutLines(self): + atts = {} + atts["id"] = "cutLines" + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("g", a) + for i in xrange( 1, len(self.net.cuts)): + self.addCutLine(self.net.cuts[i]) + self.e.endElement("g") + def addCutLine(self, cut): + edge = cut.edge.mapTo(cut.parent.foldingPoly) + if cut.dihedralAngle()>0: + foldType="valley" + else: + foldType="mountain" + atts={} + atts["x1"] = str(edge.v1.x) + atts["y1"] = str(edge.v1.y) + atts["x2"] = str(edge.v2.x) + atts["y2"] = str(edge.v2.y) + atts["id"] = "cut"+str(cut.getID()) + atts["class"] = foldType + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("line", a) + self.e.endElement("line") + def addPoly(self, fold): + face = fold.foldingPoly + atts = {} + if fold.desFace.col: + col = fold.desFace.col[0] + rgb = "rgb("+str(col.r)+","+str(col.g)+","+str(col.b)+")" + atts["fill"] = rgb + atts["class"] = "poly" + atts["id"] = "poly"+str(face.getID()) + points = "" + first = True + for vv in face.v: + if(not(first)): + points+=',' + first = False + points+=str(vv[0]) + points+=' ' + points+=str(vv[1]) + atts["points"] = points + a = xml.sax.xmlreader.AttributesImpl(atts) + self.e.startElement("polygon", a) + self.e.endElement("polygon") + def fileSelected(filename): + try: + net = Registry.GetKey('unfolder')['net'] + exporter = SVGExporter(net, filename) + exporter.export() + except: + print "Problem exporting SVG" + traceback.print_exc(file=sys.stdout) + fileSelected = staticmethod(fileSelected) + +# for importing nets saved by the above exporter +class NetHandler(xml.sax.handler.ContentHandler): + def __init__(self, net): + self.net = net + self.first = (41==41) + self.currentElement = None + self.chars = None + self.currentAction = None + self.foldsPending = {} + self.polys = {} + self.actions = {} + self.actions["nets:fold"] = self.foldInfo + self.actions["line"] = self.cutOrFold + self.actions["polygon"] = self.createPoly + def setDocumentLocator(self, locator): + pass + def startDocument(self): + pass + def endDocument(self): + for fold in self.foldsPending.values(): + face = self.net.addFace(fold.unfoldedFace()) + fold.desFace = face + self.net.folds.append(fold) + self.net.addFace(self.first) + self.foldsPending = None + self.polys = None + def startPrefixMapping(self, prefix, uri): + pass + def endPrefixMapping(self, prefix): + pass + def startElement(self, name, attributes): + self.currentAction = None + try: + self.currentAction = self.actions[name] + except: + pass + if(self.currentAction!=None): + self.currentAction(attributes) + def endElement(self, name): + pass + def startElementNS(self, name, qname, attrs): + self.currentAction = self.actions[name] + if(self.currentAction!=None): + self.currentAction(attributes) + def endElementNS(self, name, qname): + pass + def characters(self, content): + pass + def ignorableWhitespace(self): + pass + def processingInstruction(self, target, data): + pass + def skippedEntity(self, name): + pass + def foldInfo(self, atts): + self.foldsPending[atts["nets:id"]] = atts + def createPoly(self, atts): + xy = re.split('[, ]' , atts["points"]) + vectors = [] + for i in xrange(0, len(xy)-1, 2): + v = Vector([float(xy[i]), float(xy[i+1]), 0.0]) + vectors.append(v) + poly = Poly.fromVectors(vectors) + if(self.first==True): + self.first = poly + self.polys[atts["id"]] = poly + def cutOrFold(self, atts): + fid = atts["id"] + try: + fi = self.foldsPending[fid] + except: + pass + p1 = Vector([float(atts["x1"]), float(atts["y1"]), 0.0]) + p2 = Vector([float(atts["x2"]), float(atts["y2"]), 0.0]) + edge = Edge(p1, p2) + parent = None + ofPoly = None + toPoly = None + try: + parent = self.foldsPending[fi["nets:parent"]] + except: + pass + try: + ofPoly = self.polys[fi["nets:ofPoly"]] + except: + pass + try: + toPoly = self.polys[fi["nets:toPoly"]] + except: + pass + fold = Fold(parent, ofPoly , toPoly, edge, float(fi["nets:da"])) + self.foldsPending[fid] = fold + def fileSelected(filename): + try: + net = Net.importNet(filename) + try: + Registry.GetKey('unfolder')['net'] = net + except: + Registry.SetKey('unfolder', {}) + Registry.GetKey('unfolder')['net'] = net + Registry.GetKey('unfolder')['lastpath'] = filename + except: + print "Problem importing SVG" + traceback.print_exc(file=sys.stdout) + fileSelected = staticmethod(fileSelected) + + +class GUI: + def __init__(self): + self.overlaps = Draw.Create(0) + self.ani = Draw.Create(0) + self.selectedFaces =0 + self.search = Draw.Create(0) + self.diffuse = True + self.ancestors = Draw.Create(0) + self.noise = Draw.Create(0.0) + self.shape = Draw.Create(0) + self.nOverlaps = 1==2 + self.iterators = [RandomEdgeIterator,Brightest,Curvature,EdgeIterator,OddEven,Largest] + self.iterator = RandomEdgeIterator + self.overlapsText = "*" + self.message = " " + def makePopupGUI(self): + useRandom = Draw.Create(0) + pub = [] + pub.append(("Search", self.search, "Search for non-overlapping net (maybe forever)")) + pub.append(("Random", useRandom, "Random style net")) + ok = True + while ok: + ok = Blender.Draw.PupBlock("Unfold", pub) + if ok: + if useRandom.val: + self.iterator = RandomEdgeIterator + else: + self.iterator = Curvature + self.unfold() + def makeStandardGUI(self): + Draw.Register(self.draw, self.keyOrMouseEvent, self.buttonEvent) + def installScriptLink(self): + print "Adding script link for animation" + s = Blender.Scene.GetCurrent().getScriptLinks("FrameChanged") + if(s!=None and s.count("frameChanged.py")>0): + return + try: + script = Blender.Text.Get("frameChanged.py") + except: + script = Blender.Text.New("frameChanged.py") + script.write("import Blender\n") + script.write("import mesh_unfolder as Unfolder\n") + script.write("u = Blender.Registry.GetKey('unfolder')\n") + script.write("if u!=None:\n") + script.write("\tn = u['net']\n") + script.write("\tif(n!=None and n.animates):\n") + script.write("\t\tn.unfoldToCurrentFrame()\n") + Blender.Scene.GetCurrent().addScriptLink("frameChanged.py", "FrameChanged") + def unfold(self): + anc = self.ancestors.val + n = 0.0 + s = True + self.nOverlaps = 0 + searchLimit = 10 + search = 1 + Draw.Redraw(1) + net = None + name = None + try: + self.say("Unfolding...") + Draw.Redraw(1) + while(s):# and search < searchLimit): + if(net!=None): + name = net.des.name + net = Net.fromSelected(self, name) + net.setAvoidsOverlaps(not(self.overlaps.val)) + print + print "Unfolding selected object" + net.edgeIteratorClass = self.iterator + print "Using ", net.edgeIteratorClass + net.animates = self.ani.val + self.diffuse = (self.ancestors.val==0) + net.diffuse = self.diffuse + net.generations = self.ancestors.val + net.noise = self.noise.val + print "even:", net.diffuse, " depth:", net.generations + net.unfold() + n = net.report() + t = "." + if(n<1.0): + t = "Overlaps>="+str(n) + else: + t = "A complete net." + self.nOverlaps = (n>=1) + if(self.nOverlaps): + self.say(self.message+" - unfolding failed - try again ") + elif(not(self.overlaps.val)): + self.say("Success. Complete net - no overlaps ") + else: + self.say("Unfolding complete") + self.ancestors.val = anc + s = (self.search.val and n>=1.0) + dict = Registry.GetKey('unfolder') + if(not(dict)): + dict = {} + dict['net'] = net + Registry.SetKey('unfolder', dict) + if(s): + net = net.clone() + search += 1 + except(IndexError): + self.say("Please select an object to unfold") + except: + self.say("Problem unfolding selected object - see console for details") + print "Problem unfolding selected object:" + print sys.exc_info()[1] + traceback.print_exc(file=sys.stdout) + if(self.ani): + if Registry.GetKey('unfolder')==None: + print "no net!" + return + Registry.GetKey('unfolder')['net'].sortOutIPOSource() + self.installScriptLink() + Draw.Redraw(1) + def keyOrMouseEvent(self, evt, val): + if (evt == Draw.ESCKEY and not val): + Draw.Exit() + def buttonEvent(self, evt): + if (evt == 1): + self.unfold() + if (evt == 5): + try: + Registry.GetKey('unfolder')['net'].setAvoidsOverlaps(self.overlaps.val) + except: + pass + if (evt == 2): + print "Trying to set IPO curve" + try: + s = Blender.Object.GetSelected() + if(s!=None): + Registry.GetKey('unfolder')['net'].setIPOSource( s[0] ) + print "Set IPO curve" + else: + print "Please select an object to use the IPO of" + except: + print "Problem setting IPO source" + Draw.Redraw(1) + if (evt == 6): + Draw.Exit() + if (evt == 7): + try: + if (Registry.GetKey('unfolder')['net']!=None): + Registry.GetKey('unfolder')['net'].animates = self.ani.val + if(self.ani): + Registry.GetKey('unfolder')['net'].sortOutIPOSource() + self.installScriptLink() + except: + print sys.exc_info()[1] + traceback.print_exc(file=sys.stdout) + Draw.Redraw(1) + if (evt == 19): + pass + if (evt == 87): + try: + if (Registry.GetKey('unfolder')['net']!=None): + Registry.GetKey('unfolder')['net'].assignUVs() + self.say("Assigned UVs") + except: + print sys.exc_info()[1] + traceback.print_exc(file=sys.stdout) + Draw.Redraw(1) + if(evt==91): + if( testOverlap() == True): + self.nOverlaps = 1 + else: + self.nOverlaps = 0 + Draw.Redraw(1) + if(evt==233): + f1 = Poly.fromBlenderFace(Blender.Object.GetSelected()[0].getData().faces[0]) + f2 = Poly.fromBlenderFace(Blender.Object.GetSelected()[1].getData().faces[0]) + print + print Blender.Object.GetSelected()[0].getName() + print Blender.Object.GetSelected()[1].getName() + print f1.intersects2D(f2) + print f2.intersects2D(f1) + if(evt==714): + Net.unfoldAll(self) + Draw.Redraw(1) + if(evt==713): + self.iterator = self.iterators[self.shape.val] + Draw.Redraw(1) + if(evt==92): + if( testContains() == True): + self.nOverlaps = 1 + else: + self.nOverlaps = 0 + Draw.Redraw(1) + if(evt==104): + try: + filename = "net.svg" + s = Blender.Object.GetSelected() + if(s!=None and len(s)>0): + filename = s[0].getName()+".svg" + else: + if (Registry.GetKey('unfolder')['net']!=None): + filename = Registry.GetKey('unfolder')['net'].des.name + if(filename==None): + filename="net.svg" + else: + filename=filename+".svg" + Window.FileSelector(SVGExporter.fileSelected, "Select filename", filename) + except: + print "Problem exporting SVG" + traceback.print_exc(file=sys.stdout) + if(evt==107): + try: + Window.FileSelector(NetHandler.fileSelected, "Select file") + except: + print "Problem importing SVG" + traceback.print_exc(file=sys.stdout) + def say(self, m): + self.message = m + Draw.Redraw(1) + Window.Redraw(Window.Types.SCRIPT) + def draw(self): + cw = 64 + ch = 16 + l = FlowLayout(32, cw, ch, 350, 64) + l.y = 70 + self.search = Draw.Toggle("search", 19, l.nx(), l.ny(), l.cw, l.ch, self.search.val, "Search for non-overlapping mesh (potentially indefinitely)") + self.overlaps = Draw.Toggle("overlaps", 5, l.nx(), l.ny(), l.cw, l.ch, self.overlaps.val, "Allow overlaps / avoid overlaps - if off, will not place overlapping faces") + self.ani = Draw.Toggle("ani", 7, l.nx(), l.ny(), l.cw, l.ch, self.ani.val, "Animate net") + Draw.Button("uv", 87, l.nx(), l.ny(), l.cw, l.ch, "Assign net as UV to source mesh (overwriting existing UV)") + Draw.Button("Unfold", 1, l.nx(), l.ny(), l.cw, l.ch, "Unfold selected mesh to net") + Draw.Button("save", 104, l.nx(), l.ny(), l.cw, l.ch, "Save net as SVG") + Draw.Button("load", 107, l.nx(), l.ny(), l.cw, l.ch, "Load net from SVG") + #Draw.Button("test", 233, l.nx(), l.ny(), l.cw, l.ch, "test") + # unfolding enthusiasts - try uncommenting this + self.ancestors = Draw.Number("depth", 654, l.nx(), l.ny(), cw, ch, self.ancestors.val, 0, 9999, "depth of branching 0=diffuse") + #self.noise = Draw.Number("noise", 631, l.nx(), l.ny(), cw, ch, self.noise.val, 0.0, 1.0, "noisyness of branching") + #Draw.Button("UnfoldAll", 714, l.nx(), l.ny(), l.cw, l.ch, "Unfold all meshes and save their nets") + options = "order %t|random %x0|brightest %x1|curvature %x2|winding %x3| 1010 %x4|largest %x5" + self.shape = Draw.Menu(options, 713, l.nx(), l.ny(), cw, ch, self.shape.val, "shape of net") + Draw.Button("exit", 6, l.nx(), l.ny(), l.cw, l.ch, "exit") + BGL.glClearColor(0.3, 0.3, 0.3, 1) + BGL.glColor3f(0.3,0.3,0.3) + l.newLine() + BGL.glRasterPos2i(32, 100) + Draw.Text(self.message) + +class FlowLayout: + def __init__(self, margin, cw, ch, w, h): + self.x = margin-cw-4 + self.y = margin + self.cw = cw + self.ch = ch + self.width = w + self.height = h + self.margin = margin + def nx(self): + self.x+=(self.cw+4) + if(self.x>self.width): + self.x = self.margin + self.y-=self.ch+4 + return self.x + def ny(self): + return self.y + def newLine(self): + self.y-=self.ch+self.margin + self.x = self.margin + +# if xml is None, then dont bother running the script +if xml: + try: + sys.setrecursionlimit(10000) + gui = GUI() + gui.makeStandardGUI() + #gui.makePopupGUI() + except: + traceback.print_exc(file=sys.stdout) diff --git a/release/scripts/mesh_wire.py b/release/scripts/mesh_wire.py new file mode 100644 index 00000000000..35cfa325497 --- /dev/null +++ b/release/scripts/mesh_wire.py @@ -0,0 +1,285 @@ +#!BPY +""" +Name: 'Solid Wireframe' +Blender: 243 +Group: 'Mesh' +Tooltip: 'Make a solid wireframe copy of this mesh' +""" + +# -------------------------------------------------------------------------- +# Solid Wireframe1.0 by Campbell Barton (AKA Ideasman42) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +import Blender +from Blender import Scene, Mesh, Window, sys +from Blender.Mathutils import AngleBetweenVecs, TriangleNormal +from BPyMesh import faceAngles # get angles for face cornders +#import BPyMesh +#reload(BPyMesh) +#faceAngles = BPyMesh.faceAngles + +# works out the distanbce to inset the corners based on angles +from BPyMathutils import angleToLength +#import BPyMathutils +#reload(BPyMathutils) +#angleToLength = BPyMathutils.angleToLength + +import mesh_solidify + +import BPyMessages +import bpy + + +def solid_wire(ob_orig, me_orig, sce, PREF_THICKNESS, PREF_SOLID, PREF_SHARP, PREF_XSHARP): + if not PREF_SHARP and PREF_XSHARP: + PREF_XSHARP = False + + # This function runs out of editmode with a mesh + # error cases are alredy checked for + + inset_half = PREF_THICKNESS / 2 + del PREF_THICKNESS + + ob = ob_orig.copy() + me = me_orig.copy() + ob.link(me) + sce.objects.selected = [] + sce.objects.link(ob) + ob.sel = True + sce.objects.active = ob + + # Modify the object, should be a set + FGON= Mesh.EdgeFlags.FGON + edges_fgon = dict([(ed.key,None) for ed in me.edges if ed.flag & FGON]) + # edges_fgon.fromkeys([ed.key for ed in me.edges if ed.flag & FGON]) + + del FGON + + + + # each face needs its own verts + # orig_vert_count =len(me.verts) + new_vert_count = len(me.faces) * 4 + for f in me.faces: + if len(f) == 3: + new_vert_count -= 1 + + if PREF_SHARP == 0: + new_faces_edge= {} + + def add_edge(i1,i2, ni1, ni2): + + if i1>i2: + i1,i2 = i2,i1 + flip = True + else: + flip = False + new_faces_edge.setdefault((i1,i2), []).append((ni1, ni2, flip)) + + + new_verts = [] + new_faces = [] + vert_index = len(me.verts) + + for f in me.faces: + f_v_co = [v.co for v in f] + angles = faceAngles(f_v_co) + f_v_idx = [v.index for v in f] + + def new_vert(fi): + co = f_v_co[fi] + a = angles[fi] + if a > 180: + vert_inset = 1 * inset_half + else: + vert_inset = inset_half * angleToLength( abs((180-a) / 2) ) + + # Calculate the inset direction + co1 = f_v_co[fi-1] + co2 = fi+1 # Wrap this index back to the start + if co2 == len(f_v_co): co2 = 0 + co2 = f_v_co[co2] + + co1 = co1 - co + co2 = co2 - co + co1.normalize() + co2.normalize() + d = co1+co2 + # Done with inset direction + + d.length = vert_inset + return co+d + + new_verts.extend([new_vert(i) for i in xrange(len(f_v_co))]) + + if len(f_v_idx) == 4: + faces = [\ + (f_v_idx[1], f_v_idx[0], vert_index, vert_index+1),\ + (f_v_idx[2], f_v_idx[1], vert_index+1, vert_index+2),\ + (f_v_idx[3], f_v_idx[2], vert_index+2, vert_index+3),\ + (f_v_idx[0], f_v_idx[3], vert_index+3, vert_index),\ + ] + else: + faces = [\ + (f_v_idx[1], f_v_idx[0], vert_index, vert_index+1),\ + (f_v_idx[2], f_v_idx[1], vert_index+1, vert_index+2),\ + (f_v_idx[0], f_v_idx[2], vert_index+2, vert_index),\ + ] + + + if PREF_SHARP == 1: + if not edges_fgon: + new_faces.extend(faces) + else: + for nf in faces: + i1,i2 = nf[0], nf[1] + if i1>i2: i1,i2 = i2,i1 + + if edges_fgon and (i1,i2) not in edges_fgon: + new_faces.append(nf) + + + + elif PREF_SHARP == 0: + for nf in faces: + add_edge(*nf) + + vert_index += len(f_v_co) + + me.verts.extend(new_verts) + + if PREF_SHARP == 0: + def add_tri_flipped(i1,i2,i3): + try: + if AngleBetweenVecs(me.verts[i1].no, TriangleNormal(me.verts[i1].co, me.verts[i2].co, me.verts[i3].co)) < 90: + return i3,i2,i1 + else: + return i1,i2,i3 + except: + return i1,i2,i3 + + # This stores new verts that use this vert + # used for re-averaging this verts location + # based on surrounding verts. looks better but not needed. + vert_users = [set() for i in xrange(vert_index)] + + for (i1,i2), nf in new_faces_edge.iteritems(): + + if len(nf) == 2: + # Add the main face + if edges_fgon and (i1,i2) not in edges_fgon: + new_faces.append((nf[0][0], nf[0][1], nf[1][0], nf[1][1])) + + + if nf[0][2]: key1 = nf[0][1],nf[0][0] + else: key1 = nf[0][0],nf[0][1] + if nf[1][2]: key2 = nf[1][1],nf[1][0] + else: key2 = nf[1][0],nf[1][1] + + # CRAP, cont work out which way to flip so make it oppisite the verts normal. + + ###new_faces.append((i2, key1[0], key2[0])) # NO FLIPPING, WORKS THOUGH + ###new_faces.append((i1, key1[1], key2[1])) + new_faces.append(add_tri_flipped(i2, key1[0], key2[0])) + new_faces.append(add_tri_flipped(i1, key1[1], key2[1])) + + # Average vert loction so its not tooo pointy + # not realy needed but looks better + vert_users[i2].update((key1[0], key2[0])) + vert_users[i1].update((key1[1], key2[1])) + + if len(nf) == 1: + if nf[0][2]: new_faces.append((nf[0][0], nf[0][1], i2, i1)) # flipped + else: new_faces.append((i1,i2, nf[0][0], nf[0][1])) + + + # average points now. + for i, vusers in enumerate(vert_users): + if vusers: + co = me.verts[i].co + co.zero() + + for ii in vusers: + co += me.verts[ii].co + co /= len(vusers) + + + + me.faces.delete(1, range(len(me.faces))) + + me.faces.extend(new_faces) + + # External function, solidify + me.sel = True + if PREF_SOLID: + mesh_solidify.solidify(me, -inset_half*2, True, False, PREF_XSHARP) + + +def main(): + + # Gets the current scene, there can be many scenes in 1 blend file. + sce = bpy.data.scenes.active + + # Get the active object, there can only ever be 1 + # and the active object is always the editmode object. + ob_act = sce.objects.active + + if not ob_act or ob_act.type != 'Mesh': + BPyMessages.Error_NoMeshActive() + return + + # Create the variables. + PREF_THICK = Blender.Draw.Create(0.005) + PREF_SOLID = Blender.Draw.Create(1) + PREF_SHARP = Blender.Draw.Create(1) + PREF_XSHARP = Blender.Draw.Create(0) + + pup_block = [\ + ('Thick:', PREF_THICK, 0.0001, 2.0, 'Skin thickness in mesh space.'),\ + ('Solid Wire', PREF_SOLID, 'If Disabled, will use 6 sided wire segments'),\ + ('Sharp Wire', PREF_SHARP, 'Use the original mesh topology for more accurate sharp wire.'),\ + ('Extra Sharp', PREF_XSHARP, 'Use less geometry to create a sharper looking wire'),\ + ] + + if not Blender.Draw.PupBlock('Solid Wireframe', pup_block): + return + + # Saves the editmode state and go's out of + # editmode if its enabled, we cant make + # changes to the mesh data while in editmode. + is_editmode = Window.EditMode() + Window.EditMode(0) + + Window.WaitCursor(1) + me = ob_act.getData(mesh=1) # old NMesh api is default + t = sys.time() + + # Run the mesh editing function + solid_wire(ob_act, me, sce, PREF_THICK.val, PREF_SOLID.val, PREF_SHARP.val, PREF_XSHARP.val) + + # Timing the script is a good way to be aware on any speed hits when scripting + print 'Solid Wireframe finished in %.2f seconds' % (sys.time()-t) + Window.WaitCursor(0) + if is_editmode: Window.EditMode(1) + + +# This lets you can import the script without running it +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/release/scripts/obdatacopier.py b/release/scripts/obdatacopier.py new file mode 100644 index 00000000000..561e40e15da --- /dev/null +++ b/release/scripts/obdatacopier.py @@ -0,0 +1,215 @@ +#!BPY + +""" Registration info for Blender menus: <- these words are ignored +Name: 'Data Copier' +Blender: 232 +Group: 'Object' +Tip: 'Copy data from active object to other selected ones.' +""" + +__author__ = "Jean-Michel Soler (jms), Campbell Barton (Ideasman42)" +__url__ = ("blender", "elysiun", +"Script's homepage, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_lampdatacopier.htm", +"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender") +__version__ = "0.1.2" + +__bpydoc__ = """\ +Use "Data Copier" to copy attributes from the active object to other selected ones of +its same type. + +This script is still in an early version but is already useful for copying +attributes for some types of objects like lamps and cameras. + +Usage: + +Select the objects that will be updated, select the object whose data will +be copied (they must all be of the same type, of course), then run this script. +Toggle the buttons representing the attributes to be copied and press "Copy". +""" + +# ---------------------------------------------------------- +# Object DATA copier 0.1.2 +# (c) 2004 jean-michel soler +# ----------------------------------------------------------- +#---------------------------------------------- +# Page officielle/official page du blender python Object DATA copier: +# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_lampdatacopier.htm +# Communiquer les problemes et erreurs sur: +# To Communicate problems and errors on: +# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender +#--------------------------------------------- +# Blender Artistic License +# http://download.blender.org/documentation/html/x21254.html +#--------------------------------------------- + +import Blender +from Blender import * +from Blender.Draw import * +from Blender.BGL import * + + +scn= Blender.Scene.GetCurrent() + +type_func_method= type(dir) +type_func= type(lambda:i) +type_dict= type({}) +# type_list= type([]) + +IGNORE_VARS = 'users', 'fakeUser', 'edges', 'faces', 'verts', 'elements' + +def renew(): + scn= Blender.Scene.GetCurrent() + act_ob= scn.objects.active + if act_ob==None: + return {} + + act_ob_type= act_ob.getType() + act_ob_data= act_ob.getData(mesh=1) + + if act_ob_data==None: # Surf? + return {} + + PARAM={} + evt=4 + doc='doc' + + for prop_name in dir(act_ob_data): + if not prop_name.startswith('__') and prop_name not in IGNORE_VARS: + # Get the type + try: exec 'prop_type= type(act_ob_data.%s)' % prop_name + except: prop_type= None + + if prop_type != None and prop_type not in (type_func_method, type_func, type_dict): + + # Now we know that the attribute can be listed in the UI Create a button and tooltip. + + # Tooltip + try: + if prop_name=='mode': + try: + exec "doc=str(%s.Modes)+' ; value : %s'"%( act_ob_type, str(act_ob_data.mode) ) + except: + exec """doc= '%s'+' value = '+ str(act_ob.getData(mesh=1).%s)"""%(prop_name, prop_name) + elif prop_name=='type': + try: + exec "doc=str(%s.Types)+' ; value : %s'"%( act_ob_type, str(act_ob_data.type) ) + except: + exec """doc= '%s'+' value = '+ str(act_ob.getData(mesh=1).%s)"""%(prop_name, prop_name) + else: + exec """doc= '%s'+' value = '+ str(act_ob_data.%s)"""%(prop_name, prop_name) + if doc.find('built-in')!=-1: + exec """doc= 'This is a function ! Doc = '+ str(act_ob_data.%s.__doc__)"""% prop_name + except: + doc='Doc...' + + # Button + PARAM[prop_name]= [Create(0), evt, doc] + evt+=1 + + return PARAM + +def copy(): + global PARAM + + scn= Blender.Scene.GetCurrent() + act_ob= scn.getActiveObject() + if act_ob==None: + Blender.Draw.PupMenu('Error|No Active Object.') + return + + act_ob_type= act_ob.getType() + + if act_ob_type in ('Empty', 'Surf'): + Blender.Draw.PupMenu('Error|Copying Empty or Surf object data isnt supported.') + return + + act_ob_data= act_ob.getData(mesh=1) + + print '\n\nStarting copy for object "%s"' % act_ob.name + some_errors= False + for ob in scn.objects.context: + if ob != act_ob and ob.getType() == act_ob_type: + ob_data= None + for prop_name, value in PARAM.iteritems(): + if value[0].val==1: + + # Init the object data if we havnt alredy + if ob_data==None: + ob_data= ob.getData(mesh=1) + + try: + exec "ob_data.%s = act_ob_data.%s"%(prop_name, prop_name) + except: + some_errors= True + print 'Cant copy property "%s" for type "%s"' % (prop_name, act_ob_type) + if some_errors: + Blender.Draw.PupMenu('Some attributes could not be copied, see console for details.') + +PARAM= renew() + +def EVENT(evt,val): + pass + +def BUTTON(evt): + global PARAM + if (evt==1): + Exit() + + if (evt==2): + copy() + Blender.Redraw() + + if (evt==3): + PARAM= renew() + Blender.Redraw() + +def DRAW(): + global PARAM + + scn= Blender.Scene.GetCurrent() + act_ob= scn.objects.active + + glColor3f(0.7, 0.7, 0.7) + glClear(GL_COLOR_BUFFER_BIT) + glColor3f(0.1, 0.1, 0.15) + + size=Buffer(GL_FLOAT, 4) + glGetFloatv(GL_SCISSOR_BOX, size) + size= size.list + for s in [0,1,2,3]: size[s]=int(size[s]) + ligne=20 + + Button("Exit",1,20,4,80,ligne) + Button("Copy",2,102,4,80,ligne) + Button("Renew",3,184,4,80,ligne) + + glRasterPos2f(20, ligne*2-8) + if act_ob: + Text(act_ob.getType()+" DATA copier") + else: + Text("Please select an object") + + + max=size[3] / 22 -2 + pos = 0 + decal = 20 + key=PARAM.keys() + key.sort() + for p in key: + if pos==max: + decal+=102 + pos=1 + else: + pos+=1 + + PARAM[p][0]=Toggle(p, + PARAM[p][1], + decal, + pos*22+22, + 100, + 20, + PARAM[p][0].val, + str(PARAM[p][2])) + + +Register(DRAW,EVENT,BUTTON) diff --git a/release/scripts/object_apply_def.py b/release/scripts/object_apply_def.py new file mode 100644 index 00000000000..67e4179a674 --- /dev/null +++ b/release/scripts/object_apply_def.py @@ -0,0 +1,174 @@ +#!BPY + +""" +Name: 'Apply Deformation' +Blender: 242 +Group: 'Object' +Tooltip: 'Make copys of all the selected objects with modifiers, softbodies and fluid baked into a mesh' +""" + +__author__ = "Martin Poirier (theeth), Jean-Michel Soler (jms), Campbell Barton (ideasman)" +# This script is the result of merging the functionalities of two other: +# Martin Poirier's Apply_Def.py and +# Jean-Michel Soler's Fix From Everything + +__url__ = ("http://www.blender.org", "http://blenderartists.org", "http://members.iinet.net.au/~cpbarton/ideasman/", "http://jmsoler.free.fr") +__version__ = "1.6 07/07/2006" + +__bpydoc__ = """\ +This script creates "raw" copies of deformed meshes. + +Usage: + +Select any number of Objects and run this script. A fixed copy of each selected object +will be created, with the word "_def" appended to its name. If an object with +the same name already exists, it appends a number at the end as Blender itself does. + +Objects in Blender can be deformed by armatures, lattices, curve objects and subdivision, +but this will only change its appearance on screen and rendered +images -- the actual mesh data is still simpler, with vertices in an original +"rest" position and less vertices than the subdivided version. + +Use this script if you want a "real" version of the deformed mesh, so you can +directly manipulate or export its data. + +This script will work with object types: Mesh, Metaballs, Text3d, Curves and Nurbs Surface. +""" + + +# $Id$ +# +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2003: Martin Poirier, theeth@yahoo.com +# +# Thanks to Jonathan Hudson for help with the vertex groups part +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + + +import Blender +import bpy +import BPyMesh + +def copy_vgroups(source_ob, target_ob): + + source_me = source_ob.getData(mesh=1) + + vgroups= source_me.getVertGroupNames() + if vgroups: + ADD= Blender.Mesh.AssignModes.ADD + target_me = target_ob.getData(mesh=1) + for vgroupname in vgroups: + target_me.addVertGroup(vgroupname) + if len(target_me.verts) == len(source_me.verts): + vlist = source_me.getVertsFromGroup(vgroupname, True) + try: + for vpair in vlist: + target_me.assignVertsToGroup(vgroupname, [vpair[0]], vpair[1], ADD) + except: + pass + + +def apply_deform(): + scn= bpy.data.scenes.active + #Blender.Window.EditMode(0) + + NAME_LENGTH = 19 + SUFFIX = "_def" + SUFFIX_LENGTH = len(SUFFIX) + # Get all object and mesh names + + + ob_list = list(scn.objects.context) + ob_act = scn.objects.active + + # Assume no soft body + has_sb= False + + # reverse loop so we can remove objects (metaballs in this case) + for ob_idx in xrange(len(ob_list)-1, -1, -1): + ob= ob_list[ob_idx] + + ob.sel = 0 # deselect while where checking the metaballs + + # Test for a softbody + if not has_sb and ob.isSB(): + has_sb= True + + # Remove all numbered metaballs because their disp list is only on the main metaball (un numbered) + if ob.type == 'MBall': + name= ob.name + # is this metaball numbered? + dot_idx= name.rfind('.') + 1 + if name[dot_idx:].isdigit(): + # Not the motherball, ignore it. + del ob_list[ob_idx] + + + if not ob_list: + Blender.Draw.PupMenu('No objects selected, nothing to do.') + return + + + if has_sb: + curframe=Blender.Get('curframe') + for f in xrange(curframe): + Blender.Set('curframe',f+1) + Blender.Window.RedrawAll() + + used_names = [ob.name for ob in Blender.Object.Get()] + used_names.extend(Blender.NMesh.GetNames()) + + + deformedList = [] + for ob in ob_list: + + # Get the mesh data + new_me= BPyMesh.getMeshFromObject(ob, vgroups=False) + + if not new_me: + continue # Object has no display list + + + name = ob.name + new_name = "%s_def" % name[:NAME_LENGTH-SUFFIX_LENGTH] + num = 0 + + while new_name in used_names: + new_name = "%s_def.%.3i" % (name[:NAME_LENGTH-(SUFFIX_LENGTH+SUFFIX_LENGTH)], num) + num += 1 + used_names.append(new_name) + + new_me.name= new_name + + new_ob= scn.objects.new(new_me) + new_ob.setMatrix(ob.matrixWorld) + + # Make the active duplicate also active + if ob == ob_act: + scn.objects.active = new_ob + + # Original object was a mesh? see if we can copy any vert groups. + if ob.type =='Mesh': + copy_vgroups(ob, new_ob) + + Blender.Window.RedrawAll() + +if __name__=='__main__': + apply_deform() \ No newline at end of file diff --git a/release/scripts/object_batch_name_edit.py b/release/scripts/object_batch_name_edit.py new file mode 100644 index 00000000000..05ca5868d19 --- /dev/null +++ b/release/scripts/object_batch_name_edit.py @@ -0,0 +1,274 @@ +#!BPY +""" +Name: 'Batch Object Name Edit' +Blender: 240 +Group: 'Object' +Tooltip: 'Apply the chosen rule to rename all selected objects at once.' +""" +__author__ = "Campbell Barton" +__url__ = ("blender", "elysiun") +__version__ = "1.0" + +__bpydoc__ = """\ +"Batch Object Name Edit" allows you to change multiple names of Blender +objects at once. It provides options to define if you want to: replace text +in the current names, truncate their beginnings or endings or prepend / append +strings to them. + +Usage: +Select the objects to be renamed and run this script from the Object->Scripts +menu of the 3d View. +""" +# $Id$ +# +# -------------------------------------------------------------------------- +# Batch Name Edit by Campbell Barton (AKA Ideasman) +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- +from Blender import * +import bpy + +global renameCount +renameCount = 0 +obsel = [ob for ob in bpy.data.scenes.active.objects.context if not ob.lib] + +def setDataNameWrapper(ob, newname): + if ob.getData(name_only=1) == newname: + return False + + data= ob.getData(mesh=1) + + if data and not data.lib: + data.name= newname + return True + return False + +def main(): + global renameCount + # Rename the datablocks that are used by the object. + def renameLinkedDataFromObject(): + + # Result 1, we want to rename data + for ob in obsel: + if ob.name == ob.getData(name_only=1): + return # Alredy the same name, dont bother. + + data = ob.getData(mesh=1) # use mesh so we dont have to update the nmesh. + if data and not data.lib: + data.name = ob.name + + + def new(): + global renameCount + NEW_NAME_STRING = Draw.Create('') + RENAME_LINKED = Draw.Create(0) + pup_block = [\ + ('New Name: ', NEW_NAME_STRING, 19, 19, 'New Name'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Replace in name...', pup_block): + return 0 + + NEW_NAME_STRING= NEW_NAME_STRING.val + + Window.WaitCursor(1) + for ob in obsel: + if ob.name != NEW_NAME_STRING: + ob.name = NEW_NAME_STRING + renameCount+=1 + + return RENAME_LINKED.val + + def replace(): + global renameCount + REPLACE_STRING = Draw.Create('') + WITH_STRING = Draw.Create('') + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Replace: ', REPLACE_STRING, 19, 19, 'Text to find'),\ + ('With:', WITH_STRING, 19, 19, 'Text to replace with'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Replace in name...', pup_block) or\ + ((not REPLACE_STRING.val) and (not WITH_STRING)): + return 0 + + REPLACE_STRING = REPLACE_STRING.val + WITH_STRING = WITH_STRING.val + + Window.WaitCursor(1) + for ob in obsel: + newname = ob.name.replace(REPLACE_STRING, WITH_STRING) + if ob.name != newname: + ob.name = newname + renameCount+=1 + return RENAME_LINKED.val + + + def prefix(): + global renameCount + PREFIX_STRING = Draw.Create('') + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Prefix: ', PREFIX_STRING, 19, 19, 'Name prefix'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Prefix...', pup_block) or\ + not PREFIX_STRING.val: + return 0 + + PREFIX_STRING = PREFIX_STRING.val + + Window.WaitCursor(1) + for ob in obsel: + ob.name = PREFIX_STRING + ob.name + renameCount+=1 # we knows these are different. + return RENAME_LINKED.val + + def suffix(): + global renameCount + SUFFIX_STRING = Draw.Create('') + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Suffix: ', SUFFIX_STRING, 19, 19, 'Name suffix'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Suffix...', pup_block) or\ + not SUFFIX_STRING.val: + return 0 + + SUFFIX_STRING = SUFFIX_STRING.val + + Window.WaitCursor(1) + for ob in obsel: + ob.name = ob.name + SUFFIX_STRING + renameCount+=1 # we knows these are different. + return RENAME_LINKED.val + + def truncate_start(): + global renameCount + TRUNCATE_START = Draw.Create(0) + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Truncate Start: ', TRUNCATE_START, 0, 19, 'Truncate chars from the start of the name'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Truncate Start...', pup_block) or\ + not TRUNCATE_START.val: + return 0 + + Window.WaitCursor(1) + TRUNCATE_START = TRUNCATE_START.val + for ob in obsel: + newname = ob.name[TRUNCATE_START: ] + ob.name = newname + renameCount+=1 + + return RENAME_LINKED.val + + def truncate_end(): + global renameCount + TRUNCATE_END = Draw.Create(0) + RENAME_LINKED = Draw.Create(0) + + pup_block = [\ + ('Truncate End: ', TRUNCATE_END, 0, 19, 'Truncate chars from the end of the name'),\ + ('Rename ObData', RENAME_LINKED, 'Renames objects data to match the obname'),\ + ] + + if not Draw.PupBlock('Truncate End...', pup_block) or\ + not TRUNCATE_END.val: + return 0 + + Window.WaitCursor(1) + TRUNCATE_END = TRUNCATE_END.val + for ob in obsel: + newname = ob.name[: -TRUNCATE_END] + ob.name = newname + renameCount+=1 + + return RENAME_LINKED.val + + def renameObjectFromLinkedData(): + global renameCount + Window.WaitCursor(1) + + for ob in obsel: + newname = ob.getData(name_only=1) + if newname != None and ob.name != newname: + ob.name = newname + renameCount+=1 + return 0 + + def renameObjectFromDupGroup(): + global renameCount + Window.WaitCursor(1) + + for ob in obsel: + group= ob.DupGroup + if group != None: + newname= group.name + if newname != ob.name: + ob.name = newname + renameCount+=1 + return 0 + + def renameLinkedDataFromObject(): + global renameCount + Window.WaitCursor(1) + + for ob in obsel: + if setDataNameWrapper(ob, ob.name): + renameCount+=1 + return 0 + + name = "Selected Object Names%t|New Name|Replace Text|Add Prefix|Add Suffix|Truncate Start|Truncate End|Rename Objects to Data Names|Rename Objects to DupGroup Names|Rename Data to Object Names" + result = Draw.PupMenu(name) + renLinked = 0 # Rename linked data to the object name? + if result == -1: + return + elif result == 1: renLinked= new() + elif result == 2: renLinked= replace() + elif result == 3: renLinked= prefix() + elif result == 4: renLinked= suffix() + elif result == 5: renLinked= truncate_start() + elif result == 6: renLinked= truncate_end() + elif result == 7: renameObjectFromLinkedData() + elif result == 8: renameObjectFromDupGroup() + elif result == 9: renameLinkedDataFromObject() + + if renLinked: + renameLinkedDataFromObject() + + Window.WaitCursor(0) + + Draw.PupMenu('renamed: %d objects.' % renameCount) + +if __name__=='__main__': + main() diff --git a/release/scripts/object_cookie_cutter.py b/release/scripts/object_cookie_cutter.py new file mode 100644 index 00000000000..2a6e0ad6b2e --- /dev/null +++ b/release/scripts/object_cookie_cutter.py @@ -0,0 +1,667 @@ +#!BPY +""" +Name: 'Cookie Cut from View' +Blender: 234 +Group: 'Object' +Tooltip: 'Cut from the view axis, (Sel 3d Curves and Meshes (only edges) into other meshes with faces)' +""" +__author__= "Campbell Barton" +__url__= ["blender", "blenderartist"] +__version__= "1.0" + +__bpydoc__= """\ +This script takes the selected mesh objects, devides them into 2 groups +Cutters and The objects to be cut. + +Cutters are meshes with no faces, just edge loops. and any meshes with faces will be cut. + +Usage: + +Select 2 or more meshes, one with no faces (a closed polyline) and one with faces to cut. + +Align the view on the axis you want to cut. +For shapes that have overlapping faces (from the view), hide any backfacing faces so they will be ignored during the cut. +Run the script. + +You can choose to make the cut verts lie on the face that they were cut from or on the edge that cut them. +This script supports UV coordinates and images. +""" + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Script copyright (C) Campbell Barton +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender +from math import sqrt +import BPyMesh +Vector= Blender.Mathutils.Vector +LineIntersect2D= Blender.Geometry.LineIntersect2D +PointInTriangle2D= Blender.Geometry.PointInTriangle2D + +# Auto class +def auto_class(slots): + exec('class container_class(object): __slots__=%s' % slots) + return container_class + + +bignum= 1<<30 +def bounds_xy(iter_item): + ''' + Works with types + MMesh.verts + MFace + MEdge + ''' + xmin= ymin= bignum + xmax= ymax= -bignum + for v in iter_item: + x= v.co.x + y= v.co.y + if xxmax: xmax= x + if y>ymax: ymax= y + + return xmin, ymin, xmax, ymax + +def bounds_intersect(a,b): + ''' + each tuple is + xmin, ymin, xmax, ymax + ''' + if\ + a[0]>b[2] or\ + a[1]>b[3] or\ + a[2]i2: + i1,i2= i2,i1 + return i1, i2 + +def sorted_indicies(i1, i2): + if i1>i2: + i1,i2= i2,i1 + return i1, i2 + +def fake_length2d(pt1, pt2): + ''' + Only used for comparison so dont sqrt + ''' + #return math.sqrt(abs(pow(x1-x2, 2)+ pow(y1-y2, 2))) + return pow(pt1[0]-pt2[0], 2) + pow(pt1[1]- pt2[1], 2) + +def length2d(pt1, pt2): + ''' + Only used for comparison so dont sqrt + ''' + #return math.sqrt(abs(pow(x1-x2, 2)+ pow(y1-y2, 2))) + return sqrt(pow(pt1[0]-pt2[0], 2) + pow(pt1[1]- pt2[1], 2)) + + + +def tri_area_2d(v1, v2, v3): + e1 = length2d(v1, v2) + e2 = length2d(v2, v3) + e3 = length2d(v3, v1) + p = e1+e2+e3 + return 0.25 * sqrt(abs(p*(p-2*e1)*(p-2*e2)*(p-2*e3))) + +def tri_pt_find_z_2d(pt, tri): + """ Takes a face and 3d vector and assigns teh vectors Z to its on the face""" + + l1= tri_area_2d(tri[1], tri[2], pt) + l2= tri_area_2d(tri[0], tri[2], pt) + l3= tri_area_2d(tri[0], tri[1], pt) + + tot= l1+l2+l3 + # Normalize + l1=l1/tot + l2=l2/tot + l3=l3/tot + + z1= tri[0].z*l1 + z2= tri[1].z*l2 + z3= tri[2].z*l3 + + return z1+z2+z3 + + +def tri_pt_find_uv_2d(pt, tri, uvs): + """ Takes a face and 3d vector and assigns teh vectors Z to its on the face""" + + l1= tri_area_2d(tri[1], tri[2], pt) + l2= tri_area_2d(tri[0], tri[2], pt) + l3= tri_area_2d(tri[0], tri[1], pt) + + tot= l1+l2+l3 + if not tot: # No area, just return the first uv + return Vector(uvs[0]) + + # Normalize + l1=l1/tot + l2=l2/tot + l3=l3/tot + + uv1= uvs[0]*l1 + uv2= uvs[1]*l2 + uv3= uvs[2]*l3 + + return uv1+uv2+uv3 + + + + +def mesh_edge_dict(me): + ed_dict= {} + for f in me.faces: + if not f.hide: + for edkey in f.edge_keys: + ed_dict.setdefault(edkey, []).append(f) + + return ed_dict + + + +def terrain_cut_2d(t, c, PREF_Z_LOC): + ''' + t is the terrain + c is the cutter + + PREF_Z_LOC: 0 - from terrain face + 1 - from cutter edge + + returns nothing + ''' + + # do we have a 2d intersection + if not bounds_intersect(t.bounds, c.bounds): + return + + # Local vars + me_t= t.mesh + me_c= c.mesh + + has_uv= me_t.faceUV + + Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) + ''' + first assign a face terrain face for each cutter verticie + ''' + cut_verts_temp= list(me_c.verts) + cut_vert_terrain_faces= [None] * len(me_c.verts) + vert_z_level= [-10.0] * len(me_c.verts) + + for v in me_c.verts: + v_index= v.index + v_co= v.co + for fidx, f in enumerate(me_t.faces): + if not f.hide: + if point_in_bounds(v_co, t.face_bounds[fidx]): + f_v= [vv.co for vv in f] + if point_in_poly2d(v_co, f_v): + + + if PREF_Z_LOC==0: + ''' + Get the z location from the face. + ''' + + if len(f_v)==3: + vert_z_level[v_index]= tri_pt_find_z_2d(v_co, (f_v[0], f_v[1], f_v[2]) ) + else: + # Quad, which side are we on? + a1= tri_area_2d(f_v[0], f_v[1], v_co) + a2= tri_area_2d(f_v[1], f_v[2], v_co) + + a3= tri_area_2d(f_v[0], f_v[1], f_v[2]) + + if a1+a2